From f283e073c4756ac27fd4846c2fdf7b70e724e2df Mon Sep 17 00:00:00 2001 From: vasyl Date: Sat, 10 Jul 2021 21:11:27 +1000 Subject: [PATCH] Fix date values are not auto detected as headers --- src/lil-csv.js | 11 ++++++----- test/generate.test.js | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/lil-csv.js b/src/lil-csv.js index 8f9ce89..c9448bb 100644 --- a/src/lil-csv.js +++ b/src/lil-csv.js @@ -4,6 +4,7 @@ let isNumber = (v) => typeof v === "number"; let isBoolean = (v) => typeof v === "boolean"; let isDate = (v) => v instanceof Date && !isNaN(v.valueOf()); let isObject = (v) => v && typeof v === "object" && !isArray(v); +const isPlainObject = (value) => value && typeof value == "object" && value.__proto__ == Object.prototype; let isFunction = (v) => typeof v === "function"; function getDeep(obj, path) { @@ -13,7 +14,7 @@ function getDeep(obj, path) { function setDeep(obj, path, value) { path.split(".").reduce((result, curr, index, paths) => { let newVal = index + 1 === paths.length ? value : {}; - return isObject(result[curr]) ? result[curr] : (result[curr] = newVal); + return isPlainObject(result[curr]) ? result[curr] : (result[curr] = newVal); }, obj); } @@ -21,9 +22,9 @@ function mergeDeep(target, ...sources) { if (!sources.length) return target; let source = sources.shift(); - if (isObject(target) && isObject(source)) { + if (isPlainObject(target) && isPlainObject(source)) { for (let [key, value] of Object.entries(source)) { - if (isObject(value)) { + if (isPlainObject(value)) { mergeDeep((target[key] = target[key] || {}), value); } else { target[key] = value; @@ -37,7 +38,7 @@ function mergeDeep(target, ...sources) { function keysDeep(obj, prefix) { return Object.entries(obj).reduce((keys, [k, v]) => { let newKey = prefix ? prefix + "." + k : k; - return keys.concat(isObject(v) ? keysDeep(v, newKey) : newKey); + return keys.concat(isPlainObject(v) ? keysDeep(v, newKey) : newKey); }, []); } @@ -170,7 +171,7 @@ export function generate(rows, { header = true, lineTerminator = "\n", escapeCha if (!isArray(rows[0])) throw new Error("Can't auto detect header from rows"); } - if (isObject(header)) { + if (isPlainObject(header)) { // If there is "star" header then the column order would be taken from the data rows; // but if no "*" was given then let's user the `header` object order. let detectedHeadersSet = new Set(header["*"] ? detectedHeaders : Object.keys(header)); diff --git a/test/generate.test.js b/test/generate.test.js index 2b27a76..9120977 100644 --- a/test/generate.test.js +++ b/test/generate.test.js @@ -138,4 +138,28 @@ John,Smith,1999-01-15,123.00,Y Alice,Dwarf,1991-11-24,123.00,N` ); }); + + it("should parse and generate with '*' header", () => { + let fileContents = `firstName,lastName,dob,price,completed +John,Smith,1999-01-15,123.55,Y +Alice,Dwarf,1991-11-24,123.55,N`; + const people = parse(fileContents, { + header: { + "*": String, + dob: (v) => (v ? new Date(v) : null), + price: (v) => (isNaN(v) ? null : Number(v)), + completed: (v) => String(v).toUpperCase() === "Y", + }, + }); + + let string = generate(people, { + header: { + "*": String, + dob: (v) => (v ? new Date(v).toISOString().substr(0, 10) : ""), + price: (v) => (isNaN(v) ? "" : Number(v).toFixed(2)), + completed: (v) => (v ? "Y" : "N"), + }, + }); + assert.strictEqual(string, fileContents); + }); });