From 71c98d31c4eccab42b0391d7c0090551d14fb9ad Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 7 Apr 2019 10:24:48 +0000 Subject: [PATCH 01/38] Update project configuration - Move tests to test/ directory - Add mocha config to package.json - Add typescript dependencies --- package-lock.json | 236 ++++++++++++++++++++++++ package.json | 24 ++- {tests => test}/data/areas.json | 0 {tests => test}/data/districts.json | 0 {tests => test}/data/incodes.json | 0 {tests => test}/data/normalisation.json | 0 {tests => test}/data/outcodes.json | 0 {tests => test}/data/postcodes.csv.gz | Bin {tests => test}/data/sectors.json | 0 {tests => test}/data/sub-districts.json | 0 {tests => test}/data/units.json | 0 {tests => test}/data/validation.json | 0 {tests => test}/exhaustive_unit.js | 0 {tests => test}/unit.js | 0 14 files changed, 258 insertions(+), 2 deletions(-) rename {tests => test}/data/areas.json (100%) rename {tests => test}/data/districts.json (100%) rename {tests => test}/data/incodes.json (100%) rename {tests => test}/data/normalisation.json (100%) rename {tests => test}/data/outcodes.json (100%) rename {tests => test}/data/postcodes.csv.gz (100%) rename {tests => test}/data/sectors.json (100%) rename {tests => test}/data/sub-districts.json (100%) rename {tests => test}/data/units.json (100%) rename {tests => test}/data/validation.json (100%) rename {tests => test}/exhaustive_unit.js (100%) rename {tests => test}/unit.js (100%) diff --git a/package-lock.json b/package-lock.json index b1cc156..84a201d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -111,6 +111,30 @@ "to-fast-properties": "^2.0.0" } }, + "@cablanchard/tsconfig": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@cablanchard/tsconfig/-/tsconfig-0.0.1.tgz", + "integrity": "sha512-2oQpsub+881xsqTUwVvxoPHLVXOe83koq8kO8+4fjjrUGBnnsC3DFDB08fBBM2o3HgWWFLIGMvXSi6jexOi1XA==", + "dev": true + }, + "@cablanchard/tslint": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@cablanchard/tslint/-/tslint-0.0.1.tgz", + "integrity": "sha512-sZYAjrosdF5xpOoUapZ1Xs4zJB7OAD0rRAD6DGG1+qP0hoMTSUNayWEkty10XjrdsCd1xqzh1+FhScEArLF7Pw==", + "dev": true + }, + "@types/chai": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", + "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", + "dev": true + }, + "@types/mocha": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", + "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", + "dev": true + }, "ajv": { "version": "6.9.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz", @@ -144,6 +168,12 @@ "color-convert": "^1.9.0" } }, + "arg": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", + "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -222,6 +252,65 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -337,6 +426,18 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -506,6 +607,12 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", @@ -1158,6 +1265,23 @@ "function-bind": "^1.1.1" } }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + } + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -1580,6 +1704,12 @@ "chalk": "^2.0.1" } }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, "map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", @@ -3035,6 +3165,12 @@ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -3143,6 +3279,15 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, + "resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, "resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", @@ -3383,6 +3528,24 @@ "urix": "^0.1.0" } }, + "source-map-support": { + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.11.tgz", + "integrity": "sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", @@ -3554,6 +3717,67 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, + "ts-node": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.0.3.tgz", + "integrity": "sha512-2qayBA4vdtVRuDo11DEFSsD/SFsBXQBRZZhbRGSIkmYmVkWjULn/GGMdG10KVqkaGndljfaTD8dKjWgcejO8YA==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" + } + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + }, + "tslint": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.15.0.tgz", + "integrity": "sha512-6bIEujKR21/3nyeoX2uBnE8s+tMXCQXhqMmaIPJpHmXJoBJPTLcI7/VHRtUwMhnLVdwLqqY3zmd8Dxqa5CVdJA==", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.13.0", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -3569,6 +3793,12 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, + "typescript": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.2.tgz", + "integrity": "sha512-Og2Vn6Mk7JAuWA1hQdDQN/Ekm/SchX80VzLhjKN9ETYrIepBFAd8PkOdOTK2nKt0FCkmMZKBJvQ1dV1gIxPu/A==", + "dev": true + }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -3805,6 +4035,12 @@ "lodash": "^4.17.11", "yargs": "^12.0.5" } + }, + "yn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.0.tgz", + "integrity": "sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==", + "dev": true } } } diff --git a/package.json b/package.json index 1d1065e..fb77778 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,32 @@ "dependencies": {}, "prettier": {}, "devDependencies": { + "@cablanchard/tsconfig": "0.0.1", + "@cablanchard/tslint": "0.0.1", + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.6", "chai": "~4.2.0", "coveralls": "~3.0.2", "csv": "~5.1.1", "mocha": "~6.0.0", "nyc": "~13.3.0", - "prettier": "~1.16.4" + "prettier": "~1.16.4", + "source-map-support": "^0.5.11", + "ts-node": "^8.0.3", + "tslint": "^5.15.0", + "typescript": "^3.4.2" + }, + "mocha": { + "extension": [ + "js", + "ts" + ], + "exit": true, + "fullTrace": true, + "require": [ + "ts-node/register", + "source-map-support/register" + ] }, "files": [ "index.js" @@ -28,7 +48,7 @@ "all": true }, "scripts": { - "test": "NODE_ENV=test node_modules/.bin/nyc node_modules/.bin/mocha tests/ --exit", + "test": "NODE_ENV=test node_modules/.bin/nyc node_modules/.bin/mocha", "coverage": "node_modules/.bin/nyc report --reporter=text-lcov | node_modules/.bin/coveralls || true" }, "repository": { diff --git a/tests/data/areas.json b/test/data/areas.json similarity index 100% rename from tests/data/areas.json rename to test/data/areas.json diff --git a/tests/data/districts.json b/test/data/districts.json similarity index 100% rename from tests/data/districts.json rename to test/data/districts.json diff --git a/tests/data/incodes.json b/test/data/incodes.json similarity index 100% rename from tests/data/incodes.json rename to test/data/incodes.json diff --git a/tests/data/normalisation.json b/test/data/normalisation.json similarity index 100% rename from tests/data/normalisation.json rename to test/data/normalisation.json diff --git a/tests/data/outcodes.json b/test/data/outcodes.json similarity index 100% rename from tests/data/outcodes.json rename to test/data/outcodes.json diff --git a/tests/data/postcodes.csv.gz b/test/data/postcodes.csv.gz similarity index 100% rename from tests/data/postcodes.csv.gz rename to test/data/postcodes.csv.gz diff --git a/tests/data/sectors.json b/test/data/sectors.json similarity index 100% rename from tests/data/sectors.json rename to test/data/sectors.json diff --git a/tests/data/sub-districts.json b/test/data/sub-districts.json similarity index 100% rename from tests/data/sub-districts.json rename to test/data/sub-districts.json diff --git a/tests/data/units.json b/test/data/units.json similarity index 100% rename from tests/data/units.json rename to test/data/units.json diff --git a/tests/data/validation.json b/test/data/validation.json similarity index 100% rename from tests/data/validation.json rename to test/data/validation.json diff --git a/tests/exhaustive_unit.js b/test/exhaustive_unit.js similarity index 100% rename from tests/exhaustive_unit.js rename to test/exhaustive_unit.js diff --git a/tests/unit.js b/test/unit.js similarity index 100% rename from tests/unit.js rename to test/unit.js From 209efe4c578e131c1f8c6f524cbfd250279a4d1e Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 7 Apr 2019 10:30:29 +0000 Subject: [PATCH 02/38] Update author info --- package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index fb77778..2c12698 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,11 @@ "validation", "parsing" ], - "author": "Ideal Postcodes", + "author": { + "name": "Ideal Postcodes", + "url": "https://ideal-postcodes.co.uk", + "email": "support@ideal-postcodes.co.uk" + }, "license": "MIT", "bugs": { "url": "https://github.com/ideal-postcodes/postcode/issues" From 7e57321cd170f895b886f09b31c92fc47b2c2807 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 7 Apr 2019 10:30:45 +0000 Subject: [PATCH 03/38] Use ~ for pinning deps --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 2c12698..d7a0936 100644 --- a/package.json +++ b/package.json @@ -8,18 +8,18 @@ "devDependencies": { "@cablanchard/tsconfig": "0.0.1", "@cablanchard/tslint": "0.0.1", - "@types/chai": "^4.1.7", - "@types/mocha": "^5.2.6", + "@types/chai": "~4.1.7", + "@types/mocha": "~5.2.6", "chai": "~4.2.0", "coveralls": "~3.0.2", "csv": "~5.1.1", "mocha": "~6.0.0", "nyc": "~13.3.0", "prettier": "~1.16.4", - "source-map-support": "^0.5.11", - "ts-node": "^8.0.3", - "tslint": "^5.15.0", - "typescript": "^3.4.2" + "source-map-support": "~0.5.11", + "ts-node": "~8.0.3", + "tslint": "~5.15.0", + "typescript": "~3.4.2" }, "mocha": { "extension": [ From 0444f9202f39fc6c17dc2e05c99d2ac7c51ff1f1 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 7 Apr 2019 10:38:11 +0000 Subject: [PATCH 04/38] Add tslint config --- package.json | 1 + tslint.json | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 tslint.json diff --git a/package.json b/package.json index d7a0936..b82e799 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ }, "scripts": { "test": "NODE_ENV=test node_modules/.bin/nyc node_modules/.bin/mocha", + "lint": "node_modules/.bin/tslint -c tslint.json -p tsconfig.json", "coverage": "node_modules/.bin/nyc report --reporter=text-lcov | node_modules/.bin/coveralls || true" }, "repository": { diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..e2f8225 --- /dev/null +++ b/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "@cablanchard/tslint" +} From 7468275cdbc42114658ae43470cfd49dac4be655 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 7 Apr 2019 11:04:50 +0000 Subject: [PATCH 05/38] Add @types/node --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index b82e799..5979cbd 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "@cablanchard/tslint": "0.0.1", "@types/chai": "~4.1.7", "@types/mocha": "~5.2.6", + "@types/node": "~11.13.0", "chai": "~4.2.0", "coveralls": "~3.0.2", "csv": "~5.1.1", From 02995045c5c0acd2fb546f9a750185b1b2ff1a8a Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 7 Apr 2019 11:05:32 +0000 Subject: [PATCH 06/38] Update gitignore --- .gitignore | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c8db4f5..a056594 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,62 @@ -node_modules +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage .nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# dotenv environment variables file +.env + +dist + +.cache + .DS_Store + From 780287d89c85aba7ed7146e5101ca4eeed59ff23 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 7 Apr 2019 14:48:52 +0000 Subject: [PATCH 07/38] Migrate unit tests to typescript --- test/unit.js | 196 --------------------------------------------------- test/unit.ts | 154 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 196 deletions(-) delete mode 100644 test/unit.js create mode 100644 test/unit.ts diff --git a/test/unit.js b/test/unit.js deleted file mode 100644 index f8b6066..0000000 --- a/test/unit.js +++ /dev/null @@ -1,196 +0,0 @@ -var assert = require("chai").assert, - fs = require("fs"), - path = require("path"), - dataDir = path.join(__dirname, "/data"), - Postcode = require(path.join(__dirname, "../index")), - testData, testResult; - -describe("Postcode#Valid", function () { - before(function (done) { - testData = fs.readFile(path.join(dataDir, "validation.json"), function (error, data) { - if (error) throw error; - testData = JSON.parse(data); - done(); - }); - }); - - it ("should return true for postcodes that look correct", function () { - testData.tests.forEach(function (elem) { - assert.equal(new Postcode(elem.base).valid(), elem.expected); - }); - }); -}); - -describe("Postcode normalisation", function () { - before(function (done) { - testData = fs.readFile(path.join(dataDir, "normalisation.json"), function (error, data) { - if (error) throw error; - testData = JSON.parse(data); - done(); - }); - }); - - it ("should correctly normalise postcodes", function () { - testData.tests.forEach(function (elem) { - assert.equal(new Postcode(elem.base).normalise(), elem.expected); - }) - }); - - it ("should return null if invalid postcode", function () { - assert.isNull(new Postcode("Definitly bogus").normalise()); - }); -}); - -describe("Postcode.validOutcode", function () { - it ("should return true for valid outcodes", function (done) { - testData = fs.readFile(path.join(dataDir, "outcodes.json"), function (error, data) { - if (error) throw error; - testData = JSON.parse(data); - testData.tests.forEach(function (test) { - assert.isTrue(Postcode.validOutcode(test.expected)); - }); - done(); - }); - }); - it ("should return false for invalid outcode", function (done) { - var invalidOutcodes = ["BOGUS", "Hello there", "12345"]; - invalidOutcodes.forEach(function (code) { - assert.isFalse(Postcode.validOutcode(code)); - }); - done(); - }); -}); - -describe("Incode parsing", function () { - before(function (done) { - testData = fs.readFile(path.join(dataDir, "incodes.json"), function (error, data) { - if (error) throw error; - testData = JSON.parse(data); - done(); - }); - }); - - it ("should correctly parse incodes", function () { - testData.tests.forEach(function (elem) { - assert.equal(new Postcode(elem.base).incode(), elem.expected); - }); - }); - - it ("should return null if invalid postcode", function () { - assert.isNull(new Postcode("Definitly bogus").incode()); - }); -}); - -describe("Outcode parsing", function () { - before(function (done) { - testData = fs.readFile(path.join(dataDir, "outcodes.json"), function (error, data) { - if (error) throw error; - testData = JSON.parse(data); - done(); - }); - }); - - it ("should correctly parse outcodes", function () { - testData.tests.forEach(function (elem) { - assert.equal(new Postcode(elem.base).outcode(), elem.expected); - }); - }); - it ("should return null if invalid postcode", function () { - assert.isNull(new Postcode("Definitly bogus").outcode()); - }); -}); - -describe("Area parsing", function () { - before(function (done) { - testData = fs.readFile(path.join(dataDir, "areas.json"), function (error, data) { - if (error) throw error; - testData = JSON.parse(data); - done(); - }); - }); - - it ("should correctly parse areas", function () { - testData.tests.forEach(function (elem) { - assert.equal(new Postcode(elem.base).area(), elem.expected); - }); - }); - it ("should return null if invalid postcode", function () { - assert.isNull(new Postcode("Definitely bogus").area()); - }); -}); - -describe("District parsing", function () { - before(function (done) { - testData = fs.readFile(path.join(dataDir, "districts.json"), function (error, data) { - if (error) throw error; - testData = JSON.parse(data); - done(); - }); - }); - - it ("should correctly parse districts", function () { - testData.tests.forEach(function (elem) { - assert.equal(new Postcode(elem.base).district(), elem.expected); - }); - }); - it ("should return null if invalid postcode", function () { - assert.isNull(new Postcode("Definitely bogus").district()); - }); -}); - -describe("Sub-district parsing", function () { - before(function (done) { - testData = fs.readFile(path.join(dataDir, "sub-districts.json"), function (error, data) { - if (error) throw error; - testData = JSON.parse(data); - done(); - }); - }); - - it ("should correctly parse sub-districts", function () { - testData.tests.forEach(function (elem) { - assert.equal(new Postcode(elem.base).subDistrict(), elem.expected); - }); - }); - it ("should return null if invalid postcode", function () { - assert.isNull(new Postcode("Definitely bogus").subDistrict()); - }); -}); - -describe("Sector parsing", function () { - before(function (done) { - testData = fs.readFile(path.join(dataDir, "sectors.json"), function (error, data) { - if (error) throw error; - testData = JSON.parse(data); - done(); - }); - }); - - it ("should correctly parse sectors", function () { - testData.tests.forEach(function (elem) { - assert.equal(new Postcode(elem.base).sector(), elem.expected); - }); - }); - it ("should return null if invalid postcode", function () { - assert.isNull(new Postcode("Definitely bogus").sector()); - }); -}); - -describe("Unit parsing", function () { - before(function (done) { - testData = fs.readFile(path.join(dataDir, "units.json"), function (error, data) { - if (error) throw error; - testData = JSON.parse(data); - done(); - }); - }); - - it ("should correctly parse units", function () { - testData.tests.forEach(function (elem) { - assert.equal(new Postcode(elem.base).unit(), elem.expected); - }); - }); - it ("should return null if invalid postcode", function () { - assert.isNull(new Postcode("Definitely bogus").unit()); - }); -}); diff --git a/test/unit.ts b/test/unit.ts new file mode 100644 index 0000000..949df75 --- /dev/null +++ b/test/unit.ts @@ -0,0 +1,154 @@ +import { assert } from "chai"; +import { readFile } from "fs"; +import { join } from "path"; +import Postcode from "../index"; + +const dataDir = join(__dirname, "/data"); + +interface TestFixtures { + tests: TestCase[]; +} + +interface TestCase { + base: string; + expected: string; +} + +const loadFixtures = (fileName: string): Promise => { + return new Promise((resolve, reject) => { + const filePath = join(dataDir, fileName); + readFile(filePath, { encoding: "utf8" }, (error, data) => { + if (error) return reject(error); + try { + resolve(JSON.parse(data.toString())); + } catch (error) { + return reject(error); + } + }); + }); +}; + +interface TestMethodOptions { + tests: TestCase[]; + method: string; +} + +const testMethod = (options: TestMethodOptions): void => { + const { tests, method } = options; + tests.forEach(({ base, expected }) => { + const p = new Postcode(base); + const result = p[method].call(p); + assert.equal(result, expected); + }); +}; + +describe("Postcode#Valid", async () => { + it("should return true for postcodes that look correct", async () => { + const { tests } = await loadFixtures("validation.json"); + testMethod({ method: "valid", tests }); + }); +}); + +describe("Postcode normalisation", () => { + it("should correctly normalise postcodes", async () => { + const { tests } = await loadFixtures("normalisation.json"); + testMethod({ method: "normalise", tests }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(new Postcode("Definitly bogus").normalise()); + }); +}); + +describe("Postcode.validOutcode", () => { + it("should return true for valid outcodes", async () => { + const { tests } = await loadFixtures("outcodes.json"); + tests.forEach(({ expected }) => + assert.isTrue(Postcode.validOutcode(expected)) + ); + }); + + it("should return false for invalid outcode", () => { + const invalidOutcodes = ["BOGUS", "Hello there", "12345"]; + invalidOutcodes.forEach(code => + assert.isFalse(Postcode.validOutcode(code)) + ); + }); +}); + +describe("Incode parsing", () => { + it("should correctly parse incodes", async () => { + const { tests } = await loadFixtures("incodes.json"); + testMethod({ method: "incode", tests }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(new Postcode("Definitly bogus").incode()); + }); +}); + +describe("Outcode parsing", () => { + it("should correctly parse outcodes", async () => { + const { tests } = await loadFixtures("outcodes.json"); + testMethod({ method: "outcode", tests }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(new Postcode("Definitly bogus").outcode()); + }); +}); + +describe("Area parsing", () => { + it("should correctly parse areas", async () => { + const { tests } = await loadFixtures("areas.json"); + testMethod({ method: "area", tests }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(new Postcode("Definitely bogus").area()); + }); +}); + +describe("District parsing", () => { + it("should correctly parse districts", async () => { + const { tests } = await loadFixtures("districts.json"); + testMethod({ method: "district", tests }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(new Postcode("Definitely bogus").district()); + }); +}); + +describe("Sub-district parsing", () => { + it("should correctly parse sub-districts", async () => { + const { tests } = await loadFixtures("sub-districts.json"); + testMethod({ method: "subDistrict", tests }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(new Postcode("Definitely bogus").subDistrict()); + }); +}); + +describe("Sector parsing", () => { + it("should correctly parse sectors", async () => { + const { tests } = await loadFixtures("sectors.json"); + testMethod({ method: "sector", tests }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(new Postcode("Definitely bogus").sector()); + }); +}); + +describe("Unit parsing", () => { + it("should correctly parse units", async () => { + const { tests } = await loadFixtures("units.json"); + testMethod({ method: "unit", tests }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(new Postcode("Definitely bogus").unit()); + }); +}); From 44971037a31f1facdcecdf7caffac536e586067f Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 7 Apr 2019 14:50:24 +0000 Subject: [PATCH 08/38] Migrate exhaustive test suite to typescript --- test/exhaustive_unit.js | 229 ---------------------------------------- test/exhaustive_unit.ts | 228 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 228 insertions(+), 229 deletions(-) delete mode 100644 test/exhaustive_unit.js create mode 100644 test/exhaustive_unit.ts diff --git a/test/exhaustive_unit.js b/test/exhaustive_unit.js deleted file mode 100644 index c3fbde5..0000000 --- a/test/exhaustive_unit.js +++ /dev/null @@ -1,229 +0,0 @@ -const assert = require("chai").assert; -const { createReadStream } = require("fs"); -const { parse } = require("csv"); -const { resolve } = require("path"); -const zlib = require("zlib"); -const Postcode = require("../index"); - -describe("Exhaustive postcode test", function() { - const testData = []; - - before(function(done) { - this.timeout(60000); - console.log( - "Loading in complete array of postcodes (this might take a while)..." - ); - const inputFile = resolve(__dirname, "./data/postcodes.csv.gz"); - createReadStream(inputFile) - .pipe(zlib.createGunzip()) - .pipe(parse({ delimiter: "," })) - .on("data", data => testData.push(data)) - .on("error", done) - .on("end", done); - }); - - describe("Postcode#Valid", function() { - it("should all be valid", function(done) { - this.timeout(60000); - testData.forEach(function(testPostcode) { - var pc = testPostcode[0], - postcode = new Postcode(testPostcode[0]); - assert.isTrue( - postcode.valid(), - "Expected " + testPostcode[0] + " to be valid" - ); - }); - done(); - }); - }); - describe("Postcode normalisation", function() { - it("should not throw and provide consistant normalised postcode", function(done) { - this.timeout(60000); - testData.forEach(function(testPostcode) { - var pc = testPostcode[0], - postcode = new Postcode(pc), - downcasePostcode = new Postcode(pc.toLowerCase()), - unspacedPostcode = new Postcode(pc.replace(/\s/, "")); - if (pc.length === 7) { - // Since this isn't normalised in dataset, best we can do is see if normalised data matches - assert.equal(postcode.normalise(), downcasePostcode.normalise()); - assert.equal(postcode.normalise(), unspacedPostcode.normalise()); - } else { - // Any space indicates incode/outcode - assert.equal(postcode.normalise(), pc.replace(/\s*/, " ")); - assert.equal(downcasePostcode.normalise(), pc.replace(/\s*/, " ")); - assert.equal(unspacedPostcode.normalise(), pc.replace(/\s*/, " ")); - } - }); - done(); - }); - }); - describe("Incode parsing", function() { - it("should return the correct incode", function(done) { - this.timeout(60000); - testData.forEach(function(testPostcode) { - var pc = testPostcode[0], - postcode = new Postcode(pc), - downcasePostcode = new Postcode(pc.toLowerCase()), - unspacedPostcode = new Postcode(pc.replace(/\s/, "")), - testIncode; - if (pc.length === 7) { - // Since this isn't normalised in dataset, best we can do is see if normalised data matches - assert.equal(postcode.incode(), downcasePostcode.incode()); - assert.equal(postcode.incode(), unspacedPostcode.incode()); - } else { - // Any space indicates incode/outcode - testIncode = pc.match(/.*\s/)[0].replace(/\s/, ""); - assert.equal(postcode.incode(), testIncode); - assert.equal(downcasePostcode.incode(), testIncode); - assert.equal(unspacedPostcode.incode(), testIncode); - } - }); - done(); - }); - }); - describe("Outcode parsing", function() { - it("should return the correct outcode", function(done) { - this.timeout(60000); - testData.forEach(function(testPostcode) { - var pc = testPostcode[0], - postcode = new Postcode(pc), - downcasePostcode = new Postcode(pc.toLowerCase()), - unspacedPostcode = new Postcode(pc.replace(/\s/, "")), - testIncode; - if (pc.length === 7) { - // Since this isn't normalised in dataset, best we can do is see if normalised data matches - assert.equal(postcode.outcode(), downcasePostcode.outcode()); - assert.equal(postcode.outcode(), unspacedPostcode.outcode()); - } else { - // Any space indicates incode/outcode - testIncode = pc.match(/\s.*/)[0].replace(/\s/, ""); - assert.equal(postcode.outcode(), testIncode); - assert.equal(downcasePostcode.outcode(), testIncode); - assert.equal(unspacedPostcode.outcode(), testIncode); - } - }); - done(); - }); - }); - describe("Area parsing", function() { - it("should return the correct area", function(done) { - this.timeout(60000); - testData.forEach(function(testPostcode) { - var pc = testPostcode[0], - postcode = new Postcode(pc), - downcasePostcode = new Postcode(pc.toLowerCase()), - unspacedPostcode = new Postcode(pc.replace(/\s/, "")), - testArea; - if (pc.length === 7) { - // Since this isn't normalised in dataset, best we can do is see if normalised data matches - assert.equal(postcode.area(), downcasePostcode.area()); - assert.equal(postcode.area(), unspacedPostcode.area()); - } else { - // Any space indicates incode/outcode - testArea = pc.match(/\s.*/)[0].replace(/\s/, ""); - assert.equal(postcode.area(), testArea); - assert.equal(downcasePostcode.area(), testArea); - assert.equal(unspacedPostcode.area(), testArea); - } - }); - done(); - }); - }); - describe("District parsing", function() { - it("should return the correct district", function(done) { - this.timeout(60000); - testData.forEach(function(testPostcode) { - var pc = testPostcode[0], - postcode = new Postcode(pc), - downcasePostcode = new Postcode(pc.toLowerCase()), - unspacedPostcode = new Postcode(pc.replace(/\s/, "")), - testDistrict; - if (pc.length === 7) { - // Since this isn't normalised in dataset, best we can do is see if normalised data matches - assert.equal(postcode.district(), downcasePostcode.district()); - assert.equal(postcode.district(), unspacedPostcode.district()); - } else { - // Any space indicates incode/outcode - testDistrict = pc.match(/\s.*/)[0].replace(/\s/, ""); - assert.equal(postcode.district(), testDistrict); - assert.equal(downcasePostcode.district(), testDistrict); - assert.equal(unspacedPostcode.district(), testDistrict); - } - }); - done(); - }); - }); - describe("Sub-district parsing", function() { - it("should return the correct sub-district", function(done) { - this.timeout(60000); - testData.forEach(function(testPostcode) { - var pc = testPostcode[0], - postcode = new Postcode(pc), - downcasePostcode = new Postcode(pc.toLowerCase()), - unspacedPostcode = new Postcode(pc.replace(/\s/, "")), - testSubDistrict; - if (pc.length === 7) { - // Since this isn't normalised in dataset, best we can do is see if normalised data matches - assert.equal(postcode.subDistrict(), downcasePostcode.subDistrict()); - assert.equal(postcode.subDistrict(), unspacedPostcode.subDistrict()); - } else { - // Any space indicates incode/outcode - testSubDistrict = pc.match(/\s.*/)[0].replace(/\s/, ""); - assert.equal(postcode.subDistrict(), testSubDistrict); - assert.equal(downcasePostcode.subDistrict(), testSubDistrict); - assert.equal(unspacedPostcode.subDistrict(), testSubDistrict); - } - }); - done(); - }); - }); - describe("Sector parsing", function() { - it("should return the correct sector", function(done) { - this.timeout(60000); - testData.forEach(function(testPostcode) { - var pc = testPostcode[0], - postcode = new Postcode(pc), - downcasePostcode = new Postcode(pc.toLowerCase()), - unspacedPostcode = new Postcode(pc.replace(/\s/, "")), - testSector; - if (pc.length === 7) { - // Since this isn't normalised in dataset, best we can do is see if normalised data matches - assert.equal(postcode.sector(), downcasePostcode.sector()); - assert.equal(postcode.sector(), unspacedPostcode.sector()); - } else { - // Any space indicates incode/outcode - testSector = pc.match(/\s.*/)[0].replace(/\s/, ""); - assert.equal(postcode.sector(), testSector); - assert.equal(downcasePostcode.sector(), testSector); - assert.equal(unspacedPostcode.sector(), testSector); - } - }); - done(); - }); - }); - describe("Unit parsing", function() { - it("should return the correct unit", function(done) { - this.timeout(60000); - testData.forEach(function(testPostcode) { - var pc = testPostcode[0], - postcode = new Postcode(pc), - downcasePostcode = new Postcode(pc.toLowerCase()), - unspacedPostcode = new Postcode(pc.replace(/\s/, "")), - testUnit; - if (pc.length === 7) { - // Since this isn't normalised in dataset, best we can do is see if normalised data matches - assert.equal(postcode.unit(), downcasePostcode.unit()); - assert.equal(postcode.unit(), unspacedPostcode.unit()); - } else { - // Any space indicates incode/outcode - testUnit = pc.match(/\s.*/)[0].replace(/\s/, ""); - assert.equal(postcode.unit(), testUnit); - assert.equal(downcasePostcode.unit(), testUnit); - assert.equal(unspacedPostcode.unit(), testUnit); - } - }); - done(); - }); - }); -}); diff --git a/test/exhaustive_unit.ts b/test/exhaustive_unit.ts new file mode 100644 index 0000000..2a7f763 --- /dev/null +++ b/test/exhaustive_unit.ts @@ -0,0 +1,228 @@ +/* tslint:disable:no-invalid-this */ + +import { assert } from "chai"; +import { createReadStream } from "fs"; +import { parse } from "csv"; +import { resolve } from "path"; +import { createGunzip } from "zlib"; + +const TIMEOUT = 60000; +const PC_LENGTH = 7; + +import Postcode from "../index"; + +describe("Exhaustive postcode test", () => { + const testData = []; + + before(function(done) { + this.timeout(TIMEOUT); + console.log( + "Loading in complete array of postcodes (this might take a while)..." + ); + const inputFile = resolve(__dirname, "./data/postcodes.csv.gz"); + createReadStream(inputFile) + .pipe(createGunzip()) + .pipe(parse({ delimiter: "," })) + .on("data", data => testData.push(data[0])) + .on("error", done) + .on("end", done); + }); + + describe("Postcode#Valid", () => { + it("should all be valid", function(done) { + this.timeout(TIMEOUT); + testData.forEach(postcode => { + const p = new Postcode(postcode); + assert.isTrue(p.valid(), `Expected ${postcode} to be valid`); + }); + done(); + }); + }); + + describe("Postcode normalisation", () => { + it("should not throw and provide consistant normalised postcode", function(done) { + this.timeout(TIMEOUT); + testData.forEach(postcode => { + const p = new Postcode(postcode); + const downcasePostcode = new Postcode(postcode.toLowerCase()); + const unspacedPostcode = new Postcode(postcode.replace(/\s/, "")); + if (postcode.length === PC_LENGTH) { + // Since this isn't normalised in dataset, best we can do is see if normalised data matches + assert.equal(p.normalise(), downcasePostcode.normalise()); + assert.equal(p.normalise(), unspacedPostcode.normalise()); + } else { + // Any space indicates incode/outcode + assert.equal(p.normalise(), postcode.replace(/\s*/, " ")); + assert.equal( + downcasePostcode.normalise(), + postcode.replace(/\s*/, " ") + ); + assert.equal( + unspacedPostcode.normalise(), + postcode.replace(/\s*/, " ") + ); + } + }); + done(); + }); + }); + + describe("Incode parsing", () => { + it("should return the correct incode", function(done) { + this.timeout(TIMEOUT); + testData.forEach(postcode => { + const p = new Postcode(postcode); + const downcasePostcode = new Postcode(postcode.toLowerCase()); + const unspacedPostcode = new Postcode(postcode.replace(/\s/, "")); + + if (postcode.length === PC_LENGTH) { + // Since this isn't normalised in dataset, best we can do is see if normalised data matches + assert.equal(p.incode(), downcasePostcode.incode()); + assert.equal(p.incode(), unspacedPostcode.incode()); + } else { + // Any space indicates incode/outcode + const testIncode = postcode.match(/.*\s/)[0].replace(/\s/, ""); + assert.equal(p.incode(), testIncode); + assert.equal(downcasePostcode.incode(), testIncode); + assert.equal(unspacedPostcode.incode(), testIncode); + } + }); + done(); + }); + }); + + describe("Outcode parsing", () => { + it("should return the correct outcode", function(done) { + this.timeout(TIMEOUT); + testData.forEach(postcode => { + const p = new Postcode(postcode); + const downcasePostcode = new Postcode(postcode.toLowerCase()); + const unspacedPostcode = new Postcode(postcode.replace(/\s/, "")); + if (postcode.length === PC_LENGTH) { + // Since this isn't normalised in dataset, best we can do is see if normalised data matches + assert.equal(p.outcode(), downcasePostcode.outcode()); + assert.equal(p.outcode(), unspacedPostcode.outcode()); + } else { + // Any space indicates incode/outcode + const testIncode = postcode.match(/\s.*/)[0].replace(/\s/, ""); + assert.equal(p.outcode(), testIncode); + assert.equal(downcasePostcode.outcode(), testIncode); + assert.equal(unspacedPostcode.outcode(), testIncode); + } + }); + done(); + }); + }); + describe("Area parsing", () => { + it("should return the correct area", function(done) { + this.timeout(TIMEOUT); + testData.forEach(postcode => { + const p = new Postcode(postcode); + const downcasePostcode = new Postcode(postcode.toLowerCase()); + const unspacedPostcode = new Postcode(postcode.replace(/\s/, "")); + if (postcode.length === PC_LENGTH) { + // Since this isn't normalised in dataset, best we can do is see if normalised data matches + assert.equal(p.area(), downcasePostcode.area()); + assert.equal(p.area(), unspacedPostcode.area()); + } else { + // Any space indicates incode/outcode + const testArea = postcode.match(/\s.*/)[0].replace(/\s/, ""); + assert.equal(p.area(), testArea); + assert.equal(downcasePostcode.area(), testArea); + assert.equal(unspacedPostcode.area(), testArea); + } + }); + done(); + }); + }); + describe("District parsing", () => { + it("should return the correct district", function(done) { + this.timeout(TIMEOUT); + testData.forEach(postcode => { + const p = new Postcode(postcode); + const downcasePostcode = new Postcode(postcode.toLowerCase()); + const unspacedPostcode = new Postcode(postcode.replace(/\s/, "")); + if (postcode.length === PC_LENGTH) { + // Since this isn't normalised in dataset, best we can do is see if normalised data matches + assert.equal(p.district(), downcasePostcode.district()); + assert.equal(p.district(), unspacedPostcode.district()); + } else { + // Any space indicates incode/outcode + const testDistrict = postcode.match(/\s.*/)[0].replace(/\s/, ""); + assert.equal(p.district(), testDistrict); + assert.equal(downcasePostcode.district(), testDistrict); + assert.equal(unspacedPostcode.district(), testDistrict); + } + }); + done(); + }); + }); + describe("Sub-district parsing", () => { + it("should return the correct sub-district", function(done) { + this.timeout(TIMEOUT); + testData.forEach(postcode => { + const p = new Postcode(postcode); + const downcasePostcode = new Postcode(postcode.toLowerCase()); + const unspacedPostcode = new Postcode(postcode.replace(/\s/, "")); + if (postcode.length === PC_LENGTH) { + // Since this isn't normalised in dataset, best we can do is see if normalised data matches + assert.equal(p.subDistrict(), downcasePostcode.subDistrict()); + assert.equal(p.subDistrict(), unspacedPostcode.subDistrict()); + } else { + // Any space indicates incode/outcode + const testSubDistrict = postcode.match(/\s.*/)[0].replace(/\s/, ""); + assert.equal(p.subDistrict(), testSubDistrict); + assert.equal(downcasePostcode.subDistrict(), testSubDistrict); + assert.equal(unspacedPostcode.subDistrict(), testSubDistrict); + } + }); + done(); + }); + }); + describe("Sector parsing", () => { + it("should return the correct sector", function(done) { + this.timeout(TIMEOUT); + testData.forEach(postcode => { + const p = new Postcode(postcode); + const downcasePostcode = new Postcode(postcode.toLowerCase()); + const unspacedPostcode = new Postcode(postcode.replace(/\s/, "")); + if (postcode.length === PC_LENGTH) { + // Since this isn't normalised in dataset, best we can do is see if normalised data matches + assert.equal(p.sector(), downcasePostcode.sector()); + assert.equal(p.sector(), unspacedPostcode.sector()); + } else { + // Any space indicates incode/outcode + const testSector = postcode.match(/\s.*/)[0].replace(/\s/, ""); + assert.equal(p.sector(), testSector); + assert.equal(downcasePostcode.sector(), testSector); + assert.equal(unspacedPostcode.sector(), testSector); + } + }); + done(); + }); + }); + describe("Unit parsing", () => { + it("should return the correct unit", function(done) { + this.timeout(TIMEOUT); + testData.forEach(postcode => { + const p = new Postcode(postcode); + const downcasePostcode = new Postcode(postcode.toLowerCase()); + const unspacedPostcode = new Postcode(postcode.replace(/\s/, "")); + if (postcode.length === PC_LENGTH) { + // Since this isn't normalised in dataset, best we can do is see if normalised data matches + assert.equal(p.unit(), downcasePostcode.unit()); + assert.equal(p.unit(), unspacedPostcode.unit()); + } else { + // Any space indicates incode/outcode + const testUnit = postcode.match(/\s.*/)[0].replace(/\s/, ""); + assert.equal(p.unit(), testUnit); + assert.equal(downcasePostcode.unit(), testUnit); + assert.equal(unspacedPostcode.unit(), testUnit); + } + }); + done(); + }); + }); +}); + +/* tslint:disable:no-invalid-this */ From b7e615ab98659b5ab859160d3c53a246a3677189 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Mon, 8 Apr 2019 15:44:59 +0000 Subject: [PATCH 09/38] Port to typescript --- index.js | 106 ----------------------------------- lib/index.ts | 119 ++++++++++++++++++++++++++++++++++++++++ package-lock.json | 6 ++ package.json | 6 +- test/exhaustive_unit.ts | 2 +- test/unit.ts | 2 +- tsconfig.json | 9 +++ 7 files changed, 140 insertions(+), 110 deletions(-) delete mode 100644 index.js create mode 100644 lib/index.ts create mode 100644 tsconfig.json diff --git a/index.js b/index.js deleted file mode 100644 index a17a555..0000000 --- a/index.js +++ /dev/null @@ -1,106 +0,0 @@ -"use strict"; - -var validationRegex = /^[a-z]{1,2}\d[a-z\d]?\s*\d[a-z]{2}$/i, - incodeRegex = /\d[a-z]{2}$/i, - validOutcodeRegex = /^[a-z]{1,2}\d[a-z\d]?$/i, - areaRegex = /^[a-z]{1,2}/i, - districtSplitRegex = /^([a-z]{1,2}\d)([a-z])$/i, - sectorRegex = /^[a-z]{1,2}\d[a-z\d]?\s*\d/i, - unitRegex = /[a-z]{2}$/i; - -function isValidPostcode(postcode) { - return !!postcode.match(validationRegex); -} - -function parseOutcode(postcode) { - return postcode.replace(incodeRegex, "").replace(/\s+/, ""); -} - -function parseIncode(postcode) { - return postcode.match(incodeRegex)[0]; -} - -function parseArea(postcode) { - return postcode.match(areaRegex)[0]; -} - -function parseSector(postcode) { - return postcode.match(sectorRegex)[0]; -} - -function parseUnit(postcode) { - return postcode.match(unitRegex)[0]; -} - -function Postcode(rawPostcode) { - this._raw = rawPostcode; - this._valid = isValidPostcode(rawPostcode); -} - -Postcode.validOutcode = function(outcode) { - return !!outcode.match(validOutcodeRegex); -}; - -Postcode.prototype.valid = function() { - return this._valid; -}; - -Postcode.prototype.incode = function() { - if (!this._valid) return null; - if (this._incode) return this._incode; - this._incode = parseIncode(this._raw).toUpperCase(); - return this._incode; -}; - -Postcode.prototype.outcode = function() { - if (!this._valid) return null; - if (this._outcode) return this._outcode; - this._outcode = parseOutcode(this._raw).toUpperCase(); - return this._outcode; -}; - -Postcode.prototype.area = function() { - if (!this._valid) return null; - if (this._area) return this._area; - this._area = parseArea(this._raw).toUpperCase(); - return this._area; -}; - -Postcode.prototype.district = function() { - if (!this._valid) return null; - if (this._district) return this._district; - var outcode = this.outcode(); - var split = outcode.match(districtSplitRegex); - this._district = split ? split[1] : outcode; - return this._district; -}; - -Postcode.prototype.subDistrict = function() { - if (!this._valid) return null; - if (this._subDistrict) return this._subDistrict; - var outcode = this.outcode(); - var split = outcode.match(districtSplitRegex); - this._subDistrict = split ? outcode : null; - return this._subDistrict; -}; - -Postcode.prototype.sector = function() { - if (!this._valid) return null; - if (this._sector) return this._sector; - this._sector = parseSector(this.normalise()).toUpperCase(); - return this._sector; -}; - -Postcode.prototype.unit = function() { - if (!this._valid) return null; - if (this._unit) return this._unit; - this._unit = parseUnit(this._raw).toUpperCase(); - return this._unit; -}; - -Postcode.prototype.normalise = function() { - if (!this._valid) return null; - return [this.outcode(), " ", this.incode()].join(""); -}; - -module.exports = Postcode; diff --git a/lib/index.ts b/lib/index.ts new file mode 100644 index 0000000..5bc4575 --- /dev/null +++ b/lib/index.ts @@ -0,0 +1,119 @@ +export default class Postcode { + private _raw: string; + private _valid: boolean; + private _incode: string | void; + private _outcode: string | void; + private _area: string | void; + private _unit: string | void; + private _district: string | void; + private _subDistrict: string | void; + private _sector: string | void; + + constructor(postcode) { + this._raw = postcode; + this._valid = isValidPostcode(postcode); + } + + static validOutcode(outcode: string): boolean { + return outcode.match(validOutcodeRegex) !== null; + } + + valid(): boolean { + return this._valid; + } + + incode(): string | null { + if (!this._valid) return null; + if (this._incode) return this._incode; + this._incode = parseIncode(this._raw).toUpperCase(); + return this._incode; + } + + outcode(): string | null { + if (!this._valid) return null; + if (this._outcode) return this._outcode; + this._outcode = parseOutcode(this._raw).toUpperCase(); + return this._outcode; + } + + area(): string | null { + if (!this._valid) return null; + if (this._area) return this._area; + this._area = parseArea(this._raw).toUpperCase(); + return this._area; + } + + district(): string | null { + if (!this._valid) return null; + if (this._district) return this._district; + const outcode = this.outcode(); + if (outcode === undefined) return null; + const split = outcode.match(districtSplitRegex); + this._district = split ? split[1] : outcode; + return this._district; + } + + subDistrict(): string | null { + if (!this._valid) return null; + if (this._subDistrict) return this._subDistrict; + const outcode = this.outcode(); + const split = outcode.match(districtSplitRegex); + this._subDistrict = split ? outcode : null; + return this._subDistrict; + } + + sector(): string | null { + if (!this._valid) return null; + if (this._sector) return this._sector; + this._sector = parseSector(this.normalise()).toUpperCase(); + return this._sector; + } + + unit(): string | null { + if (!this._valid) return null; + if (this._unit) return this._unit; + this._unit = parseUnit(this._raw).toUpperCase(); + return this._unit; + } + + normalise(): string | null { + if (!this._valid) return null; + return `${this.outcode()} ${this.incode()}`; + } +} + +const validationRegex = /^[a-z]{1,2}\d[a-z\d]?\s*\d[a-z]{2}$/i; +const incodeRegex = /\d[a-z]{2}$/i; +const validOutcodeRegex = /^[a-z]{1,2}\d[a-z\d]?$/i; +const areaRegex = /^[a-z]{1,2}/i; +const districtSplitRegex = /^([a-z]{1,2}\d)([a-z])$/i; +const sectorRegex = /^[a-z]{1,2}\d[a-z\d]?\s*\d/i; +const unitRegex = /[a-z]{2}$/i; + +interface Validator { + (input: string): boolean; +} + +const isValidPostcode: Validator = postcode => + postcode.match(validationRegex) !== null; + +interface Parser { + (postcode: string): string; +} +const parseOutcode: Parser = postcode => { + return postcode.replace(incodeRegex, "").replace(/\s+/, ""); +}; + +const parseIncode: Parser = postcode => { + return postcode.match(incodeRegex)[0]; +}; + +const parseArea: Parser = postcode => { + return postcode.match(areaRegex)[0]; +}; + +const parseSector: Parser = postcode => { + return postcode.match(sectorRegex)[0]; +}; + +const parseUnit: Parser = postcode => postcode.match(unitRegex)[0]; diff --git a/package-lock.json b/package-lock.json index 84a201d..265951a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -135,6 +135,12 @@ "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", "dev": true }, + "@types/node": { + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.0.tgz", + "integrity": "sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng==", + "dev": true + }, "ajv": { "version": "6.9.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz", diff --git a/package.json b/package.json index 5979cbd..9136082 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,8 @@ "name": "postcode", "version": "1.0.1", "description": "UK Postcode helper methods", - "main": "index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", "dependencies": {}, "prettier": {}, "devDependencies": { @@ -35,7 +36,8 @@ ] }, "files": [ - "index.js" + "dist", + "example.js" ], "runkitExampleFilename": "example.js", "nyc": { diff --git a/test/exhaustive_unit.ts b/test/exhaustive_unit.ts index 2a7f763..a5c684b 100644 --- a/test/exhaustive_unit.ts +++ b/test/exhaustive_unit.ts @@ -9,7 +9,7 @@ import { createGunzip } from "zlib"; const TIMEOUT = 60000; const PC_LENGTH = 7; -import Postcode from "../index"; +import Postcode from "../lib/index"; describe("Exhaustive postcode test", () => { const testData = []; diff --git a/test/unit.ts b/test/unit.ts index 949df75..bcfdd15 100644 --- a/test/unit.ts +++ b/test/unit.ts @@ -1,7 +1,7 @@ import { assert } from "chai"; import { readFile } from "fs"; import { join } from "path"; -import Postcode from "../index"; +import Postcode from "../lib/index"; const dataDir = join(__dirname, "/data"); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f22d9ed --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@cablanchard/tsconfig", + "compilerOptions": { + "lib": ["ES6"], + "strict": false, + "outFile": "dist/index.js" + }, + "include": ["lib/**/*"] +} From 47597a380b30d21351772d2b93a32be3070c7054 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sat, 13 Apr 2019 09:12:55 +0000 Subject: [PATCH 10/38] Switch to csv-parse from csv; Add build script --- package-lock.json | 17 +++++++++++++++-- package.json | 4 +++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 265951a..4ff0e0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -129,6 +129,14 @@ "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", "dev": true }, + "@types/csv-parse": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@types/csv-parse/-/csv-parse-1.1.12.tgz", + "integrity": "sha512-p6uZznjJOcFaymduLYf45ik28IYzChnkt+ofJOWa16bb2JRCHdxs/ai03q6raizCc5JuunVsbgtlDxfu9y2Nag==", + "requires": { + "@types/node": "*" + } + }, "@types/mocha": { "version": "5.2.6", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", @@ -138,8 +146,7 @@ "@types/node": { "version": "11.13.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.0.tgz", - "integrity": "sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng==", - "dev": true + "integrity": "sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng==" }, "ajv": { "version": "6.9.2", @@ -717,6 +724,12 @@ } } }, + "csv-parse": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.4.0.tgz", + "integrity": "sha512-rvoRlZxu6Ap8jOkhoQQeI+5y/eTPqEIVk20bxZmo81k2ArUiNLv8LAERTEKarOQuC7BKXGyzSqAKWox115bg7A==", + "dev": true + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", diff --git a/package.json b/package.json index 9136082..63d6946 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "dependencies": {}, "prettier": {}, "devDependencies": { + "@types/csv-parse": "~1.1.12", "@cablanchard/tsconfig": "0.0.1", "@cablanchard/tslint": "0.0.1", "@types/chai": "~4.1.7", @@ -14,7 +15,7 @@ "@types/node": "~11.13.0", "chai": "~4.2.0", "coveralls": "~3.0.2", - "csv": "~5.1.1", + "csv-parse": "~4.4.0", "mocha": "~6.0.0", "nyc": "~13.3.0", "prettier": "~1.16.4", @@ -53,6 +54,7 @@ "scripts": { "test": "NODE_ENV=test node_modules/.bin/nyc node_modules/.bin/mocha", "lint": "node_modules/.bin/tslint -c tslint.json -p tsconfig.json", + "build": "./node_modules/.bin/tsc", "coverage": "node_modules/.bin/nyc report --reporter=text-lcov | node_modules/.bin/coveralls || true" }, "repository": { From fd9c12f503ff7c5a6aad74cd0a4ec45dd30c8989 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sat, 13 Apr 2019 09:13:26 +0000 Subject: [PATCH 11/38] Enable strict compilation --- lib/index.ts | 66 ++++++++++++++++++++++++++--------------- test/exhaustive_unit.ts | 36 +++++++++++++++------- test/unit.ts | 17 +++++++++-- tsconfig.json | 3 +- 4 files changed, 84 insertions(+), 38 deletions(-) diff --git a/lib/index.ts b/lib/index.ts index 5bc4575..177e479 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,15 +1,15 @@ -export default class Postcode { +class Postcode { private _raw: string; private _valid: boolean; - private _incode: string | void; - private _outcode: string | void; - private _area: string | void; - private _unit: string | void; - private _district: string | void; - private _subDistrict: string | void; - private _sector: string | void; - - constructor(postcode) { + private _incode?: string | null; + private _outcode?: string | null; + private _area?: string | null; + private _unit?: string | null; + private _district?: string | null; + private _subDistrict?: string | null; + private _sector?: string | null; + + constructor(postcode: string) { this._raw = postcode; this._valid = isValidPostcode(postcode); } @@ -25,21 +25,21 @@ export default class Postcode { incode(): string | null { if (!this._valid) return null; if (this._incode) return this._incode; - this._incode = parseIncode(this._raw).toUpperCase(); + this._incode = nullOrUpperCase(parseIncode(this._raw)); return this._incode; } outcode(): string | null { if (!this._valid) return null; if (this._outcode) return this._outcode; - this._outcode = parseOutcode(this._raw).toUpperCase(); + this._outcode = nullOrUpperCase(parseOutcode(this._raw)); return this._outcode; } area(): string | null { if (!this._valid) return null; if (this._area) return this._area; - this._area = parseArea(this._raw).toUpperCase(); + this._area = nullOrUpperCase(parseArea(this._raw)); return this._area; } @@ -47,9 +47,9 @@ export default class Postcode { if (!this._valid) return null; if (this._district) return this._district; const outcode = this.outcode(); - if (outcode === undefined) return null; + if (outcode === null) return null; const split = outcode.match(districtSplitRegex); - this._district = split ? split[1] : outcode; + this._district = split !== null ? split[1] : outcode; return this._district; } @@ -57,22 +57,24 @@ export default class Postcode { if (!this._valid) return null; if (this._subDistrict) return this._subDistrict; const outcode = this.outcode(); + if (outcode === null) return null; const split = outcode.match(districtSplitRegex); - this._subDistrict = split ? outcode : null; + this._subDistrict = split !== null ? outcode : null; return this._subDistrict; } sector(): string | null { - if (!this._valid) return null; if (this._sector) return this._sector; - this._sector = parseSector(this.normalise()).toUpperCase(); + const normalised = this.normalise(); + if (normalised === null) return null; + this._sector = parseSector(normalised); return this._sector; } unit(): string | null { if (!this._valid) return null; if (this._unit) return this._unit; - this._unit = parseUnit(this._raw).toUpperCase(); + this._unit = nullOrUpperCase(parseUnit(this._raw)); return this._unit; } @@ -98,22 +100,38 @@ const isValidPostcode: Validator = postcode => postcode.match(validationRegex) !== null; interface Parser { - (postcode: string): string; + (postcode: string): string | null; } const parseOutcode: Parser = postcode => { return postcode.replace(incodeRegex, "").replace(/\s+/, ""); }; const parseIncode: Parser = postcode => { - return postcode.match(incodeRegex)[0]; + const match = postcode.match(incodeRegex); + if (match === null) return null; + return match[0]; }; const parseArea: Parser = postcode => { - return postcode.match(areaRegex)[0]; + const match = postcode.match(areaRegex); + if (match === null) return null; + return match[0]; }; const parseSector: Parser = postcode => { - return postcode.match(sectorRegex)[0]; + const match = postcode.match(sectorRegex); + if (match === null) return null; + return match[0]; +}; + +const parseUnit: Parser = postcode => { + const match = postcode.match(unitRegex); + if (match === null) return null; + return match[0]; +}; + +const nullOrUpperCase = (s: string | null): string | null => { + return s === null ? null : s.toUpperCase(); }; -const parseUnit: Parser = postcode => postcode.match(unitRegex)[0]; +export = Postcode; diff --git a/test/exhaustive_unit.ts b/test/exhaustive_unit.ts index a5c684b..dbaefeb 100644 --- a/test/exhaustive_unit.ts +++ b/test/exhaustive_unit.ts @@ -2,7 +2,7 @@ import { assert } from "chai"; import { createReadStream } from "fs"; -import { parse } from "csv"; +import parse from "csv-parse"; import { resolve } from "path"; import { createGunzip } from "zlib"; @@ -11,8 +11,10 @@ const PC_LENGTH = 7; import Postcode from "../lib/index"; +type CsvRecord = [string]; + describe("Exhaustive postcode test", () => { - const testData = []; + const testData: string[] = []; before(function(done) { this.timeout(TIMEOUT); @@ -23,7 +25,7 @@ describe("Exhaustive postcode test", () => { createReadStream(inputFile) .pipe(createGunzip()) .pipe(parse({ delimiter: "," })) - .on("data", data => testData.push(data[0])) + .on("data", (data: CsvRecord) => testData.push(data[0])) .on("error", done) .on("end", done); }); @@ -81,7 +83,9 @@ describe("Exhaustive postcode test", () => { assert.equal(p.incode(), unspacedPostcode.incode()); } else { // Any space indicates incode/outcode - const testIncode = postcode.match(/.*\s/)[0].replace(/\s/, ""); + const match = postcode.match(/.*\s/); + if (match === null) throw new Error("null detected"); + const testIncode = match[0].replace(/\s/, ""); assert.equal(p.incode(), testIncode); assert.equal(downcasePostcode.incode(), testIncode); assert.equal(unspacedPostcode.incode(), testIncode); @@ -104,7 +108,9 @@ describe("Exhaustive postcode test", () => { assert.equal(p.outcode(), unspacedPostcode.outcode()); } else { // Any space indicates incode/outcode - const testIncode = postcode.match(/\s.*/)[0].replace(/\s/, ""); + const match = postcode.match(/\s.*/); + if (match === null) throw new Error("null detected"); + const testIncode = match[0].replace(/\s/, ""); assert.equal(p.outcode(), testIncode); assert.equal(downcasePostcode.outcode(), testIncode); assert.equal(unspacedPostcode.outcode(), testIncode); @@ -126,7 +132,9 @@ describe("Exhaustive postcode test", () => { assert.equal(p.area(), unspacedPostcode.area()); } else { // Any space indicates incode/outcode - const testArea = postcode.match(/\s.*/)[0].replace(/\s/, ""); + const match = postcode.match(/\s.*/); + if (match === null) throw new Error("null detected"); + const testArea = match[0].replace(/\s/, ""); assert.equal(p.area(), testArea); assert.equal(downcasePostcode.area(), testArea); assert.equal(unspacedPostcode.area(), testArea); @@ -148,7 +156,9 @@ describe("Exhaustive postcode test", () => { assert.equal(p.district(), unspacedPostcode.district()); } else { // Any space indicates incode/outcode - const testDistrict = postcode.match(/\s.*/)[0].replace(/\s/, ""); + const match = postcode.match(/\s.*/); + if (match === null) throw new Error("null detected"); + const testDistrict = match[0].replace(/\s/, ""); assert.equal(p.district(), testDistrict); assert.equal(downcasePostcode.district(), testDistrict); assert.equal(unspacedPostcode.district(), testDistrict); @@ -170,7 +180,9 @@ describe("Exhaustive postcode test", () => { assert.equal(p.subDistrict(), unspacedPostcode.subDistrict()); } else { // Any space indicates incode/outcode - const testSubDistrict = postcode.match(/\s.*/)[0].replace(/\s/, ""); + const match = postcode.match(/\s.*/); + if (match === null) throw new Error("null detected"); + const testSubDistrict = match[0].replace(/\s/, ""); assert.equal(p.subDistrict(), testSubDistrict); assert.equal(downcasePostcode.subDistrict(), testSubDistrict); assert.equal(unspacedPostcode.subDistrict(), testSubDistrict); @@ -192,7 +204,9 @@ describe("Exhaustive postcode test", () => { assert.equal(p.sector(), unspacedPostcode.sector()); } else { // Any space indicates incode/outcode - const testSector = postcode.match(/\s.*/)[0].replace(/\s/, ""); + const match = postcode.match(/\s.*/); + if (match === null) throw new Error("null detected"); + const testSector = match[0].replace(/\s/, ""); assert.equal(p.sector(), testSector); assert.equal(downcasePostcode.sector(), testSector); assert.equal(unspacedPostcode.sector(), testSector); @@ -214,7 +228,9 @@ describe("Exhaustive postcode test", () => { assert.equal(p.unit(), unspacedPostcode.unit()); } else { // Any space indicates incode/outcode - const testUnit = postcode.match(/\s.*/)[0].replace(/\s/, ""); + const match = postcode.match(/\s.*/); + if (match === null) throw new Error("null detected"); + const testUnit = match[0].replace(/\s/, ""); assert.equal(p.unit(), testUnit); assert.equal(downcasePostcode.unit(), testUnit); assert.equal(unspacedPostcode.unit(), testUnit); diff --git a/test/unit.ts b/test/unit.ts index bcfdd15..7038eb2 100644 --- a/test/unit.ts +++ b/test/unit.ts @@ -28,9 +28,19 @@ const loadFixtures = (fileName: string): Promise => { }); }; +type Method = + | "normalise" + | "incode" + | "outcode" + | "area" + | "district" + | "unit" + | "sector" + | "subDistrict"; + interface TestMethodOptions { tests: TestCase[]; - method: string; + method: Method; } const testMethod = (options: TestMethodOptions): void => { @@ -45,7 +55,10 @@ const testMethod = (options: TestMethodOptions): void => { describe("Postcode#Valid", async () => { it("should return true for postcodes that look correct", async () => { const { tests } = await loadFixtures("validation.json"); - testMethod({ method: "valid", tests }); + tests.forEach(({ base, expected }) => { + const p = new Postcode(base); + assert.equal(p.valid(), Boolean(expected)); + }); }); }); diff --git a/tsconfig.json b/tsconfig.json index f22d9ed..4086db4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,8 +2,7 @@ "extends": "@cablanchard/tsconfig", "compilerOptions": { "lib": ["ES6"], - "strict": false, - "outFile": "dist/index.js" + "outDir": "dist" }, "include": ["lib/**/*"] } From 3ba63a2f6029904482f85df57e4d1c6ee40b5356 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sat, 13 Apr 2019 10:23:05 +0000 Subject: [PATCH 12/38] Fix link to repo --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 63d6946..6e0dcdb 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/ideal-postcodes/postcode" + "url": "https://github.com/ideal-postcodes/postcode.git" }, "keywords": [ "uk", From 417ef5111f08e547d6d42b6e3755f63c14c5a97f Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sat, 13 Apr 2019 10:26:13 +0000 Subject: [PATCH 13/38] Updated readme - Document new methods - General cleanup --- README.md | 134 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 118 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 5250600..28cc72d 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,123 @@ -[![CircleCI](https://circleci.com/gh/ideal-postcodes/postcode.svg?style=svg)](https://circleci.com/gh/ideal-postcodes/postcode) [![Coverage Status](https://coveralls.io/repos/github/ideal-postcodes/postcode/badge.svg?branch=master)](https://coveralls.io/github/ideal-postcodes/postcode?branch=master) ![Dependencies](https://img.shields.io/david/ideal-postcodes/postcode.svg?style=flat) ![Size](https://img.shields.io/bundlephobia/min/postcode.svg?style=flat) +

+ Postcode.js +

-# Postcode +> Validate & parse UK postcodes +[![CircleCI](https://circleci.com/gh/ideal-postcodes/postcode.svg?style=svg)](https://circleci.com/gh/ideal-postcodes/postcode) +[![Coverage Status](https://coveralls.io/repos/github/ideal-postcodes/postcode/badge.svg?branch=master)](https://coveralls.io/github/ideal-postcodes/postcode?branch=master) +![Dependencies](https://img.shields.io/david/ideal-postcodes/postcode.svg?style=flat) +![Size](https://img.shields.io/bundlephobia/min/postcode.svg?style=flat) +![Downloads](https://img.shields.io/npm/dm/postcode.svg) [![Try postcode on RunKit](https://badge.runkitcdn.com/postcode.svg)](https://npm.runkit.com/postcode) -Utility methods for UK Postcodes. +Utility methods for UK Postcodes, including validating the shape of a postcode, extracting postcode elements (like incodes, outcodes, areas and [more](#Definitions)). -Included is a test suite that tests against all postcodes listed in the Ordnance Survey's postcode dataset as of January 2014. +Tested against ~1.7 million postcodes on ONSPD. + +## Features + +- [Check](#Validate) whether a postcode conforms to the [correct format](https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Formatting) +- [Extract](#Extract) useful elements of a postcode like incode, outcode, sector +- [Single purpose static methods](#Static Methods) +- Tested against a list of ~1.7 million postcodes listed on ONS Postcode Directory + +## Links + +- [API Documentation](https://ideal-postcodes.github.io/postcode/) +- [Try postcode.js on RunKit](https://npm.runkit.com/postcode) +- [Postcode element definitions](#Definitions) +- [Caveat on postcode validation](#Note on Postcode Validation) ## Getting Started -Install with `npm install postcode` +### Installation + +```bash +npm install postcode +``` + +### Wield + +```javascript +import Postcode from "postcode"; +``` + +### Validate + +```javascript +Postcode.isValid("AA1 1AB"); # => true +``` + +### Parse + +Pass a string to `Postcode.parse`. This will return a valid or invalid postcode instance which can be easily destructured. + +#### Valid Postcode + +``` +const { + normalised, // => "SW1A 2AA" + outcode, // => "SW1A" + incode, // => "2AA" + area, // => "SW" + district, // => "SW1" + unit, // => "AA" + sector, // => "SW1A 2" + subDistrict, // => "SW1A" + valid, // => true +} = Postcode.parse("Sw1A 2aa "); +``` + +#### Invalid postcode -Create an instance of Postcode to perform utility methods, like so +``` +const { + normalised, // => undefined + outcode, // => undefined + incode, // => undefined + area, // => undefined + district, // => undefined + unit, // => undefined + sector, // => undefined + subDistrict, // => undefined + valid, // => false +} = Postcode.parse(" Oh no, ): "); +``` + +#### Accessor Overview + +| Postcode | .outcode | .incode | .area | .district | .subDistrict | .sector | .unit | +|----------|----------|---------|-------|-----------|--------------|---------|-------| +| AA9A 9AA | AA9A | 9AA | AA | AA9 | AA9A | AA9A 9 | AA | +| A9A 9AA | A9A | 9AA | A | A9 | A9A | A9A 9 | AA | +| A9 9AA | A9 | 9AA | A | A9 | `undefined` | A9 9 | AA | +| A99 9AA | A99 | 9AA | A | A99 | `undefined` | A99 9 | AA | +| AA9 9AA | AA9 | 9AA | AA | AA9 | `undefined` | AA9 9 | AA | +| AA99 9AA | AA99 | 9AA | AA | AA99 | `undefined` | AA99 9 | AA | + +### Static Methods + +If you're just after a single value, you would be better served by calling a static method on `Postcode`. + +```javascript +Postcode.isValid("Sw1A 2aa"); // => true + +Postcode.toNormalised("Sw1A 2aa"); // => "SW1A 2AA" +Postcode.toOutcode("Sw1A 2aa"); // => "SW1A" +Postcode.toIncode("Sw1A 2aa"); // => "2AA" +Postcode.toArea("Sw1A 2aa"); // => "AA" +Postcode.toDistrict("Sw1A 2aa"); // => "SW1" +Postcode.toSubDistrict("Sw1A 2aa"); // => "SW1A" +Postcode.toSector("Sw1A 2aa"); // => "SW1A 2" +Postcode.toUnit("Sw1A 2aa"); // => "AA" +``` + +### Older API + +Below documents the old validation API, which continues to be supported. + +Create an instance of Postcode to perform utility methods, like so: ```javascript const Postcode = require("postcode"); @@ -91,23 +196,20 @@ The postcode sector is made up of the postcode district, the single space, and t The postcode unit is two characters added to the end of the postcode sector. Each postcode unit generally represents a street, part of a street, a single address, a group of properties, a single property, a sub-section of the property, an individual organisation or (for instance Driver and Vehicle Licensing Agency) a subsection of the organisation. The level of discrimination is often based on the amount of mail received by the premises or business. Examples of postcode units include "NY" (from "SW1W 0NY"), "GZ" (from "PO16 7GZ"), "HF" (from "GU16 7HF"), or "JQ" (from "L1 8JQ"). -Sources: - -- https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Formatting -- https://en.wikipedia.org/wiki/London_postal_district#Numbered_divisions - -## Testing - -```npm test``` - ## Note on Postcode Validation Postcodes cannot be validated just with a regular expression. Proper postcode validation requires having a full list of postcodes to check against. Relying on a regex will produce false postives/negatives. A complete list of Postcodes can be obtained from the ONS Postcode Directory, which is updated every 3 months. +## Testing + +```bash +npm test +``` + ## License MIT -Contains Ordnance Survey Data © Crown Copyright & Database Right 2014 +Contains Ordnance Survey Data © Crown Copyright & Database Right From c075fc36b7dc68531ba994446fd71640684e267a Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sat, 13 Apr 2019 10:26:37 +0000 Subject: [PATCH 14/38] Update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87ced09..3b1cee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ Any changes, including backwards incompatible changes will be listed here +## 1.1.0 (12/02/2019) + +- Ported to typescript (now exports typings) +- New methods (cleaner instance methods, more static methods) +- Updated documentation +- Added benchmarks + ## 1.0.1 (12/02/2019) - Add runkit example From 81db2debc577f78ffc26a4d986bc9473883cf0b3 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sat, 13 Apr 2019 10:30:57 +0000 Subject: [PATCH 15/38] Add typedoc and script --- package-lock.json | 305 ++++++++++++++++++++++++++++++++++++++-------- package.json | 4 +- 2 files changed, 260 insertions(+), 49 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4ff0e0a..65730da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -133,10 +133,70 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/@types/csv-parse/-/csv-parse-1.1.12.tgz", "integrity": "sha512-p6uZznjJOcFaymduLYf45ik28IYzChnkt+ofJOWa16bb2JRCHdxs/ai03q6raizCc5JuunVsbgtlDxfu9y2Nag==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/fs-extra": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.5.tgz", + "integrity": "sha512-w7iqhDH9mN8eLClQOYTkhdYUOSpp25eXxfc6VbFOGtzxW34JcvctH2bKjj4jD4++z4R5iO5D+pg48W2e03I65A==", + "dev": true, "requires": { "@types/node": "*" } }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/handlebars": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.1.0.tgz", + "integrity": "sha512-gq9YweFKNNB1uFK71eRqsd4niVkXrxHugqWFQkeLRJvGjnxsLr16bYtcsG4tOFwmYi0Bax+wCkbf1reUfdl4kA==", + "dev": true, + "requires": { + "handlebars": "*" + } + }, + "@types/highlight.js": { + "version": "9.12.3", + "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz", + "integrity": "sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==", + "dev": true + }, + "@types/lodash": { + "version": "4.14.123", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.123.tgz", + "integrity": "sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==", + "dev": true + }, + "@types/marked": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.4.2.tgz", + "integrity": "sha512-cDB930/7MbzaGF6U3IwSQp6XBru8xWajF5PV2YZZeV8DyiliTuld11afVztGI9+yJZ29il5E+NpGA6ooV/Cjkg==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, "@types/mocha": { "version": "5.2.6", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", @@ -146,7 +206,18 @@ "@types/node": { "version": "11.13.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.0.tgz", - "integrity": "sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng==" + "integrity": "sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng==", + "dev": true + }, + "@types/shelljs": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-UNACC6scKFVljWEvO3rHBkbbKXu3QkKPBOMCisxI7au9cnFK7tjOGPsKh5OjedAPLmtsKSarmk+YeehKTQSKtg==", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } }, "ajv": { "version": "6.9.2", @@ -677,53 +748,6 @@ "which": "^1.2.9" } }, - "csv": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/csv/-/csv-5.1.1.tgz", - "integrity": "sha512-gezB9D+enrh2tLj+vsAD8JyYRMIJdSMpec/Pgbb+7YRj6Q6/D12HLSwjhx+CrirRT4dESjZYXWX1JfqlV4RlTA==", - "dev": true, - "requires": { - "csv-generate": "^3.2.0", - "csv-parse": "^4.3.0", - "csv-stringify": "^5.1.2", - "stream-transform": "^1.0.8" - }, - "dependencies": { - "csv-generate": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.2.0.tgz", - "integrity": "sha512-ZdS2KrgoLxm1guL9XhuaZX223Tiorldvl9QC0M/gihcrJavNDokAp/rX3CyyRHpK+rImxEE3L47cHe7npQMkkg==", - "dev": true - }, - "csv-parse": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.3.1.tgz", - "integrity": "sha512-1V98UTtfefu8yKdYIGX1LFhfE2yMllveq2uCBay5y4ybfTzvW6I4M6r8Yc2YnKJdJBUig5ksEMh/bLqKg4vEMQ==", - "dev": true - }, - "csv-stringify": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.3.0.tgz", - "integrity": "sha512-VMYPbE8zWz475smwqb9VbX9cj0y4J0PBl59UdcqzLkzXHZZ8dh4Rmbb0ZywsWEtUml4A96Hn7Q5MW9ppVghYzg==", - "dev": true, - "requires": { - "lodash.get": "~4.4.2" - } - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "stream-transform": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-1.0.8.tgz", - "integrity": "sha512-1q+dL790Ps0NV33rISMq9OLtfDA9KMJZdo1PHZXE85orrWsM4FAh8CVyAOTHO0rhyeM138KNPngBPrx33bFsxw==", - "dev": true - } - } - }, "csv-parse": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.4.0.tgz", @@ -1167,6 +1191,17 @@ "map-cache": "^0.2.2" } }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1253,12 +1288,38 @@ "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", "dev": true }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, + "handlebars": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz", + "integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -1351,6 +1412,12 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "highlight.js": { + "version": "9.15.6", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.6.tgz", + "integrity": "sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==", + "dev": true + }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -1393,6 +1460,12 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", @@ -1659,6 +1732,15 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -1753,6 +1835,12 @@ "object-visit": "^1.0.0" } }, + "marked": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.4.0.tgz", + "integrity": "sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw==", + "dev": true + }, "mem": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", @@ -1945,6 +2033,12 @@ "to-regex": "^3.0.1" } }, + "neo-async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -3101,6 +3195,24 @@ "wrappy": "1" } }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, "os-locale": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", @@ -3208,6 +3320,12 @@ "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==", "dev": true }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "psl": { "version": "1.1.31", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", @@ -3236,6 +3354,15 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -3400,6 +3527,17 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shelljs": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -3812,12 +3950,71 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, + "typedoc": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.14.2.tgz", + "integrity": "sha512-aEbgJXV8/KqaVhcedT7xG6d2r+mOvB5ep3eIz1KuB5sc4fDYXcepEEMdU7XSqLFO5hVPu0nllHi1QxX2h/QlpQ==", + "dev": true, + "requires": { + "@types/fs-extra": "^5.0.3", + "@types/handlebars": "^4.0.38", + "@types/highlight.js": "^9.12.3", + "@types/lodash": "^4.14.110", + "@types/marked": "^0.4.0", + "@types/minimatch": "3.0.3", + "@types/shelljs": "^0.8.0", + "fs-extra": "^7.0.0", + "handlebars": "^4.0.6", + "highlight.js": "^9.13.1", + "lodash": "^4.17.10", + "marked": "^0.4.0", + "minimatch": "^3.0.0", + "progress": "^2.0.0", + "shelljs": "^0.8.2", + "typedoc-default-themes": "^0.5.0", + "typescript": "3.2.x" + }, + "dependencies": { + "typescript": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz", + "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==", + "dev": true + } + } + }, + "typedoc-default-themes": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz", + "integrity": "sha1-bcJDPnjti+qOiHo6zeLzF4W9Yic=", + "dev": true + }, "typescript": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.2.tgz", "integrity": "sha512-Og2Vn6Mk7JAuWA1hQdDQN/Ekm/SchX80VzLhjKN9ETYrIepBFAd8PkOdOTK2nKt0FCkmMZKBJvQ1dV1gIxPu/A==", "dev": true }, + "uglify-js": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.4.tgz", + "integrity": "sha512-GpKo28q/7Bm5BcX9vOu4S46FwisbPbAmkkqPnGIpKvKTM96I85N6XHQV+k4I6FA2wxgLhcsSyHoNhzucwCflvA==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -3853,6 +4050,12 @@ } } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -3955,6 +4158,12 @@ "string-width": "^1.0.2 || 2" } }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", diff --git a/package.json b/package.json index 6e0dcdb..8e8d0c4 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,10 @@ "dependencies": {}, "prettier": {}, "devDependencies": { - "@types/csv-parse": "~1.1.12", "@cablanchard/tsconfig": "0.0.1", "@cablanchard/tslint": "0.0.1", "@types/chai": "~4.1.7", + "@types/csv-parse": "~1.1.12", "@types/mocha": "~5.2.6", "@types/node": "~11.13.0", "chai": "~4.2.0", @@ -22,6 +22,7 @@ "source-map-support": "~0.5.11", "ts-node": "~8.0.3", "tslint": "~5.15.0", + "typedoc": "~0.14.2", "typescript": "~3.4.2" }, "mocha": { @@ -54,6 +55,7 @@ "scripts": { "test": "NODE_ENV=test node_modules/.bin/nyc node_modules/.bin/mocha", "lint": "node_modules/.bin/tslint -c tslint.json -p tsconfig.json", + "docs": "./node_modules/.bin/typedoc --mode file --excludePrivate --hideGenerator --excludeExternals --target ES5 --out docs/ --name 'Postcode.js' --theme minimal lib/", "build": "./node_modules/.bin/tsc", "coverage": "node_modules/.bin/nyc report --reporter=text-lcov | node_modules/.bin/coveralls || true" }, From acf9378404839e5aae894158ea8008f4ca87c69d Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 14 Apr 2019 09:25:37 +0000 Subject: [PATCH 16/38] Add linter to tests --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8e8d0c4..64a88b4 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "all": true }, "scripts": { - "test": "NODE_ENV=test node_modules/.bin/nyc node_modules/.bin/mocha", + "test": "npm run lint && NODE_ENV=test node_modules/.bin/nyc node_modules/.bin/mocha", "lint": "node_modules/.bin/tslint -c tslint.json -p tsconfig.json", "docs": "./node_modules/.bin/typedoc --mode file --excludePrivate --hideGenerator --excludeExternals --target ES5 --out docs/ --name 'Postcode.js' --theme minimal lib/", "build": "./node_modules/.bin/tsc", From 18b06cf4f7925401bd19fc4c76083995863ba227 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 14 Apr 2019 09:39:53 +0000 Subject: [PATCH 17/38] Move out fixture logic --- test/unit.ts | 28 +--------------------------- test/util/helper.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 27 deletions(-) create mode 100644 test/util/helper.ts diff --git a/test/unit.ts b/test/unit.ts index 7038eb2..eed5b70 100644 --- a/test/unit.ts +++ b/test/unit.ts @@ -1,32 +1,6 @@ import { assert } from "chai"; -import { readFile } from "fs"; -import { join } from "path"; import Postcode from "../lib/index"; - -const dataDir = join(__dirname, "/data"); - -interface TestFixtures { - tests: TestCase[]; -} - -interface TestCase { - base: string; - expected: string; -} - -const loadFixtures = (fileName: string): Promise => { - return new Promise((resolve, reject) => { - const filePath = join(dataDir, fileName); - readFile(filePath, { encoding: "utf8" }, (error, data) => { - if (error) return reject(error); - try { - resolve(JSON.parse(data.toString())); - } catch (error) { - return reject(error); - } - }); - }); -}; +import { loadFixtures, TestCase } from "./util/helper"; type Method = | "normalise" diff --git a/test/util/helper.ts b/test/util/helper.ts new file mode 100644 index 0000000..f45cef7 --- /dev/null +++ b/test/util/helper.ts @@ -0,0 +1,27 @@ +import { join } from "path"; +import { readFile } from "fs"; + +const dataDir = join(__dirname, "../data"); + +interface TestFixtures { + tests: TestCase[]; +} + +export interface TestCase { + base: string; + expected: string; +} + +export const loadFixtures = (fileName: string): Promise => { + return new Promise((resolve, reject) => { + const filePath = join(dataDir, fileName); + readFile(filePath, { encoding: "utf8" }, (error, data) => { + if (error) return reject(error); + try { + resolve(JSON.parse(data.toString())); + } catch (error) { + return reject(error); + } + }); + }); +}; From 6c3229a7a7947b13c526aeb17bf60fa6f960385b Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 14 Apr 2019 16:57:44 +0000 Subject: [PATCH 18/38] Update design - revert to nulls for continuity - be more strict on inputs --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 28cc72d..bd96b61 100644 --- a/README.md +++ b/README.md @@ -66,21 +66,21 @@ const { sector, // => "SW1A 2" subDistrict, // => "SW1A" valid, // => true -} = Postcode.parse("Sw1A 2aa "); +} = Postcode.parse("Sw1A 2aa"); ``` #### Invalid postcode ``` const { - normalised, // => undefined - outcode, // => undefined - incode, // => undefined - area, // => undefined - district, // => undefined - unit, // => undefined - sector, // => undefined - subDistrict, // => undefined + normalised, // => null + outcode, // => null + incode, // => null + area, // => null + district, // => null + unit, // => null + sector, // => null + subDistrict, // => null valid, // => false } = Postcode.parse(" Oh no, ): "); ``` @@ -91,10 +91,10 @@ const { |----------|----------|---------|-------|-----------|--------------|---------|-------| | AA9A 9AA | AA9A | 9AA | AA | AA9 | AA9A | AA9A 9 | AA | | A9A 9AA | A9A | 9AA | A | A9 | A9A | A9A 9 | AA | -| A9 9AA | A9 | 9AA | A | A9 | `undefined` | A9 9 | AA | -| A99 9AA | A99 | 9AA | A | A99 | `undefined` | A99 9 | AA | -| AA9 9AA | AA9 | 9AA | AA | AA9 | `undefined` | AA9 9 | AA | -| AA99 9AA | AA99 | 9AA | AA | AA99 | `undefined` | AA99 9 | AA | +| A9 9AA | A9 | 9AA | A | A9 | `null` | A9 9 | AA | +| A99 9AA | A99 | 9AA | A | A99 | `null` | A99 9 | AA | +| AA9 9AA | AA9 | 9AA | AA | AA9 | `null` | AA9 9 | AA | +| AA99 9AA | AA99 | 9AA | AA | AA99 | `null` | AA99 9 | AA | ### Static Methods From eceee23792eedf40b3bb28031e5b29be0d6e7cb3 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 14 Apr 2019 17:28:37 +0000 Subject: [PATCH 19/38] Convert existing private methods to static methods --- lib/index.ts | 203 +++++++++++++++++++++++++++++++------------ test/statics.unit.ts | 117 +++++++++++++++++++++++++ 2 files changed, 264 insertions(+), 56 deletions(-) create mode 100644 test/statics.unit.ts diff --git a/lib/index.ts b/lib/index.ts index 177e479..7a01e9a 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,3 +1,136 @@ +interface Validator { + (input: string): boolean; +} + +interface Parser { + (postcode: string): string | null; +} + +/** + * Return first elem of input is RegExpMatchArray or null if input null + */ +const firstOrNull = (match: RegExpMatchArray | null): string | null => { + if (match === null) return null; + return match[0]; +}; + +const SPACE_REGEX = /\s+/gi; + +/** + * Drop all spaces and uppercase + */ +const sanitize = (s: string): string => { + return s.replace(SPACE_REGEX, "").toUpperCase(); +}; + +const matchOn = (s: string, regex: RegExp): RegExpMatchArray | null => { + return sanitize(s).match(regex); +}; + +const incodeRegex = /\d[a-z]{2}$/i; +const validOutcodeRegex = /^[a-z]{1,2}\d[a-z\d]?$/i; +const districtSplitRegex = /^([a-z]{1,2}\d)([a-z])$/i; +const VALIDATION_REGEX = /^[a-z]{1,2}\d[a-z\d]?\s*\d[a-z]{2}$/i; + +/** + * Detects a "valid" postcode + * - Starts and ends on a non-space character + * - Any length of intervening space is allowed + * - Must conform to one of following schemas: + * - AA1A 1AA + * - A1A 1AA + * - A1 1AA + * - A99 9AA + * - AA9 9AA + * - AA99 9AA + */ +const isValid: Validator = postcode => { + return postcode.match(VALIDATION_REGEX) !== null; +}; + +/** + * Returns a normalised postcode string (i.e. uppercased and properly spaced) + * + * Returns null if invalid postcode + */ +const toNormalised: Parser = postcode => { + const outcode = toOutcode(postcode); + if (outcode === null) return null; + const incode = toIncode(postcode); + if (incode === null) return null; + return `${outcode} ${incode}`; +}; + +/** + * Returns a correctly formatted outcode given a postcode + * + * Returns null if invalid postcode + */ +const toOutcode: Parser = postcode => { + if (!isValid(postcode)) return null; + return sanitize(postcode).replace(incodeRegex, ""); +}; + +/** + * Returns a correctly formatted incode given a postcode + * + * Returns null if invalid postcode + */ +const toIncode: Parser = postcode => { + if (!isValid(postcode)) return null; + const match = matchOn(postcode, incodeRegex); + return firstOrNull(match); +}; + +const AREA_REGEX = /^[a-z]{1,2}/i; + +/** + * Returns a correctly formatted area given a postcode + * + * Returns null if invalid postcode + */ +const toArea: Parser = postcode => { + if (!isValid(postcode)) return null; + const match = matchOn(postcode, AREA_REGEX); + return firstOrNull(match); +}; + +/** + * Returns a correctly formatted sector given a postcode + * + * Returns null if invalid postcode + */ +const toSector: Parser = postcode => { + const outcode = toOutcode(postcode); + if (outcode === null) return null; + const incode = toIncode(postcode); + if (incode === null) return null; + return `${outcode} ${incode[0]}`; +}; + +const UNIT_REGEX = /[a-z]{2}$/i; + +/** + * Returns a correctly formatted unit given a postcode + * + * Returns null if invalid postcode + */ +const toUnit: Parser = postcode => { + if (!isValid(postcode)) return null; + const match = matchOn(postcode, UNIT_REGEX); + return firstOrNull(match); +}; + +/** + * Postcode + * + * This wraps an input postcode string and provides instance methods to + * validate, normalise or extract postcode data. + * + * This API is a bit more cumbersome that it needs to be. You should + * favour `Postcode.parse()` or a static method depending on the + * task at hand. + */ class Postcode { private _raw: string; private _valid: boolean; @@ -11,9 +144,17 @@ class Postcode { constructor(postcode: string) { this._raw = postcode; - this._valid = isValidPostcode(postcode); + this._valid = isValid(postcode); } + static isValid = isValid; + static toNormalised = toNormalised; + static toOutcode = toOutcode; + static toIncode = toIncode; + static toArea = toArea; + static toSector = toSector; + static toUnit = toUnit; + static validOutcode(outcode: string): boolean { return outcode.match(validOutcodeRegex) !== null; } @@ -25,21 +166,21 @@ class Postcode { incode(): string | null { if (!this._valid) return null; if (this._incode) return this._incode; - this._incode = nullOrUpperCase(parseIncode(this._raw)); + this._incode = toIncode(this._raw); return this._incode; } outcode(): string | null { if (!this._valid) return null; if (this._outcode) return this._outcode; - this._outcode = nullOrUpperCase(parseOutcode(this._raw)); + this._outcode = toOutcode(this._raw); return this._outcode; } area(): string | null { if (!this._valid) return null; if (this._area) return this._area; - this._area = nullOrUpperCase(parseArea(this._raw)); + this._area = toArea(this._raw); return this._area; } @@ -67,14 +208,14 @@ class Postcode { if (this._sector) return this._sector; const normalised = this.normalise(); if (normalised === null) return null; - this._sector = parseSector(normalised); + this._sector = toSector(normalised); return this._sector; } unit(): string | null { if (!this._valid) return null; if (this._unit) return this._unit; - this._unit = nullOrUpperCase(parseUnit(this._raw)); + this._unit = toUnit(this._raw); return this._unit; } @@ -84,54 +225,4 @@ class Postcode { } } -const validationRegex = /^[a-z]{1,2}\d[a-z\d]?\s*\d[a-z]{2}$/i; -const incodeRegex = /\d[a-z]{2}$/i; -const validOutcodeRegex = /^[a-z]{1,2}\d[a-z\d]?$/i; -const areaRegex = /^[a-z]{1,2}/i; -const districtSplitRegex = /^([a-z]{1,2}\d)([a-z])$/i; -const sectorRegex = /^[a-z]{1,2}\d[a-z\d]?\s*\d/i; -const unitRegex = /[a-z]{2}$/i; - -interface Validator { - (input: string): boolean; -} - -const isValidPostcode: Validator = postcode => - postcode.match(validationRegex) !== null; - -interface Parser { - (postcode: string): string | null; -} -const parseOutcode: Parser = postcode => { - return postcode.replace(incodeRegex, "").replace(/\s+/, ""); -}; - -const parseIncode: Parser = postcode => { - const match = postcode.match(incodeRegex); - if (match === null) return null; - return match[0]; -}; - -const parseArea: Parser = postcode => { - const match = postcode.match(areaRegex); - if (match === null) return null; - return match[0]; -}; - -const parseSector: Parser = postcode => { - const match = postcode.match(sectorRegex); - if (match === null) return null; - return match[0]; -}; - -const parseUnit: Parser = postcode => { - const match = postcode.match(unitRegex); - if (match === null) return null; - return match[0]; -}; - -const nullOrUpperCase = (s: string | null): string | null => { - return s === null ? null : s.toUpperCase(); -}; - export = Postcode; diff --git a/test/statics.unit.ts b/test/statics.unit.ts new file mode 100644 index 0000000..206123c --- /dev/null +++ b/test/statics.unit.ts @@ -0,0 +1,117 @@ +import { assert } from "chai"; +import Postcode from "../lib/index"; +import { loadFixtures, TestCase } from "./util/helper"; + +interface StaticMethod { + (postcode: string): string | null; +} + +interface TestMethodOptions { + tests: TestCase[]; + method: StaticMethod; +} + +const testMethod = (options: TestMethodOptions): void => { + const { tests, method } = options; + tests.forEach(({ base, expected }) => { + const result = method.call(null, base); + assert.equal(result, expected); + }); +}; + +describe("Postcode.isValid", async () => { + it("should return true for postcodes that look correct", async () => { + const { tests } = await loadFixtures("validation.json"); + tests.forEach(({ base, expected }) => { + assert.equal(Postcode.isValid(base), Boolean(expected)); + }); + }); +}); + +describe("Postcode.toNormalised", () => { + it("should correctly normalise postcodes", async () => { + const { tests } = await loadFixtures("normalisation.json"); + testMethod({ method: Postcode.toNormalised, tests }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(Postcode.toNormalised("Definitly bogus")); + }); +}); + +describe("Postcode.toIncode", () => { + it("should correctly parse incodes", async () => { + const { tests } = await loadFixtures("incodes.json"); + testMethod({ method: Postcode.toIncode, tests }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(Postcode.toIncode("Definitly bogus")); + }); +}); + +describe("Postcode.toOutcode", () => { + it("should correctly parse outcodes", async () => { + const { tests } = await loadFixtures("outcodes.json"); + testMethod({ method: Postcode.toOutcode, tests }); + }); + + it("should return undefined if invalid postcode", () => { + assert.isNull(Postcode.toOutcode("Definitly bogus")); + }); +}); + +describe("Postcode.toArea", () => { + it("should correctly parse areas", async () => { + const { tests } = await loadFixtures("areas.json"); + testMethod({ method: Postcode.toArea, tests }); + }); + + it("should return undefined if invalid postcode", () => { + assert.isNull(Postcode.toArea("Definitely bogus")); + }); +}); + +// describe("Postcode.toDistrict", () => { +// it("should correctly parse districts", async () => { +// const { tests } = await loadFixtures("districts.json"); +// testMethod({ method: Postcode.toDistrict, tests }); +// }); + +// it("should return undefined if invalid postcode", () => { +// assert.isNull(Postcode.toDistrict("Definitely bogus")); +// }); +// }); + +// describe("Postcode.toSubDistrict", () => { +// it("should correctly parse sub-districts", async () => { +// const { tests } = await loadFixtures("sub-districts.json"); +// testMethod({ method: Postcode.toSubDistrict, tests }); +// }); + +// it("should return undefined if invalid postcode", () => { +// assert.isNull(Postcode.toSubDistrict("Definitely bogus")); +// }); +// }); + +describe("Postcode.toSector", () => { + it("should correctly parse sectors", async () => { + const { tests } = await loadFixtures("sectors.json"); + testMethod({ method: Postcode.toSector, tests }); + }); + + it("should return undefined if invalid postcode", () => { + assert.isNull(Postcode.toSector("Definitely bogus")); + }); +}); + +describe("Postcode.toUnit", () => { + it("should correctly parse units", async () => { + const { tests } = await loadFixtures("units.json"); + testMethod({ method: Postcode.toUnit, tests }); + }); + + it("should return undefined if invalid postcode", () => { + assert.isNull(Postcode.toUnit("Definitely bogus")); + }); +}); From 4dbede053710de51b8fc098b585a85644095f015 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 14 Apr 2019 17:39:27 +0000 Subject: [PATCH 20/38] Point instances to a static method if postcode is invalid Simplifies instance method and hopefully improves performance --- lib/index.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/index.ts b/lib/index.ts index 7a01e9a..cde0395 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -121,6 +121,8 @@ const toUnit: Parser = postcode => { return firstOrNull(match); }; +const returnNull = () => null; + /** * Postcode * @@ -145,6 +147,18 @@ class Postcode { constructor(postcode: string) { this._raw = postcode; this._valid = isValid(postcode); + + // All parse methods should return null if invalid + if (!this._valid) { + this.incode = returnNull; + this.outcode = returnNull; + this.area = returnNull; + this.district = returnNull; + this.subDistrict = returnNull; + this.sector = returnNull; + this.unit = returnNull; + this.normalise = returnNull; + } } static isValid = isValid; @@ -164,21 +178,18 @@ class Postcode { } incode(): string | null { - if (!this._valid) return null; if (this._incode) return this._incode; this._incode = toIncode(this._raw); return this._incode; } outcode(): string | null { - if (!this._valid) return null; if (this._outcode) return this._outcode; this._outcode = toOutcode(this._raw); return this._outcode; } area(): string | null { - if (!this._valid) return null; if (this._area) return this._area; this._area = toArea(this._raw); return this._area; @@ -206,21 +217,17 @@ class Postcode { sector(): string | null { if (this._sector) return this._sector; - const normalised = this.normalise(); - if (normalised === null) return null; - this._sector = toSector(normalised); + this._sector = toSector(this._raw); return this._sector; } unit(): string | null { - if (!this._valid) return null; if (this._unit) return this._unit; this._unit = toUnit(this._raw); return this._unit; } normalise(): string | null { - if (!this._valid) return null; return `${this.outcode()} ${this.incode()}`; } } From 43349b57d7e59217d547333e4715df9cdc1dbd1f Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 14 Apr 2019 17:52:16 +0000 Subject: [PATCH 21/38] Implement toDistrict Document & add deploy on instance method --- lib/index.ts | 33 +++++++++++++++++++++++++-------- test/statics.unit.ts | 18 +++++++++--------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/lib/index.ts b/lib/index.ts index cde0395..a45d1b5 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -29,7 +29,6 @@ const matchOn = (s: string, regex: RegExp): RegExpMatchArray | null => { const incodeRegex = /\d[a-z]{2}$/i; const validOutcodeRegex = /^[a-z]{1,2}\d[a-z\d]?$/i; -const districtSplitRegex = /^([a-z]{1,2}\d)([a-z])$/i; const VALIDATION_REGEX = /^[a-z]{1,2}\d[a-z\d]?\s*\d[a-z]{2}$/i; /** @@ -121,6 +120,28 @@ const toUnit: Parser = postcode => { return firstOrNull(match); }; +const DISTRICT_SPLIT_REGEX = /^([a-z]{1,2}\d)([a-z])$/i; + +/** + * Returns a correctly formatted district given a postcode + * + * Returns null if invalid postcode + * + * @example + * + * ``` + * toDistrict("AA9") // => "AA9" + * toDistrict("A9A") // => "A9" + * ``` + */ +const toDistrict: Parser = postcode => { + const outcode = toOutcode(postcode); + if (outcode === null) return null; + const match = outcode.match(DISTRICT_SPLIT_REGEX); + if (match === null) return outcode; + return match[1]; +}; + const returnNull = () => null; /** @@ -168,6 +189,7 @@ class Postcode { static toArea = toArea; static toSector = toSector; static toUnit = toUnit; + static toDistrict = toDistrict; static validOutcode(outcode: string): boolean { return outcode.match(validOutcodeRegex) !== null; @@ -196,13 +218,8 @@ class Postcode { } district(): string | null { - if (!this._valid) return null; if (this._district) return this._district; - const outcode = this.outcode(); - if (outcode === null) return null; - const split = outcode.match(districtSplitRegex); - this._district = split !== null ? split[1] : outcode; - return this._district; + return (this._district = toDistrict(this._raw)); } subDistrict(): string | null { @@ -210,7 +227,7 @@ class Postcode { if (this._subDistrict) return this._subDistrict; const outcode = this.outcode(); if (outcode === null) return null; - const split = outcode.match(districtSplitRegex); + const split = outcode.match(DISTRICT_SPLIT_REGEX); this._subDistrict = split !== null ? outcode : null; return this._subDistrict; } diff --git a/test/statics.unit.ts b/test/statics.unit.ts index 206123c..d26d947 100644 --- a/test/statics.unit.ts +++ b/test/statics.unit.ts @@ -72,16 +72,16 @@ describe("Postcode.toArea", () => { }); }); -// describe("Postcode.toDistrict", () => { -// it("should correctly parse districts", async () => { -// const { tests } = await loadFixtures("districts.json"); -// testMethod({ method: Postcode.toDistrict, tests }); -// }); +describe("Postcode.toDistrict", () => { + it("should correctly parse districts", async () => { + const { tests } = await loadFixtures("districts.json"); + testMethod({ method: Postcode.toDistrict, tests }); + }); -// it("should return undefined if invalid postcode", () => { -// assert.isNull(Postcode.toDistrict("Definitely bogus")); -// }); -// }); + it("should return undefined if invalid postcode", () => { + assert.isNull(Postcode.toDistrict("Definitely bogus")); + }); +}); // describe("Postcode.toSubDistrict", () => { // it("should correctly parse sub-districts", async () => { From 7f06280f542a2e7d6c8e7d561afa7742d4c2f573 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 14 Apr 2019 17:59:57 +0000 Subject: [PATCH 22/38] Implement toSubDistrict static method --- lib/index.ts | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/index.ts b/lib/index.ts index a45d1b5..9f1a57a 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -130,8 +130,8 @@ const DISTRICT_SPLIT_REGEX = /^([a-z]{1,2}\d)([a-z])$/i; * @example * * ``` - * toDistrict("AA9") // => "AA9" - * toDistrict("A9A") // => "A9" + * toDistrict("AA9 9AA") // => "AA9" + * toDistrict("A9A 9AA") // => "A9" * ``` */ const toDistrict: Parser = postcode => { @@ -142,6 +142,29 @@ const toDistrict: Parser = postcode => { return match[1]; }; +/** + * Returns a correctly formatted subdistrict given a postcode + * + * Returns null if no subdistrict is available on valid postcode + * Returns null if invalid postcode + * + * @example + * + * ``` + * toSubDistrict("AA9A 9AA") // => "AA9A" + * toSubDistrict("A9A 9AA") // => "A9A" + * toSubDistrict("AA9 9AA") // => null + * toSubDistrict("A9 9AA") // => null + * ``` + */ +const toSubDistrict: Parser = postcode => { + const outcode = toOutcode(postcode); + if (outcode === null) return null; + const split = outcode.match(DISTRICT_SPLIT_REGEX); + if (split === null) return null; + return outcode; +}; + const returnNull = () => null; /** @@ -190,6 +213,7 @@ class Postcode { static toSector = toSector; static toUnit = toUnit; static toDistrict = toDistrict; + static toSubDistrict = toSubDistrict; static validOutcode(outcode: string): boolean { return outcode.match(validOutcodeRegex) !== null; @@ -223,12 +247,8 @@ class Postcode { } subDistrict(): string | null { - if (!this._valid) return null; if (this._subDistrict) return this._subDistrict; - const outcode = this.outcode(); - if (outcode === null) return null; - const split = outcode.match(DISTRICT_SPLIT_REGEX); - this._subDistrict = split !== null ? outcode : null; + this._subDistrict = toSubDistrict(this._raw); return this._subDistrict; } From 861a3641c1fd4e548bcc4d10d3af5b6de25e028f Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 14 Apr 2019 18:03:09 +0000 Subject: [PATCH 23/38] Memoize and return on one line --- lib/index.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/lib/index.ts b/lib/index.ts index 9f1a57a..3ecd590 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -225,20 +225,17 @@ class Postcode { incode(): string | null { if (this._incode) return this._incode; - this._incode = toIncode(this._raw); - return this._incode; + return (this._incode = toIncode(this._raw)); } outcode(): string | null { if (this._outcode) return this._outcode; - this._outcode = toOutcode(this._raw); - return this._outcode; + return (this._outcode = toOutcode(this._raw)); } area(): string | null { if (this._area) return this._area; - this._area = toArea(this._raw); - return this._area; + return (this._area = toArea(this._raw)); } district(): string | null { @@ -248,20 +245,17 @@ class Postcode { subDistrict(): string | null { if (this._subDistrict) return this._subDistrict; - this._subDistrict = toSubDistrict(this._raw); - return this._subDistrict; + return (this._subDistrict = toSubDistrict(this._raw)); } sector(): string | null { if (this._sector) return this._sector; - this._sector = toSector(this._raw); - return this._sector; + return (this._sector = toSector(this._raw)); } unit(): string | null { if (this._unit) return this._unit; - this._unit = toUnit(this._raw); - return this._unit; + return (this._unit = toUnit(this._raw)); } normalise(): string | null { From 6e552e364d80387f20cf1072616b42edf57ce1eb Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Sun, 14 Apr 2019 19:24:16 +0000 Subject: [PATCH 24/38] Require minimum node of 8.0.0; Bump major version --- CHANGELOG.md | 9 ++++++--- package.json | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b1cee2..9da7dac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,15 @@ Any changes, including backwards incompatible changes will be listed here -## 1.1.0 (12/02/2019) +## 2.0.0 (12/02/2019) +- *Breaking Change*: Require minimum node.js of 8.0.0 - Ported to typescript (now exports typings) -- New methods (cleaner instance methods, more static methods) +- Provides a cleaner, more modern API to extract and parse while supporting old methods + - Add static methods to extract single datapoints + - Add a ValidPostcode class with accessor methods which can be destructured - Updated documentation -- Added benchmarks +- Added benchmarking ## 1.0.1 (12/02/2019) diff --git a/package.json b/package.json index 64a88b4..ec60dc4 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,12 @@ { "name": "postcode", - "version": "1.0.1", + "version": "2.0.0", "description": "UK Postcode helper methods", "main": "dist/index.js", "types": "dist/index.d.ts", + "engines": { + "node": ">= 8.0.0" + }, "dependencies": {}, "prettier": {}, "devDependencies": { From 4d52e1818c66158b3f276c00e44e4da021517897 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Thu, 18 Apr 2019 05:08:17 +0000 Subject: [PATCH 25/38] Add toSubDistrict tests --- test/statics.unit.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/statics.unit.ts b/test/statics.unit.ts index d26d947..1e728eb 100644 --- a/test/statics.unit.ts +++ b/test/statics.unit.ts @@ -83,16 +83,16 @@ describe("Postcode.toDistrict", () => { }); }); -// describe("Postcode.toSubDistrict", () => { -// it("should correctly parse sub-districts", async () => { -// const { tests } = await loadFixtures("sub-districts.json"); -// testMethod({ method: Postcode.toSubDistrict, tests }); -// }); - -// it("should return undefined if invalid postcode", () => { -// assert.isNull(Postcode.toSubDistrict("Definitely bogus")); -// }); -// }); +describe("Postcode.toSubDistrict", () => { + it("should correctly parse sub-districts", async () => { + const { tests } = await loadFixtures("sub-districts.json"); + testMethod({ method: Postcode.toSubDistrict, tests }); + }); + + it("should return undefined if invalid postcode", () => { + assert.isNull(Postcode.toSubDistrict("Definitely bogus")); + }); +}); describe("Postcode.toSector", () => { it("should correctly parse sectors", async () => { From 8eab216cd4e45d8129e0487a456a965eadacd600 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Thu, 18 Apr 2019 14:00:56 +0000 Subject: [PATCH 26/38] Fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd96b61..5f0f302 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Postcode.js + Postcode.js

> Validate & parse UK postcodes From 5d66fa3b16bf291e9c1eacd7b1489b43a63d667d Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Thu, 18 Apr 2019 16:02:53 +0200 Subject: [PATCH 27/38] Update README.md Fix in page links --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5f0f302..e39e2f5 100644 --- a/README.md +++ b/README.md @@ -17,17 +17,17 @@ Tested against ~1.7 million postcodes on ONSPD. ## Features -- [Check](#Validate) whether a postcode conforms to the [correct format](https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Formatting) -- [Extract](#Extract) useful elements of a postcode like incode, outcode, sector -- [Single purpose static methods](#Static Methods) +- [Check](#validate) whether a postcode conforms to the [correct format](https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Formatting) +- [Extract](#extract) useful elements of a postcode like incode, outcode, sector +- [Single purpose static methods](#static-methods) - Tested against a list of ~1.7 million postcodes listed on ONS Postcode Directory ## Links - [API Documentation](https://ideal-postcodes.github.io/postcode/) - [Try postcode.js on RunKit](https://npm.runkit.com/postcode) -- [Postcode element definitions](#Definitions) -- [Caveat on postcode validation](#Note on Postcode Validation) +- [Postcode element definitions](#definitions) +- [Caveat on postcode validation](#note-on-postcode-Validation) ## Getting Started From d6b67029c5de151ba6ba5c30760960655faecf35 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Thu, 18 Apr 2019 16:05:20 +0200 Subject: [PATCH 28/38] Update README.md Fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e39e2f5..b20f31e 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,13 @@ Tested against ~1.7 million postcodes on ONSPD. ## Features - [Check](#validate) whether a postcode conforms to the [correct format](https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Formatting) -- [Extract](#extract) useful elements of a postcode like incode, outcode, sector +- [Extract](#parse) useful elements of a postcode like incode, outcode, sector - [Single purpose static methods](#static-methods) - Tested against a list of ~1.7 million postcodes listed on ONS Postcode Directory ## Links -- [API Documentation](https://ideal-postcodes.github.io/postcode/) +- [API Documentation](https://postcodejs.ideal-postcodes.dev) - [Try postcode.js on RunKit](https://npm.runkit.com/postcode) - [Postcode element definitions](#definitions) - [Caveat on postcode validation](#note-on-postcode-Validation) From 4d6c8411bfd8ec7f91e10e5111d31fd6fa12ad0c Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Fri, 19 Apr 2019 06:37:55 +0000 Subject: [PATCH 29/38] Move out interface definitions --- test/unit.ts | 21 +++------------------ test/util/helper.ts | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/test/unit.ts b/test/unit.ts index eed5b70..4dcce56 100644 --- a/test/unit.ts +++ b/test/unit.ts @@ -1,23 +1,8 @@ import { assert } from "chai"; import Postcode from "../lib/index"; -import { loadFixtures, TestCase } from "./util/helper"; - -type Method = - | "normalise" - | "incode" - | "outcode" - | "area" - | "district" - | "unit" - | "sector" - | "subDistrict"; - -interface TestMethodOptions { - tests: TestCase[]; - method: Method; -} - -const testMethod = (options: TestMethodOptions): void => { +import { loadFixtures, TestMethod } from "./util/helper"; + +const testMethod: TestMethod = options => { const { tests, method } = options; tests.forEach(({ base, expected }) => { const p = new Postcode(base); diff --git a/test/util/helper.ts b/test/util/helper.ts index f45cef7..eb80cc9 100644 --- a/test/util/helper.ts +++ b/test/util/helper.ts @@ -1,6 +1,25 @@ import { join } from "path"; import { readFile } from "fs"; +type PostcodeMethod = + | "normalise" + | "incode" + | "outcode" + | "area" + | "district" + | "unit" + | "sector" + | "subDistrict"; + +interface TestMethodOptions { + tests: TestCase[]; + method: PostcodeMethod; +} + +export interface TestMethod { + (options: TestMethodOptions): void; +} + const dataDir = join(__dirname, "../data"); interface TestFixtures { From 2336c47f370ed2bfee134440a0a8fe6464a1bef6 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Fri, 19 Apr 2019 06:38:19 +0000 Subject: [PATCH 30/38] Implement Postcode.parse - Returns eith a ValidPostcode or InvalidPostcode instance with same properties - InvalidPostcode has a fixed definition - ValidPostcode provides accessor methods to allow for easy destructuring and cleaner access --- lib/index.ts | 73 ++++++++++++++++++ test/parse.unit.ts | 187 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 test/parse.unit.ts diff --git a/lib/index.ts b/lib/index.ts index 3ecd590..a5d2162 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -6,6 +6,74 @@ interface Parser { (postcode: string): string | null; } +class ValidPostcode { + private instance: Postcode; + + constructor(postcode: string) { + this.instance = new Postcode(postcode); + } + + get valid(): boolean { + return this.instance.valid(); + } + + get postcode(): string { + return this.instance.normalise(); + } + + get incode(): string { + return this.instance.incode(); + } + + get outcode(): string { + return this.instance.outcode(); + } + + get area(): string { + return this.instance.area(); + } + + get district(): string { + return this.instance.district(); + } + + get subDistrict(): string { + return this.instance.subDistrict(); + } + + get sector(): string { + return this.instance.sector(); + } + + get unit(): string { + return this.instance.unit(); + } +} + +type InvalidPostcode = { + valid: false; + postcode: null; + incode: null; + outcode: null; + area: null; + district: null; + subDistrict: null; + sector: null; + unit: null; +}; + +const invalidPostcode: InvalidPostcode = Object.freeze({ + valid: false, + postcode: null, + incode: null, + outcode: null, + area: null, + district: null, + subDistrict: null, + sector: null, + unit: null +}); + /** * Return first elem of input is RegExpMatchArray or null if input null */ @@ -219,6 +287,11 @@ class Postcode { return outcode.match(validOutcodeRegex) !== null; } + static parse(postcode: string): ValidPostcode | InvalidPostcode { + if (isValid(postcode)) return new ValidPostcode(postcode); + return { ...invalidPostcode }; + } + valid(): boolean { return this._valid; } diff --git a/test/parse.unit.ts b/test/parse.unit.ts new file mode 100644 index 0000000..75664d5 --- /dev/null +++ b/test/parse.unit.ts @@ -0,0 +1,187 @@ +import { assert } from "chai"; +import { loadFixtures } from "./util/helper"; +import Postcode from "../lib/index"; + +const INVALID_POSTCODE = Object.freeze({ + valid: false, + postcode: null, + incode: null, + outcode: null, + area: null, + district: null, + subDistrict: null, + sector: null, + unit: null +}); + +describe("Postcode.parse", () => { + describe("invalid postcode", () => { + it("returns an invalid postcode object", () => { + const { + valid, + postcode, + incode, + outcode, + area, + district, + subDistrict, + sector, + unit + } = Postcode.parse("foo"); + assert.deepEqual( + { + valid, + postcode, + incode, + outcode, + area, + district, + subDistrict, + sector, + unit + }, + { ...INVALID_POSTCODE } + ); + }); + }); + + describe("with valid postcode", () => { + describe("Postcode#Valid", async () => { + it("should return true for postcodes that look correct", async () => { + const { tests } = await loadFixtures("validation.json"); + tests.forEach(({ base, expected }) => { + const result = Postcode.parse(base); + assert.equal(result.valid, Boolean(expected)); + }); + }); + + describe("Postcode normalisation", () => { + it("should correctly normalise postcodes", async () => { + const { tests } = await loadFixtures("normalisation.json"); + tests.forEach(({ base, expected }) => { + const result = Postcode.parse(base); + assert.equal(result.postcode, expected); + }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(Postcode.parse("Definitly bogus").postcode); + }); + }); + + describe("Postcode.validOutcode", () => { + it("should return true for valid outcodes", async () => { + const { tests } = await loadFixtures("outcodes.json"); + tests.forEach(({ expected }) => + assert.isTrue(Postcode.validOutcode(expected)) + ); + }); + + it("should return false for invalid outcode", () => { + const invalidOutcodes = ["BOGUS", "Hello there", "12345"]; + invalidOutcodes.forEach(code => + assert.isFalse(Postcode.validOutcode(code)) + ); + }); + }); + + describe("Incode parsing", () => { + it("should correctly parse incodes", async () => { + const { tests } = await loadFixtures("incodes.json"); + tests.forEach(({ base, expected }) => { + const result = Postcode.parse(base); + assert.equal(result.incode, expected); + }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(Postcode.parse("Definitly bogus").incode); + }); + }); + + describe("Outcode parsing", () => { + it("should correctly parse outcodes", async () => { + const { tests } = await loadFixtures("outcodes.json"); + tests.forEach(({ base, expected }) => { + const result = Postcode.parse(base); + assert.equal(result.outcode, expected); + }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(Postcode.parse("Definitly bogus").outcode); + }); + }); + + describe("Area parsing", () => { + it("should correctly parse areas", async () => { + const { tests } = await loadFixtures("areas.json"); + tests.forEach(({ base, expected }) => { + const result = Postcode.parse(base); + assert.equal(result.area, expected); + }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(Postcode.parse("Definitely bogus").area); + }); + }); + + describe("District parsing", () => { + it("should correctly parse districts", async () => { + const { tests } = await loadFixtures("districts.json"); + tests.forEach(({ base, expected }) => { + const result = Postcode.parse(base); + assert.equal(result.district, expected); + }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(Postcode.parse("Definitely bogus").district); + }); + }); + + describe("Sub-district parsing", () => { + it("should correctly parse sub-districts", async () => { + const { tests } = await loadFixtures("sub-districts.json"); + tests.forEach(({ base, expected }) => { + const result = Postcode.parse(base); + assert.equal(result.subDistrict, expected); + }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(Postcode.parse("Definitely bogus").subDistrict); + }); + }); + + describe("Sector parsing", () => { + it("should correctly parse sectors", async () => { + const { tests } = await loadFixtures("sectors.json"); + tests.forEach(({ base, expected }) => { + const result = Postcode.parse(base); + assert.equal(result.sector, expected); + }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(Postcode.parse("Definitely bogus").sector); + }); + }); + + describe("Unit parsing", () => { + it("should correctly parse units", async () => { + const { tests } = await loadFixtures("units.json"); + tests.forEach(({ base, expected }) => { + const result = Postcode.parse(base); + assert.equal(result.unit, expected); + }); + }); + + it("should return null if invalid postcode", () => { + assert.isNull(Postcode.parse("Definitely bogus").unit); + }); + }); + }); + }); +}); From 01bf744f3828a8dcedfacbb1275efe8c4065c542 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Fri, 19 Apr 2019 06:43:18 +0000 Subject: [PATCH 31/38] Add benchmarks - Install package - Add script --- package-lock.json | 24 +++++++++++++++++++++++- package.json | 3 +++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 65730da..beecbfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "postcode", - "version": "1.0.1", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -123,6 +123,12 @@ "integrity": "sha512-sZYAjrosdF5xpOoUapZ1Xs4zJB7OAD0rRAD6DGG1+qP0hoMTSUNayWEkty10XjrdsCd1xqzh1+FhScEArLF7Pw==", "dev": true }, + "@types/benchmark": { + "version": "1.0.31", + "resolved": "https://registry.npmjs.org/@types/benchmark/-/benchmark-1.0.31.tgz", + "integrity": "sha512-F6fVNOkGEkSdo/19yWYOwVKGvzbTeWkR/XQYBKtGBQ9oGRjBN9f/L4aJI4sDcVPJO58Y1CJZN8va9V2BhrZapA==", + "dev": true + }, "@types/chai": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", @@ -465,6 +471,16 @@ "tweetnacl": "^0.14.3" } }, + "benchmark": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", + "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=", + "dev": true, + "requires": { + "lodash": "^4.17.4", + "platform": "^1.3.3" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3308,6 +3324,12 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "platform": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.5.tgz", + "integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q==", + "dev": true + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", diff --git a/package.json b/package.json index ec60dc4..a173e23 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,12 @@ "devDependencies": { "@cablanchard/tsconfig": "0.0.1", "@cablanchard/tslint": "0.0.1", + "@types/benchmark": "~1.0.31", "@types/chai": "~4.1.7", "@types/csv-parse": "~1.1.12", "@types/mocha": "~5.2.6", "@types/node": "~11.13.0", + "benchmark": "~2.1.4", "chai": "~4.2.0", "coveralls": "~3.0.2", "csv-parse": "~4.4.0", @@ -60,6 +62,7 @@ "lint": "node_modules/.bin/tslint -c tslint.json -p tsconfig.json", "docs": "./node_modules/.bin/typedoc --mode file --excludePrivate --hideGenerator --excludeExternals --target ES5 --out docs/ --name 'Postcode.js' --theme minimal lib/", "build": "./node_modules/.bin/tsc", + "benchmark": "npm run build && node benchmark.js", "coverage": "node_modules/.bin/nyc report --reporter=text-lcov | node_modules/.bin/coveralls || true" }, "repository": { From 14423dab9322b91eddbc1177faabaf93a136bb52 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Fri, 19 Apr 2019 07:19:20 +0000 Subject: [PATCH 32/38] Add npm install version --- package-lock.json | 3722 +++++++++++++++++++++++++++++++++++++++++++-- package.json | 1 + 2 files changed, 3608 insertions(+), 115 deletions(-) diff --git a/package-lock.json b/package-lock.json index beecbfe..7907634 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1476,6 +1476,17 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, + "install-npm-version": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/install-npm-version/-/install-npm-version-1.0.3.tgz", + "integrity": "sha512-viOiEfPZFZqbgviQby8ualLRisU47ABdvqX7L3dBSTxSui3EqqosqRBu6m6E62xKcfy2wAwhoh5So0q3rHOevg==", + "dev": true, + "requires": { + "minimist": "^1.2.0", + "npm": "^6.4.1", + "sanitize-filename": "^1.6.1" + } + }, "interpret": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", @@ -1937,139 +1948,3596 @@ "dependencies": { "is-extendable": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "mocha": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.0.2.tgz", + "integrity": "sha512-RtTJsmmToGyeTznSOMoM6TPEk1A84FQaHIciKrRqARZx+B5ccJ5tXlmJzEKGBxZdqk9UjpRsesZTUkZmR5YnuQ==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "findup-sync": "2.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.12.0", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "ms": "2.1.1", + "node-environment-flags": "1.0.4", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "12.0.5", + "yargs-parser": "11.1.1", + "yargs-unparser": "1.5.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "neo-async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-environment-flags": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.4.tgz", + "integrity": "sha512-M9rwCnWVLW7PX+NUWe3ejEdiLYinRpsEre9hMkU/6NS4h+EEulYaDH1gCEZ2gyXsmw+RXYDaV2JkkTNcsPDJ0Q==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "npm": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.9.0.tgz", + "integrity": "sha512-91V+zB5hDxO+Jyp2sUKS7juHlIM95dGQxTeQtmZI1nAI/7kjWXFipPrtwwKjhyKmV4GsS2LzJhrxRjGWsU9z/w==", + "dev": true, + "requires": { + "JSONStream": "^1.3.5", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "^2.0.0", + "archy": "~1.0.0", + "bin-links": "^1.1.2", + "bluebird": "^3.5.3", + "byte-size": "^5.0.1", + "cacache": "^11.3.2", + "call-limit": "~1.1.0", + "chownr": "^1.1.1", + "ci-info": "^2.0.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.5.1", + "cmd-shim": "~2.0.2", + "columnify": "~1.5.4", + "config-chain": "^1.1.12", + "debuglog": "*", + "detect-indent": "~5.0.0", + "detect-newline": "^2.1.0", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "figgy-pudding": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "gentle-fs": "^2.0.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "has-unicode": "~2.0.1", + "hosted-git-info": "^2.7.1", + "iferr": "^1.0.2", + "imurmurhash": "*", + "inflight": "~1.0.6", + "inherits": "~2.0.3", + "ini": "^1.3.5", + "init-package-json": "^1.10.3", + "is-cidr": "^3.0.0", + "json-parse-better-errors": "^1.0.2", + "lazy-property": "~1.0.0", + "libcipm": "^3.0.3", + "libnpm": "^2.0.1", + "libnpmaccess": "*", + "libnpmhook": "^5.0.2", + "libnpmorg": "*", + "libnpmsearch": "*", + "libnpmteam": "*", + "libnpx": "^10.2.0", + "lock-verify": "^2.1.0", + "lockfile": "^1.0.4", + "lodash._baseindexof": "*", + "lodash._baseuniq": "~4.6.0", + "lodash._bindcallback": "*", + "lodash._cacheindexof": "*", + "lodash._createcache": "*", + "lodash._getnative": "*", + "lodash.clonedeep": "~4.5.0", + "lodash.restparam": "*", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "lru-cache": "^4.1.5", + "meant": "~1.0.1", + "mississippi": "^3.0.0", + "mkdirp": "~0.5.1", + "move-concurrently": "^1.0.1", + "node-gyp": "^3.8.0", + "nopt": "~4.0.1", + "normalize-package-data": "^2.5.0", + "npm-audit-report": "^1.3.2", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "~3.0.0", + "npm-lifecycle": "^2.1.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.4.1", + "npm-pick-manifest": "^2.2.3", + "npm-profile": "*", + "npm-registry-fetch": "^3.9.0", + "npm-user-validate": "~1.0.0", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "^1.5.1", + "osenv": "^0.1.5", + "pacote": "^9.5.0", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "qrcode-terminal": "^0.12.0", + "query-string": "^6.2.0", + "qw": "~1.0.1", + "read": "~1.0.7", + "read-cmd-shim": "~1.0.1", + "read-installed": "~4.0.3", + "read-package-json": "^2.0.13", + "read-package-tree": "^5.2.2", + "readable-stream": "^3.1.1", + "readdir-scoped-modules": "*", + "request": "^2.88.0", + "retry": "^0.12.0", + "rimraf": "^2.6.3", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "sha": "~2.0.1", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "^6.0.1", + "stringify-package": "^1.0.0", + "tar": "^4.4.8", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "unique-filename": "^1.1.1", + "unpipe": "~1.0.0", + "update-notifier": "^2.5.0", + "uuid": "^3.3.2", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^1.3.1", + "worker-farm": "^1.6.0", + "write-file-atomic": "^2.4.2" + }, + "dependencies": { + "JSONStream": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "agent-base": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.4.1", + "bundled": true, + "dev": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "ajv": { + "version": "5.5.2", + "bundled": true, + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-align": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "asap": { + "version": "2.0.6", + "bundled": true, + "dev": true + }, + "asn1": { + "version": "0.2.4", + "bundled": true, + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "bundled": true, + "dev": true + }, + "aws4": { + "version": "1.8.0", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bin-links": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "bluebird": "^3.5.0", + "cmd-shim": "^2.0.2", + "gentle-fs": "^2.0.0", + "graceful-fs": "^4.1.11", + "write-file-atomic": "^2.3.0" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true, + "requires": { + "inherits": "~2.0.0" + } + }, + "bluebird": { + "version": "3.5.3", + "bundled": true, + "dev": true + }, + "boxen": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "builtins": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "byline": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "byte-size": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "cacache": { + "version": "11.3.2", + "bundled": true, + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + }, + "dependencies": { + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "unique-filename": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true + } + } + }, + "call-limit": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "capture-stack-trace": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "chalk": { + "version": "2.4.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "cidr-regex": { + "version": "2.0.10", + "bundled": true, + "dev": true, + "requires": { + "ip-regex": "^2.1.0" + } + }, + "cli-boxes": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "cli-columns": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.0.0", + "strip-ansi": "^3.0.1" + } + }, + "cli-table3": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + } + }, + "cliui": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "cmd-shim": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "color-convert": { + "version": "1.9.1", + "bundled": true, + "dev": true, + "requires": { + "color-name": "^1.1.1" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "colors": { + "version": "1.3.3", + "bundled": true, + "dev": true, + "optional": true + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "dev": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, + "combined-stream": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "bundled": true, + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "config-chain": { + "version": "1.1.12", + "bundled": true, + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "configstore": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true, + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "create-error-class": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "cyclist": { + "version": "0.2.2", + "bundled": true, + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true + } + } + }, + "debuglog": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "deep-extend": { + "version": "0.5.1", + "bundled": true, + "dev": true + }, + "defaults": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "detect-indent": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "detect-newline": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "dot-prop": { + "version": "4.2.0", + "bundled": true, + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "dotenv": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "duplexify": { + "version": "3.6.0", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "editor": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "encoding": { + "version": "0.1.12", + "bundled": true, + "dev": true, + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "err-code": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "errno": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "es6-promise": { + "version": "4.2.6", + "bundled": true, + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "execa": { + "version": "0.7.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "figgy-pudding": { + "version": "3.5.1", + "bundled": true, + "dev": true + }, + "find-npm-prefix": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flush-write-stream": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true + }, + "form-data": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs-vacuum": { + "version": "1.2.10", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + }, + "dependencies": { + "iferr": { + "version": "0.1.5", + "bundled": true, + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "genfun": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "gentle-fs": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.2", + "fs-vacuum": "^1.2.10", + "graceful-fs": "^4.1.11", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "path-is-inside": "^1.0.2", + "read-cmd-shim": "^1.0.1", + "slide": "^1.1.6" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true, + "dev": true + } + } + }, + "get-caller-file": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "global-dirs": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "got": { + "version": "6.7.1", + "bundled": true, + "dev": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.1.15", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "har-validator": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "ajv": "^5.3.0", + "har-schema": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "hosted-git-info": { + "version": "2.7.1", + "bundled": true, + "dev": true + }, + "http-cache-semantics": { + "version": "3.8.1", + "bundled": true, + "dev": true + }, + "http-proxy-agent": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + } + }, + "http-signature": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + } + }, + "humanize-ms": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "iferr": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "import-lazy": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true + }, + "init-package-json": { + "version": "1.10.3", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.1", + "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^3.0.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "ip": { + "version": "1.1.5", + "bundled": true, + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "is-ci": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "ci-info": "^1.0.0" + }, + "dependencies": { + "ci-info": { + "version": "1.6.0", + "bundled": true, + "dev": true + } + } + }, + "is-cidr": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "cidr-regex": "^2.0.10" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + } + }, + "is-npm": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-obj": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-redirect": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-retry-allowed": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "bundled": true, + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "bundled": true, + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "latest-version": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "package-json": "^4.0.0" + } + }, + "lazy-property": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "lcid": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "libcipm": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "bin-links": "^1.1.2", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "graceful-fs": "^4.1.11", + "ini": "^1.3.5", + "lock-verify": "^2.0.2", + "mkdirp": "^0.5.1", + "npm-lifecycle": "^2.0.3", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "pacote": "^9.1.0", + "read-package-json": "^2.0.13", + "rimraf": "^2.6.2", + "worker-farm": "^1.6.0" + } + }, + "libnpm": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "bin-links": "^1.1.2", + "bluebird": "^3.5.3", + "find-npm-prefix": "^1.0.2", + "libnpmaccess": "^3.0.1", + "libnpmconfig": "^1.2.1", + "libnpmhook": "^5.0.2", + "libnpmorg": "^1.0.0", + "libnpmpublish": "^1.1.0", + "libnpmsearch": "^2.0.0", + "libnpmteam": "^1.0.1", + "lock-verify": "^2.0.2", + "npm-lifecycle": "^2.1.0", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "npm-profile": "^4.0.1", + "npm-registry-fetch": "^3.8.0", + "npmlog": "^4.1.2", + "pacote": "^9.2.3", + "read-package-json": "^2.0.13", + "stringify-package": "^1.0.0" + } + }, + "libnpmaccess": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "get-stream": "^4.0.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^3.8.0" + }, + "dependencies": { + "aproba": { + "version": "2.0.0", + "bundled": true, + "dev": true + } + } + }, + "libnpmconfig": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "find-up": "^3.0.0", + "ini": "^1.3.5" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "bundled": true, + "dev": true + } + } + }, + "libnpmhook": { + "version": "5.0.2", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^3.8.0" + } + }, + "libnpmorg": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^3.8.0" + }, + "dependencies": { + "aproba": { + "version": "2.0.0", + "bundled": true, + "dev": true + } + } + }, + "libnpmpublish": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.0.0", + "lodash.clonedeep": "^4.5.0", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^3.8.0", + "semver": "^5.5.1", + "ssri": "^6.0.1" + } + }, + "libnpmsearch": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^3.8.0" + } + }, + "libnpmteam": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^3.8.0" + }, + "dependencies": { + "aproba": { + "version": "2.0.0", + "bundled": true, + "dev": true + } + } + }, + "libnpx": { + "version": "10.2.0", + "bundled": true, + "dev": true, + "requires": { + "dotenv": "^5.0.1", + "npm-package-arg": "^6.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.0", + "update-notifier": "^2.3.0", + "which": "^1.3.0", + "y18n": "^4.0.0", + "yargs": "^11.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lock-verify": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "npm-package-arg": "^6.1.0", + "semver": "^5.4.1" + } + }, + "lockfile": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "signal-exit": "^3.0.2" + } + }, + "lodash._baseindexof": { + "version": "3.1.0", + "bundled": true, + "dev": true + }, + "lodash._baseuniq": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "requires": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "lodash._cacheindexof": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "lodash._createcache": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0" + } + }, + "lodash._createset": { + "version": "4.0.3", + "bundled": true, + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "bundled": true, + "dev": true + }, + "lodash._root": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "bundled": true, + "dev": true + }, + "lodash.restparam": { + "version": "3.6.1", + "bundled": true, + "dev": true + }, + "lodash.union": { + "version": "4.6.0", + "bundled": true, + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "bundled": true, + "dev": true + }, + "lodash.without": { + "version": "4.4.0", + "bundled": true, + "dev": true + }, + "lowercase-keys": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "bundled": true, + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "make-fetch-happen": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^11.0.1", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "meant": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "mem": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "mime-db": { + "version": "1.35.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.19", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "~1.35.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.3.3", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + }, + "dependencies": { + "yallist": { + "version": "3.0.2", + "bundled": true, + "dev": true + } + } + }, + "minizlib": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mississippi": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "move-concurrently": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + } + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "bundled": true, + "dev": true + }, + "node-fetch-npm": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-gyp": { + "version": "3.8.0", + "bundled": true, + "dev": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "nopt": { + "version": "3.0.6", + "bundled": true, + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + } + } + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "resolve": { + "version": "1.10.0", + "bundled": true, + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "npm-audit-report": { + "version": "1.3.2", + "bundled": true, + "dev": true, + "requires": { + "cli-table3": "^0.5.0", + "console-control-strings": "^1.1.0" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true + }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "npm-install-checks": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "semver": "^2.3.0 || 3.x || 4 || 5" + } + }, + "npm-lifecycle": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "byline": "^5.0.0", + "graceful-fs": "^4.1.11", + "node-gyp": "^3.8.0", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", + "uid-number": "0.0.6", + "umask": "^1.1.0", + "which": "^1.3.1" + } + }, + "npm-logical-tree": { + "version": "1.2.1", + "bundled": true, + "dev": true + }, + "npm-package-arg": { + "version": "6.1.0", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^2.6.0", + "osenv": "^0.1.5", + "semver": "^5.5.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "2.2.3", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "npm-profile": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.2 || 2", + "figgy-pudding": "^3.4.1", + "npm-registry-fetch": "^3.8.0" + } + }, + "npm-registry-fetch": { + "version": "3.9.0", + "bundled": true, + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^4.1.3", + "make-fetch-happen": "^4.0.1", + "npm-package-arg": "^6.1.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npm-user-validate": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.5.1", + "bundled": true, + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "package-json": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + } + }, + "pacote": { + "version": "9.5.0", + "bundled": true, + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cacache": "^11.3.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^4.0.1", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^2.2.3", + "npm-registry-fetch": "^3.8.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.8", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true + } + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "pify": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-retry": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "retry": { + "version": "0.10.1", + "bundled": true, + "dev": true + } + } + }, + "promzard": { + "version": "0.3.0", + "bundled": true, + "dev": true, + "requires": { + "read": "1" + } + }, + "proto-list": { + "version": "1.2.4", + "bundled": true, + "dev": true + }, + "protoduck": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "requires": { + "genfun": "^5.0.0" + } + }, + "prr": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "psl": { + "version": "1.1.29", + "bundled": true, + "dev": true + }, + "pump": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "bundled": true, + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "qs": { + "version": "6.5.2", + "bundled": true, + "dev": true + }, + "query-string": { + "version": "6.2.0", + "bundled": true, + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "strict-uri-encode": "^2.0.0" + } + }, + "qw": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "rc": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "requires": { + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true + } + } + }, + "read": { + "version": "1.0.7", + "bundled": true, + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "read-cmd-shim": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "graceful-fs": "^4.1.2", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + } + }, + "read-package-json": { + "version": "2.0.13", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "slash": "^1.0.0" + } + }, + "read-package-tree": { + "version": "5.2.2", + "bundled": true, + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "once": "^1.3.0", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0" + } + }, + "readable-stream": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-scoped-modules": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "registry-auth-token": { + "version": "3.3.2", + "bundled": true, + "dev": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "rc": "^1.0.1" + } + }, + "request": { + "version": "2.88.0", + "bundled": true, + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "retry": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-queue": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.1" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.6.0", + "bundled": true, + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "semver": "^5.0.3" + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "sha": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "slash": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "slide": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "smart-buffer": { + "version": "4.0.1", + "bundled": true, + "dev": true + }, + "socks": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.0.1" + } + }, + "socks-proxy-agent": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "~4.2.0", + "socks": "~2.2.0" + } + }, + "sorted-object": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "sorted-union-stream": { + "version": "2.1.3", + "bundled": true, + "dev": true, + "requires": { + "from2": "^1.3.0", + "stream-iterate": "^1.1.0" + }, + "dependencies": { + "from2": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.10" + } + }, + "isarray": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true, + "dev": true + } + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.3", + "bundled": true, + "dev": true + }, + "sshpk": { + "version": "1.14.2", + "bundled": true, + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stream-each": { + "version": "1.2.2", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-iterate": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "readable-stream": "^2.1.5", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-shift": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "strict-uri-encode": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringify-package": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + }, + "dependencies": { + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true + } + } + }, + "term-size": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "^0.7.0" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "through": { + "version": "2.3.8", + "bundled": true, + "dev": true + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "timed-out": { + "version": "4.0.1", + "bundled": true, + "dev": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "bundled": true, + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "typedarray": { + "version": "0.0.6", + "bundled": true, + "dev": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true + }, + "umask": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "unzip-response": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "update-notifier": { + "version": "2.5.0", + "bundled": true, + "dev": true, + "requires": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "url-parse-lax": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "util-extend": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "uuid": { + "version": "3.3.2", + "bundled": true, + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "verror": { + "version": "1.10.0", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "defaults": "^1.0.3" } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + }, + "which": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true, "dev": true - } - } - }, - "mocha": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.0.2.tgz", - "integrity": "sha512-RtTJsmmToGyeTznSOMoM6TPEk1A84FQaHIciKrRqARZx+B5ccJ5tXlmJzEKGBxZdqk9UjpRsesZTUkZmR5YnuQ==", - "dev": true, - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "findup-sync": "2.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.12.0", - "log-symbols": "2.2.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "ms": "2.1.1", - "node-environment-flags": "1.0.4", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "12.0.5", - "yargs-parser": "11.1.1", - "yargs-unparser": "1.5.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, "dev": true, "requires": { - "ms": "^2.1.1" + "string-width": "^1.0.2" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } } }, - "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "widest-line": { + "version": "2.0.0", + "bundled": true, "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "string-width": "^2.1.1" } }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "worker-farm": { + "version": "1.6.0", + "bundled": true, "dev": true, "requires": { - "has-flag": "^3.0.0" + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "2.4.2", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "xtend": { + "version": "4.0.1", + "bundled": true, + "dev": true + }, + "y18n": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "11.0.0", + "bundled": true, + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + }, + "dependencies": { + "y18n": { + "version": "3.2.1", + "bundled": true, + "dev": true + } + } + }, + "yargs-parser": { + "version": "9.0.2", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "^4.1.0" } } } }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "neo-async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", - "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node-environment-flags": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.4.tgz", - "integrity": "sha512-M9rwCnWVLW7PX+NUWe3ejEdiLYinRpsEre9hMkU/6NS4h+EEulYaDH1gCEZ2gyXsmw+RXYDaV2JkkTNcsPDJ0Q==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3" - } - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -3499,6 +6967,15 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "sanitize-filename": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.1.tgz", + "integrity": "sha1-YS2hyWRz+gLczaktzVtKsWSmdyo=", + "dev": true, + "requires": { + "truncate-utf8-bytes": "^1.0.0" + } + }, "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", @@ -3896,6 +7373,15 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, + "truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=", + "dev": true, + "requires": { + "utf8-byte-length": "^1.0.1" + } + }, "ts-node": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.0.3.tgz", @@ -4139,6 +7625,12 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "utf8-byte-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", + "integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=", + "dev": true + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", diff --git a/package.json b/package.json index a173e23..0f6f7b3 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "chai": "~4.2.0", "coveralls": "~3.0.2", "csv-parse": "~4.4.0", + "install-npm-version": "~1.0.3", "mocha": "~6.0.0", "nyc": "~13.3.0", "prettier": "~1.16.4", From 85e9bd5a16fffd31f21eb37d7618ac031925ec80 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Fri, 19 Apr 2019 07:20:01 +0000 Subject: [PATCH 33/38] Implement basic benchmarks Pre 2.0.0 instance methods vs >2.0.0 static methods --- benchmark.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 benchmark.js diff --git a/benchmark.js b/benchmark.js new file mode 100644 index 0000000..05afb63 --- /dev/null +++ b/benchmark.js @@ -0,0 +1,44 @@ +"use strict"; +const inv = require("install-npm-version"); +const benchmarkVersion = "1.0.1"; +const benchmarkLib = `postcode@${benchmarkVersion}`; + +const message = ` + Benchmarking master against ${benchmarkLib} + +`; + +inv + .Install(benchmarkLib, { Verbosity: "debug" }) + .then(() => runBenchmarks()) + .catch(error => { + console.log(error); + process.exit(1); + }); + +const runBenchmarks = () => { + const { Suite } = require("benchmark"); + const suite = new Suite(); + + const Postcode = require("./dist/index"); + const PreviousPostcode = require(benchmarkLib); + + const extractInputs = ({ tests }) => tests.map(({ base }) => base); + + const validation = extractInputs(require("./test/data/validation.json")); + suite + .add(`(version: ${benchmarkVersion}) Postcode#valid`, () => { + validation.forEach(postcode => { + const result = new PreviousPostcode(postcode).valid(); + }); + }) + .add("(version: master) Postcode.isValid", () => { + validation.forEach(postcode => { + const result = Postcode.isValid(postcode); + }); + }) + .on("cycle", event => { + console.log(String(event.target)); + }) + .run({}); +}; From 1cd240aae725e03fb7252e642335a7d1ea9c0dee Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Fri, 19 Apr 2019 07:53:16 +0000 Subject: [PATCH 34/38] Benchmark static methods --- benchmark.js | 151 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 135 insertions(+), 16 deletions(-) diff --git a/benchmark.js b/benchmark.js index 05afb63..97eb1b2 100644 --- a/benchmark.js +++ b/benchmark.js @@ -1,14 +1,26 @@ "use strict"; -const inv = require("install-npm-version"); -const benchmarkVersion = "1.0.1"; + +const benchmarkVersion = [...process.argv].pop(); + +const noVersionMessage = `Aborted benchmark + +Please specify a bench version. E.g: npm run benchmark -- 2.0.0 +`; + +if (benchmarkVersion.match(/\d+\.\d+\.\d+/) === null) { + console.log(noVersionMessage); + return process.exit(1); +} + const benchmarkLib = `postcode@${benchmarkVersion}`; const message = ` - Benchmarking master against ${benchmarkLib} - + Benchmarking master against postcode@${benchmarkLib} `; -inv +console.log(message); + +require("install-npm-version") .Install(benchmarkLib, { Verbosity: "debug" }) .then(() => runBenchmarks()) .catch(error => { @@ -18,7 +30,7 @@ inv const runBenchmarks = () => { const { Suite } = require("benchmark"); - const suite = new Suite(); + const newSuite = name => new Suite({ name }); const Postcode = require("./dist/index"); const PreviousPostcode = require(benchmarkLib); @@ -26,16 +38,123 @@ const runBenchmarks = () => { const extractInputs = ({ tests }) => tests.map(({ base }) => base); const validation = extractInputs(require("./test/data/validation.json")); - suite - .add(`(version: ${benchmarkVersion}) Postcode#valid`, () => { - validation.forEach(postcode => { - const result = new PreviousPostcode(postcode).valid(); - }); - }) - .add("(version: master) Postcode.isValid", () => { - validation.forEach(postcode => { - const result = Postcode.isValid(postcode); - }); + const areas = extractInputs(require("./test/data/areas.json")); + const districts = extractInputs(require("./test/data/districts.json")); + const incodes = extractInputs(require("./test/data/incodes.json")); + const normalisation = extractInputs( + require("./test/data/normalisation.json") + ); + const outcodes = extractInputs(require("./test/data/outcodes.json")); + const sectors = extractInputs(require("./test/data/sectors.json")); + const subDistricts = extractInputs(require("./test/data/sub-districts.json")); + const units = extractInputs(require("./test/data/units.json")); + + newSuite(".isValid") + .add(benchmarkVersion, () => { + validation.forEach(postcode => PreviousPostcode.isValid(postcode)); + }) + .add("master", () => { + validation.forEach(postcode => Postcode.isValid(postcode)); + }) + .on("cycle", event => { + console.log(String(event.target)); + }) + .run({}); + + newSuite(".toArea") + .add(benchmarkVersion, () => { + areas.forEach(postcode => PreviousPostcode.toArea(postcode)); + }) + .add("master", () => { + areas.forEach(postcode => Postcode.toArea(postcode)); + }) + .on("cycle", event => { + console.log(String(event.target)); + }) + .run({}); + + newSuite(".toDistrict") + .add(benchmarkVersion, () => { + districts.forEach(postcode => PreviousPostcode.toDistrict(postcode)); + }) + .add("master", () => { + districts.forEach(postcode => Postcode.toDistrict(postcode)); + }) + .on("cycle", event => { + console.log(String(event.target)); + }) + .run({}); + + newSuite(".toNormalised") + .add(benchmarkVersion, () => { + incodes.forEach(postcode => PreviousPostcode.toIncode(postcode)); + }) + .add("master", () => { + incodes.forEach(postcode => Postcode.toIncode(postcode)); + }) + .on("cycle", event => { + console.log(String(event.target)); + }) + .run({}); + + newSuite(".toNormalised") + .add(benchmarkVersion, () => { + normalisation.forEach(postcode => + PreviousPostcode.toNormalised(postcode) + ); + }) + .add("master", () => { + normalisation.forEach(postcode => Postcode.toNormalised(postcode)); + }) + .on("cycle", event => { + console.log(String(event.target)); + }) + .run({}); + + newSuite(".toOutcode") + .add(benchmarkVersion, () => { + outcodes.forEach(postcode => PreviousPostcode.toOutcode(postcode)); + }) + .add("master", () => { + outcodes.forEach(postcode => Postcode.toOutcode(postcode)); + }) + .on("cycle", event => { + console.log(String(event.target)); + }) + .run({}); + + newSuite(".toSector") + .add(benchmarkVersion, () => { + sectors.forEach(postcode => PreviousPostcode.toSector(postcode)); + }) + .add("master", () => { + sectors.forEach(postcode => Postcode.toSector(postcode)); + }) + .on("cycle", event => { + console.log(String(event.target)); + }) + .run({}); + + newSuite("toSubDistrict") + .add(benchmarkVersion, () => { + subDistricts.forEach(postcode => + PreviousPostcode.toSubDistrict(postcode) + ); + }) + .add("master", () => { + subDistricts.forEach(postcode => Postcode.toSubDistrict(postcode)); + }) + .on("cycle", event => { + console.log(String(event.target)); + }) + .run({}); + + newSuite("toUnit") + .add(benchmarkVersion, () => { + units.forEach(postcode => PreviousPostcode.toUnit(postcode)); + }) + .add("master", () => { + units.forEach(postcode => Postcode.toUnit(postcode)); }) .on("cycle", event => { console.log(String(event.target)); From 3737f700c235b2a62ab490b1167dd705bee823d5 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Fri, 19 Apr 2019 07:53:26 +0000 Subject: [PATCH 35/38] Fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b20f31e..16fde01 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ import Postcode from "postcode"; ### Validate ```javascript -Postcode.isValid("AA1 1AB"); # => true +Postcode.isValid("AA1 1AB"); // => true ``` ### Parse From b62073d37ae2b72158e187bc8740b42efb846ddb Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Fri, 19 Apr 2019 08:09:18 +0000 Subject: [PATCH 36/38] Documentation fixes - Object.freeze creates a readonly object that doesn't play will in TS 3.2 - Gitignore docs directory --- .gitignore | 2 ++ lib/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index a056594..9eafe5b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +# # Logs logs *.log @@ -59,4 +60,5 @@ dist .cache .DS_Store +docs diff --git a/lib/index.ts b/lib/index.ts index a5d2162..647be65 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -62,7 +62,7 @@ type InvalidPostcode = { unit: null; }; -const invalidPostcode: InvalidPostcode = Object.freeze({ +const invalidPostcode: InvalidPostcode = { valid: false, postcode: null, incode: null, @@ -72,7 +72,7 @@ const invalidPostcode: InvalidPostcode = Object.freeze({ subDistrict: null, sector: null, unit: null -}); +}; /** * Return first elem of input is RegExpMatchArray or null if input null From 445e748d3f50c67c0b659a712ce4bb416ad6ccce Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Fri, 19 Apr 2019 08:09:50 +0000 Subject: [PATCH 37/38] Prepare for publish --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 9e1b4f9..a4a4ab9 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ }, "scripts": { "test": "npm run lint && NODE_ENV=test node_modules/.bin/nyc node_modules/.bin/mocha", + "prepare": "npm test && npm run build", "lint": "node_modules/.bin/tslint -c tslint.json -p tsconfig.json", "docs": "./node_modules/.bin/typedoc --mode file --excludePrivate --hideGenerator --excludeExternals --target ES5 --out docs/ --name 'Postcode.js' --theme minimal lib/", "build": "./node_modules/.bin/tsc", From 87d03568cf4c2f6ebcf98dceeb3515ca83dbac18 Mon Sep 17 00:00:00 2001 From: Christopher Blanchard Date: Fri, 19 Apr 2019 08:23:27 +0000 Subject: [PATCH 38/38] Final update to docs - Add link to doc site - Add links to github repo and npm package --- CHANGELOG.md | 2 +- README.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9da7dac..f5b9551 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ Any changes, including backwards incompatible changes will be listed here - Provides a cleaner, more modern API to extract and parse while supporting old methods - Add static methods to extract single datapoints - Add a ValidPostcode class with accessor methods which can be destructured -- Updated documentation +- Updated documentation: [postcodejs.ideal-postcodes.dev](https://postcodejs.ideal-postcodes.dev) - Added benchmarking ## 1.0.1 (12/02/2019) diff --git a/README.md b/README.md index 16fde01..5326027 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,12 @@ Tested against ~1.7 million postcodes on ONSPD. ## Links +- [GitHub Repository](https://github.com/ideal-postcodes/openapi) - [API Documentation](https://postcodejs.ideal-postcodes.dev) - [Try postcode.js on RunKit](https://npm.runkit.com/postcode) - [Postcode element definitions](#definitions) - [Caveat on postcode validation](#note-on-postcode-Validation) +- [NPM Package](https://www.npmjs.com/package/postcode) ## Getting Started