From d9eaba6135ec1261aa4bf93bd3f6b6d54094731e Mon Sep 17 00:00:00 2001 From: doug-martin Date: Sat, 21 Dec 2019 17:29:25 -0600 Subject: [PATCH] Migrate to jest --- .eslintrc.js | 4 +- .mocharc.js | 14 - .nycrc | 24 - {test => __tests__}/RecordingStream.ts | 0 .../formatter/CsvFormatterStream.spec.ts | 906 ++++ .../formatter/FormatterOptions.spec.ts | 85 +- .../formatter/__fixtures__}/.gitkeep | 0 .../formatter/FieldFormatter.spec.ts | 37 +- .../formatter/formatter/RowFormatter.spec.ts | 201 +- .../issues/__fixtures__}/issue102.csv | 0 .../issues/__fixtures__}/issue68-invalid.tsv | 0 .../issues/__fixtures__}/issue68.tsv | 0 .../issues/__fixtures__}/issue87.csv | 0 .../issues/issue102.spec.ts | 11 +- .../issues/issue111.spec.ts | 13 +- .../issues/issue131.spec.ts | 5 +- .../issues/issue150.spec.ts | 3 +- .../issues/issue158.spec.ts | 3 +- .../issues/issue174.spec.ts | 3 +- .../issues/issue214.spec.ts | 9 +- .../issues/issue223.spec.ts | 3 +- .../issues/issue252.spec.ts | 3 +- .../issues/issue68.spec.ts | 28 +- .../issues/issue77.spec.ts | 19 +- .../issues/issue87.spec.ts | 5 +- .../issues/issue93.spec.ts | 5 +- .../issues/issue97.spec.ts | 3 +- .../parser/CsvParsingStream.spec.ts | 495 +- .../parser/ParserOptions.spec.ts | 101 +- .../parser/__fixtures__}/alternateEncoding.ts | 0 .../parser/__fixtures__}/duplicateHeaders.ts | 0 .../parser/__fixtures__}/emptyRows.ts | 0 .../__fixtures__}/headerColumnMismatch.ts | 0 .../parser/__fixtures__}/index.ts | 2 + .../parser/__fixtures__}/malformed.ts | 0 .../__fixtures__}/noHeadersAndQuotes.ts | 0 .../parser/__fixtures__}/skipLines.ts | 0 .../parser/__fixtures__}/trailingComma.ts | 0 .../parser/__fixtures__}/withHeaders.ts | 0 .../withHeadersAlternateDelimiter.ts | 0 .../withHeadersAndAlternateQuote.ts | 0 .../withHeadersAndMissingColumns.ts | 0 .../__fixtures__}/withHeadersAndQuotes.ts | 0 .../__fixtures__}/withHeadersSkippedLines.ts | 0 .../parser/parser/Parser.spec.ts | 235 +- .../parser/parser/RowParser.spec.ts | 65 +- .../parser/parser/Scanner.spec.ts | 99 +- .../parser/parser/column/ColumnParser.spec.ts | 5 +- .../column/NonQuotedColumnParser.spec.ts | 75 +- .../parser/column/QuotedColumnParser.spec.ts | 312 +- .../transforms/HeaderTransformer.spec.ts | 146 +- .../RowTransformerValidator.spec.ts | 88 +- jest.config.js | 11 + package-lock.json | 4813 ++++++++++++++--- package.json | 20 +- test/formatter/CsvFormatterStream.test.ts | 923 ---- tsconfig.json | 2 +- 57 files changed, 5891 insertions(+), 2885 deletions(-) delete mode 100644 .mocharc.js delete mode 100644 .nycrc rename {test => __tests__}/RecordingStream.ts (100%) create mode 100644 __tests__/formatter/CsvFormatterStream.spec.ts rename test/formatter/FormatterOptions.test.ts => __tests__/formatter/FormatterOptions.spec.ts (52%) rename {test/formatter/assets => __tests__/formatter/__fixtures__}/.gitkeep (100%) rename test/formatter/formatter/FieldFormatter.test.ts => __tests__/formatter/formatter/FieldFormatter.spec.ts (73%) rename test/formatter/formatter/RowFormatter.test.ts => __tests__/formatter/formatter/RowFormatter.spec.ts (58%) rename {test/issues/assets => __tests__/issues/__fixtures__}/issue102.csv (100%) rename {test/issues/assets => __tests__/issues/__fixtures__}/issue68-invalid.tsv (100%) rename {test/issues/assets => __tests__/issues/__fixtures__}/issue68.tsv (100%) rename {test/issues/assets => __tests__/issues/__fixtures__}/issue87.csv (100%) rename test/issues/issue102.test.ts => __tests__/issues/issue102.spec.ts (73%) rename test/issues/issue111.test.ts => __tests__/issues/issue111.spec.ts (87%) rename test/issues/issue131.test.ts => __tests__/issues/issue131.spec.ts (79%) rename test/issues/issue150.test.ts => __tests__/issues/issue150.spec.ts (89%) rename test/issues/issue158.test.ts => __tests__/issues/issue158.spec.ts (88%) rename test/issues/issue174.test.ts => __tests__/issues/issue174.spec.ts (91%) rename test/issues/issue214.test.ts => __tests__/issues/issue214.spec.ts (84%) rename test/issues/issue223.test.ts => __tests__/issues/issue223.spec.ts (91%) rename test/issues/issue252.test.ts => __tests__/issues/issue252.spec.ts (81%) rename test/issues/issue68.test.ts => __tests__/issues/issue68.spec.ts (60%) rename test/issues/issue77.test.ts => __tests__/issues/issue77.spec.ts (65%) rename test/issues/issue87.test.ts => __tests__/issues/issue87.spec.ts (87%) rename test/issues/issue93.test.ts => __tests__/issues/issue93.spec.ts (91%) rename test/issues/issue97.test.ts => __tests__/issues/issue97.spec.ts (81%) rename test/parser/CsvParsingStream.test.ts => __tests__/parser/CsvParsingStream.spec.ts (56%) rename test/parser/ParserOptions.test.ts => __tests__/parser/ParserOptions.spec.ts (53%) rename {test/parser/assets => __tests__/parser/__fixtures__}/alternateEncoding.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/duplicateHeaders.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/emptyRows.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/headerColumnMismatch.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/index.ts (95%) rename {test/parser/assets => __tests__/parser/__fixtures__}/malformed.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/noHeadersAndQuotes.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/skipLines.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/trailingComma.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/withHeaders.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/withHeadersAlternateDelimiter.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/withHeadersAndAlternateQuote.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/withHeadersAndMissingColumns.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/withHeadersAndQuotes.ts (100%) rename {test/parser/assets => __tests__/parser/__fixtures__}/withHeadersSkippedLines.ts (100%) rename test/parser/parser/Parser.test.ts => __tests__/parser/parser/Parser.spec.ts (85%) rename test/parser/parser/RowParser.test.ts => __tests__/parser/parser/RowParser.spec.ts (68%) rename test/parser/parser/Scanner.test.ts => __tests__/parser/parser/Scanner.spec.ts (58%) rename test/parser/parser/column/ColumnParser.test.ts => __tests__/parser/parser/column/ColumnParser.spec.ts (88%) rename test/parser/parser/column/NonQuotedColumnParser.test.ts => __tests__/parser/parser/column/NonQuotedColumnParser.spec.ts (69%) rename test/parser/parser/column/QuotedColumnParser.test.ts => __tests__/parser/parser/column/QuotedColumnParser.spec.ts (67%) rename test/parser/transforms/HeaderTransformer.test.ts => __tests__/parser/transforms/HeaderTransformer.spec.ts (50%) rename test/parser/transforms/RowTransformerValidator.test.ts => __tests__/parser/transforms/RowTransformerValidator.spec.ts (66%) create mode 100644 jest.config.js delete mode 100644 test/formatter/CsvFormatterStream.test.ts diff --git a/.eslintrc.js b/.eslintrc.js index 399d0248..6b32f758 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -14,7 +14,7 @@ module.exports = { ], env: { node: true, - mocha: true, + jest: true, }, settings:{ "import/extensions": [ @@ -65,7 +65,7 @@ module.exports = { overrides: [ { "files": [ - "*.test.ts" + "*.spec.ts" ], "rules": { "@typescript-eslint/explicit-function-return-type": "off", diff --git a/.mocharc.js b/.mocharc.js deleted file mode 100644 index 24dba14a..00000000 --- a/.mocharc.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - diff: true, - require: ['ts-node/register', 'source-map-support/register'], - extension: ['ts', 'js'], - package: './package.json', - reporter: 'spec', - slow: 75, - timeout: 5000, - recursive: true, - ui: 'bdd' -}; - -// --recursive -// test/ \ No newline at end of file diff --git a/.nycrc b/.nycrc deleted file mode 100644 index 4e1ecbcc..00000000 --- a/.nycrc +++ /dev/null @@ -1,24 +0,0 @@ -{ - "extends": "@istanbuljs/nyc-config-typescript", - "all": true, - "check-coverage": true, - "lines": 90, - "functions": 90, - "branches": 90, - "statements": 90, - "exclude": [ - "**/*.d.ts", - "coverage/**", - "packages/*/test/**", - "test/**", - "test{,-*}.ts", - "**/*{.,-}{test,spec}.ts", - "**/__tests__/**", - "**/node_modules/**", - "benchmark/**/*", - "examples/**/*", - "docs/**/*", - ".eslintrc.js", - ".mocharc.js" - ] -} diff --git a/test/RecordingStream.ts b/__tests__/RecordingStream.ts similarity index 100% rename from test/RecordingStream.ts rename to __tests__/RecordingStream.ts diff --git a/__tests__/formatter/CsvFormatterStream.spec.ts b/__tests__/formatter/CsvFormatterStream.spec.ts new file mode 100644 index 00000000..f7017a5b --- /dev/null +++ b/__tests__/formatter/CsvFormatterStream.spec.ts @@ -0,0 +1,906 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as csv from '../../src'; +import { FormatterOptions, CsvFormatterStream } from '../../src/formatter'; +import RecordingStream from '../RecordingStream'; + +describe('CsvFormatterStream', () => { + const objectRows = [ + { a: 'a1', b: 'b1' }, + { a: 'a2', b: 'b2' }, + ]; + + const arrayRows = [ + ['a', 'b'], + ['a1', 'b1'], + ['a2', 'b2'], + ]; + + const multiDimensionalRows = [ + [ + ['a', 'a1'], + ['b', 'b1'], + ], + [ + ['a', 'a2'], + ['b', 'b2'], + ], + ]; + + const pipeToRecordingStream = (formatter: CsvFormatterStream, rows: csv.FormatterRow[]) => + new Promise((res, rej) => { + const rs = new RecordingStream(); + formatter + .on('error', e => rej(e)) + .pipe(rs) + .on('finish', () => { + res(rs.data); + }); + rows.forEach(row => formatter.write(row)); + formatter.end(); + }); + + const formatRows = (rows: csv.FormatterRow[], options: csv.FormatterOptionsArgs = {}) => + pipeToRecordingStream(csv.format(options), rows); + + it('should write an array of arrays', () => + expect(formatRows(arrayRows, { headers: true })).resolves.toEqual(['a,b', '\na1,b1', '\na2,b2'])); + + it('should write an array of objects', () => + expect(formatRows(objectRows, { headers: true })).resolves.toEqual(['a,b', '\na1,b1', '\na2,b2'])); + + describe('transform option', () => { + it('should support transforming an array of arrays', () => + expect( + formatRows(arrayRows, { + headers: true, + transform(row: csv.FormatterRow) { + return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); + }, + }), + ).resolves.toEqual(['A,B', '\nA1,B1', '\nA2,B2'])); + + it('should support transforming an array of multi-dimensional arrays', () => + expect( + formatRows(multiDimensionalRows, { + headers: true, + transform(row: csv.FormatterRow) { + return (row as csv.FormatterRowHashArray).map(entry => [entry[0], entry[1].toUpperCase()]); + }, + }), + ).resolves.toEqual(['a,b', '\nA1,B1', '\nA2,B2'])); + + it('should support transforming an array of objects', () => + expect( + formatRows(objectRows, { + headers: true, + transform(row: csv.FormatterRowMap) { + return { A: row.a, B: row.b }; + }, + }), + ).resolves.toEqual(['A,B', '\na1,b1', '\na2,b2'])); + }); + describe('#transform', () => { + it('should support transforming an array of arrays', async () => { + const formatter = new CsvFormatterStream( + new FormatterOptions({ headers: true }), + ).transform((row: csv.FormatterRow) => (row as csv.FormatterRowArray).map(entry => entry.toUpperCase())); + await expect(pipeToRecordingStream(formatter, arrayRows)).resolves.toEqual(['A,B', '\nA1,B1', '\nA2,B2']); + }); + + it('should support transforming an array of multi-dimensional arrays', async () => { + const formatter = new CsvFormatterStream(new FormatterOptions({ headers: true })).transform( + (row: csv.FormatterRow): csv.FormatterRow => + (row as csv.FormatterRowHashArray).map(entry => [entry[0], entry[1].toUpperCase()]), + ); + await expect(pipeToRecordingStream(formatter, multiDimensionalRows)).resolves.toEqual([ + 'a,b', + '\nA1,B1', + '\nA2,B2', + ]); + }); + + it('should support transforming an array of objects', async () => { + const formatter = new CsvFormatterStream(new FormatterOptions({ headers: true })).transform( + (row: csv.FormatterRow): csv.FormatterRow => ({ + A: (row as csv.FormatterRowMap).a, + B: (row as csv.FormatterRowMap).b, + }), + ); + await expect(pipeToRecordingStream(formatter, objectRows)).resolves.toEqual(['A,B', '\na1,b1', '\na2,b2']); + }); + + it('should error if the transform fails', async () => { + const formatter = new CsvFormatterStream(new FormatterOptions({ headers: true })).transform( + (): csv.FormatterRow => { + throw new Error('Expected error'); + }, + ); + await expect(pipeToRecordingStream(formatter, objectRows)).rejects.toThrowError('Expected error'); + }); + }); + + describe('rowDelimiter option', () => { + it('should support specifying an alternate row delimiter', () => + expect( + formatRows(objectRows, { + headers: true, + rowDelimiter: '\r\n', + }), + ).resolves.toEqual(['a,b', '\r\na1,b1', '\r\na2,b2'])); + + it('should escape values that contain the alternate row delimiter', async () => { + const rows = [ + { a: 'a\n1', b: 'b1' }, + { a: 'a\n2', b: 'b2' }, + ]; + await expect( + formatRows(rows, { + headers: true, + rowDelimiter: '\n', + }), + ).resolves.toEqual(['a,b', '\n"a\n1",b1', '\n"a\n2",b2']); + }); + }); + + describe('quoteColumns option', () => { + describe('quote all columns and headers if quoteColumns is true and quoteHeaders is false', () => { + const opts = { + headers: true, + quoteColumns: true, + }; + it('should work with objects', () => + expect(formatRows(objectRows, opts)).resolves.toEqual(['"a","b"', '\n"a1","b1"', '\n"a2","b2"'])); + + it('should work with arrays', () => + expect(formatRows(arrayRows, opts)).resolves.toEqual(['"a","b"', '\n"a1","b1"', '\n"a2","b2"'])); + + it('should work with multi-dimenional arrays', () => + expect(formatRows(multiDimensionalRows, opts)).resolves.toEqual([ + '"a","b"', + '\n"a1","b1"', + '\n"a2","b2"', + ])); + }); + + describe('quote headers if quoteHeaders is true and not columns is quoteColumns is undefined', () => { + const opts = { headers: true, quoteHeaders: true }; + it('should work with objects', () => + expect(formatRows(objectRows, opts)).resolves.toEqual(['"a","b"', '\na1,b1', '\na2,b2'])); + + it('should work with arrays', () => + expect(formatRows(arrayRows, opts)).resolves.toEqual(['"a","b"', '\na1,b1', '\na2,b2'])); + + it('should work with multi-dimensional arrays', () => + expect(formatRows(multiDimensionalRows, opts)).resolves.toEqual(['"a","b"', '\na1,b1', '\na2,b2'])); + }); + + describe('quote columns if quoteColumns is true and not quote headers if quoteHeaders is false', () => { + const opts = { headers: true, quoteHeaders: false, quoteColumns: true }; + it('should work with objects', () => + expect(formatRows(objectRows, opts)).resolves.toEqual(['a,b', '\n"a1","b1"', '\n"a2","b2"'])); + + it('should work with arrays', () => + expect(formatRows(arrayRows, opts)).resolves.toEqual(['a,b', '\n"a1","b1"', '\n"a2","b2"'])); + + it('should work with multi-dimensional arrays', () => + expect(formatRows(multiDimensionalRows, opts)).resolves.toEqual(['a,b', '\n"a1","b1"', '\n"a2","b2"'])); + }); + + describe('if quoteColumns object it should only quote the specified column and header', () => { + const opts = { headers: true, quoteColumns: { a: true } }; + it('should work with objects', () => + expect(formatRows(objectRows, opts)).resolves.toEqual(['"a",b', '\n"a1",b1', '\n"a2",b2'])); + + it('should work with arrays', () => + expect(formatRows(arrayRows, opts)).resolves.toEqual(['"a",b', '\n"a1",b1', '\n"a2",b2'])); + + it('should work with multi dimensional arrays', () => + expect(formatRows(multiDimensionalRows, opts)).resolves.toEqual(['"a",b', '\n"a1",b1', '\n"a2",b2'])); + }); + + describe('if quoteColumns object and quoteHeaders is false it should only quote the specified column and not the header', () => { + const opts = { + headers: true, + quoteHeaders: false, + quoteColumns: { a: true }, + }; + it('should work with objects', () => + expect(formatRows(multiDimensionalRows, opts)).resolves.toEqual(['a,b', '\n"a1",b1', '\n"a2",b2'])); + + it('should work with arrays', () => + expect(formatRows(arrayRows, opts)).resolves.toEqual(['a,b', '\n"a1",b1', '\n"a2",b2'])); + + it('should work with multi-dimensional arrays', () => + expect(formatRows(multiDimensionalRows, opts)).resolves.toEqual(['a,b', '\n"a1",b1', '\n"a2",b2'])); + }); + + describe('if quoteColumns is an array it should only quote the specified column index', () => { + const opts = { headers: true, quoteColumns: [true] }; + it('should work with objects', () => + expect(formatRows(objectRows, opts)).resolves.toEqual(['"a",b', '\n"a1",b1', '\n"a2",b2'])); + + it('should work with arrays', () => + expect(formatRows(arrayRows, opts)).resolves.toEqual(['"a",b', '\n"a1",b1', '\n"a2",b2'])); + + it('should work with multi-dimensional arrays', () => + expect(formatRows(multiDimensionalRows, opts)).resolves.toEqual(['"a",b', '\n"a1",b1', '\n"a2",b2'])); + }); + + describe('if quoteColumns is false and quoteHeaders is an object it should only quote the specified header and not the column', () => { + const opts = { + headers: true, + quoteHeaders: { a: true }, + quoteColumns: false, + }; + it('should work with object', () => + expect(formatRows(objectRows, opts)).resolves.toEqual(['"a",b', '\na1,b1', '\na2,b2'])); + + it('should work with arrays', () => + expect(formatRows(arrayRows, opts)).resolves.toEqual(['"a",b', '\na1,b1', '\na2,b2'])); + + it('should work with multi-dimenional arrays', () => + expect(formatRows(multiDimensionalRows, opts)).resolves.toEqual(['"a",b', '\na1,b1', '\na2,b2'])); + }); + + describe('if quoteColumns is an object and quoteHeaders is an object it should only quote the specified header and column', () => { + const opts = { + headers: true, + quoteHeaders: { b: true }, + quoteColumns: { a: true }, + }; + it('should work with objects', () => + expect(formatRows(objectRows, opts)).resolves.toEqual(['a,"b"', '\n"a1",b1', '\n"a2",b2'])); + + it('should work with arrays', () => + expect(formatRows(arrayRows, opts)).resolves.toEqual(['a,"b"', '\n"a1",b1', '\n"a2",b2'])); + + it('should work with multi-dimensional arrays', () => + expect(formatRows(multiDimensionalRows, opts)).resolves.toEqual(['a,"b"', '\n"a1",b1', '\n"a2",b2'])); + }); + + describe('if quoteHeaders is an array and quoteColumns is an false it should only quote the specified header and not the column', () => { + const opts = { + headers: true, + quoteHeaders: [false, true], + quoteColumns: false, + }; + it('should work with objects', () => + expect(formatRows(objectRows, opts)).resolves.toEqual(['a,"b"', '\na1,b1', '\na2,b2'])); + + it('should work with arrays', () => + expect(formatRows(arrayRows, opts)).resolves.toEqual(['a,"b"', '\na1,b1', '\na2,b2'])); + + it('should work with arrays of multi-dimensional arrays', () => + expect(formatRows(multiDimensionalRows, opts)).resolves.toEqual(['a,"b"', '\na1,b1', '\na2,b2'])); + }); + }); + + describe('header option', () => { + it('should write an array of objects without headers', () => + expect(formatRows(objectRows, { headers: false })).resolves.toEqual(['a1,b1', '\na2,b2'])); + + it('should write an array of objects with headers', () => + expect(formatRows(objectRows, { headers: true })).resolves.toEqual(['a,b', '\na1,b1', '\na2,b2'])); + + it('should write an array of arrays without headers', async () => { + const rows = [ + ['a1', 'b1'], + ['a2', 'b2'], + ]; + await expect(formatRows(rows, { headers: false })).resolves.toEqual(['a1,b1', '\na2,b2']); + }); + + it('should write an array of arrays with headers', () => + expect(formatRows(arrayRows, { headers: true })).resolves.toEqual(['a,b', '\na1,b1', '\na2,b2'])); + + it('should write an array of multi-dimensional arrays without headers', () => + expect(formatRows(multiDimensionalRows, { headers: false })).resolves.toEqual(['a1,b1', '\na2,b2'])); + + it('should write an array of multi-dimensional arrays with headers', () => + expect(formatRows(multiDimensionalRows, { headers: true })).resolves.toEqual([ + 'a,b', + '\na1,b1', + '\na2,b2', + ])); + + it('should not write anything if headers are provided but no rows are provided', () => + expect(formatRows([], { headers: true })).resolves.toEqual([])); + + describe('alwaysWriteHeaders option', () => { + it('should write the headers if rows are not provided', async () => { + const headers = ['h1', 'h2']; + await expect( + formatRows([], { + headers, + alwaysWriteHeaders: true, + }), + ).resolves.toEqual([headers.join(',')]); + }); + + it('should write the headers ones if rows are provided', async () => { + const headers = ['h1', 'h2']; + await expect( + formatRows(arrayRows, { + headers, + alwaysWriteHeaders: true, + }), + ).resolves.toEqual([headers.join(','), '\na,b', '\na1,b1', '\na2,b2']); + }); + + it('should fail if no headers are provided', async () => { + await expect(formatRows([], { alwaysWriteHeaders: true })).rejects.toThrowError( + '`alwaysWriteHeaders` option is set to true but `headers` option not provided.', + ); + }); + + it('should write the headers and an endRowDelimiter if includeEndRowDelimiter is true', async () => { + const headers = ['h1', 'h2']; + await expect( + formatRows([], { + headers, + includeEndRowDelimiter: true, + alwaysWriteHeaders: true, + }), + ).resolves.toEqual([headers.join(','), '\n']); + }); + }); + }); + + it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => + expect( + formatRows(objectRows, { + headers: true, + includeEndRowDelimiter: true, + }), + ).resolves.toEqual(['a,b', '\na1,b1', '\na2,b2', '\n'])); + + it('should write a BOM character if writeBOM is true', () => + expect( + formatRows(objectRows, { + headers: true, + writeBOM: true, + }), + ).resolves.toEqual(['\ufeff', 'a,b', '\na1,b1', '\na2,b2'])); + + describe('.writeToString', () => { + it('should write an array of arrays', () => + expect(csv.writeToString(arrayRows, { headers: true })).resolves.toEqual('a,b\na1,b1\na2,b2')); + + it('should support transforming an array of arrays', () => + expect( + csv.writeToString(arrayRows, { + headers: true, + transform(row: csv.FormatterRow): csv.FormatterRow { + return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); + }, + }), + ).resolves.toEqual('A,B\nA1,B1\nA2,B2')); + + it('should write an array of multi-dimensional arrays', () => + expect(csv.writeToString(multiDimensionalRows, { headers: true })).resolves.toEqual('a,b\na1,b1\na2,b2')); + + it('should support transforming an array of multi-dimensional arrays', () => + expect( + csv.writeToString(multiDimensionalRows, { + headers: true, + transform(row: csv.FormatterRow) { + return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); + }, + }), + ).resolves.toEqual('a,b\nA1,B1\nA2,B2')); + + it('should write an array of objects', () => + expect( + csv.writeToString(objectRows, { + headers: true, + transform(row: csv.FormatterRowMap) { + return { + A: row.a, + B: row.b, + }; + }, + }), + ).resolves.toEqual('A,B\na1,b1\na2,b2')); + + describe('header option', () => { + it('should write an array of objects without headers', () => + expect(csv.writeToString(objectRows, { headers: false })).resolves.toEqual('a1,b1\na2,b2')); + + it('should write an array of objects with headers', () => + expect(csv.writeToString(objectRows, { headers: true })).resolves.toEqual('a,b\na1,b1\na2,b2')); + + it('should write an array of arrays without headers', async () => { + const rows = [ + ['a1', 'b1'], + ['a2', 'b2'], + ]; + await expect(csv.writeToString(rows, { headers: false })).resolves.toEqual('a1,b1\na2,b2'); + }); + + it('should write an array of arrays with headers', () => + expect(csv.writeToString(arrayRows, { headers: true })).resolves.toEqual('a,b\na1,b1\na2,b2')); + + it('should write an array of multi-dimensional arrays without headers', () => + expect(csv.writeToString(multiDimensionalRows, { headers: false })).resolves.toEqual('a1,b1\na2,b2')); + + it('should write an array of multi-dimensional arrays with headers', () => + expect(csv.writeToString(multiDimensionalRows, { headers: true })).resolves.toEqual( + 'a,b\na1,b1\na2,b2', + )); + }); + + describe('rowDelimiter option', () => { + it('should support specifying an alternate row delimiter', () => + expect(csv.writeToString(objectRows, { headers: true, rowDelimiter: '\r\n' })).resolves.toEqual( + 'a,b\r\na1,b1\r\na2,b2', + )); + + it('should escape values that contain the alternate row delimiter', async () => { + const rows = [ + { a: 'a\t1', b: 'b1' }, + { a: 'a\t2', b: 'b2' }, + ]; + await expect(csv.writeToString(rows, { headers: true, rowDelimiter: '\t' })).resolves.toEqual( + 'a,b\t"a\t1",b1\t"a\t2",b2', + ); + }); + }); + + it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => + expect(csv.writeToString(objectRows, { headers: true, includeEndRowDelimiter: true })).resolves.toEqual( + 'a,b\na1,b1\na2,b2\n', + )); + }); + + describe('.writeToBuffer', () => { + it('should write an array of arrays', () => + expect(csv.writeToBuffer(arrayRows, { headers: true })).resolves.toEqual(Buffer.from('a,b\na1,b1\na2,b2'))); + + it('should support transforming an array of arrays', () => + expect( + csv.writeToBuffer(arrayRows, { + headers: true, + transform(row: csv.FormatterRow): csv.FormatterRow { + return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); + }, + }), + ).resolves.toEqual(Buffer.from('A,B\nA1,B1\nA2,B2'))); + + it('should write an array of multi-dimensional arrays', () => + expect(csv.writeToBuffer(multiDimensionalRows, { headers: true })).resolves.toEqual( + Buffer.from('a,b\na1,b1\na2,b2'), + )); + + it('should support transforming an array of multi-dimensional arrays', () => + expect( + csv.writeToBuffer(multiDimensionalRows, { + headers: true, + transform(row: csv.FormatterRow) { + return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); + }, + }), + ).resolves.toEqual(Buffer.from('a,b\nA1,B1\nA2,B2'))); + + it('should write an array of objects', () => + expect( + csv.writeToBuffer(objectRows, { + headers: true, + transform(row: csv.FormatterRowMap): csv.FormatterRow { + return { + A: row.a, + B: row.b, + }; + }, + }), + ).resolves.toEqual(Buffer.from('A,B\na1,b1\na2,b2'))); + + describe('header option', () => { + it('should write an array of objects without headers', () => + expect(csv.writeToBuffer(objectRows, { headers: false })).resolves.toEqual( + Buffer.from('a1,b1\na2,b2'), + )); + + it('should write an array of objects with headers', () => + expect(csv.writeToBuffer(objectRows, { headers: true })).resolves.toEqual( + Buffer.from('a,b\na1,b1\na2,b2'), + )); + + it('should write an array of arrays without headers', async () => { + const rows = [ + ['a1', 'b1'], + ['a2', 'b2'], + ]; + await expect(csv.writeToBuffer(rows, { headers: false })).resolves.toEqual(Buffer.from('a1,b1\na2,b2')); + }); + + it('should write an array of arrays with headers', () => + expect(csv.writeToBuffer(arrayRows, { headers: true })).resolves.toEqual( + Buffer.from('a,b\na1,b1\na2,b2'), + )); + + it('should write an array of multi-dimensional arrays without headers', () => + expect(csv.writeToBuffer(multiDimensionalRows, { headers: false })).resolves.toEqual( + Buffer.from('a1,b1\na2,b2'), + )); + + it('should write an array of multi-dimensional arrays with headers', () => + expect(csv.writeToBuffer(multiDimensionalRows, { headers: true })).resolves.toEqual( + Buffer.from('a,b\na1,b1\na2,b2'), + )); + }); + + describe('rowDelimiter option', () => { + it('should support specifying an alternate row delimiter', () => + expect(csv.writeToBuffer(objectRows, { headers: true, rowDelimiter: '\r\n' })).resolves.toEqual( + Buffer.from('a,b\r\na1,b1\r\na2,b2'), + )); + it('should escape values that contain the alternate row delimiter', async () => { + const rows = [ + { a: 'a\t1', b: 'b1' }, + { a: 'a\t2', b: 'b2' }, + ]; + await expect(csv.writeToBuffer(rows, { headers: true, rowDelimiter: '\t' })).resolves.toEqual( + Buffer.from('a,b\t"a\t1",b1\t"a\t2",b2'), + ); + }); + }); + + it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => + expect(csv.writeToBuffer(objectRows, { headers: true, includeEndRowDelimiter: true })).resolves.toEqual( + Buffer.from('a,b\na1,b1\na2,b2\n'), + )); + }); + + describe('.write', () => { + const writeToRecordingStream = (rows: csv.FormatterRow[], options = {}) => + new Promise((res, rej) => { + const rs = new RecordingStream(); + csv.write(rows, options) + .on('error', rej) + .pipe(rs) + .on('finish', () => { + res(rs.data); + }); + }); + + it('should write an array of arrays', () => + expect(writeToRecordingStream(arrayRows, { headers: true })).resolves.toEqual([ + 'a,b', + '\na1,b1', + '\na2,b2', + ])); + + it('should support transforming an array of arrays', () => + expect( + writeToRecordingStream(arrayRows, { + headers: true, + transform(row: csv.FormatterRow) { + return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); + }, + }), + ).resolves.toEqual(['A,B', '\nA1,B1', '\nA2,B2'])); + + it('should write an array of multi-dimensional arrays', () => + expect(writeToRecordingStream(multiDimensionalRows, { headers: true })).resolves.toEqual([ + 'a,b', + '\na1,b1', + '\na2,b2', + ])); + + it('should support transforming an array of multi-dimensional arrays', () => + expect( + writeToRecordingStream(multiDimensionalRows, { + headers: true, + transform(row: csv.FormatterRow) { + return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); + }, + }), + ).resolves.toEqual(['a,b', '\nA1,B1', '\nA2,B2'])); + + it('should write an array of objects', () => + expect(writeToRecordingStream(objectRows, { headers: true })).resolves.toEqual([ + 'a,b', + '\na1,b1', + '\na2,b2', + ])); + + it('should support transforming an array of objects', () => + expect( + writeToRecordingStream(objectRows, { + headers: true, + transform(row: csv.FormatterRowMap) { + return { + A: row.a, + B: row.b, + }; + }, + }), + ).resolves.toEqual(['A,B', '\na1,b1', '\na2,b2'])); + + describe('rowDelimiter option', () => { + it('should support specifying an alternate row delimiter', () => + expect(writeToRecordingStream(objectRows, { headers: true, rowDelimiter: '\r\n' })).resolves.toEqual([ + 'a,b', + '\r\na1,b1', + '\r\na2,b2', + ])); + + it('should escape values that contain the alternate row delimiter', async () => { + const rows = [ + { a: 'a\n1', b: 'b1' }, + { a: 'a\n2', b: 'b2' }, + ]; + await expect(writeToRecordingStream(rows, { headers: true, rowDelimiter: '\n' })).resolves.toEqual([ + 'a,b', + '\n"a\n1",b1', + '\n"a\n2",b2', + ]); + }); + }); + + it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => + expect( + writeToRecordingStream(objectRows, { headers: true, includeEndRowDelimiter: true }), + ).resolves.toEqual(['a,b', '\na1,b1', '\na2,b2', '\n'])); + }); + + describe('.writeToPath', () => { + const writeToPath = (rows: csv.FormatterRow[], options = {}) => + new Promise((res, rej) => { + const csvPath = path.resolve(__dirname, '__fixtures__', 'test_output.csv'); + csv.writeToPath(csvPath, rows, options) + .on('error', rej) + .on('finish', () => { + const content = fs.readFileSync(csvPath); + fs.unlinkSync(csvPath); + res(content); + }); + }); + + it('should write an array of arrays', () => + expect(writeToPath(arrayRows, { headers: true })).resolves.toEqual(Buffer.from('a,b\na1,b1\na2,b2'))); + + it('should write an array of objects', () => + expect(writeToPath(objectRows, { headers: true })).resolves.toEqual(Buffer.from('a,b\na1,b1\na2,b2'))); + + it('should write an array of multi-dimensional arrays', () => + expect(writeToPath(multiDimensionalRows, { headers: true })).resolves.toEqual( + Buffer.from('a,b\na1,b1\na2,b2'), + )); + + it('should support transforming an array of arrays', () => + expect( + writeToPath(arrayRows, { + headers: true, + transform(row: csv.FormatterRow) { + return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); + }, + }), + ).resolves.toEqual(Buffer.from('A,B\nA1,B1\nA2,B2'))); + + it('should transforming an array of objects', () => + expect( + writeToPath(objectRows, { + headers: true, + transform(row: csv.FormatterRowMap) { + return { + A: row.a, + B: row.b, + }; + }, + }), + ).resolves.toEqual(Buffer.from('A,B\na1,b1\na2,b2'))); + + it('should transforming an array of multi-dimensional array', () => + expect( + writeToPath(multiDimensionalRows, { + headers: true, + transform(row: csv.FormatterRow) { + return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); + }, + }), + ).resolves.toEqual(Buffer.from('a,b\nA1,B1\nA2,B2'))); + + describe('rowDelimiter option', () => { + it('should support specifying an alternate row delimiter', () => + expect(writeToPath(objectRows, { headers: true, rowDelimiter: '\r\n' })).resolves.toEqual( + Buffer.from('a,b\r\na1,b1\r\na2,b2'), + )); + + it('should escape values that contain the alternate row delimiter', async () => { + const rows = [ + { a: 'a\r\n1', b: 'b1' }, + { a: 'a\r\n2', b: 'b2' }, + ]; + await expect(writeToPath(rows, { headers: true, rowDelimiter: '\r\n' })).resolves.toEqual( + Buffer.from('a,b\r\n"a\r\n1",b1\r\n"a\r\n2",b2'), + ); + }); + }); + + it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => + expect(writeToPath(objectRows, { headers: true, includeEndRowDelimiter: true })).resolves.toEqual( + Buffer.from('a,b\na1,b1\na2,b2\n'), + )); + }); + + describe('.write', () => { + const writeToRecordingStream = (rows: csv.FormatterRow[], options = {}) => + new Promise((res, rej) => { + const rs = new RecordingStream(); + csv.write(rows, options) + .on('error', rej) + .pipe(rs) + .on('finish', () => { + res(rs.data); + }); + }); + + it('should write an array of arrays', () => + expect(writeToRecordingStream(arrayRows, { headers: true })).resolves.toEqual([ + 'a,b', + '\na1,b1', + '\na2,b2', + ])); + + it('should support transforming an array of arrays', () => + expect( + writeToRecordingStream(arrayRows, { + headers: true, + transform(row: csv.FormatterRow) { + return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); + }, + }), + ).resolves.toEqual(['A,B', '\nA1,B1', '\nA2,B2'])); + + it('should write an array of multi-dimensional arrays', () => + expect(writeToRecordingStream(multiDimensionalRows, { headers: true })).resolves.toEqual([ + 'a,b', + '\na1,b1', + '\na2,b2', + ])); + + it('should support transforming an array of multi-dimensional arrays', () => + expect( + writeToRecordingStream(multiDimensionalRows, { + headers: true, + transform(row: csv.FormatterRow) { + return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); + }, + }), + ).resolves.toEqual(['a,b', '\nA1,B1', '\nA2,B2'])); + + it('should write an array of objects', () => + expect(writeToRecordingStream(objectRows, { headers: true })).resolves.toEqual([ + 'a,b', + '\na1,b1', + '\na2,b2', + ])); + + it('should support transforming an array of objects', () => + expect( + writeToRecordingStream(objectRows, { + headers: true, + transform(row: csv.FormatterRowMap) { + return { + A: row.a, + B: row.b, + }; + }, + }), + ).resolves.toEqual(['A,B', '\na1,b1', '\na2,b2'])); + + describe('rowDelimiter option', () => { + it('should support specifying an alternate row delimiter', () => + expect(writeToRecordingStream(objectRows, { headers: true, rowDelimiter: '\r\n' })).resolves.toEqual([ + 'a,b', + '\r\na1,b1', + '\r\na2,b2', + ])); + + it('should escape values that contain the alternate row delimiter', async () => { + const rows = [ + { a: 'a\n1', b: 'b1' }, + { a: 'a\n2', b: 'b2' }, + ]; + await expect(writeToRecordingStream(rows, { headers: true, rowDelimiter: '\n' })).resolves.toEqual([ + 'a,b', + '\n"a\n1",b1', + '\n"a\n2",b2', + ]); + }); + }); + + it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => + expect( + writeToRecordingStream(objectRows, { headers: true, includeEndRowDelimiter: true }), + ).resolves.toEqual(['a,b', '\na1,b1', '\na2,b2', '\n'])); + }); + + describe('.writeToStream', () => { + const writeToStream = (rows: csv.FormatterRow[], options: csv.FormatterOptionsArgs = {}) => + new Promise((res, rej) => { + const rs = new RecordingStream(); + csv.writeToStream(rs, rows, options); + rs.on('error', rej).on('finish', () => { + res(rs.data); + }); + }); + + it('should write an array of arrays', () => + expect(writeToStream(arrayRows, { headers: true })).resolves.toEqual(['a,b', '\na1,b1', '\na2,b2'])); + + it('should write an array of objects', () => + expect(writeToStream(objectRows, { headers: true })).resolves.toEqual(['a,b', '\na1,b1', '\na2,b2'])); + + it('should write an array of multi-dimensional arrays', () => + expect(writeToStream(multiDimensionalRows, { headers: true })).resolves.toEqual([ + 'a,b', + '\na1,b1', + '\na2,b2', + ])); + + it('should support transforming an array of arrays', () => + expect( + writeToStream(arrayRows, { + headers: true, + transform(row: csv.FormatterRow): csv.FormatterRow { + return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); + }, + }), + ).resolves.toEqual(['A,B', '\nA1,B1', '\nA2,B2'])); + + it('should transforming an array of objects', () => + expect( + writeToStream(objectRows, { + headers: true, + transform(row: csv.FormatterRowMap): csv.FormatterRow { + return { + A: row.a, + B: row.b, + }; + }, + }), + ).resolves.toEqual(['A,B', '\na1,b1', '\na2,b2'])); + + it('should transforming an array of multi-dimensional array', () => + expect( + writeToStream(multiDimensionalRows, { + headers: true, + transform(row: csv.FormatterRow): csv.FormatterRow { + return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); + }, + }), + ).resolves.toEqual(['a,b', '\nA1,B1', '\nA2,B2'])); + + describe('rowDelimiter option', () => { + it('should support specifying an alternate row delimiter', () => + expect(writeToStream(objectRows, { headers: true, rowDelimiter: '\r\n' })).resolves.toEqual([ + 'a,b', + '\r\na1,b1', + '\r\na2,b2', + ])); + + it('should escape values that contain the alternate row delimiter', async () => { + const rows = [ + { a: 'a\r\n1', b: 'b1' }, + { a: 'a\r\n2', b: 'b2' }, + ]; + await expect(writeToStream(rows, { headers: true, rowDelimiter: '\r\n' })).resolves.toEqual([ + 'a,b', + '\r\n"a\r\n1",b1', + '\r\n"a\r\n2",b2', + ]); + }); + }); + + it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => + expect(writeToStream(objectRows, { headers: true, includeEndRowDelimiter: true })).resolves.toEqual([ + 'a,b', + '\na1,b1', + '\na2,b2', + '\n', + ])); + }); +}); diff --git a/test/formatter/FormatterOptions.test.ts b/__tests__/formatter/FormatterOptions.spec.ts similarity index 52% rename from test/formatter/FormatterOptions.test.ts rename to __tests__/formatter/FormatterOptions.spec.ts index d8afe80f..b131416c 100644 --- a/test/formatter/FormatterOptions.test.ts +++ b/__tests__/formatter/FormatterOptions.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { FormatterOptionsArgs } from '../../src'; import { FormatterOptions } from '../../src/formatter'; @@ -7,99 +6,91 @@ describe('FormatterOptions', () => { describe('#objectMode', () => { it('should have default objectMode', () => { - assert.strictEqual(createOptions().objectMode, true); + expect(createOptions().objectMode).toBe(true); }); it('should accept a boolean objectMode', () => { - assert.strictEqual(createOptions({ objectMode: true }).objectMode, true); - assert.strictEqual(createOptions({ objectMode: false }).objectMode, false); + expect(createOptions({ objectMode: true }).objectMode).toBe(true); + expect(createOptions({ objectMode: false }).objectMode).toBe(false); }); }); describe('#delimiter', () => { it('should have default delimiter', () => { - assert.strictEqual(createOptions().delimiter, ','); + expect(createOptions().delimiter).toBe(','); }); it('should accept a custom delimiter', () => { - assert.strictEqual(createOptions({ delimiter: '\t' }).delimiter, '\t'); + expect(createOptions({ delimiter: '\t' }).delimiter).toBe('\t'); }); }); describe('#rowDelimiter', () => { it('should have default rowDelimiter', () => { - assert.strictEqual(createOptions().rowDelimiter, '\n'); + expect(createOptions().rowDelimiter).toBe('\n'); }); it('should accept a custom rowDelimiter', () => { - assert.strictEqual(createOptions({ rowDelimiter: '\r\n' }).rowDelimiter, '\r\n'); + expect(createOptions({ rowDelimiter: '\r\n' }).rowDelimiter).toBe('\r\n'); }); }); describe('#quote', () => { it('should set a default quote value', () => { - assert.strictEqual(createOptions().quote, '"'); + expect(createOptions().quote).toBe('"'); }); it('should accept an alternate quote', () => { - assert.strictEqual(createOptions({ quote: '$' }).quote, '$'); + expect(createOptions({ quote: '$' }).quote).toBe('$'); }); it('if the set to true the default quote should be used', () => { - assert.strictEqual(createOptions({ quote: true }).quote, '"'); + expect(createOptions({ quote: true }).quote).toBe('"'); }); it('if the set to false the quote should be empty', () => { - assert.strictEqual(createOptions({ quote: false }).quote, ''); + expect(createOptions({ quote: false }).quote).toBe(''); }); }); describe('#escape', () => { it('should set the escape character to the quote value if not specified', () => { - assert.strictEqual(createOptions().escape, '"'); + expect(createOptions().escape).toBe('"'); }); it('should set the escape character to the quote value if not specified', () => { - assert.strictEqual(createOptions({ quote: '$' }).escape, '$'); + expect(createOptions({ quote: '$' }).escape).toBe('$'); }); it('should accept an alternate escape', () => { - assert.strictEqual(createOptions({ escape: '%' }).escape, '%'); + expect(createOptions({ escape: '%' }).escape).toBe('%'); }); }); describe('#quoteColumns', () => { it('should set the quoteColumns to false', () => { - assert.strictEqual(createOptions().quoteColumns, false); + expect(createOptions().quoteColumns).toBe(false); }); it('should set the quoteColumns to true if specified', () => { - assert.strictEqual(createOptions({ quoteColumns: true }).quoteColumns, true); + expect(createOptions({ quoteColumns: true }).quoteColumns).toBe(true); }); it('should set the quoteColumns to an array if specified', () => { - assert.deepStrictEqual(createOptions({ quoteColumns: [true, true, true] }).quoteColumns, [ - true, - true, - true, - ]); + expect(createOptions({ quoteColumns: [true, true, true] }).quoteColumns).toEqual([true, true, true]); }); it('should set the quoteColumns to an object if specified', () => { - assert.deepStrictEqual(createOptions({ quoteColumns: { a: true, b: false } }).quoteColumns, { + expect(createOptions({ quoteColumns: { a: true, b: false } }).quoteColumns).toEqual({ a: true, b: false, }); }); it('should set quoteHeaders to quoteColumns if quoteHeaders is not specified and quoteColumns is', () => { - assert.deepStrictEqual(createOptions({ quoteColumns: true }).quoteHeaders, true); - assert.deepStrictEqual(createOptions({ quoteColumns: [true, true, true] }).quoteHeaders, [ - true, - true, - true, - ]); - assert.deepStrictEqual(createOptions({ quoteColumns: { a: true, b: false } }).quoteHeaders, { + expect(createOptions({ quoteColumns: true }).quoteHeaders).toBe(true); + expect(createOptions({ quoteColumns: [true, true, true] }).quoteHeaders).toEqual([true, true, true]); + expect(createOptions({ quoteColumns: { a: true, b: false } }).quoteHeaders).toEqual({ a: true, b: false, }); @@ -108,23 +99,19 @@ describe('FormatterOptions', () => { describe('#quoteHeaders', () => { it('should set the quoteHeaders to false', () => { - assert.strictEqual(createOptions().quoteHeaders, false); + expect(createOptions().quoteHeaders).toBe(false); }); it('should set the quoteHeaders to true if specified', () => { - assert.strictEqual(createOptions({ quoteHeaders: true }).quoteHeaders, true); + expect(createOptions({ quoteHeaders: true }).quoteHeaders).toBe(true); }); it('should set the quoteHeaders to an array if specified', () => { - assert.deepStrictEqual(createOptions({ quoteHeaders: [true, true, true] }).quoteHeaders, [ - true, - true, - true, - ]); + expect(createOptions({ quoteHeaders: [true, true, true] }).quoteHeaders).toEqual([true, true, true]); }); it('should set the quoteHeaders to an object if specified', () => { - assert.deepStrictEqual(createOptions({ quoteHeaders: { a: true, b: false } }).quoteHeaders, { + expect(createOptions({ quoteHeaders: { a: true, b: false } }).quoteHeaders).toEqual({ a: true, b: false, }); @@ -133,53 +120,53 @@ describe('FormatterOptions', () => { describe('#headers', () => { it('should have default headers', () => { - assert.strictEqual(createOptions().headers, null); + expect(createOptions().headers).toBeNull(); }); it('should accept an array of headers', () => { - assert.deepStrictEqual(createOptions({ headers: ['1', '2', '3'] }).headers, ['1', '2', '3']); + expect(createOptions({ headers: ['1', '2', '3'] }).headers).toEqual(['1', '2', '3']); }); it('should accept an boolean and set headers to null', () => { - assert.deepStrictEqual(createOptions({ headers: true }).headers, null); + expect(createOptions({ headers: true }).headers).toBeNull(); }); it('should set hasHeaders provided to true if headers is provided as an array', () => { - assert.deepStrictEqual(createOptions({ headers: ['1', '2', '3'] }).shouldWriteHeaders, true); + expect(createOptions({ headers: ['1', '2', '3'] }).shouldWriteHeaders).toBe(true); }); it('should set hasHeaders provided to false if headers is provided as a boolean', () => { - assert.deepStrictEqual(createOptions({ headers: true }).shouldWriteHeaders, true); + expect(createOptions({ headers: true }).shouldWriteHeaders).toBe(true); }); }); describe('#includeEndRowDelimiter', () => { it('should set includeEndRowDelimiter to false by default', () => { - assert.strictEqual(createOptions().includeEndRowDelimiter, false); + expect(createOptions().includeEndRowDelimiter).toBe(false); }); it('should set to true if the includeEndRowDelimiter is specified', () => { - assert.strictEqual(createOptions({ includeEndRowDelimiter: true }).includeEndRowDelimiter, true); + expect(createOptions({ includeEndRowDelimiter: true }).includeEndRowDelimiter).toBe(true); }); }); describe('#writeBOM', () => { it('should set writeBOM to false by default', () => { - assert.strictEqual(createOptions().writeBOM, false); + expect(createOptions().writeBOM).toBe(false); }); it('should set to true if the writeBOM is specified', () => { - assert.strictEqual(createOptions({ writeBOM: true }).writeBOM, true); + expect(createOptions({ writeBOM: true }).writeBOM).toBe(true); }); }); describe('#alwaysWriteHeaders', () => { it('should set alwaysWriteHeaders to false by default', () => { - assert.strictEqual(createOptions().alwaysWriteHeaders, false); + expect(createOptions().alwaysWriteHeaders).toBe(false); }); it('should set to provided value if the alwaysWriteHeaders is specified', () => { - assert.strictEqual(createOptions({ alwaysWriteHeaders: true }).alwaysWriteHeaders, true); + expect(createOptions({ alwaysWriteHeaders: true }).alwaysWriteHeaders).toBe(true); }); }); }); diff --git a/test/formatter/assets/.gitkeep b/__tests__/formatter/__fixtures__/.gitkeep similarity index 100% rename from test/formatter/assets/.gitkeep rename to __tests__/formatter/__fixtures__/.gitkeep diff --git a/test/formatter/formatter/FieldFormatter.test.ts b/__tests__/formatter/formatter/FieldFormatter.spec.ts similarity index 73% rename from test/formatter/formatter/FieldFormatter.test.ts rename to __tests__/formatter/formatter/FieldFormatter.spec.ts index a469260e..ff26c8a6 100644 --- a/test/formatter/formatter/FieldFormatter.test.ts +++ b/__tests__/formatter/formatter/FieldFormatter.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { FormatterOptionsArgs } from '../../../src'; import { FormatterOptions, FieldFormatter } from '../../../src/formatter'; @@ -11,94 +10,94 @@ describe('FieldFormatter', () => { describe('header columns', () => { it('should return the field not quoted if it contains no quotes', () => { const formatter = createFormatter(); - assert.strictEqual(formatter.format('header', 0, true), 'header'); + expect(formatter.format('header', 0, true)).toEqual('header'); }); it('should quote the field and escape quotes if it contains a quote character', () => { const formatter = createFormatter(); - assert.strictEqual(formatter.format('hea"d"er', 0, true), '"hea""d""er"'); + expect(formatter.format('hea"d"er', 0, true)).toEqual('"hea""d""er"'); }); it('should quote the field and if it contains a rowDelimiter', () => { const formatter = createFormatter({ rowDelimiter: '\r\n' }); - assert.strictEqual(formatter.format('hea\r\nder', 0, true), '"hea\r\nder"'); + expect(formatter.format('hea\r\nder', 0, true)).toEqual('"hea\r\nder"'); }); it('should quote the field if quoteHeaders is true', () => { const formatter = createFormatter({ quoteHeaders: true }); - assert.strictEqual(formatter.format('header', 0, true), '"header"'); + expect(formatter.format('header', 0, true)).toEqual('"header"'); }); it('should quote the header if quote headers is an array and the index of the header is true in the quoteHeaders array', () => { const formatter = createFormatter({ quoteHeaders: [true] }); - assert.strictEqual(formatter.format('header', 0, true), '"header"'); + expect(formatter.format('header', 0, true)).toEqual('"header"'); }); it('should not quote the header if quote headers is an array and the index of the header is false in the quoteHeaders array', () => { const formatter = createFormatter({ quoteHeaders: [false] }); - assert.strictEqual(formatter.format('header', 0, true), 'header'); + expect(formatter.format('header', 0, true)).toEqual('header'); }); it('should quote the header if quoteHeaders is an object and quoteHeaders object has true for the column name', () => { const formatter = createFormatter({ quoteHeaders: { header: true }, headers: ['header'] }); - assert.strictEqual(formatter.format('header', 0, true), '"header"'); + expect(formatter.format('header', 0, true)).toEqual('"header"'); }); it('should not quote the header if quoteHeaders is an object and quoteHeaders object has false for the column nam', () => { const formatter = createFormatter({ quoteHeaders: { header: false }, headers: ['header'] }); - assert.strictEqual(formatter.format('header', 0, true), 'header'); + expect(formatter.format('header', 0, true)).toEqual('header'); }); it('should not quote the header if quoteHeaders is an object and quoteHeaders object does not contain the header', () => { const formatter = createFormatter({ quoteHeaders: { header2: true }, headers: ['header'] }); - assert.strictEqual(formatter.format('header', 0, true), 'header'); + expect(formatter.format('header', 0, true)).toEqual('header'); }); }); describe('non-header columns', () => { it('should return the field not quoted if it contains no quotes', () => { const formatter = createFormatter(); - assert.strictEqual(formatter.format('col', 0, false), 'col'); + expect(formatter.format('col', 0, false)).toEqual('col'); }); it('should quote the field and escape quotes if it contains a quote character', () => { const formatter = createFormatter(); - assert.strictEqual(formatter.format('c"o"l', 0, false), '"c""o""l"'); + expect(formatter.format('c"o"l', 0, false)).toEqual('"c""o""l"'); }); it('should quote the field if it contains a rowDelimiter', () => { const formatter = createFormatter({ rowDelimiter: '\r\n' }); - assert.strictEqual(formatter.format('col\r\n', 0, false), '"col\r\n"'); + expect(formatter.format('col\r\n', 0, false)).toEqual('"col\r\n"'); }); it('should quote the field if quoteColumns is true', () => { const formatter = createFormatter({ quoteColumns: true }); - assert.strictEqual(formatter.format('col', 0, false), '"col"'); + expect(formatter.format('col', 0, false)).toEqual('"col"'); }); it('should quote the header if quote headers is an array and the index of the header is true in the quoteColumns array', () => { const formatter = createFormatter({ quoteColumns: [true] }); - assert.strictEqual(formatter.format('col', 0, false), '"col"'); + expect(formatter.format('col', 0, false)).toEqual('"col"'); }); it('should not quote the header if quote headers is an array and the index of the header is false in the quoteColumns array', () => { const formatter = createFormatter({ quoteColumns: [false] }); - assert.strictEqual(formatter.format('col', 0, false), 'col'); + expect(formatter.format('col', 0, false)).toEqual('col'); }); it('should quote the header if quoteColumns is an object and quoteColumns object has true for the column name', () => { const formatter = createFormatter({ quoteColumns: { header: true }, headers: ['header'] }); - assert.strictEqual(formatter.format('col', 0, false), '"col"'); + expect(formatter.format('col', 0, false)).toEqual('"col"'); }); it('should not quote the header if quoteColumns is an object and quoteColumns object has false for the column nam', () => { const formatter = createFormatter({ quoteColumns: { header: false }, headers: ['header'] }); - assert.strictEqual(formatter.format('col', 0, false), 'col'); + expect(formatter.format('col', 0, false)).toEqual('col'); }); it('should not quote the header if quoteColumns is an object and quoteColumns object does not contain the header', () => { const formatter = createFormatter({ quoteColumns: { header2: true }, headers: ['header'] }); - assert.strictEqual(formatter.format('col', 0, false), 'col'); + expect(formatter.format('col', 0, false)).toEqual('col'); }); }); }); diff --git a/test/formatter/formatter/RowFormatter.test.ts b/__tests__/formatter/formatter/RowFormatter.spec.ts similarity index 58% rename from test/formatter/formatter/RowFormatter.test.ts rename to __tests__/formatter/formatter/RowFormatter.spec.ts index aa3052cc..64b68864 100644 --- a/test/formatter/formatter/RowFormatter.test.ts +++ b/__tests__/formatter/formatter/RowFormatter.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { FormatterRow as Row, FormatterRowArray as RowArray, @@ -49,89 +48,78 @@ describe('RowFormatter', () => { setImmediate(() => cb(new Error('Expected Error'))); }; - it('should format an array', () => { + it('should format an array', async () => { const formatter = createFormatter({ headers: true }); - return formatRow(headerRow, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b'])); + await expect(formatRow(headerRow, formatter)).resolves.toEqual(['a,b']); }); - it('should should append a new line if a second row is written', () => { + it('should should append a new line if a second row is written', async () => { const formatter = createFormatter({ headers: true }); - return formatRow(headerRow, formatter) - .then(rows => assert.deepStrictEqual(rows, ['a,b'])) - .then(() => formatRow(columnsRow, formatter)) - .then(rows => assert.deepStrictEqual(rows, ['\na1,b1'])); + await expect(formatRow(headerRow, formatter)).resolves.toEqual(['a,b']); + await expect(formatRow(columnsRow, formatter)).resolves.toEqual(['\na1,b1']); }); - it('should support a sync transform', () => { + it('should support a sync transform', async () => { const formatter = createFormatter({ headers: true, transform: syncTransform }); - return formatRow(headerRow, formatter).then(rows => assert.deepStrictEqual(rows, ['A,B'])); + await expect(formatRow(headerRow, formatter)).resolves.toEqual(['A,B']); }); - it('should catch a sync transform thrown error', () => { + it('should catch a sync transform thrown error', async () => { const formatter = createFormatter({ headers: true, transform: syncError }); - return formatRow(headerRow, formatter).catch(err => assert.strictEqual(err.message, 'Expected Error')); + await expect(formatRow(headerRow, formatter)).rejects.toThrowError('Expected Error'); }); - it('should support an async transform', () => { + it('should support an async transform', async () => { const formatter = createFormatter({ headers: true, transform: asyncTransform }); - return formatRow(headerRow, formatter).then(rows => assert.deepStrictEqual(rows, ['A,B'])); + await expect(formatRow(headerRow, formatter)).resolves.toEqual(['A,B']); }); - it('should support an async transform with error', () => { + it('should support an async transform with error', async () => { const formatter = createFormatter({ headers: true, transform: asyncErrorTransform }); - return formatRow(headerRow, formatter).catch(err => assert.strictEqual(err.message, 'Expected Error')); + await expect(formatRow(headerRow, formatter)).rejects.toThrowError('Expected Error'); }); describe('headers option', () => { describe('with headers=false', () => { - it('should still write the first row', () => { + it('should still write the first row', async () => { const formatter = createFormatter({ headers: false }); - return formatRow(headerRow, formatter).then(rows => - assert.deepStrictEqual(rows, [headerRow.join(',')]), - ); + await expect(formatRow(headerRow, formatter)).resolves.toEqual([headerRow.join(',')]); }); }); describe('with headers=true', () => { - it('should only write the first row', () => { + it('should only write the first row', async () => { const formatter = createFormatter({ headers: true }); - return formatRow(headerRow, formatter).then(rows => - assert.deepStrictEqual(rows, [headerRow.join(',')]), - ); + await expect(formatRow(headerRow, formatter)).resolves.toEqual([headerRow.join(',')]); }); }); describe('with headers provided', () => { - it('should only write the first row', () => { + it('should only write the first row', async () => { const formatter = createFormatter({ headers: headerRow }); - return formatRow(columnsRow, formatter).then(rows => - assert.deepStrictEqual(rows, [headerRow.join(','), `\n${columnsRow.join(',')}`]), - ); + await expect(formatRow(columnsRow, formatter)).resolves.toEqual([ + headerRow.join(','), + `\n${columnsRow.join(',')}`, + ]); }); - it('should append an additional column for new fields', () => { + it('should append an additional column for new fields', async () => { const formatter = createFormatter({ headers: ['A', 'B', 'no_field'] }); - return formatRow(columnsRow, formatter).then(rows => - assert.deepStrictEqual(rows, ['A,B,no_field', '\na1,b1,']), - ); + await expect(formatRow(columnsRow, formatter)).resolves.toEqual(['A,B,no_field', '\na1,b1,']); }); - it('should exclude columns that do not have a header', () => { + it('should exclude columns that do not have a header', async () => { const formatter = createFormatter({ headers: ['A'] }); - return formatRow(columnsRow, formatter).then(rows => - assert.deepStrictEqual(rows, ['A', '\na1']), - ); + await expect(formatRow(columnsRow, formatter)).resolves.toEqual(['A', '\na1']); }); }); }); describe('rowDelimiter option', () => { - it('should support specifying an alternate row delimiter', () => { + it('should support specifying an alternate row delimiter', async () => { const formatter = createFormatter({ headers: true, rowDelimiter: '\r\n' }); - return formatRow(headerRow, formatter) - .then(rows => assert.deepStrictEqual(rows, ['a,b'])) - .then(() => formatRow(columnsRow, formatter)) - .then(rows => assert.deepStrictEqual(rows, ['\r\na1,b1'])); + await expect(formatRow(headerRow, formatter)).resolves.toEqual(['a,b']); + await expect(formatRow(columnsRow, formatter)).resolves.toEqual(['\r\na1,b1']); }); }); }); @@ -154,75 +142,73 @@ describe('RowFormatter', () => { const asyncErrorTransform = (rowToTransform: RowHashArray, cb: RowTransformCallback) => setImmediate(() => cb(new Error('Expected Error'))); - it('should format a multi-dimensional array with headers true', () => { + it('should format a multi-dimensional array with headers true', async () => { const formatter = createFormatter({ headers: true }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b', '\na1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b', '\na1,b1']); }); - it('should not include headers if headers is false', () => { + it('should not include headers if headers is false', async () => { const formatter = createFormatter({ headers: false }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a1,b1']); }); - it('should support a sync transform', () => { + it('should support a sync transform', async () => { const formatter = createFormatter({ headers: true, transform: syncTransform }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b', '\nA1,B1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b', '\nA1,B1']); }); - it('should catch a sync transform thrown error', () => { + it('should catch a sync transform thrown error', async () => { const formatter = createFormatter({ headers: true, transform: syncError }); - return formatRow(row, formatter).catch(err => assert.strictEqual(err.message, 'Expected Error')); + await expect(formatRow(row, formatter)).rejects.toThrowError('Expected Error'); }); - it('should support an async transform', () => { + it('should support an async transform', async () => { const formatter = createFormatter({ headers: true, transform: asyncTransform }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b', '\nA1,B1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b', '\nA1,B1']); }); - it('should support an async transform with error', () => { + it('should support an async transform with error', async () => { const formatter = createFormatter({ headers: true, transform: asyncErrorTransform }); - return formatRow(row, formatter).catch(err => assert.strictEqual(err.message, 'Expected Error')); + await expect(formatRow(row, formatter)).rejects.toThrowError('Expected Error'); }); describe('headers option', () => { describe('with headers=false', () => { - it('should still write the first row', () => { + it('should still write the first row', async () => { const formatter = createFormatter({ headers: false }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a1,b1']); }); }); describe('with headers=true', () => { - it('should only write the first row', () => { + it('should only write the first row', async () => { const formatter = createFormatter({ headers: true }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b', '\na1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b', '\na1,b1']); }); }); describe('with headers provided', () => { - it('should write the headers and first row', () => { + it('should write the headers and first row', async () => { const formatter = createFormatter({ headers: ['A', 'B'] }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['A,B', '\na1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['A,B', '\na1,b1']); }); - it('should append an additional column for new fields', () => { + it('should append an additional column for new fields', async () => { const formatter = createFormatter({ headers: ['A', 'B', 'no_field'] }); - return formatRow(row, formatter).then(rows => - assert.deepStrictEqual(rows, ['A,B,no_field', '\na1,b1,']), - ); + await expect(formatRow(row, formatter)).resolves.toEqual(['A,B,no_field', '\na1,b1,']); }); - it('should exclude columns that do not have a header', () => { + it('should exclude columns that do not have a header', async () => { const formatter = createFormatter({ headers: ['A'] }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['A', '\na1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['A', '\na1']); }); }); }); describe('rowDelimiter option', () => { - it('should support specifying an alternate row delimiter', () => { + it('should support specifying an alternate row delimiter', async () => { const formatter = createFormatter({ headers: true, rowDelimiter: '\r\n' }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b', '\r\na1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b', '\r\na1,b1']); }); }); }); @@ -242,75 +228,73 @@ describe('RowFormatter', () => { const asyncErrorTransform = (rowToTransform: RowMap, cb: RowTransformCallback) => setImmediate(() => cb(new Error('Expected Error'))); - it('should return a headers row with when headers true', () => { + it('should return a headers row with when headers true', async () => { const formatter = createFormatter({ headers: true }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b', '\na1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b', '\na1,b1']); }); - it('should not include headers if headers is false', () => { + it('should not include headers if headers is false', async () => { const formatter = createFormatter({ headers: false }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a1,b1']); }); - it('should support a sync transform', () => { + it('should support a sync transform', async () => { const formatter = createFormatter({ headers: true, transform: syncTransform }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b', '\nA1,B1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b', '\nA1,B1']); }); - it('should catch a sync transform thrown error', () => { + it('should catch a sync transform thrown error', async () => { const formatter = createFormatter({ headers: true, transform: syncError }); - return formatRow(row, formatter).catch(err => assert.strictEqual(err.message, 'Expected Error')); + await expect(formatRow(row, formatter)).rejects.toThrowError('Expected Error'); }); - it('should support an async transform', () => { + it('should support an async transform', async () => { const formatter = createFormatter({ headers: true, transform: asyncTransform }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b', '\nA1,B1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b', '\nA1,B1']); }); - it('should support an async transform with error', () => { + it('should support an async transform with error', async () => { const formatter = createFormatter({ headers: true, transform: asyncErrorTransform }); - return formatRow(row, formatter).catch(err => assert.strictEqual(err.message, 'Expected Error')); + await expect(formatRow(row, formatter)).rejects.toThrowError('Expected Error'); }); describe('headers option', () => { describe('with headers=false', () => { - it('should still write the first row', () => { + it('should still write the first row', async () => { const formatter = createFormatter({ headers: false }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a1,b1']); }); }); describe('with headers=true', () => { - it('should only write the first row', () => { + it('should only write the first row', async () => { const formatter = createFormatter({ headers: true }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b', '\na1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b', '\na1,b1']); }); }); describe('with headers provided', () => { - it('should the new headers and the row', () => { + it('should the new headers and the row', async () => { const formatter = createFormatter({ headers: ['a', 'b'] }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b', '\na1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b', '\na1,b1']); }); - it('should respect the order of the columns', () => { + it('should respect the order of the columns', async () => { const formatter = createFormatter({ headers: ['b', 'a'] }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['b,a', '\nb1,a1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['b,a', '\nb1,a1']); }); - it('should append an additional column for new fields', () => { + it('should append an additional column for new fields', async () => { const formatter = createFormatter({ headers: ['a', 'b', 'no_field'] }); - return formatRow(row, formatter).then(rows => - assert.deepStrictEqual(rows, ['a,b,no_field', '\na1,b1,']), - ); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b,no_field', '\na1,b1,']); }); }); }); describe('rowDelimiter option', () => { - it('should support specifying an alternate row delimiter', () => { + it('should support specifying an alternate row delimiter', async () => { const formatter = createFormatter({ headers: true, rowDelimiter: '\r\n' }); - return formatRow(row, formatter).then(rows => assert.deepStrictEqual(rows, ['a,b', '\r\na1,b1'])); + await expect(formatRow(row, formatter)).resolves.toEqual(['a,b', '\r\na1,b1']); }); }); }); @@ -318,38 +302,31 @@ describe('RowFormatter', () => { describe('#finish', () => { describe('alwaysWriteHeaders option', () => { - it('should return a headers row if no rows have been written', () => { + it('should return a headers row if no rows have been written', async () => { const headers = ['h1', 'h2']; const formatter = createFormatter({ headers, alwaysWriteHeaders: true }); - return finish(formatter).then(rows => assert.deepStrictEqual(rows, [headers.join(',')])); + await expect(finish(formatter)).resolves.toEqual([headers.join(',')]); }); - it('should not return a headers row if rows have been written', () => { + it('should not return a headers row if rows have been written', async () => { const headers = ['h1', 'h2']; const formatter = createFormatter({ headers, alwaysWriteHeaders: true }); - return formatRow(['c1', 'c2'], formatter) - .then(rows => { - assert.deepStrictEqual(rows, ['h1,h2', '\nc1,c2']); - return finish(formatter); - }) - .then(rows => assert.deepStrictEqual(rows, [])); + await expect(formatRow(['c1', 'c2'], formatter)).resolves.toEqual(['h1,h2', '\nc1,c2']); + await expect(finish(formatter)).resolves.toEqual([]); }); - it('should reject if headers are not specified', () => { + it('should reject if headers are not specified', async () => { const formatter = createFormatter({ alwaysWriteHeaders: true }); - return finish(formatter).catch(e => - assert.strictEqual( - e.message, - '`alwaysWriteHeaders` option is set to true but `headers` option not provided.', - ), + await expect(finish(formatter)).rejects.toThrowError( + '`alwaysWriteHeaders` option is set to true but `headers` option not provided.', ); }); }); describe('includeEndRowDelimiter option', () => { - it('should write the endRowDelimiter if ', () => { + it('should write the endRowDelimiter if ', async () => { const formatter = createFormatter({ includeEndRowDelimiter: true }); - return finish(formatter).then(rows => assert.deepStrictEqual(rows, ['\n'])); + await expect(finish(formatter)).resolves.toEqual(['\n']); }); }); }); @@ -357,10 +334,10 @@ describe('RowFormatter', () => { describe('#rowTransform', () => { it('should throw an error if the transform is set and is not a function', () => { const formatter = createFormatter(); - assert.throws(() => { + expect(() => { // @ts-ignore formatter.rowTransform = 'foo'; - }, /TypeError: The transform should be a function/); + }).toThrow('The transform should be a function'); }); }); }); diff --git a/test/issues/assets/issue102.csv b/__tests__/issues/__fixtures__/issue102.csv similarity index 100% rename from test/issues/assets/issue102.csv rename to __tests__/issues/__fixtures__/issue102.csv diff --git a/test/issues/assets/issue68-invalid.tsv b/__tests__/issues/__fixtures__/issue68-invalid.tsv similarity index 100% rename from test/issues/assets/issue68-invalid.tsv rename to __tests__/issues/__fixtures__/issue68-invalid.tsv diff --git a/test/issues/assets/issue68.tsv b/__tests__/issues/__fixtures__/issue68.tsv similarity index 100% rename from test/issues/assets/issue68.tsv rename to __tests__/issues/__fixtures__/issue68.tsv diff --git a/test/issues/assets/issue87.csv b/__tests__/issues/__fixtures__/issue87.csv similarity index 100% rename from test/issues/assets/issue87.csv rename to __tests__/issues/__fixtures__/issue87.csv diff --git a/test/issues/issue102.test.ts b/__tests__/issues/issue102.spec.ts similarity index 73% rename from test/issues/issue102.test.ts rename to __tests__/issues/issue102.spec.ts index a2434f1c..62c8870f 100644 --- a/test/issues/issue102.test.ts +++ b/__tests__/issues/issue102.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { resolve } from 'path'; import { parseFile } from '../../src'; @@ -16,16 +15,18 @@ describe('Issue #102 - https://github.com/C2FO/fast-csv/issues/102', () => { it('parse all rows ', next => { let receivedRows = 0; - parseFile(resolve(__dirname, 'assets', 'issue102.csv')) + parseFile(resolve(__dirname, '__fixtures__', 'issue102.csv')) .on('data-invalid', () => next(new Error('Should not have received data-invalid event'))) .on('data', r => { receivedRows += 1; - assert.deepStrictEqual(r, row); + if (receivedRows % 1000 === 0) { + expect(r).toEqual(row); + } }) .on('error', err => next(err)) .on('end', (rowCount: number) => { - assert.strictEqual(rowCount, 100000); - assert.strictEqual(receivedRows, rowCount); + expect(rowCount).toBe(100000); + expect(receivedRows).toBe(rowCount); next(); }); }); diff --git a/test/issues/issue111.test.ts b/__tests__/issues/issue111.spec.ts similarity index 87% rename from test/issues/issue111.test.ts rename to __tests__/issues/issue111.spec.ts index 85937a1c..57ab5316 100644 --- a/test/issues/issue111.test.ts +++ b/__tests__/issues/issue111.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { ParserOptions, Parser } from '../../src/parser'; describe('Issue #111 - https://github.com/C2FO/fast-csv/issues/111', () => { @@ -8,7 +7,7 @@ describe('Issue #111 - https://github.com/C2FO/fast-csv/issues/111', () => { it('should parse a block of CSV text with a trailing delimiter', () => { const data = 'first_name,last_name,email_address,empty\nFirst1,Last1,email1@email.com,\n'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(runParser(data, false, myParser), { + expect(runParser(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -20,7 +19,7 @@ describe('Issue #111 - https://github.com/C2FO/fast-csv/issues/111', () => { it('should parse a block of CSV text with a delimiter at file end', () => { const data = 'first_name,last_name,email_address,empty\nFirst1,Last1,email1@email.com,'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(runParser(data, false, myParser), { + expect(runParser(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -32,7 +31,7 @@ describe('Issue #111 - https://github.com/C2FO/fast-csv/issues/111', () => { it('should parse a block of CSV text with two delimiters at file end', () => { const data = 'first_name,last_name,email_address,empty1,empty2\nFirst1,Last1,email1@email.com,,'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(runParser(data, false, myParser), { + expect(runParser(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty1', 'empty2'], @@ -44,7 +43,7 @@ describe('Issue #111 - https://github.com/C2FO/fast-csv/issues/111', () => { it('should parse a block of CSV text with a trailing delimiter followed by a space', () => { const data = 'first_name,last_name,email_address,empty\nFirst1,Last1,email1@email.com, \n'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(runParser(data, false, myParser), { + expect(runParser(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -56,7 +55,7 @@ describe('Issue #111 - https://github.com/C2FO/fast-csv/issues/111', () => { it('should parse a block of Space Separated Value text with a trailing delimiter', () => { const data = 'first_name last_name email_address empty\nFirst1 Last1 email1@email.com \n'; const myParser = createParser({ delimiter: ' ' }); - assert.deepStrictEqual(runParser(data, false, myParser), { + expect(runParser(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -68,7 +67,7 @@ describe('Issue #111 - https://github.com/C2FO/fast-csv/issues/111', () => { it('should parse a block of Space Separated Values with two delimiters at file end', () => { const data = 'first_name last_name email_address empty empty2\nFirst1 Last1 email1@email.com \n'; const myParser = createParser({ delimiter: ' ' }); - assert.deepStrictEqual(runParser(data, false, myParser), { + expect(runParser(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty', 'empty2'], diff --git a/test/issues/issue131.test.ts b/__tests__/issues/issue131.spec.ts similarity index 79% rename from test/issues/issue131.test.ts rename to __tests__/issues/issue131.spec.ts index a5243ed9..3a556ebe 100644 --- a/test/issues/issue131.test.ts +++ b/__tests__/issues/issue131.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { EOL } from 'os'; import * as csv from '../../src'; @@ -13,8 +12,8 @@ describe('Issue #131 - https://github.com/C2FO/fast-csv/issues/131', () => { csv.parseString(csvWithBom, { headers: true }) .on('data', data => actual.push(data)) .on('end', (count: number) => { - assert.deepStrictEqual(actual[0].first_name, 'First1'); - assert.strictEqual(count, actual.length); + expect(actual[0].first_name).toBe('First1'); + expect(count).toBe(actual.length); next(); }); }); diff --git a/test/issues/issue150.test.ts b/__tests__/issues/issue150.spec.ts similarity index 89% rename from test/issues/issue150.test.ts rename to __tests__/issues/issue150.spec.ts index 4fd0cc04..db0ba99c 100644 --- a/test/issues/issue150.test.ts +++ b/__tests__/issues/issue150.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { ParserOptions, Parser } from '../../src/parser'; describe('Issue #150 - https://github.com/C2FO/fast-csv/issues/150', () => { @@ -9,7 +8,7 @@ describe('Issue #150 - https://github.com/C2FO/fast-csv/issues/150', () => { const data = 'first_name,last_name,email_address\r'; const myParser = createParser({}); const parsedData = runParser(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'first_name,last_name,email_address\r', rows: [], }); diff --git a/test/issues/issue158.test.ts b/__tests__/issues/issue158.spec.ts similarity index 88% rename from test/issues/issue158.test.ts rename to __tests__/issues/issue158.spec.ts index c70c1ed7..f794c22b 100644 --- a/test/issues/issue158.test.ts +++ b/__tests__/issues/issue158.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import * as csv from '../../src'; import RecordingStream from '../RecordingStream'; @@ -35,7 +34,7 @@ describe('Issue #158 - https://github.com/C2FO/fast-csv/issues/158', () => { .pipe(rs) .on('error', next) .on('finish', () => { - assert.deepStrictEqual(rs.data.join(''), 'id,name,calculatedValue\n1,a,2\n2,b,4\n3,c,6'); + expect(rs.data.join('')).toBe('id,name,calculatedValue\n1,a,2\n2,b,4\n3,c,6'); next(); }); }); diff --git a/test/issues/issue174.test.ts b/__tests__/issues/issue174.spec.ts similarity index 91% rename from test/issues/issue174.test.ts rename to __tests__/issues/issue174.spec.ts index 2e249095..c976a215 100644 --- a/test/issues/issue174.test.ts +++ b/__tests__/issues/issue174.spec.ts @@ -1,5 +1,4 @@ import { EOL } from 'os'; -import * as assert from 'assert'; import { ParserOptionsArgs } from '../../src'; import { Parser, ParserOptions } from '../../src/parser'; @@ -12,7 +11,7 @@ describe('Issue #174 - https://github.com/C2FO/fast-csv/issues/174', () => { it('skip trailing whitespace after a quoted field', () => { const parser = createParser({ headers: true }); const parsedData = runParser(CSV_CONTENT, false, parser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [ ['f1', 'f2', 'f3'], diff --git a/test/issues/issue214.test.ts b/__tests__/issues/issue214.spec.ts similarity index 84% rename from test/issues/issue214.test.ts rename to __tests__/issues/issue214.spec.ts index 72730894..2c9cf50a 100644 --- a/test/issues/issue214.test.ts +++ b/__tests__/issues/issue214.spec.ts @@ -1,5 +1,4 @@ import { EOL } from 'os'; -import * as assert from 'assert'; import * as csv from '../../src'; describe('Issue #214 - https://github.com/C2FO/fast-csv/issues/214', () => { @@ -24,8 +23,8 @@ describe('Issue #214 - https://github.com/C2FO/fast-csv/issues/214', () => { .on('data', (r: csv.ParserRowMap) => rows.push(r)) .on('error', next) .on('end', (count: number) => { - assert.deepStrictEqual(rows, expectedRows); - assert.strictEqual(count, expectedRows.length); + expect(rows).toEqual(expectedRows); + expect(count).toBe(expectedRows.length); next(); }); }); @@ -36,8 +35,8 @@ describe('Issue #214 - https://github.com/C2FO/fast-csv/issues/214', () => { .addListener('data', (r: csv.ParserRowMap) => rows.push(r)) .on('error', next) .on('end', (count: number) => { - assert.deepStrictEqual(rows, expectedRows); - assert.strictEqual(count, expectedRows.length); + expect(rows).toEqual(expectedRows); + expect(count).toBe(expectedRows.length); next(); }); }); diff --git a/test/issues/issue223.test.ts b/__tests__/issues/issue223.spec.ts similarity index 91% rename from test/issues/issue223.test.ts rename to __tests__/issues/issue223.spec.ts index 29948a1b..68b7967e 100644 --- a/test/issues/issue223.test.ts +++ b/__tests__/issues/issue223.spec.ts @@ -1,5 +1,4 @@ import { EOL } from 'os'; -import * as assert from 'assert'; import { Parser, ParserOptions } from '../../src/parser'; describe('Issue #223 - https://github.com/C2FO/fast-csv/issues/223', () => { @@ -10,7 +9,7 @@ describe('Issue #223 - https://github.com/C2FO/fast-csv/issues/223', () => { const CSV_CONTENT = ['"ABC" ,"DEFG" ,12345,"HI"', '"JKLM" ,"NOP" ,67890,"QR" '].join(EOL); const parser = createParser(); const parsedData = runParser(CSV_CONTENT, false, parser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [ ['ABC', 'DEFG', '12345', 'HI'], diff --git a/test/issues/issue252.test.ts b/__tests__/issues/issue252.spec.ts similarity index 81% rename from test/issues/issue252.test.ts rename to __tests__/issues/issue252.spec.ts index 238c6281..0c797c41 100644 --- a/test/issues/issue252.test.ts +++ b/__tests__/issues/issue252.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import * as csv from '../../src'; import RecordingStream from '../RecordingStream'; @@ -16,7 +15,7 @@ describe('Issue #252 - https://github.com/C2FO/fast-csv/issues/252', () => { .pipe(rs) .on('error', next) .on('finish', () => { - assert.deepStrictEqual(rs.data.join(''), 'header1,header2,header3\na,b,c\nd,e,f'); + expect(rs.data.join('')).toBe('header1,header2,header3\na,b,c\nd,e,f'); next(); }); }); diff --git a/test/issues/issue68.test.ts b/__tests__/issues/issue68.spec.ts similarity index 60% rename from test/issues/issue68.test.ts rename to __tests__/issues/issue68.spec.ts index 046d923c..dbb6b0dc 100644 --- a/test/issues/issue68.test.ts +++ b/__tests__/issues/issue68.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import * as path from 'path'; import * as domain from 'domain'; import * as csv from '../../src'; @@ -11,13 +10,16 @@ describe('Issue #68 - https://github.com/C2FO/fast-csv/issues/68', () => { d.exit(); if (!called) { called = true; - assert.strictEqual(/^Parse Error/.test(err.message), true); + expect(err.message).toMatch(/^Parse Error/); next(); } }); d.run(() => csv - .parseFile(path.resolve(__dirname, './assets/issue68-invalid.tsv'), { headers: true, delimiter: '\t' }) + .parseFile(path.resolve(__dirname, '__fixtures__', 'issue68-invalid.tsv'), { + headers: true, + delimiter: '\t', + }) .on('data', () => null), ); }); @@ -29,7 +31,7 @@ describe('Issue #68 - https://github.com/C2FO/fast-csv/issues/68', () => { d.exit(); if (!called) { called = true; - assert.strictEqual(err.message, 'Data error'); + expect(err.message).toBe('Data error'); next(); } else { throw err; @@ -37,15 +39,15 @@ describe('Issue #68 - https://github.com/C2FO/fast-csv/issues/68', () => { }); d.run(() => { let count = 0; - csv.parseFile(path.resolve(__dirname, './assets/issue68.tsv'), { headers: true, delimiter: '\t' }).on( - 'data', - () => { - count += 1; - if (count % 1001 === 0) { - throw new Error('Data error'); - } - }, - ); + csv.parseFile(path.resolve(__dirname, '__fixtures__', 'issue68.tsv'), { + headers: true, + delimiter: '\t', + }).on('data', () => { + count += 1; + if (count % 1001 === 0) { + throw new Error('Data error'); + } + }); }); }); }); diff --git a/test/issues/issue77.test.ts b/__tests__/issues/issue77.spec.ts similarity index 65% rename from test/issues/issue77.test.ts rename to __tests__/issues/issue77.spec.ts index ba423c4b..a90e3089 100644 --- a/test/issues/issue77.test.ts +++ b/__tests__/issues/issue77.spec.ts @@ -1,19 +1,17 @@ -import * as assert from 'assert'; import * as fs from 'fs'; import * as path from 'path'; import * as csv from '../../src'; describe('Issue #77 - https://github.com/C2FO/fast-csv/issues/77', () => { it('should sort columns by order of headers defined when formatting a csv', next => { - const writable = fs.createWriteStream(path.resolve(__dirname, 'assets/test.csv'), { encoding: 'utf8' }); + const writable = fs.createWriteStream(path.resolve(__dirname, '__fixtures__/test.csv'), { encoding: 'utf8' }); const csvStream = csv.format({ headers: ['second', 'first'] }).on('error', next); writable.on('finish', () => { - assert.strictEqual( - fs.readFileSync(path.resolve(__dirname, 'assets/test.csv')).toString(), - 'second,first\n2,1', + expect(fs.readFileSync(path.resolve(__dirname, '__fixtures__', 'test.csv'))).toEqual( + Buffer.from('second,first\n2,1'), ); - fs.unlinkSync(path.resolve(__dirname, 'assets/test.csv')); + fs.unlinkSync(path.resolve(__dirname, '__fixtures__', 'test.csv')); next(); }); @@ -25,15 +23,14 @@ describe('Issue #77 - https://github.com/C2FO/fast-csv/issues/77', () => { }); it('should write headers even with no data when formatting a csv', next => { - const writable = fs.createWriteStream(path.resolve(__dirname, 'assets/test.csv'), { encoding: 'utf8' }); + const writable = fs.createWriteStream(path.resolve(__dirname, '__fixtures__/test.csv'), { encoding: 'utf8' }); const csvStream = csv.format({ headers: ['first', 'second'] }).on('error', next); writable.on('finish', () => { - assert.strictEqual( - fs.readFileSync(path.resolve(__dirname, 'assets/test.csv')).toString(), - 'first,second\n,', + expect(fs.readFileSync(path.resolve(__dirname, '__fixtures__/test.csv'))).toEqual( + Buffer.from('first,second\n,'), ); - fs.unlinkSync(path.resolve(__dirname, 'assets/test.csv')); + fs.unlinkSync(path.resolve(__dirname, '__fixtures__/test.csv')); next(); }); diff --git a/test/issues/issue87.test.ts b/__tests__/issues/issue87.spec.ts similarity index 87% rename from test/issues/issue87.test.ts rename to __tests__/issues/issue87.spec.ts index 236f423d..556fcea1 100644 --- a/test/issues/issue87.test.ts +++ b/__tests__/issues/issue87.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import * as fs from 'fs'; import * as path from 'path'; import { Transform, TransformCallback } from 'stream'; @@ -31,13 +30,13 @@ describe('Issue #87 - https://github.com/C2FO/fast-csv/issues/87', () => { it('should not emit end until data is flushed from source', next => { const myStream = new MyStream(); - fs.createReadStream(path.resolve(__dirname, './assets/issue87.csv')) + fs.createReadStream(path.resolve(__dirname, '__fixtures__', 'issue87.csv')) .pipe(csv.parse({ headers: true })) .on('error', next) .pipe(myStream) .on('error', next) .on('finish', () => { - assert.strictEqual(myStream.rowCount, 99); + expect(myStream.rowCount).toBe(99); next(); }); }); diff --git a/test/issues/issue93.test.ts b/__tests__/issues/issue93.spec.ts similarity index 91% rename from test/issues/issue93.test.ts rename to __tests__/issues/issue93.spec.ts index c1076a19..7f525431 100644 --- a/test/issues/issue93.test.ts +++ b/__tests__/issues/issue93.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import * as domain from 'domain'; import { EOL } from 'os'; import * as csv from '../../src'; @@ -15,7 +14,7 @@ describe('Issue #93 - https://github.com/C2FO/fast-csv/issues/93', () => { throw err; } called = true; - assert.strictEqual(err.message, 'End error'); + expect(err.message).toBe('End error'); next(); }); d.run(() => @@ -40,7 +39,7 @@ describe('Issue #93 - https://github.com/C2FO/fast-csv/issues/93', () => { throw err; } called = true; - assert.strictEqual(err.message, 'End error'); + expect(err.message).toBe('End error'); next(); }); d.run(() => diff --git a/test/issues/issue97.test.ts b/__tests__/issues/issue97.spec.ts similarity index 81% rename from test/issues/issue97.test.ts rename to __tests__/issues/issue97.spec.ts index dcce783e..0e287f60 100644 --- a/test/issues/issue97.test.ts +++ b/__tests__/issues/issue97.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import * as csv from '../../src'; import RecordingStream from '../RecordingStream'; @@ -14,7 +13,7 @@ describe('Issue #97 - https://github.com/C2FO/fast-csv/issues/97', () => { .pipe(rs) .on('error', next) .on('finish', () => { - assert.deepStrictEqual(rs.data.join(''), 'field1,field2\na1"a,b1"b\na2"a,b2"b'); + expect(rs.data.join('')).toBe('field1,field2\na1"a,b1"b\na2"a,b2"b'); next(); }); }); diff --git a/test/parser/CsvParsingStream.test.ts b/__tests__/parser/CsvParsingStream.spec.ts similarity index 56% rename from test/parser/CsvParsingStream.test.ts rename to __tests__/parser/CsvParsingStream.spec.ts index e8f68df7..fe4fbadd 100644 --- a/test/parser/CsvParsingStream.test.ts +++ b/__tests__/parser/CsvParsingStream.spec.ts @@ -1,21 +1,19 @@ -/* eslint-disable no-cond-assign,@typescript-eslint/camelcase */ -import * as assert from 'assert'; +/* eslint-disable no-cond-assign,@typescript-eslint/camelcase,@typescript-eslint/no-explicit-any */ import * as fs from 'fs'; import * as domain from 'domain'; -import * as sinon from 'sinon'; import partition from 'lodash.partition'; import * as csv from '../../src'; -import assets, { PathAndContent } from './assets'; +import assets, { PathAndContent } from './__fixtures__'; import { CsvParserStream } from '../../src/parser'; -import Done = Mocha.Done; +import DoneCallback = jest.DoneCallback; describe('CsvParserStream', () => { - const listenForError = (stream: CsvParserStream, message: string, next: Done) => { + const listenForError = (stream: CsvParserStream, message: string, next: DoneCallback) => { let called = false; stream .on('error', (err: Error) => { - assert.strictEqual(err.message, message); + expect(err.message).toBe(message); if (!called) { called = true; next(); @@ -74,18 +72,27 @@ describe('CsvParserStream', () => { parser.end(); }); + const expectParsed = ( + resultsPromise: Promise, + expectedRows: any[], + expectedInvalidRows: any[] = [], + ): Promise => { + return expect(resultsPromise).resolves.toEqual({ + count: expectedRows.length + expectedInvalidRows.length, + rows: expectedRows, + invalidRows: expectedInvalidRows, + }); + }; + it('should parse a csv without quotes or escapes', () => - parseContentAndCollect(assets.withHeaders, { headers: true }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeaders.parsed); - assert.strictEqual(count, rows.length); - })); + expectParsed(parseContentAndCollect(assets.withHeaders, { headers: true }), assets.withHeaders.parsed)); it('should emit a readable event ', next => { const actual: csv.ParserRow[] = []; const parser = csv.parse({ headers: true }); const stream = parser.on('error', next).on('end', (count: number) => { - assert.deepStrictEqual(actual, assets.withHeaders.parsed); - assert.strictEqual(count, actual.length); + expect(actual).toEqual(assets.withHeaders.parsed); + expect(count).toBe(actual.length); next(); }); let index = 0; @@ -99,116 +106,95 @@ describe('CsvParserStream', () => { stream.end(); }); - it('should emit data as a buffer if objectMode is false', () => { + it('should emit data as a buffer if objectMode is false', async () => { const expected = assets.withHeaders.parsed.map(r => Buffer.from(JSON.stringify(r))); - return parseContentAndCollect(assets.withHeaders, { headers: true, objectMode: false }).then( - ({ count, rows }) => { - assert.deepStrictEqual(rows, expected); - assert.strictEqual(count, rows.length); - }, - ); + await expectParsed(parseContentAndCollect(assets.withHeaders, { headers: true, objectMode: false }), expected); }); it('should emit data as an object if objectMode is true', () => - parseContentAndCollect(assets.withHeaders, { headers: true, objectMode: true }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeaders.parsed); - assert.strictEqual(count, rows.length); - })); + expectParsed( + parseContentAndCollect(assets.withHeaders, { headers: true, objectMode: true }), + assets.withHeaders.parsed, + )); it('should emit data as an object if objectMode is not specified', () => - parseContentAndCollect(assets.withHeaders, { headers: true }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeaders.parsed); - assert.strictEqual(count, rows.length); - })); + expectParsed(parseContentAndCollect(assets.withHeaders, { headers: true }), assets.withHeaders.parsed)); it('should parse a csv with quotes', () => - parseContentAndCollect(assets.withHeadersAndQuotes, { headers: true }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeadersAndQuotes.parsed); - assert.strictEqual(count, rows.length); - })); + expectParsed( + parseContentAndCollect(assets.withHeadersAndQuotes, { headers: true }), + assets.withHeadersAndQuotes.parsed, + )); it('should parse a csv with without headers', () => - parseContentAndCollect(assets.noHeadersAndQuotes).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.noHeadersAndQuotes.parsed); - assert.strictEqual(count, rows.length); - })); + expectParsed(parseContentAndCollect(assets.noHeadersAndQuotes), assets.noHeadersAndQuotes.parsed)); it("should parse a csv with ' escapes", () => - parseContentAndCollect(assets.withHeadersAndAlternateQuote, { headers: true, quote: "'" }).then( - ({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeadersAndAlternateQuote.parsed); - assert.strictEqual(count, rows.length); - }, + expectParsed( + parseContentAndCollect(assets.withHeadersAndAlternateQuote, { headers: true, quote: "'" }), + assets.withHeadersAndAlternateQuote.parsed, )); describe('headers option', () => { - it('should allow specifying of headers', () => { + it('should allow specifying of headers', async () => { const expected = assets.noHeadersAndQuotes.parsed.map(r => ({ first_name: r[0], last_name: r[1], email_address: r[2], address: r[3], })); - return parseContentAndCollect(assets.noHeadersAndQuotes, { - headers: ['first_name', 'last_name', 'email_address', 'address'], - }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, expected); - assert.strictEqual(count, rows.length); - }); + await expectParsed( + parseContentAndCollect(assets.noHeadersAndQuotes, { + headers: ['first_name', 'last_name', 'email_address', 'address'], + }), + expected, + ); }); - it('should allow transforming headers with a function', () => { + it('should allow transforming headers with a function', async () => { const expected = assets.withHeadersAndQuotes.parsed.map(r => ({ firstName: r.first_name, lastName: r.last_name, emailAddress: r.email_address, address: r.address, })); - const transform = sinon.stub().returns(['firstName', 'lastName', 'emailAddress', 'address']); - return parseContentAndCollect(assets.withHeadersAndQuotes, { - headers: transform, - }).then(({ count, rows }) => { - sinon.assert.calledOnce(transform); - sinon.assert.calledWith(transform, ['first_name', 'last_name', 'email_address', 'address']); - assert.deepStrictEqual(rows, expected); - assert.strictEqual(count, rows.length); - }); + const transform = jest.fn().mockReturnValue(['firstName', 'lastName', 'emailAddress', 'address']); + await expectParsed(parseContentAndCollect(assets.withHeadersAndQuotes, { headers: transform }), expected); + expect(transform).toBeCalledTimes(1); + expect(transform).toBeCalledWith(['first_name', 'last_name', 'email_address', 'address']); }); describe('renameHeaders option', () => { - it('should allow renaming headers', () => { + it('should allow renaming headers', async () => { const expected = assets.withHeadersAndQuotes.parsed.map(r => ({ firstName: r.first_name, lastName: r.last_name, emailAddress: r.email_address, address: r.address, })); - return parseContentAndCollect(assets.withHeadersAndQuotes, { - headers: ['firstName', 'lastName', 'emailAddress', 'address'], - renameHeaders: true, - }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, expected); - assert.strictEqual(count, rows.length); - }); + await expectParsed( + parseContentAndCollect(assets.withHeadersAndQuotes, { + headers: ['firstName', 'lastName', 'emailAddress', 'address'], + renameHeaders: true, + }), + expected, + ); }); - it('should ignore the renameHeaders option if transforming headers with a function', () => { + it('should ignore the renameHeaders option if transforming headers with a function', async () => { const expected = assets.withHeadersAndQuotes.parsed.map(r => ({ firstName: r.first_name, lastName: r.last_name, emailAddress: r.email_address, address: r.address, })); - const transform = sinon.stub().returns(['firstName', 'lastName', 'emailAddress', 'address']); - return parseContentAndCollect(assets.withHeadersAndQuotes, { - headers: transform, - renameHeaders: true, - }).then(({ count, rows }) => { - sinon.assert.calledOnce(transform); - sinon.assert.calledWith(transform, ['first_name', 'last_name', 'email_address', 'address']); - assert.deepStrictEqual(rows, expected); - assert.strictEqual(count, rows.length); - }); + const transform = jest.fn().mockReturnValue(['firstName', 'lastName', 'emailAddress', 'address']); + await expectParsed( + parseContentAndCollect(assets.withHeadersAndQuotes, { headers: transform, renameHeaders: true }), + expected, + ); + expect(transform).toBeCalledTimes(1); + expect(transform).toBeCalledWith(['first_name', 'last_name', 'email_address', 'address']); }); it('should propagate an error when trying to rename headers without providing new ones', next => { @@ -241,121 +227,99 @@ describe('CsvParserStream', () => { }); it('should discard extra columns that do not map to a header when discardUnmappedColumns is true', () => - parseContentAndCollect(assets.headerColumnMismatch, { headers: true, discardUnmappedColumns: true }).then( - ({ count, rows }) => { - assert.deepStrictEqual(rows, assets.headerColumnMismatch.parsed); - assert.strictEqual(count, rows.length); - }, + expectParsed( + parseContentAndCollect(assets.headerColumnMismatch, { headers: true, discardUnmappedColumns: true }), + assets.headerColumnMismatch.parsed, )); - it('should report missing columns that do not exist but have a header with strictColumnHandling option', () => { + it('should report missing columns that do not exist but have a header with strictColumnHandling option', async () => { const expectedRows = assets.withHeadersAndMissingColumns.parsed.filter(r => r.address !== null); const expectedInvalidRows = assets.withHeadersAndMissingColumns.parsed .filter(r => r.address === null) .map(r => Object.values(r).filter(v => !!v)); - return parseContentAndCollect(assets.withHeadersAndMissingColumns, { - headers: true, - strictColumnHandling: true, - }).then(({ count, rows, invalidRows }) => { - assert.deepStrictEqual(rows, expectedRows); - assert.deepStrictEqual(invalidRows, expectedInvalidRows); - assert.strictEqual(count, rows.length + invalidRows.length); - }); + await expectParsed( + parseContentAndCollect(assets.withHeadersAndMissingColumns, { + headers: true, + strictColumnHandling: true, + }), + expectedRows, + expectedInvalidRows, + ); }); - it('should allow specifying of columns as a sparse array', () => { + it('should allow specifying of columns as a sparse array', async () => { const expected = assets.noHeadersAndQuotes.parsed.map(r => ({ first_name: r[0], email_address: r[2], })); - return parseContentAndCollect(assets.noHeadersAndQuotes, { - headers: ['first_name', undefined, 'email_address', undefined], - }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, expected); - assert.strictEqual(count, rows.length); - }); + await expectParsed( + parseContentAndCollect(assets.noHeadersAndQuotes, { + headers: ['first_name', undefined, 'email_address', undefined], + }), + expected, + ); }); }); it('should parse data with an alternate encoding', () => - parseContentAndCollect(assets.alternateEncoding, { headers: true, encoding: 'utf16le' }).then( - ({ count, rows }) => { - assert.deepStrictEqual(rows, assets.alternateEncoding.parsed); - assert.strictEqual(count, rows.length); - }, + expectParsed( + parseContentAndCollect(assets.alternateEncoding, { headers: true, encoding: 'utf16le' }), + assets.alternateEncoding.parsed, )); it('should handle a trailing comma', () => - parseContentAndCollect(assets.trailingComma, { headers: true }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.trailingComma.parsed); - assert.strictEqual(count, rows.length); - })); + expectParsed(parseContentAndCollect(assets.trailingComma, { headers: true }), assets.trailingComma.parsed)); it('should skip valid, but empty rows when ignoreEmpty is true', () => - parseContentAndCollect(assets.emptyRows, { headers: true, ignoreEmpty: true }).then( - ({ count, rows, invalidRows }) => { - assert.strictEqual(count, 0); - assert.deepStrictEqual(rows, []); - assert.deepStrictEqual(invalidRows, []); - }, - )); + expectParsed(parseContentAndCollect(assets.emptyRows, { headers: true, ignoreEmpty: true }), [])); describe('alternate delimiters', () => { ['\t', '|', ';'].forEach(delimiter => { - it(`should support '${delimiter.replace(/\t/, '\\t')}' delimiters`, () => { + it(`should support '${delimiter.replace(/\t/, '\\t')}' delimiters`, async () => { const { path: assetPath, content } = assets.withHeadersAlternateDelimiter; - const data = { - path: assetPath, - content: content(delimiter), - }; - return parseContentAndCollect(data, { headers: true, delimiter }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeadersAlternateDelimiter.parsed); - assert.strictEqual(count, rows.length); - }); + const data = { path: assetPath, content: content(delimiter) }; + await expectParsed( + parseContentAndCollect(data, { headers: true, delimiter }), + assets.withHeadersAlternateDelimiter.parsed, + ); }); }); }); describe('maxRows option', () => { - it('should parse up to the specified number of maxRows', () => { + it('should parse up to the specified number of maxRows', async () => { const maxRows = 3; - return parseContentAndCollect(assets.withHeaders, { headers: true, maxRows }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeaders.parsed.slice(0, maxRows)); - assert.strictEqual(count, maxRows); - }); + await expectParsed( + parseContentAndCollect(assets.withHeaders, { headers: true, maxRows }), + assets.withHeaders.parsed.slice(0, maxRows), + ); }); - it('should parse all rows if maxRows === 0', () => { + it('should parse all rows if maxRows === 0', async () => { const maxRows = 0; - return parseContentAndCollect(assets.withHeaders, { headers: true, maxRows }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeaders.parsed); - assert.strictEqual(count, rows.length); - }); + await expectParsed( + parseContentAndCollect(assets.withHeaders, { headers: true, maxRows }), + assets.withHeaders.parsed, + ); }); }); describe('skipLines option', () => { - it('should skip up to the specified number of rows using the first non-skipped line as headers', () => { + it('should skip up to the specified number of rows using the first non-skipped line as headers', async () => { const skipLines = 2; - return parseContentAndCollect(assets.withHeadersSkippedLines, { - headers: true, - skipLines, - }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeadersSkippedLines.parsed); - assert.strictEqual(count, rows.length); - }); + await expectParsed( + parseContentAndCollect(assets.withHeadersSkippedLines, { headers: true, skipLines }), + assets.withHeadersSkippedLines.parsed, + ); }); - it('should skip up to the specified number of rows not withoutHeaders', () => { + it('should skip up to the specified number of rows not withoutHeaders', async () => { const skipLines = 2; - return parseContentAndCollect(assets.skipLines, { skipLines }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.skipLines.parsed); - assert.strictEqual(count, rows.length); - }); + await expectParsed(parseContentAndCollect(assets.skipLines, { skipLines }), assets.skipLines.parsed); }); describe('with transform', () => { - it('should not transform skipped rows', () => { + it('should not transform skipped rows', async () => { let transformedRows: csv.ParserRow[] = []; const transformer = (row: csv.ParserRow): csv.ParserRow => { const transformed = { @@ -370,18 +334,13 @@ describe('CsvParserStream', () => { const expected = assets.withHeadersSkippedLines.parsed.map(transformer); transformedRows = []; const parser = csv.parse({ headers: true, skipLines }).transform(transformer); - return parseContentAndCollectFromStream(assets.withHeadersSkippedLines, parser).then( - ({ count, rows }) => { - assert.deepStrictEqual(rows, expected); - assert.deepStrictEqual(transformedRows, expected); - assert.strictEqual(count, expected.length); - }, - ); + await expectParsed(parseContentAndCollectFromStream(assets.withHeadersSkippedLines, parser), expected); + expect(transformedRows).toEqual(expected); }); }); describe('with validate', () => { - it('should not validate skipped rows', () => { + it('should not validate skipped rows', async () => { let validatedRows: csv.ParserRow[] = []; const validator = (row: csv.ParserRow): boolean => { validatedRows.push(row); @@ -389,96 +348,83 @@ describe('CsvParserStream', () => { }; const skipLines = 2; const nonSkippedRows = assets.withHeadersSkippedLines.parsed; - const expected = nonSkippedRows.filter(validator); + const [expected, invalid] = partition(nonSkippedRows, validator); validatedRows = []; const parser = csv.parse({ headers: true, skipLines }).validate(validator); - return parseContentAndCollectFromStream(assets.withHeadersSkippedLines, parser).then( - ({ count, rows }) => { - assert.deepStrictEqual(rows, expected); - assert.deepStrictEqual(validatedRows, nonSkippedRows); - assert.strictEqual(count, nonSkippedRows.length); - }, + await expectParsed( + parseContentAndCollectFromStream(assets.withHeadersSkippedLines, parser), + expected, + invalid, ); + expect(validatedRows).toEqual(nonSkippedRows); }); }); - it('should parse all rows if maxRows === 0', () => { + it('should parse all rows if maxRows === 0', async () => { const skipLines = 0; - return parseContentAndCollect(assets.withHeaders, { headers: true, skipLines }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeaders.parsed); - assert.strictEqual(count, rows.length); - }); + await expectParsed( + parseContentAndCollect(assets.withHeaders, { headers: true, skipLines }), + assets.withHeaders.parsed, + ); }); }); describe('skipRows option', () => { describe('with headers', () => { - it('should skip up to the specified number of rows not including the header row in the count', () => { + it('should skip up to the specified number of rows not including the header row in the count', async () => { const skipRows = 3; - return parseContentAndCollect(assets.withHeaders, { - headers: true, - skipRows, - }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeaders.parsed.slice(skipRows)); - assert.strictEqual(count, rows.length); - }); + await expectParsed( + parseContentAndCollect(assets.withHeaders, { headers: true, skipRows }), + assets.withHeaders.parsed.slice(skipRows), + ); }); - it('should skip up to the specified number of rows and allow renaming the headers', () => { + it('should skip up to the specified number of rows and allow renaming the headers', async () => { const skipRows = 3; - return parseContentAndCollect(assets.withHeaders, { - headers: ['h1', 'h2', 'h3'], - renameHeaders: true, - skipRows, - }).then(({ count, rows }) => { - assert.deepStrictEqual( - rows, - assets.withHeaders.parsed.slice(skipRows).map(r => { - return { - h1: r.first_name, - h2: r.last_name, - h3: r.email_address, - }; - }), - ); - assert.strictEqual(count, rows.length); + const expected = assets.withHeaders.parsed.slice(skipRows).map(r => { + return { + h1: r.first_name, + h2: r.last_name, + h3: r.email_address, + }; }); + await expectParsed( + parseContentAndCollect(assets.withHeaders, { + headers: ['h1', 'h2', 'h3'], + renameHeaders: true, + skipRows, + }), + expected, + ); }); }); describe('without headers', () => { - it('should skip up to the specified number of rows without headers', () => { + it('should skip up to the specified number of rows without headers', async () => { const skipRows = 3; - return parseContentAndCollect(assets.noHeadersAndQuotes, { skipRows }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.noHeadersAndQuotes.parsed.slice(skipRows)); - assert.strictEqual(count, rows.length); - }); + const expected = assets.noHeadersAndQuotes.parsed.slice(skipRows); + await expectParsed(parseContentAndCollect(assets.noHeadersAndQuotes, { skipRows }), expected); }); - it('should skip up to the specified number of rows without headers and allow specifying headers', () => { + it('should skip up to the specified number of rows without headers and allow specifying headers', async () => { const skipRows = 3; - return parseContentAndCollect(assets.noHeadersAndQuotes, { - headers: ['h1', 'h2', 'h3', 'h4'], - skipRows, - }).then(({ count, rows }) => { - assert.deepStrictEqual( - rows, - assets.noHeadersAndQuotes.parsed.slice(skipRows).map(r => { - return { - h1: r[0], - h2: r[1], - h3: r[2], - h4: r[3], - }; - }), - ); - assert.strictEqual(count, rows.length); + const expected = assets.noHeadersAndQuotes.parsed.slice(skipRows).map(r => { + return { + h1: r[0], + h2: r[1], + h3: r[2], + h4: r[3], + }; }); + await expectParsed( + parseContentAndCollect(assets.noHeadersAndQuotes, { headers: ['h1', 'h2', 'h3', 'h4'], skipRows }), + expected, + ); }); }); describe('with transform', () => { - it('should not transform skipped rows', () => { + it('should not transform skipped rows', async () => { let transformedRows: csv.ParserRow[] = []; const transformer = (row: csv.ParserRow): csv.ParserRow => { const transformed = { @@ -494,16 +440,13 @@ describe('CsvParserStream', () => { const expected = assets.withHeaders.parsed.slice(skipRows).map(transformer); transformedRows = []; const parser = csv.parse({ headers: true, skipRows }).transform(transformer); - return parseContentAndCollectFromStream(assets.withHeaders, parser).then(({ count, rows }) => { - assert.deepStrictEqual(rows, expected); - assert.deepStrictEqual(transformedRows, expected); - assert.strictEqual(count, expected.length); - }); + await expectParsed(parseContentAndCollectFromStream(assets.withHeaders, parser), expected); + expect(transformedRows).toEqual(expected); }); }); describe('with validate', () => { - it('should not validate skipped rows', () => { + it('should not validate skipped rows', async () => { let validatedRows: csv.ParserRow[] = []; const validator = (row: csv.ParserRow): boolean => { validatedRows.push(row); @@ -511,23 +454,20 @@ describe('CsvParserStream', () => { }; const skipRows = 3; const nonSkippedRows = assets.withHeaders.parsed.slice(skipRows); - const expected = nonSkippedRows.filter(validator); + const [expected, invalid] = partition(nonSkippedRows, validator); validatedRows = []; const parser = csv.parse({ headers: true, skipRows }).validate(validator); - return parseContentAndCollectFromStream(assets.withHeaders, parser).then(({ count, rows }) => { - assert.deepStrictEqual(rows, expected); - assert.deepStrictEqual(validatedRows, nonSkippedRows); - assert.strictEqual(count, nonSkippedRows.length); - }); + await expectParsed(parseContentAndCollectFromStream(assets.withHeaders, parser), expected, invalid); + expect(validatedRows).toEqual(nonSkippedRows); }); }); - it('should parse all rows if maxRows === 0', () => { + it('should parse all rows if maxRows === 0', async () => { const skipRows = 0; - return parseContentAndCollect(assets.withHeaders, { headers: true, skipRows }).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeaders.parsed); - assert.strictEqual(count, rows.length); - }); + await expectParsed( + parseContentAndCollect(assets.withHeaders, { headers: true, skipRows }), + assets.withHeaders.parsed, + ); }); }); @@ -544,28 +484,18 @@ describe('CsvParserStream', () => { cb(null, syncValidator(row)); }; - it('should allow validation of rows', () => { - const invalidValid = partition(assets.withHeaders.parsed, syncValidator); + it('should allow validation of rows', async () => { + const [valid, invalid] = partition(assets.withHeaders.parsed, syncValidator); const parser = csv.parse({ headers: true }).validate(syncValidator); - - return parseContentAndCollectFromStream(assets.withHeaders, parser).then(({ count, rows, invalidRows }) => { - assert.deepStrictEqual(invalidRows, invalidValid[1]); - assert.deepStrictEqual(rows, invalidValid[0]); - assert.strictEqual(count, invalidValid[0].length + invalidValid[1].length); - }); + await expectParsed(parseContentAndCollectFromStream(assets.withHeaders, parser), valid, invalid); }); - it('should allow async validation of rows', () => { + it('should allow async validation of rows', async () => { const validator = (row: csv.ParserRow): boolean => parseInt((row as csv.ParserRowMap).first_name.replace(/^First/, ''), 10) % 2 !== 0; - const invalidValid = partition(assets.withHeaders.parsed, validator); + const [valid, invalid] = partition(assets.withHeaders.parsed, validator); const parser = csv.parse({ headers: true }).validate(asyncValidator); - - return parseContentAndCollectFromStream(assets.withHeaders, parser).then(({ count, rows, invalidRows }) => { - assert.deepStrictEqual(invalidRows, invalidValid[1]); - assert.deepStrictEqual(rows, invalidValid[0]); - assert.strictEqual(count, invalidValid[0].length + invalidValid[1].length); - }); + await expectParsed(parseContentAndCollectFromStream(assets.withHeaders, parser), valid, invalid); }); it('should propagate errors from async validation', next => { @@ -617,10 +547,10 @@ describe('CsvParserStream', () => { }); it('should throw an error if validate is not called with a function', () => { - assert.throws(() => { - // @ts-ignore - csv.parse({ headers: true }).validate('hello'); - }, /TypeError: The validate should be a function/); + // @ts-ignore + expect(() => csv.parse({ headers: true }).validate('hello')).toThrowError( + 'The validate should be a function', + ); }); }); @@ -632,24 +562,18 @@ describe('CsvParserStream', () => { address: (row as csv.ParserRowMap).address, }); - it('should allow transforming of data', () => { + it('should allow transforming of data', async () => { const expected = assets.withHeaders.parsed.map(transformer); const parser = csv.parse({ headers: true }).transform(transformer); - return parseContentAndCollectFromStream(assets.withHeaders, parser).then(({ count, rows }) => { - assert.deepStrictEqual(rows, expected); - assert.strictEqual(count, expected.length); - }); + await expectParsed(parseContentAndCollectFromStream(assets.withHeaders, parser), expected); }); - it('should async transformation of data', () => { + it('should async transformation of data', async () => { const expected = assets.withHeaders.parsed.map(transformer); const parser = csv .parse({ headers: true }) .transform((row, next) => setImmediate(() => next(null, transformer(row)))); - return parseContentAndCollectFromStream(assets.withHeaders, parser).then(({ count, rows }) => { - assert.deepStrictEqual(rows, expected); - assert.strictEqual(count, expected.length); - }); + await expectParsed(parseContentAndCollectFromStream(assets.withHeaders, parser), expected); }); it('should propogate errors when transformation of data', next => { @@ -699,10 +623,10 @@ describe('CsvParserStream', () => { }); it('should throw an error if a transform is not called with a function', () => { - assert.throws(() => { - // @ts-ignore - csv.parse({ headers: true }).transform('hello'); - }, /TypeError: The transform should be a function/); + // @ts-ignore + expect(() => csv.parse({ headers: true }).transform('hello')).toThrowError( + 'The transform should be a function', + ); }); }); @@ -717,20 +641,20 @@ describe('CsvParserStream', () => { .on('error', rej) .pipe(stream) .on('data', row => { - assert.ok(!paused); + expect(paused).toBe(false); rows.push(row); paused = true; stream.pause(); setTimeout(() => { - assert.ok(paused); + expect(paused).toBe(true); paused = false; stream.resume(); }, 100); }) .on('error', rej) .on('end', (count: number) => { - assert.deepStrictEqual(rows, assets.withHeaders.parsed); - assert.strictEqual(count, rows.length); + expect(rows).toEqual(assets.withHeaders.parsed); + expect(count).toBe(rows.length); res(); }); }); @@ -747,7 +671,7 @@ describe('CsvParserStream', () => { throw err; } called = true; - assert.strictEqual(err.message, 'End error'); + expect(err.message).toBe('End error'); next(); }); d.run(() => @@ -765,37 +689,26 @@ describe('CsvParserStream', () => { }); describe('.parseStream', () => { - it('should accept a stream', () => { + it('should accept a stream', async () => { assets.write(assets.withHeaders); const stream = csv.parseStream(fs.createReadStream(assets.withHeaders.path), { headers: true }); - return collectData(stream).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeaders.parsed); - assert.strictEqual(count, rows.length); - }); + await expectParsed(collectData(stream), assets.withHeaders.parsed); }); }); describe('.parseFile', () => { - it('parse a csv from the given path', () => { + it('parse a csv from the given path', async () => { assets.write(assets.withHeaders); const stream = csv.parseFile(assets.withHeaders.path, { headers: true }); - return collectData(stream).then(({ count, rows }) => { - assert.deepStrictEqual(rows, assets.withHeaders.parsed); - assert.strictEqual(count, rows.length); - }); + await expectParsed(collectData(stream), assets.withHeaders.parsed); }); }); describe('.parseString', () => { - it('should accept a csv string', next => { - const actual: csv.ParserRow[] = []; - csv.parseString(assets.withHeaders.content, { headers: true }) - .on('data', data => actual.push(data)) - .on('end', (count: number) => { - assert.deepStrictEqual(actual, assets.withHeaders.parsed); - assert.strictEqual(count, actual.length); - next(); - }); - }); + it('should accept a csv string', () => + expectParsed( + collectData(csv.parseString(assets.withHeaders.content, { headers: true })), + assets.withHeaders.parsed, + )); }); }); diff --git a/test/parser/ParserOptions.test.ts b/__tests__/parser/ParserOptions.spec.ts similarity index 53% rename from test/parser/ParserOptions.test.ts rename to __tests__/parser/ParserOptions.spec.ts index 59867354..e35a4432 100644 --- a/test/parser/ParserOptions.test.ts +++ b/__tests__/parser/ParserOptions.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { ParserOptionsArgs } from '../../src'; import { ParserOptions } from '../../src/parser'; @@ -7,211 +6,211 @@ describe('ParserOptions', () => { describe('#objectMode', () => { it('should have default objectMode', () => { - assert.strictEqual(createOptions().objectMode, true); + expect(createOptions().objectMode).toBe(true); }); it('should accept a boolean objectMode', () => { - assert.strictEqual(createOptions({ objectMode: true }).objectMode, true); - assert.strictEqual(createOptions({ objectMode: false }).objectMode, false); + expect(createOptions({ objectMode: true }).objectMode).toBe(true); + expect(createOptions({ objectMode: false }).objectMode).toBe(false); }); }); describe('#delimiter', () => { it('should have default delimiter', () => { - assert.strictEqual(createOptions().delimiter, ','); + expect(createOptions().delimiter).toBe(','); }); it('should accept a custom delimiter', () => { - assert.strictEqual(createOptions({ delimiter: '\t' }).delimiter, '\t'); + expect(createOptions({ delimiter: '\t' }).delimiter).toBe('\t'); }); it('should escape a custom delimiter', () => { - assert.strictEqual(createOptions({ delimiter: '\\' }).delimiter, '\\'); - assert.strictEqual(createOptions({ delimiter: '\\' }).escapedDelimiter, '\\\\'); + expect(createOptions({ delimiter: '\\' }).delimiter).toBe('\\'); + expect(createOptions({ delimiter: '\\' }).escapedDelimiter).toBe('\\\\'); }); }); describe('#strictColumnHandling', () => { it('should set default strictColumnHandling to false', () => { - assert.strictEqual(createOptions().strictColumnHandling, false); + expect(createOptions().strictColumnHandling).toBe(false); }); it('should accept a strictColumnHandling parameter', () => { - assert.strictEqual(createOptions({ strictColumnHandling: true }).strictColumnHandling, true); + expect(createOptions({ strictColumnHandling: true }).strictColumnHandling).toBe(true); }); }); describe('#quote', () => { it('should set a default quote value', () => { - assert.strictEqual(createOptions().quote, '"'); + expect(createOptions().quote).toBe('"'); }); it('should accept an alternate quote', () => { - assert.strictEqual(createOptions({ quote: '$' }).quote, '$'); + expect(createOptions({ quote: '$' }).quote).toBe('$'); }); }); describe('#escapeChar', () => { it('should set the escape character to the quote value if not specified', () => { - assert.strictEqual(createOptions().escapeChar, '"'); + expect(createOptions().escapeChar).toBe('"'); }); it('should set the escape character to the quote value if not specified', () => { - assert.strictEqual(createOptions({ quote: '$' }).escapeChar, '$'); + expect(createOptions({ quote: '$' }).escapeChar).toBe('$'); }); it('should accept an alternate escape', () => { - assert.strictEqual(createOptions({ escape: '%' }).escapeChar, '%'); + expect(createOptions({ escape: '%' }).escapeChar).toBe('%'); }); }); describe('#comment', () => { it('should set the comment null if not specified', () => { - assert.strictEqual(createOptions().comment, null); + expect(createOptions().comment).toBe(null); }); it('should accept a comment character', () => { - assert.strictEqual(createOptions({ comment: '#' }).comment, '#'); + expect(createOptions({ comment: '#' }).comment).toBe('#'); }); }); describe('#supportsComments', () => { it('should set supports comments to false by default', () => { - assert.strictEqual(createOptions().supportsComments, false); + expect(createOptions().supportsComments).toBe(false); }); it('should set to true if the comment character is specified', () => { - assert.strictEqual(createOptions({ comment: '#' }).supportsComments, true); + expect(createOptions({ comment: '#' }).supportsComments).toBe(true); }); }); describe('#trim', () => { it('should have default trim', () => { - assert.strictEqual(createOptions().trim, false); + expect(createOptions().trim).toBe(false); }); it('should accept a boolean objectMode', () => { - assert.strictEqual(createOptions({ trim: true }).trim, true); - assert.strictEqual(createOptions({ trim: false }).trim, false); + expect(createOptions({ trim: true }).trim).toBe(true); + expect(createOptions({ trim: false }).trim).toBe(false); }); }); describe('#ltrim', () => { it('should have default ltrim', () => { - assert.strictEqual(createOptions().ltrim, false); + expect(createOptions().ltrim).toBe(false); }); it('should accept a boolean objectMode', () => { - assert.strictEqual(createOptions({ ltrim: true }).ltrim, true); - assert.strictEqual(createOptions({ ltrim: false }).ltrim, false); + expect(createOptions({ ltrim: true }).ltrim).toBe(true); + expect(createOptions({ ltrim: false }).ltrim).toBe(false); }); }); describe('#rtrim', () => { it('should have default rtrim', () => { - assert.strictEqual(createOptions().rtrim, false); + expect(createOptions().rtrim).toBe(false); }); it('should accept a boolean objectMode', () => { - assert.strictEqual(createOptions({ rtrim: true }).rtrim, true); - assert.strictEqual(createOptions({ rtrim: false }).rtrim, false); + expect(createOptions({ rtrim: true }).rtrim).toBe(true); + expect(createOptions({ rtrim: false }).rtrim).toBe(false); }); }); describe('#discardUnmappedColumns', () => { it('should have default discardUnmappedColumns', () => { - assert.strictEqual(createOptions().discardUnmappedColumns, false); + expect(createOptions().discardUnmappedColumns).toBe(false); }); it('should accept a boolean objectMode', () => { - assert.strictEqual(createOptions({ discardUnmappedColumns: true }).discardUnmappedColumns, true); - assert.strictEqual(createOptions({ discardUnmappedColumns: false }).discardUnmappedColumns, false); + expect(createOptions({ discardUnmappedColumns: true }).discardUnmappedColumns).toBe(true); + expect(createOptions({ discardUnmappedColumns: false }).discardUnmappedColumns).toBe(false); }); }); describe('#strictColumnHandling', () => { it('should have default strictColumnHandling', () => { - assert.strictEqual(createOptions().strictColumnHandling, false); + expect(createOptions().strictColumnHandling).toBe(false); }); it('should accept a boolean objectMode', () => { - assert.strictEqual(createOptions({ strictColumnHandling: true }).strictColumnHandling, true); - assert.strictEqual(createOptions({ strictColumnHandling: false }).strictColumnHandling, false); + expect(createOptions({ strictColumnHandling: true }).strictColumnHandling).toBe(true); + expect(createOptions({ strictColumnHandling: false }).strictColumnHandling).toBe(false); }); }); describe('#headers', () => { it('should have default headers', () => { - assert.strictEqual(createOptions().headers, null); + expect(createOptions().headers).toBeNull(); }); it('should accept an array of headers', () => { - assert.deepStrictEqual(createOptions({ headers: ['1', '2', '3'] }).headers, ['1', '2', '3']); + expect(createOptions({ headers: ['1', '2', '3'] }).headers).toEqual(['1', '2', '3']); }); it('should accept a function', () => { const opts = createOptions({ headers: headers => headers.map(h => h?.toLowerCase()) }); // @ts-ignore - assert.deepStrictEqual(opts.headers(['A', 'B', 'C']), ['a', 'b', 'c']); + expect(opts.headers(['A', 'B', 'C'])).toEqual(['a', 'b', 'c']); }); it('should accept headers as a boolean', () => { - assert.deepStrictEqual(createOptions({ headers: true }).headers, true); + expect(createOptions({ headers: true }).headers).toBe(true); }); }); describe('#renameHeaders', () => { it('should have default renameHeaders', () => { - assert.strictEqual(createOptions().renameHeaders, false); + expect(createOptions().renameHeaders).toBe(false); }); it('should accept a boolean renameHeaders', () => { - assert.strictEqual(createOptions({ renameHeaders: true }).renameHeaders, true); - assert.strictEqual(createOptions({ renameHeaders: false }).renameHeaders, false); + expect(createOptions({ renameHeaders: true }).renameHeaders).toBe(true); + expect(createOptions({ renameHeaders: false }).renameHeaders).toBe(false); }); }); describe('#maxRows', () => { it('should default maxRows 0 and limitRows to false', () => { const opts = createOptions(); - assert.strictEqual(opts.maxRows, 0); - assert.strictEqual(opts.limitRows, false); + expect(opts.maxRows).toBe(0); + expect(opts.limitRows).toBe(false); }); it('should set maxRows to the provided option and limitRows to true if maxRows > 0', () => { const opts = createOptions({ maxRows: 1 }); - assert.strictEqual(opts.maxRows, 1); - assert.strictEqual(opts.limitRows, true); + expect(opts.maxRows).toBe(1); + expect(opts.limitRows).toBe(true); }); it('should set maxRows to the provided option and limitRows to true if maxRows === 0', () => { const opts = createOptions({ maxRows: 0 }); - assert.strictEqual(opts.maxRows, 0); - assert.strictEqual(opts.limitRows, false); + expect(opts.maxRows).toBe(0); + expect(opts.limitRows).toBe(false); }); }); describe('#skipLines', () => { it('should default skipLines to 0', () => { const opts = createOptions(); - assert.strictEqual(opts.skipLines, 0); + expect(opts.skipLines).toBe(0); }); it('should set skipLines to the user provided option', () => { const opts = createOptions({ skipLines: 10 }); - assert.strictEqual(opts.skipLines, 10); + expect(opts.skipLines).toBe(10); }); }); describe('#skipRows', () => { it('should default skipLines to 0', () => { const opts = createOptions(); - assert.strictEqual(opts.skipRows, 0); + expect(opts.skipRows).toBe(0); }); it('should set skipLines to the user provided option', () => { const opts = createOptions({ skipRows: 10 }); - assert.strictEqual(opts.skipRows, 10); + expect(opts.skipRows).toBe(10); }); }); }); diff --git a/test/parser/assets/alternateEncoding.ts b/__tests__/parser/__fixtures__/alternateEncoding.ts similarity index 100% rename from test/parser/assets/alternateEncoding.ts rename to __tests__/parser/__fixtures__/alternateEncoding.ts diff --git a/test/parser/assets/duplicateHeaders.ts b/__tests__/parser/__fixtures__/duplicateHeaders.ts similarity index 100% rename from test/parser/assets/duplicateHeaders.ts rename to __tests__/parser/__fixtures__/duplicateHeaders.ts diff --git a/test/parser/assets/emptyRows.ts b/__tests__/parser/__fixtures__/emptyRows.ts similarity index 100% rename from test/parser/assets/emptyRows.ts rename to __tests__/parser/__fixtures__/emptyRows.ts diff --git a/test/parser/assets/headerColumnMismatch.ts b/__tests__/parser/__fixtures__/headerColumnMismatch.ts similarity index 100% rename from test/parser/assets/headerColumnMismatch.ts rename to __tests__/parser/__fixtures__/headerColumnMismatch.ts diff --git a/test/parser/assets/index.ts b/__tests__/parser/__fixtures__/index.ts similarity index 95% rename from test/parser/assets/index.ts rename to __tests__/parser/__fixtures__/index.ts index 5333b1c1..9eec0c72 100644 --- a/test/parser/assets/index.ts +++ b/__tests__/parser/__fixtures__/index.ts @@ -14,6 +14,7 @@ import malformed from './malformed'; import trailingComma from './trailingComma'; import emptyRows from './emptyRows'; import duplicateHeaders from './duplicateHeaders'; +import RecordingStream from '../../RecordingStream'; export interface PathAndContent { path: string; @@ -33,6 +34,7 @@ const write = (opts: PathAndContent): void => { }; export default { + RecordingStream, write, alternateEncoding, duplicateHeaders, diff --git a/test/parser/assets/malformed.ts b/__tests__/parser/__fixtures__/malformed.ts similarity index 100% rename from test/parser/assets/malformed.ts rename to __tests__/parser/__fixtures__/malformed.ts diff --git a/test/parser/assets/noHeadersAndQuotes.ts b/__tests__/parser/__fixtures__/noHeadersAndQuotes.ts similarity index 100% rename from test/parser/assets/noHeadersAndQuotes.ts rename to __tests__/parser/__fixtures__/noHeadersAndQuotes.ts diff --git a/test/parser/assets/skipLines.ts b/__tests__/parser/__fixtures__/skipLines.ts similarity index 100% rename from test/parser/assets/skipLines.ts rename to __tests__/parser/__fixtures__/skipLines.ts diff --git a/test/parser/assets/trailingComma.ts b/__tests__/parser/__fixtures__/trailingComma.ts similarity index 100% rename from test/parser/assets/trailingComma.ts rename to __tests__/parser/__fixtures__/trailingComma.ts diff --git a/test/parser/assets/withHeaders.ts b/__tests__/parser/__fixtures__/withHeaders.ts similarity index 100% rename from test/parser/assets/withHeaders.ts rename to __tests__/parser/__fixtures__/withHeaders.ts diff --git a/test/parser/assets/withHeadersAlternateDelimiter.ts b/__tests__/parser/__fixtures__/withHeadersAlternateDelimiter.ts similarity index 100% rename from test/parser/assets/withHeadersAlternateDelimiter.ts rename to __tests__/parser/__fixtures__/withHeadersAlternateDelimiter.ts diff --git a/test/parser/assets/withHeadersAndAlternateQuote.ts b/__tests__/parser/__fixtures__/withHeadersAndAlternateQuote.ts similarity index 100% rename from test/parser/assets/withHeadersAndAlternateQuote.ts rename to __tests__/parser/__fixtures__/withHeadersAndAlternateQuote.ts diff --git a/test/parser/assets/withHeadersAndMissingColumns.ts b/__tests__/parser/__fixtures__/withHeadersAndMissingColumns.ts similarity index 100% rename from test/parser/assets/withHeadersAndMissingColumns.ts rename to __tests__/parser/__fixtures__/withHeadersAndMissingColumns.ts diff --git a/test/parser/assets/withHeadersAndQuotes.ts b/__tests__/parser/__fixtures__/withHeadersAndQuotes.ts similarity index 100% rename from test/parser/assets/withHeadersAndQuotes.ts rename to __tests__/parser/__fixtures__/withHeadersAndQuotes.ts diff --git a/test/parser/assets/withHeadersSkippedLines.ts b/__tests__/parser/__fixtures__/withHeadersSkippedLines.ts similarity index 100% rename from test/parser/assets/withHeadersSkippedLines.ts rename to __tests__/parser/__fixtures__/withHeadersSkippedLines.ts diff --git a/test/parser/parser/Parser.test.ts b/__tests__/parser/parser/Parser.spec.ts similarity index 85% rename from test/parser/parser/Parser.test.ts rename to __tests__/parser/parser/Parser.spec.ts index 524cec76..896e46a8 100644 --- a/test/parser/parser/Parser.test.ts +++ b/__tests__/parser/parser/Parser.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { ParserOptionsArgs } from '../../../src'; import { ParserOptions, Parser } from '../../../src/parser'; @@ -10,7 +9,7 @@ describe('Parser', () => { it('should parse a block of CSV text that starts with a BOM', () => { const data = '\ufefffirst_name,last_name,email_address'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [['first_name', 'last_name', 'email_address']], }); @@ -21,7 +20,7 @@ describe('Parser', () => { it('should parse a block of CSV text', () => { const data = 'first_name,last_name,email_address\nFirst1,Last1,email1@email.com'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -33,7 +32,7 @@ describe('Parser', () => { it('should ignore empty rows if ignoreEmpty is true', () => { const data = 'first_name,last_name,email_address\nFirst1,Last1,email1@email.com\n,,'; const myParser = createParser({ delimiter: ',', ignoreEmpty: true }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -45,7 +44,7 @@ describe('Parser', () => { it('should not ignore empty rows if ignoreEmpty is false', () => { const data = 'first_name,last_name,email_address\nFirst1,Last1,email1@email.com\n,,'; const myParser = createParser({ delimiter: ',', ignoreEmpty: false }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -58,7 +57,7 @@ describe('Parser', () => { it('should parse a block of CSV text with a trailing delimiter', () => { const data = 'first_name,last_name,email_address,empty\nFirst1,Last1,email1@email.com,\n'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -70,7 +69,7 @@ describe('Parser', () => { it('should parse a block of CSV text with a trailing delimiter and no new line', () => { const data = 'first_name,last_name,email_address,empty\nFirst1,Last1,email1@email.com,'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -82,7 +81,7 @@ describe('Parser', () => { it('should parse a block of CSV text with a trailing delimiter followed by a space', () => { const data = 'first_name,last_name,email_address,empty\nFirst1,Last1,email1@email.com, \n'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -94,7 +93,7 @@ describe('Parser', () => { it('should parse a block of Space Separated Value text with a trailing delimiter', () => { const data = 'first_name last_name email_address empty\nFirst1 Last1 email1@email.com \n'; const myParser = createParser({ delimiter: ' ' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -106,7 +105,7 @@ describe('Parser', () => { it('should return the rest of the line if there is more data', () => { const data = 'first_name,last_name,email_address\nFirst1,Last1,email1@email.com'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, true, myParser), { + expect(parse(data, true, myParser)).toEqual({ line: 'First1,Last1,email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); @@ -116,11 +115,11 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address\nFirst1,Last1,email1@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'First1,Last1,email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); - assert.deepStrictEqual(parse(`${parsedData.line}\nFirst2,Last2,email2@email.com`, false, myParser), { + expect(parse(`${parsedData.line}\nFirst2,Last2,email2@email.com`, false, myParser)).toEqual({ line: '', rows: [ ['First1', 'Last1', 'email1@email.com'], @@ -133,7 +132,7 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'first_name,last_name,email_address', rows: [], }); @@ -143,7 +142,7 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address,'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'first_name,last_name,email_address,', rows: [], }); @@ -153,7 +152,7 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address, '; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'first_name,last_name,email_address, ', rows: [], }); @@ -163,7 +162,7 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address\n'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [['first_name', 'last_name', 'email_address']], }); @@ -174,7 +173,7 @@ describe('Parser', () => { it('should parse a block of CSV text', () => { const data = 'first_name,last_name,email_address\n"First,1","Last,1","email1@email.com"'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -186,7 +185,7 @@ describe('Parser', () => { it('should parse a block of CSV text with a trailing delimiter', () => { const data = 'first_name,last_name,email_address,empty\nFirst1,Last1,email1@email.com,\n'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -198,7 +197,7 @@ describe('Parser', () => { it('should parse a block of CSV text with a trailing delimiter followed by a space', () => { const data = 'first_name,last_name,email_address,empty\nFirst1,Last1,email1@email.com, \n'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -210,7 +209,7 @@ describe('Parser', () => { it('should parse a block of Space Separated Value text with a trailing delimiter', () => { const data = 'first_name last_name email_address empty\nFirst1 Last1 email1@email.com \n'; const myParser = createParser({ delimiter: ' ' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -222,7 +221,7 @@ describe('Parser', () => { it('should parse a block of CSV text with escaped escaped char', () => { const data = 'first_name,last_name,email_address\n"First,""1""","Last,""1""","email1@email.com"'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -234,7 +233,7 @@ describe('Parser', () => { it('should parse a block of CSV text with alternate escape char', () => { const data = 'first_name,last_name,email_address\n"First,\\"1\\"","Last,\\"1\\"","email1@email.com"'; const myParser = createParser({ delimiter: ',', escape: '\\' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -246,7 +245,7 @@ describe('Parser', () => { it('should return the rest of the line if a complete value is not found', () => { const data = 'first_name,last_name,email_address\n"First,""1""","Last,""1""","email1@email.com'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, true, myParser), { + expect(parse(data, true, myParser)).toEqual({ line: '"First,""1""","Last,""1""","email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); @@ -256,40 +255,39 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address\n"First,""1""","Last,""1""","email1@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"First,""1""","Last,""1""","email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); - assert.deepStrictEqual( + expect( parse(`${parsedData.line}"\n"First,""2""","Last,""2""","email2@email.com"`, false, myParser), - { - line: '', - rows: [ - ['First,"1"', 'Last,"1"', 'email1@email.com'], - ['First,"2"', 'Last,"2"', 'email2@email.com'], - ], - }, - ); + ).toEqual({ + line: '', + rows: [ + ['First,"1"', 'Last,"1"', 'email1@email.com'], + ['First,"2"', 'Last,"2"', 'email2@email.com'], + ], + }); }); it('should throw an error if there is not more data and there is an invalid escape sequence', () => { const data = 'first_name,last_name,email_address\n"First,""1""","Last,""1""","email1@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"First,""1""","Last,""1""","email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); - assert.throws(() => { + expect(() => { myParser.parse(`${parsedData.line}\n"First,"",2""","Last""2""","email2@email.com"`, false); - }, /Parse Error: expected: ',' OR new line got: 'F'. at 'First,"",2/); + }).toThrowError(/Parse Error: expected: ',' OR new line got: 'F'. at 'First,"",2/); }); it('should handle empty values properly', () => { const data = '"","",""\n,Last4,email4@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, false, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [ ['', '', ''], @@ -302,7 +300,7 @@ describe('Parser', () => { const data = '"first_name","last_name","email_address"'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"first_name","last_name","email_address"', rows: [], }); @@ -312,7 +310,7 @@ describe('Parser', () => { const data = '"first_name","last_name","email_address",'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"first_name","last_name","email_address",', rows: [], }); @@ -322,7 +320,7 @@ describe('Parser', () => { const data = '"first_name","last_name","email_address"\n'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [['first_name', 'last_name', 'email_address']], }); @@ -333,7 +331,7 @@ describe('Parser', () => { it('should ignore escaping if quote is null', () => { const data = 'first_name,last_name,email_address\n"First1","Last1","email1@email.com"'; const myParser = createParser({ delimiter: ',', quote: null }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -349,7 +347,7 @@ describe('Parser', () => { it('should parse a block of CSV text', () => { const data = 'first_name,last_name,email_address\rFirst1,Last1,email1@email.com'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -361,7 +359,7 @@ describe('Parser', () => { it('should parse a block of CSV text with a trailing delimiter', () => { const data = 'first_name,last_name,email_address,empty\rFirst1,Last1,email1@email.com,\r'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -373,7 +371,7 @@ describe('Parser', () => { it('should parse a block of CSV text with a trailing delimiter followed by a space', () => { const data = 'first_name,last_name,email_address,empty\nFirst1,Last1,email1@email.com, \r'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -385,7 +383,7 @@ describe('Parser', () => { it('should parse a block of Space Separated Value text with a trailing delimiter', () => { const data = 'first_name last_name email_address empty\rFirst1 Last1 email1@email.com \r'; const myParser = createParser({ delimiter: ' ' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address', 'empty'], @@ -397,7 +395,7 @@ describe('Parser', () => { it('should return the rest of the line if there is more data', () => { const data = 'first_name,last_name,email_address\rFirst1,Last1,email1@email.com'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, true, myParser), { + expect(parse(data, true, myParser)).toEqual({ line: 'First1,Last1,email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); @@ -407,11 +405,11 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address\rFirst1,Last1,email1@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'First1,Last1,email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); - assert.deepStrictEqual(parse(`${parsedData.line}\rFirst2,Last2,email2@email.com`, false, myParser), { + expect(parse(`${parsedData.line}\rFirst2,Last2,email2@email.com`, false, myParser)).toEqual({ line: '', rows: [ ['First1', 'Last1', 'email1@email.com'], @@ -424,7 +422,7 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'first_name,last_name,email_address', rows: [], }); @@ -434,7 +432,7 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address,'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'first_name,last_name,email_address,', rows: [], }); @@ -444,7 +442,7 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address\r'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'first_name,last_name,email_address\r', rows: [], }); @@ -455,7 +453,7 @@ describe('Parser', () => { it('should parse a block of CSV text', () => { const data = 'first_name,last_name,email_address\r"First,1","Last,1","email1@email.com"'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -467,7 +465,7 @@ describe('Parser', () => { it('should parse a block of CSV text with escaped escaped char', () => { const data = 'first_name,last_name,email_address\r"First,""1""","Last,""1""","email1@email.com"'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -479,7 +477,7 @@ describe('Parser', () => { it('should parse a block of CSV text with alternate escape char', () => { const data = 'first_name,last_name,email_address\r"First,\\"1\\"","Last,\\"1\\"","email1@email.com"'; const myParser = createParser({ delimiter: ',', escape: '\\' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -491,7 +489,7 @@ describe('Parser', () => { it('should return the rest of the line if a complete value is not found', () => { const data = 'first_name,last_name,email_address\r"First,""1""","Last,""1""","email1@email.com'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, true, myParser), { + expect(parse(data, true, myParser)).toEqual({ line: '"First,""1""","Last,""1""","email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); @@ -501,40 +499,39 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address\r"First,""1""","Last,""1""","email1@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"First,""1""","Last,""1""","email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); - assert.deepStrictEqual( + expect( parse(`${parsedData.line}"\r"First,""2""","Last,""2""","email2@email.com"`, false, myParser), - { - line: '', - rows: [ - ['First,"1"', 'Last,"1"', 'email1@email.com'], - ['First,"2"', 'Last,"2"', 'email2@email.com'], - ], - }, - ); + ).toEqual({ + line: '', + rows: [ + ['First,"1"', 'Last,"1"', 'email1@email.com'], + ['First,"2"', 'Last,"2"', 'email2@email.com'], + ], + }); }); it('should throw an error if there is not more data and there is an invalid escape sequence', () => { const data = 'first_name,last_name,email_address\r"First,""1""","Last,""1""","email1@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"First,""1""","Last,""1""","email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); - assert.throws(() => { + expect(() => { myParser.parse(`${parsedData.line}\r"First,"",2""","Last""2""","email2@email.com"`, false); - }, /Parse Error: expected: ',' OR new line got: 'F'. at 'First,"",2/); + }).toThrowError(/Parse Error: expected: ',' OR new line got: 'F'. at 'First,"",2/); }); it('should handle empty values properly', () => { const data = '"","",""\r,Last4,email4@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, false, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [ ['', '', ''], @@ -547,7 +544,7 @@ describe('Parser', () => { const data = '"first_name","last_name","email_address"'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"first_name","last_name","email_address"', rows: [], }); @@ -557,7 +554,7 @@ describe('Parser', () => { const data = '"first_name","last_name","email_address",'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"first_name","last_name","email_address",', rows: [], }); @@ -567,7 +564,7 @@ describe('Parser', () => { const data = '"first_name","last_name","email_address"\r'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"first_name","last_name","email_address"\r', rows: [], }); @@ -578,7 +575,7 @@ describe('Parser', () => { it('should ignore escaping if quote is null', () => { const data = 'first_name,last_name,email_address\r"First1","Last1","email1@email.com"'; const myParser = createParser({ delimiter: ',', quote: null }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -594,7 +591,7 @@ describe('Parser', () => { it('should parse a block of CSV text', () => { const data = 'first_name,last_name,email_address\r\nFirst1,Last1,email1@email.com'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -606,7 +603,7 @@ describe('Parser', () => { it('should return the rest of the line if there is more data', () => { const data = 'first_name,last_name,email_address\r\nFirst1,Last1,email1@email.com'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, true, myParser), { + expect(parse(data, true, myParser)).toEqual({ line: 'First1,Last1,email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); @@ -616,11 +613,11 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address\r\nFirst1,Last1,email1@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'First1,Last1,email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); - assert.deepStrictEqual(parse(`${parsedData.line}\r\nFirst2,Last2,email2@email.com`, false, myParser), { + expect(parse(`${parsedData.line}\r\nFirst2,Last2,email2@email.com`, false, myParser)).toEqual({ line: '', rows: [ ['First1', 'Last1', 'email1@email.com'], @@ -633,7 +630,7 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'first_name,last_name,email_address', rows: [], }); @@ -643,7 +640,7 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address\r'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'first_name,last_name,email_address\r', rows: [], }); @@ -653,7 +650,7 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address,'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: 'first_name,last_name,email_address,', rows: [], }); @@ -663,7 +660,7 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address\r\n'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [['first_name', 'last_name', 'email_address']], }); @@ -674,7 +671,7 @@ describe('Parser', () => { it('should parse a block of CSV text', () => { const data = 'first_name,last_name,email_address\r\n"First,1","Last,1","email1@email.com"'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -686,7 +683,7 @@ describe('Parser', () => { it('should parse a block of CSV text with escaped escaped char', () => { const data = 'first_name,last_name,email_address\r\n"First,""1""","Last,""1""","email1@email.com"'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -698,7 +695,7 @@ describe('Parser', () => { it('should parse a block of CSV text with alternate escape char', () => { const data = 'first_name,last_name,email_address\r\n"First,\\"1\\"","Last,\\"1\\"","email1@email.com"'; const myParser = createParser({ delimiter: ',', escape: '\\' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -710,7 +707,7 @@ describe('Parser', () => { it('should return the rest of the line if a complete value is not found', () => { const data = 'first_name,last_name,email_address\r\n"First,""1""","Last,""1""","email1@email.com'; const myParser = createParser({ delimiter: ',' }); - assert.deepStrictEqual(parse(data, true, myParser), { + expect(parse(data, true, myParser)).toEqual({ line: '"First,""1""","Last,""1""","email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); @@ -720,40 +717,39 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address\r\n"First,""1""","Last,""1""","email1@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"First,""1""","Last,""1""","email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); - assert.deepStrictEqual( + expect( parse(`${parsedData.line}"\r\n"First,""2""","Last,""2""","email2@email.com"`, false, myParser), - { - line: '', - rows: [ - ['First,"1"', 'Last,"1"', 'email1@email.com'], - ['First,"2"', 'Last,"2"', 'email2@email.com'], - ], - }, - ); + ).toEqual({ + line: '', + rows: [ + ['First,"1"', 'Last,"1"', 'email1@email.com'], + ['First,"2"', 'Last,"2"', 'email2@email.com'], + ], + }); }); it('should throw an error if there is not more data and there is an invalid escape sequence', () => { const data = 'first_name,last_name,email_address\r\n"First,""1""","Last,""1""","email1@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"First,""1""","Last,""1""","email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); - assert.throws(() => { + expect(() => { myParser.parse(`${parsedData.line}\r\n"First,"",2""","Last""2""","email2@email.com"`, false); - }, /Parse Error: expected: ',' OR new line got: 'F'. at 'First,"",2/); + }).toThrowError(/Parse Error: expected: ',' OR new line got: 'F'. at 'First,"",2/); }); it('should handle empty values properly', () => { const data = '"","",""\r\n,Last4,email4@email.com'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, false, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [ ['', '', ''], @@ -766,7 +762,7 @@ describe('Parser', () => { const data = '"first_name","last_name","email_address"'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"first_name","last_name","email_address"', rows: [], }); @@ -776,7 +772,7 @@ describe('Parser', () => { const data = '"first_name","last_name","email_address",'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '"first_name","last_name","email_address",', rows: [], }); @@ -786,7 +782,7 @@ describe('Parser', () => { const data = '"first_name","last_name","email_address"\r\n'; const myParser = createParser({ delimiter: ',' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [['first_name', 'last_name', 'email_address']], }); @@ -797,7 +793,7 @@ describe('Parser', () => { it('should ignore escaping if quote is null', () => { const data = 'first_name,last_name,email_address\r\n"First1","Last1","email1@email.com"'; const myParser = createParser({ delimiter: ',', quote: null }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -812,7 +808,7 @@ describe('Parser', () => { it('should parse a block of CSV text', () => { const data = 'first_name,last_name,email_address\n#The first row of data\nFirst1,Last1,email1@email.com'; const myParser = createParser({ delimiter: ',', comment: '#' }); - assert.deepStrictEqual(parse(data, false, myParser), { + expect(parse(data, false, myParser)).toEqual({ line: '', rows: [ ['first_name', 'last_name', 'email_address'], @@ -824,7 +820,7 @@ describe('Parser', () => { it('should return the rest of the line if there is more data', () => { const data = 'first_name,last_name,email_address\n#First1,Last1,email1@email.com'; const myParser = createParser({ delimiter: ',', comment: '#' }); - assert.deepStrictEqual(parse(data, true, myParser), { + expect(parse(data, true, myParser)).toEqual({ line: '#First1,Last1,email1@email.com', rows: [['first_name', 'last_name', 'email_address']], }); @@ -834,31 +830,30 @@ describe('Parser', () => { const data = 'first_name,last_name,email_address\n#This is a comment'; const myParser = createParser({ delimiter: ',', comment: '#' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '#This is a comment', rows: [['first_name', 'last_name', 'email_address']], }); - assert.deepStrictEqual( + expect( parse( `${parsedData.line}\nFirst1,Last1,email1@email.com\nFirst2,Last2,email2@email.com`, false, myParser, ), - { - line: '', - rows: [ - ['First1', 'Last1', 'email1@email.com'], - ['First2', 'Last2', 'email2@email.com'], - ], - }, - ); + ).toEqual({ + line: '', + rows: [ + ['First1', 'Last1', 'email1@email.com'], + ['First2', 'Last2', 'email2@email.com'], + ], + }); }); it('should not parse a row if a new line is not found and there is more data', () => { const data = '#first_name,last_name,email_address'; const myParser = createParser({ delimiter: ',', comment: '#' }); const parsedData = parse(data, true, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '#first_name,last_name,email_address', rows: [], }); @@ -868,7 +863,7 @@ describe('Parser', () => { const data = 'f#irst_name,last_name,email_address'; const myParser = createParser({ delimiter: ',', comment: '#' }); const parsedData = parse(data, false, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [['f#irst_name', 'last_name', 'email_address']], }); @@ -878,7 +873,7 @@ describe('Parser', () => { const data = '"#first_name",last_name,email_address'; const myParser = createParser({ delimiter: ',', comment: '#' }); const parsedData = parse(data, false, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [['#first_name', 'last_name', 'email_address']], }); @@ -888,7 +883,7 @@ describe('Parser', () => { const data = '#Comment1\n#Comment2'; const myParser = createParser({ delimiter: ',', comment: '#' }); const parsedData = parse(data, false, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [], }); @@ -898,7 +893,7 @@ describe('Parser', () => { const data = '#Comment1\n#Comment2\n'; const myParser = createParser({ delimiter: ',', comment: '#' }); const parsedData = parse(data, false, myParser); - assert.deepStrictEqual(parsedData, { + expect(parsedData).toEqual({ line: '', rows: [], }); diff --git a/test/parser/parser/RowParser.test.ts b/__tests__/parser/parser/RowParser.spec.ts similarity index 68% rename from test/parser/parser/RowParser.test.ts rename to __tests__/parser/parser/RowParser.spec.ts index 49da09e1..8d7c0df9 100644 --- a/test/parser/parser/RowParser.test.ts +++ b/__tests__/parser/parser/RowParser.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { ParserOptionsArgs } from '../../../src'; import { ParserOptions, Scanner, RowParser } from '../../../src/parser'; @@ -15,65 +14,65 @@ describe('RowParser', () => { it('should not parse a row that does not have a row delimiter', () => { const line = 'first_name,last_name,email_address'; const { scanner, row } = parse(line, true); - assert.strictEqual(scanner.line, line); - assert.strictEqual(row, null); + expect(scanner.line).toBe(line); + expect(row).toBeNull(); }); it('should parse and empty row', () => { const line = ',,\n'; const { scanner, row } = parse(line, true); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['', '', '']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['', '', '']); }); it('should parse and empty row with quotes with trailing delimiter', () => { const line = '"","","","",\n'; const { scanner, row } = parse(line, true); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['', '', '', '', '']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['', '', '', '', '']); }); it('should parse and empty row with quotes without trailing delimiter', () => { const line = '"","","",""\n'; const { scanner, row } = parse(line, true); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['', '', '', '']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['', '', '', '']); }); it('should parse a row that does have a LF', () => { const line = 'first_name,last_name,email_address\n'; const { scanner, row } = parse(line, true); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['first_name', 'last_name', 'email_address']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['first_name', 'last_name', 'email_address']); }); it('should parse a row that has a LF in a quoted column', () => { const line = '"first\nname",last_name,email_address\n'; const { scanner, row } = parse(line, true); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['first\nname', 'last_name', 'email_address']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['first\nname', 'last_name', 'email_address']); }); it('should parse a row that has a CR in a quoted column', () => { const line = '"first\rname",last_name,email_address\n'; const { scanner, row } = parse(line, true); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['first\rname', 'last_name', 'email_address']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['first\rname', 'last_name', 'email_address']); }); it('should parse a row that has a CRLF in a quoted column', () => { const line = '"first\r\nname",last_name,email_address\n'; const { scanner, row } = parse(line, true); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['first\r\nname', 'last_name', 'email_address']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['first\r\nname', 'last_name', 'email_address']); }); it('should parse a row with a "\\t" delimiter with fields that have spaces', () => { const line = '058B \t09/09/2003\tGL\tARONCA\t58 \t0191006\t1H7\t1 \t \t \tA751 \tAERONCA058B\n'; const { scanner, row } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, [ + expect(scanner.line).toBe(''); + expect(row).toEqual([ '058B ', '09/09/2003', 'GL', @@ -92,22 +91,22 @@ describe('RowParser', () => { it('should parse a row that does have a CR/LF', () => { const line = 'first_name,last_name,email_address\r\n'; const { scanner, row } = parse(line, true); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['first_name', 'last_name', 'email_address']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['first_name', 'last_name', 'email_address']); }); it('should not parse a row that does have a CR but no LF', () => { const line = 'first_name,last_name,email_address\r'; const { scanner, row } = parse(line, true); - assert.strictEqual(scanner.line, line); - assert.deepStrictEqual(row, null); + expect(scanner.line).toBe(line); + expect(row).toBeNull(); }); it('should not parse a row that does have a CR but no LF but is followed by more data', () => { const line = 'first_name,last_name,email_address\rFirst1'; const { scanner, row } = parse(line, true); - assert.strictEqual(scanner.line, 'First1'); - assert.deepStrictEqual(row, ['first_name', 'last_name', 'email_address']); + expect(scanner.line).toBe('First1'); + expect(row).toEqual(['first_name', 'last_name', 'email_address']); }); }); @@ -115,29 +114,29 @@ describe('RowParser', () => { it('should parse a row that does not have a row delimiter', () => { const line = 'first_name,last_name,email_address'; const { scanner, row } = parse(line, false); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['first_name', 'last_name', 'email_address']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['first_name', 'last_name', 'email_address']); }); it('should parse a row that does have a LF', () => { const line = 'first_name,last_name,email_address\n'; const { scanner, row } = parse(line, false); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['first_name', 'last_name', 'email_address']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['first_name', 'last_name', 'email_address']); }); it('should parse a row that does have a CR/LF', () => { const line = 'first_name,last_name,email_address\r\n'; const { scanner, row } = parse(line, false); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['first_name', 'last_name', 'email_address']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['first_name', 'last_name', 'email_address']); }); it('should parse a row that does have a CR but no LF', () => { const line = 'first_name,last_name,email_address\r'; const { scanner, row } = parse(line, false); - assert.strictEqual(scanner.line, ''); - assert.deepStrictEqual(row, ['first_name', 'last_name', 'email_address']); + expect(scanner.line).toBe(''); + expect(row).toEqual(['first_name', 'last_name', 'email_address']); }); }); }); diff --git a/test/parser/parser/Scanner.test.ts b/__tests__/parser/parser/Scanner.spec.ts similarity index 58% rename from test/parser/parser/Scanner.test.ts rename to __tests__/parser/parser/Scanner.spec.ts index b5a1db80..11ffde9c 100644 --- a/test/parser/parser/Scanner.test.ts +++ b/__tests__/parser/parser/Scanner.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { ParserOptionsArgs } from '../../../src'; import { ParserOptions, Scanner, Token, MaybeToken } from '../../../src/parser'; @@ -12,72 +11,70 @@ describe('Scanner', () => { cursor, }); - const assertToken = (token: MaybeToken): token is Token => { - if (token === null) { - assert.fail('Expected non-null token'); - } + const expectNonNullToken = (token: MaybeToken): token is Token => { + expect(token).not.toBeNull(); return true; }; - const assertTokenContent = (token: MaybeToken, content: string): void => { - if (assertToken(token)) { - assert.strictEqual(token.token, content); + const expectTokenContent = (token: MaybeToken, content: string): void => { + if (expectNonNullToken(token)) { + expect(token.token).toBe(content); } }; describe('#hasMoreCharacters', () => { it('should return true if the cursor is not past the end of the line', () => { - assert.strictEqual(getScanner('hello', true).hasMoreCharacters, true); + expect(getScanner('hello', true).hasMoreCharacters).toBe(true); }); it('should return true if the cursor is not past the end of the line', () => { - assert.strictEqual(getScanner('hello', true, 5).hasMoreCharacters, false); + expect(getScanner('hello', true, 5).hasMoreCharacters).toBe(false); }); }); describe('#nextNonSpaceToken', () => { it('should get non space token in the line', () => { - assertTokenContent(getScanner(' h', true, 0).nextNonSpaceToken, 'h'); + expectTokenContent(getScanner(' h', true, 0).nextNonSpaceToken, 'h'); }); it('should get the LF in the line', () => { - assertTokenContent(getScanner(' \n', true, 0).nextNonSpaceToken, '\n'); + expectTokenContent(getScanner(' \n', true, 0).nextNonSpaceToken, '\n'); }); it('should get the CR in the line', () => { - assertTokenContent(getScanner(' \r', true, 0).nextNonSpaceToken, '\r'); + expectTokenContent(getScanner(' \r', true, 0).nextNonSpaceToken, '\r'); }); it('should get the CRLF in the line', () => { - assertTokenContent(getScanner(' \r\n', true, 0).nextNonSpaceToken, '\r\n'); + expectTokenContent(getScanner(' \r\n', true, 0).nextNonSpaceToken, '\r\n'); }); it('should return null if there is nothing but white space', () => { - assert.strictEqual(getScanner(' \t', true, 0).nextNonSpaceToken, null); + expect(getScanner(' \t', true, 0).nextNonSpaceToken).toBeNull(); }); it('should return a token the delimiter is a space token', () => { - assertTokenContent(getScanner(' \t', true, 0, { delimiter: '\t' }).nextNonSpaceToken, '\t'); + expectTokenContent(getScanner(' \t', true, 0, { delimiter: '\t' }).nextNonSpaceToken, '\t'); }); }); describe('#nextCharacterToken', () => { it('should get the next character in the line', () => { - assertTokenContent(getScanner('h', true, 0).nextCharacterToken, 'h'); + expectTokenContent(getScanner('h', true, 0).nextCharacterToken, 'h'); }); it('should get the next character in the line if it it whitespace', () => { - assertTokenContent(getScanner(' h', true, 0).nextCharacterToken, ' '); + expectTokenContent(getScanner(' h', true, 0).nextCharacterToken, ' '); }); it('should return null if the cursor is at the end of the line', () => { - assert.strictEqual(getScanner('hello', true, 5).nextCharacterToken, null); + expect(getScanner('hello', true, 5).nextCharacterToken).toBe(null); }); }); describe('#line from cursor', () => { it('should return the line from the current cursor', () => { - assert.strictEqual(getScanner('hello', true, 2).lineFromCursor, 'llo'); + expect(getScanner('hello', true, 2).lineFromCursor).toBe('llo'); }); }); @@ -85,19 +82,19 @@ describe('Scanner', () => { it('should advance past the next LF', () => { const scanner = getScanner('hel\nlo', true, 2); scanner.advancePastLine(); - assert.strictEqual(scanner.lineFromCursor, 'lo'); + expect(scanner.lineFromCursor).toBe('lo'); }); it('should advance past the next CR', () => { const scanner = getScanner('hel\rlo', true, 2); scanner.advancePastLine(); - assert.strictEqual(scanner.lineFromCursor, 'lo'); + expect(scanner.lineFromCursor).toBe('lo'); }); it('should advance past the next CRLF', () => { const scanner = getScanner('hel\r\nlo', true, 2); scanner.advancePastLine(); - assert.strictEqual(scanner.lineFromCursor, 'lo'); + expect(scanner.lineFromCursor).toBe('lo'); }); }); @@ -105,25 +102,25 @@ describe('Scanner', () => { it('should advance past the next LF', () => { const scanner = getScanner('hel\nlo', true, 2); scanner.advancePastLine(); - assert.strictEqual(scanner.lineFromCursor, 'lo'); + expect(scanner.lineFromCursor).toBe('lo'); }); it('should advance past the next CR', () => { const scanner = getScanner('hel\rlo', true, 2); scanner.advancePastLine(); - assert.strictEqual(scanner.lineFromCursor, 'lo'); + expect(scanner.lineFromCursor).toBe('lo'); }); it('should advance past the next CRLF', () => { const scanner = getScanner('hel\r\nlo', true, 2); scanner.advancePastLine(); - assert.strictEqual(scanner.lineFromCursor, 'lo'); + expect(scanner.lineFromCursor).toBe('lo'); }); }); describe('#advanceTo', () => { it('should set the cursor to the supplied value', () => { - assert.strictEqual(getScanner('hello', true, 0).advanceTo(2).cursor, 2); + expect(getScanner('hello', true, 0).advanceTo(2).cursor).toBe(2); }); }); @@ -131,8 +128,8 @@ describe('Scanner', () => { it('should set the cursor to the supplied value', () => { const scanner = getScanner('hello', true, 0); const token = scanner.nextCharacterToken; - if (assertToken(token)) { - assert.strictEqual(scanner.advanceToToken(token).cursor, token.startCursor); + if (expectNonNullToken(token)) { + expect(scanner.advanceToToken(token).cursor).toBe(token.startCursor); } }); }); @@ -141,8 +138,8 @@ describe('Scanner', () => { it('should set the cursor to the supplied value', () => { const scanner = getScanner('hello', true, 0); const token = scanner.nextCharacterToken; - if (assertToken(token)) { - assert.strictEqual(scanner.advancePastToken(token).cursor, token.endCursor + 1); + if (expectNonNullToken(token)) { + expect(scanner.advancePastToken(token).cursor).toBe(token.endCursor + 1); } }); }); @@ -150,9 +147,9 @@ describe('Scanner', () => { describe('#truncateToCursor', () => { it('should set the cursor to the supplied value', () => { const scanner = getScanner('hello', true, 2).truncateToCursor(); - assert.strictEqual(scanner.line, 'llo'); - assert.strictEqual(scanner.lineLength, 3); - assert.strictEqual(scanner.cursor, 0); + expect(scanner.line).toBe('llo'); + expect(scanner.lineLength).toBe(3); + expect(scanner.cursor).toBe(0); }); }); }); @@ -162,67 +159,67 @@ describe('Token', () => { describe('.isTokenRowDelimiter', () => { it('should return true if the token is a row delimiter', () => { - assert.strictEqual(Token.isTokenRowDelimiter(createToken('\n')), true); - assert.strictEqual(Token.isTokenRowDelimiter(createToken('\r')), true); - assert.strictEqual(Token.isTokenRowDelimiter(createToken('\r\n')), true); + expect(Token.isTokenRowDelimiter(createToken('\n'))).toBe(true); + expect(Token.isTokenRowDelimiter(createToken('\r'))).toBe(true); + expect(Token.isTokenRowDelimiter(createToken('\r\n'))).toBe(true); }); it('should return false if the token is not a row delimiter', () => { - assert.strictEqual(Token.isTokenRowDelimiter(createToken('\\n')), false); - assert.strictEqual(Token.isTokenRowDelimiter(createToken('\\r')), false); + expect(Token.isTokenRowDelimiter(createToken('\\n'))).toBe(false); + expect(Token.isTokenRowDelimiter(createToken('\\r'))).toBe(false); }); }); describe('#isTokenCarriageReturn', () => { it('should return true if the token is a CR delimiter', () => { - assert.strictEqual(Token.isTokenCarriageReturn(createToken('\r'), createOptions()), true); + expect(Token.isTokenCarriageReturn(createToken('\r'), createOptions())).toBe(true); }); it('should return false if the token is not a CR delimiter', () => { - assert.strictEqual(Token.isTokenCarriageReturn(createToken('\n'), createOptions()), false); - assert.strictEqual(Token.isTokenCarriageReturn(createToken('\r\n'), createOptions()), false); + expect(Token.isTokenCarriageReturn(createToken('\n'), createOptions())).toBe(false); + expect(Token.isTokenCarriageReturn(createToken('\r\n'), createOptions())).toBe(false); }); }); describe('#isTokenComment', () => { it('should return true if the token is a comment character', () => { - assert.strictEqual(Token.isTokenComment(createToken('#'), createOptions({ comment: '#' })), true); + expect(Token.isTokenComment(createToken('#'), createOptions({ comment: '#' }))).toBe(true); }); it('should return false if the token is not a comment character', () => { - assert.strictEqual(Token.isTokenComment(createToken('+'), createOptions({ comment: '#' })), false); + expect(Token.isTokenComment(createToken('+'), createOptions({ comment: '#' }))).toBe(false); }); it('should return false if the token is not a comments are not supported', () => { - assert.strictEqual(Token.isTokenComment(createToken('#'), createOptions()), false); + expect(Token.isTokenComment(createToken('#'), createOptions())).toBe(false); }); }); describe('#isTokenEscapeCharacter', () => { it('should return true if the token is an escape character', () => { - assert.strictEqual(Token.isTokenEscapeCharacter(createToken('\\'), createOptions({ escape: '\\' })), true); + expect(Token.isTokenEscapeCharacter(createToken('\\'), createOptions({ escape: '\\' }))).toBe(true); }); it('should return false if the token is not a escape character', () => { - assert.strictEqual(Token.isTokenEscapeCharacter(createToken('"'), createOptions({ escape: '\\' })), false); + expect(Token.isTokenEscapeCharacter(createToken('"'), createOptions({ escape: '\\' }))).toBe(false); }); }); describe('#isTokenQuote', () => { it('should return true if the token is an quote character', () => { - assert.strictEqual(Token.isTokenEscapeCharacter(createToken('$'), createOptions({ quote: '$' })), true); + expect(Token.isTokenEscapeCharacter(createToken('$'), createOptions({ quote: '$' }))).toBe(true); }); it('should return false if the token is not a quote character', () => { - assert.strictEqual(Token.isTokenEscapeCharacter(createToken('"'), createOptions({ quote: '$' })), false); + expect(Token.isTokenEscapeCharacter(createToken('"'), createOptions({ quote: '$' }))).toBe(false); }); }); describe('#isTokenDelimiter', () => { it('should return true if the token is an delimiter character', () => { - assert.strictEqual(Token.isTokenDelimiter(createToken('\t'), createOptions({ delimiter: '\t' })), true); + expect(Token.isTokenDelimiter(createToken('\t'), createOptions({ delimiter: '\t' }))).toBe(true); }); it('should return false if the token is not a delimiter character', () => { - assert.strictEqual(Token.isTokenDelimiter(createToken(','), createOptions({ delimiter: '\t' })), false); + expect(Token.isTokenDelimiter(createToken(','), createOptions({ delimiter: '\t' }))).toBe(false); }); }); }); diff --git a/test/parser/parser/column/ColumnParser.test.ts b/__tests__/parser/parser/column/ColumnParser.spec.ts similarity index 88% rename from test/parser/parser/column/ColumnParser.test.ts rename to __tests__/parser/parser/column/ColumnParser.spec.ts index 3553b32e..d09ed87f 100644 --- a/test/parser/parser/column/ColumnParser.test.ts +++ b/__tests__/parser/parser/column/ColumnParser.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import * as sinon from 'sinon'; import { ParserOptions, Scanner, ColumnParser } from '../../../../src/parser'; @@ -16,7 +15,7 @@ describe('ColumnParser', () => { .once() .withArgs(scanner) .returns(expectedResult); - assert.deepStrictEqual(lineParser.parse(scanner), expectedResult); + expect(lineParser.parse(scanner)).toEqual(expectedResult); mock.verify(); }); }); @@ -32,7 +31,7 @@ describe('ColumnParser', () => { .once() .withArgs(scanner) .returns(expectedResult); - assert.deepStrictEqual(lineParser.parse(scanner), expectedResult); + expect(lineParser.parse(scanner)).toEqual(expectedResult); mock.verify(); }); }); diff --git a/test/parser/parser/column/NonQuotedColumnParser.test.ts b/__tests__/parser/parser/column/NonQuotedColumnParser.spec.ts similarity index 69% rename from test/parser/parser/column/NonQuotedColumnParser.test.ts rename to __tests__/parser/parser/column/NonQuotedColumnParser.spec.ts index 19f0d6fd..30dad12f 100644 --- a/test/parser/parser/column/NonQuotedColumnParser.test.ts +++ b/__tests__/parser/parser/column/NonQuotedColumnParser.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { ParserOptionsArgs } from '../../../../src'; import { ParserOptions, Scanner, NonQuotedColumnParser } from '../../../../src/parser'; @@ -17,64 +16,64 @@ describe('NonQuotedColumnParser', () => { const parserOptions = new ParserOptions({}); const lineParser = new NonQuotedColumnParser(parserOptions); const scanner = new Scanner({ line, parserOptions, hasMoreData: true }); - assert.strictEqual(lineParser.parse(scanner), null); + expect(lineParser.parse(scanner)).toBeNull(); }); it('should parse a column up to a column delimiter', () => { const line = 'hello,world'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ',world'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(',world'); }); it('should parse a column when not followed by any characters', () => { const line = 'hello'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(''); }); it('should parse a column up to a LF', () => { const line = 'hello\nworld'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\nworld'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\nworld'); }); it('should parse a column up to a CR', () => { const line = 'hello\rworld'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\rworld'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\rworld'); }); it('should parse a column up to a CRLF', () => { const line = 'hello\r\nworld'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\r\nworld'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\r\nworld'); }); describe('trim options', () => { it('should trim the item', () => { const line = ' hello '; const { scanner, col } = parse(line, true, { trim: true }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(''); }); it('should ltrim the item', () => { const line = ' hello '; const { scanner, col } = parse(line, true, { ltrim: true }); - assert.strictEqual(col, 'hello '); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hello '); + expect(scanner.lineFromCursor).toBe(''); }); it('should rtrim the item', () => { const line = ' hello '; const { scanner, col } = parse(line, true, { rtrim: true }); - assert.strictEqual(col, ' hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe(' hello'); + expect(scanner.lineFromCursor).toBe(''); }); }); }); @@ -85,72 +84,72 @@ describe('NonQuotedColumnParser', () => { const parserOptions = new ParserOptions({ delimiter: '\t' }); const lineParser = new NonQuotedColumnParser(parserOptions); const scanner = new Scanner({ line, parserOptions, hasMoreData: true }); - assert.strictEqual(lineParser.parse(scanner), null); - assert.strictEqual(scanner, scanner); + expect(lineParser.parse(scanner)).toBeNull(); + expect(scanner).toBe(scanner); }); it('should parse a column when not followed by any characters', () => { const line = 'hello'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(''); }); it('should parse a column up to the column delimiter', () => { const line = 'hello\tworld'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\tworld'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\tworld'); }); it('should include all white space up to a column delimiter', () => { const line = ' \t '; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, ' '); - assert.strictEqual(scanner.lineFromCursor, '\t '); + expect(col).toBe(' '); + expect(scanner.lineFromCursor).toBe('\t '); }); it('should parse a column up to a LF', () => { const line = 'hello\nworld'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\nworld'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\nworld'); }); it('should parse a column up to a CR', () => { const line = 'hello\rworld'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\rworld'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\rworld'); }); it('should parse a column up to a CRLF', () => { const line = 'hello\r\nworld'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\r\nworld'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\r\nworld'); }); describe('trim options', () => { it('should trim white space from both ends when trim is true', () => { const line = ' hello \t'; const { scanner, col } = parse(line, true, { delimiter: '\t', trim: true }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\t'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\t'); }); it('should trim white space from the left when ltrim is true', () => { const line = ' hello \t'; const { scanner, col } = parse(line, true, { delimiter: '\t', ltrim: true }); - assert.strictEqual(col, 'hello '); - assert.strictEqual(scanner.lineFromCursor, '\t'); + expect(col).toBe('hello '); + expect(scanner.lineFromCursor).toBe('\t'); }); it('should trim white space from the right when rtrim is true', () => { const line = ' hello \t'; const { scanner, col } = parse(line, true, { delimiter: '\t', ltrim: true }); - assert.strictEqual(col, 'hello '); - assert.strictEqual(scanner.lineFromCursor, '\t'); + expect(col).toBe('hello '); + expect(scanner.lineFromCursor).toBe('\t'); }); }); }); diff --git a/test/parser/parser/column/QuotedColumnParser.test.ts b/__tests__/parser/parser/column/QuotedColumnParser.spec.ts similarity index 67% rename from test/parser/parser/column/QuotedColumnParser.test.ts rename to __tests__/parser/parser/column/QuotedColumnParser.spec.ts index 6fdc206d..b51278d4 100644 --- a/test/parser/parser/column/QuotedColumnParser.test.ts +++ b/__tests__/parser/parser/column/QuotedColumnParser.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { ParserOptionsArgs } from '../../../../src'; import { ParserOptions, QuotedColumnParser, Scanner } from '../../../../src/parser'; @@ -17,169 +16,175 @@ describe('QuotedColumnParser', () => { const parserOptions = new ParserOptions({}); const lineParser = new QuotedColumnParser(parserOptions); const scanner = new Scanner({ line, parserOptions, hasMoreData: true }); - assert.strictEqual(lineParser.parse(scanner), null); - assert.strictEqual(scanner, scanner); + expect(lineParser.parse(scanner)).toBe(null); + expect(scanner).toBe(scanner); }); it('should parse a quoted col when not followed by any characters', () => { const line = '"hello"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(''); }); it('should not parse a quoted col when not followed by any characters', () => { const line = '"hello,'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, null); - assert.strictEqual(scanner.lineFromCursor, '"hello,'); + expect(col).toBe(null); + expect(scanner.lineFromCursor).toBe('"hello,'); }); it('should parse a quoted col up to a column delimiter', () => { const line = '"hello","world"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ',"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(',"world"'); }); it('should parse a quoted col up to a column delimiter with a LF in the column', () => { const line = '"hel\nlo","world"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hel\nlo'); - assert.strictEqual(scanner.lineFromCursor, ',"world"'); + expect(col).toBe('hel\nlo'); + expect(scanner.lineFromCursor).toBe(',"world"'); }); it('should parse a quoted col up to a column delimiter with a CR in the column', () => { const line = '"hel\rlo","world"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hel\rlo'); - assert.strictEqual(scanner.lineFromCursor, ',"world"'); + expect(col).toBe('hel\rlo'); + expect(scanner.lineFromCursor).toBe(',"world"'); }); it('should parse a quoted col up to a column delimiter with a CRLF in the column', () => { const line = '"hel\r\nlo","world"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hel\r\nlo'); - assert.strictEqual(scanner.lineFromCursor, ',"world"'); + expect(col).toBe('hel\r\nlo'); + expect(scanner.lineFromCursor).toBe(',"world"'); }); it('should parse a quoted col up to a LF', () => { const line = '"hello"\n"world"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\n"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\n"world"'); }); it('should parse a quoted col up to a CR', () => { const line = '"hello"\r"world"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\r"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\r"world"'); }); it('should parse a quoted col up to a CR', () => { const line = '"hello"\r\n"world"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\r\n"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\r\n"world"'); }); it('should parse a quoted column with escaped quotes when not followed by any characters', () => { const line = '"hell""o"""'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe(''); }); it('should parse a quoted column with escaped quotes when followed by a delimiter', () => { const line = '"hell""o""","world"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, ',"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe(',"world"'); }); it('should parse a quoted column with escaped quotes when followed by a LF', () => { const line = '"hell""o"""\n"world"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, '\n"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe('\n"world"'); }); it('should parse a quoted column with escaped quotes when followed by a CR', () => { const line = '"hell""o"""\r"world"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, '\r"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe('\r"world"'); }); it('should parse a quoted column with escaped quotes when followed by a CRLF', () => { const line = '"hell""o"""\r\n"world"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, '\r\n"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe('\r\n"world"'); }); it('should skip white space after a quote up to the column delimiter', () => { const line = '"Hello" ,"World"'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'Hello'); - assert.strictEqual(scanner.lineFromCursor, ',"World"'); + expect(col).toBe('Hello'); + expect(scanner.lineFromCursor).toBe(',"World"'); }); it('should skip white space after a quote up to a LF', () => { const line = '"Hello" \n'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'Hello'); - assert.strictEqual(scanner.lineFromCursor, '\n'); + expect(col).toBe('Hello'); + expect(scanner.lineFromCursor).toBe('\n'); }); it('should skip white space after a quote up to a CR', () => { const line = '"Hello" \r'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'Hello'); - assert.strictEqual(scanner.lineFromCursor, '\r'); + expect(col).toBe('Hello'); + expect(scanner.lineFromCursor).toBe('\r'); }); it('should skip white space after a quote up to a CRLF', () => { const line = '"Hello" \r\n'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, 'Hello'); - assert.strictEqual(scanner.lineFromCursor, '\r\n'); + expect(col).toBe('Hello'); + expect(scanner.lineFromCursor).toBe('\r\n'); }); it('should skip white space after a quote if has more data is false and there is no new line', () => { const line = '"Hello" '; const { scanner, col } = parse(line, false); - assert.strictEqual(col, 'Hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('Hello'); + expect(scanner.lineFromCursor).toBe(''); }); it('should include all quoted white space up to a column delimiter', () => { const line = '" "," "'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, ' '); - assert.strictEqual(scanner.lineFromCursor, '," "'); + expect(col).toBe(' '); + expect(scanner.lineFromCursor).toBe('," "'); }); it('should throw an error if a column contains a closing quote that is not followed by a row or column delimiter', () => { const line = '"hello\n"First'; - assert.throws(() => parse(line, true), /Parse Error: expected: ',' OR new line got: 'F'. at 'First/); - assert.throws(() => parse(line, false), /Parse Error: expected: ',' OR new line got: 'F'. at 'First/); + expect(() => parse(line, true)).toThrowError( + /Parse Error: expected: ',' OR new line got: 'F'. at 'First/, + ); + expect(() => parse(line, false)).toThrowError( + /Parse Error: expected: ',' OR new line got: 'F'. at 'First/, + ); }); describe('hasMoreData is true', () => { it('should not parse a column without a closing quote', () => { const line = '"hell""o'; const { scanner, col } = parse(line, true); - assert.strictEqual(col, null); - assert.strictEqual(scanner.lineFromCursor, line); + expect(col).toBe(null); + expect(scanner.lineFromCursor).toBe(line); }); }); describe('hasMoreData is false', () => { it('should not parse a column without a closing quote', () => { const line = '"hell""o'; - assert.throws(() => parse(line, false), /Parse Error: missing closing: '"' in line: at '"hell""o'/); + expect(() => parse(line, false)).toThrowError( + /Parse Error: missing closing: '"' in line: at '"hell""o'/, + ); }); }); }); @@ -190,130 +195,128 @@ describe('QuotedColumnParser', () => { const parserOptions = new ParserOptions({ delimiter: '\t' }); const lineParser = new QuotedColumnParser(parserOptions); const scanner = new Scanner({ line, parserOptions, hasMoreData: true }); - assert.strictEqual(lineParser.parse(scanner), null); - assert.strictEqual(scanner, scanner); + expect(lineParser.parse(scanner)).toBe(null); + expect(scanner).toBe(scanner); }); it('should parse a quoted col when not followed by any characters', () => { const line = '"hello"'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(''); }); it('should parse a quoted col up to a column delimiter', () => { const line = '"hello"\t"world"'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\t"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\t"world"'); }); it('should parse a quoted col up to a LF', () => { const line = '"hello"\n"world"'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\n"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\n"world"'); }); it('should parse a quoted col up to a CR', () => { const line = '"hello"\r"world"'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\r"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\r"world"'); }); it('should parse a quoted col up to a CR', () => { const line = '"hello"\r\n"world"'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\r\n"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\r\n"world"'); }); it('should parse a quoted column with escaped quotes when not followed by any characters', () => { const line = '"hell""o"""'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe(''); }); it('should parse a quoted column with escaped quotes when followed by a delimiter', () => { const line = '"hell""o"""\t"world"'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, '\t"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe('\t"world"'); }); it('should parse a quoted column with escaped quotes when followed by a LF', () => { const line = '"hell""o"""\n"world"'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, '\n"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe('\n"world"'); }); it('should parse a quoted column with escaped quotes when followed by a CR', () => { const line = '"hell""o"""\r"world"'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, '\r"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe('\r"world"'); }); it('should parse a quoted column with escaped quotes when followed by a CRLF', () => { const line = '"hell""o"""\r\n"world"'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, '\r\n"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe('\r\n"world"'); }); it('should skip white space after a quote up to the column delimiter', () => { const line = '"Hello" \t"World"'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'Hello'); - assert.strictEqual(scanner.lineFromCursor, '\t"World"'); + expect(col).toBe('Hello'); + expect(scanner.lineFromCursor).toBe('\t"World"'); }); it('should skip white space after a quote up to a LF', () => { const line = '"Hello" \n'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'Hello'); - assert.strictEqual(scanner.lineFromCursor, '\n'); + expect(col).toBe('Hello'); + expect(scanner.lineFromCursor).toBe('\n'); }); it('should skip white space after a quote up to a CR', () => { const line = '"Hello" \r'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'Hello'); - assert.strictEqual(scanner.lineFromCursor, '\r'); + expect(col).toBe('Hello'); + expect(scanner.lineFromCursor).toBe('\r'); }); it('should skip white space after a quote up to a CRLF', () => { const line = '"Hello" \r\n'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, 'Hello'); - assert.strictEqual(scanner.lineFromCursor, '\r\n'); + expect(col).toBe('Hello'); + expect(scanner.lineFromCursor).toBe('\r\n'); }); it('should skip white space after a quote if has more data is false and there is no new line', () => { const line = '"Hello" '; const { scanner, col } = parse(line, false, { delimiter: '\t' }); - assert.strictEqual(col, 'Hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('Hello'); + expect(scanner.lineFromCursor).toBe(''); }); it('should include all quoted white space up to a column delimiter', () => { const line = '" "\t" "'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, ' '); - assert.strictEqual(scanner.lineFromCursor, '\t" "'); + expect(col).toBe(' '); + expect(scanner.lineFromCursor).toBe('\t" "'); }); it('should throw an error if a column contains a closing quote that is not followed by a row or column delimiter', () => { const line = '"hello\n"First'; - assert.throws( - () => parse(line, true, { delimiter: '\t' }), + expect(() => parse(line, true, { delimiter: '\t' })).toThrowError( /Parse Error: expected: '\t' OR new line got: 'F'. at 'First/, ); - assert.throws( - () => parse(line, false, { delimiter: '\t' }), + expect(() => parse(line, false, { delimiter: '\t' })).toThrowError( /Parse Error: expected: '\t' OR new line got: 'F'. at 'First/, ); }); @@ -322,16 +325,15 @@ describe('QuotedColumnParser', () => { it('should not parse a column without a closing quote', () => { const line = '"hell""o'; const { scanner, col } = parse(line, true, { delimiter: '\t' }); - assert.strictEqual(col, null); - assert.strictEqual(scanner.lineFromCursor, line); + expect(col).toBe(null); + expect(scanner.lineFromCursor).toBe(line); }); }); describe('hasMoreData is false', () => { it('should not parse a column without a closing quote', () => { const line = '"hell""o'; - assert.throws( - () => parse(line, false, { delimiter: '\t' }), + expect(() => parse(line, false, { delimiter: '\t' })).toThrowError( /Parse Error: missing closing: '"' in line: at '"hell""o'/, ); }); @@ -344,88 +346,86 @@ describe('QuotedColumnParser', () => { const parserOptions = new ParserOptions({ quote: '$' }); const lineParser = new QuotedColumnParser(parserOptions); const scanner = new Scanner({ line, parserOptions, hasMoreData: true }); - assert.strictEqual(lineParser.parse(scanner), null); - assert.strictEqual(scanner, scanner); + expect(lineParser.parse(scanner)).toBe(null); + expect(scanner).toBe(scanner); }); it('should parse a quoted col when not followed by any characters', () => { const line = '$hello$'; const { scanner, col } = parse(line, true, { quote: '$' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(''); }); it('should parse a quoted col up to a column delimiter', () => { const line = '$hello$,$world$'; const { scanner, col } = parse(line, true, { quote: '$' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ',$world$'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(',$world$'); }); it('should parse a quoted col up to a LF', () => { const line = '$hello$\n$world$'; const { scanner, col } = parse(line, true, { quote: '$' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\n$world$'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\n$world$'); }); it('should parse a quoted col up to a CR', () => { const line = '$hello$\r$world$'; const { scanner, col } = parse(line, true, { quote: '$' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\r$world$'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\r$world$'); }); it('should parse a quoted col up to a CR', () => { const line = '$hello$\r\n$world$'; const { scanner, col } = parse(line, true, { quote: '$' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\r\n$world$'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\r\n$world$'); }); it('should parse a quoted column with escaped quotes when not followed by any characters', () => { const line = '$hell$$o$$$'; const { scanner, col } = parse(line, true, { quote: '$' }); - assert.strictEqual(col, 'hell$o$'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hell$o$'); + expect(scanner.lineFromCursor).toBe(''); }); it('should parse a quoted column with escaped quotes when followed by a delimiter', () => { const line = '$hell$$o$$$,$world$'; const { scanner, col } = parse(line, true, { quote: '$' }); - assert.strictEqual(col, 'hell$o$'); - assert.strictEqual(scanner.lineFromCursor, ',$world$'); + expect(col).toBe('hell$o$'); + expect(scanner.lineFromCursor).toBe(',$world$'); }); it('should parse a quoted column with escaped quotes when followed by a LF', () => { const line = '$hell$$o$$$\n$world$'; const { scanner, col } = parse(line, true, { quote: '$' }); - assert.strictEqual(col, 'hell$o$'); - assert.strictEqual(scanner.lineFromCursor, '\n$world$'); + expect(col).toBe('hell$o$'); + expect(scanner.lineFromCursor).toBe('\n$world$'); }); it('should parse a quoted column with escaped quotes when followed by a CR', () => { const line = '$hell$$o$$$\r$world$'; const { scanner, col } = parse(line, true, { quote: '$' }); - assert.strictEqual(col, 'hell$o$'); - assert.strictEqual(scanner.lineFromCursor, '\r$world$'); + expect(col).toBe('hell$o$'); + expect(scanner.lineFromCursor).toBe('\r$world$'); }); it('should parse a quoted column with escaped quotes when followed by a CRLF', () => { const line = '$hell$$o$$$\r\n$world$'; const { scanner, col } = parse(line, true, { quote: '$' }); - assert.strictEqual(col, 'hell$o$'); - assert.strictEqual(scanner.lineFromCursor, '\r\n$world$'); + expect(col).toBe('hell$o$'); + expect(scanner.lineFromCursor).toBe('\r\n$world$'); }); it('should throw an error if a column contains a closing quote that is not followed by a row or column delimiter', () => { const line = '$hello\n$First'; - assert.throws( - () => parse(line, true, { quote: '$' }), + expect(() => parse(line, true, { quote: '$' })).toThrowError( /Parse Error: expected: ',' OR new line got: 'F'. at 'First/, ); - assert.throws( - () => parse(line, false, { quote: '$' }), + expect(() => parse(line, false, { quote: '$' })).toThrowError( /Parse Error: expected: ',' OR new line got: 'F'. at 'First/, ); }); @@ -434,16 +434,15 @@ describe('QuotedColumnParser', () => { it('should not parse a column without a closing quote', () => { const line = '$hell$$o'; const { scanner, col } = parse(line, true, { quote: '$' }); - assert.strictEqual(col, null); - assert.strictEqual(scanner.lineFromCursor, line); + expect(col).toBe(null); + expect(scanner.lineFromCursor).toBe(line); }); }); describe('hasMoreData is false', () => { it('should not parse a column without a closing quote', () => { const line = '$hell$$o'; - assert.throws( - () => parse(line, false, { quote: '$' }), + expect(() => parse(line, false, { quote: '$' })).toThrowError( /Parse Error: missing closing: '\$' in line: at '\$hell\$\$o'/, ); }); @@ -456,95 +455,93 @@ describe('QuotedColumnParser', () => { const parserOptions = new ParserOptions({ escape: '$' }); const lineParser = new QuotedColumnParser(parserOptions); const scanner = new Scanner({ line, parserOptions, hasMoreData: true }); - assert.strictEqual(lineParser.parse(scanner), null); - assert.strictEqual(scanner, scanner); + expect(lineParser.parse(scanner)).toBe(null); + expect(scanner).toBe(scanner); }); it('should parse a quoted col when not followed by any characters', () => { const line = '"hello"'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(''); }); it('should parse a quoted col up to a column delimiter', () => { const line = '"hello","world"'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ',"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(',"world"'); }); it('should parse an escape not followed by a quote', () => { const line = '"hell$o","world"'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, 'hell$o'); - assert.strictEqual(scanner.lineFromCursor, ',"world"'); + expect(col).toBe('hell$o'); + expect(scanner.lineFromCursor).toBe(',"world"'); }); it('should parse a quoted col up to a LF', () => { const line = '"hello"\n"world"'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\n"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\n"world"'); }); it('should parse a quoted col up to a CR', () => { const line = '"hello"\r"world"'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\r"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\r"world"'); }); it('should parse a quoted col up to a CR', () => { const line = '"hello"\r\n"world"'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, '\r\n"world"'); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe('\r\n"world"'); }); it('should parse a quoted column with escaped quotes when not followed by any characters', () => { const line = '"hell$"o$""'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe(''); }); it('should parse a quoted column with escaped quotes when followed by a delimiter', () => { const line = '"hell$"o$"","world"'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, ',"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe(',"world"'); }); it('should parse a quoted column with escaped quotes when followed by a LF', () => { const line = '"hell$"o$""\n"world"'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, '\n"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe('\n"world"'); }); it('should parse a quoted column with escaped quotes when followed by a CR', () => { const line = '"hell$"o$""\r"world"'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, '\r"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe('\r"world"'); }); it('should parse a quoted column with escaped quotes when followed by a CRLF', () => { const line = '"hell$"o$""\r\n"world"'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, 'hell"o"'); - assert.strictEqual(scanner.lineFromCursor, '\r\n"world"'); + expect(col).toBe('hell"o"'); + expect(scanner.lineFromCursor).toBe('\r\n"world"'); }); it('should throw an error if a column contains a closing quote that is not followed by a row or column delimiter', () => { const line = '"hello\n"First'; - assert.throws( - () => parse(line, true, { escape: '$' }), + expect(() => parse(line, true, { escape: '$' })).toThrowError( /Parse Error: expected: ',' OR new line got: 'F'. at 'First/, ); - assert.throws( - () => parse(line, false, { escape: '$' }), + expect(() => parse(line, false, { escape: '$' })).toThrowError( /Parse Error: expected: ',' OR new line got: 'F'. at 'First/, ); }); @@ -553,16 +550,15 @@ describe('QuotedColumnParser', () => { it('should not parse a column without a closing quote', () => { const line = '"hell$"o'; const { scanner, col } = parse(line, true, { escape: '$' }); - assert.strictEqual(col, null); - assert.strictEqual(scanner.lineFromCursor, line); + expect(col).toBe(null); + expect(scanner.lineFromCursor).toBe(line); }); }); describe('hasMoreData is false', () => { it('should not parse a column without a closing quote', () => { const line = '"hell$"o'; - assert.throws( - () => parse(line, false, { escape: '$' }), + expect(() => parse(line, false, { escape: '$' })).toThrowError( /Parse Error: missing closing: '"' in line: at '"hell\$"o'/, ); }); @@ -573,22 +569,22 @@ describe('QuotedColumnParser', () => { it('should trim the item', () => { const line = '" hello "'; const { scanner, col } = parse(line, true, { trim: true }); - assert.strictEqual(col, 'hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hello'); + expect(scanner.lineFromCursor).toBe(''); }); it('should ltrim the item', () => { const line = '" hello "'; const { scanner, col } = parse(line, true, { ltrim: true }); - assert.strictEqual(col, 'hello '); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe('hello '); + expect(scanner.lineFromCursor).toBe(''); }); it('should rtrim the item', () => { const line = '" hello "'; const { scanner, col } = parse(line, true, { rtrim: true }); - assert.strictEqual(col, ' hello'); - assert.strictEqual(scanner.lineFromCursor, ''); + expect(col).toBe(' hello'); + expect(scanner.lineFromCursor).toBe(''); }); }); }); diff --git a/test/parser/transforms/HeaderTransformer.test.ts b/__tests__/parser/transforms/HeaderTransformer.spec.ts similarity index 50% rename from test/parser/transforms/HeaderTransformer.test.ts rename to __tests__/parser/transforms/HeaderTransformer.spec.ts index 15f517a1..5f980d94 100644 --- a/test/parser/transforms/HeaderTransformer.test.ts +++ b/__tests__/parser/transforms/HeaderTransformer.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { ParserOptionsArgs, ParserRowArray as RowArray } from '../../../src'; import { ParserOptions, RowValidationResult, HeaderTransformer } from '../../../src/parser'; @@ -19,181 +18,148 @@ describe('HeaderTransformer', () => { }); describe('#transform', () => { - it('should return a valid row', () => { + it('should return a valid row', async () => { const row = ['a', 'b']; const transformer = createHeaderTransformer({ headers: false }); - return transform(row, transformer).then(results => { - assert.deepStrictEqual(results, { row, isValid: true }); - }); + await expect(transform(row, transformer)).resolves.toEqual({ row, isValid: true }); }); - it('should return a null row that is still valid if headers is true', () => { + it('should return a null row that is still valid if headers is true', async () => { const row = ['a', 'b']; const transformer = createHeaderTransformer({ headers: true }); - return transform(row, transformer).then(results => { - assert.deepStrictEqual(results, { row: null, isValid: true }); - }); + await expect(transform(row, transformer)).resolves.toEqual({ row: null, isValid: true }); }); - it('should return a row with mapped headers if headers is an array', () => { + it('should return a row with mapped headers if headers is an array', async () => { const row = ['a', 'b']; const transformer = createHeaderTransformer({ headers: ['header1', 'header2'] }); - return transform(row, transformer).then(results => { - assert.deepStrictEqual(results, { row: { header1: 'a', header2: 'b' }, isValid: true }); + await expect(transform(row, transformer)).resolves.toEqual({ + row: { header1: 'a', header2: 'b' }, + isValid: true, }); }); - it('should skip columns with an undefined header', () => { + it('should skip columns with an undefined header', async () => { const row = ['a', 'b', 'c']; const transformer = createHeaderTransformer({ headers: ['header1', undefined, 'header2'] }); - return transform(row, transformer).then(results => { - assert.deepStrictEqual(results, { row: { header1: 'a', header2: 'c' }, isValid: true }); + await expect(transform(row, transformer)).resolves.toEqual({ + row: { header1: 'a', header2: 'c' }, + isValid: true, }); }); - it('should skip the first row if renameHeaders is true and headers is an array', () => { + it('should skip the first row if renameHeaders is true and headers is an array', async () => { const row1 = ['origHeader1', 'origHeader2']; const row2 = ['a', 'b']; const transformer = createHeaderTransformer({ headers: ['header1', 'header2'], renameHeaders: true }); - return transform(row1, transformer) - .then(results => { - assert.deepStrictEqual(results, { row: null, isValid: true }); - return transform(row2, transformer); - }) - .then(results => { - assert.deepStrictEqual(results, { row: { header1: 'a', header2: 'b' }, isValid: true }); - }); + await expect(transform(row1, transformer)).resolves.toEqual({ row: null, isValid: true }); + await expect(transform(row2, transformer)).resolves.toEqual({ + row: { header1: 'a', header2: 'b' }, + isValid: true, + }); }); - it('should skip the first row if headers is function and properly map the headers to the row', () => { + it('should skip the first row if headers is function and properly map the headers to the row', async () => { const row1 = ['origHeader1', 'origHeader2']; const row2 = ['a', 'b']; const transformer = createHeaderTransformer({ headers: headers => headers.map(h => h?.toUpperCase()), }); - return transform(row1, transformer) - .then(results => { - assert.deepStrictEqual(results, { row: null, isValid: true }); - return transform(row2, transformer); - }) - .then(results => { - assert.deepStrictEqual(results, { row: { ORIGHEADER1: 'a', ORIGHEADER2: 'b' }, isValid: true }); - }); + await expect(transform(row1, transformer)).resolves.toEqual({ row: null, isValid: true }); + await expect(transform(row2, transformer)).resolves.toEqual({ + row: { ORIGHEADER1: 'a', ORIGHEADER2: 'b' }, + isValid: true, + }); }); - it('should throw an error if headers is true and the first row is not unique', () => { + it('should throw an error if headers is true and the first row is not unique', async () => { const row1 = ['origHeader1', 'origHeader1', 'origHeader2']; const transformer = createHeaderTransformer({ headers: true }); - return transform(row1, transformer).then( - () => assert.fail('should have failed'), - err => assert.strictEqual(err.message, 'Duplicate headers found ["origHeader1"]'), - ); + await expect(transform(row1, transformer)).rejects.toThrowError('Duplicate headers found ["origHeader1"]'); }); it('should throw an error if headers is an array and is not unique', () => { const headers = ['origHeader1', 'origHeader1', 'origHeader2']; - assert.throws(() => createHeaderTransformer({ headers }), /Duplicate headers found \["origHeader1"]/); + expect(() => createHeaderTransformer({ headers })).toThrowError('Duplicate headers found ["origHeader1"]'); }); - it('should throw an error if headers is a transform and returns non-unique values', () => { + it('should throw an error if headers is a transform and returns non-unique values', async () => { const row = ['h1', 'h2', 'h3']; const transformer = createHeaderTransformer({ headers: () => ['h1', 'h1', 'h3'] }); - return transform(row, transformer).catch(err => - assert.strictEqual(err.message, 'Duplicate headers found ["h1"]'), - ); + await expect(transform(row, transformer)).rejects.toThrowError('Duplicate headers found ["h1"]'); }); - it('should throw an error if headers is not defined and renameHeaders is true', () => { + it('should throw an error if headers is not defined and renameHeaders is true', async () => { const row1 = ['origHeader1', 'origHeader2']; const transformer = createHeaderTransformer({ renameHeaders: true }); - return transform(row1, transformer).then( - () => assert.fail('should have failed'), - err => - assert.strictEqual(err.message, 'Error renaming headers: new headers must be provided in an array'), + await expect(transform(row1, transformer)).rejects.toThrowError( + 'Error renaming headers: new headers must be provided in an array', ); }); - it('should throw an error if the row length is > than the headers length as strictColumnHandling is not defined', () => { + it('should throw an error if the row length is > than the headers length as strictColumnHandling is not defined', async () => { const row = ['a', 'b', 'c']; const transformer = createHeaderTransformer({ headers: ['header1', 'header2'] }); - return transform(row, transformer).then( - () => assert.fail('should have failed'), - err => - assert.strictEqual( - err.message, - 'Unexpected Error: column header mismatch expected: 2 columns got: 3', - ), + await expect(transform(row, transformer)).rejects.toThrowError( + 'Unexpected Error: column header mismatch expected: 2 columns got: 3', ); }); - it('should throw an error if the row length is > than the headers length as strictColumnHandling is false', () => { + it('should throw an error if the row length is > than the headers length as strictColumnHandling is false', async () => { const row = ['a', 'b', 'c']; const transformer = createHeaderTransformer({ headers: ['header1', 'header2'], strictColumnHandling: false, }); - return transform(row, transformer).then( - () => assert.fail('should have failed'), - err => - assert.strictEqual( - err.message, - 'Unexpected Error: column header mismatch expected: 2 columns got: 3', - ), + await expect(transform(row, transformer)).rejects.toThrowError( + 'Unexpected Error: column header mismatch expected: 2 columns got: 3', ); }); - it('should mark the row as invalid if the row length is > than the headers length as strictColumnHandling is true', () => { + it('should mark the row as invalid if the row length is > than the headers length as strictColumnHandling is true', async () => { const row = ['a', 'b', 'c']; const transformer = createHeaderTransformer({ headers: ['header1', 'header2'], strictColumnHandling: true, }); - return transform(row, transformer).then(results => { - assert.deepStrictEqual(results, { - row, - isValid: false, - reason: 'Column header mismatch expected: 2 columns got: 3', - }); + await expect(transform(row, transformer)).resolves.toEqual({ + row, + isValid: false, + reason: 'Column header mismatch expected: 2 columns got: 3', }); }); - it('should return a mapped row if row length is < than the headers length as strictColumnHandling is not defined', () => { + it('should return a mapped row if row length is < than the headers length as strictColumnHandling is not defined', async () => { const row = ['a']; const transformer = createHeaderTransformer({ headers: ['header1', 'header2'] }); - return transform(row, transformer).then(results => { - assert.deepStrictEqual(results, { - row: { header1: 'a', header2: '' }, - isValid: true, - }); + await expect(transform(row, transformer)).resolves.toEqual({ + row: { header1: 'a', header2: '' }, + isValid: true, }); }); - it('should return a mapped row if row length is < than the headers length as strictColumnHandling is not false', () => { + it('should return a mapped row if row length is < than the headers length as strictColumnHandling is not false', async () => { const row = ['a']; const transformer = createHeaderTransformer({ headers: ['header1', 'header2'], strictColumnHandling: false, }); - return transform(row, transformer).then(results => { - assert.deepStrictEqual(results, { - row: { header1: 'a', header2: '' }, - isValid: true, - }); + await expect(transform(row, transformer)).resolves.toEqual({ + row: { header1: 'a', header2: '' }, + isValid: true, }); }); - it('should mark the row as invalid if the row length is < than the headers length as strictColumnHandling is true', () => { + it('should mark the row as invalid if the row length is < than the headers length as strictColumnHandling is true', async () => { const row = ['a']; const transformer = createHeaderTransformer({ headers: ['header1', 'header2'], strictColumnHandling: true, }); - return transform(row, transformer).then(results => { - assert.deepStrictEqual(results, { - row, - isValid: false, - reason: 'Column header mismatch expected: 2 columns got: 1', - }); + await expect(transform(row, transformer)).resolves.toEqual({ + row, + isValid: false, + reason: 'Column header mismatch expected: 2 columns got: 1', }); }); }); diff --git a/test/parser/transforms/RowTransformerValidator.test.ts b/__tests__/parser/transforms/RowTransformerValidator.spec.ts similarity index 66% rename from test/parser/transforms/RowTransformerValidator.test.ts rename to __tests__/parser/transforms/RowTransformerValidator.spec.ts index e52a4a7b..2e648529 100644 --- a/test/parser/transforms/RowTransformerValidator.test.ts +++ b/__tests__/parser/transforms/RowTransformerValidator.spec.ts @@ -1,4 +1,3 @@ -import * as assert from 'assert'; import { ParserRow as Row, ParserRowArray as RowArray } from '../../../src'; import { RowValidationResult, RowTransformerValidator } from '../../../src/parser'; @@ -19,55 +18,52 @@ describe('RowTransformerValidator', () => { }); describe('#transformAndValidate', () => { - it('should return a valid row if validator and transform are not defined', () => { + it('should return a valid row if validator and transform are not defined', async () => { const row = ['a', 'b']; const transformer = createRowTransformerValidator(); - return transformAndValidate(row, transformer).then(results => { - assert.deepStrictEqual(results, { row, isValid: true }); - }); + await expect(transformAndValidate(row, transformer)).resolves.toEqual({ row, isValid: true }); }); describe('#rowTransform', () => { it('should throw an error if the transform is not a function', () => { const transformer = createRowTransformerValidator(); - assert.throws(() => { + expect(() => { // @ts-ignore transformer.rowTransform = 'foo'; - }, /TypeError: The transform should be a function/); + }).toThrowError('The transform should be a function'); }); - it('should transform a row synchronously', () => { + it('should transform a row synchronously', async () => { const row = ['a', 'b']; const transformer = createRowTransformerValidator(); transformer.rowTransform = (r: Row) => (r as RowArray).map(col => col.toUpperCase()); - return transformAndValidate(row, transformer).then(results => { - assert.deepStrictEqual(results, { row: ['A', 'B'], isValid: true }); + await expect(transformAndValidate(row, transformer)).resolves.toEqual({ + row: ['A', 'B'], + isValid: true, }); }); - it('should transform a row synchronously', () => { + it('should transform a row synchronously', async () => { const row = ['a', 'b']; const transformer = createRowTransformerValidator(); transformer.rowTransform = (r: Row) => (r as RowArray).map(col => col.toUpperCase()); - return transformAndValidate(row, transformer).then(results => { - assert.deepStrictEqual(results, { row: ['A', 'B'], isValid: true }); + await expect(transformAndValidate(row, transformer)).resolves.toEqual({ + row: ['A', 'B'], + isValid: true, }); }); - it('should resolve with an error if the transform throws an error', () => { + it('should resolve with an error if the transform throws an error', async () => { const row = ['a', 'b']; const transformer = createRowTransformerValidator(); // eslint-disable-next-line @typescript-eslint/no-unused-vars transformer.rowTransform = (r: Row) => { throw new Error('Expected error'); }; - return transformAndValidate(row, transformer).then( - () => assert.fail('should have failed'), - err => assert.strictEqual(err.message, 'Expected error'), - ); + await expect(transformAndValidate(row, transformer)).rejects.toThrowError('Expected error'); }); - it('should transform a row asynchronously', () => { + it('should transform a row asynchronously', async () => { const row = ['a', 'b']; const transformer = createRowTransformerValidator(); transformer.rowTransform = (r: Row, cb) => { @@ -78,12 +74,13 @@ describe('RowTransformerValidator', () => { ); }); }; - return transformAndValidate(row, transformer).then(results => { - assert.deepStrictEqual(results, { row: ['A', 'B'], isValid: true }); + await expect(transformAndValidate(row, transformer)).resolves.toEqual({ + row: ['A', 'B'], + isValid: true, }); }); - it('should resolve with an error if an error is provided to the callback', () => { + it('should resolve with an error if an error is provided to the callback', async () => { const row = ['a', 'b']; const transformer = createRowTransformerValidator(); transformer.rowTransform = (r: Row, cb) => { @@ -91,33 +88,32 @@ describe('RowTransformerValidator', () => { cb(new Error('Expected error')); }); }; - return transformAndValidate(row, transformer).then( - () => assert.fail('should have failed'), - err => assert.strictEqual(err.message, 'Expected error'), - ); + await expect(transformAndValidate(row, transformer)).rejects.toThrowError('Expected error'); }); }); describe('#rowValidator', () => { it('should throw an error if the validator is not a function', () => { const transformer = createRowTransformerValidator(); - assert.throws(() => { + expect(() => { // @ts-ignore transformer.rowValidator = 'foo'; - }, /TypeError: The validate should be a function/); + }).toThrowError('The validate should be a function'); }); - it('should validate a row synchronously', () => { + it('should validate a row synchronously', async () => { const row = ['a', 'b']; const transformer = createRowTransformerValidator(); // eslint-disable-next-line @typescript-eslint/no-unused-vars transformer.rowValidator = (r: Row) => false; - return transformAndValidate(row, transformer).then(results => { - assert.deepStrictEqual(results, { row, isValid: false, reason: undefined }); + await expect(transformAndValidate(row, transformer)).resolves.toEqual({ + row, + isValid: false, + reason: undefined, }); }); - it('should validate a row asynchronously', () => { + it('should validate a row asynchronously', async () => { const row = ['a', 'b']; const transformer = createRowTransformerValidator(); transformer.rowValidator = (r: Row, cb) => { @@ -125,12 +121,14 @@ describe('RowTransformerValidator', () => { cb(null, false); }); }; - return transformAndValidate(row, transformer).then(results => { - assert.deepStrictEqual(results, { row, isValid: false, reason: undefined }); + await expect(transformAndValidate(row, transformer)).resolves.toEqual({ + row, + isValid: false, + reason: undefined, }); }); - it('should validate a row asynchronously with a reason', () => { + it('should validate a row asynchronously with a reason', async () => { const row = ['a', 'b']; const transformer = createRowTransformerValidator(); transformer.rowValidator = (r: Row, cb) => { @@ -138,25 +136,24 @@ describe('RowTransformerValidator', () => { cb(null, false, 'just because'); }); }; - return transformAndValidate(row, transformer).then(results => { - assert.deepStrictEqual(results, { row, isValid: false, reason: 'just because' }); + await expect(transformAndValidate(row, transformer)).resolves.toEqual({ + row, + isValid: false, + reason: 'just because', }); }); - it('should resolve with an error if the validate throws an error', () => { + it('should resolve with an error if the validate throws an error', async () => { const row = ['a', 'b']; const transformer = createRowTransformerValidator(); // eslint-disable-next-line @typescript-eslint/no-unused-vars transformer.rowValidator = (r: Row) => { throw new Error('Expected error'); }; - return transformAndValidate(row, transformer).then( - () => assert.fail('should have failed'), - err => assert.strictEqual(err.message, 'Expected error'), - ); + await expect(transformAndValidate(row, transformer)).rejects.toThrowError('Expected error'); }); - it('should resolve with an error if an error is provided to the callback', () => { + it('should resolve with an error if an error is provided to the callback', async () => { const row = ['a', 'b']; const transformer = createRowTransformerValidator(); transformer.rowValidator = (r: Row, cb) => { @@ -164,10 +161,7 @@ describe('RowTransformerValidator', () => { cb(new Error('Expected error')); }); }; - return transformAndValidate(row, transformer).then( - () => assert.fail('should have failed'), - err => assert.strictEqual(err.message, 'Expected error'), - ); + await expect(transformAndValidate(row, transformer)).rejects.toThrowError('Expected error'); }); }); }); diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..f865a7b8 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,11 @@ +// jest.config.js +module.exports = { + // [...] + // Replace `ts-jest` with the preset you want to use + // from the above list + preset: 'ts-jest', + collectCoverageFrom: [ + "src/**/*.ts" + ], + testMatch: [ "**/__tests__/**/*.spec.ts"], +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d7fd30dc..9155f394 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,57 @@ "@babel/highlight": "^7.0.0" } }, + "@babel/core": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.7.tgz", + "integrity": "sha512-jlSjuj/7z138NLZALxVgrx13AOtqip42ATZP7+kYl53GvDV6+4dCek1mVUo8z8c8Xnw/mx2q3d9HWh3griuesQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.7", + "@babel/helpers": "^7.7.4", + "@babel/parser": "^7.7.7", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + } + } + }, "@babel/generator": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.4.tgz", @@ -45,6 +96,12 @@ "@babel/types": "^7.7.4" } }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, "@babel/helper-split-export-declaration": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", @@ -54,6 +111,17 @@ "@babel/types": "^7.7.4" } }, + "@babel/helpers": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.7.4.tgz", + "integrity": "sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==", + "dev": true, + "requires": { + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, "@babel/highlight": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", @@ -71,6 +139,15 @@ "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==", "dev": true }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz", + "integrity": "sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, "@babel/template": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", @@ -130,12 +207,282 @@ "to-fast-properties": "^2.0.0" } }, + "@cnakazawa/watch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", + "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "@istanbuljs/nyc-config-typescript": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/nyc-config-typescript/-/nyc-config-typescript-0.1.3.tgz", "integrity": "sha512-EzRFg92bRSD1W/zeuNkeGwph0nkWf+pP2l/lYW4/5hav7RjKKBN5kV1Ix7Tvi0CMu3pC4Wi/U7rNisiJMR3ORg==", "dev": true }, + "@jest/console": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "dev": true, + "requires": { + "@jest/source-map": "^24.9.0", + "chalk": "^2.0.1", + "slash": "^2.0.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "@jest/core": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", + "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/reporters": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.9.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-resolve-dependencies": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "jest-watcher": "^24.9.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "slash": "^2.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "@jest/environment": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", + "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "dev": true, + "requires": { + "@jest/fake-timers": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/fake-timers": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/reporters": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.4.2", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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==", + "dev": true + } + } + }, + "@jest/source-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/test-result": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/istanbul-lib-coverage": "^2.0.0" + } + }, + "@jest/test-sequencer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" + } + }, + "@jest/transform": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", + "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.9.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.9.0", + "jest-regex-util": "^24.9.0", + "jest-util": "^24.9.0", + "micromatch": "^3.1.10", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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==", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + } + } + }, + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, "@sinonjs/commons": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz", @@ -180,12 +527,87 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "@types/babel__core": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", + "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz", + "integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", + "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.8.tgz", + "integrity": "sha512-yGeB2dHEdvxjP0y4UbRtQaSkXJ9649fYCmIdRoul5kfAoGCwxuCbMhag0k3RPfnuh9kPGm8x89btcfDEXdVWGw==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", "dev": true }, + "@types/istanbul-lib-coverage": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", + "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", + "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", + "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "24.0.24", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.24.tgz", + "integrity": "sha512-vgaG968EDPSJPMunEDdZvZgvxYSmeH8wKqBlHSkBt1pV2XlLEVDzsj1ZhLuI4iG4Pv841tES61txSBF0obh4CQ==", + "dev": true, + "requires": { + "jest-diff": "^24.3.0" + } + }, "@types/json-schema": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", @@ -288,12 +710,6 @@ "@types/lodash": "*" } }, - "@types/mocha": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", - "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", - "dev": true - }, "@types/node": { "version": "12.12.17", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.17.tgz", @@ -311,6 +727,27 @@ "integrity": "sha512-EZQUP3hSZQyTQRfiLqelC9NMWd1kqLcmQE0dMiklxBkgi84T+cHOhnKpgk4NnOWpGX863yE6+IaGnOXUNFqDnQ==", "dev": true }, + "@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "@types/yargs": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", + "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", + "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.11.0.tgz", @@ -370,18 +807,48 @@ } } }, + "abab": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", + "dev": true + }, "acorn": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", "dev": true }, + "acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", + "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==", + "dev": true + } + } + }, "acorn-jsx": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", "dev": true }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "dev": true + }, "ajv": { "version": "6.10.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", @@ -394,12 +861,6 @@ "uri-js": "^4.2.2" } }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", - "dev": true - }, "ansi-escapes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", @@ -424,6 +885,16 @@ "color-convert": "^1.9.0" } }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, "append-transform": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", @@ -454,6 +925,30 @@ "sprintf-js": "~1.0.2" } }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, "array-from": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", @@ -490,6 +985,12 @@ } } }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, "array.prototype.flat": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.2.tgz", @@ -516,18 +1017,36 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -540,23 +1059,142 @@ "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==", "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 - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "babel-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", + "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", "dev": true, "requires": { - "tweetnacl": "^0.14.3" - } - }, - "brace-expansion": { - "version": "1.1.11", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.9.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "babel-plugin-istanbul": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" + } + }, + "babel-plugin-jest-hoist": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", + "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", + "dev": true, + "requires": { + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", + "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.9.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "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, @@ -565,18 +1203,99 @@ "concat-map": "0.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==", + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", "dev": true }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, "caching-transform": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", @@ -627,6 +1346,15 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -667,6 +1395,29 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -693,12 +1444,28 @@ "wrap-ansi": "^2.0.0" } }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -736,6 +1503,12 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -763,6 +1536,12 @@ "safe-buffer": "~5.1.1" } }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -875,6 +1654,21 @@ } } }, + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -884,6 +1678,30 @@ "assert-plus": "^1.0.0" } }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -899,6 +1717,12 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -923,18 +1747,71 @@ "object-keys": "^1.0.12" } }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, + "diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "dev": true + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -944,6 +1821,15 @@ "esutils": "^2.0.2" } }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1019,6 +1905,34 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "escodegen": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", + "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "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==", + "dev": true, + "optional": true + } + } + }, "eslint": { "version": "6.7.2", "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.7.2.tgz", @@ -1333,6 +2247,12 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "exec-sh": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", + "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", + "dev": true + }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -1348,12 +2268,103 @@ "strip-eof": "^1.0.0" } }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "expect": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -1365,6 +2376,71 @@ "tmp": "^0.0.33" } }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -1395,6 +2471,15 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, "figures": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", @@ -1413,6 +2498,36 @@ "flat-cache": "^2.0.1" } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "find-cache-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", @@ -1444,15 +2559,6 @@ "locate-path": "^3.0.0" } }, - "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } - }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -1481,6 +2587,12 @@ "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, "foreground-child": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", @@ -1520,550 +2632,1918 @@ "mime-types": "^2.1.12" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": 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 - }, - "get-stdin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", - "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "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" - } - }, - "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "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.5.3", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", - "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", - "dev": true, - "requires": { - "neo-async": "^2.6.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "hasha": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", - "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "is-stream": "^1.0.1" + "map-cache": "^0.2.2" } }, - "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 - }, - "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "husky": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/husky/-/husky-3.1.0.tgz", - "integrity": "sha512-FJkPoHHB+6s4a+jwPqBudBDvYZsoQW5/HBuMSehC8qDiCe50kpcxeqFoDSlow+9I6wg47YxBoT3WxaURlrDIIQ==", + "fsevents": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", "dev": true, + "optional": true, "requires": { - "chalk": "^2.4.2", - "ci-info": "^2.0.0", - "cosmiconfig": "^5.2.1", - "execa": "^1.0.0", - "get-stdin": "^7.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.2.0", - "read-pkg": "^5.2.0", - "run-node": "^1.0.0", - "slash": "^3.0.0" + "bindings": "^1.5.0", + "nan": "^2.12.1", + "node-pre-gyp": "*" }, "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "abbrev": { + "version": "1.1.1", + "bundled": true, "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } + "optional": true }, - "locate-path": { - "version": "5.0.0", + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "3.2.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.6", + "bundled": true, + "dev": true, + "optional": 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" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.14.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.7.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.13", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": 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 + }, + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "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" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "handlebars": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hasha": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", + "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "dev": true, + "requires": { + "is-stream": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "husky": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/husky/-/husky-3.1.0.tgz", + "integrity": "sha512-FJkPoHHB+6s4a+jwPqBudBDvYZsoQW5/HBuMSehC8qDiCe50kpcxeqFoDSlow+9I6wg47YxBoT3WxaURlrDIIQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "ci-info": "^2.0.0", + "cosmiconfig": "^5.2.1", + "execa": "^1.0.0", + "get-stdin": "^7.0.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^4.2.0", + "please-upgrade-node": "^3.2.0", + "read-pkg": "^5.2.0", + "run-node": "^1.0.0", + "slash": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { - "p-locate": "^4.1.0" + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "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 + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + } + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "dependencies": { + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "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.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "inquirer": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", + "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "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 + }, + "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 + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } } }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "p-limit": "^2.2.0" + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } } + } + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true }, - "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", - "lines-and-columns": "^1.1.6" + "is-buffer": "^1.1.5" } - }, - "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==", + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "find-up": "^4.0.0" + "is-buffer": "^1.1.5" } + } + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "is-buffer": "^1.1.5" } - }, - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true } } }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "has-symbols": "^1.0.1" } }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "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 + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", "dev": true, "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "append-transform": "^1.0.0" } }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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 + } + } }, - "inquirer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", - "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", "dev": true, "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^2.4.2", - "cli-cursor": "^3.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.15", - "mute-stream": "0.0.8", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^4.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" + "handlebars": "^4.1.2" + } + }, + "jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", + "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", + "dev": true, + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.9.0" }, "dependencies": { "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "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==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "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 + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true + "jest-cli": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", + "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", + "dev": true, + "requires": { + "@jest/core": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^13.3.0" + } }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true + "jest-changed-files": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + } }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" + } }, - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", - "dev": true + "jest-diff": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true + "jest-docblock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", + "dev": true, + "requires": { + "detect-newline": "^2.1.0" + } }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true + "jest-each": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" + } }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true + "jest-environment-jsdom": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", + "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0", + "jsdom": "^11.5.1" + } }, - "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 + "jest-environment-node": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", + "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0" + } }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", "dev": true }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "jest-haste-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", "dev": true, "requires": { - "is-extglob": "^2.1.1" + "@jest/types": "^24.9.0", + "anymatch": "^2.0.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.7", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3", + "walker": "^1.0.7" } }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true + "jest-jasmine2": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", + "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.9.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0", + "throat": "^4.0.0" + } }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "jest-leak-detector": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", + "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", "dev": true, "requires": { - "has": "^1.0.1" + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" } }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "jest-matcher-utils": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "jest-mock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0" + } }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "jest-pnp-resolver": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", + "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", "dev": true }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", "dev": true }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "jest-resolve": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true + "jest-resolve-dependencies": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", + "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.9.0" + } }, - "istanbul-lib-hook": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", - "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "jest-runner": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", + "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", "dev": true, "requires": { - "append-transform": "^1.0.0" + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-leak-detector": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" } }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "jest-runtime": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", + "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", "dev": true, "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^13.3.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "jest-serializer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", + "dev": true + }, + "jest-snapshot": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", + "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "expect": "^24.9.0", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.9.0", + "semver": "^6.2.0" }, "dependencies": { "semver": { @@ -2074,65 +4554,96 @@ } } }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "jest-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", "dev": true, "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" }, "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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==", + "dev": true } } }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", "dev": true, "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + } + }, + "jest-watcher": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", + "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.9.0", + "string-length": "^2.0.0" }, "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true } } }, - "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", "dev": true, "requires": { - "handlebars": "^4.1.2" + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "js-tokens": { @@ -2157,6 +4668,48 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + } + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -2193,6 +4746,23 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -2211,6 +4781,18 @@ "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", "dev": true }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, "lcid": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", @@ -2226,6 +4808,18 @@ "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", "dev": true }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -2316,12 +4910,24 @@ "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", "integrity": "sha1-I+89lTVWUgOmbO/VuDD4SJEa+0g=" }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, "lodash.partition": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.partition/-/lodash.partition-4.6.0.tgz", "integrity": "sha1-o45GtzRp4EILDaEhLmbUFL42S6Q=", "dev": true }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, "lodash.unescape": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", @@ -2339,21 +4945,21 @@ "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", "dev": true }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, "lolex": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", "dev": true }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -2388,6 +4994,15 @@ "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", "dev": true }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, "map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", @@ -2397,6 +5012,21 @@ "p-defer": "^1.0.0" } }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, "mem": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", @@ -2433,6 +5063,33 @@ } } }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, "mime-db": { "version": "1.42.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", @@ -2469,147 +5126,36 @@ "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=", + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { - "minimist": "0.0.8" - } - }, - "mocha": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz", - "integrity": "sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==", - "dev": true, - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.0", - "yargs-parser": "13.1.1", - "yargs-unparser": "1.6.0" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "is-plain-object": "^2.0.4" } } } }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -2622,6 +5168,32 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -2659,22 +5231,29 @@ "path-to-regexp": "^1.7.0" } }, - "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-notifier": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", "dev": true, "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" } }, "normalize-package-data": { @@ -2689,6 +5268,15 @@ "validate-npm-package-license": "^3.0.1" } }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -2704,6 +5292,12 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, "nyc": { "version": "14.1.1", "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", @@ -2743,6 +5337,43 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "object-inspect": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", @@ -2755,6 +5386,15 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", @@ -2810,6 +5450,15 @@ "es-abstract": "^1.5.1" } }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "object.values": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", @@ -2907,6 +5556,15 @@ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -2937,6 +5595,12 @@ "p-limit": "^2.0.0" } }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -2973,6 +5637,18 @@ "error-ex": "^1.2.0" } }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -3035,6 +5711,15 @@ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, "pkg-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", @@ -3098,6 +5783,18 @@ "semver-compare": "^1.0.0" } }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -3119,12 +5816,42 @@ "fast-diff": "^1.1.2" } }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "prompts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.0.tgz", + "integrity": "sha512-NfbbPPg/74fT7wk2XYQ7hAIp9zJyZp5Fu19iRbORqqy1BhtrkZ0fPafBU+7bmn8ie69DpT0R6QpJIN2oisYjJg==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.3" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -3159,6 +5886,12 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, + "react-is": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", + "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", + "dev": true + }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -3225,6 +5958,25 @@ } } }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, "regexpp": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", @@ -3240,6 +5992,24 @@ "es6-error": "^4.0.1" } }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -3268,6 +6038,34 @@ "uuid": "^3.3.2" } }, + "request-promise-core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } + } + }, + "request-promise-native": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "dev": true, + "requires": { + "request-promise-core": "1.1.3", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -3289,12 +6087,35 @@ "path-parse": "^1.0.6" } }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -3305,6 +6126,12 @@ "signal-exit": "^3.0.2" } }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -3314,6 +6141,12 @@ "glob": "^7.1.3" } }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true + }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", @@ -3344,12 +6177,52 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", @@ -3368,6 +6241,29 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -3383,6 +6279,12 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -3415,6 +6317,12 @@ } } }, + "sisteransi": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.4.tgz", + "integrity": "sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig==", + "dev": true + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -3432,12 +6340,153 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, "source-map-support": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", @@ -3456,6 +6505,12 @@ } } }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, "spawn-wrap": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", @@ -3502,6 +6557,15 @@ "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", "dev": true }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -3525,6 +6589,49 @@ "tweetnacl": "~0.14.0" } }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + } + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -3576,21 +6683,12 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -3715,6 +6813,12 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -3730,12 +6834,66 @@ "os-tmpdir": "~1.0.2" } }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -3754,6 +6912,50 @@ } } }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "ts-jest": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-24.2.0.tgz", + "integrity": "sha512-Yc+HLyldlIC9iIK8xEN7tV960Or56N49MDP7hubCZUeI7EbIOTsas6rXCMB4kQjLACJ7eDOF4xWEO5qumpKsag==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "buffer-from": "1.x", + "fast-json-stable-stringify": "2.x", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "mkdirp": "0.x", + "resolve": "1.x", + "semver": "^5.5", + "yargs-parser": "10.x" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, "ts-node": { "version": "8.5.4", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.4.tgz", @@ -3852,6 +7054,58 @@ } } }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -3861,6 +7115,28 @@ "punycode": "^2.1.0" } }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", @@ -3894,6 +7170,56 @@ "extsprintf": "^1.2.0" } }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -3909,15 +7235,6 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -3997,6 +7314,21 @@ "signal-exit": "^3.0.2" } }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", @@ -4066,101 +7398,6 @@ "decamelize": "^1.2.0" } }, - "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 71bd2360..b0558dfe 100644 --- a/package.json +++ b/package.json @@ -6,13 +6,14 @@ "types": "./build/src/index.d.ts", "scripts": { "prepare": "npm run build", - "build": "tsc", - "mocha": "nyc mocha", - "test": "npm run lint && npm run mocha", - "lint": "eslint --ext=.js,.ts src/ test/ examples/", - "lint-fix": "eslint --fix --ext=.js,.ts src/ test/ examples/", + "build": "npm run clean && tsc", + "clean": "rm -rf ./build", + "jest": "jest --coverage", + "test": "npm run lint && npm run jest", + "lint": "eslint --ext=.js,.ts src/ __tests__/ examples/", + "lint-fix": "eslint --fix --ext=.js,.ts src/ __tests__/ examples/", "benchmark": "node ./benchmark", - "coverage": "nyc report --reporter=text-lcov | coveralls" + "coverage": "jest --coverage --coverageReporters=text-lcov | coveralls" }, "files": [ "build/src/**" @@ -34,7 +35,9 @@ "license": "MIT", "devDependencies": { "@istanbuljs/nyc-config-typescript": "^0.1.3", + "@types/jest": "^24.0.24", "@types/lodash.escaperegexp": "^4.1.6", + "@types/lodash.groupby": "^4.6.6", "@types/lodash.isboolean": "^3.0.6", "@types/lodash.isequal": "^4.5.5", "@types/lodash.isfunction": "^3.0.6", @@ -43,8 +46,6 @@ "@types/lodash.isundefined": "^3.0.6", "@types/lodash.partition": "^4.6.6", "@types/lodash.uniq": "^4.5.6", - "@types/lodash.groupby": "^4.6.6", - "@types/mocha": "^5.2.7", "@types/sinon": "^7.5.1", "@typescript-eslint/eslint-plugin": "^2.11.0", "@typescript-eslint/parser": "^2.11.0", @@ -55,12 +56,13 @@ "eslint-plugin-import": "^2.19.1", "eslint-plugin-prettier": "^3.1.1", "husky": "^3.1.0", + "jest": "^24.9.0", "lodash.partition": "^4.6.0", - "mocha": "^6.2.2", "nyc": "^14.1.1", "prettier": "^1.19.1", "sinon": "^7.5.0", "source-map-support": "^0.5.16", + "ts-jest": "^24.2.0", "ts-node": "^8.5.4", "typescript": "^3.7.3" }, diff --git a/test/formatter/CsvFormatterStream.test.ts b/test/formatter/CsvFormatterStream.test.ts deleted file mode 100644 index 79c1f4c8..00000000 --- a/test/formatter/CsvFormatterStream.test.ts +++ /dev/null @@ -1,923 +0,0 @@ -import * as assert from 'assert'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as csv from '../../src'; -import { FormatterOptions, CsvFormatterStream } from '../../src/formatter'; -import RecordingStream from '../RecordingStream'; - -describe('CsvFormatterStream', () => { - const objectRows = [ - { a: 'a1', b: 'b1' }, - { a: 'a2', b: 'b2' }, - ]; - - const arrayRows = [ - ['a', 'b'], - ['a1', 'b1'], - ['a2', 'b2'], - ]; - - const multiDimensionalRows = [ - [ - ['a', 'a1'], - ['b', 'b1'], - ], - [ - ['a', 'a2'], - ['b', 'b2'], - ], - ]; - - const pipeToRecordingStream = (formatter: CsvFormatterStream, rows: csv.FormatterRow[]) => - new Promise((res, rej) => { - const rs = new RecordingStream(); - formatter - .on('error', e => rej(e)) - .pipe(rs) - .on('finish', () => { - res(rs.data); - }); - rows.forEach(row => formatter.write(row)); - formatter.end(); - }); - - const formatRows = (rows: csv.FormatterRow[], options: csv.FormatterOptionsArgs = {}) => - pipeToRecordingStream(csv.format(options), rows); - - it('should write an array of arrays', () => - formatRows(arrayRows, { headers: true }).then(written => - assert.deepStrictEqual(written, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should write an array of objects', () => - formatRows(objectRows, { headers: true }).then(written => - assert.deepStrictEqual(written, ['a,b', '\na1,b1', '\na2,b2']), - )); - - describe('transform option', () => { - it('should support transforming an array of arrays', () => - formatRows(arrayRows, { - headers: true, - transform(row: csv.FormatterRow) { - return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); - }, - }).then(written => assert.deepStrictEqual(written, ['A,B', '\nA1,B1', '\nA2,B2']))); - - it('should support transforming an array of multi-dimensional arrays', () => - formatRows(multiDimensionalRows, { - headers: true, - transform(row: csv.FormatterRow) { - return (row as csv.FormatterRowHashArray).map(entry => [entry[0], entry[1].toUpperCase()]); - }, - }).then(written => { - assert.deepStrictEqual(written, ['a,b', '\nA1,B1', '\nA2,B2']); - })); - - it('should support transforming an array of objects', () => - formatRows(objectRows, { - headers: true, - transform(row: csv.FormatterRowMap) { - return { A: row.a, B: row.b }; - }, - }).then(written => assert.deepStrictEqual(written, ['A,B', '\na1,b1', '\na2,b2']))); - }); - describe('#transform', () => { - it('should support transforming an array of arrays', () => { - const formatter = new CsvFormatterStream( - new FormatterOptions({ headers: true }), - ).transform((row: csv.FormatterRow) => (row as csv.FormatterRowArray).map(entry => entry.toUpperCase())); - return pipeToRecordingStream(formatter, arrayRows).then(written => - assert.deepStrictEqual(written, ['A,B', '\nA1,B1', '\nA2,B2']), - ); - }); - - it('should support transforming an array of multi-dimensional arrays', () => { - const formatter = new CsvFormatterStream(new FormatterOptions({ headers: true })).transform( - (row: csv.FormatterRow): csv.FormatterRow => - (row as csv.FormatterRowHashArray).map(entry => [entry[0], entry[1].toUpperCase()]), - ); - return pipeToRecordingStream(formatter, multiDimensionalRows).then(written => - assert.deepStrictEqual(written, ['a,b', '\nA1,B1', '\nA2,B2']), - ); - }); - - it('should support transforming an array of objects', () => { - const formatter = new CsvFormatterStream(new FormatterOptions({ headers: true })).transform( - (row: csv.FormatterRow): csv.FormatterRow => ({ - A: (row as csv.FormatterRowMap).a, - B: (row as csv.FormatterRowMap).b, - }), - ); - return pipeToRecordingStream(formatter, objectRows).then(written => - assert.deepStrictEqual(written, ['A,B', '\na1,b1', '\na2,b2']), - ); - }); - - it('should error if the transform fails', () => { - const formatter = new CsvFormatterStream(new FormatterOptions({ headers: true })).transform( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - (row: csv.FormatterRow): csv.FormatterRow => { - throw new Error('Expected error'); - }, - ); - return pipeToRecordingStream(formatter, objectRows).then( - () => assert.fail('Should have failed'), - err => { - assert.strictEqual(err.message, 'Expected error'); - }, - ); - }); - }); - - describe('rowDelimiter option', () => { - it('should support specifying an alternate row delimiter', () => - formatRows(objectRows, { - headers: true, - rowDelimiter: '\r\n', - }).then(written => assert.deepStrictEqual(written, ['a,b', '\r\na1,b1', '\r\na2,b2']))); - - it('should escape values that contain the alternate row delimiter', () => { - const rows = [ - { a: 'a\n1', b: 'b1' }, - { a: 'a\n2', b: 'b2' }, - ]; - return formatRows(rows, { headers: true, rowDelimiter: '\n' }).then(written => - assert.deepStrictEqual(written, ['a,b', '\n"a\n1",b1', '\n"a\n2",b2']), - ); - }); - }); - - describe('quoteColumns option', () => { - describe('quote all columns and headers if quoteColumns is true and quoteHeaders is false', () => { - it('should work with objects', () => - formatRows(objectRows, { headers: true, quoteColumns: true }).then(written => - assert.deepStrictEqual(written, ['"a","b"', '\n"a1","b1"', '\n"a2","b2"']), - )); - - it('should work with arrays', () => - formatRows(arrayRows, { headers: true, quoteColumns: true }).then(written => - assert.deepStrictEqual(written, ['"a","b"', '\n"a1","b1"', '\n"a2","b2"']), - )); - - it('should work with multi-dimenional arrays', () => - formatRows(multiDimensionalRows, { headers: true, quoteColumns: true }).then(written => - assert.deepStrictEqual(written, ['"a","b"', '\n"a1","b1"', '\n"a2","b2"']), - )); - }); - - describe('quote headers if quoteHeaders is true and not columns is quoteColumns is undefined', () => { - it('should work with objects', () => - formatRows(objectRows, { headers: true, quoteHeaders: true }).then(written => - assert.deepStrictEqual(written, ['"a","b"', '\na1,b1', '\na2,b2']), - )); - - it('should work with arrays', () => - formatRows(arrayRows, { headers: true, quoteHeaders: true }).then(written => - assert.deepStrictEqual(written, ['"a","b"', '\na1,b1', '\na2,b2']), - )); - - it('should work with multi-dimensional arrays', () => - formatRows(multiDimensionalRows, { headers: true, quoteHeaders: true }).then(written => - assert.deepStrictEqual(written, ['"a","b"', '\na1,b1', '\na2,b2']), - )); - }); - - describe('quote columns if quoteColumns is true and not quote headers if quoteHeaders is false', () => { - it('should work with objects', () => - formatRows(objectRows, { headers: true, quoteHeaders: false, quoteColumns: true }).then(written => - assert.deepStrictEqual(written, ['a,b', '\n"a1","b1"', '\n"a2","b2"']), - )); - - it('should work with arrays', () => - formatRows(arrayRows, { headers: true, quoteHeaders: false, quoteColumns: true }).then(written => - assert.deepStrictEqual(written, ['a,b', '\n"a1","b1"', '\n"a2","b2"']), - )); - - it('should work with multi-dimensional arrays', () => - formatRows(multiDimensionalRows, { - headers: true, - quoteHeaders: false, - quoteColumns: true, - }).then(written => assert.deepStrictEqual(written, ['a,b', '\n"a1","b1"', '\n"a2","b2"']))); - }); - - describe('if quoteColumns object it should only quote the specified column and header', () => { - it('should work with objects', () => - formatRows(objectRows, { headers: true, quoteColumns: { a: true } }).then(written => - assert.deepStrictEqual(written, ['"a",b', '\n"a1",b1', '\n"a2",b2']), - )); - - it('should work with arrays', () => - formatRows(arrayRows, { headers: true, quoteColumns: { a: true } }).then(written => - assert.deepStrictEqual(written, ['"a",b', '\n"a1",b1', '\n"a2",b2']), - )); - - it('should work with multi dimensional arrays', () => - formatRows(multiDimensionalRows, { headers: true, quoteColumns: { a: true } }).then(written => - assert.deepStrictEqual(written, ['"a",b', '\n"a1",b1', '\n"a2",b2']), - )); - }); - - describe('if quoteColumns object and quoteHeaders is false it should only quote the specified column and not the header', () => { - it('should work with objects', () => - formatRows(multiDimensionalRows, { - headers: true, - quoteHeaders: false, - quoteColumns: { a: true }, - }).then(written => assert.deepStrictEqual(written, ['a,b', '\n"a1",b1', '\n"a2",b2']))); - - it('should work with arrays', () => - formatRows(arrayRows, { headers: true, quoteHeaders: false, quoteColumns: { a: true } }).then(written => - assert.deepStrictEqual(written, ['a,b', '\n"a1",b1', '\n"a2",b2']), - )); - - it('should work with multi-dimensional arrays', () => - formatRows(multiDimensionalRows, { - headers: true, - quoteHeaders: false, - quoteColumns: { a: true }, - }).then(written => assert.deepStrictEqual(written, ['a,b', '\n"a1",b1', '\n"a2",b2']))); - }); - - describe('if quoteColumns is an array it should only quote the specified column index', () => { - it('should work with objects', () => - formatRows(objectRows, { headers: true, quoteColumns: [true] }).then(written => - assert.deepStrictEqual(written, ['"a",b', '\n"a1",b1', '\n"a2",b2']), - )); - - it('should work with arrays', () => - formatRows(arrayRows, { headers: true, quoteColumns: [true] }).then(written => - assert.deepStrictEqual(written, ['"a",b', '\n"a1",b1', '\n"a2",b2']), - )); - - it('should work with multi-dimensional arrays', () => - formatRows(multiDimensionalRows, { headers: true, quoteColumns: [true] }).then(written => - assert.deepStrictEqual(written, ['"a",b', '\n"a1",b1', '\n"a2",b2']), - )); - }); - - describe('if quoteColumns is false and quoteHeaders is an object it should only quote the specified header and not the column', () => { - it('should work with object', () => - formatRows(objectRows, { - headers: true, - quoteHeaders: { a: true }, - quoteColumns: false, - }).then(written => assert.deepStrictEqual(written, ['"a",b', '\na1,b1', '\na2,b2']))); - - it('should work with arrays', () => - formatRows(arrayRows, { headers: true, quoteHeaders: { a: true }, quoteColumns: false }).then(written => - assert.deepStrictEqual(written, ['"a",b', '\na1,b1', '\na2,b2']), - )); - - it('should work with multi-dimenional arrays', () => - formatRows(multiDimensionalRows, { - headers: true, - quoteHeaders: { a: true }, - quoteColumns: false, - }).then(written => assert.deepStrictEqual(written, ['"a",b', '\na1,b1', '\na2,b2']))); - }); - - describe('if quoteColumns is an object and quoteHeaders is an object it should only quote the specified header and column', () => { - it('should work with objects', () => - formatRows(objectRows, { - headers: true, - quoteHeaders: { b: true }, - quoteColumns: { a: true }, - }).then(written => assert.deepStrictEqual(written, ['a,"b"', '\n"a1",b1', '\n"a2",b2']))); - - it('should work with arrays', () => - formatRows(arrayRows, { - headers: true, - quoteHeaders: { b: true }, - quoteColumns: { a: true }, - }).then(written => assert.deepStrictEqual(written, ['a,"b"', '\n"a1",b1', '\n"a2",b2']))); - - it('should work with multi-dimensional arrays', () => - formatRows(multiDimensionalRows, { - headers: true, - quoteHeaders: { b: true }, - quoteColumns: { a: true }, - }).then(written => assert.deepStrictEqual(written, ['a,"b"', '\n"a1",b1', '\n"a2",b2']))); - }); - - describe('if quoteHeaders is an array and quoteColumns is an false it should only quote the specified header and not the column', () => { - it('should work with objects', () => - formatRows(objectRows, { - headers: true, - quoteHeaders: [false, true], - quoteColumns: false, - }).then(written => assert.deepStrictEqual(written, ['a,"b"', '\na1,b1', '\na2,b2']))); - - it('should work with arrays', () => - formatRows(arrayRows, { - headers: true, - quoteHeaders: [false, true], - quoteColumns: false, - }).then(written => assert.deepStrictEqual(written, ['a,"b"', '\na1,b1', '\na2,b2']))); - - it('should work with arrays of multi-dimensional arrays', () => - formatRows(multiDimensionalRows, { - headers: true, - quoteHeaders: [false, true], - quoteColumns: false, - }).then(written => assert.deepStrictEqual(written, ['a,"b"', '\na1,b1', '\na2,b2']))); - }); - }); - - describe('header option', () => { - it('should write an array of objects without headers', () => - formatRows(objectRows, { headers: false }).then(formatted => - assert.deepStrictEqual(formatted, ['a1,b1', '\na2,b2']), - )); - - it('should write an array of objects with headers', () => - formatRows(objectRows, { headers: true }).then(formatted => - assert.deepStrictEqual(formatted, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should write an array of arrays without headers', () => { - const rows = [ - ['a1', 'b1'], - ['a2', 'b2'], - ]; - return formatRows(rows, { headers: false }).then(formatted => - assert.deepStrictEqual(formatted, ['a1,b1', '\na2,b2']), - ); - }); - - it('should write an array of arrays with headers', () => - formatRows(arrayRows, { headers: true }).then(parsedCsv => - assert.deepStrictEqual(parsedCsv, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should write an array of multi-dimensional arrays without headers', () => - formatRows(multiDimensionalRows, { headers: false }).then(parsedCsv => - assert.deepStrictEqual(parsedCsv, ['a1,b1', '\na2,b2']), - )); - - it('should write an array of multi-dimensional arrays with headers', () => - formatRows(multiDimensionalRows, { headers: true }).then(parsedCsv => - assert.deepStrictEqual(parsedCsv, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should not write anything if headers are provided but no rows are provided', () => - formatRows([], { headers: true }).then(parsedCsv => assert.deepStrictEqual(parsedCsv, []))); - - describe('alwaysWriteHeaders option', () => { - it('should write the headers if rows are not provided', () => { - const headers = ['h1', 'h2']; - return formatRows([], { headers, alwaysWriteHeaders: true }).then(parsedCsv => - assert.deepStrictEqual(parsedCsv, [headers.join(',')]), - ); - }); - - it('should write the headers ones if rows are provided', () => { - const headers = ['h1', 'h2']; - return formatRows(arrayRows, { headers, alwaysWriteHeaders: true }).then(parsedCsv => - assert.deepStrictEqual(parsedCsv, [headers.join(','), '\na,b', '\na1,b1', '\na2,b2']), - ); - }); - - it('should fail if no headers are provided', () => { - return formatRows(arrayRows, { alwaysWriteHeaders: true }).catch(e => - assert.strictEqual( - e.message, - '`alwaysWriteHeaders` option is set to true but `headers` option not provided.', - ), - ); - }); - - it('should write the headers and an endRowDelimiter if includeEndRowDelimiter is true', () => { - const headers = ['h1', 'h2']; - return formatRows([], { - headers, - includeEndRowDelimiter: true, - alwaysWriteHeaders: true, - }).then(parsedCsv => assert.deepStrictEqual(parsedCsv, [headers.join(','), '\n'])); - }); - }); - }); - - it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => - formatRows(objectRows, { headers: true, includeEndRowDelimiter: true }).then(written => - assert.deepStrictEqual(written, ['a,b', '\na1,b1', '\na2,b2', '\n']), - )); - - it('should write a BOM character if writeBOM is true', () => - formatRows(objectRows, { headers: true, writeBOM: true }).then(written => - assert.deepStrictEqual(written, ['\ufeff', 'a,b', '\na1,b1', '\na2,b2']), - )); - - describe('.writeToString', () => { - it('should write an array of arrays', () => - csv - .writeToString(arrayRows, { headers: true }) - .then(formatted => assert.strictEqual(formatted, 'a,b\na1,b1\na2,b2'))); - - it('should support transforming an array of arrays', () => - csv - .writeToString(arrayRows, { - headers: true, - transform(row: csv.FormatterRow): csv.FormatterRow { - return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); - }, - }) - .then(formatted => assert.strictEqual(formatted, 'A,B\nA1,B1\nA2,B2'))); - - it('should write an array of multi-dimensional arrays', () => - csv - .writeToString(multiDimensionalRows, { headers: true }) - .then(formatted => assert.strictEqual(formatted, 'a,b\na1,b1\na2,b2'))); - - it('should support transforming an array of multi-dimensional arrays', () => - csv - .writeToString(multiDimensionalRows, { - headers: true, - transform(row: csv.FormatterRow) { - return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); - }, - }) - .then(formatted => assert.strictEqual(formatted, 'a,b\nA1,B1\nA2,B2'))); - - it('should write an array of objects', () => - csv - .writeToString(objectRows, { - headers: true, - transform(row: csv.FormatterRowMap) { - return { - A: row.a, - B: row.b, - }; - }, - }) - .then(formatted => assert.strictEqual(formatted, 'A,B\na1,b1\na2,b2'))); - - describe('header option', () => { - it('should write an array of objects without headers', () => - csv - .writeToString(objectRows, { headers: false }) - .then(formatted => assert.strictEqual(formatted, 'a1,b1\na2,b2'))); - - it('should write an array of objects with headers', () => - csv - .writeToString(objectRows, { headers: true }) - .then(formatted => assert.strictEqual(formatted, 'a,b\na1,b1\na2,b2'))); - - it('should write an array of arrays without headers', () => { - const rows = [ - ['a1', 'b1'], - ['a2', 'b2'], - ]; - return csv - .writeToString(rows, { headers: false }) - .then(formatted => assert.strictEqual(formatted, 'a1,b1\na2,b2')); - }); - - it('should write an array of arrays with headers', () => - csv - .writeToString(arrayRows, { headers: true }) - .then(parsedCsv => assert.strictEqual(parsedCsv, 'a,b\na1,b1\na2,b2'))); - - it('should write an array of multi-dimensional arrays without headers', () => - csv - .writeToString(multiDimensionalRows, { headers: false }) - .then(parsedCsv => assert.strictEqual(parsedCsv, 'a1,b1\na2,b2'))); - - it('should write an array of multi-dimensional arrays with headers', () => - csv - .writeToString(multiDimensionalRows, { headers: true }) - .then(parsedCsv => assert.strictEqual(parsedCsv, 'a,b\na1,b1\na2,b2'))); - }); - - describe('rowDelimiter option', () => { - it('should support specifying an alternate row delimiter', () => - csv - .writeToString(objectRows, { headers: true, rowDelimiter: '\r\n' }) - .then(parsedCsv => assert.strictEqual(parsedCsv, 'a,b\r\na1,b1\r\na2,b2'))); - it('should escape values that contain the alternate row delimiter', () => { - const rows = [ - { a: 'a\t1', b: 'b1' }, - { a: 'a\t2', b: 'b2' }, - ]; - return csv - .writeToString(rows, { headers: true, rowDelimiter: '\t' }) - .then(parsedCsv => assert.strictEqual(parsedCsv, 'a,b\t"a\t1",b1\t"a\t2",b2')); - }); - }); - - it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => - csv - .writeToString(objectRows, { headers: true, includeEndRowDelimiter: true }) - .then(parsedCsv => assert.strictEqual(parsedCsv, 'a,b\na1,b1\na2,b2\n'))); - }); - - describe('.writeToBuffer', () => { - it('should write an array of arrays', () => - csv - .writeToBuffer(arrayRows, { headers: true }) - .then(formatted => assert.deepStrictEqual(formatted, Buffer.from('a,b\na1,b1\na2,b2')))); - - it('should support transforming an array of arrays', () => - csv - .writeToBuffer(arrayRows, { - headers: true, - transform(row: csv.FormatterRow): csv.FormatterRow { - return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); - }, - }) - .then(formatted => assert.deepStrictEqual(formatted, Buffer.from('A,B\nA1,B1\nA2,B2')))); - - it('should write an array of multi-dimensional arrays', () => - csv - .writeToBuffer(multiDimensionalRows, { headers: true }) - .then(formatted => assert.deepStrictEqual(formatted, Buffer.from('a,b\na1,b1\na2,b2')))); - - it('should support transforming an array of multi-dimensional arrays', () => - csv - .writeToBuffer(multiDimensionalRows, { - headers: true, - transform(row: csv.FormatterRow) { - return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); - }, - }) - .then(formatted => assert.deepStrictEqual(formatted, Buffer.from('a,b\nA1,B1\nA2,B2')))); - - it('should write an array of objects', () => - csv - .writeToBuffer(objectRows, { - headers: true, - transform(row: csv.FormatterRowMap): csv.FormatterRow { - return { - A: row.a, - B: row.b, - }; - }, - }) - .then(formatted => assert.deepStrictEqual(formatted, Buffer.from('A,B\na1,b1\na2,b2')))); - - describe('header option', () => { - it('should write an array of objects without headers', () => - csv - .writeToBuffer(objectRows, { headers: false }) - .then(formatted => assert.deepStrictEqual(formatted, Buffer.from('a1,b1\na2,b2')))); - - it('should write an array of objects with headers', () => - csv - .writeToBuffer(objectRows, { headers: true }) - .then(formatted => assert.deepStrictEqual(formatted, Buffer.from('a,b\na1,b1\na2,b2')))); - - it('should write an array of arrays without headers', () => { - const rows = [ - ['a1', 'b1'], - ['a2', 'b2'], - ]; - return csv - .writeToBuffer(rows, { headers: false }) - .then(formatted => assert.deepStrictEqual(formatted, Buffer.from('a1,b1\na2,b2'))); - }); - - it('should write an array of arrays with headers', () => - csv - .writeToBuffer(arrayRows, { headers: true }) - .then(parsedCsv => assert.deepStrictEqual(parsedCsv, Buffer.from('a,b\na1,b1\na2,b2')))); - - it('should write an array of multi-dimensional arrays without headers', () => - csv - .writeToBuffer(multiDimensionalRows, { headers: false }) - .then(parsedCsv => assert.deepStrictEqual(parsedCsv, Buffer.from('a1,b1\na2,b2')))); - - it('should write an array of multi-dimensional arrays with headers', () => - csv - .writeToBuffer(multiDimensionalRows, { headers: true }) - .then(parsedCsv => assert.deepStrictEqual(parsedCsv, Buffer.from('a,b\na1,b1\na2,b2')))); - }); - - describe('rowDelimiter option', () => { - it('should support specifying an alternate row delimiter', () => - csv - .writeToBuffer(objectRows, { headers: true, rowDelimiter: '\r\n' }) - .then(parsedCsv => assert.deepStrictEqual(parsedCsv, Buffer.from('a,b\r\na1,b1\r\na2,b2')))); - it('should escape values that contain the alternate row delimiter', () => { - const rows = [ - { a: 'a\t1', b: 'b1' }, - { a: 'a\t2', b: 'b2' }, - ]; - return csv - .writeToBuffer(rows, { headers: true, rowDelimiter: '\t' }) - .then(parsedCsv => assert.deepStrictEqual(parsedCsv, Buffer.from('a,b\t"a\t1",b1\t"a\t2",b2'))); - }); - }); - - it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => - csv - .writeToBuffer(objectRows, { headers: true, includeEndRowDelimiter: true }) - .then(parsedCsv => assert.deepStrictEqual(parsedCsv, Buffer.from('a,b\na1,b1\na2,b2\n')))); - }); - - describe('.write', () => { - const writeToRecordingStream = (rows: csv.FormatterRow[], options = {}) => - new Promise((res, rej) => { - const rs = new RecordingStream(); - csv.write(rows, options) - .on('error', rej) - .pipe(rs) - .on('finish', () => { - res(rs.data); - }); - }); - - it('should write an array of arrays', () => - writeToRecordingStream(arrayRows, { headers: true }).then(data => - assert.deepStrictEqual(data, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should support transforming an array of arrays', () => - writeToRecordingStream(arrayRows, { - headers: true, - transform(row: csv.FormatterRow) { - return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); - }, - }).then(data => assert.deepStrictEqual(data, ['A,B', '\nA1,B1', '\nA2,B2']))); - - it('should write an array of multi-dimensional arrays', () => - writeToRecordingStream(multiDimensionalRows, { headers: true }).then(data => - assert.deepStrictEqual(data, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should support transforming an array of multi-dimensional arrays', () => - writeToRecordingStream(multiDimensionalRows, { - headers: true, - transform(row: csv.FormatterRow) { - return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); - }, - }).then(data => assert.deepStrictEqual(data, ['a,b', '\nA1,B1', '\nA2,B2']))); - - it('should write an array of objects', () => - writeToRecordingStream(objectRows, { headers: true }).then(data => - assert.deepStrictEqual(data, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should support transforming an array of objects', () => - writeToRecordingStream(objectRows, { - headers: true, - transform(row: csv.FormatterRowMap) { - return { - A: row.a, - B: row.b, - }; - }, - }).then(data => assert.deepStrictEqual(data, ['A,B', '\na1,b1', '\na2,b2']))); - - describe('rowDelimiter option', () => { - it('should support specifying an alternate row delimiter', () => - writeToRecordingStream(objectRows, { headers: true, rowDelimiter: '\r\n' }).then(data => - assert.deepStrictEqual(data, ['a,b', '\r\na1,b1', '\r\na2,b2']), - )); - - it('should escape values that contain the alternate row delimiter', () => { - const rows = [ - { a: 'a\n1', b: 'b1' }, - { a: 'a\n2', b: 'b2' }, - ]; - return writeToRecordingStream(rows, { headers: true, rowDelimiter: '\n' }).then(data => - assert.deepStrictEqual(data, ['a,b', '\n"a\n1",b1', '\n"a\n2",b2']), - ); - }); - }); - - it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => - writeToRecordingStream(objectRows, { headers: true, includeEndRowDelimiter: true }).then(data => - assert.deepStrictEqual(data, ['a,b', '\na1,b1', '\na2,b2', '\n']), - )); - }); - - describe('.writeToPath', () => { - const writeToPath = (rows: csv.FormatterRow[], options = {}) => - new Promise((res, rej) => { - const csvPath = path.resolve(__dirname, 'assets/test_output.csv'); - csv.writeToPath(csvPath, rows, options) - .on('error', rej) - .on('finish', () => { - const content = fs.readFileSync(csvPath); - fs.unlinkSync(csvPath); - res(content); - }); - }); - - it('should write an array of arrays', () => - writeToPath(arrayRows, { headers: true }).then(content => - assert.deepStrictEqual(content, Buffer.from('a,b\na1,b1\na2,b2')), - )); - - it('should write an array of objects', () => - writeToPath(objectRows, { headers: true }).then(content => - assert.deepStrictEqual(content, Buffer.from('a,b\na1,b1\na2,b2')), - )); - - it('should write an array of multi-dimensional arrays', () => - writeToPath(multiDimensionalRows, { headers: true }).then(content => - assert.deepStrictEqual(content, Buffer.from('a,b\na1,b1\na2,b2')), - )); - - it('should support transforming an array of arrays', () => - writeToPath(arrayRows, { - headers: true, - transform(row: csv.FormatterRow) { - return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); - }, - }).then(content => assert.deepStrictEqual(content, Buffer.from('A,B\nA1,B1\nA2,B2')))); - - it('should transforming an array of objects', () => - writeToPath(objectRows, { - headers: true, - transform(row: csv.FormatterRowMap) { - return { - A: row.a, - B: row.b, - }; - }, - }).then(content => assert.deepStrictEqual(content, Buffer.from('A,B\na1,b1\na2,b2')))); - - it('should transforming an array of multi-dimensional array', () => - writeToPath(multiDimensionalRows, { - headers: true, - transform(row: csv.FormatterRow) { - return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); - }, - }).then(content => assert.deepStrictEqual(content, Buffer.from('a,b\nA1,B1\nA2,B2')))); - - describe('rowDelimiter option', () => { - it('should support specifying an alternate row delimiter', () => - writeToPath(objectRows, { headers: true, rowDelimiter: '\r\n' }).then(content => - assert.deepStrictEqual(content, Buffer.from('a,b\r\na1,b1\r\na2,b2')), - )); - - it('should escape values that contain the alternate row delimiter', () => { - const rows = [ - { a: 'a\r\n1', b: 'b1' }, - { a: 'a\r\n2', b: 'b2' }, - ]; - return writeToPath(rows, { headers: true, rowDelimiter: '\r\n' }).then(content => - assert.deepStrictEqual(content, Buffer.from('a,b\r\n"a\r\n1",b1\r\n"a\r\n2",b2')), - ); - }); - }); - - it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => - writeToPath(objectRows, { headers: true, includeEndRowDelimiter: true }).then(content => - assert.deepStrictEqual(content, Buffer.from('a,b\na1,b1\na2,b2\n')), - )); - }); - - describe('.write', () => { - const writeToRecordingStream = (rows: csv.FormatterRow[], options = {}) => - new Promise((res, rej) => { - const rs = new RecordingStream(); - csv.write(rows, options) - .on('error', rej) - .pipe(rs) - .on('finish', () => { - res(rs.data); - }); - }); - - it('should write an array of arrays', () => - writeToRecordingStream(arrayRows, { headers: true }).then(data => - assert.deepStrictEqual(data, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should support transforming an array of arrays', () => - writeToRecordingStream(arrayRows, { - headers: true, - transform(row: csv.FormatterRow) { - return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); - }, - }).then(data => assert.deepStrictEqual(data, ['A,B', '\nA1,B1', '\nA2,B2']))); - - it('should write an array of multi-dimensional arrays', () => - writeToRecordingStream(multiDimensionalRows, { headers: true }).then(data => - assert.deepStrictEqual(data, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should support transforming an array of multi-dimensional arrays', () => - writeToRecordingStream(multiDimensionalRows, { - headers: true, - transform(row: csv.FormatterRow) { - return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); - }, - }).then(data => assert.deepStrictEqual(data, ['a,b', '\nA1,B1', '\nA2,B2']))); - - it('should write an array of objects', () => - writeToRecordingStream(objectRows, { headers: true }).then(data => - assert.deepStrictEqual(data, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should support transforming an array of objects', () => - writeToRecordingStream(objectRows, { - headers: true, - transform(row: csv.FormatterRowMap) { - return { - A: row.a, - B: row.b, - }; - }, - }).then(data => assert.deepStrictEqual(data, ['A,B', '\na1,b1', '\na2,b2']))); - - describe('rowDelimiter option', () => { - it('should support specifying an alternate row delimiter', () => - writeToRecordingStream(objectRows, { headers: true, rowDelimiter: '\r\n' }).then(data => - assert.deepStrictEqual(data, ['a,b', '\r\na1,b1', '\r\na2,b2']), - )); - - it('should escape values that contain the alternate row delimiter', () => { - const rows = [ - { a: 'a\n1', b: 'b1' }, - { a: 'a\n2', b: 'b2' }, - ]; - return writeToRecordingStream(rows, { headers: true, rowDelimiter: '\n' }).then(data => - assert.deepStrictEqual(data, ['a,b', '\n"a\n1",b1', '\n"a\n2",b2']), - ); - }); - }); - - it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => - writeToRecordingStream(objectRows, { headers: true, includeEndRowDelimiter: true }).then(data => - assert.deepStrictEqual(data, ['a,b', '\na1,b1', '\na2,b2', '\n']), - )); - }); - - describe('.writeToStream', () => { - const writeToStream = (rows: csv.FormatterRow[], options: csv.FormatterOptionsArgs = {}) => - new Promise((res, rej) => { - const rs = new RecordingStream(); - csv.writeToStream(rs, rows, options); - rs.on('error', rej).on('finish', () => { - res(rs.data); - }); - }); - - it('should write an array of arrays', () => - writeToStream(arrayRows, { headers: true }).then(content => - assert.deepStrictEqual(content, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should write an array of objects', () => - writeToStream(objectRows, { headers: true }).then(content => - assert.deepStrictEqual(content, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should write an array of multi-dimensional arrays', () => - writeToStream(multiDimensionalRows, { headers: true }).then(content => - assert.deepStrictEqual(content, ['a,b', '\na1,b1', '\na2,b2']), - )); - - it('should support transforming an array of arrays', () => - writeToStream(arrayRows, { - headers: true, - transform(row: csv.FormatterRow): csv.FormatterRow { - return (row as csv.FormatterRowArray).map(entry => entry.toUpperCase()); - }, - }).then(content => assert.deepStrictEqual(content, ['A,B', '\nA1,B1', '\nA2,B2']))); - - it('should transforming an array of objects', () => - writeToStream(objectRows, { - headers: true, - transform(row: csv.FormatterRowMap): csv.FormatterRow { - return { - A: row.a, - B: row.b, - }; - }, - }).then(content => assert.deepStrictEqual(content, ['A,B', '\na1,b1', '\na2,b2']))); - - it('should transforming an array of multi-dimensional array', () => - writeToStream(multiDimensionalRows, { - headers: true, - transform(row: csv.FormatterRow): csv.FormatterRow { - return (row as csv.FormatterRowHashArray).map(col => [col[0], col[1].toUpperCase()]); - }, - }).then(content => assert.deepStrictEqual(content, ['a,b', '\nA1,B1', '\nA2,B2']))); - - describe('rowDelimiter option', () => { - it('should support specifying an alternate row delimiter', () => - writeToStream(objectRows, { headers: true, rowDelimiter: '\r\n' }).then(content => - assert.deepStrictEqual(content, ['a,b', '\r\na1,b1', '\r\na2,b2']), - )); - - it('should escape values that contain the alternate row delimiter', () => { - const rows = [ - { a: 'a\r\n1', b: 'b1' }, - { a: 'a\r\n2', b: 'b2' }, - ]; - return writeToStream(rows, { headers: true, rowDelimiter: '\r\n' }).then(content => - assert.deepStrictEqual(content, ['a,b', '\r\n"a\r\n1",b1', '\r\n"a\r\n2",b2']), - ); - }); - }); - - it('should add a final rowDelimiter if includeEndRowDelimiter is true', () => - writeToStream(objectRows, { headers: true, includeEndRowDelimiter: true }).then(content => - assert.deepStrictEqual(content, ['a,b', '\na1,b1', '\na2,b2', '\n']), - )); - }); -}); diff --git a/tsconfig.json b/tsconfig.json index ac8f6922..e7bfd658 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,6 +22,6 @@ ], "include": [ "src/**/*.ts", - "test/**/*.ts" + "__tests__/**/*.ts" ] } \ No newline at end of file