Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ Returns the CSV `string` or rejects with an `Error` if there was an issue.
* `false` uses the following keys:
* `['specifications']`
* Note: This may result in CSV output that does not map back exactly to the original JSON. See #102 for more information.
* `fieldTitleMap` - Object - Specify field titles that should be renamed.
* Default: `{}`
* Example: `{ "key1": "Key 1", "key2": "Key 2"}`
* `keys` - Array - Specify the keys that should be converted.
* Default: These will be auto-detected from your data by default.
* Keys can either be specified as a String representing the key path that should be converted, or as an Object of the following format:
Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const defaultJson2CsvOptions: DefaultJson2CsvOptions = {
useDateIso8601Format: false,
useLocaleFormat: false,
wrapBooleans: false,
fieldTitleMap: Object.create({}),
};

export const defaultCsv2JsonOptions: DefaultCsv2JsonOptions = {
Expand Down
4 changes: 2 additions & 2 deletions src/json2csv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { evaluatePath } from 'doc-path';
import { deepKeysFromList } from 'deeks';
import { excelBOM, errors } from './constants';
import * as utils from './utils';
import type { FullJson2CsvOptions, Json2CsvParams } from './types';
import type { DefaultJson2CsvOptions, Json2CsvParams } from './types';

export const Json2Csv = function (options: FullJson2CsvOptions) {
export const Json2Csv = function (options: DefaultJson2CsvOptions) {
const wrapDelimiterCheckRegex = new RegExp(options.delimiter.wrap, 'g'),
crlfSearchRegex = /\r?\n|\r/,
customValueParser = options.parseValue && typeof options.parseValue === 'function' ? options.parseValue : null,
Expand Down
12 changes: 5 additions & 7 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ export interface Json2CsvOptions extends SharedConverterOptions {
*/
excludeKeys?: (string | RegExp)[];

/**
* Map keys to user provided titles.
*/
fieldTitleMap?: Record<string, string>;

/**
* Specify how values should be converted into CSV format. This function is provided a single field value at a time and must return a `String`.
* Note: Using this option may override other options, including `useDateIso8601Format` and `useLocaleFormat`.
Expand Down Expand Up @@ -189,13 +194,6 @@ export interface DefaultCsv2JsonOptions extends
// Then extend the types with required fields and specific fields omitted:
Omit<Omit<Omit<Omit<BuiltCsv2JsonOptions, 'wrapBooleans'>, 'keys'>, 'headerFields'>, 'parseValue'> {}

export interface FullJson2CsvOptions extends DefaultJson2CsvOptions {
/**
* Internal field that is used to map keys to user provided titles.
*/
fieldTitleMap: Record<string, string>;
}

export type FullCsv2JsonOptions = DefaultCsv2JsonOptions

export interface HeaderField {
Expand Down
8 changes: 4 additions & 4 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { evaluatePath, setPath } from 'doc-path';
import { defaultJson2CsvOptions, defaultCsv2JsonOptions } from './constants';
import type { Json2CsvOptions, Csv2JsonOptions, FullJson2CsvOptions, FullCsv2JsonOptions } from './types';
import type { Json2CsvOptions, Csv2JsonOptions, DefaultJson2CsvOptions, FullCsv2JsonOptions } from './types';

const dateStringRegex = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/,
MAX_ARRAY_LENGTH = 100000;
Expand All @@ -12,7 +12,7 @@ const dateStringRegex = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/,
* If a user does not provide custom options, then we use our default
* If options are provided, then we set each valid key that was passed
*/
export function buildJ2COptions(opts: Json2CsvOptions): FullJson2CsvOptions {
export function buildJ2COptions(opts: Json2CsvOptions): DefaultJson2CsvOptions {
return {
...defaultJson2CsvOptions,
...opts,
Expand All @@ -21,7 +21,7 @@ export function buildJ2COptions(opts: Json2CsvOptions): FullJson2CsvOptions {
wrap: opts?.delimiter?.wrap || defaultJson2CsvOptions.delimiter.wrap,
eol: opts?.delimiter?.eol || defaultJson2CsvOptions.delimiter.eol,
},
fieldTitleMap: Object.create({}),
fieldTitleMap: opts?.fieldTitleMap || Object.create({}),
};
}

Expand Down Expand Up @@ -60,7 +60,7 @@ export function deepCopy<T>(obj: T): T {
* of a string. Given the RFC4180 requirements, that means that the value is
* wrapped in value wrap delimiters (usually a quotation mark on each side).
*/
export function isStringRepresentation(fieldValue: string, options: FullJson2CsvOptions | FullCsv2JsonOptions) {
export function isStringRepresentation(fieldValue: string, options: DefaultJson2CsvOptions | FullCsv2JsonOptions) {
const firstChar = fieldValue[0],
lastIndex = fieldValue.length - 1,
lastChar = fieldValue[lastIndex];
Expand Down
1 change: 1 addition & 0 deletions test/config/testCsvFilesList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const csvFileConfig = [
{ key: 'arrayIndexesAsKeys', file: '../data/csv/arrayIndexesAsKeys.csv' },
{ key: 'keyWithEndingDot', file: '../data/csv/keyWithEndingDot.csv' },
{ key: 'fieldEolAtStart', file: '../data/csv/fieldEolAtStart.csv' },
{ key: 'renamedHeaderField', file: '../data/csv/renamedHeaderField.csv' },
];

function readCsvFile(filePath: string) {
Expand Down
3 changes: 3 additions & 0 deletions test/data/csv/renamedHeaderField.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
arrayOfStrings,renamedSubField,number,isBoolean,renamedOptionalField
"[""test1"",""test2""]",subValue,5,true,this one has it
"[""test3"",""test4""]",subValue,7,false,null
11 changes: 11 additions & 0 deletions test/json2csv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,17 @@ export function runTests() {
csv = json2csv(jsonTestData.deepNestedArrays.seven_levels_deep, options);
assert.equal(csv, expectedCSV);
});

it('should rename the header fields according to options', () => {
const csv = json2csv(jsonTestData.assortedValues, {
fieldTitleMap: {
'optionalField': 'renamedOptionalField',
'object.subField': 'renamedSubField',
},
});

assert.equal(csv, csvTestData.renamedHeaderField);
});
});
});

Expand Down