From d3ceb6730da09b25dc0ad2ed6d2efa0d82c1e5a6 Mon Sep 17 00:00:00 2001 From: cphil Date: Thu, 13 Aug 2020 16:36:52 -0700 Subject: [PATCH 01/21] Fix Issue #9 --- lib/index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index 5cb94f6..3745ce1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -29,7 +29,7 @@ function arrayToList(useSpace, array, formatter) { sql += useSpace ? ' (' : '('; for (var i = 0; i < array.length; i++) { - sql += (i === 0 ? '' : ', ') + formatter(array[i]); + sql += (i === 0 ? '' : ', ') + formatter(array[i]); } sql += ')'; @@ -92,7 +92,9 @@ function quoteLiteral(value) { var literal = null; var explicitCast = null; - if (value === undefined || value === null) { + if (typeof (value) == 'number') { + return value; + } else if (value === undefined || value === null) { return 'NULL'; } else if (value === false) { return "'f'"; @@ -204,7 +206,7 @@ function formatWithArray(fmt, parameters) { re += '])'; re = new RegExp(re, 'g'); - return fmt.replace(re, function(_, type) { + return fmt.replace(re, function (_, type) { if (type === '%') { return '%'; From ff49040e142b0f3fb0f1b35e619a57e0ebe0d447 Mon Sep 17 00:00:00 2001 From: cphil Date: Thu, 13 Aug 2020 16:55:31 -0700 Subject: [PATCH 02/21] Fix unit tests for #9 --- test/index.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/index.js b/test/index.js index 8e772e1..c224f1b 100644 --- a/test/index.js +++ b/test/index.js @@ -97,7 +97,7 @@ describe('format(fmt, ...)', function() { }); it('should format array of array as a literal', function() { - format('%L', testNestedArray).should.equal("('1', '2'), ('3', '4'), ('5', '6')"); + format('%L', testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); }); it('should format literal using position field', function() { @@ -166,7 +166,7 @@ describe('format.withArray(fmt, args)', function() { }); it('should format array of array as a literal', function() { - format.withArray('%L', [testNestedArray]).should.equal("('1', '2'), ('3', '4'), ('5', '6')"); + format.withArray('%L', [testNestedArray]).should.equal("(1, 2), (3, 4), (5, 6)"); }); }); }); @@ -257,14 +257,14 @@ describe('format.literal(val)', function() { it('should quote', function() { format.literal(true).should.equal("'t'"); format.literal(false).should.equal("'f'"); - format.literal(0).should.equal("'0'"); - format.literal(15).should.equal("'15'"); - format.literal(-15).should.equal("'-15'"); - format.literal(45.13).should.equal("'45.13'"); - format.literal(-45.13).should.equal("'-45.13'"); + format.literal(0).should.equal(0); + format.literal(15).should.equal(15); + format.literal(-15).should.equal(-15); + format.literal(45.13).should.equal(45.13); + format.literal(-45.13).should.equal(-45.13); format.literal('hello world').should.equal("'hello world'"); - format.literal(testArray).should.equal("'abc','1','t',NULL,'2012-12-14 13:06:43.152+00'"); - format.literal(testNestedArray).should.equal("('1', '2'), ('3', '4'), ('5', '6')"); + format.literal(testArray).should.equal("'abc',1,'t',NULL,'2012-12-14 13:06:43.152+00'"); + format.literal(testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); format.literal(testDate).should.equal("'2012-12-14 13:06:43.152+00'"); format.literal(testObject).should.equal("'{\"a\":1,\"b\":2}'::jsonb"); }); From d56ef15558f970dcf2ebdf68f16a2f20bd6292e1 Mon Sep 17 00:00:00 2001 From: cphil Date: Thu, 13 Aug 2020 17:19:03 -0700 Subject: [PATCH 03/21] Sanitize number value --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 3745ce1..7cc848b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -93,7 +93,7 @@ function quoteLiteral(value) { var explicitCast = null; if (typeof (value) == 'number') { - return value; + return Number(value); } else if (value === undefined || value === null) { return 'NULL'; } else if (value === false) { From b904a3f9874b69a6a3f671808246abf456c04c61 Mon Sep 17 00:00:00 2001 From: cphil Date: Sun, 16 Aug 2020 08:15:15 -0700 Subject: [PATCH 04/21] Add Special Case Numbers Add Cases / Update Unit Test --- lib/index.js | 14 +++-- test/index.js | 140 +++++++++++++++++++++++++------------------------- 2 files changed, 81 insertions(+), 73 deletions(-) diff --git a/lib/index.js b/lib/index.js index 7cc848b..a1107da 100644 --- a/lib/index.js +++ b/lib/index.js @@ -92,10 +92,18 @@ function quoteLiteral(value) { var literal = null; var explicitCast = null; - if (typeof (value) == 'number') { - return Number(value); - } else if (value === undefined || value === null) { + if (value === undefined || value === null) { return 'NULL'; + } else if (typeof value === 'bigint') { + return BigInt(value); + } else if (value === Number.POSITIVE_INFINITY) { + return "'Infinity'"; + } else if (value === Number.NEGATIVE_INFINITY) { + return "'-Infinity'"; + } else if (Number.isNaN(value)) { + return "'NaN'"; + } else if (typeof value === 'number') {//Test must be AFTER other special case number tests + return Number(value); } else if (value === false) { return "'f'"; } else if (value === true) { diff --git a/test/index.js b/test/index.js index c224f1b..80e21fa 100644 --- a/test/index.js +++ b/test/index.js @@ -6,23 +6,23 @@ var format = require(__dirname + '/../lib'); var should = require('should'); var testDate = new Date(Date.UTC(2012, 11, 14, 13, 6, 43, 152)); -var testArray = [ 'abc', 1, true, null, testDate ]; -var testIdentArray = [ 'abc', 'AbC', 1, true, testDate ]; +var testArray = ['abc', 1, true, null, testDate, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, 1n]; +var testIdentArray = ['abc', 'AbC', 1, true, testDate]; var testObject = { a: 1, b: 2 }; -var testNestedArray = [ [1, 2], [3, 4], [5, 6] ]; +var testNestedArray = [[1, 2], [3, 4], [5, 6]]; -describe('format(fmt, ...)', function() { - describe('%s', function() { - it('should format as a simple string', function() { +describe('format(fmt, ...)', function () { + describe('%s', function () { + it('should format as a simple string', function () { format('some %s here', 'thing').should.equal('some thing here'); format('some %s thing %s', 'long', 'here').should.equal('some long thing here'); }); - it('should format array of array as simple string', function() { + it('should format array of array as simple string', function () { format('many %s %s', 'things', testNestedArray).should.equal('many things (1, 2), (3, 4), (5, 6)'); }); - it('should format string using position field', function() { + it('should format string using position field', function () { format('some %1$s', 'thing').should.equal('some thing'); format('some %1$s %1$s', 'thing').should.equal('some thing thing'); format('some %1$s %s', 'thing', 'again').should.equal('some thing again'); @@ -31,45 +31,45 @@ describe('format(fmt, ...)', function() { format('some %1$s %2$s %s %1$s', 'thing', 'again', 'some').should.equal('some thing again some thing'); }); - it('should not format string using position 0', function() { - (function() { + it('should not format string using position 0', function () { + (function () { format('some %0$s', 'thing'); }).should.throw(Error); }); - it('should not format string using position field with too few arguments', function() { - (function() { + it('should not format string using position field with too few arguments', function () { + (function () { format('some %2$s', 'thing'); }).should.throw(Error); }); }); - describe('%%', function() { - it('should format as %', function() { + describe('%%', function () { + it('should format as %', function () { format('some %%', 'thing').should.equal('some %'); }); - it('should not eat args', function() { + it('should not eat args', function () { format('just %% a %s', 'test').should.equal('just % a test'); }); - it('should not format % using position field', function() { + it('should not format % using position field', function () { format('%1$%', 'thing').should.equal('%1$%'); }); }); - describe('%I', function() { - it('should format as an identifier', function() { + describe('%I', function () { + it('should format as an identifier', function () { format('some %I', 'foo/bar/baz').should.equal('some "foo/bar/baz"'); }); - it('should not format array of array as an identifier', function() { - (function() { + it('should not format array of array as an identifier', function () { + (function () { format('many %I %I', 'foo/bar/baz', testNestedArray); }).should.throw(Error); }); - it('should format identifier using position field', function() { + it('should format identifier using position field', function () { format('some %1$I', 'thing').should.equal('some thing'); format('some %1$I %1$I', 'thing').should.equal('some thing thing'); format('some %1$I %I', 'thing', 'again').should.equal('some thing again'); @@ -78,29 +78,29 @@ describe('format(fmt, ...)', function() { format('some %1$I %2$I %I %1$I', 'thing', 'again', 'huh').should.equal('some thing again huh thing'); }); - it('should not format identifier using position 0', function() { - (function() { + it('should not format identifier using position 0', function () { + (function () { format('some %0$I', 'thing'); }).should.throw(Error); }); - it('should not format identifier using position field with too few arguments', function() { - (function() { + it('should not format identifier using position field with too few arguments', function () { + (function () { format('some %2$I', 'thing'); }).should.throw(Error); }); }); - describe('%L', function() { - it('should format as a literal', function() { + describe('%L', function () { + it('should format as a literal', function () { format('%L', "Tobi's").should.equal("'Tobi''s'"); }); - it('should format array of array as a literal', function() { + it('should format array of array as a literal', function () { format('%L', testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); }); - it('should format literal using position field', function() { + it('should format literal using position field', function () { format('some %1$L', 'thing').should.equal("some 'thing'"); format('some %1$L %1$L', 'thing').should.equal("some 'thing' 'thing'"); format('some %1$L %L', 'thing', 'again').should.equal("some 'thing' 'again'"); @@ -109,70 +109,70 @@ describe('format(fmt, ...)', function() { format('some %1$L %2$L %L %1$L', 'thing', 'again', 'some').should.equal("some 'thing' 'again' 'some' 'thing'"); }); - it('should not format literal using position 0', function() { - (function() { + it('should not format literal using position 0', function () { + (function () { format('some %0$L', 'thing'); }).should.throw(Error); }); - it('should not format literal using position field with too few arguments', function() { - (function() { + it('should not format literal using position field with too few arguments', function () { + (function () { format('some %2$L', 'thing'); }).should.throw(Error); }); }); }); -describe('format.withArray(fmt, args)', function() { - describe('%s', function() { - it('should format as a simple string', function() { - format.withArray('some %s here', [ 'thing' ]).should.equal('some thing here'); - format.withArray('some %s thing %s', [ 'long', 'here' ]).should.equal('some long thing here'); +describe('format.withArray(fmt, args)', function () { + describe('%s', function () { + it('should format as a simple string', function () { + format.withArray('some %s here', ['thing']).should.equal('some thing here'); + format.withArray('some %s thing %s', ['long', 'here']).should.equal('some long thing here'); }); - it('should format array of array as simple string', function() { + it('should format array of array as simple string', function () { format.withArray('many %s %s', ['things', testNestedArray]).should.equal('many things (1, 2), (3, 4), (5, 6)'); }); }); - describe('%%', function() { - it('should format as %', function() { - format.withArray('some %%', [ 'thing' ]).should.equal('some %'); + describe('%%', function () { + it('should format as %', function () { + format.withArray('some %%', ['thing']).should.equal('some %'); }); - it('should not eat args', function() { - format.withArray('just %% a %s', [ 'test' ]).should.equal('just % a test'); - format.withArray('just %% a %s %s %s', [ 'test', 'again', 'and again' ]).should.equal('just % a test again and again'); + it('should not eat args', function () { + format.withArray('just %% a %s', ['test']).should.equal('just % a test'); + format.withArray('just %% a %s %s %s', ['test', 'again', 'and again']).should.equal('just % a test again and again'); }); }); - describe('%I', function() { - it('should format as an identifier', function() { - format.withArray('some %I', [ 'foo/bar/baz' ]).should.equal('some "foo/bar/baz"'); - format.withArray('some %I and %I', [ 'foo/bar/baz', '#hey' ]).should.equal('some "foo/bar/baz" and "#hey"'); + describe('%I', function () { + it('should format as an identifier', function () { + format.withArray('some %I', ['foo/bar/baz']).should.equal('some "foo/bar/baz"'); + format.withArray('some %I and %I', ['foo/bar/baz', '#hey']).should.equal('some "foo/bar/baz" and "#hey"'); }); - it('should not format array of array as an identifier', function() { - (function() { + it('should not format array of array as an identifier', function () { + (function () { format.withArray('many %I %I', ['foo/bar/baz', testNestedArray]); }).should.throw(Error); }); }); - describe('%L', function() { - it('should format as a literal', function() { - format.withArray('%L', [ "Tobi's" ]).should.equal("'Tobi''s'"); - format.withArray('%L %L', [ "Tobi's", "birthday" ]).should.equal("'Tobi''s' 'birthday'"); + describe('%L', function () { + it('should format as a literal', function () { + format.withArray('%L', ["Tobi's"]).should.equal("'Tobi''s'"); + format.withArray('%L %L', ["Tobi's", "birthday"]).should.equal("'Tobi''s' 'birthday'"); }); - it('should format array of array as a literal', function() { + it('should format array of array as a literal', function () { format.withArray('%L', [testNestedArray]).should.equal("(1, 2), (3, 4), (5, 6)"); }); }); }); -describe('format.string(val)', function() { - it('should coerce to a string', function() { +describe('format.string(val)', function () { + it('should coerce to a string', function () { format.string(undefined).should.equal(''); format.string(null).should.equal(''); format.string(true).should.equal('t'); @@ -183,15 +183,15 @@ describe('format.string(val)', function() { format.string(45.13).should.equal('45.13'); format.string(-45.13).should.equal('-45.13'); format.string('something').should.equal('something'); - format.string(testArray).should.equal('abc,1,t,2012-12-14 13:06:43.152+00'); + format.string(testArray).should.equal('abc,1,t,2012-12-14 13:06:43.152+00,-Infinity,Infinity,NaN,1'); format.string(testNestedArray).should.equal('(1, 2), (3, 4), (5, 6)'); format.string(testDate).should.equal('2012-12-14 13:06:43.152+00'); format.string(testObject).should.equal('{"a":1,"b":2}'); }); }); -describe('format.ident(val)', function() { - it('should quote when necessary', function() { +describe('format.ident(val)', function () { + it('should quote when necessary', function () { format.ident('foo').should.equal('foo'); format.ident('_foo').should.equal('_foo'); format.ident('_foo_bar$baz').should.equal('_foo_bar$baz'); @@ -199,13 +199,13 @@ describe('format.ident(val)', function() { format.ident('test."some".stuff').should.equal('"test.""some"".stuff"'); }); - it('should quote reserved words', function() { + it('should quote reserved words', function () { format.ident('desc').should.equal('"desc"'); format.ident('join').should.equal('"join"'); format.ident('cross').should.equal('"cross"'); }); - it('should quote', function() { + it('should quote', function () { format.ident(true).should.equal('"t"'); format.ident(false).should.equal('"f"'); format.ident(0).should.equal('"0"'); @@ -214,7 +214,7 @@ describe('format.ident(val)', function() { format.ident(45.13).should.equal('"45.13"'); format.ident(-45.13).should.equal('"-45.13"'); format.ident(testIdentArray).should.equal('abc,"AbC","1","t","2012-12-14 13:06:43.152+00"'); - (function() { + (function () { format.ident(testNestedArray) }).should.throw(Error); format.ident(testDate).should.equal('"2012-12-14 13:06:43.152+00"'); @@ -248,13 +248,13 @@ describe('format.ident(val)', function() { }); }); -describe('format.literal(val)', function() { - it('should return NULL for null', function() { +describe('format.literal(val)', function () { + it('should return NULL for null', function () { format.literal(null).should.equal('NULL'); format.literal(undefined).should.equal('NULL'); }); - it('should quote', function() { + it('should quote', function () { format.literal(true).should.equal("'t'"); format.literal(false).should.equal("'f'"); format.literal(0).should.equal(0); @@ -263,17 +263,17 @@ describe('format.literal(val)', function() { format.literal(45.13).should.equal(45.13); format.literal(-45.13).should.equal(-45.13); format.literal('hello world').should.equal("'hello world'"); - format.literal(testArray).should.equal("'abc',1,'t',NULL,'2012-12-14 13:06:43.152+00'"); + format.literal(testArray).should.equal("'abc',1,'t',NULL,'2012-12-14 13:06:43.152+00','-Infinity','Infinity','NaN',1"); format.literal(testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); format.literal(testDate).should.equal("'2012-12-14 13:06:43.152+00'"); format.literal(testObject).should.equal("'{\"a\":1,\"b\":2}'::jsonb"); }); - it('should format quotes', function() { + it('should format quotes', function () { format.literal("O'Reilly").should.equal("'O''Reilly'"); }); - it('should format backslashes', function() { + it('should format backslashes', function () { format.literal('\\whoop\\').should.equal("E'\\\\whoop\\\\'"); }); }); \ No newline at end of file From badcfea35525c1ec911d6457dd5cc0c345726a11 Mon Sep 17 00:00:00 2001 From: cphil Date: Sun, 16 Aug 2020 08:19:42 -0700 Subject: [PATCH 05/21] Update Readme to reflect PR changes --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8d4592c..6dd176d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Node.js implementation of [PostgreSQL format()](http://www.postgresql.org/docs/9 ```js var format = require('pg-format'); var sql = format('SELECT * FROM %I WHERE my_col = %L %s', 'my_table', 34, 'LIMIT 10'); -console.log(sql); // SELECT * FROM my_table WHERE my_col = '34' LIMIT 10 +console.log(sql); // SELECT * FROM my_table WHERE my_col = 34 LIMIT 10 ``` ## API @@ -28,7 +28,7 @@ You can define where an argument is positioned using ```n$``` where ```n``` is t ```js var format = require('pg-format'); var sql = format('SELECT %1$L, %1$L, %L', 34, 'test'); -console.log(sql); // SELECT '34', '34', 'test' +console.log(sql); // SELECT 34, 34, 'test' ``` ### format.config(cfg) @@ -72,10 +72,10 @@ var myObject = { a: 1, b: 2 }; var myNestedArray = [['a', 1], ['b', 2]]; var sql = format('SELECT * FROM t WHERE c1 IN (%L) AND c2 = %L', myArray, myObject); -console.log(sql); // SELECT * FROM t WHERE c1 IN ('1','2','3') AND c2 = '{"a":1,"b":2}' +console.log(sql); // SELECT * FROM t WHERE c1 IN (1,2,3) AND c2 = '{"a":1,"b":2}' sql = format('INSERT INTO t (name, age) VALUES %L', myNestedArray); -console.log(sql); // INSERT INTO t (name, age) VALUES ('a', '1'), ('b', '2') +console.log(sql); // INSERT INTO t (name, age) VALUES ('a', 1), ('b', 2) ``` ## Testing From 8e7aa48dee67ab7d2ab9738ba6990de06256e33f Mon Sep 17 00:00:00 2001 From: cphil Date: Sun, 23 Aug 2020 18:49:29 -0700 Subject: [PATCH 06/21] Fix / Add to Unit Testing Quote Literal To String --- lib/index.js | 4 ++-- test/index.js | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/index.js b/lib/index.js index a1107da..debd68f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -95,7 +95,7 @@ function quoteLiteral(value) { if (value === undefined || value === null) { return 'NULL'; } else if (typeof value === 'bigint') { - return BigInt(value); + return BigInt(value).toString(); } else if (value === Number.POSITIVE_INFINITY) { return "'Infinity'"; } else if (value === Number.NEGATIVE_INFINITY) { @@ -103,7 +103,7 @@ function quoteLiteral(value) { } else if (Number.isNaN(value)) { return "'NaN'"; } else if (typeof value === 'number') {//Test must be AFTER other special case number tests - return Number(value); + return Number(value).toString(); } else if (value === false) { return "'f'"; } else if (value === true) { diff --git a/test/index.js b/test/index.js index 80e21fa..5e9644c 100644 --- a/test/index.js +++ b/test/index.js @@ -7,7 +7,7 @@ var should = require('should'); var testDate = new Date(Date.UTC(2012, 11, 14, 13, 6, 43, 152)); var testArray = ['abc', 1, true, null, testDate, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, 1n]; -var testIdentArray = ['abc', 'AbC', 1, true, testDate]; +var testIdentArray = ['abc', 'AbC', 1, true, testDate, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, 1n]; var testObject = { a: 1, b: 2 }; var testNestedArray = [[1, 2], [3, 4], [5, 6]]; @@ -213,7 +213,7 @@ describe('format.ident(val)', function () { format.ident(-15).should.equal('"-15"'); format.ident(45.13).should.equal('"45.13"'); format.ident(-45.13).should.equal('"-45.13"'); - format.ident(testIdentArray).should.equal('abc,"AbC","1","t","2012-12-14 13:06:43.152+00"'); + format.ident(testIdentArray).should.equal('abc,"AbC","1","t","2012-12-14 13:06:43.152+00","-Infinity","Infinity","NaN","1"'); (function () { format.ident(testNestedArray) }).should.throw(Error); @@ -257,11 +257,11 @@ describe('format.literal(val)', function () { it('should quote', function () { format.literal(true).should.equal("'t'"); format.literal(false).should.equal("'f'"); - format.literal(0).should.equal(0); - format.literal(15).should.equal(15); - format.literal(-15).should.equal(-15); - format.literal(45.13).should.equal(45.13); - format.literal(-45.13).should.equal(-45.13); + format.literal(0).should.equal('0'); + format.literal(15).should.equal('15'); + format.literal(-15).should.equal('-15'); + format.literal(45.13).should.equal('45.13'); + format.literal(-45.13).should.equal('-45.13'); format.literal('hello world').should.equal("'hello world'"); format.literal(testArray).should.equal("'abc',1,'t',NULL,'2012-12-14 13:06:43.152+00','-Infinity','Infinity','NaN',1"); format.literal(testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); From 871993345b2892db3a2c3396e482d266c24348a9 Mon Sep 17 00:00:00 2001 From: cphil Date: Tue, 11 May 2021 21:14:51 -0700 Subject: [PATCH 07/21] Convert to Typescript --- lib/index.d.ts | 15 ++ lib/index.js | 177 +++++++------- lib/reserved.d.ts | 0 lib/reserved.js | 3 +- package-lock.json | 569 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 67 +++--- src/index.ts | 260 +++++++++++++++++++++ src/reserved.ts | 150 ++++++++++++ tsconfig.json | 71 ++++++ 9 files changed, 1190 insertions(+), 122 deletions(-) create mode 100644 lib/index.d.ts create mode 100644 lib/reserved.d.ts create mode 100644 package-lock.json create mode 100644 src/index.ts create mode 100644 src/reserved.ts create mode 100644 tsconfig.json diff --git a/lib/index.d.ts b/lib/index.d.ts new file mode 100644 index 0000000..6f5c423 --- /dev/null +++ b/lib/index.d.ts @@ -0,0 +1,15 @@ +declare var reservedMap: any; +declare var fmtPattern: { + ident: string; + literal: string; + string: string; +}; +declare function formatDate(date: any): string; +declare function isReserved(value: any): boolean; +declare function arrayToList(useSpace: any, array: any, formatter: any): string; +declare function quoteIdent(value: any): string; +declare function quoteLiteral(value: any): string; +declare function quoteString(value: any): string; +declare function config(cfg: any): void; +declare function formatWithArray(fmt: any, parameters: any): any; +declare function format(fmt: string): string; diff --git a/lib/index.js b/lib/index.js index debd68f..c62f2b6 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,260 +1,259 @@ 'use strict'; - // reserved Postgres words var reservedMap = require(__dirname + '/reserved.js'); - var fmtPattern = { ident: 'I', literal: 'L', string: 's', }; - // convert to Postgres default ISO 8601 format function formatDate(date) { date = date.replace('T', ' '); date = date.replace('Z', '+00'); return date; } - function isReserved(value) { if (reservedMap[value.toUpperCase()]) { return true; } return false; } - function arrayToList(useSpace, array, formatter) { var sql = ''; var temp = []; - sql += useSpace ? ' (' : '('; for (var i = 0; i < array.length; i++) { sql += (i === 0 ? '' : ', ') + formatter(array[i]); } sql += ')'; - return sql; } - // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c function quoteIdent(value) { - if (value === undefined || value === null) { throw new Error('SQL identifier cannot be null or undefined'); - } else if (value === false) { + } + else if (value === false) { return '"f"'; - } else if (value === true) { + } + else if (value === true) { return '"t"'; - } else if (value instanceof Date) { + } + else if (value instanceof Date) { return '"' + formatDate(value.toISOString()) + '"'; - } else if (value instanceof Buffer) { + } + else if (value instanceof Buffer) { throw new Error('SQL identifier cannot be a buffer'); - } else if (Array.isArray(value) === true) { + } + else if (Array.isArray(value) === true) { var temp = []; for (var i = 0; i < value.length; i++) { if (Array.isArray(value[i]) === true) { throw new Error('Nested array to grouped list conversion is not supported for SQL identifier'); - } else { + } + else { temp.push(quoteIdent(value[i])); } } return temp.toString(); - } else if (value === Object(value)) { + } + else if (value === Object(value)) { throw new Error('SQL identifier cannot be an object'); } - var ident = value.toString().slice(0); // create copy - // do not quote a valid, unquoted identifier if (/^[a-z_][a-z0-9_$]*$/.test(ident) === true && isReserved(ident) === false) { return ident; } - var quoted = '"'; - for (var i = 0; i < ident.length; i++) { var c = ident[i]; if (c === '"') { quoted += c + c; - } else { + } + else { quoted += c; } } - quoted += '"'; - return quoted; -}; - +} +; // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c function quoteLiteral(value) { - - var literal = null; + var literal = ''; var explicitCast = null; - if (value === undefined || value === null) { return 'NULL'; - } else if (typeof value === 'bigint') { + } + else if (typeof value === 'bigint') { return BigInt(value).toString(); - } else if (value === Number.POSITIVE_INFINITY) { + } + else if (value === Number.POSITIVE_INFINITY) { return "'Infinity'"; - } else if (value === Number.NEGATIVE_INFINITY) { + } + else if (value === Number.NEGATIVE_INFINITY) { return "'-Infinity'"; - } else if (Number.isNaN(value)) { + } + else if (Number.isNaN(value)) { return "'NaN'"; - } else if (typeof value === 'number') {//Test must be AFTER other special case number tests + } + else if (typeof value === 'number') { //Test must be AFTER other special case number tests return Number(value).toString(); - } else if (value === false) { + } + else if (value === false) { return "'f'"; - } else if (value === true) { + } + else if (value === true) { return "'t'"; - } else if (value instanceof Date) { + } + else if (value instanceof Date) { return "'" + formatDate(value.toISOString()) + "'"; - } else if (value instanceof Buffer) { + } + else if (value instanceof Buffer) { return "E'\\\\x" + value.toString('hex') + "'"; - } else if (Array.isArray(value) === true) { + } + else if (Array.isArray(value) === true) { var temp = []; for (var i = 0; i < value.length; i++) { if (Array.isArray(value[i]) === true) { - temp.push(arrayToList(i !== 0, value[i], quoteLiteral)) - } else { + temp.push(arrayToList(i !== 0, value[i], quoteLiteral)); + } + else { temp.push(quoteLiteral(value[i])); } } return temp.toString(); - } else if (value === Object(value)) { + } + else if (value === Object(value)) { explicitCast = 'jsonb'; literal = JSON.stringify(value); - } else { + } + else { literal = value.toString().slice(0); // create copy } - var hasBackslash = false; var quoted = '\''; - for (var i = 0; i < literal.length; i++) { var c = literal[i]; if (c === '\'') { quoted += c + c; - } else if (c === '\\') { + } + else if (c === '\\') { quoted += c + c; hasBackslash = true; - } else { + } + else { quoted += c; } } - quoted += '\''; - if (hasBackslash === true) { quoted = 'E' + quoted; } - if (explicitCast) { quoted += '::' + explicitCast; } - return quoted; -}; - +} +; function quoteString(value) { - if (value === undefined || value === null) { return ''; - } else if (value === false) { + } + else if (value === false) { return 'f'; - } else if (value === true) { + } + else if (value === true) { return 't'; - } else if (value instanceof Date) { + } + else if (value instanceof Date) { return formatDate(value.toISOString()); - } else if (value instanceof Buffer) { + } + else if (value instanceof Buffer) { return '\\x' + value.toString('hex'); - } else if (Array.isArray(value) === true) { + } + else if (Array.isArray(value) === true) { var temp = []; for (var i = 0; i < value.length; i++) { if (value[i] !== null && value[i] !== undefined) { if (Array.isArray(value[i]) === true) { temp.push(arrayToList(i !== 0, value[i], quoteString)); - } else { + } + else { temp.push(quoteString(value[i])); } } } return temp.toString(); - } else if (value === Object(value)) { + } + else if (value === Object(value)) { return JSON.stringify(value); } - return value.toString().slice(0); // return copy } - function config(cfg) { - // default fmtPattern.ident = 'I'; fmtPattern.literal = 'L'; fmtPattern.string = 's'; - if (cfg && cfg.pattern) { - if (cfg.pattern.ident) { fmtPattern.ident = cfg.pattern.ident; } - if (cfg.pattern.literal) { fmtPattern.literal = cfg.pattern.literal; } - if (cfg.pattern.string) { fmtPattern.string = cfg.pattern.string; } + if (cfg.pattern.ident) { + fmtPattern.ident = cfg.pattern.ident; + } + if (cfg.pattern.literal) { + fmtPattern.literal = cfg.pattern.literal; + } + if (cfg.pattern.string) { + fmtPattern.string = cfg.pattern.string; + } } } - function formatWithArray(fmt, parameters) { - var index = 0; var params = parameters; - - var re = '%(%|(\\d+\\$)?['; - re += fmtPattern.ident; - re += fmtPattern.literal; - re += fmtPattern.string; - re += '])'; - re = new RegExp(re, 'g'); - + var reText = '%(%|(\\d+\\$)?['; + reText += fmtPattern.ident; + reText += fmtPattern.literal; + reText += fmtPattern.string; + reText += '])'; + var re = new RegExp(reText, 'g'); return fmt.replace(re, function (_, type) { - if (type === '%') { return '%'; } - var position = index; var tokens = type.split('$'); - if (tokens.length > 1) { position = parseInt(tokens[0]) - 1; type = tokens[1]; } - if (position < 0) { throw new Error('specified argument 0 but arguments start at 1'); - } else if (position > params.length - 1) { + } + else if (position > params.length - 1) { throw new Error('too few arguments'); } - index = position + 1; - if (type === fmtPattern.ident) { return quoteIdent(params[position]); - } else if (type === fmtPattern.literal) { + } + else if (type === fmtPattern.literal) { return quoteLiteral(params[position]); - } else if (type === fmtPattern.string) { + } + else if (type === fmtPattern.string) { return quoteString(params[position]); } }); } - function format(fmt) { var args = Array.prototype.slice.call(arguments); args = args.slice(1); // first argument is fmt return formatWithArray(fmt, args); } - exports = module.exports = format; exports.config = config; exports.ident = quoteIdent; exports.literal = quoteLiteral; exports.string = quoteString; -exports.withArray = formatWithArray; \ No newline at end of file +exports.withArray = formatWithArray; diff --git a/lib/reserved.d.ts b/lib/reserved.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/lib/reserved.js b/lib/reserved.js index 9ddc5c8..b9a2d1d 100644 --- a/lib/reserved.js +++ b/lib/reserved.js @@ -1,3 +1,4 @@ +"use strict"; // // PostgreSQL reserved words // @@ -147,4 +148,4 @@ module.exports = { "WHERE": true, "WITH": true, "WITHOUT": true, -}; \ No newline at end of file +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..695ddd3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,569 @@ +{ + "name": "node-pg-format", + "version": "1.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/node": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz", + "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==", + "dev": true + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true, + "optional": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "commander": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", + "dev": true + }, + "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 + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", + "dev": true + }, + "escodegen": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz", + "integrity": "sha1-MOz89mypjcZ80v0WKr626vqM5vw=", + "dev": true, + "requires": { + "esprima": "^1.2.2", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.5.0", + "source-map": "~0.2.0" + }, + "dependencies": { + "esprima": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", + "integrity": "sha1-CZNQL+r2aBODJXVvMPmlH+7sEek=", + "dev": true + } + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-levenshtein": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz", + "integrity": "sha1-AXjc3uAjuSkFGTrwlZ6KdjnP3Lk=", + "dev": true + }, + "fileset": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz", + "integrity": "sha1-WI74lzxmI7KnbfRlEFaWuWqsgGc=", + "dev": true, + "requires": { + "glob": "5.x", + "minimatch": "2.x" + } + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", + "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", + "dev": true + }, + "growl": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz", + "integrity": "sha1-Sy3sjZB+k9szZiTc7AGDUC+MlCg=", + "dev": true + }, + "handlebars": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "istanbul": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.2.tgz", + "integrity": "sha1-dl5yi5RVvt222qe5zsS5w8Pt5Ic=", + "dev": true, + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.7.x", + "esprima": "2.7.x", + "fileset": "0.2.x", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + } + }, + "jade": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "dev": true, + "requires": { + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, + "dependencies": { + "commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "dev": true + }, + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "dev": true + } + } + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "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 + } + } + }, + "levn": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz", + "integrity": "sha1-uo0znQykphDjo/FFucr0iAcVUFQ=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.0", + "type-check": "~0.3.1" + } + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "dev": true, + "requires": { + "brace-expansion": "^1.0.0" + } + }, + "minimist": { + "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.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.4.5.tgz", + "integrity": "sha1-FRdo3Sh161G8gpXpgAAm6fK7OY8=", + "dev": true, + "requires": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.3", + "growl": "1.8.1", + "jade": "0.26.3", + "mkdirp": "0.5.1", + "supports-color": "1.2.0" + }, + "dependencies": { + "glob": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", + "integrity": "sha1-4xPusknHr/qlxHUoaw4RW1mDlGc=", + "dev": true, + "requires": { + "graceful-fs": "~2.0.0", + "inherits": "2", + "minimatch": "~0.2.11" + } + }, + "minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "dev": true, + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "supports-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", + "dev": true + } + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz", + "integrity": "sha1-t1qJlaLUF98ltuTjhi9QqohlE2g=", + "dev": true, + "requires": { + "deep-is": "~0.1.2", + "fast-levenshtein": "~1.0.0", + "levn": "~0.2.5", + "prelude-ls": "~1.1.1", + "type-check": "~0.3.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "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 + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "should": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/should/-/should-8.2.1.tgz", + "integrity": "sha1-aW3q/mMbOSbgc/X2xumHjipVPKE=", + "dev": true, + "requires": { + "should-equal": "0.7.2", + "should-format": "0.3.2", + "should-type": "0.2.0" + } + }, + "should-equal": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-0.7.2.tgz", + "integrity": "sha1-pqlj2/UBuT7TS3gHrn1/BC/CTKg=", + "dev": true, + "requires": { + "should-type": "0.2.0" + } + }, + "should-format": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-0.3.2.tgz", + "integrity": "sha1-pZgx4Bot3uFJkRvHFIvlyAMZ4f8=", + "dev": true, + "requires": { + "should-type": "0.2.0" + } + }, + "should-type": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-0.2.0.tgz", + "integrity": "sha1-ZwfvlVKdmJ3MCY/gdTqx+RNrt/Y=", + "dev": true + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "typescript": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==" + }, + "uglify-js": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.1.tgz", + "integrity": "sha512-RjxApKkrPJB6kjJxQS3iZlf///REXWYxYJxO/MpmlQzVkDWVI3PSnCBWezMecmTU/TRkNxrl8bmsfFQCp+LO+Q==", + "dev": true, + "optional": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/package.json b/package.json index 40f588a..e238346 100644 --- a/package.json +++ b/package.json @@ -1,33 +1,36 @@ { - "author": { - "name": "Datalanche, Inc.", - "url": "https://www.datalanche.com" - }, - "name": "pg-format", - "license": "MIT", - "homepage": "https://github.com/datalanche/node-pg-format", - "description": "Node.js implementation of PostgreSQL's format() to safely create dynamic SQL queries.", - "version": "1.0.4", - "repository": { - "type": "git", - "url": "https://github.com/datalanche/node-pg-format.git" - }, - "main": "lib/index.js", - "directories": { - "lib": "./lib" - }, - "engines": { - "node": ">=4.0" - }, - "dependencies": { - }, - "devDependencies": { - "istanbul": "0.4.2", - "mocha": "2.4.5", - "should": "8.2.1" - }, - "scripts": { - "test": "node ./node_modules/mocha/bin/mocha", - "cover-test": "node_modules/.bin/istanbul cover node_modules/.bin/_mocha" - } -} + "author": { + "name": "Clint Phillips", + "url": "http://github.com/cphillips" + }, + "name": "node-pg-format", + "license": "MIT", + "homepage": "https://github.com/cphillips/node-pg-format", + "description": "Node.js implementation of PostgreSQL's format() to safely create dynamic SQL queries.", + "version": "1.1.0", + "repository": { + "type": "git", + "url": "https://github.com/cphillips/node-pg-format.git" + }, + "main": "lib/index.js", + "directories": { + "lib": "./lib" + }, + "engines": { + "node": ">=4.0" + }, + "dependencies": {}, + "devDependencies": { + "@types/node": "^15.0.2", + "typescript": "^4.2.4", + "istanbul": "0.4.2", + "mocha": "2.4.5", + "should": "8.2.1" + }, + "scripts": { + "prepublish": "npm build", + "build": "tsc", + "test": "node ./node_modules/mocha/bin/mocha", + "cover-test": "node_modules/.bin/istanbul cover node_modules/.bin/_mocha" + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..cd0f09e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,260 @@ +'use strict'; + +// reserved Postgres words +var reservedMap = require(__dirname + '/reserved.js'); + +var fmtPattern = { + ident: 'I', + literal: 'L', + string: 's', +}; + +// convert to Postgres default ISO 8601 format +function formatDate(date):string { + date = date.replace('T', ' '); + date = date.replace('Z', '+00'); + return date; +} + +function isReserved(value) { + if (reservedMap[value.toUpperCase()]) { + return true; + } + return false; +} + +function arrayToList(useSpace, array, formatter) { + var sql = ''; + var temp = []; + + sql += useSpace ? ' (' : '('; + for (var i = 0; i < array.length; i++) { + sql += (i === 0 ? '' : ', ') + formatter(array[i]); + } + sql += ')'; + + return sql; +} + +// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c +function quoteIdent(value): string { + + if (value === undefined || value === null) { + throw new Error('SQL identifier cannot be null or undefined'); + } else if (value === false) { + return '"f"'; + } else if (value === true) { + return '"t"'; + } else if (value instanceof Date) { + return '"' + formatDate(value.toISOString()) + '"'; + } else if (value instanceof Buffer) { + throw new Error('SQL identifier cannot be a buffer'); + } else if (Array.isArray(value) === true) { + var temp: string[] = []; + for (var i = 0; i < value.length; i++) { + if (Array.isArray(value[i]) === true) { + throw new Error('Nested array to grouped list conversion is not supported for SQL identifier'); + } else { + temp.push(quoteIdent(value[i])); + } + } + return temp.toString(); + } else if (value === Object(value)) { + throw new Error('SQL identifier cannot be an object'); + } + + var ident = value.toString().slice(0); // create copy + + // do not quote a valid, unquoted identifier + if (/^[a-z_][a-z0-9_$]*$/.test(ident) === true && isReserved(ident) === false) { + return ident; + } + + var quoted = '"'; + + for (var i = 0; i < ident.length; i++) { + var c = ident[i]; + if (c === '"') { + quoted += c + c; + } else { + quoted += c; + } + } + + quoted += '"'; + + return quoted; +}; + +// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c +function quoteLiteral(value) { + + let literal = ''; + let explicitCast: string | null = null; + + if (value === undefined || value === null) { + return 'NULL'; + } else if (typeof value === 'bigint') { + return BigInt(value).toString(); + } else if (value === Number.POSITIVE_INFINITY) { + return "'Infinity'"; + } else if (value === Number.NEGATIVE_INFINITY) { + return "'-Infinity'"; + } else if (Number.isNaN(value)) { + return "'NaN'"; + } else if (typeof value === 'number') {//Test must be AFTER other special case number tests + return Number(value).toString(); + } else if (value === false) { + return "'f'"; + } else if (value === true) { + return "'t'"; + } else if (value instanceof Date) { + return "'" + formatDate(value.toISOString()) + "'"; + } else if (value instanceof Buffer) { + return "E'\\\\x" + value.toString('hex') + "'"; + } else if (Array.isArray(value) === true) { + var temp: string[] = []; + for (var i = 0; i < value.length; i++) { + if (Array.isArray(value[i]) === true) { + temp.push(arrayToList(i !== 0, value[i], quoteLiteral)) + } else { + temp.push(quoteLiteral(value[i])); + } + } + return temp.toString(); + } else if (value === Object(value)) { + explicitCast = 'jsonb'; + literal = JSON.stringify(value); + } else { + literal = value.toString().slice(0); // create copy + } + + var hasBackslash = false; + var quoted = '\''; + + for (var i = 0; i < literal.length; i++) { + var c = literal[i]; + if (c === '\'') { + quoted += c + c; + } else if (c === '\\') { + quoted += c + c; + hasBackslash = true; + } else { + quoted += c; + } + } + + quoted += '\''; + + if (hasBackslash === true) { + quoted = 'E' + quoted; + } + + if (explicitCast) { + quoted += '::' + explicitCast; + } + + return quoted; +}; + +function quoteString(value):string { + + if (value === undefined || value === null) { + return ''; + } else if (value === false) { + return 'f'; + } else if (value === true) { + return 't'; + } else if (value instanceof Date) { + return formatDate(value.toISOString()); + } else if (value instanceof Buffer) { + return '\\x' + value.toString('hex'); + } else if (Array.isArray(value) === true) { + var temp: string[] = []; + for (var i = 0; i < value.length; i++) { + if (value[i] !== null && value[i] !== undefined) { + if (Array.isArray(value[i]) === true) { + temp.push(arrayToList(i !== 0, value[i], quoteString)); + } else { + temp.push(quoteString(value[i])); + } + } + } + return temp.toString(); + } else if (value === Object(value)) { + return JSON.stringify(value); + } + + return value.toString().slice(0); // return copy +} + +function config(cfg) { + + // default + fmtPattern.ident = 'I'; + fmtPattern.literal = 'L'; + fmtPattern.string = 's'; + + if (cfg && cfg.pattern) { + if (cfg.pattern.ident) { fmtPattern.ident = cfg.pattern.ident; } + if (cfg.pattern.literal) { fmtPattern.literal = cfg.pattern.literal; } + if (cfg.pattern.string) { fmtPattern.string = cfg.pattern.string; } + } +} + +function formatWithArray(fmt, parameters) { + + var index = 0; + var params = parameters; + + var reText = '%(%|(\\d+\\$)?['; + reText += fmtPattern.ident; + reText += fmtPattern.literal; + reText += fmtPattern.string; + reText += '])'; + const re = new RegExp(reText, 'g'); + + return fmt.replace(re, function (_, type) { + + if (type === '%') { + return '%'; + } + + var position = index; + var tokens = type.split('$'); + + if (tokens.length > 1) { + position = parseInt(tokens[0]) - 1; + type = tokens[1]; + } + + if (position < 0) { + throw new Error('specified argument 0 but arguments start at 1'); + } else if (position > params.length - 1) { + throw new Error('too few arguments'); + } + + index = position + 1; + + if (type === fmtPattern.ident) { + return quoteIdent(params[position]); + } else if (type === fmtPattern.literal) { + return quoteLiteral(params[position]); + } else if (type === fmtPattern.string) { + return quoteString(params[position]); + } + }); +} + +function format(fmt:string):string { + var args = Array.prototype.slice.call(arguments); + args = args.slice(1); // first argument is fmt + return formatWithArray(fmt, args); +} + +exports = module.exports = format; +exports.config = config; +exports.ident = quoteIdent; +exports.literal = quoteLiteral; +exports.string = quoteString; +exports.withArray = formatWithArray; \ No newline at end of file diff --git a/src/reserved.ts b/src/reserved.ts new file mode 100644 index 0000000..9ddc5c8 --- /dev/null +++ b/src/reserved.ts @@ -0,0 +1,150 @@ +// +// PostgreSQL reserved words +// +module.exports = { + "AES128": true, + "AES256": true, + "ALL": true, + "ALLOWOVERWRITE": true, + "ANALYSE": true, + "ANALYZE": true, + "AND": true, + "ANY": true, + "ARRAY": true, + "AS": true, + "ASC": true, + "AUTHORIZATION": true, + "BACKUP": true, + "BETWEEN": true, + "BINARY": true, + "BLANKSASNULL": true, + "BOTH": true, + "BYTEDICT": true, + "CASE": true, + "CAST": true, + "CHECK": true, + "COLLATE": true, + "COLUMN": true, + "CONSTRAINT": true, + "CREATE": true, + "CREDENTIALS": true, + "CROSS": true, + "CURRENT_DATE": true, + "CURRENT_TIME": true, + "CURRENT_TIMESTAMP": true, + "CURRENT_USER": true, + "CURRENT_USER_ID": true, + "DEFAULT": true, + "DEFERRABLE": true, + "DEFLATE": true, + "DEFRAG": true, + "DELTA": true, + "DELTA32K": true, + "DESC": true, + "DISABLE": true, + "DISTINCT": true, + "DO": true, + "ELSE": true, + "EMPTYASNULL": true, + "ENABLE": true, + "ENCODE": true, + "ENCRYPT": true, + "ENCRYPTION": true, + "END": true, + "EXCEPT": true, + "EXPLICIT": true, + "FALSE": true, + "FOR": true, + "FOREIGN": true, + "FREEZE": true, + "FROM": true, + "FULL": true, + "GLOBALDICT256": true, + "GLOBALDICT64K": true, + "GRANT": true, + "GROUP": true, + "GZIP": true, + "HAVING": true, + "IDENTITY": true, + "IGNORE": true, + "ILIKE": true, + "IN": true, + "INITIALLY": true, + "INNER": true, + "INTERSECT": true, + "INTO": true, + "IS": true, + "ISNULL": true, + "JOIN": true, + "LEADING": true, + "LEFT": true, + "LIKE": true, + "LIMIT": true, + "LOCALTIME": true, + "LOCALTIMESTAMP": true, + "LUN": true, + "LUNS": true, + "LZO": true, + "LZOP": true, + "MINUS": true, + "MOSTLY13": true, + "MOSTLY32": true, + "MOSTLY8": true, + "NATURAL": true, + "NEW": true, + "NOT": true, + "NOTNULL": true, + "NULL": true, + "NULLS": true, + "OFF": true, + "OFFLINE": true, + "OFFSET": true, + "OLD": true, + "ON": true, + "ONLY": true, + "OPEN": true, + "OR": true, + "ORDER": true, + "OUTER": true, + "OVERLAPS": true, + "PARALLEL": true, + "PARTITION": true, + "PERCENT": true, + "PLACING": true, + "PRIMARY": true, + "RAW": true, + "READRATIO": true, + "RECOVER": true, + "REFERENCES": true, + "REJECTLOG": true, + "RESORT": true, + "RESTORE": true, + "RIGHT": true, + "SELECT": true, + "SESSION_USER": true, + "SIMILAR": true, + "SOME": true, + "SYSDATE": true, + "SYSTEM": true, + "TABLE": true, + "TAG": true, + "TDES": true, + "TEXT255": true, + "TEXT32K": true, + "THEN": true, + "TO": true, + "TOP": true, + "TRAILING": true, + "TRUE": true, + "TRUNCATECOLUMNS": true, + "UNION": true, + "UNIQUE": true, + "USER": true, + "USING": true, + "VERBOSE": true, + "WALLET": true, + "WHEN": true, + "WHERE": true, + "WITH": true, + "WITHOUT": true, +}; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..a2e1c69 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,71 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* 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', 'react', 'react-jsx' or 'react-jsxdev'. */ + "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": "./lib", /* Redirect output structure to the directory. */ + "rootDir": "./src", /* 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": false, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* 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. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ + + /* 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. */ + } +} From 3bc37921c160aeae0fe746c501e33099fef6cdf4 Mon Sep 17 00:00:00 2001 From: cphil Date: Tue, 11 May 2021 21:15:25 -0700 Subject: [PATCH 08/21] Version to 1.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e238346..99c6677 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "license": "MIT", "homepage": "https://github.com/cphillips/node-pg-format", "description": "Node.js implementation of PostgreSQL's format() to safely create dynamic SQL queries.", - "version": "1.1.0", + "version": "1.2.0", "repository": { "type": "git", "url": "https://github.com/cphillips/node-pg-format.git" From d758c7543648c2ecd8623a87579348230f79f083 Mon Sep 17 00:00:00 2001 From: cphil Date: Wed, 12 May 2021 05:42:33 -0700 Subject: [PATCH 09/21] Complete Typescript Port --- lib/index.d.ts | 12 +-- lib/index.js | 11 +-- src/index.ts | 241 ++++++++++++++++++++++++------------------------ src/reserved.ts | 2 +- tsconfig.json | 2 +- 5 files changed, 131 insertions(+), 137 deletions(-) diff --git a/lib/index.d.ts b/lib/index.d.ts index 6f5c423..e14ed8c 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1,15 +1,15 @@ -declare var reservedMap: any; -declare var fmtPattern: { +declare const reservedMap: any; +declare const fmtPattern: { ident: string; literal: string; string: string; }; -declare function formatDate(date: any): string; -declare function isReserved(value: any): boolean; -declare function arrayToList(useSpace: any, array: any, formatter: any): string; +declare function formatDate(date: string): string; +declare function isReserved(value: string): boolean; +declare function arrayToList(useSpace: boolean, array: any[], formatter: (value: any) => string): string; declare function quoteIdent(value: any): string; declare function quoteLiteral(value: any): string; declare function quoteString(value: any): string; declare function config(cfg: any): void; declare function formatWithArray(fmt: any, parameters: any): any; -declare function format(fmt: string): string; +declare function format(fmt: string, ...args: any[]): string; diff --git a/lib/index.js b/lib/index.js index c62f2b6..23f72df 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,4 +1,4 @@ -'use strict'; +"use strict"; // reserved Postgres words var reservedMap = require(__dirname + '/reserved.js'); var fmtPattern = { @@ -20,7 +20,6 @@ function isReserved(value) { } function arrayToList(useSpace, array, formatter) { var sql = ''; - var temp = []; sql += useSpace ? ' (' : '('; for (var i = 0; i < array.length; i++) { sql += (i === 0 ? '' : ', ') + formatter(array[i]); @@ -78,7 +77,6 @@ function quoteIdent(value) { quoted += '"'; return quoted; } -; // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c function quoteLiteral(value) { var literal = ''; @@ -156,7 +154,6 @@ function quoteLiteral(value) { } return quoted; } -; function quoteString(value) { if (value === undefined || value === null) { return ''; @@ -247,8 +244,10 @@ function formatWithArray(fmt, parameters) { }); } function format(fmt) { - var args = Array.prototype.slice.call(arguments); - args = args.slice(1); // first argument is fmt + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } return formatWithArray(fmt, args); } exports = module.exports = format; diff --git a/src/index.ts b/src/index.ts index cd0f09e..77b43bf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,260 +1,255 @@ -'use strict'; - // reserved Postgres words -var reservedMap = require(__dirname + '/reserved.js'); +const reservedMap = require(__dirname + '/reserved.js') -var fmtPattern = { +const fmtPattern = { ident: 'I', literal: 'L', string: 's', -}; +} // convert to Postgres default ISO 8601 format -function formatDate(date):string { - date = date.replace('T', ' '); - date = date.replace('Z', '+00'); - return date; +function formatDate(date:string): string { + date = date.replace('T', ' ') + date = date.replace('Z', '+00') + return date } -function isReserved(value) { +function isReserved(value:string):boolean { if (reservedMap[value.toUpperCase()]) { - return true; + return true } - return false; + return false } -function arrayToList(useSpace, array, formatter) { - var sql = ''; - var temp = []; +function arrayToList(useSpace:boolean, array:any[], formatter:(value:any)=>string) { + let sql = '' - sql += useSpace ? ' (' : '('; - for (var i = 0; i < array.length; i++) { - sql += (i === 0 ? '' : ', ') + formatter(array[i]); + sql += useSpace ? ' (' : '(' + for (let i = 0; i < array.length; i++) { + sql += (i === 0 ? '' : ', ') + formatter(array[i]) } - sql += ')'; + sql += ')' - return sql; + return sql } // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c -function quoteIdent(value): string { +function quoteIdent(value:any): string { if (value === undefined || value === null) { - throw new Error('SQL identifier cannot be null or undefined'); + throw new Error('SQL identifier cannot be null or undefined') } else if (value === false) { - return '"f"'; + return '"f"' } else if (value === true) { - return '"t"'; + return '"t"' } else if (value instanceof Date) { - return '"' + formatDate(value.toISOString()) + '"'; + return '"' + formatDate(value.toISOString()) + '"' } else if (value instanceof Buffer) { - throw new Error('SQL identifier cannot be a buffer'); + throw new Error('SQL identifier cannot be a buffer') } else if (Array.isArray(value) === true) { - var temp: string[] = []; - for (var i = 0; i < value.length; i++) { + const temp: string[] = [] + for (let i = 0; i < value.length; i++) { if (Array.isArray(value[i]) === true) { - throw new Error('Nested array to grouped list conversion is not supported for SQL identifier'); + throw new Error('Nested array to grouped list conversion is not supported for SQL identifier') } else { - temp.push(quoteIdent(value[i])); + temp.push(quoteIdent(value[i])) } } - return temp.toString(); + return temp.toString() } else if (value === Object(value)) { - throw new Error('SQL identifier cannot be an object'); + throw new Error('SQL identifier cannot be an object') } - var ident = value.toString().slice(0); // create copy + const ident = value.toString().slice(0) // create copy // do not quote a valid, unquoted identifier if (/^[a-z_][a-z0-9_$]*$/.test(ident) === true && isReserved(ident) === false) { - return ident; + return ident } - var quoted = '"'; + let quoted = '"' - for (var i = 0; i < ident.length; i++) { - var c = ident[i]; + for (let i = 0; i < ident.length; i++) { + const c = ident[i] if (c === '"') { - quoted += c + c; + quoted += c + c } else { - quoted += c; + quoted += c } } - quoted += '"'; + quoted += '"' - return quoted; -}; + return quoted +} // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c function quoteLiteral(value) { - let literal = ''; - let explicitCast: string | null = null; + let literal = '' + let explicitCast: string | null = null if (value === undefined || value === null) { - return 'NULL'; + return 'NULL' } else if (typeof value === 'bigint') { - return BigInt(value).toString(); + return BigInt(value).toString() } else if (value === Number.POSITIVE_INFINITY) { - return "'Infinity'"; + return "'Infinity'" } else if (value === Number.NEGATIVE_INFINITY) { - return "'-Infinity'"; + return "'-Infinity'" } else if (Number.isNaN(value)) { - return "'NaN'"; + return "'NaN'" } else if (typeof value === 'number') {//Test must be AFTER other special case number tests - return Number(value).toString(); + return Number(value).toString() } else if (value === false) { - return "'f'"; + return "'f'" } else if (value === true) { - return "'t'"; + return "'t'" } else if (value instanceof Date) { - return "'" + formatDate(value.toISOString()) + "'"; + return "'" + formatDate(value.toISOString()) + "'" } else if (value instanceof Buffer) { - return "E'\\\\x" + value.toString('hex') + "'"; + return "E'\\\\x" + value.toString('hex') + "'" } else if (Array.isArray(value) === true) { - var temp: string[] = []; - for (var i = 0; i < value.length; i++) { + const temp: string[] = [] + for (let i = 0; i < value.length; i++) { if (Array.isArray(value[i]) === true) { temp.push(arrayToList(i !== 0, value[i], quoteLiteral)) } else { - temp.push(quoteLiteral(value[i])); + temp.push(quoteLiteral(value[i])) } } - return temp.toString(); + return temp.toString() } else if (value === Object(value)) { - explicitCast = 'jsonb'; - literal = JSON.stringify(value); + explicitCast = 'jsonb' + literal = JSON.stringify(value) } else { - literal = value.toString().slice(0); // create copy + literal = value.toString().slice(0) // create copy } - var hasBackslash = false; - var quoted = '\''; + let hasBackslash = false + let quoted = '\'' - for (var i = 0; i < literal.length; i++) { - var c = literal[i]; + for (let i = 0; i < literal.length; i++) { + const c = literal[i] if (c === '\'') { - quoted += c + c; + quoted += c + c } else if (c === '\\') { - quoted += c + c; - hasBackslash = true; + quoted += c + c + hasBackslash = true } else { - quoted += c; + quoted += c } } - quoted += '\''; + quoted += '\'' if (hasBackslash === true) { - quoted = 'E' + quoted; + quoted = 'E' + quoted } if (explicitCast) { - quoted += '::' + explicitCast; + quoted += '::' + explicitCast } - return quoted; -}; + return quoted +} -function quoteString(value):string { +function quoteString(value): string { if (value === undefined || value === null) { - return ''; + return '' } else if (value === false) { - return 'f'; + return 'f' } else if (value === true) { - return 't'; + return 't' } else if (value instanceof Date) { - return formatDate(value.toISOString()); + return formatDate(value.toISOString()) } else if (value instanceof Buffer) { - return '\\x' + value.toString('hex'); + return '\\x' + value.toString('hex') } else if (Array.isArray(value) === true) { - var temp: string[] = []; - for (var i = 0; i < value.length; i++) { + const temp: string[] = [] + for (let i = 0; i < value.length; i++) { if (value[i] !== null && value[i] !== undefined) { if (Array.isArray(value[i]) === true) { - temp.push(arrayToList(i !== 0, value[i], quoteString)); + temp.push(arrayToList(i !== 0, value[i], quoteString)) } else { - temp.push(quoteString(value[i])); + temp.push(quoteString(value[i])) } } } - return temp.toString(); + return temp.toString() } else if (value === Object(value)) { - return JSON.stringify(value); + return JSON.stringify(value) } - return value.toString().slice(0); // return copy + return value.toString().slice(0) // return copy } function config(cfg) { // default - fmtPattern.ident = 'I'; - fmtPattern.literal = 'L'; - fmtPattern.string = 's'; + fmtPattern.ident = 'I' + fmtPattern.literal = 'L' + fmtPattern.string = 's' if (cfg && cfg.pattern) { - if (cfg.pattern.ident) { fmtPattern.ident = cfg.pattern.ident; } - if (cfg.pattern.literal) { fmtPattern.literal = cfg.pattern.literal; } - if (cfg.pattern.string) { fmtPattern.string = cfg.pattern.string; } + if (cfg.pattern.ident) { fmtPattern.ident = cfg.pattern.ident } + if (cfg.pattern.literal) { fmtPattern.literal = cfg.pattern.literal } + if (cfg.pattern.string) { fmtPattern.string = cfg.pattern.string } } } function formatWithArray(fmt, parameters) { - var index = 0; - var params = parameters; + let index = 0 + let params = parameters - var reText = '%(%|(\\d+\\$)?['; - reText += fmtPattern.ident; - reText += fmtPattern.literal; - reText += fmtPattern.string; - reText += '])'; - const re = new RegExp(reText, 'g'); + let reText = '%(%|(\\d+\\$)?[' + reText += fmtPattern.ident + reText += fmtPattern.literal + reText += fmtPattern.string + reText += '])' + const re = new RegExp(reText, 'g') return fmt.replace(re, function (_, type) { if (type === '%') { - return '%'; + return '%' } - var position = index; - var tokens = type.split('$'); + let position = index + const tokens = type.split('$') if (tokens.length > 1) { - position = parseInt(tokens[0]) - 1; - type = tokens[1]; + position = parseInt(tokens[0]) - 1 + type = tokens[1] } if (position < 0) { - throw new Error('specified argument 0 but arguments start at 1'); + throw new Error('specified argument 0 but arguments start at 1') } else if (position > params.length - 1) { - throw new Error('too few arguments'); + throw new Error('too few arguments') } - index = position + 1; + index = position + 1 if (type === fmtPattern.ident) { - return quoteIdent(params[position]); + return quoteIdent(params[position]) } else if (type === fmtPattern.literal) { - return quoteLiteral(params[position]); + return quoteLiteral(params[position]) } else if (type === fmtPattern.string) { - return quoteString(params[position]); + return quoteString(params[position]) } - }); + }) } -function format(fmt:string):string { - var args = Array.prototype.slice.call(arguments); - args = args.slice(1); // first argument is fmt - return formatWithArray(fmt, args); +function format(fmt: string, ...args: any[]): string { + return formatWithArray(fmt, args) } -exports = module.exports = format; -exports.config = config; -exports.ident = quoteIdent; -exports.literal = quoteLiteral; -exports.string = quoteString; -exports.withArray = formatWithArray; \ No newline at end of file +exports = module.exports = format +exports.config = config +exports.ident = quoteIdent +exports.literal = quoteLiteral +exports.string = quoteString +exports.withArray = formatWithArray \ No newline at end of file diff --git a/src/reserved.ts b/src/reserved.ts index 9ddc5c8..4fa2735 100644 --- a/src/reserved.ts +++ b/src/reserved.ts @@ -147,4 +147,4 @@ module.exports = { "WHERE": true, "WITH": true, "WITHOUT": true, -}; \ No newline at end of file +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index a2e1c69..417a1c5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,7 +32,7 @@ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ // "strictPropertyInitialization": true, /* 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. */ + "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ // "noUnusedLocals": true, /* Report errors on unused locals. */ From ebee2c3d16e257b7dad1b525aa97efbe0feae345 Mon Sep 17 00:00:00 2001 From: cphil Date: Wed, 12 May 2021 05:47:50 -0700 Subject: [PATCH 10/21] Merge Alex Anderson reserved words --- src/reserved.ts | 300 +++++++++++++++++++++++++----------------------- 1 file changed, 155 insertions(+), 145 deletions(-) diff --git a/src/reserved.ts b/src/reserved.ts index 4fa2735..faf03b8 100644 --- a/src/reserved.ts +++ b/src/reserved.ts @@ -1,150 +1,160 @@ // // PostgreSQL reserved words +// see: https://www.postgresql.org/docs/current/sql-keywords-appendix.html // module.exports = { - "AES128": true, - "AES256": true, - "ALL": true, - "ALLOWOVERWRITE": true, - "ANALYSE": true, - "ANALYZE": true, - "AND": true, - "ANY": true, - "ARRAY": true, - "AS": true, - "ASC": true, - "AUTHORIZATION": true, - "BACKUP": true, - "BETWEEN": true, - "BINARY": true, - "BLANKSASNULL": true, - "BOTH": true, - "BYTEDICT": true, - "CASE": true, - "CAST": true, - "CHECK": true, - "COLLATE": true, - "COLUMN": true, - "CONSTRAINT": true, - "CREATE": true, - "CREDENTIALS": true, - "CROSS": true, - "CURRENT_DATE": true, - "CURRENT_TIME": true, - "CURRENT_TIMESTAMP": true, - "CURRENT_USER": true, - "CURRENT_USER_ID": true, - "DEFAULT": true, - "DEFERRABLE": true, - "DEFLATE": true, - "DEFRAG": true, - "DELTA": true, - "DELTA32K": true, - "DESC": true, - "DISABLE": true, - "DISTINCT": true, - "DO": true, - "ELSE": true, - "EMPTYASNULL": true, - "ENABLE": true, - "ENCODE": true, - "ENCRYPT": true, - "ENCRYPTION": true, - "END": true, - "EXCEPT": true, - "EXPLICIT": true, - "FALSE": true, - "FOR": true, - "FOREIGN": true, - "FREEZE": true, - "FROM": true, - "FULL": true, - "GLOBALDICT256": true, - "GLOBALDICT64K": true, - "GRANT": true, - "GROUP": true, - "GZIP": true, - "HAVING": true, - "IDENTITY": true, - "IGNORE": true, - "ILIKE": true, - "IN": true, - "INITIALLY": true, - "INNER": true, - "INTERSECT": true, - "INTO": true, - "IS": true, - "ISNULL": true, - "JOIN": true, - "LEADING": true, - "LEFT": true, - "LIKE": true, - "LIMIT": true, - "LOCALTIME": true, - "LOCALTIMESTAMP": true, - "LUN": true, - "LUNS": true, - "LZO": true, - "LZOP": true, - "MINUS": true, - "MOSTLY13": true, - "MOSTLY32": true, - "MOSTLY8": true, - "NATURAL": true, - "NEW": true, - "NOT": true, - "NOTNULL": true, - "NULL": true, - "NULLS": true, - "OFF": true, - "OFFLINE": true, - "OFFSET": true, - "OLD": true, - "ON": true, - "ONLY": true, - "OPEN": true, - "OR": true, - "ORDER": true, - "OUTER": true, - "OVERLAPS": true, - "PARALLEL": true, - "PARTITION": true, - "PERCENT": true, - "PLACING": true, - "PRIMARY": true, - "RAW": true, - "READRATIO": true, - "RECOVER": true, - "REFERENCES": true, - "REJECTLOG": true, - "RESORT": true, - "RESTORE": true, - "RIGHT": true, - "SELECT": true, - "SESSION_USER": true, - "SIMILAR": true, - "SOME": true, - "SYSDATE": true, - "SYSTEM": true, - "TABLE": true, - "TAG": true, - "TDES": true, - "TEXT255": true, - "TEXT32K": true, - "THEN": true, - "TO": true, - "TOP": true, - "TRAILING": true, - "TRUE": true, - "TRUNCATECOLUMNS": true, - "UNION": true, - "UNIQUE": true, - "USER": true, - "USING": true, - "VERBOSE": true, - "WALLET": true, - "WHEN": true, - "WHERE": true, - "WITH": true, - "WITHOUT": true, + "AES128": true, + "AES256": true, + "ALL": true, + "ALLOWOVERWRITE": true, + "ANALYSE": true, + "ANALYZE": true, + "AND": true, + "ANY": true, + "ARRAY": true, + "AS": true, + "ASC": true, + "ASYMMETRIC": true, + "AUTHORIZATION": true, + "BACKUP": true, + "BETWEEN": true, + "BINARY": true, + "BLANKSASNULL": true, + "BOTH": true, + "BYTEDICT": true, + "CASE": true, + "CAST": true, + "CHECK": true, + "COLLATE": true, + "COLUMN": true, + "CONSTRAINT": true, + "CREATE": true, + "CREDENTIALS": true, + "CROSS": true, + "CURRENT_CATALOG": true, + "CURRENT_DATE": true, + "CURRENT_ROLE": true, + "CURRENT_TIME": true, + "CURRENT_TIMESTAMP": true, + "CURRENT_USER": true, + "CURRENT_USER_ID": true, + "DEFAULT": true, + "DEFERRABLE": true, + "DEFLATE": true, + "DEFRAG": true, + "DELTA": true, + "DELTA32K": true, + "DESC": true, + "DISABLE": true, + "DISTINCT": true, + "DO": true, + "ELSE": true, + "EMPTYASNULL": true, + "ENABLE": true, + "ENCODE": true, + "ENCRYPT": true, + "ENCRYPTION": true, + "END": true, + "EXCEPT": true, + "EXPLICIT": true, + "FALSE": true, + "FETCH": true, + "FOR": true, + "FOREIGN": true, + "FREEZE": true, + "FROM": true, + "FULL": true, + "GLOBALDICT256": true, + "GLOBALDICT64K": true, + "GRANT": true, + "GROUP": true, + "GZIP": true, + "HAVING": true, + "IDENTITY": true, + "IGNORE": true, + "ILIKE": true, + "IN": true, + "INITIALLY": true, + "INNER": true, + "INTERSECT": true, + "INTO": true, + "IS": true, + "ISNULL": true, + "JOIN": true, + "LATERAL": true, + "LEADING": true, + "LEFT": true, + "LIKE": true, + "LIMIT": true, + "LOCALTIME": true, + "LOCALTIMESTAMP": true, + "LUN": true, + "LUNS": true, + "LZO": true, + "LZOP": true, + "MINUS": true, + "MOSTLY13": true, + "MOSTLY32": true, + "MOSTLY8": true, + "NATURAL": true, + "NEW": true, + "NOT": true, + "NOTNULL": true, + "NULL": true, + "NULLS": true, + "OFF": true, + "OFFLINE": true, + "OFFSET": true, + "OLD": true, + "ON": true, + "ONLY": true, + "OPEN": true, + "OR": true, + "ORDER": true, + "OUTER": true, + "OVERLAPS": true, + "PARALLEL": true, + "PARTITION": true, + "PERCENT": true, + "PLACING": true, + "PRIMARY": true, + "RAW": true, + "READRATIO": true, + "RECOVER": true, + "REFERENCES": true, + "REJECTLOG": true, + "RESORT": true, + "RESTORE": true, + "RETURNING": true, + "RIGHT": true, + "SELECT": true, + "SESSION_USER": true, + "SIMILAR": true, + "SOME": true, + "SYMMETRIC": true, + "SYSDATE": true, + "SYSTEM": true, + "TABLE": true, + "TAG": true, + "TDES": true, + "TEXT255": true, + "TEXT32K": true, + "THEN": true, + "TO": true, + "TOP": true, + "TRAILING": true, + "TRUE": true, + "TRUNCATECOLUMNS": true, + "UNION": true, + "UNIQUE": true, + "USER": true, + "USING": true, + "VARIADIC": true, + "VERBOSE": true, + "WALLET": true, + "WHEN": true, + "WHERE": true, + "WINDOW": true, + "WITH": true, + "WITHOUT": true, } \ No newline at end of file From 9f19d96eefb1ac96a77fba7b89db57387f2c3c75 Mon Sep 17 00:00:00 2001 From: cphil Date: Wed, 12 May 2021 05:53:57 -0700 Subject: [PATCH 11/21] Update Reserved Words --- README.md | 20 ++++++++++---------- lib/reserved.js | 10 ++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6dd176d..d226932 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ Node.js implementation of [PostgreSQL format()](http://www.postgresql.org/docs/9 ## Example ```js -var format = require('pg-format'); -var sql = format('SELECT * FROM %I WHERE my_col = %L %s', 'my_table', 34, 'LIMIT 10'); +const format = require('pg-format'); +const sql = format('SELECT * FROM %I WHERE my_col = %L %s', 'my_table', 34, 'LIMIT 10'); console.log(sql); // SELECT * FROM my_table WHERE my_col = 34 LIMIT 10 ``` @@ -26,15 +26,15 @@ Returns a formatted string based on ```fmt``` which has a style similar to the C #### Argument position You can define where an argument is positioned using ```n$``` where ```n``` is the argument index starting at 1. ```js -var format = require('pg-format'); -var sql = format('SELECT %1$L, %1$L, %L', 34, 'test'); +const format = require('pg-format'); +const sql = format('SELECT %1$L, %1$L, %L', 34, 'test'); console.log(sql); // SELECT 34, 34, 'test' ``` ### format.config(cfg) Changes the global configuration. You can change which letters are used to denote identifiers, literals, and strings in the formatted string. This is useful when the formatted string contains a PL/pgSQL function which calls [PostgreSQL format()](http://www.postgresql.org/docs/9.3/static/functions-string.html#FUNCTIONS-STRING-FORMAT) itself. ```js -var format = require('pg-format'); +const format = require('pg-format'); format.config({ pattern: { ident: 'V', @@ -65,13 +65,13 @@ For arrays, each element is escaped when appropriate and concatenated to a comma For objects, ```JSON.stringify()``` is called and the resulting string is escaped if appropriate. Objects can be used for literals (```%L```) and strings (```%s```), but not identifiers (```%I```). See the example below. ```js -var format = require('pg-format'); +const format = require('pg-format'); -var myArray = [ 1, 2, 3 ]; -var myObject = { a: 1, b: 2 }; -var myNestedArray = [['a', 1], ['b', 2]]; +const myArray = [ 1, 2, 3 ]; +const myObject = { a: 1, b: 2 }; +const myNestedArray = [['a', 1], ['b', 2]]; -var sql = format('SELECT * FROM t WHERE c1 IN (%L) AND c2 = %L', myArray, myObject); +let sql = format('SELECT * FROM t WHERE c1 IN (%L) AND c2 = %L', myArray, myObject); console.log(sql); // SELECT * FROM t WHERE c1 IN (1,2,3) AND c2 = '{"a":1,"b":2}' sql = format('INSERT INTO t (name, age) VALUES %L', myNestedArray); diff --git a/lib/reserved.js b/lib/reserved.js index b9a2d1d..29d98d5 100644 --- a/lib/reserved.js +++ b/lib/reserved.js @@ -1,6 +1,7 @@ "use strict"; // // PostgreSQL reserved words +// see: https://www.postgresql.org/docs/current/sql-keywords-appendix.html // module.exports = { "AES128": true, @@ -14,6 +15,7 @@ module.exports = { "ARRAY": true, "AS": true, "ASC": true, + "ASYMMETRIC": true, "AUTHORIZATION": true, "BACKUP": true, "BETWEEN": true, @@ -30,7 +32,9 @@ module.exports = { "CREATE": true, "CREDENTIALS": true, "CROSS": true, + "CURRENT_CATALOG": true, "CURRENT_DATE": true, + "CURRENT_ROLE": true, "CURRENT_TIME": true, "CURRENT_TIMESTAMP": true, "CURRENT_USER": true, @@ -55,6 +59,7 @@ module.exports = { "EXCEPT": true, "EXPLICIT": true, "FALSE": true, + "FETCH": true, "FOR": true, "FOREIGN": true, "FREEZE": true, @@ -77,6 +82,7 @@ module.exports = { "IS": true, "ISNULL": true, "JOIN": true, + "LATERAL": true, "LEADING": true, "LEFT": true, "LIKE": true, @@ -120,11 +126,13 @@ module.exports = { "REJECTLOG": true, "RESORT": true, "RESTORE": true, + "RETURNING": true, "RIGHT": true, "SELECT": true, "SESSION_USER": true, "SIMILAR": true, "SOME": true, + "SYMMETRIC": true, "SYSDATE": true, "SYSTEM": true, "TABLE": true, @@ -142,10 +150,12 @@ module.exports = { "UNIQUE": true, "USER": true, "USING": true, + "VARIADIC": true, "VERBOSE": true, "WALLET": true, "WHEN": true, "WHERE": true, + "WINDOW": true, "WITH": true, "WITHOUT": true, }; From 0cda20b05c5e35a9b3b6a80070c0b2cd0a4ace31 Mon Sep 17 00:00:00 2001 From: cphil Date: Wed, 12 May 2021 05:55:01 -0700 Subject: [PATCH 12/21] Update Test Instructions in Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d226932..7158424 100644 --- a/README.md +++ b/README.md @@ -82,5 +82,6 @@ console.log(sql); // INSERT INTO t (name, age) VALUES ('a', 1), ('b', 2) ``` npm install +npm run build npm test ``` \ No newline at end of file From abf0e03229f34644e0331ccf8d01815588b3cc03 Mon Sep 17 00:00:00 2001 From: cphil Date: Wed, 12 May 2021 05:55:22 -0700 Subject: [PATCH 13/21] Version Up --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 99c6677..5f45219 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "license": "MIT", "homepage": "https://github.com/cphillips/node-pg-format", "description": "Node.js implementation of PostgreSQL's format() to safely create dynamic SQL queries.", - "version": "1.2.0", + "version": "1.2.1", "repository": { "type": "git", "url": "https://github.com/cphillips/node-pg-format.git" From 8095cbbc5d29c5b11805ea98f5273efe64313123 Mon Sep 17 00:00:00 2001 From: cphil Date: Wed, 12 May 2021 05:57:02 -0700 Subject: [PATCH 14/21] Fix readme for install --- README.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7158424..18662f2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Node.js implementation of [PostgreSQL format()](http://www.postgresql.org/docs/9 ## Install - npm install pg-format + npm install node-pg-format ## Example ```js diff --git a/package.json b/package.json index 5f45219..69b2641 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "license": "MIT", "homepage": "https://github.com/cphillips/node-pg-format", "description": "Node.js implementation of PostgreSQL's format() to safely create dynamic SQL queries.", - "version": "1.2.1", + "version": "1.2.2", "repository": { "type": "git", "url": "https://github.com/cphillips/node-pg-format.git" From 0f7a8b6e5c20ecc4ee023b3ce3a3499539699f4b Mon Sep 17 00:00:00 2001 From: cphil Date: Mon, 17 May 2021 14:43:56 -0700 Subject: [PATCH 15/21] publish 1.2.7 --- lib/index.js | 2 +- package.json | 3 +- src/index.ts | 2 +- test/index.js | 448 +++++++++++++++++++++++++------------------------- 4 files changed, 230 insertions(+), 225 deletions(-) diff --git a/lib/index.js b/lib/index.js index 23f72df..4833400 100644 --- a/lib/index.js +++ b/lib/index.js @@ -61,7 +61,7 @@ function quoteIdent(value) { } var ident = value.toString().slice(0); // create copy // do not quote a valid, unquoted identifier - if (/^[a-z_][a-z0-9_$]*$/.test(ident) === true && isReserved(ident) === false) { + if (/^[a-z_][a-z0-9_$.]*$/.test(ident) === true && isReserved(ident) === false) { return ident; } var quoted = '"'; diff --git a/package.json b/package.json index 69b2641..5ad2de7 100644 --- a/package.json +++ b/package.json @@ -7,12 +7,13 @@ "license": "MIT", "homepage": "https://github.com/cphillips/node-pg-format", "description": "Node.js implementation of PostgreSQL's format() to safely create dynamic SQL queries.", - "version": "1.2.2", + "version": "1.2.7", "repository": { "type": "git", "url": "https://github.com/cphillips/node-pg-format.git" }, "main": "lib/index.js", + "types": "lib/index.d.ts", "directories": { "lib": "./lib" }, diff --git a/src/index.ts b/src/index.ts index 77b43bf..91f8878 100644 --- a/src/index.ts +++ b/src/index.ts @@ -63,7 +63,7 @@ function quoteIdent(value:any): string { const ident = value.toString().slice(0) // create copy // do not quote a valid, unquoted identifier - if (/^[a-z_][a-z0-9_$]*$/.test(ident) === true && isReserved(ident) === false) { + if (/^[a-z_][a-z0-9_$.]*$/.test(ident) === true && isReserved(ident) === false) { return ident } diff --git a/test/index.js b/test/index.js index 5e9644c..0d56c00 100644 --- a/test/index.js +++ b/test/index.js @@ -12,268 +12,272 @@ var testObject = { a: 1, b: 2 }; var testNestedArray = [[1, 2], [3, 4], [5, 6]]; describe('format(fmt, ...)', function () { - describe('%s', function () { - it('should format as a simple string', function () { - format('some %s here', 'thing').should.equal('some thing here'); - format('some %s thing %s', 'long', 'here').should.equal('some long thing here'); - }); - - it('should format array of array as simple string', function () { - format('many %s %s', 'things', testNestedArray).should.equal('many things (1, 2), (3, 4), (5, 6)'); - }); - - it('should format string using position field', function () { - format('some %1$s', 'thing').should.equal('some thing'); - format('some %1$s %1$s', 'thing').should.equal('some thing thing'); - format('some %1$s %s', 'thing', 'again').should.equal('some thing again'); - format('some %1$s %2$s', 'thing', 'again').should.equal('some thing again'); - format('some %1$s %2$s %1$s', 'thing', 'again').should.equal('some thing again thing'); - format('some %1$s %2$s %s %1$s', 'thing', 'again', 'some').should.equal('some thing again some thing'); - }); - - it('should not format string using position 0', function () { - (function () { - format('some %0$s', 'thing'); - }).should.throw(Error); - }); - - it('should not format string using position field with too few arguments', function () { - (function () { - format('some %2$s', 'thing'); - }).should.throw(Error); - }); + describe('%s', function () { + it('should format as a simple string', function () { + format('some %s here', 'thing').should.equal('some thing here'); + format('some %s thing %s', 'long', 'here').should.equal('some long thing here'); }); - describe('%%', function () { - it('should format as %', function () { - format('some %%', 'thing').should.equal('some %'); - }); + it('should format array of array as simple string', function () { + format('many %s %s', 'things', testNestedArray).should.equal('many things (1, 2), (3, 4), (5, 6)'); + }); - it('should not eat args', function () { - format('just %% a %s', 'test').should.equal('just % a test'); - }); + it('should format string using position field', function () { + format('some %1$s', 'thing').should.equal('some thing'); + format('some %1$s %1$s', 'thing').should.equal('some thing thing'); + format('some %1$s %s', 'thing', 'again').should.equal('some thing again'); + format('some %1$s %2$s', 'thing', 'again').should.equal('some thing again'); + format('some %1$s %2$s %1$s', 'thing', 'again').should.equal('some thing again thing'); + format('some %1$s %2$s %s %1$s', 'thing', 'again', 'some').should.equal('some thing again some thing'); + }); - it('should not format % using position field', function () { - format('%1$%', 'thing').should.equal('%1$%'); - }); + it('should not format string using position 0', function () { + (function () { + format('some %0$s', 'thing'); + }).should.throw(Error); }); - describe('%I', function () { - it('should format as an identifier', function () { - format('some %I', 'foo/bar/baz').should.equal('some "foo/bar/baz"'); - }); - - it('should not format array of array as an identifier', function () { - (function () { - format('many %I %I', 'foo/bar/baz', testNestedArray); - }).should.throw(Error); - }); - - it('should format identifier using position field', function () { - format('some %1$I', 'thing').should.equal('some thing'); - format('some %1$I %1$I', 'thing').should.equal('some thing thing'); - format('some %1$I %I', 'thing', 'again').should.equal('some thing again'); - format('some %1$I %2$I', 'thing', 'again').should.equal('some thing again'); - format('some %1$I %2$I %1$I', 'thing', 'again').should.equal('some thing again thing'); - format('some %1$I %2$I %I %1$I', 'thing', 'again', 'huh').should.equal('some thing again huh thing'); - }); - - it('should not format identifier using position 0', function () { - (function () { - format('some %0$I', 'thing'); - }).should.throw(Error); - }); - - it('should not format identifier using position field with too few arguments', function () { - (function () { - format('some %2$I', 'thing'); - }).should.throw(Error); - }); + it('should not format string using position field with too few arguments', function () { + (function () { + format('some %2$s', 'thing'); + }).should.throw(Error); }); + }); - describe('%L', function () { - it('should format as a literal', function () { - format('%L', "Tobi's").should.equal("'Tobi''s'"); - }); - - it('should format array of array as a literal', function () { - format('%L', testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); - }); - - it('should format literal using position field', function () { - format('some %1$L', 'thing').should.equal("some 'thing'"); - format('some %1$L %1$L', 'thing').should.equal("some 'thing' 'thing'"); - format('some %1$L %L', 'thing', 'again').should.equal("some 'thing' 'again'"); - format('some %1$L %2$L', 'thing', 'again').should.equal("some 'thing' 'again'"); - format('some %1$L %2$L %1$L', 'thing', 'again').should.equal("some 'thing' 'again' 'thing'"); - format('some %1$L %2$L %L %1$L', 'thing', 'again', 'some').should.equal("some 'thing' 'again' 'some' 'thing'"); - }); - - it('should not format literal using position 0', function () { - (function () { - format('some %0$L', 'thing'); - }).should.throw(Error); - }); - - it('should not format literal using position field with too few arguments', function () { - (function () { - format('some %2$L', 'thing'); - }).should.throw(Error); - }); + describe('%%', function () { + it('should format as %', function () { + format('some %%', 'thing').should.equal('some %'); }); -}); -describe('format.withArray(fmt, args)', function () { - describe('%s', function () { - it('should format as a simple string', function () { - format.withArray('some %s here', ['thing']).should.equal('some thing here'); - format.withArray('some %s thing %s', ['long', 'here']).should.equal('some long thing here'); - }); - - it('should format array of array as simple string', function () { - format.withArray('many %s %s', ['things', testNestedArray]).should.equal('many things (1, 2), (3, 4), (5, 6)'); - }); + it('should not eat args', function () { + format('just %% a %s', 'test').should.equal('just % a test'); }); - describe('%%', function () { - it('should format as %', function () { - format.withArray('some %%', ['thing']).should.equal('some %'); - }); + it('should not format % using position field', function () { + format('%1$%', 'thing').should.equal('%1$%'); + }); + }); - it('should not eat args', function () { - format.withArray('just %% a %s', ['test']).should.equal('just % a test'); - format.withArray('just %% a %s %s %s', ['test', 'again', 'and again']).should.equal('just % a test again and again'); - }); + describe('%I', function () { + it('should format as an identifier', function () { + format('some %I', 'foo/bar/baz').should.equal('some "foo/bar/baz"'); }); - describe('%I', function () { - it('should format as an identifier', function () { - format.withArray('some %I', ['foo/bar/baz']).should.equal('some "foo/bar/baz"'); - format.withArray('some %I and %I', ['foo/bar/baz', '#hey']).should.equal('some "foo/bar/baz" and "#hey"'); - }); - - it('should not format array of array as an identifier', function () { - (function () { - format.withArray('many %I %I', ['foo/bar/baz', testNestedArray]); - }).should.throw(Error); - }); + it('should format as an identifier', function () { + format('some %I', 'foo.bar').should.equal('some foo.bar'); }); - describe('%L', function () { - it('should format as a literal', function () { - format.withArray('%L', ["Tobi's"]).should.equal("'Tobi''s'"); - format.withArray('%L %L', ["Tobi's", "birthday"]).should.equal("'Tobi''s' 'birthday'"); - }); + it('should not format array of array as an identifier', function () { + (function () { + format('many %I %I', 'foo/bar/baz', testNestedArray); + }).should.throw(Error); + }); - it('should format array of array as a literal', function () { - format.withArray('%L', [testNestedArray]).should.equal("(1, 2), (3, 4), (5, 6)"); - }); + it('should format identifier using position field', function () { + format('some %1$I', 'thing').should.equal('some thing'); + format('some %1$I %1$I', 'thing').should.equal('some thing thing'); + format('some %1$I %I', 'thing', 'again').should.equal('some thing again'); + format('some %1$I %2$I', 'thing', 'again').should.equal('some thing again'); + format('some %1$I %2$I %1$I', 'thing', 'again').should.equal('some thing again thing'); + format('some %1$I %2$I %I %1$I', 'thing', 'again', 'huh').should.equal('some thing again huh thing'); }); -}); -describe('format.string(val)', function () { - it('should coerce to a string', function () { - format.string(undefined).should.equal(''); - format.string(null).should.equal(''); - format.string(true).should.equal('t'); - format.string(false).should.equal('f'); - format.string(0).should.equal('0'); - format.string(15).should.equal('15'); - format.string(-15).should.equal('-15'); - format.string(45.13).should.equal('45.13'); - format.string(-45.13).should.equal('-45.13'); - format.string('something').should.equal('something'); - format.string(testArray).should.equal('abc,1,t,2012-12-14 13:06:43.152+00,-Infinity,Infinity,NaN,1'); - format.string(testNestedArray).should.equal('(1, 2), (3, 4), (5, 6)'); - format.string(testDate).should.equal('2012-12-14 13:06:43.152+00'); - format.string(testObject).should.equal('{"a":1,"b":2}'); + it('should not format identifier using position 0', function () { + (function () { + format('some %0$I', 'thing'); + }).should.throw(Error); }); -}); -describe('format.ident(val)', function () { - it('should quote when necessary', function () { - format.ident('foo').should.equal('foo'); - format.ident('_foo').should.equal('_foo'); - format.ident('_foo_bar$baz').should.equal('_foo_bar$baz'); - format.ident('test.some.stuff').should.equal('"test.some.stuff"'); - format.ident('test."some".stuff').should.equal('"test.""some"".stuff"'); + it('should not format identifier using position field with too few arguments', function () { + (function () { + format('some %2$I', 'thing'); + }).should.throw(Error); }); + }); - it('should quote reserved words', function () { - format.ident('desc').should.equal('"desc"'); - format.ident('join').should.equal('"join"'); - format.ident('cross').should.equal('"cross"'); + describe('%L', function () { + it('should format as a literal', function () { + format('%L', "Tobi's").should.equal("'Tobi''s'"); }); - it('should quote', function () { - format.ident(true).should.equal('"t"'); - format.ident(false).should.equal('"f"'); - format.ident(0).should.equal('"0"'); - format.ident(15).should.equal('"15"'); - format.ident(-15).should.equal('"-15"'); - format.ident(45.13).should.equal('"45.13"'); - format.ident(-45.13).should.equal('"-45.13"'); - format.ident(testIdentArray).should.equal('abc,"AbC","1","t","2012-12-14 13:06:43.152+00","-Infinity","Infinity","NaN","1"'); - (function () { - format.ident(testNestedArray) - }).should.throw(Error); - format.ident(testDate).should.equal('"2012-12-14 13:06:43.152+00"'); + it('should format array of array as a literal', function () { + format('%L', testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); }); - it('should throw when undefined', function (done) { - try { - format.ident(undefined); - } catch (err) { - assert(err.message === 'SQL identifier cannot be null or undefined'); - done(); - } + it('should format literal using position field', function () { + format('some %1$L', 'thing').should.equal("some 'thing'"); + format('some %1$L %1$L', 'thing').should.equal("some 'thing' 'thing'"); + format('some %1$L %L', 'thing', 'again').should.equal("some 'thing' 'again'"); + format('some %1$L %2$L', 'thing', 'again').should.equal("some 'thing' 'again'"); + format('some %1$L %2$L %1$L', 'thing', 'again').should.equal("some 'thing' 'again' 'thing'"); + format('some %1$L %2$L %L %1$L', 'thing', 'again', 'some').should.equal("some 'thing' 'again' 'some' 'thing'"); }); - it('should throw when null', function (done) { - try { - format.ident(null); - } catch (err) { - assert(err.message === 'SQL identifier cannot be null or undefined'); - done(); - } + it('should not format literal using position 0', function () { + (function () { + format('some %0$L', 'thing'); + }).should.throw(Error); }); - it('should throw when object', function (done) { - try { - format.ident({}); - } catch (err) { - assert(err.message === 'SQL identifier cannot be an object'); - done(); - } + it('should not format literal using position field with too few arguments', function () { + (function () { + format('some %2$L', 'thing'); + }).should.throw(Error); }); + }); }); -describe('format.literal(val)', function () { - it('should return NULL for null', function () { - format.literal(null).should.equal('NULL'); - format.literal(undefined).should.equal('NULL'); +describe('format.withArray(fmt, args)', function () { + describe('%s', function () { + it('should format as a simple string', function () { + format.withArray('some %s here', ['thing']).should.equal('some thing here'); + format.withArray('some %s thing %s', ['long', 'here']).should.equal('some long thing here'); }); - it('should quote', function () { - format.literal(true).should.equal("'t'"); - format.literal(false).should.equal("'f'"); - format.literal(0).should.equal('0'); - format.literal(15).should.equal('15'); - format.literal(-15).should.equal('-15'); - format.literal(45.13).should.equal('45.13'); - format.literal(-45.13).should.equal('-45.13'); - format.literal('hello world').should.equal("'hello world'"); - format.literal(testArray).should.equal("'abc',1,'t',NULL,'2012-12-14 13:06:43.152+00','-Infinity','Infinity','NaN',1"); - format.literal(testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); - format.literal(testDate).should.equal("'2012-12-14 13:06:43.152+00'"); - format.literal(testObject).should.equal("'{\"a\":1,\"b\":2}'::jsonb"); + it('should format array of array as simple string', function () { + format.withArray('many %s %s', ['things', testNestedArray]).should.equal('many things (1, 2), (3, 4), (5, 6)'); }); + }); - it('should format quotes', function () { - format.literal("O'Reilly").should.equal("'O''Reilly'"); + describe('%%', function () { + it('should format as %', function () { + format.withArray('some %%', ['thing']).should.equal('some %'); }); - it('should format backslashes', function () { - format.literal('\\whoop\\').should.equal("E'\\\\whoop\\\\'"); + it('should not eat args', function () { + format.withArray('just %% a %s', ['test']).should.equal('just % a test'); + format.withArray('just %% a %s %s %s', ['test', 'again', 'and again']).should.equal('just % a test again and again'); }); + }); + + describe('%I', function () { + it('should format as an identifier', function () { + format.withArray('some %I', ['foo/bar/baz']).should.equal('some "foo/bar/baz"'); + format.withArray('some %I and %I', ['foo/bar/baz', '#hey']).should.equal('some "foo/bar/baz" and "#hey"'); + }); + + it('should not format array of array as an identifier', function () { + (function () { + format.withArray('many %I %I', ['foo/bar/baz', testNestedArray]); + }).should.throw(Error); + }); + }); + + describe('%L', function () { + it('should format as a literal', function () { + format.withArray('%L', ["Tobi's"]).should.equal("'Tobi''s'"); + format.withArray('%L %L', ["Tobi's", "birthday"]).should.equal("'Tobi''s' 'birthday'"); + }); + + it('should format array of array as a literal', function () { + format.withArray('%L', [testNestedArray]).should.equal("(1, 2), (3, 4), (5, 6)"); + }); + }); +}); + +describe('format.string(val)', function () { + it('should coerce to a string', function () { + format.string(undefined).should.equal(''); + format.string(null).should.equal(''); + format.string(true).should.equal('t'); + format.string(false).should.equal('f'); + format.string(0).should.equal('0'); + format.string(15).should.equal('15'); + format.string(-15).should.equal('-15'); + format.string(45.13).should.equal('45.13'); + format.string(-45.13).should.equal('-45.13'); + format.string('something').should.equal('something'); + format.string(testArray).should.equal('abc,1,t,2012-12-14 13:06:43.152+00,-Infinity,Infinity,NaN,1'); + format.string(testNestedArray).should.equal('(1, 2), (3, 4), (5, 6)'); + format.string(testDate).should.equal('2012-12-14 13:06:43.152+00'); + format.string(testObject).should.equal('{"a":1,"b":2}'); + }); +}); + +describe('format.ident(val)', function () { + it('should quote when necessary', function () { + format.ident('foo').should.equal('foo'); + format.ident('_foo').should.equal('_foo'); + format.ident('_foo_bar$baz').should.equal('_foo_bar$baz'); + format.ident('test.some.stuff').should.equal('test.some.stuff'); + format.ident('test."some".stuff').should.equal('"test.""some"".stuff"'); + }); + + it('should quote reserved words', function () { + format.ident('desc').should.equal('"desc"'); + format.ident('join').should.equal('"join"'); + format.ident('cross').should.equal('"cross"'); + }); + + it('should quote', function () { + format.ident(true).should.equal('"t"'); + format.ident(false).should.equal('"f"'); + format.ident(0).should.equal('"0"'); + format.ident(15).should.equal('"15"'); + format.ident(-15).should.equal('"-15"'); + format.ident(45.13).should.equal('"45.13"'); + format.ident(-45.13).should.equal('"-45.13"'); + format.ident(testIdentArray).should.equal('abc,"AbC","1","t","2012-12-14 13:06:43.152+00","-Infinity","Infinity","NaN","1"'); + (function () { + format.ident(testNestedArray) + }).should.throw(Error); + format.ident(testDate).should.equal('"2012-12-14 13:06:43.152+00"'); + }); + + it('should throw when undefined', function (done) { + try { + format.ident(undefined); + } catch (err) { + assert(err.message === 'SQL identifier cannot be null or undefined'); + done(); + } + }); + + it('should throw when null', function (done) { + try { + format.ident(null); + } catch (err) { + assert(err.message === 'SQL identifier cannot be null or undefined'); + done(); + } + }); + + it('should throw when object', function (done) { + try { + format.ident({}); + } catch (err) { + assert(err.message === 'SQL identifier cannot be an object'); + done(); + } + }); +}); + +describe('format.literal(val)', function () { + it('should return NULL for null', function () { + format.literal(null).should.equal('NULL'); + format.literal(undefined).should.equal('NULL'); + }); + + it('should quote', function () { + format.literal(true).should.equal("'t'"); + format.literal(false).should.equal("'f'"); + format.literal(0).should.equal('0'); + format.literal(15).should.equal('15'); + format.literal(-15).should.equal('-15'); + format.literal(45.13).should.equal('45.13'); + format.literal(-45.13).should.equal('-45.13'); + format.literal('hello world').should.equal("'hello world'"); + format.literal(testArray).should.equal("'abc',1,'t',NULL,'2012-12-14 13:06:43.152+00','-Infinity','Infinity','NaN',1"); + format.literal(testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); + format.literal(testDate).should.equal("'2012-12-14 13:06:43.152+00'"); + format.literal(testObject).should.equal("'{\"a\":1,\"b\":2}'::jsonb"); + }); + + it('should format quotes', function () { + format.literal("O'Reilly").should.equal("'O''Reilly'"); + }); + + it('should format backslashes', function () { + format.literal('\\whoop\\').should.equal("E'\\\\whoop\\\\'"); + }); }); \ No newline at end of file From 7a6c6d10778275a4ce99e523bed06abc0359a1dd Mon Sep 17 00:00:00 2001 From: cphil Date: Mon, 17 May 2021 15:26:15 -0700 Subject: [PATCH 16/21] 1.2.8 --- lib/index.d.ts | 18 ++++++++---------- lib/index.js | 12 ++++++------ package.json | 2 +- src/index.ts | 15 +++++++++------ 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/lib/index.d.ts b/lib/index.d.ts index e14ed8c..fae410b 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1,15 +1,13 @@ -declare const reservedMap: any; -declare const fmtPattern: { - ident: string; - literal: string; - string: string; -}; -declare function formatDate(date: string): string; -declare function isReserved(value: string): boolean; -declare function arrayToList(useSpace: boolean, array: any[], formatter: (value: any) => string): string; declare function quoteIdent(value: any): string; declare function quoteLiteral(value: any): string; declare function quoteString(value: any): string; -declare function config(cfg: any): void; declare function formatWithArray(fmt: any, parameters: any): any; declare function format(fmt: string, ...args: any[]): string; +declare namespace format { + var config: (cfg: any) => void; + var ident: typeof quoteIdent; + var literal: typeof quoteLiteral; + var string: typeof quoteString; + var withArray: typeof formatWithArray; +} +export = format; diff --git a/lib/index.js b/lib/index.js index 4833400..1402957 100644 --- a/lib/index.js +++ b/lib/index.js @@ -250,9 +250,9 @@ function format(fmt) { } return formatWithArray(fmt, args); } -exports = module.exports = format; -exports.config = config; -exports.ident = quoteIdent; -exports.literal = quoteLiteral; -exports.string = quoteString; -exports.withArray = formatWithArray; +format.config = config; +format.ident = quoteIdent; +format.literal = quoteLiteral; +format.string = quoteString; +format.withArray = formatWithArray; +module.exports = format; diff --git a/package.json b/package.json index 5ad2de7..34a50c4 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "license": "MIT", "homepage": "https://github.com/cphillips/node-pg-format", "description": "Node.js implementation of PostgreSQL's format() to safely create dynamic SQL queries.", - "version": "1.2.7", + "version": "1.2.8", "repository": { "type": "git", "url": "https://github.com/cphillips/node-pg-format.git" diff --git a/src/index.ts b/src/index.ts index 91f8878..44befa1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -247,9 +247,12 @@ function format(fmt: string, ...args: any[]): string { return formatWithArray(fmt, args) } -exports = module.exports = format -exports.config = config -exports.ident = quoteIdent -exports.literal = quoteLiteral -exports.string = quoteString -exports.withArray = formatWithArray \ No newline at end of file + +format.config = config +format.ident = quoteIdent +format.literal = quoteLiteral +format.string = quoteString +format.withArray = formatWithArray + +export = format + From 03a118f9ec0e2e76e47903bfcfc94f3cc94e80bd Mon Sep 17 00:00:00 2001 From: Clint Phillips Date: Sun, 17 Apr 2022 15:39:56 -0700 Subject: [PATCH 17/21] Move test system to typescript --- README.md | 16 +- package-lock.json | 3759 +++++++++++++++++++---- package.json | 18 +- src/index.ts | 22 +- src/reserved.ts | 2 +- test/index.js => src/test/index.spec.ts | 174 +- tsconfig.json | 4 +- 7 files changed, 3336 insertions(+), 659 deletions(-) rename test/index.js => src/test/index.spec.ts (56%) diff --git a/README.md b/README.md index 18662f2..c185eb9 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Node.js implementation of [PostgreSQL format()](http://www.postgresql.org/docs/9 ## Example ```js -const format = require('pg-format'); +import { format } from 'node-pg-format'; const sql = format('SELECT * FROM %I WHERE my_col = %L %s', 'my_table', 34, 'LIMIT 10'); console.log(sql); // SELECT * FROM my_table WHERE my_col = 34 LIMIT 10 ``` @@ -26,7 +26,7 @@ Returns a formatted string based on ```fmt``` which has a style similar to the C #### Argument position You can define where an argument is positioned using ```n$``` where ```n``` is the argument index starting at 1. ```js -const format = require('pg-format'); +import { format } from 'node-pg-format'; const sql = format('SELECT %1$L, %1$L, %L', 34, 'test'); console.log(sql); // SELECT 34, 34, 'test' ``` @@ -34,7 +34,7 @@ console.log(sql); // SELECT 34, 34, 'test' ### format.config(cfg) Changes the global configuration. You can change which letters are used to denote identifiers, literals, and strings in the formatted string. This is useful when the formatted string contains a PL/pgSQL function which calls [PostgreSQL format()](http://www.postgresql.org/docs/9.3/static/functions-string.html#FUNCTIONS-STRING-FORMAT) itself. ```js -const format = require('pg-format'); +import { format } from 'node-pg-format'; format.config({ pattern: { ident: 'V', @@ -45,16 +45,16 @@ format.config({ format.config(); // reset to default ``` -### format.ident(input) +### quoteIdent(input) Returns the input as an escaped SQL identifier string. ```undefined```, ```null```, and objects will throw an error. -### format.literal(input) +### quoteLiteral(input) Returns the input as an escaped SQL literal string. ```undefined``` and ```null``` will return ```'NULL'```; -### format.string(input) +### quoteString(input) Returns the input as a simple string. ```undefined``` and ```null``` will return an empty string. If an array element is ```undefined``` or ```null```, it will be removed from the output string. -### format.withArray(fmt, array) +### formatWithArray(fmt, array) Same as ```format(fmt, ...)``` except parameters are provided in an array rather than as function arguments. This is useful when dynamically creating a SQL query and the number of parameters is unknown or variable. ## Node Buffers @@ -65,7 +65,7 @@ For arrays, each element is escaped when appropriate and concatenated to a comma For objects, ```JSON.stringify()``` is called and the resulting string is escaped if appropriate. Objects can be used for literals (```%L```) and strings (```%s```), but not identifiers (```%I```). See the example below. ```js -const format = require('pg-format'); +import { format } from 'node-pg-format'; const myArray = [ 1, 2, 3 ]; const myObject = { a: 1, b: 2 }; diff --git a/package-lock.json b/package-lock.json index 695ddd3..acaa847 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,569 +1,3244 @@ { - "name": "node-pg-format", - "version": "1.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/node": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz", - "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==", - "dev": true - }, - "abbrev": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", - "dev": true - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true, - "optional": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } + "name": "node-pg-format", + "version": "1.2.8", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "node-pg-format", + "version": "1.2.8", + "license": "MIT", + "dependencies": { + "istanbul": "^0.4.5" + }, + "devDependencies": { + "@types/expect": "^24.3.0", + "@types/mocha": "^9.1.0", + "@types/node": "^15.0.2", + "mocha": "^9.2.2", + "should": "^13.2.3", + "ts-mocha": "^9.0.2", + "typescript": "^4.2.4" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", + "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/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/@babel/highlight/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/@babel/highlight/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/@babel/highlight/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/@babel/highlight/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/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@types/expect": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/expect/-/expect-24.3.0.tgz", + "integrity": "sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ==", + "deprecated": "This is a stub types definition. expect provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "expect": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true, + "optional": true + }, + "node_modules/@types/mocha": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", + "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "dev": true + }, + "node_modules/@types/node": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz", + "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=" + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "optional": true, + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "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=" + }, + "node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/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/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dependencies": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { + "source-map": "~0.2.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "optional": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "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/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "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/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "node_modules/istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "deprecated": "This module is no longer maintained, try this instead:\n npm i nyc\nVisit https://istanbul.js.org/integrations for other alternatives.", + "dependencies": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "istanbul": "lib/cli.js" + } + }, + "node_modules/istanbul/node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js-yaml/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==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "optional": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "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": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "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/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "commander": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", - "dev": true + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "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 + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "dev": true, + "dependencies": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "node_modules/should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "dependencies": { + "should-type": "^1.4.0" + } + }, + "node_modules/should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "dependencies": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "node_modules/should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "node_modules/should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "dev": true, + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "node_modules/should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-mocha": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-9.0.2.tgz", + "integrity": "sha512-WyQjvnzwrrubl0JT7EC1yWmNpcsU3fOuBFfdps30zbmFBgKniSaSOyZMZx+Wq7kytUs5CY+pEbSYEbGfIKnXTw==", + "dev": true, + "dependencies": { + "ts-node": "7.0.1" + }, + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "optionalDependencies": { + "tsconfig-paths": "^3.5.0" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X" + } + }, + "node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "optional": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uglify-js": { + "version": "3.15.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.4.tgz", + "integrity": "sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", + "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^1.9.0" + } }, - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, - "requires": { - "ms": "0.7.1" - } + "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, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "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, + "requires": { + "color-name": "1.1.3" + } }, - "diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", - "dev": true + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "escape-string-regexp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", - "dev": true + "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 + } + } + }, + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/expect": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/expect/-/expect-24.3.0.tgz", + "integrity": "sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ==", + "dev": true, + "requires": { + "expect": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true, + "optional": true + }, + "@types/mocha": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", + "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "dev": true + }, + "@types/node": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz", + "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=" + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "optional": true + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, - "escodegen": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz", - "integrity": "sha1-MOz89mypjcZ80v0WKr626vqM5vw=", - "dev": true, - "requires": { - "esprima": "^1.2.2", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.5.0", - "source-map": "~0.2.0" - }, - "dependencies": { - "esprima": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", - "integrity": "sha1-CZNQL+r2aBODJXVvMPmlH+7sEek=", - "dev": true - } - } + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "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 + } + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + }, + "dependencies": { + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + } + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "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 + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + }, + "jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "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 + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, - "estraverse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "fast-levenshtein": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz", - "integrity": "sha1-AXjc3uAjuSkFGTrwlZ6KdjnP3Lk=", - "dev": true - }, - "fileset": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz", - "integrity": "sha1-WI74lzxmI7KnbfRlEFaWuWqsgGc=", - "dev": true, - "requires": { - "glob": "5.x", - "minimatch": "2.x" - } + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + } + } + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "optional": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", - "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", - "dev": true - }, - "growl": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz", - "integrity": "sha1-Sy3sjZB+k9szZiTc7AGDUC+MlCg=", - "dev": true - }, - "handlebars": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", - "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "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" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } } + } }, "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "istanbul": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.2.tgz", - "integrity": "sha1-dl5yi5RVvt222qe5zsS5w8Pt5Ic=", - "dev": true, - "requires": { - "abbrev": "1.0.x", - "async": "1.x", - "escodegen": "1.7.x", - "esprima": "2.7.x", - "fileset": "0.2.x", - "handlebars": "^4.0.1", - "js-yaml": "3.x", - "mkdirp": "0.5.x", - "nopt": "3.x", - "once": "1.x", - "resolve": "1.1.x", - "supports-color": "^3.1.0", - "which": "^1.1.1", - "wordwrap": "^1.0.0" - } - }, - "jade": { - "version": "0.26.3", - "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", - "dev": true, - "requires": { - "commander": "0.6.1", - "mkdirp": "0.3.0" - }, - "dependencies": { - "commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true - }, - "mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "dev": true - } - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "dependencies": { - "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 - } - } - }, - "levn": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz", - "integrity": "sha1-uo0znQykphDjo/FFucr0iAcVUFQ=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.0", - "type-check": "~0.3.1" - } - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } }, "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", - "dev": true, - "requires": { - "brace-expansion": "^1.0.0" - } - }, - "minimist": { - "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.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "mocha": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.4.5.tgz", - "integrity": "sha1-FRdo3Sh161G8gpXpgAAm6fK7OY8=", - "dev": true, - "requires": { - "commander": "2.3.0", - "debug": "2.2.0", - "diff": "1.4.0", - "escape-string-regexp": "1.0.2", - "glob": "3.2.3", - "growl": "1.8.1", - "jade": "0.26.3", - "mkdirp": "0.5.1", - "supports-color": "1.2.0" - }, - "dependencies": { - "glob": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", - "integrity": "sha1-4xPusknHr/qlxHUoaw4RW1mDlGc=", - "dev": true, - "requires": { - "graceful-fs": "~2.0.0", - "inherits": "2", - "minimatch": "~0.2.11" - } - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "supports-color": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", - "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", - "dev": true - } - } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz", - "integrity": "sha1-t1qJlaLUF98ltuTjhi9QqohlE2g=", - "dev": true, - "requires": { - "deep-is": "~0.1.2", - "fast-levenshtein": "~1.0.0", - "levn": "~0.2.5", - "prelude-ls": "~1.1.1", - "type-check": "~0.3.1", - "wordwrap": "~0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - } - } - }, - "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 - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - }, - "should": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/should/-/should-8.2.1.tgz", - "integrity": "sha1-aW3q/mMbOSbgc/X2xumHjipVPKE=", - "dev": true, - "requires": { - "should-equal": "0.7.2", - "should-format": "0.3.2", - "should-type": "0.2.0" - } - }, - "should-equal": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-0.7.2.tgz", - "integrity": "sha1-pqlj2/UBuT7TS3gHrn1/BC/CTKg=", - "dev": true, - "requires": { - "should-type": "0.2.0" - } - }, - "should-format": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-0.3.2.tgz", - "integrity": "sha1-pZgx4Bot3uFJkRvHFIvlyAMZ4f8=", - "dev": true, - "requires": { - "should-type": "0.2.0" - } - }, - "should-type": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-0.2.0.tgz", - "integrity": "sha1-ZwfvlVKdmJ3MCY/gdTqx+RNrt/Y=", - "dev": true - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", - "dev": true, - "optional": true, - "requires": { - "amdefine": ">=0.0.4" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } }, "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "typescript": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", - "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==" - }, - "uglify-js": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.1.tgz", - "integrity": "sha512-RjxApKkrPJB6kjJxQS3iZlf///REXWYxYJxO/MpmlQzVkDWVI3PSnCBWezMecmTU/TRkNxrl8bmsfFQCp+LO+Q==", - "dev": true, - "optional": true + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "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=" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "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 + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "dev": true, + "requires": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "requires": { + "should-type": "^1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "requires": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "dev": true, + "requires": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "optional": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "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, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-mocha": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-9.0.2.tgz", + "integrity": "sha512-WyQjvnzwrrubl0JT7EC1yWmNpcsU3fOuBFfdps30zbmFBgKniSaSOyZMZx+Wq7kytUs5CY+pEbSYEbGfIKnXTw==", + "dev": true, + "requires": { + "ts-node": "7.0.1", + "tsconfig-paths": "^3.5.0" + } + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "dependencies": { + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true } + } + }, + "tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "optional": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "typescript": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "dev": true + }, + "uglify-js": { + "version": "3.15.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.4.tgz", + "integrity": "sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==", + "optional": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } + } } diff --git a/package.json b/package.json index 34a50c4..961accd 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "license": "MIT", "homepage": "https://github.com/cphillips/node-pg-format", "description": "Node.js implementation of PostgreSQL's format() to safely create dynamic SQL queries.", - "version": "1.2.8", + "version": "1.3.0", "repository": { "type": "git", "url": "https://github.com/cphillips/node-pg-format.git" @@ -20,18 +20,18 @@ "engines": { "node": ">=4.0" }, - "dependencies": {}, "devDependencies": { + "@types/expect": "^24.3.0", + "@types/mocha": "^9.1.0", "@types/node": "^15.0.2", - "typescript": "^4.2.4", - "istanbul": "0.4.2", - "mocha": "2.4.5", - "should": "8.2.1" + "mocha": "^9.2.2", + "should": "^13.2.3", + "ts-mocha": "^9.0.2", + "typescript": "^4.2.4" }, "scripts": { "prepublish": "npm build", "build": "tsc", - "test": "node ./node_modules/mocha/bin/mocha", - "cover-test": "node_modules/.bin/istanbul cover node_modules/.bin/_mocha" + "test": "ts-mocha -p tsconfig.json src/**/*.spec.ts" } -} \ No newline at end of file +} diff --git a/src/index.ts b/src/index.ts index 44befa1..600f1a5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ // reserved Postgres words -const reservedMap = require(__dirname + '/reserved.js') +import reservedMap from './reserved' const fmtPattern = { ident: 'I', @@ -34,7 +34,7 @@ function arrayToList(useSpace:boolean, array:any[], formatter:(value:any)=>strin } // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c -function quoteIdent(value:any): string { +export function quoteIdent(value:any): string { if (value === undefined || value === null) { throw new Error('SQL identifier cannot be null or undefined') @@ -84,7 +84,7 @@ function quoteIdent(value:any): string { } // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c -function quoteLiteral(value) { +export function quoteLiteral(value) { let literal = '' let explicitCast: string | null = null @@ -154,7 +154,7 @@ function quoteLiteral(value) { return quoted } -function quoteString(value): string { +export function quoteString(value): string { if (value === undefined || value === null) { return '' @@ -185,7 +185,7 @@ function quoteString(value): string { return value.toString().slice(0) // return copy } -function config(cfg) { +export function config(cfg) { // default fmtPattern.ident = 'I' @@ -199,7 +199,7 @@ function config(cfg) { } } -function formatWithArray(fmt, parameters) { +export function formatWithArray(fmt, parameters) { let index = 0 let params = parameters @@ -243,16 +243,8 @@ function formatWithArray(fmt, parameters) { }) } -function format(fmt: string, ...args: any[]): string { +export function format(fmt: string, ...args: any[]): string { return formatWithArray(fmt, args) } -format.config = config -format.ident = quoteIdent -format.literal = quoteLiteral -format.string = quoteString -format.withArray = formatWithArray - -export = format - diff --git a/src/reserved.ts b/src/reserved.ts index faf03b8..977d5a9 100644 --- a/src/reserved.ts +++ b/src/reserved.ts @@ -2,7 +2,7 @@ // PostgreSQL reserved words // see: https://www.postgresql.org/docs/current/sql-keywords-appendix.html // -module.exports = { +export default { "AES128": true, "AES256": true, "ALL": true, diff --git a/test/index.js b/src/test/index.spec.ts similarity index 56% rename from test/index.js rename to src/test/index.spec.ts index 0d56c00..a7269e3 100644 --- a/test/index.js +++ b/src/test/index.spec.ts @@ -1,23 +1,33 @@ -// -// Original source from https://github.com/segmentio/pg-escape -// -var assert = require('assert'); -var format = require(__dirname + '/../lib'); -var should = require('should'); - -var testDate = new Date(Date.UTC(2012, 11, 14, 13, 6, 43, 152)); -var testArray = ['abc', 1, true, null, testDate, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, 1n]; -var testIdentArray = ['abc', 'AbC', 1, true, testDate, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, 1n]; -var testObject = { a: 1, b: 2 }; -var testNestedArray = [[1, 2], [3, 4], [5, 6]]; +import { + format, + formatWithArray, + quoteIdent, + quoteLiteral, + quoteString, + config +} from '..' +import assert from 'assert' +import 'should' +import { exit } from 'process'; + + +const testDate = new Date(Date.UTC(2012, 11, 14, 13, 6, 43, 152)); +const testArray = ['abc', 1, true, null, testDate, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, 1n]; +const testIdentArray = ['abc', 'AbC', 1, true, testDate, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, 1n]; +const testObject = { a: 1, b: 2 }; +const testNestedArray = [[1, 2], [3, 4], [5, 6]]; describe('format(fmt, ...)', function () { describe('%s', function () { it('should format as a simple string', function () { + format('some %s here', 'thing').should.equal('some thing here'); format('some %s thing %s', 'long', 'here').should.equal('some long thing here'); + }); + + it('should format array of array as simple string', function () { format('many %s %s', 'things', testNestedArray).should.equal('many things (1, 2), (3, 4), (5, 6)'); }); @@ -127,107 +137,107 @@ describe('format(fmt, ...)', function () { }); }); -describe('format.withArray(fmt, args)', function () { +describe('formatWithArray(fmt, args)', function () { describe('%s', function () { it('should format as a simple string', function () { - format.withArray('some %s here', ['thing']).should.equal('some thing here'); - format.withArray('some %s thing %s', ['long', 'here']).should.equal('some long thing here'); + formatWithArray('some %s here', ['thing']).should.equal('some thing here'); + formatWithArray('some %s thing %s', ['long', 'here']).should.equal('some long thing here'); }); it('should format array of array as simple string', function () { - format.withArray('many %s %s', ['things', testNestedArray]).should.equal('many things (1, 2), (3, 4), (5, 6)'); + formatWithArray('many %s %s', ['things', testNestedArray]).should.equal('many things (1, 2), (3, 4), (5, 6)'); }); }); describe('%%', function () { it('should format as %', function () { - format.withArray('some %%', ['thing']).should.equal('some %'); + formatWithArray('some %%', ['thing']).should.equal('some %'); }); it('should not eat args', function () { - format.withArray('just %% a %s', ['test']).should.equal('just % a test'); - format.withArray('just %% a %s %s %s', ['test', 'again', 'and again']).should.equal('just % a test again and again'); + formatWithArray('just %% a %s', ['test']).should.equal('just % a test'); + formatWithArray('just %% a %s %s %s', ['test', 'again', 'and again']).should.equal('just % a test again and again'); }); }); describe('%I', function () { it('should format as an identifier', function () { - format.withArray('some %I', ['foo/bar/baz']).should.equal('some "foo/bar/baz"'); - format.withArray('some %I and %I', ['foo/bar/baz', '#hey']).should.equal('some "foo/bar/baz" and "#hey"'); + formatWithArray('some %I', ['foo/bar/baz']).should.equal('some "foo/bar/baz"'); + formatWithArray('some %I and %I', ['foo/bar/baz', '#hey']).should.equal('some "foo/bar/baz" and "#hey"'); }); it('should not format array of array as an identifier', function () { (function () { - format.withArray('many %I %I', ['foo/bar/baz', testNestedArray]); + formatWithArray('many %I %I', ['foo/bar/baz', testNestedArray]); }).should.throw(Error); }); }); describe('%L', function () { it('should format as a literal', function () { - format.withArray('%L', ["Tobi's"]).should.equal("'Tobi''s'"); - format.withArray('%L %L', ["Tobi's", "birthday"]).should.equal("'Tobi''s' 'birthday'"); + formatWithArray('%L', ["Tobi's"]).should.equal("'Tobi''s'"); + formatWithArray('%L %L', ["Tobi's", "birthday"]).should.equal("'Tobi''s' 'birthday'"); }); it('should format array of array as a literal', function () { - format.withArray('%L', [testNestedArray]).should.equal("(1, 2), (3, 4), (5, 6)"); + formatWithArray('%L', [testNestedArray]).should.equal("(1, 2), (3, 4), (5, 6)"); }); }); }); -describe('format.string(val)', function () { +describe('quoteString(val)', function () { it('should coerce to a string', function () { - format.string(undefined).should.equal(''); - format.string(null).should.equal(''); - format.string(true).should.equal('t'); - format.string(false).should.equal('f'); - format.string(0).should.equal('0'); - format.string(15).should.equal('15'); - format.string(-15).should.equal('-15'); - format.string(45.13).should.equal('45.13'); - format.string(-45.13).should.equal('-45.13'); - format.string('something').should.equal('something'); - format.string(testArray).should.equal('abc,1,t,2012-12-14 13:06:43.152+00,-Infinity,Infinity,NaN,1'); - format.string(testNestedArray).should.equal('(1, 2), (3, 4), (5, 6)'); - format.string(testDate).should.equal('2012-12-14 13:06:43.152+00'); - format.string(testObject).should.equal('{"a":1,"b":2}'); + quoteString(undefined).should.equal(''); + quoteString(null).should.equal(''); + quoteString(true).should.equal('t'); + quoteString(false).should.equal('f'); + quoteString(0).should.equal('0'); + quoteString(15).should.equal('15'); + quoteString(-15).should.equal('-15'); + quoteString(45.13).should.equal('45.13'); + quoteString(-45.13).should.equal('-45.13'); + quoteString('something').should.equal('something'); + quoteString(testArray).should.equal('abc,1,t,2012-12-14 13:06:43.152+00,-Infinity,Infinity,NaN,1'); + quoteString(testNestedArray).should.equal('(1, 2), (3, 4), (5, 6)'); + quoteString(testDate).should.equal('2012-12-14 13:06:43.152+00'); + quoteString(testObject).should.equal('{"a":1,"b":2}'); }); }); -describe('format.ident(val)', function () { +describe('quoteIdent(val)', function () { it('should quote when necessary', function () { - format.ident('foo').should.equal('foo'); - format.ident('_foo').should.equal('_foo'); - format.ident('_foo_bar$baz').should.equal('_foo_bar$baz'); - format.ident('test.some.stuff').should.equal('test.some.stuff'); - format.ident('test."some".stuff').should.equal('"test.""some"".stuff"'); + quoteIdent('foo').should.equal('foo'); + quoteIdent('_foo').should.equal('_foo'); + quoteIdent('_foo_bar$baz').should.equal('_foo_bar$baz'); + quoteIdent('test.some.stuff').should.equal('test.some.stuff'); + quoteIdent('test."some".stuff').should.equal('"test.""some"".stuff"'); }); it('should quote reserved words', function () { - format.ident('desc').should.equal('"desc"'); - format.ident('join').should.equal('"join"'); - format.ident('cross').should.equal('"cross"'); + quoteIdent('desc').should.equal('"desc"'); + quoteIdent('join').should.equal('"join"'); + quoteIdent('cross').should.equal('"cross"'); }); it('should quote', function () { - format.ident(true).should.equal('"t"'); - format.ident(false).should.equal('"f"'); - format.ident(0).should.equal('"0"'); - format.ident(15).should.equal('"15"'); - format.ident(-15).should.equal('"-15"'); - format.ident(45.13).should.equal('"45.13"'); - format.ident(-45.13).should.equal('"-45.13"'); - format.ident(testIdentArray).should.equal('abc,"AbC","1","t","2012-12-14 13:06:43.152+00","-Infinity","Infinity","NaN","1"'); + quoteIdent(true).should.equal('"t"'); + quoteIdent(false).should.equal('"f"'); + quoteIdent(0).should.equal('"0"'); + quoteIdent(15).should.equal('"15"'); + quoteIdent(-15).should.equal('"-15"'); + quoteIdent(45.13).should.equal('"45.13"'); + quoteIdent(-45.13).should.equal('"-45.13"'); + quoteIdent(testIdentArray).should.equal('abc,"AbC","1","t","2012-12-14 13:06:43.152+00","-Infinity","Infinity","NaN","1"'); (function () { - format.ident(testNestedArray) + quoteIdent(testNestedArray) }).should.throw(Error); - format.ident(testDate).should.equal('"2012-12-14 13:06:43.152+00"'); + quoteIdent(testDate).should.equal('"2012-12-14 13:06:43.152+00"'); }); it('should throw when undefined', function (done) { try { - format.ident(undefined); - } catch (err) { + quoteIdent(undefined); + } catch (err: any) { assert(err.message === 'SQL identifier cannot be null or undefined'); done(); } @@ -235,8 +245,8 @@ describe('format.ident(val)', function () { it('should throw when null', function (done) { try { - format.ident(null); - } catch (err) { + quoteIdent(null); + } catch (err: any) { assert(err.message === 'SQL identifier cannot be null or undefined'); done(); } @@ -244,40 +254,40 @@ describe('format.ident(val)', function () { it('should throw when object', function (done) { try { - format.ident({}); - } catch (err) { + quoteIdent({}); + } catch (err: any) { assert(err.message === 'SQL identifier cannot be an object'); done(); } }); }); -describe('format.literal(val)', function () { +describe('quoteLiteral(val)', function () { it('should return NULL for null', function () { - format.literal(null).should.equal('NULL'); - format.literal(undefined).should.equal('NULL'); + quoteLiteral(null).should.equal('NULL'); + quoteLiteral(undefined).should.equal('NULL'); }); it('should quote', function () { - format.literal(true).should.equal("'t'"); - format.literal(false).should.equal("'f'"); - format.literal(0).should.equal('0'); - format.literal(15).should.equal('15'); - format.literal(-15).should.equal('-15'); - format.literal(45.13).should.equal('45.13'); - format.literal(-45.13).should.equal('-45.13'); - format.literal('hello world').should.equal("'hello world'"); - format.literal(testArray).should.equal("'abc',1,'t',NULL,'2012-12-14 13:06:43.152+00','-Infinity','Infinity','NaN',1"); - format.literal(testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); - format.literal(testDate).should.equal("'2012-12-14 13:06:43.152+00'"); - format.literal(testObject).should.equal("'{\"a\":1,\"b\":2}'::jsonb"); + quoteLiteral(true).should.equal("'t'"); + quoteLiteral(false).should.equal("'f'"); + quoteLiteral(0).should.equal('0'); + quoteLiteral(15).should.equal('15'); + quoteLiteral(-15).should.equal('-15'); + quoteLiteral(45.13).should.equal('45.13'); + quoteLiteral(-45.13).should.equal('-45.13'); + quoteLiteral('hello world').should.equal("'hello world'"); + quoteLiteral(testArray).should.equal("'abc',1,'t',NULL,'2012-12-14 13:06:43.152+00','-Infinity','Infinity','NaN',1"); + quoteLiteral(testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); + quoteLiteral(testDate).should.equal("'2012-12-14 13:06:43.152+00'"); + quoteLiteral(testObject).should.equal("'{\"a\":1,\"b\":2}'::jsonb"); }); it('should format quotes', function () { - format.literal("O'Reilly").should.equal("'O''Reilly'"); + quoteLiteral("O'Reilly").should.equal("'O''Reilly'"); }); it('should format backslashes', function () { - format.literal('\\whoop\\').should.equal("E'\\\\whoop\\\\'"); + quoteLiteral('\\whoop\\').should.equal("E'\\\\whoop\\\\'"); }); }); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 417a1c5..d9227c3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,9 +4,9 @@ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "target": "ES2015", /* 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. */ + // "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', 'react', 'react-jsx' or 'react-jsxdev'. */ From 4932038165f833aa5568148b3e5f293e16a796b8 Mon Sep 17 00:00:00 2001 From: Clint Phillips Date: Sun, 17 Apr 2022 16:06:43 -0700 Subject: [PATCH 18/21] Allow mixed case w/o quoted identifies --- Makefile | 7 -- lib/index.d.ts | 19 +-- lib/index.js | 77 ++++++------ lib/reserved.d.ts | 157 ++++++++++++++++++++++++ lib/reserved.js | 3 +- lib/test/index.spec.d.ts | 1 + lib/test/index.spec.js | 251 +++++++++++++++++++++++++++++++++++++++ package.json | 2 +- src/index.ts | 3 +- src/test/index.spec.ts | 15 ++- 10 files changed, 466 insertions(+), 69 deletions(-) delete mode 100644 Makefile create mode 100644 lib/test/index.spec.d.ts create mode 100644 lib/test/index.spec.js diff --git a/Makefile b/Makefile deleted file mode 100644 index a605311..0000000 --- a/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -.PHONY: publish test - -publish: - npm publish . - -test: - @./node_modules/.bin/mocha --require should --reporter dot --bail \ No newline at end of file diff --git a/lib/index.d.ts b/lib/index.d.ts index fae410b..ece5ea7 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1,13 +1,6 @@ -declare function quoteIdent(value: any): string; -declare function quoteLiteral(value: any): string; -declare function quoteString(value: any): string; -declare function formatWithArray(fmt: any, parameters: any): any; -declare function format(fmt: string, ...args: any[]): string; -declare namespace format { - var config: (cfg: any) => void; - var ident: typeof quoteIdent; - var literal: typeof quoteLiteral; - var string: typeof quoteString; - var withArray: typeof formatWithArray; -} -export = format; +export declare function quoteIdent(value: any): string; +export declare function quoteLiteral(value: any): string; +export declare function quoteString(value: any): string; +export declare function config(cfg: any): void; +export declare function formatWithArray(fmt: any, parameters: any): any; +export declare function format(fmt: string, ...args: any[]): string; diff --git a/lib/index.js b/lib/index.js index 1402957..f419665 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,7 +1,12 @@ "use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.format = exports.formatWithArray = exports.config = exports.quoteString = exports.quoteLiteral = exports.quoteIdent = void 0; // reserved Postgres words -var reservedMap = require(__dirname + '/reserved.js'); -var fmtPattern = { +const reserved_1 = __importDefault(require("./reserved")); +const fmtPattern = { ident: 'I', literal: 'L', string: 's', @@ -13,15 +18,15 @@ function formatDate(date) { return date; } function isReserved(value) { - if (reservedMap[value.toUpperCase()]) { + if (reserved_1.default[value.toUpperCase()]) { return true; } return false; } function arrayToList(useSpace, array, formatter) { - var sql = ''; + let sql = ''; sql += useSpace ? ' (' : '('; - for (var i = 0; i < array.length; i++) { + for (let i = 0; i < array.length; i++) { sql += (i === 0 ? '' : ', ') + formatter(array[i]); } sql += ')'; @@ -45,8 +50,8 @@ function quoteIdent(value) { throw new Error('SQL identifier cannot be a buffer'); } else if (Array.isArray(value) === true) { - var temp = []; - for (var i = 0; i < value.length; i++) { + const temp = []; + for (let i = 0; i < value.length; i++) { if (Array.isArray(value[i]) === true) { throw new Error('Nested array to grouped list conversion is not supported for SQL identifier'); } @@ -59,14 +64,14 @@ function quoteIdent(value) { else if (value === Object(value)) { throw new Error('SQL identifier cannot be an object'); } - var ident = value.toString().slice(0); // create copy + const ident = value.toString().slice(0); // create copy // do not quote a valid, unquoted identifier if (/^[a-z_][a-z0-9_$.]*$/.test(ident) === true && isReserved(ident) === false) { return ident; } - var quoted = '"'; - for (var i = 0; i < ident.length; i++) { - var c = ident[i]; + let quoted = '"'; + for (let i = 0; i < ident.length; i++) { + const c = ident[i]; if (c === '"') { quoted += c + c; } @@ -77,10 +82,11 @@ function quoteIdent(value) { quoted += '"'; return quoted; } +exports.quoteIdent = quoteIdent; // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c function quoteLiteral(value) { - var literal = ''; - var explicitCast = null; + let literal = ''; + let explicitCast = null; if (value === undefined || value === null) { return 'NULL'; } @@ -112,8 +118,8 @@ function quoteLiteral(value) { return "E'\\\\x" + value.toString('hex') + "'"; } else if (Array.isArray(value) === true) { - var temp = []; - for (var i = 0; i < value.length; i++) { + const temp = []; + for (let i = 0; i < value.length; i++) { if (Array.isArray(value[i]) === true) { temp.push(arrayToList(i !== 0, value[i], quoteLiteral)); } @@ -130,10 +136,10 @@ function quoteLiteral(value) { else { literal = value.toString().slice(0); // create copy } - var hasBackslash = false; - var quoted = '\''; - for (var i = 0; i < literal.length; i++) { - var c = literal[i]; + let hasBackslash = false; + let quoted = '\''; + for (let i = 0; i < literal.length; i++) { + const c = literal[i]; if (c === '\'') { quoted += c + c; } @@ -154,6 +160,7 @@ function quoteLiteral(value) { } return quoted; } +exports.quoteLiteral = quoteLiteral; function quoteString(value) { if (value === undefined || value === null) { return ''; @@ -171,8 +178,8 @@ function quoteString(value) { return '\\x' + value.toString('hex'); } else if (Array.isArray(value) === true) { - var temp = []; - for (var i = 0; i < value.length; i++) { + const temp = []; + for (let i = 0; i < value.length; i++) { if (value[i] !== null && value[i] !== undefined) { if (Array.isArray(value[i]) === true) { temp.push(arrayToList(i !== 0, value[i], quoteString)); @@ -189,6 +196,7 @@ function quoteString(value) { } return value.toString().slice(0); // return copy } +exports.quoteString = quoteString; function config(cfg) { // default fmtPattern.ident = 'I'; @@ -206,21 +214,22 @@ function config(cfg) { } } } +exports.config = config; function formatWithArray(fmt, parameters) { - var index = 0; - var params = parameters; - var reText = '%(%|(\\d+\\$)?['; + let index = 0; + let params = parameters; + let reText = '%(%|(\\d+\\$)?['; reText += fmtPattern.ident; reText += fmtPattern.literal; reText += fmtPattern.string; reText += '])'; - var re = new RegExp(reText, 'g'); + const re = new RegExp(reText, 'g'); return fmt.replace(re, function (_, type) { if (type === '%') { return '%'; } - var position = index; - var tokens = type.split('$'); + let position = index; + const tokens = type.split('$'); if (tokens.length > 1) { position = parseInt(tokens[0]) - 1; type = tokens[1]; @@ -243,16 +252,8 @@ function formatWithArray(fmt, parameters) { } }); } -function format(fmt) { - var args = []; - for (var _i = 1; _i < arguments.length; _i++) { - args[_i - 1] = arguments[_i]; - } +exports.formatWithArray = formatWithArray; +function format(fmt, ...args) { return formatWithArray(fmt, args); } -format.config = config; -format.ident = quoteIdent; -format.literal = quoteLiteral; -format.string = quoteString; -format.withArray = formatWithArray; -module.exports = format; +exports.format = format; diff --git a/lib/reserved.d.ts b/lib/reserved.d.ts index e69de29..6c10f88 100644 --- a/lib/reserved.d.ts +++ b/lib/reserved.d.ts @@ -0,0 +1,157 @@ +declare const _default: { + AES128: boolean; + AES256: boolean; + ALL: boolean; + ALLOWOVERWRITE: boolean; + ANALYSE: boolean; + ANALYZE: boolean; + AND: boolean; + ANY: boolean; + ARRAY: boolean; + AS: boolean; + ASC: boolean; + ASYMMETRIC: boolean; + AUTHORIZATION: boolean; + BACKUP: boolean; + BETWEEN: boolean; + BINARY: boolean; + BLANKSASNULL: boolean; + BOTH: boolean; + BYTEDICT: boolean; + CASE: boolean; + CAST: boolean; + CHECK: boolean; + COLLATE: boolean; + COLUMN: boolean; + CONSTRAINT: boolean; + CREATE: boolean; + CREDENTIALS: boolean; + CROSS: boolean; + CURRENT_CATALOG: boolean; + CURRENT_DATE: boolean; + CURRENT_ROLE: boolean; + CURRENT_TIME: boolean; + CURRENT_TIMESTAMP: boolean; + CURRENT_USER: boolean; + CURRENT_USER_ID: boolean; + DEFAULT: boolean; + DEFERRABLE: boolean; + DEFLATE: boolean; + DEFRAG: boolean; + DELTA: boolean; + DELTA32K: boolean; + DESC: boolean; + DISABLE: boolean; + DISTINCT: boolean; + DO: boolean; + ELSE: boolean; + EMPTYASNULL: boolean; + ENABLE: boolean; + ENCODE: boolean; + ENCRYPT: boolean; + ENCRYPTION: boolean; + END: boolean; + EXCEPT: boolean; + EXPLICIT: boolean; + FALSE: boolean; + FETCH: boolean; + FOR: boolean; + FOREIGN: boolean; + FREEZE: boolean; + FROM: boolean; + FULL: boolean; + GLOBALDICT256: boolean; + GLOBALDICT64K: boolean; + GRANT: boolean; + GROUP: boolean; + GZIP: boolean; + HAVING: boolean; + IDENTITY: boolean; + IGNORE: boolean; + ILIKE: boolean; + IN: boolean; + INITIALLY: boolean; + INNER: boolean; + INTERSECT: boolean; + INTO: boolean; + IS: boolean; + ISNULL: boolean; + JOIN: boolean; + LATERAL: boolean; + LEADING: boolean; + LEFT: boolean; + LIKE: boolean; + LIMIT: boolean; + LOCALTIME: boolean; + LOCALTIMESTAMP: boolean; + LUN: boolean; + LUNS: boolean; + LZO: boolean; + LZOP: boolean; + MINUS: boolean; + MOSTLY13: boolean; + MOSTLY32: boolean; + MOSTLY8: boolean; + NATURAL: boolean; + NEW: boolean; + NOT: boolean; + NOTNULL: boolean; + NULL: boolean; + NULLS: boolean; + OFF: boolean; + OFFLINE: boolean; + OFFSET: boolean; + OLD: boolean; + ON: boolean; + ONLY: boolean; + OPEN: boolean; + OR: boolean; + ORDER: boolean; + OUTER: boolean; + OVERLAPS: boolean; + PARALLEL: boolean; + PARTITION: boolean; + PERCENT: boolean; + PLACING: boolean; + PRIMARY: boolean; + RAW: boolean; + READRATIO: boolean; + RECOVER: boolean; + REFERENCES: boolean; + REJECTLOG: boolean; + RESORT: boolean; + RESTORE: boolean; + RETURNING: boolean; + RIGHT: boolean; + SELECT: boolean; + SESSION_USER: boolean; + SIMILAR: boolean; + SOME: boolean; + SYMMETRIC: boolean; + SYSDATE: boolean; + SYSTEM: boolean; + TABLE: boolean; + TAG: boolean; + TDES: boolean; + TEXT255: boolean; + TEXT32K: boolean; + THEN: boolean; + TO: boolean; + TOP: boolean; + TRAILING: boolean; + TRUE: boolean; + TRUNCATECOLUMNS: boolean; + UNION: boolean; + UNIQUE: boolean; + USER: boolean; + USING: boolean; + VARIADIC: boolean; + VERBOSE: boolean; + WALLET: boolean; + WHEN: boolean; + WHERE: boolean; + WINDOW: boolean; + WITH: boolean; + WITHOUT: boolean; +}; +export default _default; diff --git a/lib/reserved.js b/lib/reserved.js index 29d98d5..bc714b2 100644 --- a/lib/reserved.js +++ b/lib/reserved.js @@ -1,9 +1,10 @@ "use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); // // PostgreSQL reserved words // see: https://www.postgresql.org/docs/current/sql-keywords-appendix.html // -module.exports = { +exports.default = { "AES128": true, "AES256": true, "ALL": true, diff --git a/lib/test/index.spec.d.ts b/lib/test/index.spec.d.ts new file mode 100644 index 0000000..a6f7b54 --- /dev/null +++ b/lib/test/index.spec.d.ts @@ -0,0 +1 @@ +import 'should'; diff --git a/lib/test/index.spec.js b/lib/test/index.spec.js new file mode 100644 index 0000000..dd1725b --- /dev/null +++ b/lib/test/index.spec.js @@ -0,0 +1,251 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const __1 = require(".."); +const assert_1 = __importDefault(require("assert")); +require("should"); +const testDate = new Date(Date.UTC(2012, 11, 14, 13, 6, 43, 152)); +//@ts-ignore +const testArray = ['abc', 1, true, null, testDate, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, 1n]; +//@ts-ignore +const testIdentArray = ['abc', 'AbC', 1, true, testDate, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, 1n]; +const testObject = { a: 1, b: 2 }; +const testNestedArray = [[1, 2], [3, 4], [5, 6]]; +describe('format(fmt, ...)', function () { + describe('%s', function () { + it('should format as a simple string', function () { + __1.format('some %s here', 'thing').should.equal('some thing here'); + __1.format('some %s thing %s', 'long', 'here').should.equal('some long thing here'); + }); + it('should format array of array as simple string', function () { + __1.format('many %s %s', 'things', testNestedArray).should.equal('many things (1, 2), (3, 4), (5, 6)'); + }); + it('should format string using position field', function () { + __1.format('some %1$s', 'thing').should.equal('some thing'); + __1.format('some %1$s %1$s', 'thing').should.equal('some thing thing'); + __1.format('some %1$s %s', 'thing', 'again').should.equal('some thing again'); + __1.format('some %1$s %2$s', 'thing', 'again').should.equal('some thing again'); + __1.format('some %1$s %2$s %1$s', 'thing', 'again').should.equal('some thing again thing'); + __1.format('some %1$s %2$s %s %1$s', 'thing', 'again', 'some').should.equal('some thing again some thing'); + }); + it('should not format string using position 0', function () { + (function () { + __1.format('some %0$s', 'thing'); + }).should.throw(Error); + }); + it('should not format string using position field with too few arguments', function () { + (function () { + __1.format('some %2$s', 'thing'); + }).should.throw(Error); + }); + }); + describe('%%', function () { + it('should format as %', function () { + __1.format('some %%', 'thing').should.equal('some %'); + }); + it('should not eat args', function () { + __1.format('just %% a %s', 'test').should.equal('just % a test'); + }); + it('should not format % using position field', function () { + __1.format('%1$%', 'thing').should.equal('%1$%'); + }); + }); + describe('%I', function () { + it('should format as an identifier', function () { + __1.format('some %I', 'foo/bar/baz').should.equal('some "foo/bar/baz"'); + }); + it('should format as an identifier', function () { + __1.format('some %I', 'foo.bar').should.equal('some foo.bar'); + }); + it('should not format array of array as an identifier', function () { + (function () { + __1.format('many %I %I', 'foo/bar/baz', testNestedArray); + }).should.throw(Error); + }); + it('should format identifier using position field', function () { + __1.format('some %1$I', 'thing').should.equal('some thing'); + __1.format('some %1$I %1$I', 'thing').should.equal('some thing thing'); + __1.format('some %1$I %I', 'thing', 'again').should.equal('some thing again'); + __1.format('some %1$I %2$I', 'thing', 'again').should.equal('some thing again'); + __1.format('some %1$I %2$I %1$I', 'thing', 'again').should.equal('some thing again thing'); + __1.format('some %1$I %2$I %I %1$I', 'thing', 'again', 'huh').should.equal('some thing again huh thing'); + }); + it('should not format identifier using position 0', function () { + (function () { + __1.format('some %0$I', 'thing'); + }).should.throw(Error); + }); + it('should not format identifier using position field with too few arguments', function () { + (function () { + __1.format('some %2$I', 'thing'); + }).should.throw(Error); + }); + }); + describe('%L', function () { + it('should format as a literal', function () { + __1.format('%L', "Tobi's").should.equal("'Tobi''s'"); + }); + it('should format array of array as a literal', function () { + __1.format('%L', testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); + }); + it('should format literal using position field', function () { + __1.format('some %1$L', 'thing').should.equal("some 'thing'"); + __1.format('some %1$L %1$L', 'thing').should.equal("some 'thing' 'thing'"); + __1.format('some %1$L %L', 'thing', 'again').should.equal("some 'thing' 'again'"); + __1.format('some %1$L %2$L', 'thing', 'again').should.equal("some 'thing' 'again'"); + __1.format('some %1$L %2$L %1$L', 'thing', 'again').should.equal("some 'thing' 'again' 'thing'"); + __1.format('some %1$L %2$L %L %1$L', 'thing', 'again', 'some').should.equal("some 'thing' 'again' 'some' 'thing'"); + }); + it('should not format literal using position 0', function () { + (function () { + __1.format('some %0$L', 'thing'); + }).should.throw(Error); + }); + it('should not format literal using position field with too few arguments', function () { + (function () { + __1.format('some %2$L', 'thing'); + }).should.throw(Error); + }); + }); +}); +describe('formatWithArray(fmt, args)', function () { + describe('%s', function () { + it('should format as a simple string', function () { + __1.formatWithArray('some %s here', ['thing']).should.equal('some thing here'); + __1.formatWithArray('some %s thing %s', ['long', 'here']).should.equal('some long thing here'); + }); + it('should format array of array as simple string', function () { + __1.formatWithArray('many %s %s', ['things', testNestedArray]).should.equal('many things (1, 2), (3, 4), (5, 6)'); + }); + }); + describe('%%', function () { + it('should format as %', function () { + __1.formatWithArray('some %%', ['thing']).should.equal('some %'); + }); + it('should not eat args', function () { + __1.formatWithArray('just %% a %s', ['test']).should.equal('just % a test'); + __1.formatWithArray('just %% a %s %s %s', ['test', 'again', 'and again']).should.equal('just % a test again and again'); + }); + }); + describe('%I', function () { + it('should format as an identifier', function () { + __1.formatWithArray('some %I', ['foo/bar/baz']).should.equal('some "foo/bar/baz"'); + __1.formatWithArray('some %I and %I', ['foo/bar/baz', '#hey']).should.equal('some "foo/bar/baz" and "#hey"'); + }); + it('should not format array of array as an identifier', function () { + (function () { + __1.formatWithArray('many %I %I', ['foo/bar/baz', testNestedArray]); + }).should.throw(Error); + }); + }); + describe('%L', function () { + it('should format as a literal', function () { + __1.formatWithArray('%L', ["Tobi's"]).should.equal("'Tobi''s'"); + __1.formatWithArray('%L %L', ["Tobi's", "birthday"]).should.equal("'Tobi''s' 'birthday'"); + }); + it('should format array of array as a literal', function () { + __1.formatWithArray('%L', [testNestedArray]).should.equal("(1, 2), (3, 4), (5, 6)"); + }); + }); +}); +describe('quoteString(val)', function () { + it('should coerce to a string', function () { + __1.quoteString(undefined).should.equal(''); + __1.quoteString(null).should.equal(''); + __1.quoteString(true).should.equal('t'); + __1.quoteString(false).should.equal('f'); + __1.quoteString(0).should.equal('0'); + __1.quoteString(15).should.equal('15'); + __1.quoteString(-15).should.equal('-15'); + __1.quoteString(45.13).should.equal('45.13'); + __1.quoteString(-45.13).should.equal('-45.13'); + __1.quoteString('something').should.equal('something'); + __1.quoteString(testArray).should.equal('abc,1,t,2012-12-14 13:06:43.152+00,-Infinity,Infinity,NaN,1'); + __1.quoteString(testNestedArray).should.equal('(1, 2), (3, 4), (5, 6)'); + __1.quoteString(testDate).should.equal('2012-12-14 13:06:43.152+00'); + __1.quoteString(testObject).should.equal('{"a":1,"b":2}'); + }); +}); +describe('quoteIdent(val)', function () { + it('should quote when necessary', function () { + __1.quoteIdent('foo').should.equal('foo'); + __1.quoteIdent('_foo').should.equal('_foo'); + __1.quoteIdent('_foo_bar$baz').should.equal('_foo_bar$baz'); + __1.quoteIdent('test.some.stuff').should.equal('test.some.stuff'); + __1.quoteIdent('test."some".stuff').should.equal('"test.""some"".stuff"'); + }); + it('should quote reserved words', function () { + __1.quoteIdent('desc').should.equal('"desc"'); + __1.quoteIdent('join').should.equal('"join"'); + __1.quoteIdent('cross').should.equal('"cross"'); + }); + it('should quote', function () { + __1.quoteIdent(true).should.equal('"t"'); + __1.quoteIdent(false).should.equal('"f"'); + __1.quoteIdent(0).should.equal('"0"'); + __1.quoteIdent(15).should.equal('"15"'); + __1.quoteIdent(-15).should.equal('"-15"'); + __1.quoteIdent(45.13).should.equal('"45.13"'); + __1.quoteIdent(-45.13).should.equal('"-45.13"'); + __1.quoteIdent(testIdentArray).should.equal('abc,"AbC","1","t","2012-12-14 13:06:43.152+00","-Infinity","Infinity","NaN","1"'); + (function () { + __1.quoteIdent(testNestedArray); + }).should.throw(Error); + __1.quoteIdent(testDate).should.equal('"2012-12-14 13:06:43.152+00"'); + }); + it('should throw when undefined', function (done) { + try { + __1.quoteIdent(undefined); + } + catch (err) { + assert_1.default(err.message === 'SQL identifier cannot be null or undefined'); + done(); + } + }); + it('should throw when null', function (done) { + try { + __1.quoteIdent(null); + } + catch (err) { + assert_1.default(err.message === 'SQL identifier cannot be null or undefined'); + done(); + } + }); + it('should throw when object', function (done) { + try { + __1.quoteIdent({}); + } + catch (err) { + assert_1.default(err.message === 'SQL identifier cannot be an object'); + done(); + } + }); +}); +describe('quoteLiteral(val)', function () { + it('should return NULL for null', function () { + __1.quoteLiteral(null).should.equal('NULL'); + __1.quoteLiteral(undefined).should.equal('NULL'); + }); + it('should quote', function () { + __1.quoteLiteral(true).should.equal("'t'"); + __1.quoteLiteral(false).should.equal("'f'"); + __1.quoteLiteral(0).should.equal('0'); + __1.quoteLiteral(15).should.equal('15'); + __1.quoteLiteral(-15).should.equal('-15'); + __1.quoteLiteral(45.13).should.equal('45.13'); + __1.quoteLiteral(-45.13).should.equal('-45.13'); + __1.quoteLiteral('hello world').should.equal("'hello world'"); + __1.quoteLiteral(testArray).should.equal("'abc',1,'t',NULL,'2012-12-14 13:06:43.152+00','-Infinity','Infinity','NaN',1"); + __1.quoteLiteral(testNestedArray).should.equal("(1, 2), (3, 4), (5, 6)"); + __1.quoteLiteral(testDate).should.equal("'2012-12-14 13:06:43.152+00'"); + __1.quoteLiteral(testObject).should.equal("'{\"a\":1,\"b\":2}'::jsonb"); + }); + it('should format quotes', function () { + __1.quoteLiteral("O'Reilly").should.equal("'O''Reilly'"); + }); + it('should format backslashes', function () { + __1.quoteLiteral('\\whoop\\').should.equal("E'\\\\whoop\\\\'"); + }); +}); diff --git a/package.json b/package.json index 961accd..1bf0923 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "typescript": "^4.2.4" }, "scripts": { - "prepublish": "npm build", + "prepublish": "npm run build", "build": "tsc", "test": "ts-mocha -p tsconfig.json src/**/*.spec.ts" } diff --git a/src/index.ts b/src/index.ts index 600f1a5..177f564 100644 --- a/src/index.ts +++ b/src/index.ts @@ -63,7 +63,8 @@ export function quoteIdent(value:any): string { const ident = value.toString().slice(0) // create copy // do not quote a valid, unquoted identifier - if (/^[a-z_][a-z0-9_$.]*$/.test(ident) === true && isReserved(ident) === false) { + // https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS + if (/^[a-zA-Z_][a-zA-Z0-9_$.]*$/.test(ident) === true && isReserved(ident) === false) { return ident } diff --git a/src/test/index.spec.ts b/src/test/index.spec.ts index a7269e3..8b3fd9f 100644 --- a/src/test/index.spec.ts +++ b/src/test/index.spec.ts @@ -5,14 +5,16 @@ import { quoteLiteral, quoteString, config -} from '..' -import assert from 'assert' -import 'should' -import { exit } from 'process'; +} from '..'; +import assert from 'assert'; +import 'should'; + const testDate = new Date(Date.UTC(2012, 11, 14, 13, 6, 43, 152)); +//@ts-ignore const testArray = ['abc', 1, true, null, testDate, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, 1n]; +//@ts-ignore const testIdentArray = ['abc', 'AbC', 1, true, testDate, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, 1n]; const testObject = { a: 1, b: 2 }; const testNestedArray = [[1, 2], [3, 4], [5, 6]]; @@ -20,13 +22,10 @@ const testNestedArray = [[1, 2], [3, 4], [5, 6]]; describe('format(fmt, ...)', function () { describe('%s', function () { it('should format as a simple string', function () { - format('some %s here', 'thing').should.equal('some thing here'); format('some %s thing %s', 'long', 'here').should.equal('some long thing here'); - }); - it('should format array of array as simple string', function () { format('many %s %s', 'things', testNestedArray).should.equal('many things (1, 2), (3, 4), (5, 6)'); @@ -227,7 +226,7 @@ describe('quoteIdent(val)', function () { quoteIdent(-15).should.equal('"-15"'); quoteIdent(45.13).should.equal('"45.13"'); quoteIdent(-45.13).should.equal('"-45.13"'); - quoteIdent(testIdentArray).should.equal('abc,"AbC","1","t","2012-12-14 13:06:43.152+00","-Infinity","Infinity","NaN","1"'); + quoteIdent(testIdentArray).should.equal('abc,AbC,"1","t","2012-12-14 13:06:43.152+00","-Infinity",Infinity,NaN,"1"'); (function () { quoteIdent(testNestedArray) }).should.throw(Error); From e839a1e593eaaef148db08a566c74e6b3e5c2c81 Mon Sep 17 00:00:00 2001 From: Clint Phillips Date: Sun, 17 Apr 2022 16:11:55 -0700 Subject: [PATCH 19/21] Update release number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1bf0923..561a356 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "license": "MIT", "homepage": "https://github.com/cphillips/node-pg-format", "description": "Node.js implementation of PostgreSQL's format() to safely create dynamic SQL queries.", - "version": "1.3.0", + "version": "1.3.1", "repository": { "type": "git", "url": "https://github.com/cphillips/node-pg-format.git" From 7a0d84cccded753c15a669a8e4a613c295ee0576 Mon Sep 17 00:00:00 2001 From: Clint Phillips Date: Sun, 17 Apr 2022 16:15:31 -0700 Subject: [PATCH 20/21] Update to 1.3.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 561a356..3745366 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "license": "MIT", "homepage": "https://github.com/cphillips/node-pg-format", "description": "Node.js implementation of PostgreSQL's format() to safely create dynamic SQL queries.", - "version": "1.3.1", + "version": "1.3.5", "repository": { "type": "git", "url": "https://github.com/cphillips/node-pg-format.git" From dfdffea0ae663cbf8ddb0beb970556dca49be2d4 Mon Sep 17 00:00:00 2001 From: Clint Phillips Date: Sun, 17 Apr 2022 16:36:10 -0700 Subject: [PATCH 21/21] Add additional types --- src/index.ts | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/index.ts b/src/index.ts index 177f564..7e834bd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,15 @@ // reserved Postgres words import reservedMap from './reserved' +export interface Pattern { + ident?: string + literal?: string + string?: string +} +export interface Config { + pattern?: Pattern +} + const fmtPattern = { ident: 'I', literal: 'L', @@ -8,20 +17,20 @@ const fmtPattern = { } // convert to Postgres default ISO 8601 format -function formatDate(date:string): string { +function formatDate(date: string): string { date = date.replace('T', ' ') date = date.replace('Z', '+00') return date } -function isReserved(value:string):boolean { +function isReserved(value: string): boolean { if (reservedMap[value.toUpperCase()]) { return true } return false } -function arrayToList(useSpace:boolean, array:any[], formatter:(value:any)=>string) { +function arrayToList(useSpace: boolean, array: any[], formatter: (value: any) => string) { let sql = '' sql += useSpace ? ' (' : '(' @@ -34,7 +43,7 @@ function arrayToList(useSpace:boolean, array:any[], formatter:(value:any)=>strin } // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c -export function quoteIdent(value:any): string { +export function quoteIdent(value: any): string { if (value === undefined || value === null) { throw new Error('SQL identifier cannot be null or undefined') @@ -85,7 +94,7 @@ export function quoteIdent(value:any): string { } // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c -export function quoteLiteral(value) { +export function quoteLiteral(value: any) { let literal = '' let explicitCast: string | null = null @@ -155,7 +164,7 @@ export function quoteLiteral(value) { return quoted } -export function quoteString(value): string { +export function quoteString(value: any): string { if (value === undefined || value === null) { return '' @@ -186,7 +195,9 @@ export function quoteString(value): string { return value.toString().slice(0) // return copy } -export function config(cfg) { + + +export function config(cfg:Config) { // default fmtPattern.ident = 'I' @@ -200,10 +211,10 @@ export function config(cfg) { } } -export function formatWithArray(fmt, parameters) { +export function formatWithArray(fmt:string, parameters:any[]) { let index = 0 - let params = parameters + const params = parameters let reText = '%(%|(\\d+\\$)?[' reText += fmtPattern.ident @@ -212,7 +223,7 @@ export function formatWithArray(fmt, parameters) { reText += '])' const re = new RegExp(reText, 'g') - return fmt.replace(re, function (_, type) { + return fmt.replace(re, (_, type) => { if (type === '%') { return '%' @@ -240,6 +251,8 @@ export function formatWithArray(fmt, parameters) { return quoteLiteral(params[position]) } else if (type === fmtPattern.string) { return quoteString(params[position]) + } else { + return '' } }) }