From 09cb43a7d2b10e658097a7edc9be808efe3cb28e Mon Sep 17 00:00:00 2001 From: Juanjo Diaz Date: Mon, 6 Apr 2020 20:57:43 +0300 Subject: [PATCH] Add definitions for json2csv v5.0 (#43663) --- types/json2csv/JSON2CSVAsyncParser.d.ts | 2 +- types/json2csv/JSON2CSVBase.d.ts | 56 +++++------- types/json2csv/JSON2CSVTransform.d.ts | 41 +++------ types/json2csv/index.d.ts | 7 +- types/json2csv/json2csv-tests.ts | 111 +++++++++++++----------- types/json2csv/transforms/base.d.ts | 1 + types/json2csv/transforms/flatten.d.ts | 15 ++++ types/json2csv/transforms/index.d.ts | 9 ++ types/json2csv/transforms/unwind.d.ts | 14 +++ 9 files changed, 134 insertions(+), 122 deletions(-) create mode 100644 types/json2csv/transforms/base.d.ts create mode 100644 types/json2csv/transforms/flatten.d.ts create mode 100644 types/json2csv/transforms/index.d.ts create mode 100644 types/json2csv/transforms/unwind.d.ts diff --git a/types/json2csv/JSON2CSVAsyncParser.d.ts b/types/json2csv/JSON2CSVAsyncParser.d.ts index 3b5d396542..6701435b4e 100644 --- a/types/json2csv/JSON2CSVAsyncParser.d.ts +++ b/types/json2csv/JSON2CSVAsyncParser.d.ts @@ -16,7 +16,7 @@ declare class JSON2CSVAsyncParser extends JSON2CSVBase { public toOutput(output: Writable): JSON2CSVAsyncParser; - public promise(): Promise; + public promise(returnCSV?: boolean): Promise; } export default JSON2CSVAsyncParser; diff --git a/types/json2csv/JSON2CSVBase.d.ts b/types/json2csv/JSON2CSVBase.d.ts index 51c87e1a6c..8123750a81 100644 --- a/types/json2csv/JSON2CSVBase.d.ts +++ b/types/json2csv/JSON2CSVBase.d.ts @@ -1,3 +1,5 @@ +import { Json2CsvTransform } from './transforms'; + export declare namespace json2csv { export interface FieldValueCallbackInfo { label: string; @@ -18,25 +20,26 @@ export declare namespace json2csv { label?: string; default?: string; value: string | FieldValueCallback; - stringify?: boolean; + } + + export interface NormalizedFieldInfo { + label: string; + value: FieldValueCallback; } export interface Options { fields?: Array>; ndjson?: boolean; - unwind?: string | Array; - unwindBlank?: boolean; - flatten?: boolean; - flattenSeparator?: string; defaultValue?: string; quote?: string; - doubleQuote?: string; + escapedQuote?: string; delimiter?: string; eol?: string; excelStrings?: boolean; header?: boolean; includeEmptyRows?: boolean; withBOM?: boolean; + transforms?: Array>; } } @@ -52,6 +55,15 @@ declare abstract class JSON2CSVBase { */ protected preprocessOpts(opts?: json2csv.Options) : json2csv.Options; + /** + * Check and normalize the fields configuration. + * + * @param {(string|json2csv.FieldInfo)[]} fields Fields configuration provided by the user + * or inferred from the data + * @returns {json2csv.NormalizedFieldInfo} preprocessed FieldsInfo array + */ + preprocessFieldsInfo(fields: Array>): Array>; + /** * Create the title row with all the provided fields as column headings * @@ -81,43 +93,15 @@ declare abstract class JSON2CSVBase { * @param {object} fieldInfo Details of the field to process to be a CSV cell * @returns {string} CSV string (cell) */ - protected processCell(row: T, fieldInfo: json2csv.FieldInfo) : string; - - /** - * Create the content of a specfic CSV row cell - * - * @param {object} row JSON object representing the CSV row that the cell belongs to - * @param {json2csv.FieldInfo} fieldInfo Details of the field to process to be a CSV cell - * @returns {any} Field value - */ - protected getValue(row: T, fieldInfo: json2csv.FieldInfo): any; + protected processCell(row: T, fieldInfo: json2csv.NormalizedFieldInfo) : string; /** * Create the content of a specfic CSV row cell * * @param {any} value Value to be included in a CSV cell - * @param {Boolean} stringify Details of the field to process to be a CSV cell * @returns {string} Value stringified and processed */ - protected processValue(value: any, stringify: Boolean): string; - - /** - * Performs the flattening of a data row recursively - * - * @param {object} dataRow Original JSON object - * @param {string} separator Separator to be used as the flattened field name - * @returns {object} Flattened object - */ - protected flatten(dataRow: T, separator: string): object; - - /** - * Performs the unwind recursively in specified sequence - * - * @param {object[]} dataRow Original JSON object - * @param {string[]} unwindPaths The paths as strings to be used to deconstruct the array - * @returns {Array} Array of objects containing all rows after unwind of chosen paths - */ - protected unwindData(dataRow: Array, unwindPaths: Array): Array; + protected processValue(value: any): string; } export default JSON2CSVBase; diff --git a/types/json2csv/JSON2CSVTransform.d.ts b/types/json2csv/JSON2CSVTransform.d.ts index f453ece8b1..6aece4c798 100644 --- a/types/json2csv/JSON2CSVTransform.d.ts +++ b/types/json2csv/JSON2CSVTransform.d.ts @@ -27,6 +27,15 @@ declare class JSON2CSVTransform extends Transform { // implements JSON2CSVBas */ protected preprocessOpts(opts?: json2csv.Options) : json2csv.Options; + /** + * Check and normalize the fields configuration. + * + * @param {(string|json2csv.FieldInfo)[]} fields Fields configuration provided by the user + * or inferred from the data + * @returns {json2csv.NormalizedFieldInfo} preprocessed FieldsInfo array + */ + preprocessFieldsInfo(fields: Array>): Array>; + /** * Create the title row with all the provided fields as column headings * @@ -56,43 +65,15 @@ declare class JSON2CSVTransform extends Transform { // implements JSON2CSVBas * @param {object} fieldInfo Details of the field to process to be a CSV cell * @returns {string} CSV string (cell) */ - protected processCell(row: T, fieldInfo: json2csv.FieldInfo) : string; - - /** - * Create the content of a specfic CSV row cell - * - * @param {object} row JSON object representing the CSV row that the cell belongs to - * @param {json2csv.FieldInfo} fieldInfo Details of the field to process to be a CSV cell - * @returns {any} Field value - */ - protected getValue(row: T, fieldInfo: json2csv.FieldInfo): any; + protected processCell(row: T, fieldInfo: json2csv.NormalizedFieldInfo) : string; /** * Create the content of a specfic CSV row cell * * @param {any} value Value to be included in a CSV cell - * @param {Boolean} stringify Details of the field to process to be a CSV cell * @returns {string} Value stringified and processed */ - protected processValue(value: any, stringify: Boolean): string; - - /** - * Performs the flattening of a data row recursively - * - * @param {object} dataRow Original JSON object - * @param {string} separator Separator to be used as the flattened field name - * @returns {object} Flattened object - */ - protected flatten(dataRow: T, separator: string): object; - - /** - * Performs the unwind recursively in specified sequence - * - * @param {object[]} dataRow Original JSON object - * @param {string[]} unwindPaths The paths as strings to be used to deconstruct the array - * @returns {Array} Array of objects containing all rows after unwind of chosen paths - */ - protected unwindData(dataRow: Array, unwindPaths: Array): Array; + protected processValue(value: any): string; } export default JSON2CSVTransform; diff --git a/types/json2csv/index.d.ts b/types/json2csv/index.d.ts index a8e734576b..45e24665be 100644 --- a/types/json2csv/index.d.ts +++ b/types/json2csv/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for json2csv 4.5 +// Type definitions for json2csv 5.0 // Project: https://github.com/zemirco/json2csv // Definitions by: Juanjo Diaz // Daniel Gooß @@ -8,6 +8,8 @@ import { Readable, TransformOptions } from 'stream'; +import * as builtInTransforms from './transforms'; + import { json2csv } from './JSON2CSVBase'; import JSON2CSVParser from './JSON2CSVParser'; import JSON2CSVAsyncParser from './JSON2CSVAsyncParser'; @@ -18,7 +20,8 @@ export default json2csv; export { JSON2CSVParser as Parser, JSON2CSVAsyncParser as AsyncParser, - JSON2CSVTransform as Transform + JSON2CSVTransform as Transform, + builtInTransforms as transforms }; // Convenience method to keep the API similar to version 3.X diff --git a/types/json2csv/json2csv-tests.ts b/types/json2csv/json2csv-tests.ts index 179a0df127..d5268a7262 100644 --- a/types/json2csv/json2csv-tests.ts +++ b/types/json2csv/json2csv-tests.ts @@ -1,7 +1,8 @@ import { Transform as NodeTransform } from 'stream'; import { createReadStream, createWriteStream } from 'fs'; -import json2csv, { AsyncParser, parse, Parser, parseAsync, Transform } from 'json2csv'; +import json2csv, { AsyncParser, parse, Parser, parseAsync, Transform, transforms } from 'json2csv'; +const { flatten, unwind } = transforms; let s: string; let obj: object; @@ -40,31 +41,30 @@ const opts: json2csv.Options = { // Supports label -> simple path { - label: 'some label', // (optional, column will be labeled 'path.to.something' if not defined) - value: 'path.to.something', // data.path.to.something - default: 'NULL' // default if value is not found (optional, overrides `defaultValue` for column) + label: 'some label', // (optional, column will be labeled 'path.to.something' if not defined) + value: 'path.to.something', // data.path.to.something + default: 'NULL' // default if value is not found (optional, overrides `defaultValue` for column) }, // Supports label -> derived value { - label: 'some label', // Soptional, column will be labeled with the function name or empty if the function is anonymous) - value: (row: Car, field: json2csv.FieldValueCallbackInfo) => { - if (field) { - return (row as any)[field.label].toLowerCase() || field.default; - } - }, - default: 'NULL', // default if value function returns null or undefined + label: 'some label', // Soptional, column will be labeled with the function name or empty if the function is anonymous) + value: (row: Car, field: json2csv.FieldValueCallbackInfo) => { + if (field) { + return (row as any)[field.label].toLowerCase() || field.default; + } + }, + default: 'NULL', // default if value function returns null or undefined }, // Supports label -> derived value { - value: (row: Car) => row.car + value: (row: Car) => row.car }, // Supports label -> derived value { - value: (row: Car) => `"${row.car}"`, - stringify: false // This flag signals if the resulting string should be quoted (stringified) or not (optional, default: true) + value: (row: Car) => `"${row.car}"`, }, ] }; @@ -86,15 +86,6 @@ try { console.error(err); } -// Test for Synchronous Parser with flatten and custom flattenSeparator -try { - const parser = new Parser({ ...opts, flatten: true, flattenSeparator: ' / ' }); - const csv = parser.parse({ car: '', price: 1, foo: { bar: '' } }); - console.log(csv); -} catch (err) { - console.error(err); -} - // Test convenience method "parse" try { const csv = parse(data, opts); @@ -130,6 +121,10 @@ asyncParser.fromInput(input).promise() .then(csv => console.log(csv)) .catch(err => console.error(err)); +asyncParser.fromInput(input).promise(false) + .then(() => console.log('Ready')) + .catch(err => console.error(err)); + asyncParser.fromInput(input).toOutput(output); // Test convenience method "parseAsync" with object input @@ -142,6 +137,30 @@ parseAsync(input, opts) .then(csv => console.log(csv)) .catch(err => console.error(err)); +// Test transforms +function myTransform(input: object) { + const transformed = { ...input, id: 1 }; + return transformed; +} +const tranformsOpts: json2csv.Options = { + transforms: [ + unwind(), + unwind({}), + unwind({ paths: ['path'] }), + unwind({ blankOut: true }), + unwind({ paths: ['path'], blankOut: true }), + flatten(), + flatten({}), + flatten({ objects: true }), + flatten({ arrays: true }), + flatten({ separator: '-' }), + flatten({ objects: true, arrays: true, separator: '-' }), + (input) => input, + (_) => ({ a: 1, b: 2 }), + myTransform, + ] +}; + /******************** * Internal Methods * ********************/ @@ -163,21 +182,14 @@ class ParserExt extends Parser { obj = this.preprocessRow({ str: '', num: 1, obj: {} }); s = this.processRow({}); s = this.processRow({ str: '', num: 1, obj: {} }); - s = this.processCell({}, { label: 'test', default: 'test2', value: 'field' }); - s = this.processCell({ str: '', num: 1, obj: {} }, { label: 'test', default: 'test2', value: 'field' }); - s = this.processCell({}, { label: 'test', default: 'test2', value: (row: object, field: json2csv.FieldValueCallbackInfo) => 'string' }); - s = this.processCell({ str: '', num: 1, obj: {} }, { label: 'test', default: 'test2', value: (row: object) => 'string' }); - this.getValue({}, { value: 'test' }); - this.getValue({ str: '', num: 1, obj: {} }, { value: 'test' }); - s = this.processValue(undefined, true); - s = this.processValue(null, true); - s = this.processValue(1, true); - s = this.processValue('test', true); - s = this.processValue(new Date(), true); - s = this.processValue({}, true); - s = this.processValue([], true); - const flattenedData: object = this.flatten({}, '.'); - const unwindedData: object[] = this.unwindData([], []); + s = this.processCell({}, { label: 'test', value: (row: object, field: json2csv.FieldValueCallbackInfo) => 'string' }); + s = this.processValue(undefined); + s = this.processValue(null); + s = this.processValue(1); + s = this.processValue('test'); + s = this.processValue(new Date()); + s = this.processValue({}); + s = this.processValue([]); } } @@ -197,20 +209,13 @@ class TransformExt extends Transform { obj = this.preprocessRow({ str: '', num: 1, obj: {} }); s = this.processRow({}); s = this.processRow({ str: '', num: 1, obj: {} }); - s = this.processCell({}, { label: 'test', default: 'test2', value: 'field' }); - s = this.processCell({ str: '', num: 1, obj: {} }, { label: 'test', default: 'test2', value: 'field' }); - s = this.processCell({}, { label: 'test', default: 'test2', value: (row: object, field: json2csv.FieldValueCallbackInfo) => 'string' }); - s = this.processCell({ str: '', num: 1, obj: {} }, { label: 'test', default: 'test2', value: (row: object) => 'string' }); - this.getValue({}, { value: 'test' }); - this.getValue({ str: '', num: 1, obj: {} }, { value: 'test' }); - s = this.processValue(undefined, true); - s = this.processValue(null, true); - s = this.processValue(1, true); - s = this.processValue('test', true); - s = this.processValue(new Date(), true); - s = this.processValue({}, true); - s = this.processValue([], true); - const flattenedData: object = this.flatten({}, '.'); - const unwindedData: object[] = this.unwindData([], []); + s = this.processCell({}, { label: 'test', value: (row: object, field: json2csv.FieldValueCallbackInfo) => 'string' }); + s = this.processValue(undefined); + s = this.processValue(null); + s = this.processValue(1); + s = this.processValue('test'); + s = this.processValue(new Date()); + s = this.processValue({}); + s = this.processValue([]); } } diff --git a/types/json2csv/transforms/base.d.ts b/types/json2csv/transforms/base.d.ts new file mode 100644 index 0000000000..2044ccde68 --- /dev/null +++ b/types/json2csv/transforms/base.d.ts @@ -0,0 +1 @@ +export type Json2CsvTransform = (item: T1) => T2|Array; diff --git a/types/json2csv/transforms/flatten.d.ts b/types/json2csv/transforms/flatten.d.ts new file mode 100644 index 0000000000..713edcc552 --- /dev/null +++ b/types/json2csv/transforms/flatten.d.ts @@ -0,0 +1,15 @@ +import { Json2CsvTransform } from './base'; + +export interface FlattenOptions { + objects?: boolean; + arrays?: boolean; + separator?: string; +} + +/** + * Builds a flattening transform + * + * @param {FlattenOptions} options Options to use for flattening + * @returns {Object => Object} Flattening transform + */ +export function flatten(options?: FlattenOptions): Json2CsvTransform; diff --git a/types/json2csv/transforms/index.d.ts b/types/json2csv/transforms/index.d.ts new file mode 100644 index 0000000000..69c516ad47 --- /dev/null +++ b/types/json2csv/transforms/index.d.ts @@ -0,0 +1,9 @@ +import { Json2CsvTransform } from './base'; +import { flatten } from './flatten'; +import { unwind } from './unwind'; + +export { + Json2CsvTransform, + flatten, + unwind +}; diff --git a/types/json2csv/transforms/unwind.d.ts b/types/json2csv/transforms/unwind.d.ts new file mode 100644 index 0000000000..9e47024de1 --- /dev/null +++ b/types/json2csv/transforms/unwind.d.ts @@ -0,0 +1,14 @@ +import { Json2CsvTransform } from './base'; + +export interface UnwindOptions { + paths?: Array; + blankOut?: boolean; +} + +/** + * Builds a unwinding transform + * + * @param {UnwindOptions} options Options to use for unwinding + * @returns {Object => Array} Array of objects containing all rows after unwind of chosen paths +*/ +export function unwind(options?: UnwindOptions): Json2CsvTransform>;