Skip to content

Commit e3a9bcf

Browse files
authored
Merge pull request #280 from petterw03/rename-header-fields
allow user to rename individual field headers
2 parents 6f43ada + a617948 commit e3a9bcf

8 files changed

Lines changed: 30 additions & 13 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ Returns the CSV `string` or rejects with an `Error` if there was an issue.
129129
* `false` uses the following keys:
130130
* `['specifications']`
131131
* Note: This may result in CSV output that does not map back exactly to the original JSON. See #102 for more information.
132+
* `fieldTitleMap` - Object - Specify field titles that should be renamed.
133+
* Default: `{}`
134+
* Example: `{ "key1": "Key 1", "key2": "Key 2"}`
132135
* `keys` - Array - Specify the keys that should be converted.
133136
* Default: These will be auto-detected from your data by default.
134137
* Keys can either be specified as a String representing the key path that should be converted, or as an Object of the following format:

src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export const defaultJson2CsvOptions: DefaultJson2CsvOptions = {
4040
useDateIso8601Format: false,
4141
useLocaleFormat: false,
4242
wrapBooleans: false,
43+
fieldTitleMap: Object.create({}),
4344
};
4445

4546
export const defaultCsv2JsonOptions: DefaultCsv2JsonOptions = {

src/json2csv.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { evaluatePath } from 'doc-path';
44
import { deepKeysFromList } from 'deeks';
55
import { excelBOM, errors } from './constants';
66
import * as utils from './utils';
7-
import type { FullJson2CsvOptions, Json2CsvParams } from './types';
7+
import type { DefaultJson2CsvOptions, Json2CsvParams } from './types';
88

9-
export const Json2Csv = function (options: FullJson2CsvOptions) {
9+
export const Json2Csv = function (options: DefaultJson2CsvOptions) {
1010
const wrapDelimiterCheckRegex = new RegExp(options.delimiter.wrap, 'g'),
1111
crlfSearchRegex = /\r?\n|\r/,
1212
customValueParser = options.parseValue && typeof options.parseValue === 'function' ? options.parseValue : null,

src/types.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ export interface Json2CsvOptions extends SharedConverterOptions {
157157
*/
158158
excludeKeys?: (string | RegExp)[];
159159

160+
/**
161+
* Map keys to user provided titles.
162+
*/
163+
fieldTitleMap?: Record<string, string>;
164+
160165
/**
161166
* 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`.
162167
* Note: Using this option may override other options, including `useDateIso8601Format` and `useLocaleFormat`.
@@ -189,13 +194,6 @@ export interface DefaultCsv2JsonOptions extends
189194
// Then extend the types with required fields and specific fields omitted:
190195
Omit<Omit<Omit<Omit<BuiltCsv2JsonOptions, 'wrapBooleans'>, 'keys'>, 'headerFields'>, 'parseValue'> {}
191196

192-
export interface FullJson2CsvOptions extends DefaultJson2CsvOptions {
193-
/**
194-
* Internal field that is used to map keys to user provided titles.
195-
*/
196-
fieldTitleMap: Record<string, string>;
197-
}
198-
199197
export type FullCsv2JsonOptions = DefaultCsv2JsonOptions
200198

201199
export interface HeaderField {

src/utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

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

77
const dateStringRegex = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/,
88
MAX_ARRAY_LENGTH = 100000;
@@ -12,7 +12,7 @@ const dateStringRegex = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/,
1212
* If a user does not provide custom options, then we use our default
1313
* If options are provided, then we set each valid key that was passed
1414
*/
15-
export function buildJ2COptions(opts: Json2CsvOptions): FullJson2CsvOptions {
15+
export function buildJ2COptions(opts: Json2CsvOptions): DefaultJson2CsvOptions {
1616
return {
1717
...defaultJson2CsvOptions,
1818
...opts,
@@ -21,7 +21,7 @@ export function buildJ2COptions(opts: Json2CsvOptions): FullJson2CsvOptions {
2121
wrap: opts?.delimiter?.wrap || defaultJson2CsvOptions.delimiter.wrap,
2222
eol: opts?.delimiter?.eol || defaultJson2CsvOptions.delimiter.eol,
2323
},
24-
fieldTitleMap: Object.create({}),
24+
fieldTitleMap: opts?.fieldTitleMap || Object.create({}),
2525
};
2626
}
2727

@@ -60,7 +60,7 @@ export function deepCopy<T>(obj: T): T {
6060
* of a string. Given the RFC4180 requirements, that means that the value is
6161
* wrapped in value wrap delimiters (usually a quotation mark on each side).
6262
*/
63-
export function isStringRepresentation(fieldValue: string, options: FullJson2CsvOptions | FullCsv2JsonOptions) {
63+
export function isStringRepresentation(fieldValue: string, options: DefaultJson2CsvOptions | FullCsv2JsonOptions) {
6464
const firstChar = fieldValue[0],
6565
lastIndex = fieldValue.length - 1,
6666
lastChar = fieldValue[lastIndex];

test/config/testCsvFilesList.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const csvFileConfig = [
5858
{ key: 'arrayIndexesAsKeys', file: '../data/csv/arrayIndexesAsKeys.csv' },
5959
{ key: 'keyWithEndingDot', file: '../data/csv/keyWithEndingDot.csv' },
6060
{ key: 'fieldEolAtStart', file: '../data/csv/fieldEolAtStart.csv' },
61+
{ key: 'renamedHeaderField', file: '../data/csv/renamedHeaderField.csv' },
6162
];
6263

6364
function readCsvFile(filePath: string) {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
arrayOfStrings,renamedSubField,number,isBoolean,renamedOptionalField
2+
"[""test1"",""test2""]",subValue,5,true,this one has it
3+
"[""test3"",""test4""]",subValue,7,false,null

test/json2csv.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,17 @@ export function runTests() {
794794
csv = json2csv(jsonTestData.deepNestedArrays.seven_levels_deep, options);
795795
assert.equal(csv, expectedCSV);
796796
});
797+
798+
it('should rename the header fields according to options', () => {
799+
const csv = json2csv(jsonTestData.assortedValues, {
800+
fieldTitleMap: {
801+
'optionalField': 'renamedOptionalField',
802+
'object.subField': 'renamedSubField',
803+
},
804+
});
805+
806+
assert.equal(csv, csvTestData.renamedHeaderField);
807+
});
797808
});
798809
});
799810

0 commit comments

Comments
 (0)