Socket
Socket
Sign inDemoInstall

i

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

i - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

lib/native.js

12

lib/inflect.js
// Requiring modules
require('./utils/array');
require('./utils/string');
module.exports = require('./methods');
module.exports = function (native) {
var methods = require('./methods');
require('./utils/inflect')(module.exports);
if (native) {
require('./native')(methods);
}
return methods
};

@@ -16,2 +16,4 @@ // A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional

var util = require('./util');
var Inflections = function () {

@@ -30,5 +32,5 @@ this.plurals = [];

if (typeof rule == 'string') {
this.uncountables = this.uncountables.del(rule);
this.uncountables = util.array.del(this.uncountables, rule);
}
this.uncountables = this.uncountables.del(replacement);
this.uncountables = util.array.del(this.uncountables, replacement);
this.plurals.unshift([rule, replacement]);

@@ -41,5 +43,5 @@ };

if (typeof rule == 'string') {
this.uncountables = this.uncountables.del(rule);
this.uncountables = util.array.del(this.uncountables, rule);
}
this.uncountables = this.uncountables.del(replacement);
this.uncountables = util.array.del(this.uncountables, replacement);
this.singulars.unshift([rule, replacement]);

@@ -54,4 +56,4 @@ };

Inflections.prototype.irregular = function (singular, plural) {
this.uncountables = this.uncountables.del(singular);
this.uncountables = this.uncountables.del(plural);
this.uncountables = util.array.del(this.uncountables, singular);
this.uncountables = util.array.del(this.uncountables, plural);
if (singular[0].toUpperCase() == plural[0].toUpperCase()) {

@@ -58,0 +60,0 @@ this.plural(new RegExp("(" + singular[0] + ")" + singular.slice(1) + "$", "i"), '$1' + plural.slice(1));

@@ -8,224 +8,227 @@ // The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,

module.exports = {
var util = require('./util');
// Import [inflections](inflections.html) instance
inflections: require('./inflections'),
var inflect = module.exports;
// Gives easy access to add inflections to this class
inflect: function (inflections_function) {
inflections_function(this.inflections);
},
// Import [inflections](inflections.html) instance
inflect.inflections = require('./inflections')
// By default, _camelize_ converts strings to UpperCamelCase. If the argument to _camelize_
// is set to _false_ then _camelize_ produces lowerCamelCase.
//
// _camelize_ will also convert '/' to '.' which is useful for converting paths to namespaces.
//
// "bullet_record".camelize() // => "BulletRecord"
// "bullet_record".camelize(false) // => "bulletRecord"
// "bullet_record/errors".camelize() // => "BulletRecord.Errors"
// "bullet_record/errors".camelize(false) // => "bulletRecord.Errors"
//
// As a rule of thumb you can think of _camelize_ as the inverse of _underscore_,
// though there are cases where that does not hold:
//
// "SSLError".underscore.camelize // => "SslError"
camelize: function(lower_case_and_underscored_word, first_letter_in_uppercase) {
var result;
if (first_letter_in_uppercase == null) first_letter_in_uppercase = true;
result = lower_case_and_underscored_word.gsub(/\/(.?)/, function($) {
return "." + ($[1].upcase());
});
result = result.gsub(/(?:_)(.)/, function($) {
return $[1].upcase();
});
if (first_letter_in_uppercase) {
return result.upcase();
} else {
return result;
}
},
// Gives easy access to add inflections to this class
inflect.inflect = function (inflections_function) {
inflections_function(inflect.inflections);
};
// Makes an underscored, lowercase form from the expression in the string.
//
// Changes '.' to '/' to convert namespaces to paths.
//
// "BulletRecord".underscore() // => "bullet_record"
// "BulletRecord.Errors".underscore() // => "bullet_record/errors"
//
// As a rule of thumb you can think of +underscore+ as the inverse of +camelize+,
// though there are cases where that does not hold:
//
// "SSLError".underscore().camelize() // => "SslError"
underscore: function (camel_cased_word) {
var self;
self = camel_cased_word.gsub(/\./, '/');
self = self.gsub(/([A-Z]+)([A-Z][a-z])/, "$1_$2");
self = self.gsub(/([a-z\d])([A-Z])/, "$1_$2");
self = self.gsub(/-/, '_');
return self.toLowerCase();
},
// By default, _camelize_ converts strings to UpperCamelCase. If the argument to _camelize_
// is set to _false_ then _camelize_ produces lowerCamelCase.
//
// _camelize_ will also convert '/' to '.' which is useful for converting paths to namespaces.
//
// "bullet_record".camelize() // => "BulletRecord"
// "bullet_record".camelize(false) // => "bulletRecord"
// "bullet_record/errors".camelize() // => "BulletRecord.Errors"
// "bullet_record/errors".camelize(false) // => "bulletRecord.Errors"
//
// As a rule of thumb you can think of _camelize_ as the inverse of _underscore_,
// though there are cases where that does not hold:
//
// "SSLError".underscore.camelize // => "SslError"
inflect.camelize = function(lower_case_and_underscored_word, first_letter_in_uppercase) {
var result;
if (first_letter_in_uppercase == null) first_letter_in_uppercase = true;
result = util.string.gsub(lower_case_and_underscored_word, /\/(.?)/, function($) {
return "." + (util.string.upcase($[1]));
});
result = util.string.gsub(result, /(?:_)(.)/, function($) {
return util.string.upcase($[1]);
});
if (first_letter_in_uppercase) {
return util.string.upcase(result);
} else {
return result;
}
};
// Replaces underscores with dashes in the string.
//
// "puni_puni".dasherize() // => "puni-puni"
dasherize: function (underscored_word) {
return underscored_word.gsub(/_/, '-');
},
// Makes an underscored, lowercase form from the expression in the string.
//
// Changes '.' to '/' to convert namespaces to paths.
//
// "BulletRecord".underscore() // => "bullet_record"
// "BulletRecord.Errors".underscore() // => "bullet_record/errors"
//
// As a rule of thumb you can think of +underscore+ as the inverse of +camelize+,
// though there are cases where that does not hold:
//
// "SSLError".underscore().camelize() // => "SslError"
inflect.underscore = function (camel_cased_word) {
var self;
self = util.string.gsub(camel_cased_word, /\./, '/');
self = util.string.gsub(self, /([A-Z]+)([A-Z][a-z])/, "$1_$2");
self = util.string.gsub(self, /([a-z\d])([A-Z])/, "$1_$2");
self = util.string.gsub(self, /-/, '_');
return self.toLowerCase();
};
// Removes the module part from the expression in the string.
//
// "BulletRecord.String.Inflections".demodulize() // => "Inflections"
// "Inflections".demodulize() // => "Inflections"
demodulize: function (class_name_in_module) {
return class_name_in_module.gsub(/^.*\./, '');
},
// Replaces underscores with dashes in the string.
//
// "puni_puni".dasherize() // => "puni-puni"
inflect.dasherize = function (underscored_word) {
return util.string.gsub(underscored_word, /_/, '-');
};
// Creates a foreign key name from a class name.
// _separate_class_name_and_id_with_underscore_ sets whether
// the method should put '_' between the name and 'id'.
//
// "Message".foreign_key() // => "message_id"
// "Message".foreign_key(false) // => "messageid"
// "Admin::Post".foreign_key() // => "post_id"
foreign_key: function (class_name, separate_class_name_and_id_with_underscore) {
if (separate_class_name_and_id_with_underscore == null) {
separate_class_name_and_id_with_underscore = true;
}
return this.underscore(this.demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id");
},
// Removes the module part from the expression in the string.
//
// "BulletRecord.String.Inflections".demodulize() // => "Inflections"
// "Inflections".demodulize() // => "Inflections"
inflect.demodulize = function (class_name_in_module) {
return util.string.gsub(class_name_in_module, /^.*\./, '');
};
// Turns a number into an ordinal string used to denote the position in an
// ordered sequence such as 1st, 2nd, 3rd, 4th.
//
// ordinalize(1) // => "1st"
// ordinalize(2) // => "2nd"
// ordinalize(1002) // => "1002nd"
// ordinalize(1003) // => "1003rd"
// ordinalize(-11) // => "-11th"
// ordinalize(-1021) // => "-1021st"
ordinalize: function (number) {
var _ref;
number = parseInt(number);
if ((_ref = Math.abs(number) % 100) === 11 || _ref === 12 || _ref === 13) {
return "" + number + "th";
} else {
switch (Math.abs(number) % 10) {
case 1:
return "" + number + "st";
case 2:
return "" + number + "nd";
case 3:
return "" + number + "rd";
default:
return "" + number + "th";
}
// Creates a foreign key name from a class name.
// _separate_class_name_and_id_with_underscore_ sets whether
// the method should put '_' between the name and 'id'.
//
// "Message".foreign_key() // => "message_id"
// "Message".foreign_key(false) // => "messageid"
// "Admin::Post".foreign_key() // => "post_id"
inflect.foreign_key = function (class_name, separate_class_name_and_id_with_underscore) {
if (separate_class_name_and_id_with_underscore == null) {
separate_class_name_and_id_with_underscore = true;
}
return inflect.underscore(inflect.demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id");
};
// Turns a number into an ordinal string used to denote the position in an
// ordered sequence such as 1st, 2nd, 3rd, 4th.
//
// ordinalize(1) // => "1st"
// ordinalize(2) // => "2nd"
// ordinalize(1002) // => "1002nd"
// ordinalize(1003) // => "1003rd"
// ordinalize(-11) // => "-11th"
// ordinalize(-1021) // => "-1021st"
inflect.ordinalize = function (number) {
var _ref;
number = parseInt(number);
if ((_ref = Math.abs(number) % 100) === 11 || _ref === 12 || _ref === 13) {
return "" + number + "th";
} else {
switch (Math.abs(number) % 10) {
case 1:
return "" + number + "st";
case 2:
return "" + number + "nd";
case 3:
return "" + number + "rd";
default:
return "" + number + "th";
}
},
}
};
// Checks a given word for uncountability
//
// "money".uncountability() // => true
// "my money".uncountability() // => true
uncountability: function (word) {
return this.inflections.uncountables.some(function(ele, ind, arr) {
return word.match(new RegExp("(\\b|_)" + ele + "$", 'i')) != null;
});
},
// Checks a given word for uncountability
//
// "money".uncountability() // => true
// "my money".uncountability() // => true
inflect.uncountability = function (word) {
return inflect.inflections.uncountables.some(function(ele, ind, arr) {
return word.match(new RegExp("(\\b|_)" + ele + "$", 'i')) != null;
});
};
// Returns the plural form of the word in the string.
//
// "post".pluralize() // => "posts"
// "octopus".pluralize() // => "octopi"
// "sheep".pluralize() // => "sheep"
// "words".pluralize() // => "words"
// "CamelOctopus".pluralize() // => "CamelOctopi"
pluralize: function (word) {
var plural, result;
result = word;
if (word === '' || this.uncountability(word)) {
return result;
} else {
for (var i = 0; i < this.inflections.plurals.length; i++) {
plural = this.inflections.plurals[i];
result = result.gsub(plural[0], plural[1]);
if (word.match(plural[0]) != null) break;
}
return result;
// Returns the plural form of the word in the string.
//
// "post".pluralize() // => "posts"
// "octopus".pluralize() // => "octopi"
// "sheep".pluralize() // => "sheep"
// "words".pluralize() // => "words"
// "CamelOctopus".pluralize() // => "CamelOctopi"
inflect.pluralize = function (word) {
var plural, result;
result = word;
if (word === '' || inflect.uncountability(word)) {
return result;
} else {
for (var i = 0; i < inflect.inflections.plurals.length; i++) {
plural = inflect.inflections.plurals[i];
result = util.string.gsub(result, plural[0], plural[1]);
if (word.match(plural[0]) != null) break;
}
},
return result;
}
};
// The reverse of _pluralize_, returns the singular form of a word in a string.
//
// "posts".singularize() // => "post"
// "octopi".singularize() // => "octopus"
// "sheep".singularize() // => "sheep"
// "word".singularize() // => "word"
// "CamelOctopi".singularize() // => "CamelOctopus"
singularize: function (word) {
var result, singular;
result = word;
if (word === '' || this.uncountability(word)) {
return result;
} else {
for (var i = 0; i < this.inflections.singulars.length; i++) {
singular = this.inflections.singulars[i];
result = result.gsub(singular[0], singular[1]);
if (word.match(singular[0])) break;
}
return result;
// The reverse of _pluralize_, returns the singular form of a word in a string.
//
// "posts".singularize() // => "post"
// "octopi".singularize() // => "octopus"
// "sheep".singularize() // => "sheep"
// "word".singularize() // => "word"
// "CamelOctopi".singularize() // => "CamelOctopus"
inflect.singularize = function (word) {
var result, singular;
result = word;
if (word === '' || inflect.uncountability(word)) {
return result;
} else {
for (var i = 0; i < inflect.inflections.singulars.length; i++) {
singular = inflect.inflections.singulars[i];
result = util.string.gsub(result, singular[0], singular[1]);
if (word.match(singular[0])) break;
}
},
return result;
}
};
// Capitalizes the first word and turns underscores into spaces and strips a
// trailing "_id", if any. Like _titleize_, this is meant for creating pretty output.
//
// "employee_salary".humanize() // => "Employee salary"
// "author_id".humanize() // => "Author"
humanize: function (lower_case_and_underscored_word) {
var human, result;
result = lower_case_and_underscored_word;
for (var i = 0; i < this.inflections.humans.length; i++) {
human = this.inflections.humans[i];
result = result.gsub(human[0], human[1]);
}
return result.gsub(/_id$/, "").gsub(/_/, " ").capitalize(true);
},
// Capitalizes the first word and turns underscores into spaces and strips a
// trailing "_id", if any. Like _titleize_, this is meant for creating pretty output.
//
// "employee_salary".humanize() // => "Employee salary"
// "author_id".humanize() // => "Author"
inflect.humanize = function (lower_case_and_underscored_word) {
var human, result;
result = lower_case_and_underscored_word;
for (var i = 0; i < inflect.inflections.humans.length; i++) {
human = inflect.inflections.humans[i];
result = util.string.gsub(result, human[0], human[1]);
}
result = util.string.gsub(result, /_id$/, "");
result = util.string.gsub(result, /_/, " ");
return util.string.capitalize(result, true);
};
// Capitalizes all the words and replaces some characters in the string to create
// a nicer looking title. _titleize_ is meant for creating pretty output. It is not
// used in the Bullet internals.
//
//
// "man from the boondocks".titleize() // => "Man From The Boondocks"
// "x-men: the last stand".titleize() // => "X Men: The Last Stand"
titleize: function (word) {
var self;
self = this.humanize(this.underscore(word));
self = self.gsub(/[^a-zA-Z:']/, ' ');
return self.capitalize();
},
// Capitalizes all the words and replaces some characters in the string to create
// a nicer looking title. _titleize_ is meant for creating pretty output. It is not
// used in the Bullet internals.
//
//
// "man from the boondocks".titleize() // => "Man From The Boondocks"
// "x-men: the last stand".titleize() // => "X Men: The Last Stand"
inflect.titleize = function (word) {
var self;
self = inflect.humanize(inflect.underscore(word));
self = util.string.gsub(self, /[^a-zA-Z:']/, ' ');
return util.string.capitalize(self);
};
// Create the name of a table like Bullet does for models to table names. This method
// uses the _pluralize_ method on the last word in the string.
//
// "RawScaledScorer".tableize() // => "raw_scaled_scorers"
// "egg_and_ham".tableize() // => "egg_and_hams"
// "fancyCategory".tableize() // => "fancy_categories"
tableize: function (class_name) {
return this.pluralize(this.underscore(class_name));
},
// Create the name of a table like Bullet does for models to table names. This method
// uses the _pluralize_ method on the last word in the string.
//
// "RawScaledScorer".tableize() // => "raw_scaled_scorers"
// "egg_and_ham".tableize() // => "egg_and_hams"
// "fancyCategory".tableize() // => "fancy_categories"
inflect.tableize = function (class_name) {
return inflect.pluralize(inflect.underscore(class_name));
};
// Create a class name from a plural table name like Bullet does for table names to models.
// Note that this returns a string and not a Class.
//
// "egg_and_hams".classify() // => "EggAndHam"
// "posts".classify() // => "Post"
//
// Singular names are not handled correctly:
//
// "business".classify() // => "Busines"
classify: function (table_name) {
return this.camelize(this.singularize(table_name.gsub(/.*\./, '')));
}
};
// Create a class name from a plural table name like Bullet does for table names to models.
// Note that this returns a string and not a Class.
//
// "egg_and_hams".classify() // => "EggAndHam"
// "posts".classify() // => "Post"
//
// Singular names are not handled correctly:
//
// "business".classify() // => "Busines"
inflect.classify = function (table_name) {
return inflect.camelize(inflect.singularize(util.string.gsub(table_name, /.*\./, '')));
}
{
"name": "i",
"version": "0.2.0",
"version": "0.3.0",
"author": "Pavan Kumar Sunkara <pavan.sss1991@gmail.com> (pksunkara.github.com)",

@@ -29,3 +29,3 @@ "description": "custom inflections for nodejs",

"scripts": {
"test": "vows --spec $(find test -name '*-test.js')"
"test": "./node_modules/.bin/vows --spec $(find test -name '*-test.js')"
},

@@ -32,0 +32,0 @@ "contributors": [

@@ -16,3 +16,3 @@ # inflect

```js
var inflect = require('i');
var inflect = require('i')();
```

@@ -27,2 +27,8 @@

only if `true` is passed while initiating
```js
var inflect = require('i')(true);
```
### Pluralize

@@ -29,0 +35,0 @@

@@ -8,5 +8,2 @@ (function() {

require('../../lib/utils/array');
require('../../lib/utils/string');
vows.describe('Module Inflector inflections').addBatch({

@@ -13,0 +10,0 @@ 'Test inflector inflections': {

(function() {
var assert, cases, vows;
var assert, cases, vows, util;

@@ -8,4 +8,3 @@ vows = require('vows');

require('../../lib/utils/array');
require('../../lib/utils/string');
util = require('../../lib/util');

@@ -184,3 +183,3 @@ cases = require('./cases');

i = _ref2[_j];
_results.push(assert.equal(topic.pluralize(i.capitalize()), words[i].capitalize()));
_results.push(assert.equal(topic.pluralize(util.string.capitalize(i)), util.string.capitalize(words[i])));
}

@@ -201,3 +200,3 @@ return _results;

i = _ref2[_j];
_results.push(assert.equal(topic.pluralize(words[i].capitalize()), words[i].capitalize()));
_results.push(assert.equal(topic.pluralize(util.string.capitalize(words[i])), util.string.capitalize(words[i])));
}

@@ -230,3 +229,3 @@ return _results;

i = _ref2[_j];
_results.push(assert.equal(topic.singularize(words[i].capitalize()), i.capitalize()));
_results.push(assert.equal(topic.singularize(util.string.capitalize(words[i])), util.string.capitalize(i)));
}

@@ -233,0 +232,0 @@ return _results;

(function() {
var assert, vows;
var assert, vows, util;

@@ -8,3 +8,3 @@ vows = require('vows');

require('../../lib/utils/array');
util = require('../../lib/util');

@@ -16,13 +16,13 @@ vows.describe('Module core extension Array').addBatch({

'first element': function(topic) {
return assert.deepEqual(topic.del('a'), ['b', 'c']);
return assert.deepEqual(util.array.del(topic, 'a'), ['b', 'c']);
},
'middle element': function(topic) {
return assert.deepEqual(topic.del('b'), ['a', 'c']);
return assert.deepEqual(util.array.del(topic, 'b'), ['a', 'c']);
},
'last element': function(topic) {
return assert.deepEqual(topic.del('c'), ['a', 'b']);
return assert.deepEqual(util.array.del(topic, 'c'), ['a', 'b']);
}
},
'element does not exist': function(topic) {
return assert.deepEqual(topic.del('d'), ['a', 'b', 'c']);
return assert.deepEqual(util.array.del(topic, 'd'), ['a', 'b', 'c']);
}

@@ -33,6 +33,6 @@ },

'first': function(topic) {
return assert.equal(topic.first(), 'a');
return assert.equal(util.array.first(topic), 'a');
},
'last': function(topic) {
return assert.equal(topic.last(), 'c');
return assert.equal(util.array.last(topic), 'c');
}

@@ -39,0 +39,0 @@ }

(function() {
var assert, vows;
var assert, vows, util;

@@ -8,4 +8,3 @@ vows = require('vows');

require('../../lib/utils/array');
require('../../lib/utils/string');
util = require('../../lib/util');

@@ -16,3 +15,3 @@ vows.describe('Module core extension String').addBatch({

'join the keys': function(topic) {
return assert.equal(topic.value(), 'bullet');
return assert.equal(util.string.value(topic), 'bullet');
}

@@ -23,9 +22,9 @@ },

'when no args': function(topic) {
return assert.equal(topic.gsub(), 'bullet');
return assert.equal(util.string.gsub(topic), 'bullet');
},
'when only 1 arg': function(topic) {
return assert.equal(topic.gsub(/./), 'bullet');
return assert.equal(util.string.gsub(topic, /./), 'bullet');
},
'when given proper args': function(topic) {
return assert.equal(topic.gsub(/[aeiou]/, '*'), 'b*ll*t');
return assert.equal(util.string.gsub(topic, /[aeiou]/, '*'), 'b*ll*t');
},

@@ -35,3 +34,3 @@ 'when replacement is a function': {

var str;
str = topic.gsub(/([aeiou])(.)/, function($) {
str = util.string.gsub(topic, /([aeiou])(.)/, function($) {
return "<" + $[1] + ">" + $[2];

@@ -43,3 +42,3 @@ });

var str;
str = topic.gsub(/[aeiou]/, function($) {
str = util.string.gsub(topic, /[aeiou]/, function($) {
return "<" + $[1] + ">";

@@ -52,6 +51,6 @@ });

'with many groups': function(topic) {
return assert.equal(topic.gsub(/([aeiou])(.)/, '<$1>$2'), 'b<u>ll<e>t');
return assert.equal(util.string.gsub(topic, /([aeiou])(.)/, '<$1>$2'), 'b<u>ll<e>t');
},
'with no groups': function(topic) {
return assert.equal(topic.gsub(/[aeiou]/, '<$1>'), 'b<u>ll<e>t');
return assert.equal(util.string.gsub(topic, /[aeiou]/, '<$1>'), 'b<u>ll<e>t');
}

@@ -63,3 +62,3 @@ }

'normal': function(topic) {
return assert.equal(topic.capitalize(), 'Employee Salary');
return assert.equal(util.string.capitalize(topic), 'Employee Salary');
}

@@ -70,12 +69,12 @@ },

'only first letter should be upcase': function(topic) {
return assert.equal(topic.upcase(), 'Bullet');
return assert.equal(util.string.upcase(topic), 'Bullet');
},
'letter after underscore': function(topic) {
return assert.equal('bullet_record'.upcase(), 'Bullet_Record');
return assert.equal(util.string.upcase('bullet_record'), 'Bullet_Record');
},
'letter after slash': function(topic) {
return assert.equal('bullet_record/errors'.upcase(), 'Bullet_Record/Errors');
return assert.equal(util.string.upcase('bullet_record/errors'), 'Bullet_Record/Errors');
},
'no letter after space': function(topic) {
return assert.equal('employee salary'.upcase(), 'Employee salary');
return assert.equal(util.string.upcase('employee salary'), 'Employee salary');
}

@@ -86,9 +85,9 @@ },

'only first letter should be downcase': function(topic) {
return assert.equal(topic.downcase(), 'bULLET');
return assert.equal(util.string.downcase(topic), 'bULLET');
},
'letter after underscore': function(topic) {
return assert.equal('BULLET_RECORD'.downcase(), 'bULLET_rECORD');
return assert.equal(util.string.downcase('BULLET_RECORD'), 'bULLET_rECORD');
},
'letter after slash': function(topic) {
return assert.equal('BULLET_RECORD/ERRORS'.downcase(), 'bULLET_rECORD/eRRORS');
return assert.equal(util.string.downcase('BULLET_RECORD/ERRORS'), 'bULLET_rECORD/eRRORS');
}

@@ -95,0 +94,0 @@ }

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