Comparing version 0.9.7 to 0.9.8
@@ -14,6 +14,9 @@ export type CsvMappingType = 'number' | 'string' | 'boolean' | 'date'; | ||
detectTypes?: boolean; | ||
detectSeparator?: boolean; | ||
}; | ||
export declare const SaveCsvDefaultOptions: CsvOptions; | ||
export declare const LoadCsvDefaultOptions: CsvOptions; | ||
export declare function saveToFile<T extends Record<string, unknown>>(data: T[], filePath: string, options?: CsvOptions): Promise<string>; | ||
export declare function loadFromFile<T extends Record<string, unknown>>(filePath: string, options?: CsvOptions): Promise<T[]>; | ||
export declare function toCsv(data: Record<string, unknown>[], options?: CsvOptions): string; | ||
export declare function writeCsv(data: Record<string, unknown>[], filePath: string, options?: CsvOptions): Promise<string>; | ||
export declare function fromCsv<T extends Record<string, unknown>>(text: string, options?: CsvOptions): T[]; | ||
export declare function readCsv<T extends Record<string, unknown>>(filePath: string, options?: CsvOptions): Promise<T[]>; |
import { readFile, writeFile } from 'fs/promises'; | ||
export const SaveCsvDefaultOptions = { | ||
separator: '\t', | ||
separator: ',', | ||
arraySeparator: '|' | ||
}; | ||
export const LoadCsvDefaultOptions = { | ||
separator: SaveCsvDefaultOptions.separator, | ||
separator: undefined, | ||
arraySeparator: SaveCsvDefaultOptions.arraySeparator, | ||
detectTypes: true | ||
}; | ||
//return line.split(new RegExp(separator + '(?=(?:[^"]*"[^"]*")*[^"]*$)')) | ||
// function to split line by separator but ignore separator inside double quotes. Keep double quotes. not using regex | ||
function splitLine(line, separator) { | ||
@@ -34,27 +32,2 @@ const values = []; | ||
} | ||
export async function saveToFile(data, filePath, options = {}) { | ||
const { separator, fields, arraySeparator } = { ...SaveCsvDefaultOptions, ...options }; | ||
const headers = fields ?? Object.keys(data[0]); | ||
const lines = [headers.join(separator)]; | ||
data.forEach(obj => { | ||
const line = headers.map(header => { | ||
let value = obj[header]; | ||
if (Array.isArray(value)) { | ||
value = `${value.join(arraySeparator)}`; | ||
} | ||
if (typeof value === 'string') { | ||
if (value.includes(separator) || value.includes(arraySeparator)) | ||
return `"${value.replace(/"/g, '""')}"`; | ||
return value; | ||
} | ||
if (typeof value === 'object' && value instanceof Date) { | ||
return value.toISOString(); | ||
} | ||
return value; | ||
}).join(separator); | ||
lines.push(line); | ||
}); | ||
await writeFile(filePath, lines.join('\n')); | ||
return filePath; | ||
} | ||
function getMappingValue(value, type, arraySeparator = ',') { | ||
@@ -90,6 +63,43 @@ if (value.startsWith('"') && value.endsWith('"')) { | ||
} | ||
export async function loadFromFile(filePath, options = {}) { | ||
const { separator, fields, mapping, detectTypes, arraySeparator } = { ...LoadCsvDefaultOptions, ...options }; | ||
const fileData = (await readFile(filePath, 'utf-8')) | ||
.split('\n') | ||
export function toCsv(data, options = {}) { | ||
const { separator, fields, arraySeparator } = { ...SaveCsvDefaultOptions, ...options }; | ||
const headers = fields ?? Object.keys(data[0]); | ||
const lines = [headers.join(separator)]; | ||
data.forEach(obj => { | ||
const line = headers.map(header => { | ||
let value = obj[header]; | ||
if (Array.isArray(value)) { | ||
value = `${value.join(arraySeparator)}`; | ||
} | ||
if (typeof value === 'string') { | ||
if (value.includes(separator) || value.includes(arraySeparator)) | ||
return `"${value.replace(/"/g, '""')}"`; | ||
return value; | ||
} | ||
if (typeof value === 'object' && value instanceof Date) { | ||
return value.toISOString(); | ||
} | ||
return value; | ||
}).join(separator); | ||
lines.push(line); | ||
}); | ||
return lines.join('\n'); | ||
} | ||
export async function writeCsv(data, filePath, options = {}) { | ||
await writeFile(filePath, toCsv(data, options)); | ||
return filePath; | ||
} | ||
// return the separator that appears the most in the first line | ||
function detectSeparator(text) { | ||
const separators = [',', ';', '\t']; | ||
const counts = separators.map(sep => ({ sep, count: (text.match(new RegExp(sep, 'g')) || []).length })); | ||
if (counts.every(c => c.count === 0)) | ||
throw new Error('No separator found in the first line'); | ||
return counts.sort((a, b) => b.count - a.count)[0].sep; | ||
} | ||
export function fromCsv(text, options = {}) { | ||
const { separator: _sep, fields, mapping, detectTypes, arraySeparator } = { ...LoadCsvDefaultOptions, ...options }; | ||
const lines = text.split('\n'); | ||
const separator = _sep ?? detectSeparator(lines[0]); | ||
const fileData = lines | ||
.map(line => splitLine((line ?? '').replace(/\r/g, ''), separator)); | ||
@@ -111,2 +121,6 @@ const headers = fields ?? fileData[0]; | ||
} | ||
export async function readCsv(filePath, options = {}) { | ||
const fileContent = await readFile(filePath, 'utf-8'); | ||
return fromCsv(fileContent, options); | ||
} | ||
//# sourceMappingURL=csv.js.map |
{ | ||
"name": "@ricb/csv", | ||
"version": "0.9.7", | ||
"version": "0.9.8", | ||
"description": "Reads and writes data to and from flat files", | ||
@@ -5,0 +5,0 @@ "main": "./dist/csv.js", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
12216
143