From 2978536634fd783d0bc13449e4f5a2c6387d67a1 Mon Sep 17 00:00:00 2001 From: Richard Ainger Date: Mon, 6 Mar 2023 16:22:33 +1000 Subject: [PATCH 1/4] fix: fixed issues handling empty keys + separator characters in the key --- __tests__/order.test.ts | 104 +++++++++++++++++++++++++++++++++++----- __tests__/parse.test.ts | 60 +++++++++++++++++++++++ package.json | 3 +- src/order.ts | 42 +++++++++++++--- src/parse.ts | 16 ++++++- yarn.lock | 5 ++ 6 files changed, 208 insertions(+), 22 deletions(-) diff --git a/__tests__/order.test.ts b/__tests__/order.test.ts index 38a2425..fdcc1c0 100644 --- a/__tests__/order.test.ts +++ b/__tests__/order.test.ts @@ -6,10 +6,11 @@ describe('order()', () => { const expectObject = ( obj: T, map: PropertyMap | null, - res: T - ) => expect(order(obj, map, '.')).toEqual(res); + res: string + ) => expect(JSON.stringify(order(obj, map, '.'))).toBe(res); - it('returns nothing for a blank JSON string', () => expectObject({}, {}, {})); + it('returns nothing for a blank JSON string', () => + expectObject({}, {}, '{}')); it('throws error if separator is an empty string', () => { expect(() => order({}, {}, '')).toThrowError( @@ -18,36 +19,36 @@ describe('order()', () => { }); it('ignores properties not found in source', () => - expectObject({}, {$: ['a']}, {})); + expectObject({}, {$: ['a']}, '{}')); it('returns regular json string if map is undefined', () => - expectObject({a: '1', b: '2'}, null, {a: '1', b: '2'})); + expectObject({a: '1', b: '2'}, null, '{"a":"1","b":"2"}')); it('ignores properties not found in map', () => - expectObject({a: '1', b: '2'}, {$: ['b']}, {b: '2'})); + expectObject({a: '1', b: '2'}, {$: ['b']}, '{"b":"2"}')); it('returns first level object properties in order', () => - expectObject({a: 2, b: 1}, {$: ['b', 'a']}, {b: 1, a: 2})); + expectObject({a: 2, b: 1}, {$: ['b', 'a']}, '{"b":1,"a":2}')); it('returns first level array value in order', () => - expectObject({a: ['2', 1, true]}, {$: ['a']}, {a: ['2', 1, true]})); + expectObject({a: ['2', 1, true]}, {$: ['a']}, '{"a":["2",1,true]}')); it('returns nested [array] > [object] properties in expected order', () => expectObject( {a: [1, {c: '3', d: '2'}]}, {'$': ['a'], '$.a.1': ['d', 'c']}, - {a: [1, {d: '2', c: '3'}]} + '{"a":[1,{"d":"2","c":"3"}]}' )); it('ignores nested [array] > [object] properties not found in map', () => expectObject( {a: [1, {b: 2, c: 3}, 4]}, {'$': ['a'], '$.a.1': ['c']}, - {a: [1, {c: 3}, 4]} + '{"a":[1,{"c":3},4]}' )); it('ignores nested [array] > [object] properties not found in map', () => - expectObject({a: [1, {b: 2, c: 3}, 4]}, {$: ['a']}, {a: [1, {}, 4]})); + expectObject({a: [1, {b: 2, c: 3}, 4]}, {$: ['a']}, '{"a":[1,{},4]}')); it('handles multi-character prefix', () => { expect( @@ -127,7 +128,7 @@ describe('order()', () => { '$.a.e': ['g', 'f'], '$.a.b': ['d', 'c'], }, - {i: 7, a: {e: {g: 5, f: 4}, h: 6, b: {d: 4, c: 3}}} + '{"i":7,"a":{"e":{"g":5,"f":4},"h":6,"b":{"d":4,"c":3}}}' )); it('returns nested [object] > [array] > [object] > [array] > [object] properties in expected order', () => @@ -161,6 +162,83 @@ describe('order()', () => { '$.a.b.1.d.0': ['f', 'e'], '$.a.b.1.d.0.f': ['h', 'g'], }, - {i: 7, a: {b: [8, {d: [{f: {h: 'h', g: true}, e: 12}, 10], c: 9}, 11]}} + '{"i":7,"a":{"b":[8,{"d":[{"f":{"h":"h","g":true},"e":12},10],"c":9},11]}}' )); + + it('handles keys with no name', () => { + expectObject( + { + '': { + b: 'str', + a: 'str', + c: 'str', + }, + }, + { + '$': [''], + '$.': ['c', 'b', 'a'], + }, + '{"":{"c":"str","b":"str","a":"str"}}' + ); + }); + + it('unescapes slashes as well as the separator when it exists in the map', () => { + expectObject( + { + '.a': { + b: {t: 'str'}, + c: {u: 'str'}, + a: {s: 'str'}, + }, + '\\': { + a: {v: 'str'}, + }, + '\\.': { + a: {w: 'str'}, + b: {x: 'str'}, + }, + '.': { + b: {y: 'str'}, + a: {z: 'str'}, + }, + }, + { + '$': ['.', '\\.', '\\', '.a'], + '$.\\.': ['a', 'b'], + '$.\\..a': ['z'], + '$.\\..b': ['y'], + '$.\\\\\\.': ['b', 'a'], + '$.\\\\\\..b': ['x'], + '$.\\\\\\..a': ['w'], + '$.\\\\': ['a'], + '$.\\\\.a': ['v'], + '$.\\.a': ['c', 'b', 'a'], + '$.\\.a.c': ['u'], + '$.\\.a.b': ['t'], + '$.\\.a.a': ['s'], + }, + '{".":{"a":{"z":"str"},"b":{"y":"str"}},' + + '"\\\\.":{"b":{"x":"str"},"a":{"w":"str"}},' + + '"\\\\":{"a":{"v":"str"}},' + + '".a":{"c":{"u":"str"},"b":{"t":"str"},"a":{"s":"str"}}}' + ); + }); + + it('numeric key order defined in map is lost', () => { + // Numeric keys aren't ordered per map but instead appear first in ascending order. + // See: https://tc39.es/ecma262/#sec-ordinaryownpropertykeys + expectObject( + { + 4: 'str', + a: 'str', + 3: 'str', + b: 'str', + 2: 'str', + }, + { + $: ['a', '4', 'b', '3', '2'], + }, + '{"2":"str","3":"str","4":"str","a":"str","b":"str"}' + ); + }); }); diff --git a/__tests__/parse.test.ts b/__tests__/parse.test.ts index 3ddb847..8c9d2ce 100644 --- a/__tests__/parse.test.ts +++ b/__tests__/parse.test.ts @@ -220,4 +220,64 @@ describe('parse ', () => { expectMap(input, map); }); + + it('handles keys with no name', () => { + const input = ` + { + "": { + "c": "str", + "b": "str", + "a": "str" + } + }`; + + const map = { + '$': [''], + '$.': ['c', 'b', 'a'], + }; + + expectMap(input, map); + }); + + it('escapes slashes as well as the separator when it exists in the object keys', () => { + // slashes in the encoded JSON are double escapes, so "\\\\" is actually equivalent to "\". + const input = ` + { + ".": { + "a": {"z": "str"}, + "b": {"y": "str"} + }, + "\\\\.": { + "b": {"x": "str"}, + "a": {"w": "str"} + }, + "\\\\": { + "a": {"v": "str"} + }, + ".a": { + "c": {"u": "str"}, + "b": {"t": "str"}, + "a": {"s": "str"} + } + }`; + + // all below slashes are escaped so "\\" is actually equivalent to "\". + const map = { + '$': ['.', '\\.', '\\', '.a'], + '$.\\.': ['a', 'b'], + '$.\\..a': ['z'], + '$.\\..b': ['y'], + '$.\\\\\\.': ['b', 'a'], + '$.\\\\\\..b': ['x'], + '$.\\\\\\..a': ['w'], + '$.\\\\': ['a'], + '$.\\\\.a': ['v'], + '$.\\.a': ['c', 'b', 'a'], + '$.\\.a.c': ['u'], + '$.\\.a.b': ['t'], + '$.\\.a.a': ['s'], + }; + + expectMap(input, map); + }); }); diff --git a/package.json b/package.json index d2752a6..967468e 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "test:watch": "jest --watch", "test:ci": "jest --ci --coverage", "compile": "tsc -p tsconfig.build.json", - "lint": "eslint **/*.{t,j}s", + "lint": "eslint \"**/*.{t,j}s\"", "lint:fix": "yarn lint --fix", "semantic-release": "semantic-release" }, @@ -65,6 +65,7 @@ "typescript": "4.1.3" }, "dependencies": { + "escape-string-regexp": "4", "lodash.clonedeep": "^4.5.0" } } diff --git a/src/order.ts b/src/order.ts index 05b629c..30e7e60 100644 --- a/src/order.ts +++ b/src/order.ts @@ -8,6 +8,36 @@ interface GetResult { value: object; } +const splitKey = (key: string, separator: string): Array => { + const parts: Array = []; + let currentPart = ''; + let isLiteral = false; + + for (let index = 0; index < key.length; index++) { + const character = key[index]; + + if (isLiteral) { + currentPart += character; + isLiteral = false; + } else if (character === '\\') { + isLiteral = true; + } else if ( + character === separator[0] && + key.substr(index, separator.length) === separator + ) { + parts.push(currentPart); + currentPart = ''; + index += separator.length - 1; + } else { + currentPart += character; + } + } + + parts.push(currentPart); + + return parts; +}; + const getProperty = ( obj: object, key: string, @@ -15,9 +45,8 @@ const getProperty = ( ): GetResult => { let exists = true; - const value = key - .split(separator) - .filter((s) => s.length > 0) + const value = splitKey(key, separator) + .slice(1) .reduce((o: object, x: string) => { exists = o && o.hasOwnProperty(x); @@ -37,9 +66,8 @@ const setProperty = ( value: object, separator: string ) => { - key - .split(separator) - .filter((s) => s.length > 0) + splitKey(key, separator) + .slice(1) .reduce((o: object, x: string, idx: number, src: Array): object => { if (idx === src.length - 1) { const valueToSet = Array.isArray(value) @@ -79,6 +107,8 @@ const order = ( ): T => { if (separator.length < 1) { throw new Error('Separator should not be an empty string.'); + } else if (separator === '/') { + throw new Error('Separator cannot be "/".'); } if (!map) { diff --git a/src/parse.ts b/src/parse.ts index 544a7f8..faa3358 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -1,7 +1,17 @@ /* eslint-disable @typescript-eslint/ban-types */ +import escapeStringRegexp from 'escape-string-regexp'; import {OrderedParseResult, PropertyMap} from './models'; +const escapeKey = (key: string, separator: string): string => { + const stringsToEscape = ['\\', separator]; + const pattern = stringsToEscape + .map((string) => escapeStringRegexp(string)) + .join('|'); + + return key.replace(new RegExp(`(${pattern})`, 'g'), '\\$1'); +}; + const traverseObject = ( obj: T, map: PropertyMap, @@ -26,7 +36,7 @@ const traverseObject = ( traverseObject( value, map, - `${parentKey}${separator}${childKey}`, + `${parentKey}${separator}${escapeKey(childKey, separator)}`, separator ); } @@ -52,12 +62,14 @@ const parse = ( if (separator.length < 1) { throw new Error('Separator should not be an empty string.'); + } else if (separator === '/') { + throw new Error('Separator cannot be "/".'); } const obj: T = JSON.parse(jsonString); const map = {}; - traverseObject(obj, map, prefix, separator); + traverseObject(obj, map, escapeKey(prefix, separator), separator); return { object: obj, map, diff --git a/yarn.lock b/yarn.lock index 16652c8..e97232a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2540,6 +2540,11 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +escape-string-regexp@4: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" From 39fd00d721155165f97e9f4633e6f589aa465a7c Mon Sep 17 00:00:00 2001 From: Richard Ainger Date: Mon, 6 Mar 2023 17:27:04 +1000 Subject: [PATCH 2/4] fix: fixed incorrect character was disallowed as a separator --- __tests__/order.test.ts | 4 ++++ __tests__/parse.test.ts | 6 ++++++ src/order.ts | 4 ++-- src/parse.ts | 4 ++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/__tests__/order.test.ts b/__tests__/order.test.ts index fdcc1c0..82f737d 100644 --- a/__tests__/order.test.ts +++ b/__tests__/order.test.ts @@ -18,6 +18,10 @@ describe('order()', () => { ); }); + it('throws error if separator is a slash', () => { + expect(() => order({}, {}, '\\')).toThrowError('Separator cannot be "\\".'); + }); + it('ignores properties not found in source', () => expectObject({}, {$: ['a']}, '{}')); diff --git a/__tests__/parse.test.ts b/__tests__/parse.test.ts index 8c9d2ce..be5872d 100644 --- a/__tests__/parse.test.ts +++ b/__tests__/parse.test.ts @@ -19,6 +19,12 @@ describe('parse ', () => { ); }); + it('throws error if separator is a slash', () => { + expect(() => parse('', '$', '\\')).toThrowError( + 'Separator cannot be "\\".' + ); + }); + it('handles top level values for of primitive types', () => { const input = ` { diff --git a/src/order.ts b/src/order.ts index 30e7e60..b979240 100644 --- a/src/order.ts +++ b/src/order.ts @@ -107,8 +107,8 @@ const order = ( ): T => { if (separator.length < 1) { throw new Error('Separator should not be an empty string.'); - } else if (separator === '/') { - throw new Error('Separator cannot be "/".'); + } else if (separator === '\\') { + throw new Error('Separator cannot be "\\".'); } if (!map) { diff --git a/src/parse.ts b/src/parse.ts index faa3358..7e70e7a 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -62,8 +62,8 @@ const parse = ( if (separator.length < 1) { throw new Error('Separator should not be an empty string.'); - } else if (separator === '/') { - throw new Error('Separator cannot be "/".'); + } else if (separator === '\\') { + throw new Error('Separator cannot be "\\".'); } const obj: T = JSON.parse(jsonString); From 9a8ed10daa448a4221db420b863e849e5f04975f Mon Sep 17 00:00:00 2001 From: Richard Ainger Date: Tue, 7 Mar 2023 14:25:08 +1000 Subject: [PATCH 3/4] fix: fixed issue handling escape sequences when ordering nested objects --- __tests__/key.test.ts | 80 +++++++++++++++++++++++++++++++++++++++++ __tests__/order.test.ts | 22 +++++++++++- src/key.ts | 45 +++++++++++++++++++++++ src/order.ts | 33 ++--------------- src/parse.ts | 11 +----- 5 files changed, 149 insertions(+), 42 deletions(-) create mode 100644 __tests__/key.test.ts create mode 100644 src/key.ts diff --git a/__tests__/key.test.ts b/__tests__/key.test.ts new file mode 100644 index 0000000..c036731 --- /dev/null +++ b/__tests__/key.test.ts @@ -0,0 +1,80 @@ +import {escapeKey, splitKey} from '../src/key'; + +describe('escapeKey()', () => { + it.each([ + [ + 'key does not contain a separator or slash', + 'object_property_name', + '~', + 'object_property_name', + ], + [ + 'key contains the separator character', + 'object~property~name', + '~', + 'object\\~property\\~name', + ], + [ + 'key contains the separator character, using a multi-character separator', + 'object$$property$$name', + '$$', + 'object\\$$property\\$$name', + ], + [ + 'key contains the escape character', + 'object\\property\\name', + '~', + 'object\\\\property\\\\name', + ], + ])( + 'handles when %s', + (description: string, key: string, separator: string, expected: string) => { + expect(escapeKey(key, separator)).toEqual(expected); + } + ); +}); + +describe('splitKey()', () => { + it.each([ + [ + 'key does not contain any escape sequences', + 'object~property~name', + '~', + ['object', 'property', 'name'], + ], + [ + 'key does not contain any escape sequences, using a multi-character separator', + 'object$$property$$name', + '$$', + ['object', 'property', 'name'], + ], + [ + 'key contains an escaped separator', + 'object~property\\~name', + '~', + ['object', 'property~name'], + ], + [ + 'keys contains an escaped separator, using a multi-character separator', + 'object$$property\\$$name', + '$$', + ['object', 'property$$name'], + ], + [ + 'it contains an escaped slash', + 'object~property\\\\name', + '~', + ['object', 'property\\name'], + ], + ])( + 'handles when %s', + ( + description: string, + key: string, + separator: string, + expected: Array + ) => { + expect(splitKey(key, separator)).toEqual(expected); + } + ); +}); diff --git a/__tests__/order.test.ts b/__tests__/order.test.ts index 82f737d..28aee45 100644 --- a/__tests__/order.test.ts +++ b/__tests__/order.test.ts @@ -186,7 +186,7 @@ describe('order()', () => { ); }); - it('unescapes slashes as well as the separator when it exists in the map', () => { + it('handles escape sequences in the object', () => { expectObject( { '.a': { @@ -228,6 +228,26 @@ describe('order()', () => { ); }); + it('handles escape sequences in child properties of the object', () => { + expectObject( + { + property: { + '..': {'.': 4, '..': 3}, + '.': {'..': 0, '...': 2, '.': 1}, + '...': {'.': 5}, + }, + }, + { + '$': ['property'], + '$.property': ['.', '..', '...'], + '$.property.\\.': ['..', '.', '...'], + '$.property.\\.\\.': ['..', '.'], + '$.property.\\.\\.\\.': ['.'], + }, + '{"property":{".":{"..":0,".":1,"...":2},"..":{"..":3,".":4},"...":{".":5}}}' + ); + }); + it('numeric key order defined in map is lost', () => { // Numeric keys aren't ordered per map but instead appear first in ascending order. // See: https://tc39.es/ecma262/#sec-ordinaryownpropertykeys diff --git a/src/key.ts b/src/key.ts new file mode 100644 index 0000000..b948902 --- /dev/null +++ b/src/key.ts @@ -0,0 +1,45 @@ +import escapeStringRegexp from 'escape-string-regexp'; + +export const escapeKey = (key: string, separator: string): string => { + const stringsToEscape = ['\\', separator]; + const pattern = stringsToEscape + .map((string) => escapeStringRegexp(string)) + .join('|'); + + return key.replace(new RegExp(`(${pattern})`, 'g'), '\\$1'); +}; + +export const splitKey = (key: string, separator: string): Array => { + // if key doesn't have any escape sequence avoid iterating through the characters. + if (key.indexOf('\\') < 0) { + return key.split(separator); + } + + const parts: Array = []; + let currentPart = ''; + let isLiteral = false; + + for (let index = 0; index < key.length; index++) { + const character = key[index]; + + if (isLiteral) { + currentPart += character; + isLiteral = false; + } else if (character === '\\') { + isLiteral = true; + } else if ( + character === separator[0] && + key.substr(index, separator.length) === separator + ) { + parts.push(currentPart); + currentPart = ''; + index += separator.length - 1; + } else { + currentPart += character; + } + } + + parts.push(currentPart); + + return parts; +}; diff --git a/src/order.ts b/src/order.ts index b979240..937e610 100644 --- a/src/order.ts +++ b/src/order.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/ban-types */ import clonedeep from 'lodash.clonedeep'; +import {escapeKey, splitKey} from './key'; import {PropertyMap} from './models'; interface GetResult { @@ -8,36 +9,6 @@ interface GetResult { value: object; } -const splitKey = (key: string, separator: string): Array => { - const parts: Array = []; - let currentPart = ''; - let isLiteral = false; - - for (let index = 0; index < key.length; index++) { - const character = key[index]; - - if (isLiteral) { - currentPart += character; - isLiteral = false; - } else if (character === '\\') { - isLiteral = true; - } else if ( - character === separator[0] && - key.substr(index, separator.length) === separator - ) { - parts.push(currentPart); - currentPart = ''; - index += separator.length - 1; - } else { - currentPart += character; - } - } - - parts.push(currentPart); - - return parts; -}; - const getProperty = ( obj: object, key: string, @@ -138,7 +109,7 @@ const order = ( copyProperty( sourceObject, resultObject, - `${parentKey}${separator}${key}`, + `${parentKey}${separator}${escapeKey(key, separator)}`, separator ) ); diff --git a/src/parse.ts b/src/parse.ts index 7e70e7a..d5eac2c 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -1,17 +1,8 @@ /* eslint-disable @typescript-eslint/ban-types */ -import escapeStringRegexp from 'escape-string-regexp'; +import {escapeKey} from './key'; import {OrderedParseResult, PropertyMap} from './models'; -const escapeKey = (key: string, separator: string): string => { - const stringsToEscape = ['\\', separator]; - const pattern = stringsToEscape - .map((string) => escapeStringRegexp(string)) - .join('|'); - - return key.replace(new RegExp(`(${pattern})`, 'g'), '\\$1'); -}; - const traverseObject = ( obj: T, map: PropertyMap, From 530d308cc595d7925b20ecbdddbea6430ac5e7bb Mon Sep 17 00:00:00 2001 From: Richard Ainger Date: Thu, 23 Mar 2023 15:35:47 +1000 Subject: [PATCH 4/4] fix: fixed error being thrown when null value encountered during parsing a JSON string --- __tests__/parse.test.ts | 20 ++++++++++++++++++++ __tests__/stringify.test.ts | 18 ++++++++++++++++++ package.json | 2 +- src/parse.ts | 2 +- yarn.lock | 10 +++++----- 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/__tests__/parse.test.ts b/__tests__/parse.test.ts index be5872d..b4d4555 100644 --- a/__tests__/parse.test.ts +++ b/__tests__/parse.test.ts @@ -286,4 +286,24 @@ describe('parse ', () => { expectMap(input, map); }); + + it('handles keys with different types of values', () => { + const input = ` + { + "a": "a", + "b": 2, + "c": 2.3, + "d": true, + "e": false, + "f": null, + "g": {}, + "h": [] + }`; + + const map = { + $: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], + }; + + expectMap(input, map); + }); }); diff --git a/__tests__/stringify.test.ts b/__tests__/stringify.test.ts index 44b50ac..89b8ac4 100644 --- a/__tests__/stringify.test.ts +++ b/__tests__/stringify.test.ts @@ -163,4 +163,22 @@ describe('stringify ', () => { }, '{"i":7,"a":{"b":[8,{"d":[{"f":{"h":"h","g":true},"e":12},10],"c":9},11]}}' )); + + it('handles keys with different types of values', () => + expectString( + { + a: 'a', + b: 2, + c: 2.3, + d: true, + e: false, + f: null, + g: {}, + h: [], + }, + { + $: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], + }, + '{"a":"a","b":2,"c":2.3,"d":true,"e":false,"f":null,"g":{},"h":[]}' + )); }); diff --git a/package.json b/package.json index 967468e..86d5713 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "typescript": "4.1.3" }, "dependencies": { - "escape-string-regexp": "4", + "escape-string-regexp": "^4.0.0", "lodash.clonedeep": "^4.5.0" } } diff --git a/src/parse.ts b/src/parse.ts index d5eac2c..1d12699 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -23,7 +23,7 @@ const traverseObject = ( childKeys.forEach((childKey) => { const value = obj[childKey]; - if (typeof value === 'object') { + if (value !== null && typeof value === 'object') { traverseObject( value, map, diff --git a/yarn.lock b/yarn.lock index e97232a..75beecd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2540,11 +2540,6 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" -escape-string-regexp@4: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2555,6 +2550,11 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + escodegen@^1.14.1: version "1.14.3" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"