From 0084f2e3229d9a36c4925d5a2c6356bff455fdc9 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Sat, 12 Sep 2020 21:22:10 +1000 Subject: [PATCH 01/45] Updating dependencies --- package-lock.json | 147 ++++++++++------------------------------------ package.json | 2 +- 2 files changed, 31 insertions(+), 118 deletions(-) diff --git a/package-lock.json b/package-lock.json index f5e1bdb..de2aaf4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -220,13 +220,6 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "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, - "optional": true - }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -296,9 +289,9 @@ } }, "diff": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.8.tgz", - "integrity": "sha1-NDJ2MI7Jkbe8giZ+1VvBQR+XFmY=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, "emoji-regex": { @@ -414,26 +407,6 @@ "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", "dev": true }, - "handlebars": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.3.tgz", - "integrity": "sha512-B0W4A2U1ww3q7VVthTKfh+epHx+q4mCt6iK+zEAzbMBpWQAwxCeKxEGpj/1oQTpzPXDNSOG7hmG14TsISH50yw==", - "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 - } - } - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -455,6 +428,12 @@ "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", "dev": true }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -583,12 +562,12 @@ } }, "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", "dev": true, "requires": { - "handlebars": "^4.1.2" + "html-escaper": "^2.0.0" } }, "js-tokens": { @@ -650,9 +629,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", "dev": true }, "lodash.flattendeep": { @@ -708,26 +687,18 @@ } }, "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "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 - } + "minimist": "^1.2.5" } }, "ms": { @@ -736,12 +707,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true - }, "nested-error-stacks": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", @@ -802,16 +767,6 @@ "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" - } - }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -1121,26 +1076,6 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, - "uglify-js": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.2.tgz", - "integrity": "sha512-+gh/xFte41GPrgSMJ/oJVq15zYmqr74pY9VoM69UzMzq9NFk4YDylclb1/bhEzZSaUQjbW5RvniHeq1cdtRYjw==", - "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 - } - } - }, "uuid": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", @@ -1158,30 +1093,14 @@ } }, "vows": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/vows/-/vows-0.8.2.tgz", - "integrity": "sha1-aR95qybM3oC6cm3en+yOc9a88us=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/vows/-/vows-0.8.3.tgz", + "integrity": "sha512-PVIxa/ovXhrw5gA3mz6M+ZF3PHlqX4tutR2p/y9NWPAaFVKcWBE8b2ktfr0opQM/qFmcOVWKjSCJVjnYOvjXhw==", "dev": true, "requires": { - "diff": "~1.0.8", + "diff": "^4.0.1", "eyes": "~0.1.6", "glob": "^7.1.2" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "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" - } - } } }, "which": { @@ -1199,12 +1118,6 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", @@ -1264,9 +1177,9 @@ } }, "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { "camelcase": "^5.0.0", diff --git a/package.json b/package.json index fd5747d..1628fbe 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ }, "devDependencies": { "nyc": "^14.1.1", - "vows": "^0.8.2" + "vows": "^0.8.3" }, "engines": { "node": ">=4" From 9feba2156c7caa1b8961b5d9db0c196720dc8e84 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Tue, 6 Oct 2020 09:23:56 +1100 Subject: [PATCH 02/45] typescript conversion --- .gitignore | 1 + lib/index.ts | 10 +++++ lib/positions.js | 5 --- lib/sets.js | 49 ---------------------- lib/sets.ts | 53 ++++++++++++++++++++++++ lib/{index.js => tokenizer.ts} | 61 +++++++++++++-------------- lib/types.js | 10 ----- lib/types/index.ts | 2 + lib/types/tokens.ts | 45 ++++++++++++++++++++ lib/types/types.ts | 10 +++++ lib/{util.js => util.ts} | 76 ++++++++++++++-------------------- package-lock.json | 5 +++ package.json | 12 ++++-- test/error-test.js | 2 +- test/main-test.js | 4 +- test/util-test.js | 6 +-- tsconfig.json | 69 ++++++++++++++++++++++++++++++ typings/index.d.ts | 68 ------------------------------ 18 files changed, 269 insertions(+), 219 deletions(-) create mode 100644 lib/index.ts delete mode 100644 lib/positions.js delete mode 100644 lib/sets.js create mode 100644 lib/sets.ts rename lib/{index.js => tokenizer.ts} (84%) delete mode 100644 lib/types.js create mode 100644 lib/types/index.ts create mode 100644 lib/types/tokens.ts create mode 100644 lib/types/types.ts rename lib/{util.js => util.ts} (55%) create mode 100644 tsconfig.json delete mode 100644 typings/index.d.ts diff --git a/.gitignore b/.gitignore index 1fd04da..b550492 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules coverage .nyc_output +dist \ No newline at end of file diff --git a/lib/index.ts b/lib/index.ts new file mode 100644 index 0000000..29109d4 --- /dev/null +++ b/lib/index.ts @@ -0,0 +1,10 @@ +import { types } from './types' +export * from './tokenizer' +import { tokenizer } from './tokenizer' +export * from './types' + +export default tokenizer +export { types } + +module.exports = tokenizer +module.exports.types = types diff --git a/lib/positions.js b/lib/positions.js deleted file mode 100644 index 894dedd..0000000 --- a/lib/positions.js +++ /dev/null @@ -1,5 +0,0 @@ -const types = require('./types'); -exports.wordBoundary = () => ({ type: types.POSITION, value: 'b' }); -exports.nonWordBoundary = () => ({ type: types.POSITION, value: 'B' }); -exports.begin = () => ({ type: types.POSITION, value: '^' }); -exports.end = () => ({ type: types.POSITION, value: '$' }); diff --git a/lib/sets.js b/lib/sets.js deleted file mode 100644 index 38a02ed..0000000 --- a/lib/sets.js +++ /dev/null @@ -1,49 +0,0 @@ -const types = require('./types'); - -const INTS = () => [{ type: types.RANGE , from: 48, to: 57 }]; - -const WORDS = () => { - return [ - { type: types.CHAR, value: 95 }, - { type: types.RANGE, from: 97, to: 122 }, - { type: types.RANGE, from: 65, to: 90 } - ].concat(INTS()); -}; - -const WHITESPACE = () => { - return [ - { type: types.CHAR, value: 9 }, - { type: types.CHAR, value: 10 }, - { type: types.CHAR, value: 11 }, - { type: types.CHAR, value: 12 }, - { type: types.CHAR, value: 13 }, - { type: types.CHAR, value: 32 }, - { type: types.CHAR, value: 160 }, - { type: types.CHAR, value: 5760 }, - { type: types.RANGE, from: 8192, to: 8202 }, - { type: types.CHAR, value: 8232 }, - { type: types.CHAR, value: 8233 }, - { type: types.CHAR, value: 8239 }, - { type: types.CHAR, value: 8287 }, - { type: types.CHAR, value: 12288 }, - { type: types.CHAR, value: 65279 } - ]; -}; - -const NOTANYCHAR = () => { - return [ - { type: types.CHAR, value: 10 }, - { type: types.CHAR, value: 13 }, - { type: types.CHAR, value: 8232 }, - { type: types.CHAR, value: 8233 }, - ]; -}; - -// Predefined class objects. -exports.words = () => ({ type: types.SET, set: WORDS(), not: false }); -exports.notWords = () => ({ type: types.SET, set: WORDS(), not: true }); -exports.ints = () => ({ type: types.SET, set: INTS(), not: false }); -exports.notInts = () => ({ type: types.SET, set: INTS(), not: true }); -exports.whitespace = () => ({ type: types.SET, set: WHITESPACE(), not: false }); -exports.notWhitespace = () => ({ type: types.SET, set: WHITESPACE(), not: true }); -exports.anyChar = () => ({ type: types.SET, set: NOTANYCHAR(), not: true }); diff --git a/lib/sets.ts b/lib/sets.ts new file mode 100644 index 0000000..6778f92 --- /dev/null +++ b/lib/sets.ts @@ -0,0 +1,53 @@ +import { types, Set, Range, Char } from './types' + +type SetsFunc = () => (Range | Char)[] +export type SetFunc = () => Set + +const INTS: SetsFunc = () => [{ type: types.RANGE , from: 48, to: 57 }]; + +const WORDS: SetsFunc = () => { + return [ + { type: types.CHAR, value: 95 }, + { type: types.RANGE, from: 97, to: 122 }, + { type: types.RANGE, from: 65, to: 90 }, + { type: types.RANGE , from: 48, to: 57 } + ]; +}; + +const WHITESPACE: SetsFunc = () => { + return [ + { type: types.CHAR, value: 9 }, + { type: types.CHAR, value: 10 }, + { type: types.CHAR, value: 11 }, + { type: types.CHAR, value: 12 }, + { type: types.CHAR, value: 13 }, + { type: types.CHAR, value: 32 }, + { type: types.CHAR, value: 160 }, + { type: types.CHAR, value: 5760 }, + { type: types.RANGE, from: 8192, to: 8202 }, + { type: types.CHAR, value: 8232 }, + { type: types.CHAR, value: 8233 }, + { type: types.CHAR, value: 8239 }, + { type: types.CHAR, value: 8287 }, + { type: types.CHAR, value: 12288 }, + { type: types.CHAR, value: 65279 } + ]; +}; + +const NOTANYCHAR: SetsFunc = () => { + return [ + { type: types.CHAR, value: 10 }, + { type: types.CHAR, value: 13 }, + { type: types.CHAR, value: 8232 }, + { type: types.CHAR, value: 8233 }, + ]; +}; + +// Predefined class objects. +export const words: SetFunc = () => ({ type: types.SET, set: WORDS(), not: false }); +export const notWords: SetFunc = () => ({ type: types.SET, set: WORDS(), not: true }); +export const ints: SetFunc = () => ({ type: types.SET, set: INTS(), not: false }); +export const notInts: SetFunc = () => ({ type: types.SET, set: INTS(), not: true }); +export const whitespace: SetFunc = () => ({ type: types.SET, set: WHITESPACE(), not: false }); +export const notWhitespace: SetFunc = () => ({ type: types.SET, set: WHITESPACE(), not: true }); +export const anyChar: SetFunc = () => ({ type: types.SET, set: NOTANYCHAR(), not: true }); diff --git a/lib/index.js b/lib/tokenizer.ts similarity index 84% rename from lib/index.js rename to lib/tokenizer.ts index df60171..e085e79 100644 --- a/lib/index.js +++ b/lib/tokenizer.ts @@ -1,43 +1,42 @@ -const util = require('./util'); -const types = require('./types'); -const sets = require('./sets'); -const positions = require('./positions'); - - -module.exports = (regexpStr) => { - let i = 0, l, c; - let start = { type: types.ROOT, stack: []}; +import * as util from './util' +import { Group, types, Root, Token } from './types' +import * as sets from './sets' + +/** + * Tokenizes a regular expression (that is currently a string) + * @param regexpStr String of regular expression to be tokenized + */ +export const tokenizer = (regexpStr: string): Root => { + let i: number = 0, c: string; + let start: Root = { type: types.ROOT, stack: [] }; // Keep track of last clause/group and stack. - let lastGroup = start; - let last = start.stack; - let groupStack = []; + let lastGroup: Group | Root = start; + let last: Token[] = start.stack ?? []; + let groupStack: (Group | Root)[] = []; - const repeatErr = (i) => { + const repeatErr = (i: number) => { util.error(regexpStr, `Nothing to repeat at column ${i - 1}`); }; // Decode a few escaped characters. let str = util.strToChars(regexpStr); - l = str.length; // Iterate through each character in string. - while (i < l) { + while (i < str.length) { c = str[i++]; switch (c) { // Handle escaped characters, inclues a few sets. case '\\': - c = str[i++]; - - switch (c) { + switch (c = str[i++]) { case 'b': - last.push(positions.wordBoundary()); + last.push({ type: types.POSITION, value: 'b'}); break; case 'B': - last.push(positions.nonWordBoundary()); + last.push({ type: types.POSITION, value: 'B'}); break; case 'w': @@ -72,7 +71,7 @@ module.exports = (regexpStr) => { // Escaped character. } else { - last.push({ type: types.CHAR, value: c.charCodeAt(0) }); + last.push({ type: types.CHAR, value: c.charCodeAt(0)}); } } @@ -81,11 +80,11 @@ module.exports = (regexpStr) => { // Positionals. case '^': - last.push(positions.begin()); + last.push({ type: types.POSITION, value: '^'}); break; case '$': - last.push(positions.end()); + last.push({ type: types.POSITION, value: '$'}); break; @@ -124,16 +123,14 @@ module.exports = (regexpStr) => { // Push group onto stack. case '(': { // Create group. - let group = { + let group: Group = { type: types.GROUP, stack: [], remember: true, }; - c = str[i]; - // If if this is a special kind of group. - if (c === '?') { + if (str[i] === '?') { c = str[i + 1]; i += 2; @@ -177,7 +174,9 @@ module.exports = (regexpStr) => { // Check if this group has a PIPE. // To get back the correct last stack. last = lastGroup.options ? - lastGroup.options[lastGroup.options.length - 1] : lastGroup.stack; + lastGroup.options[lastGroup.options.length - 1] : + lastGroup.stack; + break; @@ -189,11 +188,11 @@ module.exports = (regexpStr) => { lastGroup.options = [lastGroup.stack]; delete lastGroup.stack; } - // Create a new stack and add to options for rest of clause. - let stack = []; + let stack: Token[] = []; lastGroup.options.push(stack); last = stack; + break; } @@ -282,5 +281,3 @@ module.exports = (regexpStr) => { return start; }; - -module.exports.types = types; diff --git a/lib/types.js b/lib/types.js deleted file mode 100644 index 9484145..0000000 --- a/lib/types.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - ROOT : 0, - GROUP : 1, - POSITION : 2, - SET : 3, - RANGE : 4, - REPETITION : 5, - REFERENCE : 6, - CHAR : 7, -}; diff --git a/lib/types/index.ts b/lib/types/index.ts new file mode 100644 index 0000000..c3f7e5d --- /dev/null +++ b/lib/types/index.ts @@ -0,0 +1,2 @@ +export * from './tokens' +export * from './types' diff --git a/lib/types/tokens.ts b/lib/types/tokens.ts new file mode 100644 index 0000000..0875a45 --- /dev/null +++ b/lib/types/tokens.ts @@ -0,0 +1,45 @@ +import { types } from "./types" + +type Base = { type: T } & K + +type ValueType = Base + +export type Root = Base + +export type Group = Base + +export type Set = Base + +export type Range = Base + +export type Repetition = Base + +export type Position = ValueType +export type Reference = ValueType +export type Char = ValueType + +export type Token = Group | Position | Set | Range | Repetition | Reference | Char +export type Tokens = Root | Token + +export type SetTokens = (Range | Char | Set)[] diff --git a/lib/types/types.ts b/lib/types/types.ts new file mode 100644 index 0000000..bebc118 --- /dev/null +++ b/lib/types/types.ts @@ -0,0 +1,10 @@ +export enum types { + ROOT, + GROUP, + POSITION, + SET, + RANGE, + REPETITION, + REFERENCE, + CHAR +}; diff --git a/lib/util.js b/lib/util.ts similarity index 55% rename from lib/util.js rename to lib/util.ts index b650d7a..492cde4 100644 --- a/lib/util.js +++ b/lib/util.ts @@ -1,9 +1,7 @@ -const types = require('./types'); -const sets = require('./sets'); - +import { types, SetTokens } from './types' +import * as sets from './sets' const CTRL = '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ ?'; -const SLSH = { '0': 0, 't': 9, 'n': 10, 'v': 11, 'f': 12, 'r': 13 }; /** * Finds character representations in str and convert all to @@ -12,7 +10,7 @@ const SLSH = { '0': 0, 't': 9, 'n': 10, 'v': 11, 'f': 12, 'r': 13 }; * @param {string} str * @return {string} */ -exports.strToChars = (str) => { +export const strToChars = (str: string) => { /* jshint maxlen: false */ const charsRegex = /(\[\\b\])|(\\)?\\(?:u([A-F0-9]{4})|x([A-F0-9]{2})|(0?[0-7]{2})|c([@A-Z[\\\]^?])|([0tnvfr]))/g; return str.replace(charsRegex, (s, b, lbs, a16, b16, c8, dctrl, eslsh) => { @@ -20,12 +18,20 @@ exports.strToChars = (str) => { return s; } - let code = b ? 8 : + let code: number | undefined = b ? 8 : a16 ? parseInt(a16, 16) : b16 ? parseInt(b16, 16) : c8 ? parseInt(c8, 8) : dctrl ? CTRL.indexOf(dctrl) : - SLSH[eslsh]; + eslsh == '0' ? 0 : + eslsh == 't' ? 9 : + eslsh == 'n' ? 10 : + eslsh == 'v' ? 11 : + eslsh == 'f' ? 12 : + eslsh == 'r' ? 13 : undefined; + + if (!code) + throw new Error(`Code is undefined`) let c = String.fromCharCode(code); @@ -47,51 +53,31 @@ exports.strToChars = (str) => { * @param {string} regexpStr * @return {Array., number>} */ -exports.tokenizeClass = (str, regexpStr) => { - /* jshint maxlen: false */ - let tokens = []; +export const tokenizeClass = (str: string, regexpStr: string): [SetTokens, number] => { + let tokens: SetTokens = [], rs: string[] | null, c: string; const regexp = /\\(?:(w)|(d)|(s)|(W)|(D)|(S))|((?:(?:\\)(.)|([^\]\\]))-(?:\\)?([^\]]))|(\])|(?:\\)?([^])/g; - let rs, c; - while ((rs = regexp.exec(str)) != null) { - if (rs[1]) { - tokens.push(sets.words()); - - } else if (rs[2]) { - tokens.push(sets.ints()); - - } else if (rs[3]) { - tokens.push(sets.whitespace()); - - } else if (rs[4]) { - tokens.push(sets.notWords()); - - } else if (rs[5]) { - tokens.push(sets.notInts()); - - } else if (rs[6]) { - tokens.push(sets.notWhitespace()); - - } else if (rs[7]) { - tokens.push({ + const p = (rs[1] && sets.words()) + ?? (rs[2] && sets.ints()) + ?? (rs[3] && sets.whitespace()) + ?? (rs[4] && sets.notWords()) + ?? (rs[5] && sets.notInts()) + ?? (rs[6] && sets.notWhitespace()) + ?? (rs[7] && { type: types.RANGE, from: (rs[8] || rs[9]).charCodeAt(0), - to: rs[10].charCodeAt(0), - }); + to: rs[10].charCodeAt(0) + }) + ?? ((c = rs[12]) && { type: types.CHAR, value: c.charCodeAt(0) }) - } else if ((c = rs[12])) { - tokens.push({ - type: types.CHAR, - value: c.charCodeAt(0), - }); - - } else { + if (p) + tokens.push(p); + else return [tokens, regexp.lastIndex]; - } } - - exports.error(regexpStr, 'Unterminated character class'); + error(regexpStr, 'Unterminated character class') + throw new SyntaxError(`Invalid regular expression: ${str}: Unterminated character class`) }; @@ -101,6 +87,6 @@ exports.tokenizeClass = (str, regexpStr) => { * @param {string} regexp * @param {string} msg */ -exports.error = (regexp, msg) => { +export const error = (regexp: string, msg: string) => { throw new SyntaxError('Invalid regular expression: /' + regexp + '/: ' + msg); }; diff --git a/package-lock.json b/package-lock.json index de2aaf4..5a15dd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -110,6 +110,11 @@ "to-fast-properties": "^2.0.0" } }, + "@types/node": { + "version": "14.11.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz", + "integrity": "sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA==" + }, "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", diff --git a/package.json b/package.json index 1628fbe..cd14c3f 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,12 @@ "main": "./lib/index.js", "types": "./typings/index.d.ts", "files": [ - "lib", - "typings" + "dist" ], "scripts": { - "test": "nyc --extension --reporter=lcov --reporter=text-summary vows -- --spec test/*-test.js" + "test": "nyc --extension --reporter=lcov --reporter=text-summary vows -- --spec test/*-test.js", + "build" : "tsc", + "prepare" : "tsc" }, "directories": { "lib": "./lib" @@ -33,5 +34,8 @@ "engines": { "node": ">=4" }, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@types/node": "^14.11.2" + } } diff --git a/test/error-test.js b/test/error-test.js index 3354082..781f306 100644 --- a/test/error-test.js +++ b/test/error-test.js @@ -1,6 +1,6 @@ const vows = require('vows'); const assert = require('assert'); -const ret = require('..'); +const ret = require('../dist'); /** diff --git a/test/main-test.js b/test/main-test.js index 6729d83..d252d2e 100644 --- a/test/main-test.js +++ b/test/main-test.js @@ -1,7 +1,7 @@ const vows = require('vows'); const assert = require('assert'); -const sets = require('../lib/sets'); -const ret = require('..'); +const sets = require('../dist/sets'); +const ret = require('../dist'); const types = ret.types; diff --git a/test/util-test.js b/test/util-test.js index ae1b5de..72488a2 100644 --- a/test/util-test.js +++ b/test/util-test.js @@ -1,8 +1,8 @@ const vows = require('vows'); const assert = require('assert'); -const util = require('../lib/util'); -const types = require('..').types; -const sets = require('../lib/sets'); +const util = require('../dist/util'); +const types = require('../dist').types; +const sets = require('../dist/sets'); vows.describe('strToChars') diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c8fa6e6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,69 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + // "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + "strictNullChecks": false, /* Enable strict null checks. */ + "strictFunctionTypes": true, /* Enable strict checking of function types. */ + "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + "strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */ + "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + "noUnusedLocals": true, /* Report errors on unused locals. */ + "noUnusedParameters": true, /* Report errors on unused parameters. */ + "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} diff --git a/typings/index.d.ts b/typings/index.d.ts deleted file mode 100644 index 6fe2288..0000000 --- a/typings/index.d.ts +++ /dev/null @@ -1,68 +0,0 @@ -declare function ret(input: string): ret.Root; - -declare namespace ret { - enum types { - ROOT = 0, - GROUP = 1, - POSITION = 2, - SET = 3, - RANGE = 4, - REPETITION = 5, - REFERENCE = 6, - CHAR = 7 - } - - type Token = Group | Position | Set | Range | Repetition | Reference | Char; - type Tokens = Root | Token; - - type Root = { - type: types.ROOT; - stack?: Token[]; - options?: Token[][]; - }; - - type Group = { - type: types.GROUP; - remember: boolean; - stack?: Token[]; - options?: Token[][]; - followedBy?: boolean; - notFollowedBy?: boolean; - }; - - type Position = { - type: types.POSITION; - value: "^" | "$" | "B" | "b"; - }; - - type Set = { - type: types.SET; - set: (Set | Range | Char)[]; - not: boolean; - }; - - type Range = { - type: types.RANGE; - from: number; - to: number; - }; - - type Repetition = { - type: types.REPETITION; - min: number; - max: number; - value: Token; - }; - - type Reference = { - type: types.REFERENCE; - value: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; - }; - - type Char = { - type: types.CHAR; - value: number; - }; -} - -export = ret; From 5d0c15b7bd9089265e2ffb5317ac714a471486e7 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Tue, 6 Oct 2020 09:30:24 +1100 Subject: [PATCH 03/45] style fixes --- lib/index.ts | 16 ++++++++-------- lib/tokenizer.ts | 42 ++++++++++++++++++++++-------------------- lib/types/index.ts | 4 ++-- lib/types/tokens.ts | 2 +- lib/util.ts | 2 +- package.json | 3 --- 6 files changed, 34 insertions(+), 35 deletions(-) diff --git a/lib/index.ts b/lib/index.ts index 29109d4..3736b92 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,10 +1,10 @@ -import { types } from './types' -export * from './tokenizer' -import { tokenizer } from './tokenizer' -export * from './types' +import { types } from './types'; +export * from './tokenizer'; +import { tokenizer } from './tokenizer'; +export * from './types'; -export default tokenizer -export { types } +export default tokenizer; +export { types }; -module.exports = tokenizer -module.exports.types = types +module.exports = tokenizer; +module.exports.types = types; diff --git a/lib/tokenizer.ts b/lib/tokenizer.ts index e085e79..6fb044f 100644 --- a/lib/tokenizer.ts +++ b/lib/tokenizer.ts @@ -25,9 +25,7 @@ export const tokenizer = (regexpStr: string): Root => { // Iterate through each character in string. while (i < str.length) { - c = str[i++]; - - switch (c) { + switch (c = str[i++]) { // Handle escaped characters, inclues a few sets. case '\\': switch (c = str[i++]) { @@ -71,20 +69,20 @@ export const tokenizer = (regexpStr: string): Root => { // Escaped character. } else { - last.push({ type: types.CHAR, value: c.charCodeAt(0)}); - } - } + last.push({ type: types.CHAR, value: c.charCodeAt(0) }); + }; + }; break; // Positionals. case '^': - last.push({ type: types.POSITION, value: '^'}); + last.push({ type: types.POSITION, value: '^' }); break; case '$': - last.push({ type: types.POSITION, value: '$'}); + last.push({ type: types.POSITION, value: '$' }); break; @@ -111,7 +109,7 @@ export const tokenizer = (regexpStr: string): Root => { }); break; - } + }; // Class of any character except \n. @@ -146,10 +144,10 @@ export const tokenizer = (regexpStr: string): Root => { util.error(regexpStr, `Invalid group, character '${c}'` + ` after '?' at column ${i - 1}`); - } + }; group.remember = false; - } + }; // Insert subgroup into current group stack. last.push(group); @@ -160,6 +158,7 @@ export const tokenizer = (regexpStr: string): Root => { // Make this new group the current group. lastGroup = group; last = group.stack; + break; } @@ -168,7 +167,7 @@ export const tokenizer = (regexpStr: string): Root => { case ')': if (groupStack.length === 0) { util.error(regexpStr, `Unmatched ) at column ${i - 1}`); - } + }; lastGroup = groupStack.pop(); // Check if this group has a PIPE. @@ -187,14 +186,14 @@ export const tokenizer = (regexpStr: string): Root => { if (!lastGroup.options) { lastGroup.options = [lastGroup.stack]; delete lastGroup.stack; - } + }; // Create a new stack and add to options for rest of clause. let stack: Token[] = []; lastGroup.options.push(stack); last = stack; - + break; - } + }; // Repetition. @@ -223,9 +222,10 @@ export const tokenizer = (regexpStr: string): Root => { type: types.CHAR, value: 123, }); - } + }; + break; - } + }; case '?': if (last.length === 0) { @@ -249,6 +249,7 @@ export const tokenizer = (regexpStr: string): Root => { max: Infinity, value: last.pop(), }); + break; case '*': @@ -261,6 +262,7 @@ export const tokenizer = (regexpStr: string): Root => { max: Infinity, value: last.pop(), }); + break; @@ -270,14 +272,14 @@ export const tokenizer = (regexpStr: string): Root => { type: types.CHAR, value: c.charCodeAt(0), }); - } + }; - } + }; // Check if any groups have not been closed. if (groupStack.length !== 0) { util.error(regexpStr, 'Unterminated group'); - } + }; return start; }; diff --git a/lib/types/index.ts b/lib/types/index.ts index c3f7e5d..1b22cc5 100644 --- a/lib/types/index.ts +++ b/lib/types/index.ts @@ -1,2 +1,2 @@ -export * from './tokens' -export * from './types' +export * from './tokens'; +export * from './types'; diff --git a/lib/types/tokens.ts b/lib/types/tokens.ts index 0875a45..b82b502 100644 --- a/lib/types/tokens.ts +++ b/lib/types/tokens.ts @@ -1,4 +1,4 @@ -import { types } from "./types" +import { types } from './types' type Base = { type: T } & K diff --git a/lib/util.ts b/lib/util.ts index 492cde4..6ddda51 100644 --- a/lib/util.ts +++ b/lib/util.ts @@ -75,7 +75,7 @@ export const tokenizeClass = (str: string, regexpStr: string): [SetTokens, numbe tokens.push(p); else return [tokens, regexp.lastIndex]; - } + }; error(regexpStr, 'Unterminated character class') throw new SyntaxError(`Invalid regular expression: ${str}: Unterminated character class`) }; diff --git a/package.json b/package.json index cd14c3f..c629aec 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,6 @@ "build" : "tsc", "prepare" : "tsc" }, - "directories": { - "lib": "./lib" - }, "devDependencies": { "nyc": "^14.1.1", "vows": "^0.8.3" From 91dd1d0e1b0ab17c3c01352d01f7635f68da079c Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Tue, 6 Oct 2020 09:44:15 +1100 Subject: [PATCH 04/45] adding reconstruction functionality --- lib/reconstruct.ts | 75 ++++++++++++++++++++++++++++++++ package.json | 4 +- test/reconstruct-test.js | 93 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 lib/reconstruct.ts create mode 100644 test/reconstruct-test.js diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts new file mode 100644 index 0000000..b366230 --- /dev/null +++ b/lib/reconstruct.ts @@ -0,0 +1,75 @@ +import { types, Root, Token, Tokens, Group } from './types'; +import * as sets from './sets'; + +const simplifications: [sets.SetFunc, string][] = [ + [sets.words, '\\w'], + [sets.notWords, '\\W'], + [sets.ints, '\\d'], + [sets.notInts, '\\D'], + [sets.whitespace, '\\s'], + [sets.notWhitespace, '\\S'], + [sets.anyChar, '.'] +]; + +const reduceStack = (stack: Token[]): string => stack.map(partialConstruct).join(''); + +const createAlternate = (token: Root | Group): string => { + if ('options' in token) { + return token.options?.map(reduceStack).join('|') ?? '' + } else if ('stack' in token) { + return reduceStack(token.stack); + } else { + throw new Error(`options or stack must be within Root/Group: ${token}`); + } +}; + +export const reconstruct = (regexpToken: Root): string => partialConstruct(regexpToken); + +export const partialConstruct = (token: Tokens): string => { + switch (token.type) { + case types.ROOT: + return createAlternate(token); + case types.CHAR: + const c = String.fromCharCode(token.value); + return (/[[\]^.\/|?*+()]/.test(c) ? '\\' : '') + String.fromCharCode(token.value); + case types.POSITION: + if (token.value === '^' || token.value === '$') { + return `${token.value}`; + } else { + return `\\${token.value}`; + }; + case types.REFERENCE: + return `\\${token.value}`; + case types.SET: + for (const [set, simplification] of simplifications) { + if (JSON.stringify(set()) === JSON.stringify(token)) { + return simplification; + }; + }; + return `[${token.not ? '^' : ''}${reduceStack(token.set)}]`; + case types.RANGE: + return `${String.fromCharCode(token.from)}-${String.fromCharCode(token.to)}`; + case types.GROUP: + // Check token.remember + return `(${!token.remember ? '?' : ''}${token.lookBehind ? '<' : ''}${token.followedBy ? '=' : + token.notFollowedBy ? '!' : + (token.remember ? '' : ':') + }${createAlternate(token)})` + case types.REPETITION: + const { min, max } = token; + let endWith; + if (min === 0 && max === 1) { + endWith = '?'; + } else if (min === 1 && max === Infinity) { + endWith = '+'; + } else if (min === 0 && max === Infinity) { + endWith = '\*'; + } else { + endWith = max === Infinity ? `{${min},}` + : `{${min}${min === max ? `` : `,${max}`}}`; + } + return `${partialConstruct(token.value)}${endWith}`; + default: + throw new Error(`Invalid token type ${token}`); + }; +}; diff --git a/package.json b/package.json index c629aec..945b8a6 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ ], "scripts": { "test": "nyc --extension --reporter=lcov --reporter=text-summary vows -- --spec test/*-test.js", - "build" : "tsc", - "prepare" : "tsc" + "build": "tsc", + "prepare": "tsc" }, "devDependencies": { "nyc": "^14.1.1", diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js new file mode 100644 index 0000000..51ed1d9 --- /dev/null +++ b/test/reconstruct-test.js @@ -0,0 +1,93 @@ +const vows = require('vows'); +const assert = require('assert'); +const ret = require('../dist'); +const reconstruct = require('../dist/reconstruct').reconstruct +const partialConstruct = require('../dist/reconstruct').partialConstruct + +const inverseTestFactory = (regexp) => { + return { + topic: ret(regexp), + + [`Checking ${regexp} reconstructs`]: (t) => { + const reconstructed = reconstruct(t) // May need to do some sort of sanitisation here + assert.isString(reconstructed); + assert.deepStrictEqual(reconstructed, regexp.replace('[^0-9]', '\\D')) + }, + + [`Checking ${regexp} reconstructs using partialConstruct`]: (t) => { + const reconstructed = partialConstruct(t) // May need to do some sort of sanitisation here + assert.isString(reconstructed); + assert.deepStrictEqual(reconstructed, regexp.replace('[^0-9]', '\\D')) + } + } +} + +/*! fromentries. MIT License. Feross Aboukhadijeh */ +function fromEntries(iterable) { + return [...iterable].reduce((obj, [key, val]) => { + obj[key] = val + return obj + }, {}) +} + +const multiInverseTestFactory = regexps => fromEntries( + regexps.map(regexp => [regexp, inverseTestFactory(regexp)]) +) + +vows.describe('Regexp Reconstruction') + .addBatch({ + 'basic (using inverse of Ret)': multiInverseTestFactory([ + '', + 'a', + '1', + '.', + ',', + 'word', + '\\/\\/', + '\\W', + '\\D', + '\\w\\W\\d\\D\\s\\S.' + ]), + 'testing start and finish flags (using inverse of Ret)': multiInverseTestFactory([ + '$', + '^', + '$a^', + '.^', + '$,', + '$word^', + '$\\/\\/^', + '$\\W^', + '$\\D^', + '$\\w\\W\\d\\D\\s\\S.^' + ]), + 'all main regexp expressions': { + 'No special characters': inverseTestFactory('walnuts'), + '^ and $ in': inverseTestFactory('^yes$'), + '\\b and \\B': inverseTestFactory('\\bbeginning\\B'), + 'Predefined sets': inverseTestFactory('\\w\\W\\d\\D\\s\\S.'), + 'Custom Sets': inverseTestFactory('[$!a-z123] thing [^0-9]'), + 'Whitespace characters': inverseTestFactory('[\t\r\n\u2028\u2029 ]'), + 'Two sets in a row with dash in between': inverseTestFactory('[01]-[ab]'), + '| (Pipe)': inverseTestFactory('foo|bar|za'), + 'Group': { + 'with no special characters': inverseTestFactory('hey (there)'), + 'that is not rememered': inverseTestFactory('(?:loner)'), + 'matched previous clause if not followed by this': inverseTestFactory('what(?!ever)'), + 'matched next clause': inverseTestFactory('hello(?= there)'), + 'with subgroup': inverseTestFactory('a(b(c|(?:d))fg) @_@') + }, + 'Custom repetition with': { + 'exact amount': inverseTestFactory('(?:pika){2}'), + 'minimum amount only': inverseTestFactory('NO{6,}'), + 'both minimum and maximum': inverseTestFactory('pika\\.\\.\\. chu{3,20}!{1,2}'), + 'Brackets around a non-repetitional': inverseTestFactory('a{mustache}'), + 'Predefined repetitional': { + '? (Optional)': inverseTestFactory('hey(?: you)?'), + '+ (At least one)': inverseTestFactory('(no )+'), + '* (Any amount)': inverseTestFactory('XF*D'), + }, + 'Reference': inverseTestFactory('<(\\w+)>\\w*<\\1>'), + } + } + }) + .export(module); From f630388467f0908b248a4f1863585ea1187feb7b Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Tue, 6 Oct 2020 09:46:25 +1100 Subject: [PATCH 05/45] exporting reconstruct from index --- lib/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/index.ts b/lib/index.ts index 3736b92..62a404f 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,5 +1,6 @@ import { types } from './types'; export * from './tokenizer'; +export * from './reconstruct'; import { tokenizer } from './tokenizer'; export * from './types'; From 3cf736460478f680faf02ea04be5b9197ded9aff Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 9 Oct 2020 22:06:28 +1100 Subject: [PATCH 06/45] Update lib/types/tokens.ts Co-authored-by: fent --- lib/types/tokens.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/types/tokens.ts b/lib/types/tokens.ts index b82b502..d9dc437 100644 --- a/lib/types/tokens.ts +++ b/lib/types/tokens.ts @@ -20,7 +20,7 @@ export type Group = Base export type Set = Base From 8bfcd6fffb0cefbc23c0e3815f4bb6ffcb9cc007 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 9 Oct 2020 22:06:42 +1100 Subject: [PATCH 07/45] Update lib/types/tokens.ts Co-authored-by: fent --- lib/types/tokens.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/types/tokens.ts b/lib/types/tokens.ts index d9dc437..06aec32 100644 --- a/lib/types/tokens.ts +++ b/lib/types/tokens.ts @@ -5,7 +5,7 @@ type Base = { type: T } & K type ValueType = Base export type Root = Base From 470f570e1ec1ff29d1acbe599bfdfcfb93847829 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 9 Oct 2020 22:08:15 +1100 Subject: [PATCH 08/45] Update lib/tokenizer.ts Co-authored-by: fent --- lib/tokenizer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tokenizer.ts b/lib/tokenizer.ts index 6fb044f..f145a29 100644 --- a/lib/tokenizer.ts +++ b/lib/tokenizer.ts @@ -12,7 +12,7 @@ export const tokenizer = (regexpStr: string): Root => { // Keep track of last clause/group and stack. let lastGroup: Group | Root = start; - let last: Token[] = start.stack ?? []; + let last: Token[] = start.stack; let groupStack: (Group | Root)[] = []; From fb2b785fb1afbede2d1bae302072025f7fcd86ca Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 9 Oct 2020 22:36:48 +1100 Subject: [PATCH 09/45] Fixing review comments in PR24 --- lib/util.ts | 17 +++++++++-------- package-lock.json | 13 ++++++++++--- package.json | 10 +++++----- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/lib/util.ts b/lib/util.ts index 6ddda51..9f47298 100644 --- a/lib/util.ts +++ b/lib/util.ts @@ -16,7 +16,7 @@ export const strToChars = (str: string) => { return str.replace(charsRegex, (s, b, lbs, a16, b16, c8, dctrl, eslsh) => { if (lbs) { return s; - } + }; let code: number | undefined = b ? 8 : a16 ? parseInt(a16, 16) : @@ -30,15 +30,16 @@ export const strToChars = (str: string) => { eslsh == 'f' ? 12 : eslsh == 'r' ? 13 : undefined; - if (!code) - throw new Error(`Code is undefined`) + if (!code) { + throw new Error(`Code is undefined`); + }; let c = String.fromCharCode(code); // Escape special regex characters. if (/[[\]{}^$.|?*+()]/.test(c)) { c = '\\' + c; - } + }; return c; }); @@ -71,13 +72,13 @@ export const tokenizeClass = (str: string, regexpStr: string): [SetTokens, numbe }) ?? ((c = rs[12]) && { type: types.CHAR, value: c.charCodeAt(0) }) - if (p) + if (p) { tokens.push(p); - else + } else { return [tokens, regexp.lastIndex]; + }; }; - error(regexpStr, 'Unterminated character class') - throw new SyntaxError(`Invalid regular expression: ${str}: Unterminated character class`) + throw new SyntaxError('Invalid regular expression: /' + regexpStr + '/: Unterminated character class'); }; diff --git a/package-lock.json b/package-lock.json index 5a15dd8..e30723a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -111,9 +111,10 @@ } }, "@types/node": { - "version": "14.11.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz", - "integrity": "sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA==" + "version": "14.11.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.8.tgz", + "integrity": "sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw==", + "dev": true }, "ansi-regex": { "version": "4.1.0", @@ -1081,6 +1082,12 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, + "typescript": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz", + "integrity": "sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==", + "dev": true + }, "uuid": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", diff --git a/package.json b/package.json index c629aec..34a9644 100644 --- a/package.json +++ b/package.json @@ -21,18 +21,18 @@ ], "scripts": { "test": "nyc --extension --reporter=lcov --reporter=text-summary vows -- --spec test/*-test.js", - "build" : "tsc", - "prepare" : "tsc" + "build": "tsc", + "prepare": "tsc" }, "devDependencies": { + "@types/node": "^14.11.8", "nyc": "^14.1.1", + "typescript": "^4.0.3", "vows": "^0.8.3" }, "engines": { "node": ">=4" }, "license": "MIT", - "dependencies": { - "@types/node": "^14.11.2" - } + "dependencies": {} } From f8523f02bc348f280e3416e450da697a27363ebb Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Sat, 10 Oct 2020 23:39:30 +1100 Subject: [PATCH 10/45] Putting SyntaxError inline to be recognised by typescript compiler --- lib/tokenizer.ts | 27 +++++++++++++++++++++------ lib/util.ts | 11 ----------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/lib/tokenizer.ts b/lib/tokenizer.ts index f145a29..93fe17a 100644 --- a/lib/tokenizer.ts +++ b/lib/tokenizer.ts @@ -17,7 +17,11 @@ export const tokenizer = (regexpStr: string): Root => { const repeatErr = (i: number) => { - util.error(regexpStr, `Nothing to repeat at column ${i - 1}`); + throw new SyntaxError( + 'Invalid regular expression: /' + + regexpStr + + `/: Nothing to repeat at column ${i - 1}` + ); }; // Decode a few escaped characters. @@ -141,9 +145,12 @@ export const tokenizer = (regexpStr: string): Root => { group.notFollowedBy = true; } else if (c !== ':') { - util.error(regexpStr, - `Invalid group, character '${c}'` + - ` after '?' at column ${i - 1}`); + throw new SyntaxError( + 'Invalid regular expression: /' + + regexpStr + + `/: Invalid group, character '${c}'` + + ` after '?' at column ${i - 1}` + ); }; group.remember = false; @@ -166,7 +173,11 @@ export const tokenizer = (regexpStr: string): Root => { // Pop group out of stack. case ')': if (groupStack.length === 0) { - util.error(regexpStr, `Unmatched ) at column ${i - 1}`); + throw new SyntaxError( + 'Invalid regular expression: /' + + regexpStr + + `/: Unmatched ) at column ${i - 1}` + ); }; lastGroup = groupStack.pop(); @@ -278,7 +289,11 @@ export const tokenizer = (regexpStr: string): Root => { // Check if any groups have not been closed. if (groupStack.length !== 0) { - util.error(regexpStr, 'Unterminated group'); + throw new SyntaxError( + 'Invalid regular expression: /' + + regexpStr + + '/: Unterminated group' + ); }; return start; diff --git a/lib/util.ts b/lib/util.ts index 9f47298..6ba87d6 100644 --- a/lib/util.ts +++ b/lib/util.ts @@ -80,14 +80,3 @@ export const tokenizeClass = (str: string, regexpStr: string): [SetTokens, numbe }; throw new SyntaxError('Invalid regular expression: /' + regexpStr + '/: Unterminated character class'); }; - - -/** - * Shortcut to throw errors. - * - * @param {string} regexp - * @param {string} msg - */ -export const error = (regexp: string, msg: string) => { - throw new SyntaxError('Invalid regular expression: /' + regexp + '/: ' + msg); -}; From 27498d6c60a8b1adcf136dd4f2d50648dc40b2e2 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Tue, 17 Nov 2020 10:17:03 +1100 Subject: [PATCH 11/45] adding code coverage for reconstruct --- lib/reconstruct.ts | 15 +- package-lock.json | 1442 +++++++++++++++++++++++++++++++++++++- test/reconstruct-test.js | 58 +- 3 files changed, 1503 insertions(+), 12 deletions(-) diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts index b366230..3ac0c4b 100644 --- a/lib/reconstruct.ts +++ b/lib/reconstruct.ts @@ -15,11 +15,11 @@ const reduceStack = (stack: Token[]): string => stack.map(partialConstruct).join const createAlternate = (token: Root | Group): string => { if ('options' in token) { - return token.options?.map(reduceStack).join('|') ?? '' + return token.options.map(reduceStack).join('|'); } else if ('stack' in token) { return reduceStack(token.stack); } else { - throw new Error(`options or stack must be within Root/Group: ${token}`); + throw new Error(`options or stack must be Root or Group token`); } }; @@ -31,15 +31,16 @@ export const partialConstruct = (token: Tokens): string => { return createAlternate(token); case types.CHAR: const c = String.fromCharCode(token.value); - return (/[[\]^.\/|?*+()]/.test(c) ? '\\' : '') + String.fromCharCode(token.value); + // console.log(c, c.valueOf(), String.raw`${c}`, Number(c.charCodeAt(0)).toString(16).toUpperCase()); + return (/[[\]^.\/|?*+()]/.test(c) ? '\\' : '') + c; case types.POSITION: if (token.value === '^' || token.value === '$') { - return `${token.value}`; + return token.value; } else { - return `\\${token.value}`; + return '\\' + token.value; }; case types.REFERENCE: - return `\\${token.value}`; + return '\\' + token.value; case types.SET: for (const [set, simplification] of simplifications) { if (JSON.stringify(set()) === JSON.stringify(token)) { @@ -51,7 +52,7 @@ export const partialConstruct = (token: Tokens): string => { return `${String.fromCharCode(token.from)}-${String.fromCharCode(token.to)}`; case types.GROUP: // Check token.remember - return `(${!token.remember ? '?' : ''}${token.lookBehind ? '<' : ''}${token.followedBy ? '=' : + return `(${token.remember ? '' : '?'}${token.lookBehind ? '<' : ''}${token.followedBy ? '=' : token.notFollowedBy ? '!' : (token.remember ? '' : ':') }${createAlternate(token)})` diff --git a/package-lock.json b/package-lock.json index e30723a..b0f744a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,1448 @@ { "name": "ret", "version": "0.3.1", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "ret", + "version": "0.3.1", + "license": "MIT", + "devDependencies": { + "@types/node": "^14.11.8", + "nyc": "^14.1.1", + "typescript": "^4.0.3", + "vows": "^0.8.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.0.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", + "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.6.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.4.4" + } + }, + "node_modules/@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "dependencies": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", + "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", + "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", + "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.3", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.6.3", + "@babel/types": "^7.6.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "node_modules/@babel/types": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", + "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@types/node": { + "version": "14.11.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.8.tgz", + "integrity": "sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw==", + "dev": true + }, + "node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "dependencies": { + "default-require-extensions": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/caching-transform": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", + "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "dev": true, + "dependencies": { + "hasha": "^3.0.0", + "make-dir": "^2.0.0", + "package-hash": "^3.0.0", + "write-file-atomic": "^2.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cp-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", + "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "make-dir": "^2.0.0", + "nested-error-stacks": "^2.0.0", + "pify": "^4.0.1", + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "dependencies": { + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "dev": true, + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/foreground-child": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "dev": true, + "dependencies": { + "cross-spawn": "^4", + "signal-exit": "^3.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hasha": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", + "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "dev": true, + "dependencies": { + "is-stream": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "dependencies": { + "append-transform": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/merge-source-map/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nested-error-stacks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", + "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/nyc": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", + "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", + "dev": true, + "dependencies": { + "archy": "^1.0.0", + "caching-transform": "^3.0.2", + "convert-source-map": "^1.6.0", + "cp-file": "^6.2.0", + "find-cache-dir": "^2.1.0", + "find-up": "^3.0.0", + "foreground-child": "^1.5.6", + "glob": "^7.1.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "merge-source-map": "^1.1.0", + "resolve-from": "^4.0.0", + "rimraf": "^2.6.3", + "signal-exit": "^3.0.2", + "spawn-wrap": "^1.4.2", + "test-exclude": "^5.2.3", + "uuid": "^3.3.2", + "yargs": "^13.2.2", + "yargs-parser": "^13.0.0" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", + "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^3.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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 + }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-wrap": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", + "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==", + "dev": true, + "dependencies": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "dependencies": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz", + "integrity": "sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vows": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/vows/-/vows-0.8.3.tgz", + "integrity": "sha512-PVIxa/ovXhrw5gA3mz6M+ZF3PHlqX4tutR2p/y9NWPAaFVKcWBE8b2ktfr0opQM/qFmcOVWKjSCJVjnYOvjXhw==", + "dev": true, + "dependencies": { + "diff": "^4.0.1", + "eyes": "~0.1.6", + "glob": "^7.1.2" + }, + "bin": { + "vows": "bin/vows" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "node_modules/yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + }, + "node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.5.5", diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index 51ed1d9..9e2af7c 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -1,8 +1,10 @@ const vows = require('vows'); const assert = require('assert'); const ret = require('../dist'); +const { tokenToString } = require('typescript'); const reconstruct = require('../dist/reconstruct').reconstruct const partialConstruct = require('../dist/reconstruct').partialConstruct +const tokens = require('../dist/types').types const inverseTestFactory = (regexp) => { return { @@ -65,10 +67,18 @@ vows.describe('Regexp Reconstruction') '^ and $ in': inverseTestFactory('^yes$'), '\\b and \\B': inverseTestFactory('\\bbeginning\\B'), 'Predefined sets': inverseTestFactory('\\w\\W\\d\\D\\s\\S.'), - 'Custom Sets': inverseTestFactory('[$!a-z123] thing [^0-9]'), + 'Custom Sets': multiInverseTestFactory([ + '[$!a-z123] thing [^0-9]', + '[^.]', + '[^test]' + ]), 'Whitespace characters': inverseTestFactory('[\t\r\n\u2028\u2029 ]'), 'Two sets in a row with dash in between': inverseTestFactory('[01]-[ab]'), - '| (Pipe)': inverseTestFactory('foo|bar|za'), + '| (Pipe)': multiInverseTestFactory([ + 'foo|bar|za', + '(foo|bar|za)', + '(foo|bar|za)|(^fe|fi|fo|fum)', + ]), 'Group': { 'with no special characters': inverseTestFactory('hey (there)'), 'that is not rememered': inverseTestFactory('(?:loner)'), @@ -86,8 +96,48 @@ vows.describe('Regexp Reconstruction') '+ (At least one)': inverseTestFactory('(no )+'), '* (Any amount)': inverseTestFactory('XF*D'), }, + // 'Lookarounds': multiInverseTestFactory([ + // '(?<=a)b', + // '(?<=text)', + // '(?\\w*<\\1>'), - } - } + }, + 'Reconstruct error test (bad root)': { + 'topic': () => { + try { + reconstruct({ type : ret.types.ROOT }); + } catch (e) { + return e; + } + }, + + 'throws error emessage': (err) => { + assert.isObject(err); + assert.include(err.message, 'options or stack must be Root or Group token'); + }, + }, + + 'Reconstruct error test (invalid token)': { + 'topic': () => { + try { + reconstruct({}); + } catch (e) { + return e; + } + }, + + 'throws error emessage': (err) => { + assert.isObject(err); + assert.include(err.message, 'Invalid token type'); + }, + }, + }, }) .export(module); From 401d343cedd11331055a7ebe04ef650d8c459613 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Wed, 18 Nov 2020 08:37:03 +1100 Subject: [PATCH 12/45] fixing semicolons in reconstruct file and updating [^.] test --- lib/reconstruct.ts | 9 ++++----- test/reconstruct-test.js | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts index 3ac0c4b..e28e061 100644 --- a/lib/reconstruct.ts +++ b/lib/reconstruct.ts @@ -31,22 +31,21 @@ export const partialConstruct = (token: Tokens): string => { return createAlternate(token); case types.CHAR: const c = String.fromCharCode(token.value); - // console.log(c, c.valueOf(), String.raw`${c}`, Number(c.charCodeAt(0)).toString(16).toUpperCase()); return (/[[\]^.\/|?*+()]/.test(c) ? '\\' : '') + c; case types.POSITION: if (token.value === '^' || token.value === '$') { return token.value; } else { return '\\' + token.value; - }; + } case types.REFERENCE: return '\\' + token.value; case types.SET: for (const [set, simplification] of simplifications) { if (JSON.stringify(set()) === JSON.stringify(token)) { return simplification; - }; - }; + } + } return `[${token.not ? '^' : ''}${reduceStack(token.set)}]`; case types.RANGE: return `${String.fromCharCode(token.from)}-${String.fromCharCode(token.to)}`; @@ -72,5 +71,5 @@ export const partialConstruct = (token: Tokens): string => { return `${partialConstruct(token.value)}${endWith}`; default: throw new Error(`Invalid token type ${token}`); - }; + } }; diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index 9e2af7c..5c4cd34 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -69,7 +69,7 @@ vows.describe('Regexp Reconstruction') 'Predefined sets': inverseTestFactory('\\w\\W\\d\\D\\s\\S.'), 'Custom Sets': multiInverseTestFactory([ '[$!a-z123] thing [^0-9]', - '[^.]', + '[^\\.]', '[^test]' ]), 'Whitespace characters': inverseTestFactory('[\t\r\n\u2028\u2029 ]'), From 755e315078423097a0c59914db651265a44ade6b Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Sat, 21 Nov 2020 12:03:10 +1100 Subject: [PATCH 13/45] Removing lookbehind (not currently tokenized) --- lib/reconstruct.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts index e28e061..217da61 100644 --- a/lib/reconstruct.ts +++ b/lib/reconstruct.ts @@ -51,7 +51,7 @@ export const partialConstruct = (token: Tokens): string => { return `${String.fromCharCode(token.from)}-${String.fromCharCode(token.to)}`; case types.GROUP: // Check token.remember - return `(${token.remember ? '' : '?'}${token.lookBehind ? '<' : ''}${token.followedBy ? '=' : + return `(${token.remember ? '' : '?'}${token.followedBy ? '=' : token.notFollowedBy ? '!' : (token.remember ? '' : ':') }${createAlternate(token)})` From bb88be28daec73c13caa6fa9ad2bb9e2fd885667 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 27 Nov 2020 21:21:28 +1100 Subject: [PATCH 14/45] Add documentation for `reconstruct` and `partialConstruct` --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 118d57b..3ef39f2 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,30 @@ let tokens = ret(/foo|bar/.source); } ``` +# Reconstructing Regular Expressions from Tokens + +```ts +import { reconstruct, partialConstruct, types } from 'ret' + +const tokens = ret(/foo|bar/.source) +const setToken = { + "type": ret.types.SET, + "set": [ + { "type": types.CHAR, "value": 97 }, + { "type": types.CHAR, "value": 98 }, + { "type": types.CHAR, "value": 99 } + ], + "not": true + } + +reconstruct(tokens) // 'foo|bar' +partialConstruct({ "type": types.CHAR, "value", 102 }) // 'f' +partialConstruct(setToken) // '^abc' +``` + +The `reconstruct` function accepts a `Root` token and returns the string associated to that token. The `partialConstruct` function accepts *any* token and returns the *component* of the regular expression that is associated with that token. + + # Token Types `ret.types` is a collection of the various token types exported by ret. From d9c9325cc24fb8518580f8cf2b280b0de544a5a5 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 27 Nov 2020 21:24:34 +1100 Subject: [PATCH 15/45] Fix typo --- test/reconstruct-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index 5c4cd34..f469fdf 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -81,7 +81,7 @@ vows.describe('Regexp Reconstruction') ]), 'Group': { 'with no special characters': inverseTestFactory('hey (there)'), - 'that is not rememered': inverseTestFactory('(?:loner)'), + 'that is not remembered': inverseTestFactory('(?:loner)'), 'matched previous clause if not followed by this': inverseTestFactory('what(?!ever)'), 'matched next clause': inverseTestFactory('hello(?= there)'), 'with subgroup': inverseTestFactory('a(b(c|(?:d))fg) @_@') From 3973e463f5c6fa03ec4fccc22b0a1ad1daa4d667 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 27 Nov 2020 21:28:30 +1100 Subject: [PATCH 16/45] Remove unecessary character escaping --- lib/reconstruct.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts index 217da61..c4bdd98 100644 --- a/lib/reconstruct.ts +++ b/lib/reconstruct.ts @@ -63,7 +63,7 @@ export const partialConstruct = (token: Tokens): string => { } else if (min === 1 && max === Infinity) { endWith = '+'; } else if (min === 0 && max === Infinity) { - endWith = '\*'; + endWith = '*'; } else { endWith = max === Infinity ? `{${min},}` : `{${min}${min === max ? `` : `,${max}`}}`; From 20f9b509d570079359c7d933c2c71b2d27e7f3ff Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 27 Nov 2020 23:49:17 +1100 Subject: [PATCH 17/45] Adding tests for set simplifications --- test/reconstruct-test.js | 82 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index f469fdf..52496f8 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -13,13 +13,21 @@ const inverseTestFactory = (regexp) => { [`Checking ${regexp} reconstructs`]: (t) => { const reconstructed = reconstruct(t) // May need to do some sort of sanitisation here assert.isString(reconstructed); - assert.deepStrictEqual(reconstructed, regexp.replace('[^0-9]', '\\D')) + assert.deepStrictEqual(reconstructed, regexp.replace(/\[\^0\-9\]/g, '\\D') + .replace(/\[0\-9\]/g, '\\d') + .replace(/\[\^\_a\-zA\-Z0\-9\]/g, '\\W') + .replace(/\[\_a\-zA\-Z0\-9\]/g, '\\w') + ) }, [`Checking ${regexp} reconstructs using partialConstruct`]: (t) => { const reconstructed = partialConstruct(t) // May need to do some sort of sanitisation here assert.isString(reconstructed); - assert.deepStrictEqual(reconstructed, regexp.replace('[^0-9]', '\\D')) + assert.deepStrictEqual(reconstructed, regexp.replace(/\[\^0\-9\]/g, '\\D') + .replace(/\[0\-9\]/g, '\\d') + .replace(/\[\^\_a\-zA\-Z0\-9\]/g, '\\W') + .replace(/\[\_a\-zA\-Z0\-9\]/g, '\\w') + ) } } } @@ -108,6 +116,73 @@ vows.describe('Regexp Reconstruction') // '[\\0-@\\{-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]' ]), 'Reference': inverseTestFactory('<(\\w+)>\\w*<\\1>'), + 'Simplifications': multiInverseTestFactory([ + '[_a-zA-Z0-9]', + '[0-9]', + '[^_a-zA-Z0-9]', + '[^0-9]', + ]), + 'Set simplification tests': { + 'INTS': { + 'topic': [{ type: types.RANGE, from: 48, to: 57 }], + 'Set simplification works': (set) => { + assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: false }), '\\d') + }, + 'Negative set simplification works': (set) => { + assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: true }), '\\D') + }, + }, + 'WORDS': { + 'topic': [ + { type: types.CHAR, value: 95 }, + { type: types.RANGE, from: 97, to: 122 }, + { type: types.RANGE, from: 65, to: 90 }, + { type: types.RANGE , from: 48, to: 57 } + ], + 'Set simplification works': (set) => { + assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: false }), '\\w') + }, + 'Negative set simplification works': (set) => { + assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: true }), '\\W') + }, + }, + 'WHITESPACE': { + 'topic': [ + { type: types.CHAR, value: 9 }, + { type: types.CHAR, value: 10 }, + { type: types.CHAR, value: 11 }, + { type: types.CHAR, value: 12 }, + { type: types.CHAR, value: 13 }, + { type: types.CHAR, value: 32 }, + { type: types.CHAR, value: 160 }, + { type: types.CHAR, value: 5760 }, + { type: types.RANGE, from: 8192, to: 8202 }, + { type: types.CHAR, value: 8232 }, + { type: types.CHAR, value: 8233 }, + { type: types.CHAR, value: 8239 }, + { type: types.CHAR, value: 8287 }, + { type: types.CHAR, value: 12288 }, + { type: types.CHAR, value: 65279 } + ], + 'Set simplification works': (set) => { + assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: false }), '\\s') + }, + 'Negative set simplification works': (set) => { + assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: true }), '\\S') + }, + }, + 'NOTANYCHAR': { + 'topic': [ + { type: types.CHAR, value: 10 }, + { type: types.CHAR, value: 13 }, + { type: types.CHAR, value: 8232 }, + { type: types.CHAR, value: 8233 }, + ], + 'Set simplification works': (set) => { + assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: true }), '.') + }, + }, + }, }, 'Reconstruct error test (bad root)': { 'topic': () => { @@ -117,13 +192,11 @@ vows.describe('Regexp Reconstruction') return e; } }, - 'throws error emessage': (err) => { assert.isObject(err); assert.include(err.message, 'options or stack must be Root or Group token'); }, }, - 'Reconstruct error test (invalid token)': { 'topic': () => { try { @@ -132,7 +205,6 @@ vows.describe('Regexp Reconstruction') return e; } }, - 'throws error emessage': (err) => { assert.isObject(err); assert.include(err.message, 'Invalid token type'); From 78af34236fce8810ff341b621cd556ce7fab391f Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 27 Nov 2020 23:56:37 +1100 Subject: [PATCH 18/45] Fix typo and remove sanitisation comment --- test/reconstruct-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index 52496f8..431a21e 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -4,7 +4,7 @@ const ret = require('../dist'); const { tokenToString } = require('typescript'); const reconstruct = require('../dist/reconstruct').reconstruct const partialConstruct = require('../dist/reconstruct').partialConstruct -const tokens = require('../dist/types').types +const types = require('../dist/types').types const inverseTestFactory = (regexp) => { return { @@ -21,7 +21,7 @@ const inverseTestFactory = (regexp) => { }, [`Checking ${regexp} reconstructs using partialConstruct`]: (t) => { - const reconstructed = partialConstruct(t) // May need to do some sort of sanitisation here + const reconstructed = partialConstruct(t) assert.isString(reconstructed); assert.deepStrictEqual(reconstructed, regexp.replace(/\[\^0\-9\]/g, '\\D') .replace(/\[0\-9\]/g, '\\d') From b8d6e93fb56cf471061604fff0c89afad1e97591 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Mon, 30 Nov 2020 13:39:27 +1100 Subject: [PATCH 19/45] Update README.md Co-authored-by: fent --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ef39f2..7191380 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ import { reconstruct, partialConstruct, types } from 'ret' const tokens = ret(/foo|bar/.source) const setToken = { - "type": ret.types.SET, + "type": types.SET, "set": [ { "type": types.CHAR, "value": 97 }, { "type": types.CHAR, "value": 98 }, From f5e037a6f5c081f4c04e42fcfbd36d05a1d8be25 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Mon, 30 Nov 2020 13:44:36 +1100 Subject: [PATCH 20/45] Change partialConstruct to reconstruct --- lib/reconstruct.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts index c4bdd98..a84d16f 100644 --- a/lib/reconstruct.ts +++ b/lib/reconstruct.ts @@ -23,9 +23,7 @@ const createAlternate = (token: Root | Group): string => { } }; -export const reconstruct = (regexpToken: Root): string => partialConstruct(regexpToken); - -export const partialConstruct = (token: Tokens): string => { +export const reconstruct = (token: Tokens): string => { switch (token.type) { case types.ROOT: return createAlternate(token); @@ -68,7 +66,7 @@ export const partialConstruct = (token: Tokens): string => { endWith = max === Infinity ? `{${min},}` : `{${min}${min === max ? `` : `,${max}`}}`; } - return `${partialConstruct(token.value)}${endWith}`; + return `${reconstruct(token.value)}${endWith}`; default: throw new Error(`Invalid token type ${token}`); } From eae6b6e94db456fab87f6df967ccee53b9be103f Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Mon, 30 Nov 2020 13:46:07 +1100 Subject: [PATCH 21/45] Remove partialConstruct from readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7191380..f88f319 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ let tokens = ret(/foo|bar/.source); # Reconstructing Regular Expressions from Tokens ```ts -import { reconstruct, partialConstruct, types } from 'ret' +import { reconstruct, types } from 'ret' const tokens = ret(/foo|bar/.source) const setToken = { @@ -45,9 +45,9 @@ const setToken = { "not": true } -reconstruct(tokens) // 'foo|bar' -partialConstruct({ "type": types.CHAR, "value", 102 }) // 'f' -partialConstruct(setToken) // '^abc' +reconstruct(tokens) // 'foo|bar' +reconstruct({ "type": types.CHAR, "value", 102 }) // 'f' +reconstruct(setToken) // '^abc' ``` The `reconstruct` function accepts a `Root` token and returns the string associated to that token. The `partialConstruct` function accepts *any* token and returns the *component* of the regular expression that is associated with that token. From 08125fbbecd3e45a36c1c31ad3d2d216e5887616 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Mon, 30 Nov 2020 13:47:37 +1100 Subject: [PATCH 22/45] Remove partialConstruct from tests --- test/reconstruct-test.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index 431a21e..b860426 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -3,7 +3,6 @@ const assert = require('assert'); const ret = require('../dist'); const { tokenToString } = require('typescript'); const reconstruct = require('../dist/reconstruct').reconstruct -const partialConstruct = require('../dist/reconstruct').partialConstruct const types = require('../dist/types').types const inverseTestFactory = (regexp) => { @@ -18,16 +17,6 @@ const inverseTestFactory = (regexp) => { .replace(/\[\^\_a\-zA\-Z0\-9\]/g, '\\W') .replace(/\[\_a\-zA\-Z0\-9\]/g, '\\w') ) - }, - - [`Checking ${regexp} reconstructs using partialConstruct`]: (t) => { - const reconstructed = partialConstruct(t) - assert.isString(reconstructed); - assert.deepStrictEqual(reconstructed, regexp.replace(/\[\^0\-9\]/g, '\\D') - .replace(/\[0\-9\]/g, '\\d') - .replace(/\[\^\_a\-zA\-Z0\-9\]/g, '\\W') - .replace(/\[\_a\-zA\-Z0\-9\]/g, '\\w') - ) } } } From d36e8675914ff3c60c144bd790972e4788313ee7 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Mon, 30 Nov 2020 13:49:04 +1100 Subject: [PATCH 23/45] Replace other instances of partialConstruct with reconstruct --- test/reconstruct-test.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index b860426..ada6693 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -115,10 +115,10 @@ vows.describe('Regexp Reconstruction') 'INTS': { 'topic': [{ type: types.RANGE, from: 48, to: 57 }], 'Set simplification works': (set) => { - assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: false }), '\\d') + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '\\d') }, 'Negative set simplification works': (set) => { - assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: true }), '\\D') + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '\\D') }, }, 'WORDS': { @@ -129,10 +129,10 @@ vows.describe('Regexp Reconstruction') { type: types.RANGE , from: 48, to: 57 } ], 'Set simplification works': (set) => { - assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: false }), '\\w') + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '\\w') }, 'Negative set simplification works': (set) => { - assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: true }), '\\W') + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '\\W') }, }, 'WHITESPACE': { @@ -154,10 +154,10 @@ vows.describe('Regexp Reconstruction') { type: types.CHAR, value: 65279 } ], 'Set simplification works': (set) => { - assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: false }), '\\s') + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '\\s') }, 'Negative set simplification works': (set) => { - assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: true }), '\\S') + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '\\S') }, }, 'NOTANYCHAR': { @@ -168,7 +168,7 @@ vows.describe('Regexp Reconstruction') { type: types.CHAR, value: 8233 }, ], 'Set simplification works': (set) => { - assert.deepStrictEqual(partialConstruct({ type: types.SET, set, not: true }), '.') + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '.') }, }, }, From 219ca172e4a5f70255da64c503641b9e7158519a Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Mon, 30 Nov 2020 13:52:29 +1100 Subject: [PATCH 24/45] Converting partialConstruct to reconstruct in reduceStack --- lib/reconstruct.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts index a84d16f..ec399b0 100644 --- a/lib/reconstruct.ts +++ b/lib/reconstruct.ts @@ -11,7 +11,7 @@ const simplifications: [sets.SetFunc, string][] = [ [sets.anyChar, '.'] ]; -const reduceStack = (stack: Token[]): string => stack.map(partialConstruct).join(''); +const reduceStack = (stack: Token[]): string => stack.map(reconstruct).join(''); const createAlternate = (token: Root | Group): string => { if ('options' in token) { From 324fe8600c120d9a5f260fa89f162d4c51bb0bca Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Mon, 30 Nov 2020 14:10:41 +1100 Subject: [PATCH 25/45] Adding `module.exports.reconstruct` Needed to make importing using the syntax shown in the README valid --- lib/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/index.ts b/lib/index.ts index 62a404f..27a80b3 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -2,6 +2,7 @@ import { types } from './types'; export * from './tokenizer'; export * from './reconstruct'; import { tokenizer } from './tokenizer'; +import { reconstruct } from './reconstruct'; export * from './types'; export default tokenizer; @@ -9,3 +10,4 @@ export { types }; module.exports = tokenizer; module.exports.types = types; +module.exports.reconstruct = reconstruct; From 065405908a93902382903490547523df184cb2bc Mon Sep 17 00:00:00 2001 From: jeswr Date: Tue, 1 Dec 2020 22:13:21 +1100 Subject: [PATCH 26/45] revert package-lock.json file --- package-lock.json | 1442 +-------------------------------------------- 1 file changed, 1 insertion(+), 1441 deletions(-) diff --git a/package-lock.json b/package-lock.json index b0f744a..e30723a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,1448 +1,8 @@ { "name": "ret", "version": "0.3.1", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "ret", - "version": "0.3.1", - "license": "MIT", - "devDependencies": { - "@types/node": "^14.11.8", - "nyc": "^14.1.1", - "typescript": "^4.0.3", - "vows": "^0.8.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.0.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", - "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.6.3", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.4.4" - } - }, - "node_modules/@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "dev": true, - "dependencies": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", - "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", - "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", - "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.3", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.6.3", - "@babel/types": "^7.6.3", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - } - }, - "node_modules/@babel/types": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", - "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "node_modules/@types/node": { - "version": "14.11.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.8.tgz", - "integrity": "sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw==", - "dev": true - }, - "node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/append-transform": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", - "dev": true, - "dependencies": { - "default-require-extensions": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/caching-transform": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", - "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", - "dev": true, - "dependencies": { - "hasha": "^3.0.0", - "make-dir": "^2.0.0", - "package-hash": "^3.0.0", - "write-file-atomic": "^2.4.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/cp-file": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", - "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "make-dir": "^2.0.0", - "nested-error-stacks": "^2.0.0", - "pify": "^4.0.1", - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", - "dev": true, - "dependencies": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-require-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", - "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", - "dev": true, - "dependencies": { - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", - "dev": true, - "engines": { - "node": "> 0.1.90" - } - }, - "node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/foreground-child": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", - "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", - "dev": true, - "dependencies": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": "*" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", - "dev": true - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/hasha": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", - "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", - "dev": true, - "dependencies": { - "is-stream": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", - "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", - "dev": true - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-hook": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", - "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", - "dev": true, - "dependencies": { - "append-transform": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "dev": true, - "dependencies": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", - "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "dependencies": { - "source-map": "^0.6.1" - } - }, - "node_modules/merge-source-map/node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nested-error-stacks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", - "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/nyc": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", - "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", - "dev": true, - "dependencies": { - "archy": "^1.0.0", - "caching-transform": "^3.0.2", - "convert-source-map": "^1.6.0", - "cp-file": "^6.2.0", - "find-cache-dir": "^2.1.0", - "find-up": "^3.0.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.3", - "istanbul-lib-coverage": "^2.0.5", - "istanbul-lib-hook": "^2.0.7", - "istanbul-lib-instrument": "^3.3.0", - "istanbul-lib-report": "^2.0.8", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^2.2.4", - "js-yaml": "^3.13.1", - "make-dir": "^2.1.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.3", - "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^5.2.3", - "uuid": "^3.3.2", - "yargs": "^13.2.2", - "yargs-parser": "^13.0.0" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", - "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^3.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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 - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-type/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "dependencies": { - "es6-error": "^4.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", - "dev": true, - "dependencies": { - "path-parse": "^1.0.6" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spawn-wrap": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", - "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==", - "dev": true, - "dependencies": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "dev": true, - "dependencies": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/typescript": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz", - "integrity": "sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vows": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/vows/-/vows-0.8.3.tgz", - "integrity": "sha512-PVIxa/ovXhrw5gA3mz6M+ZF3PHlqX4tutR2p/y9NWPAaFVKcWBE8b2ktfr0opQM/qFmcOVWKjSCJVjnYOvjXhw==", - "dev": true, - "dependencies": { - "diff": "^4.0.1", - "eyes": "~0.1.6", - "glob": "^7.1.2" - }, - "bin": { - "vows": "bin/vows" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "node_modules/y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "node_modules/yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - } - }, - "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - }, "dependencies": { "@babel/code-frame": { "version": "7.5.5", From 16427ed12576f43e6cf14851324c75f476ad5956 Mon Sep 17 00:00:00 2001 From: jeswr Date: Tue, 1 Dec 2020 22:17:23 +1100 Subject: [PATCH 27/45] Update readme file to remove reference to partialConstruct in explanation --- README.md | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f88f319..1c33852 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,6 @@ Tokenizes strings that represent a regular expressions. -[![Dependency Status](https://david-dm.org/fent/ret.js.svg)](https://david-dm.org/fent/ret.js) -[![codecov](https://codecov.io/gh/fent/ret.js/branch/master/graph/badge.svg)](https://codecov.io/gh/fent/ret.js) - # Usage ```js @@ -31,6 +28,8 @@ let tokens = ret(/foo|bar/.source); # Reconstructing Regular Expressions from Tokens +The `reconstruct` function accepts a *any* token and returns, as a string, the *component* of the regular expression that is associated with that token. + ```ts import { reconstruct, types } from 'ret' @@ -46,13 +45,10 @@ const setToken = { } reconstruct(tokens) // 'foo|bar' -reconstruct({ "type": types.CHAR, "value", 102 }) // 'f' +reconstruct({ "type": types.CHAR, "value": 102 }) // 'f' reconstruct(setToken) // '^abc' ``` -The `reconstruct` function accepts a `Root` token and returns the string associated to that token. The `partialConstruct` function accepts *any* token and returns the *component* of the regular expression that is associated with that token. - - # Token Types `ret.types` is a collection of the various token types exported by ret. @@ -181,20 +177,21 @@ Represents a single character token. `value` is the character code. This might s ret.js will throw errors if given a string with an invalid regular expression. All possible errors are -* Invalid group. When a group with an immediate `?` character is followed by an invalid character. It can only be followed by `!`, `=`, or `:`. Example: `/(?_abc)/` -* Nothing to repeat. Thrown when a repetitional token is used as the first token in the current clause, as in right in the beginning of the regexp or group, or right after a pipe. Example: `/foo|?bar/`, `/{1,3}foo|bar/`, `/foo(+bar)/` -* Unmatched ). A group was not opened, but was closed. Example: `/hello)2u/` -* Unterminated group. A group was not closed. Example: `/(1(23)4/` -* Unterminated character class. A custom character set was not closed. Example: `/[abc/` +* Invalid group. When a group with an immediate`?` character is followed by an invalid character. It can only be followed by`!`,`=`, or`:`. Example:`/(?_abc)/` +* Nothing to repeat. Thrown when a repetitional token is used as the first token in the current clause, as in right in the beginning of the regexp or group, or right after a pipe. Example:`/foo|?bar/`,`/{1,3}foo|bar/`,`/foo(+bar)/` +* Unmatched ). A group was not opened, but was closed. Example:`/hello)2u/` +* Unterminated group. A group was not closed. Example:`/(1(23)4/` +* Unterminated character class. A custom character set was not closed. Example:`/[abc/` # Regular Expression Syntax Regular expressions follow the [JavaScript syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp). The following latest JavaScript additions are not supported yet: -* `\p` and `\P`: [Unicode property escapes](https://github.com/tc39/proposal-regexp-unicode-property-escapes) -* `(?)` and `\k`: [Named groups](https://github.com/tc39/proposal-regexp-named-groups) -* `(?<=)` and `(?)` and`\k`:[Named groups](https://github.com/tc39/proposal-regexp-named-groups) +* `(?<=)` and`(? Date: Tue, 1 Dec 2020 22:39:48 +1100 Subject: [PATCH 28/45] reverting package-lock.json (using version in ret/master) --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index e30723a..68ebc7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1199,4 +1199,4 @@ } } } -} +} \ No newline at end of file From b9d9ffb52e52b5d6f8ef740a3db4e8199a9d1781 Mon Sep 17 00:00:00 2001 From: jeswr Date: Mon, 4 Jan 2021 21:11:13 +1100 Subject: [PATCH 29/45] fix: make package-lock match main branch --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index ce999ee..9048421 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2212,4 +2212,4 @@ } } } -} \ No newline at end of file +} From b774a80ab1ab0fcbd4a07aa1514f96bc005e4431 Mon Sep 17 00:00:00 2001 From: jeswr Date: Mon, 4 Jan 2021 21:12:17 +1100 Subject: [PATCH 30/45] fix: revert unintended changes to readme --- README.md | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3298899..908de5a 100644 --- a/README.md +++ b/README.md @@ -180,21 +180,20 @@ Represents a single character token. `value` is the character code. This might s ret.js will throw errors if given a string with an invalid regular expression. All possible errors are -* Invalid group. When a group with an immediate`?` character is followed by an invalid character. It can only be followed by`!`,`=`, or`:`. Example:`/(?_abc)/` -* Nothing to repeat. Thrown when a repetitional token is used as the first token in the current clause, as in right in the beginning of the regexp or group, or right after a pipe. Example:`/foo|?bar/`,`/{1,3}foo|bar/`,`/foo(+bar)/` -* Unmatched ). A group was not opened, but was closed. Example:`/hello)2u/` -* Unterminated group. A group was not closed. Example:`/(1(23)4/` -* Unterminated character class. A custom character set was not closed. Example:`/[abc/` +* Invalid group. When a group with an immediate `?` character is followed by an invalid character. It can only be followed by `!`, `=`, or `:`. Example: `/(?_abc)/` +* Nothing to repeat. Thrown when a repetitional token is used as the first token in the current clause, as in right in the beginning of the regexp or group, or right after a pipe. Example: `/foo|?bar/`, `/{1,3}foo|bar/`, `/foo(+bar)/` +* Unmatched ). A group was not opened, but was closed. Example: `/hello)2u/` +* Unterminated group. A group was not closed. Example: `/(1(23)4/` +* Unterminated character class. A custom character set was not closed. Example: `/[abc/` # Regular Expression Syntax Regular expressions follow the [JavaScript syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp). The following latest JavaScript additions are not supported yet: - -* `\p` and`\P`:[Unicode property escapes](https://github.com/tc39/proposal-regexp-unicode-property-escapes) -* `(?)` and`\k`:[Named groups](https://github.com/tc39/proposal-regexp-named-groups) -* `(?<=)` and`(?)` and `\k`: [Named groups](https://github.com/tc39/proposal-regexp-named-groups) +* `(?<=)` and `(? Date: Mon, 4 Jan 2021 21:21:53 +1100 Subject: [PATCH 31/45] run lint:fix --- lib/reconstruct.ts | 24 ++++---- test/reconstruct-test.js | 126 +++++++++++++++++++-------------------- 2 files changed, 76 insertions(+), 74 deletions(-) diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts index ec399b0..2b49edc 100644 --- a/lib/reconstruct.ts +++ b/lib/reconstruct.ts @@ -8,7 +8,7 @@ const simplifications: [sets.SetFunc, string][] = [ [sets.notInts, '\\D'], [sets.whitespace, '\\s'], [sets.notWhitespace, '\\S'], - [sets.anyChar, '.'] + [sets.anyChar, '.'], ]; const reduceStack = (stack: Token[]): string => stack.map(reconstruct).join(''); @@ -27,17 +27,18 @@ export const reconstruct = (token: Tokens): string => { switch (token.type) { case types.ROOT: return createAlternate(token); - case types.CHAR: + case types.CHAR: { const c = String.fromCharCode(token.value); - return (/[[\]^.\/|?*+()]/.test(c) ? '\\' : '') + c; + return (/[[\]^./|?*+()]/.test(c) ? '\\' : '') + c; + } case types.POSITION: if (token.value === '^' || token.value === '$') { return token.value; } else { - return '\\' + token.value; + return `\\${token.value}`; } case types.REFERENCE: - return '\\' + token.value; + return `\\${token.value}`; case types.SET: for (const [set, simplification] of simplifications) { if (JSON.stringify(set()) === JSON.stringify(token)) { @@ -50,10 +51,10 @@ export const reconstruct = (token: Tokens): string => { case types.GROUP: // Check token.remember return `(${token.remember ? '' : '?'}${token.followedBy ? '=' : - token.notFollowedBy ? '!' : - (token.remember ? '' : ':') - }${createAlternate(token)})` - case types.REPETITION: + token.notFollowedBy ? '!' : + token.remember ? '' : ':' + }${createAlternate(token)})`; + case types.REPETITION: { const { min, max } = token; let endWith; if (min === 0 && max === 1) { @@ -63,10 +64,11 @@ export const reconstruct = (token: Tokens): string => { } else if (min === 0 && max === Infinity) { endWith = '*'; } else { - endWith = max === Infinity ? `{${min},}` - : `{${min}${min === max ? `` : `,${max}`}}`; + endWith = max === Infinity ? `{${min},}` : + `{${min}${min === max ? `` : `,${max}`}}`; } return `${reconstruct(token.value)}${endWith}`; + } default: throw new Error(`Invalid token type ${token}`); } diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index ada6693..a370080 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -2,36 +2,35 @@ const vows = require('vows'); const assert = require('assert'); const ret = require('../dist'); const { tokenToString } = require('typescript'); -const reconstruct = require('../dist/reconstruct').reconstruct -const types = require('../dist/types').types +const reconstruct = require('../dist/reconstruct').reconstruct; +const types = require('../dist/types').types; -const inverseTestFactory = (regexp) => { - return { - topic: ret(regexp), +const inverseTestFactory = regexp => ({ + topic: ret(regexp), - [`Checking ${regexp} reconstructs`]: (t) => { - const reconstructed = reconstruct(t) // May need to do some sort of sanitisation here - assert.isString(reconstructed); - assert.deepStrictEqual(reconstructed, regexp.replace(/\[\^0\-9\]/g, '\\D') - .replace(/\[0\-9\]/g, '\\d') - .replace(/\[\^\_a\-zA\-Z0\-9\]/g, '\\W') - .replace(/\[\_a\-zA\-Z0\-9\]/g, '\\w') - ) - } - } -} + [`Checking ${regexp} reconstructs`]: t => { + // May need to do some sort of sanitisation here + const reconstructed = reconstruct(t); + assert.isString(reconstructed); + assert.deepStrictEqual(reconstructed, regexp.replace(/\[\^0-9\]/g, '\\D') + .replace(/\[0-9\]/g, '\\d') + .replace(/\[\^_a-zA-Z0-9\]/g, '\\W') + .replace(/\[_a-zA-Z0-9\]/g, '\\w'), + ); + }, +}); -/*! fromentries. MIT License. Feross Aboukhadijeh */ +/* ! fromentries. MIT License. Feross Aboukhadijeh */ function fromEntries(iterable) { return [...iterable].reduce((obj, [key, val]) => { - obj[key] = val - return obj - }, {}) + obj[key] = val; + return obj; + }, {}); } const multiInverseTestFactory = regexps => fromEntries( - regexps.map(regexp => [regexp, inverseTestFactory(regexp)]) -) + regexps.map(regexp => [regexp, inverseTestFactory(regexp)]), +); vows.describe('Regexp Reconstruction') .addBatch({ @@ -45,7 +44,7 @@ vows.describe('Regexp Reconstruction') '\\/\\/', '\\W', '\\D', - '\\w\\W\\d\\D\\s\\S.' + '\\w\\W\\d\\D\\s\\S.', ]), 'testing start and finish flags (using inverse of Ret)': multiInverseTestFactory([ '$', @@ -57,7 +56,7 @@ vows.describe('Regexp Reconstruction') '$\\/\\/^', '$\\W^', '$\\D^', - '$\\w\\W\\d\\D\\s\\S.^' + '$\\w\\W\\d\\D\\s\\S.^', ]), 'all main regexp expressions': { 'No special characters': inverseTestFactory('walnuts'), @@ -67,7 +66,7 @@ vows.describe('Regexp Reconstruction') 'Custom Sets': multiInverseTestFactory([ '[$!a-z123] thing [^0-9]', '[^\\.]', - '[^test]' + '[^test]', ]), 'Whitespace characters': inverseTestFactory('[\t\r\n\u2028\u2029 ]'), 'Two sets in a row with dash in between': inverseTestFactory('[01]-[ab]'), @@ -76,12 +75,12 @@ vows.describe('Regexp Reconstruction') '(foo|bar|za)', '(foo|bar|za)|(^fe|fi|fo|fum)', ]), - 'Group': { + Group: { 'with no special characters': inverseTestFactory('hey (there)'), 'that is not remembered': inverseTestFactory('(?:loner)'), 'matched previous clause if not followed by this': inverseTestFactory('what(?!ever)'), 'matched next clause': inverseTestFactory('hello(?= there)'), - 'with subgroup': inverseTestFactory('a(b(c|(?:d))fg) @_@') + 'with subgroup': inverseTestFactory('a(b(c|(?:d))fg) @_@'), }, 'Custom repetition with': { 'exact amount': inverseTestFactory('(?:pika){2}'), @@ -102,41 +101,42 @@ vows.describe('Regexp Reconstruction') // ]), 'Unicode Characters': multiInverseTestFactory([ // '[A\\xA9\\u2603]|\\uD834\\uDF06', - // '[\\0-@\\{-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]' + // '[\\0-@\\{-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]| + // [\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]' ]), - 'Reference': inverseTestFactory('<(\\w+)>\\w*<\\1>'), - 'Simplifications': multiInverseTestFactory([ + Reference: inverseTestFactory('<(\\w+)>\\w*<\\1>'), + Simplifications: multiInverseTestFactory([ '[_a-zA-Z0-9]', '[0-9]', '[^_a-zA-Z0-9]', '[^0-9]', - ]), + ]), 'Set simplification tests': { - 'INTS': { - 'topic': [{ type: types.RANGE, from: 48, to: 57 }], - 'Set simplification works': (set) => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '\\d') + INTS: { + topic: [{ type: types.RANGE, from: 48, to: 57 }], + 'Set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '\\d'); }, - 'Negative set simplification works': (set) => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '\\D') + 'Negative set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '\\D'); }, }, - 'WORDS': { - 'topic': [ + WORDS: { + topic: [ { type: types.CHAR, value: 95 }, { type: types.RANGE, from: 97, to: 122 }, { type: types.RANGE, from: 65, to: 90 }, - { type: types.RANGE , from: 48, to: 57 } + { type: types.RANGE, from: 48, to: 57 }, ], - 'Set simplification works': (set) => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '\\w') + 'Set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '\\w'); }, - 'Negative set simplification works': (set) => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '\\W') + 'Negative set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '\\W'); }, }, - 'WHITESPACE': { - 'topic': [ + WHITESPACE: { + topic: [ { type: types.CHAR, value: 9 }, { type: types.CHAR, value: 10 }, { type: types.CHAR, value: 11 }, @@ -151,50 +151,50 @@ vows.describe('Regexp Reconstruction') { type: types.CHAR, value: 8239 }, { type: types.CHAR, value: 8287 }, { type: types.CHAR, value: 12288 }, - { type: types.CHAR, value: 65279 } - ], - 'Set simplification works': (set) => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '\\s') + { type: types.CHAR, value: 65279 }, + ], + 'Set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '\\s'); }, - 'Negative set simplification works': (set) => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '\\S') + 'Negative set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '\\S'); }, }, - 'NOTANYCHAR': { - 'topic': [ + NOTANYCHAR: { + topic: [ { type: types.CHAR, value: 10 }, { type: types.CHAR, value: 13 }, { type: types.CHAR, value: 8232 }, { type: types.CHAR, value: 8233 }, - ], - 'Set simplification works': (set) => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '.') + ], + 'Set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '.'); }, }, }, }, 'Reconstruct error test (bad root)': { - 'topic': () => { + topic: () => { try { - reconstruct({ type : ret.types.ROOT }); + return reconstruct({ type: ret.types.ROOT }); } catch (e) { return e; } }, - 'throws error emessage': (err) => { + 'throws error emessage': err => { assert.isObject(err); assert.include(err.message, 'options or stack must be Root or Group token'); }, }, 'Reconstruct error test (invalid token)': { - 'topic': () => { + topic: () => { try { - reconstruct({}); + return reconstruct({}); } catch (e) { return e; } }, - 'throws error emessage': (err) => { + 'throws error emessage': err => { assert.isObject(err); assert.include(err.message, 'Invalid token type'); }, From a5fb5cbaec572a49bc3906d65079ce919d0a924f Mon Sep 17 00:00:00 2001 From: jeswr Date: Tue, 5 Jan 2021 13:45:31 +1100 Subject: [PATCH 32/45] Update test file --- test/reconstruct-test.js | 244 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index a370080..f245458 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -111,6 +111,250 @@ vows.describe('Regexp Reconstruction') '[^_a-zA-Z0-9]', '[^0-9]', ]), + // Testing for https://github.com/fent/ret.js/pull/25#discussion_r533492862 + 'Range (in set) test cases': { + 'Testing complex range cases': { + 'token.from is a hyphen and the range is preceded by a single character [a\\--\\-]': { + topic: { + type: types.SET, not: false, set: [ + { type: types.CHAR, value: 97 }, + { type: types.RANGE, from: 45, to: 45 }, + ], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[a\\--\\-]'); + }, + }, + 'token.from is a hyphen and the range is preceded by a single character [a\\--\\/]': { + topic: { + type: types.SET, not: false, set: [ + { type: types.CHAR, value: 97 }, + { type: types.RANGE, from: 45, to: 47 }, + ], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[a\\--\\/]'); + }, + }, + 'token.from is a hyphen and the range is preceded by a single character [c\\--a]': { + topic: { + type: types.SET, not: false, set: [ + { type: types.CHAR, value: 99 }, + { type: types.RANGE, from: 45, to: 97 }, + ], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[c\\--a]'); + }, + }, + 'token.from is a hyphen and the range is preceded by a single character [\\-\\--\\-]': { + topic: { + type: types.SET, not: false, set: [ + { type: types.CHAR, value: 45 }, + { type: types.RANGE, from: 45, to: 45 }, + ], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[\\-\\--\\-]'); + }, + }, + 'token.from is a hyphen and the range is preceded by a predefined set [\\w\\--\\-]': { + topic: { + type: types.SET, not: false, set: [ + { + type: types.SET, not: false, set: [ + { type: types.CHAR, value: 95 }, + { type: types.RANGE, from: 97, to: 122 }, + { type: types.RANGE, from: 65, to: 90 }, + { type: types.RANGE, from: 48, to: 57 }, + ], + }, + { type: types.RANGE, from: 45, to: 45 }, + ], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[\\w\\--\\-]'); + }, + }, + 'token.from is a caret and the range is the first item of the set [9-^]': { + topic: { + type: types.SET, not: false, set: [ + { type: types.RANGE, from: 57, to: 94 }, + ], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[9-^]'); + }, + }, + 'token.to is a closing square bracket [2-\\]]': { + topic: { + type: types.SET, not: false, set: [ + { type: types.RANGE, from: 50, to: 93 }, + ], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[2-\\]]'); + }, + }, + 'token.to is a closing square bracket [\\-^]]': { + topic: { + type: types.SET, not: false, set: [ + { type: types.RANGE, from: 93, to: 94 }, + ], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[\\-^]]'); + }, + }, + 'token.to is a closing square bracket [[-\\]]': { + topic: { + type: types.SET, not: false, set: [ + { type: types.RANGE, from: 92, to: 93 }, + ], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[[-\\]]'); + }, + }, + 'token.to is a closing square bracket [[-]]': { + topic: { + type: types.ROOT, stack: [{ + type: types.SET, not: false, set: [ + { type: types.CHAR, value: 91 }, + { type: types.CHAR, value: 45 }, + ], + }, { + type: types.CHAR, value: 93, + }], + }, + 'Tokenizes correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[[-]]'); + }, + }, + 'token.from is a caret [\\^-_]': { + topic: { + type: types.ROOT, stack: [{ + type: types.SET, not: false, set: [ + { type: types.RANGE, from: 94, to: 95 }, + ], + }], + }, + 'Tokenizes correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[\\^-_]'); + }, + }, + 'token.from is a caret [\\^-^]': { + topic: { + type: types.ROOT, stack: [{ + type: types.SET, not: false, set: [ + { type: types.RANGE, from: 94, to: 94 }, + ], + }], + }, + 'Tokenizes correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[\\^-^]'); + }, + }, + 'token.from is a caret and set is negated [^^-_]': { + topic: { + type: types.ROOT, stack: [{ + type: types.SET, not: true, set: [ + { type: types.RANGE, from: 94, to: 95 }, + ], + }], + }, + 'Tokenizes correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[^^-_]'); + }, + }, + 'token.from is a caret [^^-^] and set is negated': { + topic: { + type: types.ROOT, stack: [{ + type: types.SET, not: true, set: [ + { type: types.RANGE, from: 94, to: 94 }, + ], + }], + }, + 'Tokenizes correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[^^-^]'); + }, + }, + 'Contains emtpy set': { + topic: { + type: types.SET, not: false, set: [], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[]'); + }, + }, + 'Contains emtpy negated set': { + topic: { + type: types.SET, not: true, set: [], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[^]'); + }, + }, + 'Contains emtpy nested set': { + topic: { + type: types.SET, not: false, set: [{ + type: types.SET, not: false, set: [], + }], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[]'); + }, + }, + 'Contains emtpy nested set negated': { + topic: { + type: types.SET, not: true, set: [{ + type: types.SET, not: false, set: [], + }], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[^]'); + }, + }, + 'Contains emtpy nested set and single char [a]': { + topic: { + type: types.SET, not: false, set: [ + { type: types.SET, not: false, set: [] }, + { type: types.CHAR, value: 97 }, + ], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[a]'); + }, + }, + 'Contains emtpy nested set (on right side) and single char [a]': { + topic: { + type: types.SET, not: false, set: [ + { type: types.CHAR, value: 97 }, + { type: types.SET, not: false, set: [] }, + ], + }, + 'Reconstructs correctly': set => { + assert.deepStrictEqual(reconstruct(set), '[a]'); + }, + }, + }, + 'Testing inverse relations': multiInverseTestFactory([ + '[a\\--\\-]', + '[a\\--\\/]', + '[c\\--a]', + '[\\-\\--\\-]', + '[\\w\\--\\-]', + '[9-^]', + '[09\\--\\-]', + '[2-\\]]', + '[\\^-\\]]', + '[\\^^-\\]]', + '[^^-\\]]', + '[\\[-\\]]', + '[[-\\]]', + '[[-]]' + ]), + }, 'Set simplification tests': { INTS: { topic: [{ type: types.RANGE, from: 48, to: 57 }], From 233311f22e813dc72d457af6fea73df7fe8fac62 Mon Sep 17 00:00:00 2001 From: jeswr Date: Tue, 5 Jan 2021 13:46:15 +1100 Subject: [PATCH 33/45] Update reconstruct functionality and refactor the set token writer --- lib/reconstruct.ts | 49 +++++----- lib/sets-lookup.ts | 31 +++++++ lib/write-set-tokens.ts | 98 ++++++++++++++++++++ test/reconstruct-test.js | 192 +++++++++++++++++++++++++++++++-------- 4 files changed, 306 insertions(+), 64 deletions(-) create mode 100644 lib/sets-lookup.ts create mode 100644 lib/write-set-tokens.ts diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts index 2b49edc..e5124b0 100644 --- a/lib/reconstruct.ts +++ b/lib/reconstruct.ts @@ -1,15 +1,5 @@ import { types, Root, Token, Tokens, Group } from './types'; -import * as sets from './sets'; - -const simplifications: [sets.SetFunc, string][] = [ - [sets.words, '\\w'], - [sets.notWords, '\\W'], - [sets.ints, '\\d'], - [sets.notInts, '\\D'], - [sets.whitespace, '\\s'], - [sets.notWhitespace, '\\S'], - [sets.anyChar, '.'], -]; +import { writeSetTokens, setChar } from './write-set-tokens'; const reduceStack = (stack: Token[]): string => stack.map(reconstruct).join(''); @@ -29,7 +19,9 @@ export const reconstruct = (token: Tokens): string => { return createAlternate(token); case types.CHAR: { const c = String.fromCharCode(token.value); - return (/[[\]^./|?*+()]/.test(c) ? '\\' : '') + c; + // Note that the escaping for characters inside classes is handled + // in the write-set-tokens module so '-' and ']' are not escaped here + return (/[[{}$^.|?*+()]/.test(c) ? '\\' : '') + c; } case types.POSITION: if (token.value === '^' || token.value === '$') { @@ -40,20 +32,18 @@ export const reconstruct = (token: Tokens): string => { case types.REFERENCE: return `\\${token.value}`; case types.SET: - for (const [set, simplification] of simplifications) { - if (JSON.stringify(set()) === JSON.stringify(token)) { - return simplification; - } - } - return `[${token.not ? '^' : ''}${reduceStack(token.set)}]`; - case types.RANGE: - return `${String.fromCharCode(token.from)}-${String.fromCharCode(token.to)}`; - case types.GROUP: + // We only need to negate first internal '^' if token.not is false + // This is why the second arguement is !token.not + return writeSetTokens(token, !token.not); + case types.GROUP: { // Check token.remember - return `(${token.remember ? '' : '?'}${token.followedBy ? '=' : - token.notFollowedBy ? '!' : - token.remember ? '' : ':' - }${createAlternate(token)})`; + const prefix = + token.remember ? '' : + token.followedBy ? '?=' : + token.notFollowedBy ? '?!' : + '?:'; + return `(${prefix}${createAlternate(token)})`; + } case types.REPETITION: { const { min, max } = token; let endWith; @@ -63,12 +53,17 @@ export const reconstruct = (token: Tokens): string => { endWith = '+'; } else if (min === 0 && max === Infinity) { endWith = '*'; + } else if (max === Infinity) { + endWith = `{${min},}`; + } else if (min === max) { + endWith = `{${min}}`; } else { - endWith = max === Infinity ? `{${min},}` : - `{${min}${min === max ? `` : `,${max}`}}`; + endWith = `{${min},${max}}`; } return `${reconstruct(token.value)}${endWith}`; } + case types.RANGE: + return `${setChar(token.from, true, false)}-${setChar(token.to, false, true)}`; default: throw new Error(`Invalid token type ${token}`); } diff --git a/lib/sets-lookup.ts b/lib/sets-lookup.ts new file mode 100644 index 0000000..2938732 --- /dev/null +++ b/lib/sets-lookup.ts @@ -0,0 +1,31 @@ +export const WORDS = (): Record => ({ + 95: true, + '97-122': true, + '65-90': true, + '48-57': true, +}); + +export const WHITESPACE = (): Record => ({ + 9: true, + 10: true, + 11: true, + 12: true, + 13: true, + 32: true, + 160: true, + 5760: true, + '8192-8202': true, + 8232: true, + 8233: true, + 8239: true, + 8287: true, + 12288: true, + 65279: true, +}); + +export const NOTANYCHAR = (): Record => ({ + 10: true, + 13: true, + 8232: true, + 8233: true, +}); diff --git a/lib/write-set-tokens.ts b/lib/write-set-tokens.ts new file mode 100644 index 0000000..560e4ff --- /dev/null +++ b/lib/write-set-tokens.ts @@ -0,0 +1,98 @@ +import { types, Set, Range, Char, SetTokens } from './types'; +import * as sets from './sets-lookup'; + +/** + * Takes character code and returns character to be displayed in a set + * @param {number} charCode Character code of set element + * @param {boolean} firstChar True if character is the first character of the set + * @param {boolean} lastChar True if character is the last character of the set + * @returns {string} The string for the sets character + */ +export function setChar(charCode: number, firstChar: boolean, lastChar = false): string { + // We only need to negate first internal '^' if token.not is false + return firstChar && charCode === 94 ? '\\^' : + charCode === 92 ? '\\\\' : + charCode === 93 ? '\\]' : + charCode === 45 && !lastChar ? '\\-' : + String.fromCharCode(charCode); +} + +/** + * Test if a character set matches a 'set-lookup' + * @param {SetTokens} set The set to be tested + * @param {Record} map The predefined 'set-lookup' + * @returns {boolean} True if the character set corresponds to the 'set-lookup' + */ +function sameSet(set: SetTokens, map: Record): boolean { + for (const elem of set) { + if (elem.type === types.SET) { + return false; + } + const key = elem.type === types.CHAR ? elem.value : `${elem.from}-${elem.to}`; + if (map[key]) { + map[key] = false; + } else { + return false; + } + } + return true; +} + +/** + * Writes the tokens for a set + * @param {Set} set The set to display + * @param {boolean} firstChar Whether subset contains the first character of the set + * @param {boolean} nested Whether the token is nested inside another set token + * @returns {string} The tokens for the set + */ +export function writeSetTokens(set: Set, firstChar: boolean, nested = false): string { + const len = set.set.length; + if (len === 1) { + // Ints case + const [token] = set.set; + if (token.type === types.RANGE && token.from === 48 && token.to === 57) { + return set.not ? '\\D' : '\\d'; + } + } else if (len === 4) { + if (sameSet(set.set, sets.WORDS())) { + return set.not ? '\\W' : '\\w'; + } + // Notanychar is only relevant when not nested inside another set token + if (!nested && set.not && sameSet(set.set, sets.NOTANYCHAR())) { + return '.'; + } + } else if (len === 15 && sets.WHITESPACE()) { + return set.not ? '\\S' : '\\s'; + } + let firstCharTemp = firstChar; + let tokenString = ''; + for (let i = 0; i < len; i++) { + const subset = set.set[i]; + tokenString += writeSetToken(subset, firstCharTemp, i === len - 1); + // Only cancel out firstChar condition when we reach first non empty + // set in the sequence + firstCharTemp = firstCharTemp && subset.type === types.SET && subset.set.length === 0; + } + const contents = `${set.not ? '^' : ''}${tokenString}`; + return nested ? contents : `[${contents}]`; +} + +/** + * Writes a token within a set + * @param {Range | Char | Set} set The set token to display + * @param {boolean} firstChar Whether subset contains the first character of the set + * @param {boolean} lastChar True if character is the last character of the set + * @returns {string} The token as a string + */ +function writeSetToken(set: Range | Char | Set, firstChar: boolean, lastChar: boolean): string { + if (set.type === types.CHAR) { + return setChar(set.value, firstChar, lastChar); + } else if (set.type === types.RANGE) { + if (set.from === 48 && set.to === 57) { + return '\\d'; + } else { + return `${setChar(set.from, firstChar)}-${setChar(set.to, false, true)}`; + } + } + return writeSetTokens(set, firstChar, true); +} diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index f245458..d06cbed 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -1,22 +1,35 @@ const vows = require('vows'); const assert = require('assert'); const ret = require('../dist'); -const { tokenToString } = require('typescript'); const reconstruct = require('../dist/reconstruct').reconstruct; const types = require('../dist/types').types; -const inverseTestFactory = regexp => ({ +const inverseTestFactory = (regexp, expected) => ({ topic: ret(regexp), [`Checking ${regexp} reconstructs`]: t => { + // Make sure there are no invalid test cases + if ('stack' in t) { + for (const elem of t.stack) { + const badRange = elem.type === types.SET && + elem.set.some(token => token.type === types.RANGE && token.to < token.from); + + assert.deepStrictEqual(badRange, false); + } + } + // May need to do some sort of sanitisation here const reconstructed = reconstruct(t); assert.isString(reconstructed); - assert.deepStrictEqual(reconstructed, regexp.replace(/\[\^0-9\]/g, '\\D') - .replace(/\[0-9\]/g, '\\d') - .replace(/\[\^_a-zA-Z0-9\]/g, '\\W') - .replace(/\[_a-zA-Z0-9\]/g, '\\w'), - ); + if (expected) { + assert.deepStrictEqual(reconstructed, expected); + } else { + assert.deepStrictEqual(reconstructed, regexp.replace(/\[\^0-9\]/g, '\\D') + .replace(/\[0-9\]/g, '\\d') + .replace(/\[\^_a-zA-Z0-9\]/g, '\\W') + .replace(/\[_a-zA-Z0-9\]/g, '\\w'), + ); + } }, }); @@ -41,7 +54,7 @@ vows.describe('Regexp Reconstruction') '.', ',', 'word', - '\\/\\/', + '//', '\\W', '\\D', '\\w\\W\\d\\D\\s\\S.', @@ -53,11 +66,32 @@ vows.describe('Regexp Reconstruction') '.^', '$,', '$word^', - '$\\/\\/^', + '$//^', '$\\W^', '$\\D^', '$\\w\\W\\d\\D\\s\\S.^', ]), + 'testing handleing of escaped special characters': multiInverseTestFactory([ + '\\$', + '\\^', + '\\[', + '^\\^', + '\\.', + '\\|', + '\\?', + '\\(', + '\\)', + '\\{', + '\\}', + '\\$\\^\\[]\\.|', + '$\\^\\[]\\.\\|', + '\\$^\\[]\\.\\|', + '\\$\\^\\[]\\.\\|', + '\\$\\^[]\\.\\|', + '\\$\\^[]\\.\\|', + '\\$\\^\\[].\\|', + '\\$\\^\\[]\\.|', + ]), 'all main regexp expressions': { 'No special characters': inverseTestFactory('walnuts'), '^ and $ in': inverseTestFactory('^yes$'), @@ -65,7 +99,7 @@ vows.describe('Regexp Reconstruction') 'Predefined sets': inverseTestFactory('\\w\\W\\d\\D\\s\\S.'), 'Custom Sets': multiInverseTestFactory([ '[$!a-z123] thing [^0-9]', - '[^\\.]', + '[^.]', '[^test]', ]), 'Whitespace characters': inverseTestFactory('[\t\r\n\u2028\u2029 ]'), @@ -86,7 +120,7 @@ vows.describe('Regexp Reconstruction') 'exact amount': inverseTestFactory('(?:pika){2}'), 'minimum amount only': inverseTestFactory('NO{6,}'), 'both minimum and maximum': inverseTestFactory('pika\\.\\.\\. chu{3,20}!{1,2}'), - 'Brackets around a non-repetitional': inverseTestFactory('a{mustache}'), + 'Brackets around a non-repetitional': inverseTestFactory('a{mustache}', 'a\\{mustache\\}'), 'Predefined repetitional': { '? (Optional)': inverseTestFactory('hey(?: you)?'), '+ (At least one)': inverseTestFactory('(no )+'), @@ -114,7 +148,7 @@ vows.describe('Regexp Reconstruction') // Testing for https://github.com/fent/ret.js/pull/25#discussion_r533492862 'Range (in set) test cases': { 'Testing complex range cases': { - 'token.from is a hyphen and the range is preceded by a single character [a\\--\\-]': { + 'token.from is a hyphen and the range is preceded by a single character [a\\---]': { topic: { type: types.SET, not: false, set: [ { type: types.CHAR, value: 97 }, @@ -122,10 +156,10 @@ vows.describe('Regexp Reconstruction') ], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[a\\--\\-]'); + assert.deepStrictEqual(reconstruct(set), '[a\\---]'); }, }, - 'token.from is a hyphen and the range is preceded by a single character [a\\--\\/]': { + 'token.from is a hyphen and the range is preceded by a single character [a\\--/]': { topic: { type: types.SET, not: false, set: [ { type: types.CHAR, value: 97 }, @@ -133,7 +167,7 @@ vows.describe('Regexp Reconstruction') ], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[a\\--\\/]'); + assert.deepStrictEqual(reconstruct(set), '[a\\--/]'); }, }, 'token.from is a hyphen and the range is preceded by a single character [c\\--a]': { @@ -147,7 +181,7 @@ vows.describe('Regexp Reconstruction') assert.deepStrictEqual(reconstruct(set), '[c\\--a]'); }, }, - 'token.from is a hyphen and the range is preceded by a single character [\\-\\--\\-]': { + 'token.from is a hyphen and the range is preceded by a single character [\\-\\---]': { topic: { type: types.SET, not: false, set: [ { type: types.CHAR, value: 45 }, @@ -155,10 +189,10 @@ vows.describe('Regexp Reconstruction') ], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[\\-\\--\\-]'); + assert.deepStrictEqual(reconstruct(set), '[\\-\\---]'); }, }, - 'token.from is a hyphen and the range is preceded by a predefined set [\\w\\--\\-]': { + 'token.from is a hyphen and the range is preceded by a predefined set [\\w\\---]': { topic: { type: types.SET, not: false, set: [ { @@ -173,7 +207,7 @@ vows.describe('Regexp Reconstruction') ], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[\\w\\--\\-]'); + assert.deepStrictEqual(reconstruct(set), '[\\w\\---]'); }, }, 'token.from is a caret and the range is the first item of the set [9-^]': { @@ -196,20 +230,20 @@ vows.describe('Regexp Reconstruction') assert.deepStrictEqual(reconstruct(set), '[2-\\]]'); }, }, - 'token.to is a closing square bracket [\\-^]]': { + 'token.from is a closing square bracket [\\]-^]': { topic: { type: types.SET, not: false, set: [ { type: types.RANGE, from: 93, to: 94 }, ], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[\\-^]]'); + assert.deepStrictEqual(reconstruct(set), '[\\]-^]'); }, }, 'token.to is a closing square bracket [[-\\]]': { topic: { type: types.SET, not: false, set: [ - { type: types.RANGE, from: 92, to: 93 }, + { type: types.RANGE, from: 91, to: 93 }, ], }, 'Reconstructs correctly': set => { @@ -227,7 +261,7 @@ vows.describe('Regexp Reconstruction') type: types.CHAR, value: 93, }], }, - 'Tokenizes correctly': set => { + 'Reconstructs correctly': set => { assert.deepStrictEqual(reconstruct(set), '[[-]]'); }, }, @@ -239,7 +273,7 @@ vows.describe('Regexp Reconstruction') ], }], }, - 'Tokenizes correctly': set => { + 'Reconstructs correctly': set => { assert.deepStrictEqual(reconstruct(set), '[\\^-_]'); }, }, @@ -251,7 +285,7 @@ vows.describe('Regexp Reconstruction') ], }], }, - 'Tokenizes correctly': set => { + 'Reconstructs correctly': set => { assert.deepStrictEqual(reconstruct(set), '[\\^-^]'); }, }, @@ -263,7 +297,7 @@ vows.describe('Regexp Reconstruction') ], }], }, - 'Tokenizes correctly': set => { + 'Reconstructs correctly': set => { assert.deepStrictEqual(reconstruct(set), '[^^-_]'); }, }, @@ -275,7 +309,7 @@ vows.describe('Regexp Reconstruction') ], }], }, - 'Tokenizes correctly': set => { + 'Reconstructs correctly': set => { assert.deepStrictEqual(reconstruct(set), '[^^-^]'); }, }, @@ -339,21 +373,93 @@ vows.describe('Regexp Reconstruction') }, }, 'Testing inverse relations': multiInverseTestFactory([ - '[a\\--\\-]', - '[a\\--\\/]', + '[a\\---]', + '[a\\--/]', '[c\\--a]', - '[\\-\\--\\-]', - '[\\w\\--\\-]', + '[\\-\\---]', + '[\\w\\---]', '[9-^]', - '[09\\--\\-]', + '[09\\---]', '[2-\\]]', - '[\\^-\\]]', - '[\\^^-\\]]', - '[^^-\\]]', - '[\\[-\\]]', + '[\\]-^]', + '[\\^\\]-^]', + '[^\\]-^]', + '[^^-^]', '[[-\\]]', - '[[-]]' + '[[-]]', + '\\d', + '\\D', + '[\\\\-\\\\]', + ]), + 'Testing inverse relations with repitions': multiInverseTestFactory([ + '[a\\---]{3}', + '[a\\--/]{5}\\}', + '[c\\--a]{2}', + '[\\-\\---]\\{\\}', + '[\\w\\---]{1}', + '[9-^]+', + '[09\\---]*', + '[2-\\]]?', + '[\\]-^]\\+', + '[\\^\\]-^]\\*', + '[^\\]-^]\\?', + '[^^-^]\\{0\\}', + '[[-\\]]{0,9}', + '[[-]]\\{0,9\\}', + '\\d?', + '\\D?', + '[\\\\-\\\\]?', ]), + 'Similar to predefined sets': { + 'Similar to ints': { + topic: [{ type: types.RANGE, from: 48, to: 56 }], + 'Set similar to simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '[0-8]'); + }, + 'Set similar to simplification works (nested)': set => { + assert.deepStrictEqual(reconstruct({ + type: types.SET, + set: [{ type: types.SET, set, not: false }], + not: false, + }), + '[0-8]'); + }, + 'Negative set similar to simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '[^0-8]'); + }, + }, + 'Similar to words': { + WORDS: { + topic: [ + { type: types.CHAR, value: 95 }, + { type: types.RANGE, from: 97, to: 122 }, + { type: types.RANGE, from: 48, to: 57 }, + ], + 'Set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '[_a-z\\d]'); + }, + 'Negative set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '[^_a-z\\d]'); + }, + }, + }, + 'Similar to words with nesed set': { + WORDS: { + topic: [ + { type: types.CHAR, value: 95 }, + { type: types.RANGE, from: 97, to: 122 }, + { type: types.SET, not: false, set: [] }, + { type: types.RANGE, from: 48, to: 57 }, + ], + 'Set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '[_a-z\\d]'); + }, + 'Negative set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '[^_a-z\\d]'); + }, + }, + }, + }, }, 'Set simplification tests': { INTS: { @@ -443,6 +549,18 @@ vows.describe('Regexp Reconstruction') assert.include(err.message, 'Invalid token type'); }, }, + 'Reconsutructs individual range tokens outisde of set 0-8': { + topic: reconstruct({ type: types.RANGE, from: 48, to: 56 }), + 'Outputs range correctly': res => { + assert.deepStrictEqual(res, '0-8'); + }, + }, + 'Reconsutructs individual range tokens outisde of set 0-\\]': { + topic: reconstruct({ type: types.RANGE, from: 48, to: 93 }), + 'Outputs range correctly': res => { + assert.deepStrictEqual(res, '0-\\]'); + }, + }, }, }) .export(module); From f292eb667afbc7955c07c4fac171124817b17f87 Mon Sep 17 00:00:00 2001 From: jeswr Date: Tue, 5 Jan 2021 13:56:36 +1100 Subject: [PATCH 34/45] Remove unecessary readme space change --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 908de5a..6d82d73 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ The `reconstruct` function accepts a *any* token and returns, as a string, the * ```ts import { reconstruct, types } from 'ret' - const tokens = ret(/foo|bar/.source) const setToken = { "type": types.SET, @@ -46,7 +45,6 @@ const setToken = { ], "not": true } - reconstruct(tokens) // 'foo|bar' reconstruct({ "type": types.CHAR, "value": 102 }) // 'f' reconstruct(setToken) // '^abc' @@ -262,7 +260,7 @@ The following latest JavaScript additions are not supported yet: `/\w/` ```js -// Similar logic for `\W`, `\d`, `\D`, `\s` and `\S` +// Similar logic for `\W`, `\d`, `\D`, `\s` and `\S` { "type": ret.types.ROOT, "stack": [{ From 0a9252af61e9ae23c6cf076f1d5d99860b01c2bc Mon Sep 17 00:00:00 2001 From: jeswr Date: Wed, 6 Jan 2021 11:58:25 +1100 Subject: [PATCH 35/45] Rename boolean variables --- lib/write-set-tokens.ts | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/write-set-tokens.ts b/lib/write-set-tokens.ts index 560e4ff..b7d96a4 100644 --- a/lib/write-set-tokens.ts +++ b/lib/write-set-tokens.ts @@ -4,16 +4,16 @@ import * as sets from './sets-lookup'; /** * Takes character code and returns character to be displayed in a set * @param {number} charCode Character code of set element - * @param {boolean} firstChar True if character is the first character of the set - * @param {boolean} lastChar True if character is the last character of the set + * @param {boolean} isFirstChar True if character is the first character of the set + * @param {boolean} isLastChar True if character is the last character of the set * @returns {string} The string for the sets character */ -export function setChar(charCode: number, firstChar: boolean, lastChar = false): string { +export function setChar(charCode: number, isFirstChar: boolean, isLastChar = false): string { // We only need to negate first internal '^' if token.not is false - return firstChar && charCode === 94 ? '\\^' : + return isFirstChar && charCode === 94 ? '\\^' : charCode === 92 ? '\\\\' : charCode === 93 ? '\\]' : - charCode === 45 && !lastChar ? '\\-' : + charCode === 45 && !isLastChar ? '\\-' : String.fromCharCode(charCode); } @@ -23,7 +23,7 @@ export function setChar(charCode: number, firstChar: boolean, lastChar = false): * @param {Record} map The predefined 'set-lookup' * @returns {boolean} True if the character set corresponds to the 'set-lookup' */ -function sameSet(set: SetTokens, map: Record): boolean { +function isSameSet(set: SetTokens, map: Record): boolean { for (const elem of set) { if (elem.type === types.SET) { return false; @@ -41,11 +41,11 @@ function sameSet(set: SetTokens, map: Record): boolean /** * Writes the tokens for a set * @param {Set} set The set to display - * @param {boolean} firstChar Whether subset contains the first character of the set - * @param {boolean} nested Whether the token is nested inside another set token + * @param {boolean} isFirstChar Whether subset contains the first character of the set + * @param {boolean} isNested Whether the token is nested inside another set token * @returns {string} The tokens for the set */ -export function writeSetTokens(set: Set, firstChar: boolean, nested = false): string { +export function writeSetTokens(set: Set, isFirstChar: boolean, isNested = false): string { const len = set.set.length; if (len === 1) { // Ints case @@ -54,45 +54,45 @@ export function writeSetTokens(set: Set, firstChar: boolean, nested = false): st return set.not ? '\\D' : '\\d'; } } else if (len === 4) { - if (sameSet(set.set, sets.WORDS())) { + if (isSameSet(set.set, sets.WORDS())) { return set.not ? '\\W' : '\\w'; } // Notanychar is only relevant when not nested inside another set token - if (!nested && set.not && sameSet(set.set, sets.NOTANYCHAR())) { + if (!isNested && set.not && isSameSet(set.set, sets.NOTANYCHAR())) { return '.'; } } else if (len === 15 && sets.WHITESPACE()) { return set.not ? '\\S' : '\\s'; } - let firstCharTemp = firstChar; + let isFirstCharTemp = isFirstChar; let tokenString = ''; for (let i = 0; i < len; i++) { const subset = set.set[i]; - tokenString += writeSetToken(subset, firstCharTemp, i === len - 1); + tokenString += writeSetToken(subset, isFirstCharTemp, i === len - 1); // Only cancel out firstChar condition when we reach first non empty // set in the sequence - firstCharTemp = firstCharTemp && subset.type === types.SET && subset.set.length === 0; + isFirstCharTemp = isFirstCharTemp && subset.type === types.SET && subset.set.length === 0; } const contents = `${set.not ? '^' : ''}${tokenString}`; - return nested ? contents : `[${contents}]`; + return isNested ? contents : `[${contents}]`; } /** * Writes a token within a set * @param {Range | Char | Set} set The set token to display - * @param {boolean} firstChar Whether subset contains the first character of the set - * @param {boolean} lastChar True if character is the last character of the set + * @param {boolean} isFirstChar Whether subset contains the first character of the set + * @param {boolean} isLastChar True if character is the last character of the set * @returns {string} The token as a string */ -function writeSetToken(set: Range | Char | Set, firstChar: boolean, lastChar: boolean): string { +function writeSetToken(set: Range | Char | Set, isFirstChar: boolean, isLastChar: boolean): string { if (set.type === types.CHAR) { - return setChar(set.value, firstChar, lastChar); + return setChar(set.value, isFirstChar, isLastChar); } else if (set.type === types.RANGE) { if (set.from === 48 && set.to === 57) { return '\\d'; } else { - return `${setChar(set.from, firstChar)}-${setChar(set.to, false, true)}`; + return `${setChar(set.from, isFirstChar)}-${setChar(set.to, false, true)}`; } } - return writeSetTokens(set, firstChar, true); + return writeSetTokens(set, isFirstChar, true); } From f7accaa2ab061923264a0f0ffa8fb23109a10ead Mon Sep 17 00:00:00 2001 From: jeswr Date: Wed, 6 Jan 2021 12:14:09 +1100 Subject: [PATCH 36/45] Fix (https://github.com/fent/ret.js/pull/25#discussion_r551753241) and add test cases --- lib/write-set-tokens.ts | 2 +- test/reconstruct-test.js | 47 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/write-set-tokens.ts b/lib/write-set-tokens.ts index b7d96a4..37ec0ee 100644 --- a/lib/write-set-tokens.ts +++ b/lib/write-set-tokens.ts @@ -61,7 +61,7 @@ export function writeSetTokens(set: Set, isFirstChar: boolean, isNested = false) if (!isNested && set.not && isSameSet(set.set, sets.NOTANYCHAR())) { return '.'; } - } else if (len === 15 && sets.WHITESPACE()) { + } else if (len === 15 && isSameSet(set.set, sets.WHITESPACE())) { return set.not ? '\\S' : '\\s'; } let isFirstCharTemp = isFirstChar; diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index d06cbed..9b6aa4d 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -4,6 +4,28 @@ const ret = require('../dist'); const reconstruct = require('../dist/reconstruct').reconstruct; const types = require('../dist/types').types; +const similarToWhitespaceSet = [ + { type: types.CHAR, value: 9 }, + { type: types.CHAR, value: 10 }, + { type: types.CHAR, value: 11 }, + { type: types.CHAR, value: 12 }, + { type: types.CHAR, value: 13 }, + { type: types.CHAR, value: 32 }, + { type: types.CHAR, value: 160 }, + { type: types.CHAR, value: 5760 }, + { type: types.RANGE, from: 8192, to: 8200 }, + { type: types.CHAR, value: 8232 }, + { type: types.CHAR, value: 8233 }, + { type: types.CHAR, value: 8239 }, + { type: types.CHAR, value: 8287 }, + { type: types.CHAR, value: 12288 }, + { type: types.CHAR, value: 65279 }, +].map(code => { + return code.type === types.CHAR ? + String.fromCharCode(code.value) : + String.fromCharCode(code.from) + '-' + String.fromCharCode(code.to); +}).join('') + const inverseTestFactory = (regexp, expected) => ({ topic: ret(regexp), @@ -459,6 +481,31 @@ vows.describe('Regexp Reconstruction') }, }, }, + 'Similar to whitespace': { + topic: [ + { type: types.CHAR, value: 9 }, + { type: types.CHAR, value: 10 }, + { type: types.CHAR, value: 11 }, + { type: types.CHAR, value: 12 }, + { type: types.CHAR, value: 13 }, + { type: types.CHAR, value: 32 }, + { type: types.CHAR, value: 160 }, + { type: types.CHAR, value: 5760 }, + { type: types.RANGE, from: 8192, to: 8200 }, + { type: types.CHAR, value: 8232 }, + { type: types.CHAR, value: 8233 }, + { type: types.CHAR, value: 8239 }, + { type: types.CHAR, value: 8287 }, + { type: types.CHAR, value: 12288 }, + { type: types.CHAR, value: 65279 }, + ], + 'Set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), `[${similarToWhitespaceSet}]`); + }, + 'Negative set simplification works': set => { + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), `[^${similarToWhitespaceSet}]`); + }, + }, }, }, 'Set simplification tests': { From 01caba91dbca501499af23af2dd2dc2fd7afb90e Mon Sep 17 00:00:00 2001 From: jeswr Date: Wed, 6 Jan 2021 12:18:32 +1100 Subject: [PATCH 37/45] Resolve (https://github.com/fent/ret.js/pull/25#discussion_r551754929) and add test cases --- lib/write-set-tokens.ts | 6 +----- test/reconstruct-test.js | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/lib/write-set-tokens.ts b/lib/write-set-tokens.ts index 37ec0ee..fd24051 100644 --- a/lib/write-set-tokens.ts +++ b/lib/write-set-tokens.ts @@ -88,11 +88,7 @@ function writeSetToken(set: Range | Char | Set, isFirstChar: boolean, isLastChar if (set.type === types.CHAR) { return setChar(set.value, isFirstChar, isLastChar); } else if (set.type === types.RANGE) { - if (set.from === 48 && set.to === 57) { - return '\\d'; - } else { - return `${setChar(set.from, isFirstChar)}-${setChar(set.to, false, true)}`; - } + return `${setChar(set.from, isFirstChar)}-${setChar(set.to, false, true)}`; } return writeSetTokens(set, isFirstChar, true); } diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index 9b6aa4d..8a9c98a 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -20,11 +20,9 @@ const similarToWhitespaceSet = [ { type: types.CHAR, value: 8287 }, { type: types.CHAR, value: 12288 }, { type: types.CHAR, value: 65279 }, -].map(code => { - return code.type === types.CHAR ? - String.fromCharCode(code.value) : - String.fromCharCode(code.from) + '-' + String.fromCharCode(code.to); -}).join('') +].map(code => code.type === types.CHAR ? + String.fromCharCode(code.value) : + `${String.fromCharCode(code.from)}-${String.fromCharCode(code.to)}`).join(''); const inverseTestFactory = (regexp, expected) => ({ topic: ret(regexp), @@ -458,10 +456,10 @@ vows.describe('Regexp Reconstruction') { type: types.RANGE, from: 48, to: 57 }, ], 'Set simplification works': set => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '[_a-z\\d]'); + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '[_a-z0-9]'); }, 'Negative set simplification works': set => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '[^_a-z\\d]'); + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '[^_a-z0-9]'); }, }, }, @@ -474,10 +472,10 @@ vows.describe('Regexp Reconstruction') { type: types.RANGE, from: 48, to: 57 }, ], 'Set simplification works': set => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '[_a-z\\d]'); + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), '[_a-z0-9]'); }, 'Negative set simplification works': set => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '[^_a-z\\d]'); + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), '[^_a-z0-9]'); }, }, }, @@ -500,10 +498,12 @@ vows.describe('Regexp Reconstruction') { type: types.CHAR, value: 65279 }, ], 'Set simplification works': set => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), `[${similarToWhitespaceSet}]`); + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: false }), + `[${similarToWhitespaceSet}]`); }, 'Negative set simplification works': set => { - assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), `[^${similarToWhitespaceSet}]`); + assert.deepStrictEqual(reconstruct({ type: types.SET, set, not: true }), + `[^${similarToWhitespaceSet}]`); }, }, }, From 5425a32b86523d46b67ca7bfd51251cf0aac4a55 Mon Sep 17 00:00:00 2001 From: jeswr Date: Wed, 6 Jan 2021 12:31:03 +1100 Subject: [PATCH 38/45] Resolve (https://github.com/fent/ret.js/pull/25#discussion_r551752567) --- lib/sets-lookup.ts | 4 ++++ lib/write-set-tokens.ts | 10 +++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/sets-lookup.ts b/lib/sets-lookup.ts index 2938732..b9623c3 100644 --- a/lib/sets-lookup.ts +++ b/lib/sets-lookup.ts @@ -1,3 +1,7 @@ +export const INTS = (): Record => ({ + '48-57': true, +}); + export const WORDS = (): Record => ({ 95: true, '97-122': true, diff --git a/lib/write-set-tokens.ts b/lib/write-set-tokens.ts index fd24051..4c3769d 100644 --- a/lib/write-set-tokens.ts +++ b/lib/write-set-tokens.ts @@ -47,18 +47,14 @@ function isSameSet(set: SetTokens, map: Record): boole */ export function writeSetTokens(set: Set, isFirstChar: boolean, isNested = false): string { const len = set.set.length; - if (len === 1) { - // Ints case - const [token] = set.set; - if (token.type === types.RANGE && token.from === 48 && token.to === 57) { - return set.not ? '\\D' : '\\d'; - } + if (len === 1 && isSameSet(set.set, sets.INTS())) { + return set.not ? '\\D' : '\\d'; } else if (len === 4) { if (isSameSet(set.set, sets.WORDS())) { return set.not ? '\\W' : '\\w'; } // Notanychar is only relevant when not nested inside another set token - if (!isNested && set.not && isSameSet(set.set, sets.NOTANYCHAR())) { + if (set.not && isSameSet(set.set, sets.NOTANYCHAR())) { return '.'; } } else if (len === 15 && isSameSet(set.set, sets.WHITESPACE())) { From 8e71441fcd3837e012a994c3c11f0bc5ab66b8b7 Mon Sep 17 00:00:00 2001 From: jeswr Date: Sat, 9 Jan 2021 12:24:29 +1100 Subject: [PATCH 39/45] fix https://github.com/fent/ret.js/pull/25#discussion_r554205556, missing backslash escape --- lib/reconstruct.ts | 2 +- test/reconstruct-test.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts index e5124b0..469499f 100644 --- a/lib/reconstruct.ts +++ b/lib/reconstruct.ts @@ -21,7 +21,7 @@ export const reconstruct = (token: Tokens): string => { const c = String.fromCharCode(token.value); // Note that the escaping for characters inside classes is handled // in the write-set-tokens module so '-' and ']' are not escaped here - return (/[[{}$^.|?*+()]/.test(c) ? '\\' : '') + c; + return (/[[\\{}$^.|?*+()]/.test(c) ? '\\' : '') + c; } case types.POSITION: if (token.value === '^' || token.value === '$') { diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index 8a9c98a..1764974 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -103,6 +103,7 @@ vows.describe('Regexp Reconstruction') '\\)', '\\{', '\\}', + '\\\\', '\\$\\^\\[]\\.|', '$\\^\\[]\\.\\|', '\\$^\\[]\\.\\|', @@ -111,6 +112,9 @@ vows.describe('Regexp Reconstruction') '\\$\\^[]\\.\\|', '\\$\\^\\[].\\|', '\\$\\^\\[]\\.|', + '\\$\\^\\[]\\.|\\\\', + '\\$\\^\\[]\\.\\\\|', + '\\\\\\$\\^\\[]\\.|', ]), 'all main regexp expressions': { 'No special characters': inverseTestFactory('walnuts'), From 09a33bd0831962e1fa4b7889ed54321c741349b6 Mon Sep 17 00:00:00 2001 From: jeswr Date: Thu, 14 Jan 2021 13:03:04 +1100 Subject: [PATCH 40/45] resolve https://github.com/fent/ret.js/pull/25#discussion_r554206935 --- lib/reconstruct.ts | 2 +- lib/write-set-tokens.ts | 14 +++++----- test/reconstruct-test.js | 58 ++++++++++++++++++++-------------------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts index 469499f..eac9505 100644 --- a/lib/reconstruct.ts +++ b/lib/reconstruct.ts @@ -63,7 +63,7 @@ export const reconstruct = (token: Tokens): string => { return `${reconstruct(token.value)}${endWith}`; } case types.RANGE: - return `${setChar(token.from, true, false)}-${setChar(token.to, false, true)}`; + return `${setChar(token.from)}-${setChar(token.to)}`; default: throw new Error(`Invalid token type ${token}`); } diff --git a/lib/write-set-tokens.ts b/lib/write-set-tokens.ts index 4c3769d..910ad8d 100644 --- a/lib/write-set-tokens.ts +++ b/lib/write-set-tokens.ts @@ -8,12 +8,12 @@ import * as sets from './sets-lookup'; * @param {boolean} isLastChar True if character is the last character of the set * @returns {string} The string for the sets character */ -export function setChar(charCode: number, isFirstChar: boolean, isLastChar = false): string { +export function setChar(charCode: number): string { // We only need to negate first internal '^' if token.not is false - return isFirstChar && charCode === 94 ? '\\^' : + return charCode === 94 ? '\\^' : charCode === 92 ? '\\\\' : charCode === 93 ? '\\]' : - charCode === 45 && !isLastChar ? '\\-' : + charCode === 45 ? '\\-' : String.fromCharCode(charCode); } @@ -64,7 +64,7 @@ export function writeSetTokens(set: Set, isFirstChar: boolean, isNested = false) let tokenString = ''; for (let i = 0; i < len; i++) { const subset = set.set[i]; - tokenString += writeSetToken(subset, isFirstCharTemp, i === len - 1); + tokenString += writeSetToken(subset, isFirstCharTemp); // Only cancel out firstChar condition when we reach first non empty // set in the sequence isFirstCharTemp = isFirstCharTemp && subset.type === types.SET && subset.set.length === 0; @@ -80,11 +80,11 @@ export function writeSetTokens(set: Set, isFirstChar: boolean, isNested = false) * @param {boolean} isLastChar True if character is the last character of the set * @returns {string} The token as a string */ -function writeSetToken(set: Range | Char | Set, isFirstChar: boolean, isLastChar: boolean): string { +function writeSetToken(set: Range | Char | Set, isFirstChar: boolean): string { if (set.type === types.CHAR) { - return setChar(set.value, isFirstChar, isLastChar); + return setChar(set.value); } else if (set.type === types.RANGE) { - return `${setChar(set.from, isFirstChar)}-${setChar(set.to, false, true)}`; + return `${setChar(set.from)}-${setChar(set.to)}`; } return writeSetTokens(set, isFirstChar, true); } diff --git a/test/reconstruct-test.js b/test/reconstruct-test.js index 1764974..683677b 100644 --- a/test/reconstruct-test.js +++ b/test/reconstruct-test.js @@ -180,7 +180,7 @@ vows.describe('Regexp Reconstruction') ], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[a\\---]'); + assert.deepStrictEqual(reconstruct(set), '[a\\--\\-]'); }, }, 'token.from is a hyphen and the range is preceded by a single character [a\\--/]': { @@ -213,7 +213,7 @@ vows.describe('Regexp Reconstruction') ], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[\\-\\---]'); + assert.deepStrictEqual(reconstruct(set), '[\\-\\--\\-]'); }, }, 'token.from is a hyphen and the range is preceded by a predefined set [\\w\\---]': { @@ -231,7 +231,7 @@ vows.describe('Regexp Reconstruction') ], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[\\w\\---]'); + assert.deepStrictEqual(reconstruct(set), '[\\w\\--\\-]'); }, }, 'token.from is a caret and the range is the first item of the set [9-^]': { @@ -241,7 +241,7 @@ vows.describe('Regexp Reconstruction') ], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[9-^]'); + assert.deepStrictEqual(reconstruct(set), '[9-\\^]'); }, }, 'token.to is a closing square bracket [2-\\]]': { @@ -261,7 +261,7 @@ vows.describe('Regexp Reconstruction') ], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[\\]-^]'); + assert.deepStrictEqual(reconstruct(set), '[\\]-\\^]'); }, }, 'token.to is a closing square bracket [[-\\]]': { @@ -286,7 +286,7 @@ vows.describe('Regexp Reconstruction') }], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[[-]]'); + assert.deepStrictEqual(reconstruct(set), '[[\\-]]'); }, }, 'token.from is a caret [\\^-_]': { @@ -310,7 +310,7 @@ vows.describe('Regexp Reconstruction') }], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[\\^-^]'); + assert.deepStrictEqual(reconstruct(set), '[\\^-\\^]'); }, }, 'token.from is a caret and set is negated [^^-_]': { @@ -322,7 +322,7 @@ vows.describe('Regexp Reconstruction') }], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[^^-_]'); + assert.deepStrictEqual(reconstruct(set), '[^\\^-_]'); }, }, 'token.from is a caret [^^-^] and set is negated': { @@ -334,7 +334,7 @@ vows.describe('Regexp Reconstruction') }], }, 'Reconstructs correctly': set => { - assert.deepStrictEqual(reconstruct(set), '[^^-^]'); + assert.deepStrictEqual(reconstruct(set), '[^\\^-\\^]'); }, }, 'Contains emtpy set': { @@ -397,39 +397,39 @@ vows.describe('Regexp Reconstruction') }, }, 'Testing inverse relations': multiInverseTestFactory([ - '[a\\---]', + '[a\\--\\-]', '[a\\--/]', '[c\\--a]', - '[\\-\\---]', - '[\\w\\---]', - '[9-^]', - '[09\\---]', + '[\\-\\--\\-]', + '[\\w\\--\\-]', + '[9-\\^]', + '[09\\--\\-]', '[2-\\]]', - '[\\]-^]', - '[\\^\\]-^]', - '[^\\]-^]', - '[^^-^]', + '[\\]-\\^]', + '[\\^\\]-\\^]', + '[^\\]-\\^]', + '[^\\^-\\^]', '[[-\\]]', - '[[-]]', + '[[\\-]]', '\\d', '\\D', '[\\\\-\\\\]', ]), 'Testing inverse relations with repitions': multiInverseTestFactory([ - '[a\\---]{3}', + '[a\\--\\-]{3}', '[a\\--/]{5}\\}', '[c\\--a]{2}', - '[\\-\\---]\\{\\}', - '[\\w\\---]{1}', - '[9-^]+', - '[09\\---]*', + '[\\-\\--\\-]\\{\\}', + '[\\w\\--\\-]{1}', + '[9-\\^]+', + '[09\\--\\-]*', '[2-\\]]?', - '[\\]-^]\\+', - '[\\^\\]-^]\\*', - '[^\\]-^]\\?', - '[^^-^]\\{0\\}', + '[\\]-\\^]\\+', + '[\\^\\]-\\^]\\*', + '[^\\]-\\^]\\?', + '[^\\^-\\^]\\{0\\}', '[[-\\]]{0,9}', - '[[-]]\\{0,9\\}', + '[[\\-]]\\{0,9\\}', '\\d?', '\\D?', '[\\\\-\\\\]?', From 281cd60ece1e332f2a95bb6d15c3625c6f1fea39 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 15 Jan 2021 11:12:08 +1100 Subject: [PATCH 41/45] Update lib/write-set-tokens.ts Co-authored-by: Charmander <~@charmander.me> --- lib/write-set-tokens.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/write-set-tokens.ts b/lib/write-set-tokens.ts index 910ad8d..55b11fb 100644 --- a/lib/write-set-tokens.ts +++ b/lib/write-set-tokens.ts @@ -4,8 +4,6 @@ import * as sets from './sets-lookup'; /** * Takes character code and returns character to be displayed in a set * @param {number} charCode Character code of set element - * @param {boolean} isFirstChar True if character is the first character of the set - * @param {boolean} isLastChar True if character is the last character of the set * @returns {string} The string for the sets character */ export function setChar(charCode: number): string { From 7182c9c5b13ac96cfd9d979f886b0d438479b0c0 Mon Sep 17 00:00:00 2001 From: jeswr Date: Fri, 15 Jan 2021 11:22:19 +1100 Subject: [PATCH 42/45] resolve https://github.com/fent/ret.js/pull/25#discussion_r557779768 --- lib/reconstruct.ts | 4 +--- lib/write-set-tokens.ts | 15 ++++----------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/lib/reconstruct.ts b/lib/reconstruct.ts index eac9505..76507c3 100644 --- a/lib/reconstruct.ts +++ b/lib/reconstruct.ts @@ -32,9 +32,7 @@ export const reconstruct = (token: Tokens): string => { case types.REFERENCE: return `\\${token.value}`; case types.SET: - // We only need to negate first internal '^' if token.not is false - // This is why the second arguement is !token.not - return writeSetTokens(token, !token.not); + return writeSetTokens(token); case types.GROUP: { // Check token.remember const prefix = diff --git a/lib/write-set-tokens.ts b/lib/write-set-tokens.ts index 55b11fb..16728db 100644 --- a/lib/write-set-tokens.ts +++ b/lib/write-set-tokens.ts @@ -39,11 +39,10 @@ function isSameSet(set: SetTokens, map: Record): boole /** * Writes the tokens for a set * @param {Set} set The set to display - * @param {boolean} isFirstChar Whether subset contains the first character of the set * @param {boolean} isNested Whether the token is nested inside another set token * @returns {string} The tokens for the set */ -export function writeSetTokens(set: Set, isFirstChar: boolean, isNested = false): string { +export function writeSetTokens(set: Set, isNested = false): string { const len = set.set.length; if (len === 1 && isSameSet(set.set, sets.INTS())) { return set.not ? '\\D' : '\\d'; @@ -58,14 +57,10 @@ export function writeSetTokens(set: Set, isFirstChar: boolean, isNested = false) } else if (len === 15 && isSameSet(set.set, sets.WHITESPACE())) { return set.not ? '\\S' : '\\s'; } - let isFirstCharTemp = isFirstChar; let tokenString = ''; for (let i = 0; i < len; i++) { const subset = set.set[i]; - tokenString += writeSetToken(subset, isFirstCharTemp); - // Only cancel out firstChar condition when we reach first non empty - // set in the sequence - isFirstCharTemp = isFirstCharTemp && subset.type === types.SET && subset.set.length === 0; + tokenString += writeSetToken(subset); } const contents = `${set.not ? '^' : ''}${tokenString}`; return isNested ? contents : `[${contents}]`; @@ -74,15 +69,13 @@ export function writeSetTokens(set: Set, isFirstChar: boolean, isNested = false) /** * Writes a token within a set * @param {Range | Char | Set} set The set token to display - * @param {boolean} isFirstChar Whether subset contains the first character of the set - * @param {boolean} isLastChar True if character is the last character of the set * @returns {string} The token as a string */ -function writeSetToken(set: Range | Char | Set, isFirstChar: boolean): string { +function writeSetToken(set: Range | Char | Set): string { if (set.type === types.CHAR) { return setChar(set.value); } else if (set.type === types.RANGE) { return `${setChar(set.from)}-${setChar(set.to)}`; } - return writeSetTokens(set, isFirstChar, true); + return writeSetTokens(set, true); } From 63157e4f711b7c23cef44870741825b7a756e37e Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 5 Feb 2021 18:21:00 +1100 Subject: [PATCH 43/45] Update README.md Co-authored-by: fent --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d82d73..140c229 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ let tokens = ret(/foo|bar/.source); # Reconstructing Regular Expressions from Tokens -The `reconstruct` function accepts a *any* token and returns, as a string, the *component* of the regular expression that is associated with that token. +The `reconstruct` function accepts an *any* token and returns, as a string, the *component* of the regular expression that is associated with that token. ```ts import { reconstruct, types } from 'ret' From 393b0ee479f1eaf187a9d520f74d60cdea8eea90 Mon Sep 17 00:00:00 2001 From: Jesse Wright Date: Fri, 5 Feb 2021 18:22:12 +1100 Subject: [PATCH 44/45] Update write-set-tokens.ts --- lib/write-set-tokens.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/write-set-tokens.ts b/lib/write-set-tokens.ts index 16728db..467ac16 100644 --- a/lib/write-set-tokens.ts +++ b/lib/write-set-tokens.ts @@ -7,7 +7,6 @@ import * as sets from './sets-lookup'; * @returns {string} The string for the sets character */ export function setChar(charCode: number): string { - // We only need to negate first internal '^' if token.not is false return charCode === 94 ? '\\^' : charCode === 92 ? '\\\\' : charCode === 93 ? '\\]' : From 9f1692c67acdb6c92fcff94047b3998ef7df628f Mon Sep 17 00:00:00 2001 From: jeswr Date: Mon, 8 Feb 2021 21:43:20 +1100 Subject: [PATCH 45/45] Generating set lookup at runtime --- lib/sets-lookup.ts | 61 +++++++++++++++++++---------------------- lib/types/set-lookup.ts | 8 ++++++ lib/write-set-tokens.ts | 34 +++++++++++++---------- 3 files changed, 56 insertions(+), 47 deletions(-) create mode 100644 lib/types/set-lookup.ts diff --git a/lib/sets-lookup.ts b/lib/sets-lookup.ts index b9623c3..c1e4a22 100644 --- a/lib/sets-lookup.ts +++ b/lib/sets-lookup.ts @@ -1,35 +1,30 @@ -export const INTS = (): Record => ({ - '48-57': true, -}); +import * as Sets from './sets'; +import { SetTokens, types } from './types'; -export const WORDS = (): Record => ({ - 95: true, - '97-122': true, - '65-90': true, - '48-57': true, -}); +function setToLookup(tokens: SetTokens) { + let lookup: Record = {}; + let len = 0; + for (const token of tokens) { + if (token.type === types.CHAR) { + lookup[token.value] = true; + } + // Note this is in an if statement because + // the SetTokens type is (Char | Range | Set)[] + // so a type error is thrown if it is not. + // If the SetTokens type is modified the if statement + // can be removed + if (token.type === types.RANGE) { + lookup[`${token.from}-${token.to}`] = true; + } + len += 1; + } + return { + lookup: () => ({ ...lookup }), + len, + }; +} -export const WHITESPACE = (): Record => ({ - 9: true, - 10: true, - 11: true, - 12: true, - 13: true, - 32: true, - 160: true, - 5760: true, - '8192-8202': true, - 8232: true, - 8233: true, - 8239: true, - 8287: true, - 12288: true, - 65279: true, -}); - -export const NOTANYCHAR = (): Record => ({ - 10: true, - 13: true, - 8232: true, - 8233: true, -}); +export const INTS = setToLookup(Sets.ints().set); +export const WORDS = setToLookup(Sets.words().set); +export const WHITESPACE = setToLookup(Sets.whitespace().set); +export const NOTANYCHAR = setToLookup(Sets.anyChar().set); diff --git a/lib/types/set-lookup.ts b/lib/types/set-lookup.ts new file mode 100644 index 0000000..f3e24aa --- /dev/null +++ b/lib/types/set-lookup.ts @@ -0,0 +1,8 @@ +/** + * The number of elements in a set lookup, and a + * function that returns the lookup. + */ +export interface SetLookup { + len: number; + lookup: () => Record +} diff --git a/lib/write-set-tokens.ts b/lib/write-set-tokens.ts index 467ac16..3aef48c 100644 --- a/lib/write-set-tokens.ts +++ b/lib/write-set-tokens.ts @@ -1,5 +1,6 @@ import { types, Set, Range, Char, SetTokens } from './types'; import * as sets from './sets-lookup'; +import { SetLookup } from './types/set-lookup'; /** * Takes character code and returns character to be displayed in a set @@ -17,10 +18,16 @@ export function setChar(charCode: number): string { /** * Test if a character set matches a 'set-lookup' * @param {SetTokens} set The set to be tested - * @param {Record} map The predefined 'set-lookup' + * @param {SetLookup} param The predefined 'set-lookup' & the number of elements in the lookup * @returns {boolean} True if the character set corresponds to the 'set-lookup' */ -function isSameSet(set: SetTokens, map: Record): boolean { +function isSameSet(set: SetTokens, { lookup, len }: SetLookup): boolean { + // If the set and the lookup are not of the same length + // then we immediately know that the lookup will be false + if (len !== set.length) { + return false; + } + const map = lookup(); for (const elem of set) { if (elem.type === types.SET) { return false; @@ -42,22 +49,21 @@ function isSameSet(set: SetTokens, map: Record): boole * @returns {string} The tokens for the set */ export function writeSetTokens(set: Set, isNested = false): string { - const len = set.set.length; - if (len === 1 && isSameSet(set.set, sets.INTS())) { + if (isSameSet(set.set, sets.INTS)) { return set.not ? '\\D' : '\\d'; - } else if (len === 4) { - if (isSameSet(set.set, sets.WORDS())) { - return set.not ? '\\W' : '\\w'; - } - // Notanychar is only relevant when not nested inside another set token - if (set.not && isSameSet(set.set, sets.NOTANYCHAR())) { - return '.'; - } - } else if (len === 15 && isSameSet(set.set, sets.WHITESPACE())) { + } + if (isSameSet(set.set, sets.WORDS)) { + return set.not ? '\\W' : '\\w'; + } + // Notanychar is only relevant when not nested inside another set token + if (set.not && isSameSet(set.set, sets.NOTANYCHAR)) { + return '.'; + } + if (isSameSet(set.set, sets.WHITESPACE)) { return set.not ? '\\S' : '\\s'; } let tokenString = ''; - for (let i = 0; i < len; i++) { + for (let i = 0; i < set.set.length; i++) { const subset = set.set[i]; tokenString += writeSetToken(subset); }