Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

csv-stringify

Package Overview
Dependencies
Maintainers
1
Versions
85
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

csv-stringify - npm Package Compare versions

Comparing version 6.5.1 to 6.5.2

15

lib/api/CsvError.js

@@ -1,14 +0,17 @@

class CsvError extends Error {
constructor(code, message, ...contexts) {
if(Array.isArray(message)) message = message.join(' ');
if (Array.isArray(message)) message = message.join(" ");
super(message);
if(Error.captureStackTrace !== undefined){
if (Error.captureStackTrace !== undefined) {
Error.captureStackTrace(this, CsvError);
}
this.code = code;
for(const context of contexts){
for(const key in context){
for (const context of contexts) {
for (const key in context) {
const value = context[key];
this[key] = Buffer.isBuffer(value) ? value.toString() : value == null ? value : JSON.parse(JSON.stringify(value));
this[key] = Buffer.isBuffer(value)
? value.toString()
: value == null
? value
: JSON.parse(JSON.stringify(value));
}

@@ -15,0 +18,0 @@ }

303

lib/api/index.js

@@ -1,9 +0,8 @@

import { get } from '../utils/get.js';
import { is_object } from '../utils/is_object.js';
import { normalize_columns } from './normalize_columns.js';
import { normalize_options } from './normalize_options.js';
import { get } from "../utils/get.js";
import { is_object } from "../utils/is_object.js";
import { normalize_columns } from "./normalize_columns.js";
import { normalize_options } from "./normalize_options.js";
const bom_utf8 = Buffer.from([239, 187, 191]);
const stringifier = function(options, state, info){
const stringifier = function (options, state, info) {
return {

@@ -13,16 +12,23 @@ options: options,

info: info,
__transform: function(chunk, push){
__transform: function (chunk, push) {
// Chunk validation
if(!Array.isArray(chunk) && typeof chunk !== 'object'){
return Error(`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`);
if (!Array.isArray(chunk) && typeof chunk !== "object") {
return Error(
`Invalid Record: expect an array or an object, got ${JSON.stringify(chunk)}`,
);
}
// Detect columns from the first record
if(this.info.records === 0){
if(Array.isArray(chunk)){
if(this.options.header === true && this.options.columns === undefined){
return Error('Undiscoverable Columns: header option requires column option or object records');
if (this.info.records === 0) {
if (Array.isArray(chunk)) {
if (
this.options.header === true &&
this.options.columns === undefined
) {
return Error(
"Undiscoverable Columns: header option requires column option or object records",
);
}
}else if(this.options.columns === undefined){
} else if (this.options.columns === undefined) {
const [err, columns] = normalize_columns(Object.keys(chunk));
if(err) return;
if (err) return;
this.options.columns = columns;

@@ -32,14 +38,14 @@ }

// Emit the header
if(this.info.records === 0){
if (this.info.records === 0) {
this.bom(push);
const err = this.headers(push);
if(err) return err;
if (err) return err;
}
// Emit and stringify the record if an object or an array
try{
try {
// this.emit('record', chunk, this.info.records);
if(this.options.on_record){
if (this.options.on_record) {
this.options.on_record(chunk, this.info.records);
}
}catch(err){
} catch (err) {
return err;

@@ -49,17 +55,17 @@ }

let err, chunk_string;
if(this.options.eof){
if (this.options.eof) {
[err, chunk_string] = this.stringify(chunk);
if(err) return err;
if(chunk_string === undefined){
if (err) return err;
if (chunk_string === undefined) {
return;
}else{
} else {
chunk_string = chunk_string + this.options.record_delimiter;
}
}else{
} else {
[err, chunk_string] = this.stringify(chunk);
if(err) return err;
if(chunk_string === undefined){
if (err) return err;
if (chunk_string === undefined) {
return;
}else{
if(this.options.header || this.info.records){
} else {
if (this.options.header || this.info.records) {
chunk_string = this.options.record_delimiter + chunk_string;

@@ -73,92 +79,132 @@ }

},
stringify: function(chunk, chunkIsHeader=false){
if(typeof chunk !== 'object'){
stringify: function (chunk, chunkIsHeader = false) {
if (typeof chunk !== "object") {
return [undefined, chunk];
}
const {columns} = this.options;
const { columns } = this.options;
const record = [];
// Record is an array
if(Array.isArray(chunk)){
if (Array.isArray(chunk)) {
// We are getting an array but the user has specified output columns. In
// this case, we respect the columns indexes
if(columns){
if (columns) {
chunk.splice(columns.length);
}
// Cast record elements
for(let i=0; i<chunk.length; i++){
for (let i = 0; i < chunk.length; i++) {
const field = chunk[i];
const [err, value] = this.__cast(field, {
index: i, column: i, records: this.info.records, header: chunkIsHeader
index: i,
column: i,
records: this.info.records,
header: chunkIsHeader,
});
if(err) return [err];
if (err) return [err];
record[i] = [value, field];
}
// Record is a literal object
// `columns` is always defined: it is either provided or discovered.
}else{
for(let i=0; i<columns.length; i++){
// Record is a literal object
// `columns` is always defined: it is either provided or discovered.
} else {
for (let i = 0; i < columns.length; i++) {
const field = get(chunk, columns[i].key);
const [err, value] = this.__cast(field, {
index: i, column: columns[i].key, records: this.info.records, header: chunkIsHeader
index: i,
column: columns[i].key,
records: this.info.records,
header: chunkIsHeader,
});
if(err) return [err];
if (err) return [err];
record[i] = [value, field];
}
}
let csvrecord = '';
for(let i=0; i<record.length; i++){
let csvrecord = "";
for (let i = 0; i < record.length; i++) {
let options, err;
// eslint-disable-next-line
let [value, field] = record[i];
if(typeof value === "string"){
if (typeof value === "string") {
options = this.options;
}else if(is_object(value)){
} else if (is_object(value)) {
options = value;
value = options.value;
delete options.value;
if(typeof value !== "string" && value !== undefined && value !== null){
if(err) return [Error(`Invalid Casting Value: returned value must return a string, null or undefined, got ${JSON.stringify(value)}`)];
if (
typeof value !== "string" &&
value !== undefined &&
value !== null
) {
if (err)
return [
Error(
`Invalid Casting Value: returned value must return a string, null or undefined, got ${JSON.stringify(value)}`,
),
];
}
options = {...this.options, ...options};
options = { ...this.options, ...options };
[err, options] = normalize_options(options);
if(err !== undefined){
if (err !== undefined) {
return [err];
}
}else if(value === undefined || value === null){
} else if (value === undefined || value === null) {
options = this.options;
}else{
return [Error(`Invalid Casting Value: returned value must return a string, an object, null or undefined, got ${JSON.stringify(value)}`)];
} else {
return [
Error(
`Invalid Casting Value: returned value must return a string, an object, null or undefined, got ${JSON.stringify(value)}`,
),
];
}
const {delimiter, escape, quote, quoted, quoted_empty, quoted_string, quoted_match, record_delimiter, escape_formulas} = options;
if('' === value && '' === field){
let quotedMatch = quoted_match && quoted_match.filter(quoted_match => {
if(typeof quoted_match === 'string'){
return value.indexOf(quoted_match) !== -1;
}else{
return quoted_match.test(value);
}
});
const {
delimiter,
escape,
quote,
quoted,
quoted_empty,
quoted_string,
quoted_match,
record_delimiter,
escape_formulas,
} = options;
if ("" === value && "" === field) {
let quotedMatch =
quoted_match &&
quoted_match.filter((quoted_match) => {
if (typeof quoted_match === "string") {
return value.indexOf(quoted_match) !== -1;
} else {
return quoted_match.test(value);
}
});
quotedMatch = quotedMatch && quotedMatch.length > 0;
const shouldQuote = quotedMatch || true === quoted_empty ||
const shouldQuote =
quotedMatch ||
true === quoted_empty ||
(true === quoted_string && false !== quoted_empty);
if(shouldQuote === true){
if (shouldQuote === true) {
value = quote + value + quote;
}
csvrecord += value;
}else if(value){
if(typeof value !== 'string'){
return [Error(`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`)];
} else if (value) {
if (typeof value !== "string") {
return [
Error(
`Formatter must return a string, null or undefined, got ${JSON.stringify(value)}`,
),
];
}
const containsdelimiter = delimiter.length && value.indexOf(delimiter) >= 0;
const containsQuote = (quote !== '') && value.indexOf(quote) >= 0;
const containsEscape = value.indexOf(escape) >= 0 && (escape !== quote);
const containsdelimiter =
delimiter.length && value.indexOf(delimiter) >= 0;
const containsQuote = quote !== "" && value.indexOf(quote) >= 0;
const containsEscape = value.indexOf(escape) >= 0 && escape !== quote;
const containsRecordDelimiter = value.indexOf(record_delimiter) >= 0;
const quotedString = quoted_string && typeof field === 'string';
let quotedMatch = quoted_match && quoted_match.filter(quoted_match => {
if(typeof quoted_match === 'string'){
return value.indexOf(quoted_match) !== -1;
}else{
return quoted_match.test(value);
}
});
const quotedString = quoted_string && typeof field === "string";
let quotedMatch =
quoted_match &&
quoted_match.filter((quoted_match) => {
if (typeof quoted_match === "string") {
return value.indexOf(quoted_match) !== -1;
} else {
return quoted_match.test(value);
}
});
quotedMatch = quotedMatch && quotedMatch.length > 0;

@@ -173,35 +219,45 @@ // See https://github.com/adaltas/node-csv/pull/387

switch (value[0]) {
case '=':
case '+':
case '-':
case '@':
case '\t':
case '\r':
case '\uFF1D': // Unicode '='
case '\uFF0B': // Unicode '+'
case '\uFF0D': // Unicode '-'
case '\uFF20': // Unicode '@'
value = `'${value}`;
break;
case "=":
case "+":
case "-":
case "@":
case "\t":
case "\r":
case "\uFF1D": // Unicode '='
case "\uFF0B": // Unicode '+'
case "\uFF0D": // Unicode '-'
case "\uFF20": // Unicode '@'
value = `'${value}`;
break;
}
}
const shouldQuote = containsQuote === true || containsdelimiter || containsRecordDelimiter || quoted || quotedString || quotedMatch;
if(shouldQuote === true && containsEscape === true){
const regexp = escape === '\\'
? new RegExp(escape + escape, 'g')
: new RegExp(escape, 'g');
const shouldQuote =
containsQuote === true ||
containsdelimiter ||
containsRecordDelimiter ||
quoted ||
quotedString ||
quotedMatch;
if (shouldQuote === true && containsEscape === true) {
const regexp =
escape === "\\"
? new RegExp(escape + escape, "g")
: new RegExp(escape, "g");
value = value.replace(regexp, escape + escape);
}
if(containsQuote === true){
const regexp = new RegExp(quote,'g');
if (containsQuote === true) {
const regexp = new RegExp(quote, "g");
value = value.replace(regexp, escape + quote);
}
if(shouldQuote === true){
if (shouldQuote === true) {
value = quote + value + quote;
}
csvrecord += value;
}else if(quoted_empty === true || (field === '' && quoted_string === true && quoted_empty !== false)){
} else if (
quoted_empty === true ||
(field === "" && quoted_string === true && quoted_empty !== false)
) {
csvrecord += quote + quote;
}
if(i !== record.length - 1){
if (i !== record.length - 1) {
csvrecord += delimiter;

@@ -212,4 +268,4 @@ }

},
bom: function(push){
if(this.options.bom !== true){
bom: function (push) {
if (this.options.bom !== true) {
return;

@@ -219,45 +275,46 @@ }

},
headers: function(push){
if(this.options.header === false){
headers: function (push) {
if (this.options.header === false) {
return;
}
if(this.options.columns === undefined){
if (this.options.columns === undefined) {
return;
}
let err;
let headers = this.options.columns.map(column => column.header);
if(this.options.eof){
let headers = this.options.columns.map((column) => column.header);
if (this.options.eof) {
[err, headers] = this.stringify(headers, true);
headers += this.options.record_delimiter;
}else{
} else {
[err, headers] = this.stringify(headers);
}
if(err) return err;
if (err) return err;
push(headers);
},
__cast: function(value, context){
__cast: function (value, context) {
const type = typeof value;
try{
if(type === 'string'){ // Fine for 99% of the cases
try {
if (type === "string") {
// Fine for 99% of the cases
return [undefined, this.options.cast.string(value, context)];
}else if(type === 'bigint'){
} else if (type === "bigint") {
return [undefined, this.options.cast.bigint(value, context)];
}else if(type === 'number'){
} else if (type === "number") {
return [undefined, this.options.cast.number(value, context)];
}else if(type === 'boolean'){
} else if (type === "boolean") {
return [undefined, this.options.cast.boolean(value, context)];
}else if(value instanceof Date){
} else if (value instanceof Date) {
return [undefined, this.options.cast.date(value, context)];
}else if(type === 'object' && value !== null){
} else if (type === "object" && value !== null) {
return [undefined, this.options.cast.object(value, context)];
}else{
} else {
return [undefined, value, value];
}
}catch(err){
} catch (err) {
return [err];
}
}
},
};
};
export {stringifier};
export { stringifier };

@@ -1,36 +0,43 @@

const normalize_columns = function(columns){
if(columns === undefined || columns === null){
const normalize_columns = function (columns) {
if (columns === undefined || columns === null) {
return [undefined, undefined];
}
if(typeof columns !== 'object'){
if (typeof columns !== "object") {
return [Error('Invalid option "columns": expect an array or an object')];
}
if(!Array.isArray(columns)){
if (!Array.isArray(columns)) {
const newcolumns = [];
for(const k in columns){
for (const k in columns) {
newcolumns.push({
key: k,
header: columns[k]
header: columns[k],
});
}
columns = newcolumns;
}else{
} else {
const newcolumns = [];
for(const column of columns){
if(typeof column === 'string'){
for (const column of columns) {
if (typeof column === "string") {
newcolumns.push({
key: column,
header: column
header: column,
});
}else if(typeof column === 'object' && column !== null && !Array.isArray(column)){
if(!column.key){
return [Error('Invalid column definition: property "key" is required')];
} else if (
typeof column === "object" &&
column !== null &&
!Array.isArray(column)
) {
if (!column.key) {
return [
Error('Invalid column definition: property "key" is required'),
];
}
if(column.header === undefined){
if (column.header === undefined) {
column.header = column.key;
}
newcolumns.push(column);
}else{
return [Error('Invalid column definition: expect a string or an object')];
} else {
return [
Error("Invalid column definition: expect a string or an object"),
];
}

@@ -43,2 +50,2 @@ }

export {normalize_columns};
export { normalize_columns };

@@ -0,80 +1,102 @@

import { CsvError } from "./CsvError.js";
import { normalize_columns } from "./normalize_columns.js";
import { underscore } from "../utils/underscore.js";
import { CsvError } from './CsvError.js';
import { normalize_columns } from './normalize_columns.js';
import { underscore } from '../utils/underscore.js';
const normalize_options = function(opts) {
const normalize_options = function (opts) {
const options = {};
// Merge with user options
for(const opt in opts){
for (const opt in opts) {
options[underscore(opt)] = opts[opt];
}
// Normalize option `bom`
if(options.bom === undefined || options.bom === null || options.bom === false){
if (
options.bom === undefined ||
options.bom === null ||
options.bom === false
) {
options.bom = false;
}else if(options.bom !== true){
return [new CsvError('CSV_OPTION_BOOLEAN_INVALID_TYPE', [
'option `bom` is optional and must be a boolean value,',
`got ${JSON.stringify(options.bom)}`
])];
} else if (options.bom !== true) {
return [
new CsvError("CSV_OPTION_BOOLEAN_INVALID_TYPE", [
"option `bom` is optional and must be a boolean value,",
`got ${JSON.stringify(options.bom)}`,
]),
];
}
// Normalize option `delimiter`
if(options.delimiter === undefined || options.delimiter === null){
options.delimiter = ',';
}else if(Buffer.isBuffer(options.delimiter)){
if (options.delimiter === undefined || options.delimiter === null) {
options.delimiter = ",";
} else if (Buffer.isBuffer(options.delimiter)) {
options.delimiter = options.delimiter.toString();
}else if(typeof options.delimiter !== 'string'){
return [new CsvError('CSV_OPTION_DELIMITER_INVALID_TYPE', [
'option `delimiter` must be a buffer or a string,',
`got ${JSON.stringify(options.delimiter)}`
])];
} else if (typeof options.delimiter !== "string") {
return [
new CsvError("CSV_OPTION_DELIMITER_INVALID_TYPE", [
"option `delimiter` must be a buffer or a string,",
`got ${JSON.stringify(options.delimiter)}`,
]),
];
}
// Normalize option `quote`
if(options.quote === undefined || options.quote === null){
if (options.quote === undefined || options.quote === null) {
options.quote = '"';
}else if(options.quote === true){
} else if (options.quote === true) {
options.quote = '"';
}else if(options.quote === false){
options.quote = '';
}else if (Buffer.isBuffer(options.quote)){
} else if (options.quote === false) {
options.quote = "";
} else if (Buffer.isBuffer(options.quote)) {
options.quote = options.quote.toString();
}else if(typeof options.quote !== 'string'){
return [new CsvError('CSV_OPTION_QUOTE_INVALID_TYPE', [
'option `quote` must be a boolean, a buffer or a string,',
`got ${JSON.stringify(options.quote)}`
])];
} else if (typeof options.quote !== "string") {
return [
new CsvError("CSV_OPTION_QUOTE_INVALID_TYPE", [
"option `quote` must be a boolean, a buffer or a string,",
`got ${JSON.stringify(options.quote)}`,
]),
];
}
// Normalize option `quoted`
if(options.quoted === undefined || options.quoted === null){
if (options.quoted === undefined || options.quoted === null) {
options.quoted = false;
}else{
} else {
// todo
}
// Normalize option `escape_formulas`
if(options.escape_formulas === undefined || options.escape_formulas === null){
if (
options.escape_formulas === undefined ||
options.escape_formulas === null
) {
options.escape_formulas = false;
}else if(typeof options.escape_formulas !== 'boolean'){
return [new CsvError('CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE', [
'option `escape_formulas` must be a boolean,',
`got ${JSON.stringify(options.escape_formulas)}`
])];
} else if (typeof options.escape_formulas !== "boolean") {
return [
new CsvError("CSV_OPTION_ESCAPE_FORMULAS_INVALID_TYPE", [
"option `escape_formulas` must be a boolean,",
`got ${JSON.stringify(options.escape_formulas)}`,
]),
];
}
// Normalize option `quoted_empty`
if(options.quoted_empty === undefined || options.quoted_empty === null){
if (options.quoted_empty === undefined || options.quoted_empty === null) {
options.quoted_empty = undefined;
}else{
} else {
// todo
}
// Normalize option `quoted_match`
if(options.quoted_match === undefined || options.quoted_match === null || options.quoted_match === false){
if (
options.quoted_match === undefined ||
options.quoted_match === null ||
options.quoted_match === false
) {
options.quoted_match = null;
}else if(!Array.isArray(options.quoted_match)){
} else if (!Array.isArray(options.quoted_match)) {
options.quoted_match = [options.quoted_match];
}
if(options.quoted_match){
for(const quoted_match of options.quoted_match){
const isString = typeof quoted_match === 'string';
if (options.quoted_match) {
for (const quoted_match of options.quoted_match) {
const isString = typeof quoted_match === "string";
const isRegExp = quoted_match instanceof RegExp;
if(!isString && !isRegExp){
return [Error(`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`)];
if (!isString && !isRegExp) {
return [
Error(
`Invalid Option: quoted_match must be a string or a regex, got ${JSON.stringify(quoted_match)}`,
),
];
}

@@ -84,28 +106,36 @@ }

// Normalize option `quoted_string`
if(options.quoted_string === undefined || options.quoted_string === null){
if (options.quoted_string === undefined || options.quoted_string === null) {
options.quoted_string = false;
}else{
} else {
// todo
}
// Normalize option `eof`
if(options.eof === undefined || options.eof === null){
if (options.eof === undefined || options.eof === null) {
options.eof = true;
}else{
} else {
// todo
}
// Normalize option `escape`
if(options.escape === undefined || options.escape === null){
if (options.escape === undefined || options.escape === null) {
options.escape = '"';
}else if(Buffer.isBuffer(options.escape)){
} else if (Buffer.isBuffer(options.escape)) {
options.escape = options.escape.toString();
}else if(typeof options.escape !== 'string'){
return [Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)];
} else if (typeof options.escape !== "string") {
return [
Error(
`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`,
),
];
}
if (options.escape.length > 1){
return [Error(`Invalid Option: escape must be one character, got ${options.escape.length} characters`)];
if (options.escape.length > 1) {
return [
Error(
`Invalid Option: escape must be one character, got ${options.escape.length} characters`,
),
];
}
// Normalize option `header`
if(options.header === undefined || options.header === null){
if (options.header === undefined || options.header === null) {
options.header = false;
}else{
} else {
// todo

@@ -115,74 +145,86 @@ }

const [errColumns, columns] = normalize_columns(options.columns);
if(errColumns !== undefined) return [errColumns];
if (errColumns !== undefined) return [errColumns];
options.columns = columns;
// Normalize option `quoted`
if(options.quoted === undefined || options.quoted === null){
if (options.quoted === undefined || options.quoted === null) {
options.quoted = false;
}else{
} else {
// todo
}
// Normalize option `cast`
if(options.cast === undefined || options.cast === null){
if (options.cast === undefined || options.cast === null) {
options.cast = {};
}else{
} else {
// todo
}
// Normalize option cast.bigint
if(options.cast.bigint === undefined || options.cast.bigint === null){
if (options.cast.bigint === undefined || options.cast.bigint === null) {
// Cast boolean to string by default
options.cast.bigint = value => '' + value;
options.cast.bigint = (value) => "" + value;
}
// Normalize option cast.boolean
if(options.cast.boolean === undefined || options.cast.boolean === null){
if (options.cast.boolean === undefined || options.cast.boolean === null) {
// Cast boolean to string by default
options.cast.boolean = value => value ? '1' : '';
options.cast.boolean = (value) => (value ? "1" : "");
}
// Normalize option cast.date
if(options.cast.date === undefined || options.cast.date === null){
if (options.cast.date === undefined || options.cast.date === null) {
// Cast date to timestamp string by default
options.cast.date = value => '' + value.getTime();
options.cast.date = (value) => "" + value.getTime();
}
// Normalize option cast.number
if(options.cast.number === undefined || options.cast.number === null){
if (options.cast.number === undefined || options.cast.number === null) {
// Cast number to string using native casting by default
options.cast.number = value => '' + value;
options.cast.number = (value) => "" + value;
}
// Normalize option cast.object
if(options.cast.object === undefined || options.cast.object === null){
if (options.cast.object === undefined || options.cast.object === null) {
// Stringify object as JSON by default
options.cast.object = value => JSON.stringify(value);
options.cast.object = (value) => JSON.stringify(value);
}
// Normalize option cast.string
if(options.cast.string === undefined || options.cast.string === null){
if (options.cast.string === undefined || options.cast.string === null) {
// Leave string untouched
options.cast.string = function(value){return value;};
options.cast.string = function (value) {
return value;
};
}
// Normalize option `on_record`
if(options.on_record !== undefined && typeof options.on_record !== 'function'){
if (
options.on_record !== undefined &&
typeof options.on_record !== "function"
) {
return [Error(`Invalid Option: "on_record" must be a function.`)];
}
// Normalize option `record_delimiter`
if(options.record_delimiter === undefined || options.record_delimiter === null){
options.record_delimiter = '\n';
}else if(Buffer.isBuffer(options.record_delimiter)){
if (
options.record_delimiter === undefined ||
options.record_delimiter === null
) {
options.record_delimiter = "\n";
} else if (Buffer.isBuffer(options.record_delimiter)) {
options.record_delimiter = options.record_delimiter.toString();
}else if(typeof options.record_delimiter !== 'string'){
return [Error(`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`)];
} else if (typeof options.record_delimiter !== "string") {
return [
Error(
`Invalid Option: record_delimiter must be a buffer or a string, got ${JSON.stringify(options.record_delimiter)}`,
),
];
}
switch(options.record_delimiter){
case 'unix':
options.record_delimiter = "\n";
break;
case 'mac':
options.record_delimiter = "\r";
break;
case 'windows':
options.record_delimiter = "\r\n";
break;
case 'ascii':
options.record_delimiter = "\u001e";
break;
case 'unicode':
options.record_delimiter = "\u2028";
break;
switch (options.record_delimiter) {
case "unix":
options.record_delimiter = "\n";
break;
case "mac":
options.record_delimiter = "\r";
break;
case "windows":
options.record_delimiter = "\r\n";
break;
case "ascii":
options.record_delimiter = "\u001e";
break;
case "unicode":
options.record_delimiter = "\u2028";
break;
}

@@ -192,2 +234,2 @@ return [undefined, options];

export {normalize_options};
export { normalize_options };

@@ -1,2 +0,1 @@

/*

@@ -9,13 +8,13 @@ CSV Stringify

import { Transform } from 'stream';
import { CsvError } from './api/CsvError.js';
import { is_object } from './utils/is_object.js';
import { stringifier } from './api/index.js';
import { normalize_options } from './api/normalize_options.js';
import { Transform } from "stream";
import { CsvError } from "./api/CsvError.js";
import { is_object } from "./utils/is_object.js";
import { stringifier } from "./api/index.js";
import { normalize_options } from "./api/normalize_options.js";
class Stringifier extends Transform {
constructor(opts = {}){
super({...{writableObjectMode: true}, ...opts});
constructor(opts = {}) {
super({ ...{ writableObjectMode: true }, ...opts });
const [err, options] = normalize_options(opts);
if(err !== undefined) throw err;
if (err !== undefined) throw err;
// Expose options

@@ -25,19 +24,19 @@ this.options = options;

this.state = {
stop: false
stop: false,
};
// Information
this.info = {
records: 0
records: 0,
};
this.api = stringifier(this.options, this.state, this.info);
this.api.options.on_record = (...args) => {
this.emit('record', ...args);
this.emit("record", ...args);
};
}
_transform(chunk, encoding, callback){
if(this.state.stop === true){
_transform(chunk, encoding, callback) {
if (this.state.stop === true) {
return;
}
const err = this.api.__transform(chunk, this.push.bind(this));
if(err !== undefined){
if (err !== undefined) {
this.state.stop = true;

@@ -47,4 +46,4 @@ }

}
_flush(callback){
if(this.state.stop === true){
_flush(callback) {
if (this.state.stop === true) {
// Note, Node.js 12 call flush even after an error, we must prevent

@@ -54,6 +53,6 @@ // `callback` from being called in flush without any error.

}
if(this.info.records === 0){
if (this.info.records === 0) {
this.api.bom(this.push.bind(this));
const err = this.api.headers(this.push.bind(this));
if(err) callback(err);
if (err) callback(err);
}

@@ -64,17 +63,17 @@ callback();

const stringify = function(){
const stringify = function () {
let data, options, callback;
for(const i in arguments){
for (const i in arguments) {
const argument = arguments[i];
const type = typeof argument;
if(data === undefined && (Array.isArray(argument))){
if (data === undefined && Array.isArray(argument)) {
data = argument;
}else if(options === undefined && is_object(argument)){
} else if (options === undefined && is_object(argument)) {
options = argument;
}else if(callback === undefined && type === 'function'){
} else if (callback === undefined && type === "function") {
callback = argument;
}else{
throw new CsvError('CSV_INVALID_ARGUMENT', [
'Invalid argument:',
`got ${JSON.stringify(argument)} at index ${i}`
} else {
throw new CsvError("CSV_INVALID_ARGUMENT", [
"Invalid argument:",
`got ${JSON.stringify(argument)} at index ${i}`,
]);

@@ -84,16 +83,16 @@ }

const stringifier = new Stringifier(options);
if(callback){
if (callback) {
const chunks = [];
stringifier.on('readable', function(){
stringifier.on("readable", function () {
let chunk;
while((chunk = this.read()) !== null){
while ((chunk = this.read()) !== null) {
chunks.push(chunk);
}
});
stringifier.on('error', function(err){
stringifier.on("error", function (err) {
callback(err);
});
stringifier.on('end', function(){
stringifier.on("end", function () {
try {
callback(undefined, chunks.join(''));
callback(undefined, chunks.join(""));
} catch (err) {

@@ -108,5 +107,5 @@ // This can happen if the `chunks` is extremely long; it may throw

}
if(data !== undefined){
const writer = function(){
for(const record of data){
if (data !== undefined) {
const writer = function () {
for (const record of data) {
stringifier.write(record);

@@ -117,5 +116,5 @@ }

// Support Deno, Rollup doesnt provide a shim for setImmediate
if(typeof setImmediate === 'function'){
if (typeof setImmediate === "function") {
setImmediate(writer);
}else{
} else {
setTimeout(writer, 0);

@@ -122,0 +121,0 @@ }

@@ -0,24 +1,23 @@

import { stringifier } from "./api/index.js";
import { normalize_options } from "./api/normalize_options.js";
import { stringifier } from './api/index.js';
import { normalize_options } from './api/normalize_options.js';
const stringify = function(records, opts={}){
const stringify = function (records, opts = {}) {
const data = [];
const [err, options] = normalize_options(opts);
if(err !== undefined) throw err;
if (err !== undefined) throw err;
const state = {
stop: false
stop: false,
};
// Information
const info = {
records: 0
records: 0,
};
const api = stringifier(options, state, info);
for(const record of records){
const err = api.__transform(record, function(record){
for (const record of records) {
const err = api.__transform(record, function (record) {
data.push(record);
});
if(err !== undefined) throw err;
if (err !== undefined) throw err;
}
if(data.length === 0){
if (data.length === 0) {
api.bom((d) => {

@@ -30,7 +29,7 @@ data.push(d);

});
if(err !== undefined) throw err;
if (err !== undefined) throw err;
}
return data.join('');
return data.join("");
};
export { stringify };

@@ -1,52 +0,69 @@

// Lodash implementation of `get`
const charCodeOfDot = '.'.charCodeAt(0);
const charCodeOfDot = ".".charCodeAt(0);
const reEscapeChar = /\\(\\)?/g;
const rePropName = RegExp(
// Match anything that isn't a dot or bracket.
'[^.[\\]]+' + '|' +
// Or match property names within brackets.
'\\[(?:' +
"[^.[\\]]+" +
"|" +
// Or match property names within brackets.
"\\[(?:" +
// Match a non-string expression.
'([^"\'][^[]*)' + '|' +
"([^\"'][^[]*)" +
"|" +
// Or match strings (supports escaping characters).
'(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' +
')\\]'+ '|' +
// Or match "" as the space between consecutive dots or empty brackets.
'(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))'
, 'g');
"([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" +
")\\]" +
"|" +
// Or match "" as the space between consecutive dots or empty brackets.
"(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))",
"g",
);
const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/;
const reIsPlainProp = /^\w*$/;
const getTag = function(value){
if(!value)
value === undefined ? '[object Undefined]' : '[object Null]';
const getTag = function (value) {
if (!value) value === undefined ? "[object Undefined]" : "[object Null]";
return Object.prototype.toString.call(value);
};
const isSymbol = function(value){
const isSymbol = function (value) {
const type = typeof value;
return type === 'symbol' || (type === 'object' && value && getTag(value) === '[object Symbol]');
return (
type === "symbol" ||
(type === "object" && value && getTag(value) === "[object Symbol]")
);
};
const isKey = function(value, object){
if(Array.isArray(value)){
const isKey = function (value, object) {
if (Array.isArray(value)) {
return false;
}
const type = typeof value;
if(type === 'number' || type === 'symbol' || type === 'boolean' || !value || isSymbol(value)){
if (
type === "number" ||
type === "symbol" ||
type === "boolean" ||
!value ||
isSymbol(value)
) {
return true;
}
return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
(object != null && value in Object(object));
return (
reIsPlainProp.test(value) ||
!reIsDeepProp.test(value) ||
(object != null && value in Object(object))
);
};
const stringToPath = function(string){
const stringToPath = function (string) {
const result = [];
if(string.charCodeAt(0) === charCodeOfDot){
result.push('');
if (string.charCodeAt(0) === charCodeOfDot) {
result.push("");
}
string.replace(rePropName, function(match, expression, quote, subString){
string.replace(rePropName, function (match, expression, quote, subString) {
let key = match;
if(quote){
key = subString.replace(reEscapeChar, '$1');
}else if(expression){
if (quote) {
key = subString.replace(reEscapeChar, "$1");
} else if (expression) {
key = expression.trim();

@@ -58,4 +75,5 @@ }

};
const castPath = function(value, object){
if(Array.isArray(value)){
const castPath = function (value, object) {
if (Array.isArray(value)) {
return value;

@@ -66,19 +84,20 @@ } else {

};
const toKey = function(value){
if(typeof value === 'string' || isSymbol(value))
return value;
const toKey = function (value) {
if (typeof value === "string" || isSymbol(value)) return value;
const result = `${value}`;
// eslint-disable-next-line
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
return result == "0" && 1 / value == -INFINITY ? "-0" : result;
};
const get = function(object, path){
const get = function (object, path) {
path = castPath(path, object);
let index = 0;
const length = path.length;
while(object != null && index < length){
while (object != null && index < length) {
object = object[toKey(path[index++])];
}
return (index && index === length) ? object : undefined;
return index && index === length ? object : undefined;
};
export {get};
export { get };

@@ -1,7 +0,5 @@

const is_object = function(obj){
return typeof obj === 'object' && obj !== null && ! Array.isArray(obj);
const is_object = function (obj) {
return typeof obj === "object" && obj !== null && !Array.isArray(obj);
};
export {is_object};
export { is_object };

@@ -1,6 +0,4 @@

const underscore = function(str){
return str.replace(/([A-Z])/g, function(_, match){
return '_' + match.toLowerCase();
const underscore = function (str) {
return str.replace(/([A-Z])/g, function (_, match) {
return "_" + match.toLowerCase();
});

@@ -7,0 +5,0 @@ };

{
"version": "6.5.1",
"version": "6.5.2",
"name": "csv-stringify",

@@ -14,19 +14,22 @@ "description": "CSV stringifier implementing the Node.js `stream.Transform` API",

"devDependencies": {
"@rollup/plugin-eslint": "^9.0.4",
"@rollup/plugin-node-resolve": "^15.2.1",
"@types/mocha": "^10.0.1",
"@types/node": "^20.5.6",
"@types/should": "^13.0.0",
"@eslint/js": "^9.15.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@types/mocha": "^10.0.9",
"@types/node": "^22.9.1",
"coffeescript": "~2.7.0",
"csv-generate": "^4.4.1",
"each": "^2.4.0",
"eslint": "^8.47.0",
"express": "^4.18.2",
"mocha": "~10.2.0",
"rollup": "^3.28.1",
"csv-generate": "^4.4.2",
"each": "^2.7.2",
"eslint": "^9.15.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-mocha": "^10.5.0",
"eslint-plugin-prettier": "^5.2.1",
"express": "^4.21.1",
"mocha": "~10.8.2",
"prettier": "^3.3.3",
"rollup": "^4.27.3",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-globals": "^1.4.0",
"should": "~13.2.3",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
"ts-node": "^10.9.2",
"typescript": "^5.6.3"
},

@@ -78,5 +81,9 @@ "exports": {

],
"throw-deprecation": true,
"throw-deprecation": false,
"timeout": 40000
},
"lint-staged": {
"*.js": "npm run lint:fix",
"*.md": "prettier -w"
},
"repository": {

@@ -92,9 +99,6 @@ "type": "git",

"postbuild:ts": "find dist/cjs -name '*.d.cts' -exec sh -c \"sed -i \"s/\\.js'/\\.cjs'/g\" {} || sed -i '' \"s/\\.js'/\\.cjs'/g\" {}\" \\;",
"lint": "npm run lint:lib && npm run lint:samples && npm run lint:test",
"postlint": "tsc --noEmit true",
"lint:lib": "eslint --fix lib/*.js",
"lint:samples": "eslint --fix samples/*.js",
"lint:test": "coffeelint --fix test/*.coffee",
"lint:check": "eslint",
"lint:fix": "eslint --fix",
"lint:ts": "tsc --noEmit true",
"preversion": "npm run build && git add dist",
"pretest": "npm run build",
"test": "mocha 'test/**/*.{coffee,ts}'",

@@ -121,3 +125,3 @@ "test:legacy": "mocha --ignore test/api.callback.coffee --ignore test/api.web_stream.coffee --loader=./test/loaders/legacy/all.js 'test/**/*.{coffee,ts}'"

},
"gitHead": "5a48f0cfbf05da8b3625d0a2dbf52c3991e4ad85"
"gitHead": "cc1235a58de98dd9eab0665c7b1d03213e9633c7"
}

@@ -1,2 +0,1 @@

# CSV stringifier for Node.js and the web

@@ -12,17 +11,17 @@

* [Project homepage](https://csv.js.org/stringify/)
* [API](https://csv.js.org/stringify/api/)
* [Options](https://csv.js.org/stringify/options/)
* [Examples](https://csv.js.org/stringify/examples/)
- [Project homepage](https://csv.js.org/stringify/)
- [API](https://csv.js.org/stringify/api/)
- [Options](https://csv.js.org/stringify/options/)
- [Examples](https://csv.js.org/stringify/examples/)
## Main features
* Follow the Node.js streaming API
* Simplicity with the optional callback API
* Support for custom formatters, delimiters, quotes, escape characters and header
* Support big datasets
* Complete test coverage and samples for inspiration
* Only 1 external dependency
* to be used conjointly with `csv-generate`, `csv-parse` and `stream-transform`
* MIT License
- Follow the Node.js streaming API
- Simplicity with the optional callback API
- Support for custom formatters, delimiters, quotes, escape characters and header
- Support big datasets
- Complete test coverage and samples for inspiration
- Only 1 external dependency
- to be used conjointly with `csv-generate`, `csv-parse` and `stream-transform`
- MIT License

@@ -40,11 +39,11 @@ ## Usage

```js
import { stringify } from 'csv-stringify/sync';
import assert from 'assert';
import { stringify } from "csv-stringify/sync";
import assert from "assert";
const output = stringify([
[ '1', '2', '3', '4' ],
[ 'a', 'b', 'c', 'd' ]
["1", "2", "3", "4"],
["a", "b", "c", "d"],
]);
assert.equal(output, '1,2,3,4\na,b,c,d\n');
assert.equal(output, "1,2,3,4\na,b,c,d\n");
```

@@ -64,2 +63,2 @@

* David Worms: <https://github.com/wdavidw>
- David Worms: <https://github.com/wdavidw>

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc