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

autoprefixer

Package Overview
Dependencies
Maintainers
2
Versions
244
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

autoprefixer - npm Package Compare versions

Comparing version 1.0.20140213 to 1.1.20140218

lib/hacks/break-inside.js

11

ChangeLog.md

@@ -0,1 +1,12 @@

## 1.1 “Nutrisco et extingo”
* Add source map annotation comment support.
* Add inline source map support.
* Autodetect previous source map.
* Fix source maps support on Windows.
* Fix source maps support in subdirectory.
* Add option `cascade` to create nice visual cascade of prefixes.
* Fix flexbox support for IE 10 (by Roland Warmerdam).
* Better `break-inside` support.
* Fix prefixing, when two same properties are near.
## 1.0 “Plus ultra”

@@ -2,0 +13,0 @@ * Source map support.

42

lib/autoprefixer.js
(function() {
var Autoprefixer, Browsers, Prefixes, autoprefixer, infoCache, postcss,
var Autoprefixer, Browsers, Prefixes, autoprefixer, infoCache, isPlainObject, postcss,
__slice = [].slice,

@@ -14,9 +14,19 @@ __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

isPlainObject = function(obj) {
return Object.prototype.toString.apply(obj) === '[object Object]';
};
autoprefixer = function() {
var browsers, prefixes, reqs;
var browsers, options, prefixes, reqs;
reqs = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (reqs.length === 1 && reqs[0] instanceof Array) {
reqs = reqs[0];
if (reqs.length === 1 && isPlainObject(reqs[0])) {
options = reqs[0];
reqs = void 0;
} else if (reqs.length === 0 || (reqs.length === 1 && (reqs[0] == null))) {
reqs = void 0;
} else if (reqs.length <= 2 && (reqs[0] instanceof Array || (reqs[0] == null))) {
options = reqs[1];
reqs = reqs[0];
} else if (typeof reqs[reqs.length - 1] === 'object') {
options = reqs.pop();
}

@@ -27,3 +37,3 @@ if (reqs == null) {

browsers = new Browsers(autoprefixer.data.browsers, reqs);
prefixes = new Prefixes(autoprefixer.data.prefixes, browsers);
prefixes = new Prefixes(autoprefixer.data.prefixes, browsers, options);
return new Autoprefixer(prefixes, autoprefixer.data);

@@ -38,5 +48,6 @@ };

Autoprefixer = (function() {
function Autoprefixer(prefixes, data) {
function Autoprefixer(prefixes, data, options) {
this.prefixes = prefixes;
this.data = data;
this.options = options != null ? options : {};
this.postcss = __bind(this.postcss, this);

@@ -53,21 +64,2 @@ this.browsers = this.prefixes.browsers.selected;

Autoprefixer.prototype.compile = function(str, options) {
var fixed, name, value;
if (options == null) {
options = {};
}
fixed = {};
for (name in options) {
value = options[name];
if (name === 'file') {
name = 'from';
}
fixed[name] = value;
}
if (typeof console !== "undefined" && console !== null) {
console.warn('autoprefixer: replace compile() to process(). ' + 'Method compile() is deprecated and will be removed in 1.1.');
}
return this.process(str, fixed).css;
};
Autoprefixer.prototype.postcss = function(css) {

@@ -74,0 +66,0 @@ this.prefixes.processor.remove(css);

@@ -19,2 +19,4 @@ (function() {

this.inputFiles = [];
this.processOptions = {};
this.processorOptions = {};
this.parseArguments();

@@ -24,3 +26,3 @@ }

Binary.prototype.help = function() {
return 'Usage: autoprefixer [OPTION...] FILES\n\nParse CSS files and add prefixed properties and values.\n\nOptions:\n -b, --browsers BROWSERS add prefixes for selected browsers\n -o, --output FILE set output file\n -d, --dir DIR set output dir\n -m, --map generate source map\n -i, --info show selected browsers and properties\n -h, --help show help text\n -v, --version print program version';
return 'Usage: autoprefixer [OPTION...] FILES\n\nParse CSS files and add prefixed properties and values.\n\nOptions:\n -b, --browsers BROWSERS add prefixes for selected browsers\n -o, --output FILE set output file\n -d, --dir DIR set output dir\n -m, --map generate source map\n --no-map skip source map even if previous map exists\n -I, --inline-map inline map by data:uri to annotation comment\n --no-map-annotation skip source map annotation comment is CSS\n -c, --cascade create nice visual cascade of prefixes\n -i, --info show selected browsers and properties\n -h, --help show help text\n -v, --version print program version';
};

@@ -70,4 +72,18 @@

case '--map':
this.sourceMap = true;
this.processOptions.map = true;
break;
case '--no-map':
this.processOptions.map = false;
break;
case '-I':
case '--inline-map':
this.processOptions.inlineMap = true;
break;
case '--no-map-annotation':
this.processOptions.mapAnnotation = false;
break;
case '-c':
case '--cascade':
this.processorOptions.cascade = true;
break;
case '-b':

@@ -162,8 +178,13 @@ case '--browsers':

Binary.prototype.compiler = function() {
return this.compilerCache || (this.compilerCache = autoprefixer(this.requirements));
return this.compilerCache || (this.compilerCache = autoprefixer(this.requirements, this.processorOptions));
};
Binary.prototype.compileCSS = function(css, output, input) {
var error, opts, result;
var error, name, opts, result, value, _ref;
opts = {};
_ref = this.processOptions;
for (name in _ref) {
value = _ref[name];
opts[name] = value;
}
if (input) {

@@ -175,5 +196,2 @@ opts.from = input;

}
if (this.sourceMap) {
opts.map = true;
}
if (opts.map && input && fs.existsSync(input + '.map')) {

@@ -180,0 +198,0 @@ opts.map = fs.readFileSync(input + '.map').toString();

@@ -26,2 +26,9 @@ (function() {

Browsers.withPrefix = function(value) {
if (!this.prefixesRegexp) {
this.prefixesRegexp = RegExp("" + (this.prefixes().join('|')));
}
return this.prefixesRegexp.test(value);
};
function Browsers(data, requirements) {

@@ -28,0 +35,0 @@ this.data = data;

(function() {
var Browsers, Declaration, Prefixer, vendor,
var Browsers, Declaration, Prefixer, utils, vendor,
__hasProp = {}.hasOwnProperty,

@@ -12,2 +12,4 @@ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

utils = require('./utils');
Declaration = (function(_super) {

@@ -52,11 +54,65 @@ __extends(Declaration, _super);

Declaration.prototype.insert = function(decl, prefix) {
Declaration.prototype.needCascade = function(decl) {
return decl._autoprefixerCascade || (decl._autoprefixerCascade = !!this.all.options.cascade && decl.before.indexOf("\n") !== -1);
};
Declaration.prototype.maxPrefixed = function(prefixes, decl) {
var max, prefix, _i, _len;
if (decl._autoprefixerMax) {
return decl._autoprefixerMax;
}
max = 0;
for (_i = 0, _len = prefixes.length; _i < _len; _i++) {
prefix = prefixes[_i];
prefix = utils.removeNote(prefix);
if (prefix.length > max) {
max = prefix.length;
}
}
return decl._autoprefixerMax = max;
};
Declaration.prototype.calcBefore = function(prefixes, decl, prefix) {
var before, diff, i, max, _i;
if (prefix == null) {
prefix = '';
}
before = decl.before;
max = this.maxPrefixed(prefixes, decl);
diff = max - utils.removeNote(prefix).length;
for (i = _i = 0; 0 <= diff ? _i < diff : _i > diff; i = 0 <= diff ? ++_i : --_i) {
before += ' ';
}
return before;
};
Declaration.prototype.restoreBefore = function(decl) {
var lines, min;
lines = decl.before.split("\n");
min = lines[lines.length - 1];
this.all.group(decl).up(function(prefixed) {
var array, last;
array = prefixed.before.split("\n");
last = array[array.length - 1];
if (last.length < min.length) {
return min = last;
}
});
lines[lines.length - 1] = min;
return decl.before = lines.join("\n");
};
Declaration.prototype.insert = function(decl, prefix, prefixes) {
var cloned;
cloned = this.set(this.clone(decl), prefix);
if (cloned) {
return decl.parent.insertBefore(decl, cloned);
if (!cloned) {
return;
}
if (this.needCascade(decl)) {
cloned.before = this.calcBefore(prefixes, decl, prefix);
}
return decl.parent.insertBefore(decl, cloned);
};
Declaration.prototype.add = function(decl, prefix) {
Declaration.prototype.add = function(decl, prefix, prefixes) {
var already, prefixed;

@@ -70,5 +126,17 @@ prefixed = this.prefixed(decl.prop, prefix);

}
return this.insert(decl, prefix);
return this.insert(decl, prefix, prefixes);
};
Declaration.prototype.process = function(decl) {
var prefixes;
if (this.needCascade(decl)) {
this.restoreBefore(decl);
if (prefixes = Declaration.__super__.process.apply(this, arguments)) {
return decl.before = this.calcBefore(prefixes, decl);
}
} else {
return Declaration.__super__.process.apply(this, arguments);
}
};
Declaration.prototype.old = function(prop, prefix) {

@@ -75,0 +143,0 @@ return [this.prefixed(prop, prefix)];

@@ -17,6 +17,6 @@ (function() {

FlexBasis.names = ['flex-basis'];
FlexBasis.names = ['flex-basis', 'flex-preferred-size'];
FlexBasis.prototype.normalize = function() {
return 'flex';
return 'flex-basis';
};

@@ -28,3 +28,3 @@

if (spec === 2012) {
return prefix + 'flex';
return prefix + 'flex-preferred-size';
} else {

@@ -38,7 +38,3 @@ return FlexBasis.__super__.prefixed.apply(this, arguments);

_ref = flexSpec(prefix), spec = _ref[0], prefix = _ref[1];
if (spec === 2012) {
decl.prop = prefix + 'flex';
decl.value = '0 1 ' + decl.value;
return decl;
} else if (spec === 'final') {
if (spec === 2012 || spec === 'final') {
return FlexBasis.__super__.set.apply(this, arguments);

@@ -45,0 +41,0 @@ }

@@ -23,3 +23,3 @@ (function() {

FlexDirection.prototype.insert = function(decl, prefix) {
FlexDirection.prototype.insert = function(decl, prefix, prefixes) {
var already, cloned, dir, orient, spec, value, _ref;

@@ -40,2 +40,5 @@ _ref = flexSpec(prefix), spec = _ref[0], prefix = _ref[1];

cloned.value = orient;
if (this.needCascade(decl)) {
cloned.before = this.calcBefore(prefixes, decl, prefix);
}
decl.parent.insertBefore(decl, cloned);

@@ -45,2 +48,5 @@ cloned = this.clone(decl);

cloned.value = dir;
if (this.needCascade(decl)) {
cloned.before = this.calcBefore(prefixes, decl, prefix);
}
return decl.parent.insertBefore(decl, cloned);

@@ -47,0 +53,0 @@ } else {

@@ -17,3 +17,3 @@ (function() {

Flex.names = ['flex-grow'];
Flex.names = ['flex-grow', 'flex-positive'];

@@ -30,3 +30,3 @@ Flex.prototype.normalize = function() {

} else if (spec === 2012) {
return prefix + 'flex';
return prefix + 'flex-positive';
} else {

@@ -33,0 +33,0 @@ return Flex.__super__.prefixed.apply(this, arguments);

@@ -17,6 +17,6 @@ (function() {

FlexShrink.names = ['flex-shrink'];
FlexShrink.names = ['flex-shrink', 'flex-negative'];
FlexShrink.prototype.normalize = function() {
return 'flex';
return 'flex-shrink';
};

@@ -28,3 +28,3 @@

if (spec === 2012) {
return prefix + 'flex';
return prefix + 'flex-negative';
} else {

@@ -38,7 +38,3 @@ return FlexShrink.__super__.prefixed.apply(this, arguments);

_ref = flexSpec(prefix), spec = _ref[0], prefix = _ref[1];
if (spec === 2012) {
decl.prop = prefix + 'flex';
decl.value = '0 ' + decl.value;
return decl;
} else if (spec === 'final') {
if (spec === 2012 || spec === 'final') {
return FlexShrink.__super__.set.apply(this, arguments);

@@ -45,0 +41,0 @@ }

@@ -19,2 +19,7 @@ (function() {

Flex.oldValues = {
'auto': '1',
'none': '0'
};
Flex.prototype.prefixed = function(prop, prefix) {

@@ -30,3 +35,3 @@ var spec, _ref;

Flex.prototype.normalize = function(prop) {
Flex.prototype.normalize = function() {
return 'flex';

@@ -40,2 +45,3 @@ };

decl.value = decl.value.split(' ')[0];
decl.value = Flex.oldValues[decl.value] || decl.value;
return Flex.__super__.set.call(this, decl, prefix);

@@ -42,0 +48,0 @@ } else {

@@ -17,2 +17,6 @@ (function() {

Placeholder.prototype.possible = function() {
return Placeholder.__super__.possible.apply(this, arguments).concat('-moz- old');
};
Placeholder.prototype.prefixed = function(prefix) {

@@ -19,0 +23,0 @@ if ('-webkit-' === prefix) {

@@ -57,3 +57,3 @@ (function() {

Prefixer.prototype.process = function(node) {
var parent, prefix, _i, _len, _ref, _results;
var parent, prefix, prefixes, _i, _j, _len, _len1, _ref;
if (!this.check(node)) {

@@ -63,4 +63,4 @@ return;

parent = this.parentPrefix(node);
prefixes = [];
_ref = this.prefixes;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {

@@ -71,5 +71,9 @@ prefix = _ref[_i];

}
_results.push(this.add(node, prefix));
prefixes.push(prefix);
}
return _results;
for (_j = 0, _len1 = prefixes.length; _j < _len1; _j++) {
prefix = prefixes[_j];
this.add(node, prefix, prefixes);
}
return prefixes;
};

@@ -76,0 +80,0 @@

(function() {
var Declaration, Keyframes, Prefixes, Processor, Selector, Value, declsCache, utils, vendor;
var Browsers, Declaration, Keyframes, Prefixes, Processor, Selector, Value, declsCache, utils, vendor;

@@ -8,8 +8,10 @@ utils = require('./utils');

Declaration = require('./declaration');
Processor = require('./processor');
Declaration = require('./declaration');
Keyframes = require('./keyframes');
Browsers = require('./browsers');
Selector = require('./selector');

@@ -43,2 +45,4 @@

Declaration.hack(require('./hacks/break-inside'));
Declaration.hack(require('./hacks/border-image'));

@@ -67,6 +71,7 @@

Prefixes = (function() {
function Prefixes(data, browsers) {
function Prefixes(data, browsers, options) {
var _ref;
this.data = data;
this.browsers = browsers;
this.options = options != null ? options : {};
_ref = this.preprocess(this.select(this.data)), this.add = _ref[0], this.remove = _ref[1];

@@ -198,3 +203,3 @@ this.processor = new Processor(this);

prefix = prefixes[_j];
remove.selectors.push(selector.checker(prefix));
remove.selectors.push(selector.old(prefix));
}

@@ -293,6 +298,18 @@ } else if (name[0] === '@') {

other = rule.decls[index];
if (_this.unprefixed(other.prop) !== unprefixed) {
break;
} else if (callback(other) === true) {
return true;
if (other.type === 'decl') {
if (step === -1 && other.prop === unprefixed) {
if (!Browsers.withPrefix(other.value)) {
break;
}
}
if (_this.unprefixed(other.prop) !== unprefixed) {
break;
} else if (callback(other) === true) {
return true;
}
if (step === +1 && other.prop === unprefixed) {
if (!Browsers.withPrefix(other.value)) {
break;
}
}
}

@@ -299,0 +316,0 @@ index += step;

@@ -67,3 +67,3 @@ (function() {

return function(rule, i) {
if (checker(rule)) {
if (checker.check(rule)) {
return rule.parent.remove(i);

@@ -70,0 +70,0 @@ }

(function() {
var Prefixer, Selector, utils,
var Browsers, OldSelector, Prefixer, Selector, utils,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
OldSelector = require('./old-selector');
Prefixer = require('./prefixer');
Browsers = require('./browsers');
utils = require('./utils');

@@ -20,7 +24,5 @@

Selector.prototype.check = function(rule, prefix) {
var name;
name = prefix ? this.prefixed(prefix) : this.name;
if (rule.selector.indexOf(name) !== -1) {
return !!rule.selector.match(this.regexp(prefix));
Selector.prototype.check = function(rule) {
if (rule.selector.indexOf(this.name) !== -1) {
return !!rule.selector.match(this.regexp());
} else {

@@ -31,10 +33,2 @@ return false;

Selector.prototype.checker = function(prefix) {
return (function(_this) {
return function(rule) {
return _this.check(rule, prefix);
};
})(this);
};
Selector.prototype.prefixed = function(prefix) {

@@ -50,5 +44,51 @@ return this.name.replace(/^([^\w]*)/, '$1' + prefix);

name = prefix ? this.prefixed(prefix) : this.name;
return this.regexpCache = RegExp("(^|[^:\"'=])" + (utils.escapeRegexp(name)), "gi");
return this.regexpCache[prefix] = RegExp("(^|[^:\"'=])" + (utils.escapeRegexp(name)), "gi");
};
Selector.prototype.possible = function() {
return Browsers.prefixes();
};
Selector.prototype.prefixeds = function(rule) {
var prefix, prefixeds, _i, _len, _ref;
if (rule._autoprefixerPrefixeds) {
return rule._autoprefixerPrefixeds;
}
prefixeds = {};
_ref = this.possible();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
prefix = _ref[_i];
prefixeds[prefix] = this.replace(rule.selector, prefix);
}
return rule._autoprefixerPrefixeds = prefixeds;
};
Selector.prototype.already = function(rule, prefixeds, prefix) {
var before, index, key, prefixed, some;
index = rule.parent.index(rule) - 1;
while (index >= 0) {
before = rule.parent.rules[index];
if (before.type !== 'rule') {
return false;
}
some = false;
for (key in prefixeds) {
prefixed = prefixeds[key];
if (before.selector === prefixed) {
if (prefix === key) {
return true;
} else {
some = true;
break;
}
}
}
if (!some) {
return false;
}
index -= 1;
}
return false;
};
Selector.prototype.replace = function(selector, prefix) {

@@ -59,11 +99,9 @@ return selector.replace(this.regexp(), '$1' + this.prefixed(prefix));

Selector.prototype.add = function(rule, prefix) {
var cloned, prefixed;
prefixed = this.replace(rule.selector, prefix);
if (rule.parent.some(function(i) {
return i.selector === prefixed;
})) {
var cloned, prefixeds;
prefixeds = this.prefixeds(rule);
if (this.already(rule, prefixeds, prefix)) {
return;
}
cloned = this.clone(rule, {
selector: prefixed
selector: prefixeds[prefix]
});

@@ -73,2 +111,6 @@ return rule.parent.insertBefore(rule, cloned);

Selector.prototype.old = function(prefix) {
return new OldSelector(this, prefix);
};
return Selector;

@@ -75,0 +117,0 @@

{
"name": "autoprefixer",
"version": "1.0.20140213",
"version": "1.1.20140218",
"description": "Parse CSS and add vendor prefixes to CSS rules using values from the Can I Use website",

@@ -13,3 +13,3 @@ "keywords": ["css", "prefix", "postprocessor", "postcss"],

"dependencies": {
"postcss": "~0.2",
"postcss": "~0.3.1",
"fs-extra": "~0.8.1"

@@ -19,3 +19,3 @@ },

"coffee-script": "1.7.1",
"browserify": "3.28.2",
"browserify": "3.30.1",
"should": "3.1.2",

@@ -22,0 +22,0 @@ "stylus": "0.42.2",

@@ -137,5 +137,5 @@ # Autoprefixer

Load GitHub styles
Autoprefixer: 489 ms
Compass: 4156 ms (8.5 times slower)
Stylus: 4165 ms (8.5 times slower)
Autoprefixer: 450 ms
Compass: 3825 ms (8.5 times slower)
Stylus: 3720 ms (8.3 times slower)
```

@@ -190,32 +190,47 @@

Autoprefixer will generate a source map if you set `map` option to `true`.
You must set input and output CSS files paths (by `from` and `to` options)
to generate a correct map.
Autoprefixer can modify previous source map (for example, from Sass).
it will autodetect previous map if it will be in annotation comment or in file
near input CSS. You can disable source map with `map: false` or set previous
source map content manually to `map` option (as string or JS object).
```js
var result = autoprefixer.process(css, {
map: true,
from: 'main.css',
to: 'main.out.css'
map: fs.readFileSync('main.sass.css.map'),
from: 'main.sass.css',
to: 'main.min.css'
});
result.css //=> Prefixed CSS
result.map //=> Source map content
result.css //=> CSS with source map annotation comment
result.map //=> Source map from main.sass to main.min.css
fs.writeFileSync('main.out.css.map', result.map);
fs.writeFileSync('main.min.css.map', result.map);
```
Autoprefixer can also modify previous source map (for example, from Sass
compilation). Just set original source map content (as string or JS object)
to `map` option:
Autoprefixer supports inline source maps too. If input CSS contains annotation
from previous step with map in `data:uri`, Autoprefixer will update source map
with prefixes changes and inine new map back to output CSS.
You can read more about source map options in
[PostCSS documentation](https://github.com/ai/postcss#source-map-1).
## Visual Cascade
Autoprefixer can change CSS indentation to create nice visual cascade
of prefixes. You need to send `cascade: true` option to processor constructor:
```js
var result = autoprefixer.process(css, {
map: fs.readFileSync('main.sass.css.map'),
from: 'main.sass.css',
to: 'main.min.css'
});
autoprefixer("> 1 %", "last 2 version", { cascade: true }).process(css).css
```
result.map //=> Source map from main.sass to main.min.css
and, if CSS will be uncompressed, output would be like:
```css
a {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box
}
```

@@ -290,2 +305,38 @@

### Why Autoprefixer uses CoffeeScript?
JavaScript is very popular, but this is the same reason why its syntax does not
evolve. There is an entire Internet with a lot of legacy code which should
be supported by browsers. If developers will add an inappropriate feature then
it can’t be removed in next versions but must be supported for a very long time.
This is very bad for innovation. To create new, we need to experiment and
to choose.
As a result JavaScript doesn’t have even basic syntax features, which are
present in other languages like Ruby or Python. There are no string
interpolation, short lambda syntax, foreach statement for arrays, string and
arrays slicing, etc. This features are really important, so they will be in
ECMAScript 6 (first update of JS syntax after 15 years). But this
new specification is not still released and, of cource, we must wait until
all browsers will support it.
With JavaScript preprocessors like CoffeeScript or TypeScript we can bring
innovation back. We can add new operator and use it right now, without waiting
for support in all browsers.
Autoprefixer was written in pure JavaScript before. But CoffeeScript made
Autoprefixer code much cleaner and more readable. Often 2 lines of code
become 1.
Don’t be afraid of CoffeeScript. It is just a new syntax, not another language
(like ClojureScript). You can open [examples on CoffeeScript.org] and start
to code. After a week your eyes will adjust and you will see, that CoffeeScript
is cleaner and more readable.
Situation with CoffeeScript and JavaScript is absolutely the same as with
CSS preprocessors and postprocessors. How we can develop CSS postprocessor
and avoid JS preproccesor :).
[examples on CoffeeScript.org]: http://coffeescript.org/
## Usage

@@ -316,3 +367,2 @@

require 'autoprefixer-rails'
require 'csso'

@@ -319,0 +369,0 @@ on_stylesheet_saved do |file|

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