Socket
Socket
Sign inDemoInstall

csv-stringify

Package Overview
Dependencies
Maintainers
1
Versions
84
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 4.1.0 to 4.2.0

6

CHANGELOG.md
# Changelog
## Version 4.2.0
* formatter: new string formatter
* stream: be a much better transform citizen
* package: upgrade to babel 7
## Version 4.1.0

@@ -5,0 +11,0 @@

294

lib/es5/index.js

@@ -1,8 +0,7 @@

'use strict';
"use strict";
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
// Generated by CoffeeScript 2.0.3
// Generated by CoffeeScript 2.3.2
// # CSV Stringifier
// Please look at the [README], the [samples] and the [tests] for additional

@@ -13,16 +12,12 @@ // information.

stream = require('stream');
util = require('util');
get = require('lodash.get');
// ## Usage
get = require('lodash.get'); // ## Usage
// This module export a function as its main entry point and return a transform
// stream.
// Refers to the [official prject documentation](http://csv.adaltas.com/stringify/)
// on how to call this function.
module.exports = function () {
var callback, chunks, data, options, stringifier;
if (arguments.length === 3) {

@@ -38,2 +33,3 @@ data = arguments[0];

}
if (typeof arguments[1] === 'function') {

@@ -53,9 +49,13 @@ callback = arguments[1];

}
if (options == null) {
options = {};
}
stringifier = new _Stringifier(options);
if (data) {
process.nextTick(function () {
var d, j, len;
for (j = 0, len = data.length; j < len; j++) {

@@ -65,5 +65,7 @@ d = data[j];

}
return stringifier.end();
});
}
if (callback) {

@@ -74,5 +76,7 @@ chunks = [];

results = [];
while (chunk = stringifier.read()) {
results.push(chunks.push(chunk));
}
return results;

@@ -87,7 +91,5 @@ });

}
return stringifier;
};
// You can also use *util.promisify* native function (Node.js 8+) in order to wrap callbacks into promises for more convenient use when source is a readable stream and you are OK with storing entire result set in memory:
}; // You can also use *util.promisify* native function (Node.js 8+) in order to wrap callbacks into promises for more convenient use when source is a readable stream and you are OK with storing entire result set in memory:
// ```

@@ -97,3 +99,2 @@ // const { promisify } = require('util');

// const stringifyAsync = promisify(csv.stringify);
// //returns promise

@@ -104,12 +105,12 @@ // function generateCsv(sourceData) {

// ```
// ## `Stringifier([options])`
// Options are documented [here](http://csv.adaltas.com/stringify/).
// Options are documented [here](http://csv.adaltas.com/stringify/).
_Stringifier = function Stringifier() {
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var base, base1, base10, base11, base12, base13, base14, base2, base3, base4, base5, base6, base7, base8, base9, k, options, v; // Immutable options
var base, base1, base10, base11, base12, base13, base2, base3, base4, base5, base6, base7, base8, base9, k, options, v;
// Immutable options
options = {};
for (k in opts) {

@@ -119,41 +120,61 @@ v = opts[k];

}
stream.Transform.call(this, options);
//# Default options
options.objectMode = true;
stream.Transform.call(this, options); //# Default options
this.options = options;
if ((base = this.options).delimiter == null) {
base.delimiter = ',';
}
if ((base1 = this.options).quote == null) {
base1.quote = '"';
}
if ((base2 = this.options).quoted == null) {
base2.quoted = false;
}
if ((base3 = this.options).quotedEmpty == null) {
base3.quotedEmpty = void 0;
}
if ((base4 = this.options).quotedString == null) {
base4.quotedString = false;
}
if ((base5 = this.options).eof == null) {
base5.eof = true;
}
if ((base6 = this.options).escape == null) {
base6.escape = '"';
}
if ((base7 = this.options).header == null) {
base7.header = false;
}
// Normalize the columns option
} // Normalize the columns option
this.options.columns = _Stringifier.normalize_columns(this.options.columns);
if ((base8 = this.options).formatters == null) {
base8.formatters = {};
}
if (this.options.formatters.bool) {
// Backward compatibility
this.options.formatters.boolean = this.options.formatters.bool;
} // Custom formatters
if ((base9 = this.options.formatters).string == null) {
base9.string = function (value) {
return value;
};
}
// Custom formatters
if ((base9 = this.options.formatters).date == null) {
base9.date = function (value) {
if ((base10 = this.options.formatters).date == null) {
base10.date = function (value) {
// Cast date to timestamp string by default

@@ -163,4 +184,5 @@ return '' + value.getTime();

}
if ((base10 = this.options.formatters).boolean == null) {
base10.boolean = function (value) {
if ((base11 = this.options.formatters).boolean == null) {
base11.boolean = function (value) {
// Cast boolean to string by default

@@ -174,4 +196,5 @@ if (value) {

}
if ((base11 = this.options.formatters).number == null) {
base11.number = function (value) {
if ((base12 = this.options.formatters).number == null) {
base12.number = function (value) {
// Cast number to string using native casting by default

@@ -181,4 +204,5 @@ return '' + value;

}
if ((base12 = this.options.formatters).object == null) {
base12.object = function (value) {
if ((base13 = this.options.formatters).object == null) {
base13.object = function (value) {
// Stringify object as JSON by default

@@ -188,9 +212,12 @@ return JSON.stringify(value);

}
if ((base13 = this.options).rowDelimiter == null) {
base13.rowDelimiter = '\n';
}
// Internal usage, state related
if ((base14 = this.options).rowDelimiter == null) {
base14.rowDelimiter = '\n';
} // Internal usage, state related
if (this.countWriten == null) {
this.countWriten = 0;
}
switch (this.options.rowDelimiter) {

@@ -200,17 +227,23 @@ case 'auto':

break;
case 'unix':
this.options.rowDelimiter = "\n";
break;
case 'mac':
this.options.rowDelimiter = "\r";
break;
case 'windows':
this.options.rowDelimiter = "\r\n";
break;
case 'ascii':
this.options.rowDelimiter = '\x1E';
this.options.rowDelimiter = "\x1E";
break;
case 'unicode':
this.options.rowDelimiter = '\u2028';
this.options.rowDelimiter = "\u2028";
}
return this;

@@ -220,42 +253,14 @@ };

util.inherits(_Stringifier, stream.Transform);
module.exports.Stringifier = _Stringifier; // ## `Stringifier.prototype._transform(chunk, encoding, callback)`
// Implementation of the [transform._transform function](https://nodejs.org/api/stream.html#stream_transform_transform_chunk_encoding_callback).
module.exports.Stringifier = _Stringifier;
_Stringifier.prototype._transform = function (chunk, encoding, callback) {
var base, e, preserve; // Nothing to do if null or undefined
// ## `Stringifier.prototype.headers`
// Print the header line if the option "header" is "true".
_Stringifier.prototype.headers = function () {
var headers;
if (!this.options.header) {
if (chunk == null) {
return;
}
if (!this.options.columns) {
return;
}
headers = this.options.columns.map(function (column) {
return column.header;
});
if (this.options.eof) {
headers = this.stringify(headers) + this.options.rowDelimiter;
} else {
headers = this.stringify(headers);
}
return stream.Transform.prototype.write.call(this, headers);
};
_Stringifier.prototype.end = function (chunk, encoding, callback) {
if (this.countWriten === 0) {
this.headers();
}
return stream.Transform.prototype.end.apply(this, arguments);
};
preserve = _typeof(chunk) !== 'object'; // Emit and stringify the record if an object or an array
_Stringifier.prototype.write = function (chunk, encoding, callback) {
var base, e, preserve;
// Nothing to do if null or undefined
if (chunk == null) {
return;
}
preserve = (typeof chunk === 'undefined' ? 'undefined' : _typeof(chunk)) !== 'object';
// Emit and stringify the record if an object or an array
if (!preserve) {

@@ -268,2 +273,3 @@ // Detect columns from the first record

}
try {

@@ -274,8 +280,20 @@ this.emit('record', chunk, this.countWriten);

return this.emit('error', e);
}
// Convert the record into a string
} // Convert the record into a string
if (this.options.eof) {
chunk = this.stringify(chunk) + this.options.rowDelimiter;
chunk = this.stringify(chunk);
if (chunk == null) {
return;
}
chunk = chunk + this.options.rowDelimiter;
} else {
chunk = this.stringify(chunk);
if (chunk == null) {
return;
}
if (this.options.header || this.countWriten) {

@@ -286,29 +304,39 @@ chunk = this.options.rowDelimiter + chunk;

}
if (typeof chunk === 'number') {
// Emit the csv
chunk = '' + chunk;
chunk = "".concat(chunk);
}
if (this.countWriten === 0) {
this.headers();
}
if (!preserve) {
this.countWriten++;
}
return stream.Transform.prototype.write.call(this, chunk, encoding, callback);
};
// ## `Stringifier.prototype._transform(line)`
_Stringifier.prototype._transform = function (chunk, encoding, callback) {
this.push(chunk);
return callback();
};
}; // ## `Stringifier.prototype._flush(callback)`
// Implementation of the [transform._flush function](https://nodejs.org/api/stream.html#stream_transform_flush_callback).
// ## `Stringifier.prototype.stringify(line)`
_Stringifier.prototype._flush = function (callback) {
if (this.countWriten === 0) {
this.headers();
}
return callback();
}; // ## `Stringifier.prototype.stringify(line)`
// Convert a line to a string. Line may be an object, an array or a string.
_Stringifier.prototype.stringify = function (record) {
var _record, column, columns, containsEscape, containsQuote, containsRowDelimiter, containsdelimiter, delimiter, escape, field, i, j, l, newrecord, quote, ref, ref1, regexp, shouldQuote, type, value;
if ((typeof record === 'undefined' ? 'undefined' : _typeof(record)) !== 'object') {
var _record, column, columns, containsEscape, containsQuote, containsRowDelimiter, containsdelimiter, delimiter, err, escape, field, i, j, l, newrecord, quote, ref, ref1, regexp, shouldQuote, type, value;
if (_typeof(record) !== 'object') {
return record;
}
columns = this.options.columns;

@@ -318,4 +346,6 @@ delimiter = this.options.delimiter;

escape = this.options.escape;
if (!Array.isArray(record)) {
_record = [];
if (columns) {

@@ -331,2 +361,3 @@ for (i = j = 0, ref = columns.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {

}
record = _record;

@@ -340,24 +371,35 @@ _record = null;

}
if (Array.isArray(record)) {
newrecord = '';
for (i = l = 0, ref1 = record.length; 0 <= ref1 ? l < ref1 : l > ref1; i = 0 <= ref1 ? ++l : --l) {
field = record[i];
type = typeof field === 'undefined' ? 'undefined' : _typeof(field);
if (type === 'string') {
type = _typeof(field);
// fine 99% of the cases, keep going
} else if (type === 'number') {
// Cast number to string
field = this.options.formatters.number(field);
} else if (type === 'boolean') {
field = this.options.formatters.boolean(field);
} else if (field instanceof Date) {
field = this.options.formatters.date(field);
} else if (type === 'object' && field !== null) {
field = this.options.formatters.object(field);
try {
if (type === 'string') {
// fine 99% of the cases
field = this.options.formatters.string(field);
} else if (type === 'number') {
field = this.options.formatters.number(field);
} else if (type === 'boolean') {
field = this.options.formatters.boolean(field);
} else if (field instanceof Date) {
field = this.options.formatters.date(field);
} else if (type === 'object' && field !== null) {
field = this.options.formatters.object(field);
}
} catch (error) {
err = error;
this.emit('error', err);
return;
}
if (field) {
if (typeof field !== 'string') {
return this.emit('error', Error('Formatter must return a string, null or undefined'));
this.emit('error', Error('Formatter must return a string, null or undefined'));
return null;
}
containsdelimiter = field.indexOf(delimiter) >= 0;

@@ -368,2 +410,3 @@ containsQuote = quote !== '' && field.indexOf(quote) >= 0;

shouldQuote = containsQuote || containsdelimiter || containsRowDelimiter || this.options.quoted || this.options.quotedString && typeof record[i] === 'string';
if (shouldQuote && containsEscape) {

@@ -373,2 +416,3 @@ regexp = escape === '\\' ? new RegExp(escape + escape, 'g') : new RegExp(escape, 'g');

}
if (containsQuote) {

@@ -378,5 +422,7 @@ regexp = new RegExp(quote, 'g');

}
if (shouldQuote) {
field = quote + field + quote;
}
newrecord += field;

@@ -386,2 +432,3 @@ } else if (this.options.quotedEmpty || this.options.quotedEmpty == null && record[i] === '' && this.options.quotedString) {

}
if (i !== record.length - 1) {

@@ -391,16 +438,49 @@ newrecord += delimiter;

}
record = newrecord;
}
return record;
};
}; // ## `Stringifier.prototype.headers`
// Print the header line if the option "header" is "true".
_Stringifier.prototype.headers = function () {
var headers;
if (!this.options.header) {
return;
}
if (!this.options.columns) {
return;
}
headers = this.options.columns.map(function (column) {
return column.header;
});
if (this.options.eof) {
headers = this.stringify(headers) + this.options.rowDelimiter;
} else {
headers = this.stringify(headers);
}
return this.push(headers);
}; // ## `Stringifier.prototype.headers`
// Print the header line if the option "header" is "true".
_Stringifier.normalize_columns = function (columns) {
var column, k, v;
if (columns == null) {
return null;
}
if (columns != null) {
if ((typeof columns === 'undefined' ? 'undefined' : _typeof(columns)) !== 'object') {
if (_typeof(columns) !== 'object') {
throw Error('Invalid option "columns": expect an array or an object');
}
if (!Array.isArray(columns)) {

@@ -410,2 +490,3 @@ columns = function () {

results = [];
for (k in columns) {

@@ -418,2 +499,3 @@ v = columns[k];

}
return results;

@@ -425,4 +507,6 @@ }();

results = [];
for (j = 0, len = columns.length; j < len; j++) {
column = columns[j];
if (typeof column === 'string') {

@@ -433,9 +517,11 @@ results.push({

});
} else if ((typeof column === 'undefined' ? 'undefined' : _typeof(column)) === 'object' && column != null && !Array.isArray(column)) {
} else if (_typeof(column) === 'object' && column != null && !Array.isArray(column)) {
if (!column.key) {
throw Error('Invalid column definition: property "key" is required');
}
if (column.header == null) {
column.header = column.key;
}
results.push(column);

@@ -446,2 +532,3 @@ } else {

}
return results;

@@ -451,7 +538,6 @@ }();

}
return columns;
};
// [readme]: https://github.com/wdavidw/node-csv-stringify
}; // [readme]: https://github.com/wdavidw/node-csv-stringify
// [samples]: https://github.com/wdavidw/node-csv-stringify/tree/master/samples
// [tests]: https://github.com/wdavidw/node-csv-stringify/tree/master/test

@@ -1,8 +0,6 @@

'use strict';
"use strict";
// Generated by CoffeeScript 2.0.3
// Generated by CoffeeScript 2.3.2
// # CSV Stringify Sync
// Provides a synchronous alternative to the CSV stringifier.
// Usage: `data = stringify(records, [options]`

@@ -14,4 +12,2 @@ var StringDecoder, stringify;

StringDecoder = _require.StringDecoder;
stringify = require('./index');

@@ -21,5 +17,5 @@

var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var data, decoder, i, len, record, stringifier;
data = [];
if (records instanceof Buffer) {

@@ -29,3 +25,5 @@ decoder = new StringDecoder();

}
stringifier = new stringify.Stringifier(options);
stringifier.push = function (record) {

@@ -36,2 +34,3 @@ if (record) {

};
for (i = 0, len = records.length; i < len; i++) {

@@ -41,4 +40,5 @@ record = records[i];

}
stringifier.end();
return data.join('');
};

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

// Generated by CoffeeScript 2.0.3
// Generated by CoffeeScript 2.3.2
// # CSV Stringifier

@@ -98,3 +98,3 @@

Stringifier = function(opts = {}) {
var base, base1, base10, base11, base12, base13, base2, base3, base4, base5, base6, base7, base8, base9, k, options, v;
var base, base1, base10, base11, base12, base13, base14, base2, base3, base4, base5, base6, base7, base8, base9, k, options, v;
// Immutable options

@@ -106,2 +106,3 @@ options = {};

}
options.objectMode = true;
stream.Transform.call(this, options);

@@ -144,4 +145,9 @@ //# Default options

// Custom formatters
if ((base9 = this.options.formatters).date == null) {
base9.date = function(value) {
if ((base9 = this.options.formatters).string == null) {
base9.string = function(value) {
return value;
};
}
if ((base10 = this.options.formatters).date == null) {
base10.date = function(value) {
// Cast date to timestamp string by default

@@ -151,4 +157,4 @@ return '' + value.getTime();

}
if ((base10 = this.options.formatters).boolean == null) {
base10.boolean = function(value) {
if ((base11 = this.options.formatters).boolean == null) {
base11.boolean = function(value) {
// Cast boolean to string by default

@@ -162,4 +168,4 @@ if (value) {

}
if ((base11 = this.options.formatters).number == null) {
base11.number = function(value) {
if ((base12 = this.options.formatters).number == null) {
base12.number = function(value) {
// Cast number to string using native casting by default

@@ -169,4 +175,4 @@ return '' + value;

}
if ((base12 = this.options.formatters).object == null) {
base12.object = function(value) {
if ((base13 = this.options.formatters).object == null) {
base13.object = function(value) {
// Stringify object as JSON by default

@@ -176,4 +182,4 @@ return JSON.stringify(value);

}
if ((base13 = this.options).rowDelimiter == null) {
base13.rowDelimiter = '\n';
if ((base14 = this.options).rowDelimiter == null) {
base14.rowDelimiter = '\n';
}

@@ -210,32 +216,6 @@ // Internal usage, state related

// ## `Stringifier.prototype.headers`
// ## `Stringifier.prototype._transform(chunk, encoding, callback)`
// Print the header line if the option "header" is "true".
Stringifier.prototype.headers = function() {
var headers;
if (!this.options.header) {
return;
}
if (!this.options.columns) {
return;
}
headers = this.options.columns.map(function(column) {
return column.header;
});
if (this.options.eof) {
headers = this.stringify(headers) + this.options.rowDelimiter;
} else {
headers = this.stringify(headers);
}
return stream.Transform.prototype.write.call(this, headers);
};
Stringifier.prototype.end = function(chunk, encoding, callback) {
if (this.countWriten === 0) {
this.headers();
}
return stream.Transform.prototype.end.apply(this, arguments);
};
Stringifier.prototype.write = function(chunk, encoding, callback) {
// Implementation of the [transform._transform function](https://nodejs.org/api/stream.html#stream_transform_transform_chunk_encoding_callback).
Stringifier.prototype._transform = function(chunk, encoding, callback) {
var base, e, preserve;

@@ -263,5 +243,12 @@ // Nothing to do if null or undefined

if (this.options.eof) {
chunk = this.stringify(chunk) + this.options.rowDelimiter;
chunk = this.stringify(chunk);
if (chunk == null) {
return;
}
chunk = chunk + this.options.rowDelimiter;
} else {
chunk = this.stringify(chunk);
if (chunk == null) {
return;
}
if (this.options.header || this.countWriten) {

@@ -282,8 +269,13 @@ chunk = this.options.rowDelimiter + chunk;

}
return stream.Transform.prototype.write.call(this, chunk, encoding, callback);
this.push(chunk);
return callback();
};
// ## `Stringifier.prototype._transform(line)`
Stringifier.prototype._transform = function(chunk, encoding, callback) {
this.push(chunk);
// ## `Stringifier.prototype._flush(callback)`
// Implementation of the [transform._flush function](https://nodejs.org/api/stream.html#stream_transform_flush_callback).
Stringifier.prototype._flush = function(callback) {
if (this.countWriten === 0) {
this.headers();
}
return callback();

@@ -296,3 +288,3 @@ };

Stringifier.prototype.stringify = function(record) {
var _record, column, columns, containsEscape, containsQuote, containsRowDelimiter, containsdelimiter, delimiter, escape, field, i, j, l, newrecord, quote, ref, ref1, regexp, shouldQuote, type, value;
var _record, column, columns, containsEscape, containsQuote, containsRowDelimiter, containsdelimiter, delimiter, err, escape, field, i, j, l, newrecord, quote, ref, ref1, regexp, shouldQuote, type, value;
if (typeof record !== 'object') {

@@ -308,3 +300,3 @@ return record;

if (columns) {
for (i = j = 0, ref = columns.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
for (i = j = 0, ref = columns.length; (0 <= ref ? j < ref : j > ref); i = 0 <= ref ? ++j : --j) {
value = get(record, columns[i].key);

@@ -327,21 +319,27 @@ _record[i] = (typeof value === 'undefined' || value === null) ? '' : value;

newrecord = '';
for (i = l = 0, ref1 = record.length; 0 <= ref1 ? l < ref1 : l > ref1; i = 0 <= ref1 ? ++l : --l) {
for (i = l = 0, ref1 = record.length; (0 <= ref1 ? l < ref1 : l > ref1); i = 0 <= ref1 ? ++l : --l) {
field = record[i];
type = typeof field;
if (type === 'string') {
// fine 99% of the cases, keep going
} else if (type === 'number') {
// Cast number to string
field = this.options.formatters.number(field);
} else if (type === 'boolean') {
field = this.options.formatters.boolean(field);
} else if (field instanceof Date) {
field = this.options.formatters.date(field);
} else if (type === 'object' && field !== null) {
field = this.options.formatters.object(field);
try {
if (type === 'string') {
// fine 99% of the cases
field = this.options.formatters.string(field);
} else if (type === 'number') {
field = this.options.formatters.number(field);
} else if (type === 'boolean') {
field = this.options.formatters.boolean(field);
} else if (field instanceof Date) {
field = this.options.formatters.date(field);
} else if (type === 'object' && field !== null) {
field = this.options.formatters.object(field);
}
} catch (error) {
err = error;
this.emit('error', err);
return;
}
if (field) {
if (typeof field !== 'string') {
return this.emit('error', Error('Formatter must return a string, null or undefined'));
this.emit('error', Error('Formatter must return a string, null or undefined'));
return null;
}

@@ -377,2 +375,27 @@ containsdelimiter = field.indexOf(delimiter) >= 0;

// ## `Stringifier.prototype.headers`
// Print the header line if the option "header" is "true".
Stringifier.prototype.headers = function() {
var headers;
if (!this.options.header) {
return;
}
if (!this.options.columns) {
return;
}
headers = this.options.columns.map(function(column) {
return column.header;
});
if (this.options.eof) {
headers = this.stringify(headers) + this.options.rowDelimiter;
} else {
headers = this.stringify(headers);
}
return this.push(headers);
};
// ## `Stringifier.prototype.headers`
// Print the header line if the option "header" is "true".
Stringifier.normalize_columns = function(columns) {

@@ -379,0 +402,0 @@ var column, k, v;

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

// Generated by CoffeeScript 2.0.3
// Generated by CoffeeScript 2.3.2
// # CSV Stringify Sync

@@ -3,0 +3,0 @@

{
"version": "4.1.0",
"version": "4.2.0",
"name": "csv-stringify",

@@ -20,4 +20,5 @@ "description": "CSV stringifier implementing the Node.js `stream.Transform` API",

"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"@babel/cli": "^7.1.0",
"@babel/core": "^7.1.0",
"@babel/preset-env": "^7.1.0",
"coffeescript": "~2.3.1",

@@ -24,0 +25,0 @@ "csv-generate": "~2.1.0",

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc