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

svgo

Package Overview
Dependencies
Maintainers
1
Versions
104
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

svgo - npm Package Compare versions

Comparing version 0.0.9 to 0.1.0

.svgo.yml

30

CHANGELOG.md

@@ -0,1 +1,29 @@

### [ [>](//github.com/svg/svgo/tree/v0.1.0) ] 0.1.0 / 22.11.2012
* new plugin [plugins/removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) (close [#6](https://github.com/svg/svgo/issues/6))
* plugins/convertPathData: convert straight curves into lines segments (close [#17](https://github.com/svg/svgo/issues/17)); remove an absolute coords conversions
* plugins/convertPathData: convert quadratic Bézier curveto into smooth shorthand (close [#31](https://github.com/svg/svgo/issues/31))
* plugins/convertPathData: convert curveto into smooth shorthand (close [#30](https://github.com/svg/svgo/issues/30))
* lib/svgo: global API refactoring (close [#37](https://github.com/svg/svgo/issues/37))
* lib/svgo: fatal and stupid error in stream chunks concatenation (fix [#40](https://github.com/svg/svgo/issues/40))
* lib/coa: batch folder optimization (close [#29](https://github.com/svg/svgo/issues/29))
* lib/coa: support arguments as aliases to `--input` and `--output` (close [#28](https://github.com/svg/svgo/issues/28))
* project logo by [Egor Bolhshakov](http://xizzzy.ru/)
* move modules to `./lib/svgo/`
* rename and convert `config.json` to `.svgo.yml`
* add [./docs/](https://github.com/svg/svgo/tree/master/docs)
* plugins/convertPathData: don't remove first `M` even if it's `0,0`
* plugins/convertPathData: stronger defense from infinite loop
* plugins/moveElemsAttrsToGroup: should affect only inheritable attributes (fix [#46](https://github.com/svg/svgo/issues/46))*
* plugins/removeComments: ignore comments which starts with '!' (close [#43](https://github.com/svg/svgo/issues/43))
* config: `cleanupAttrs` should be before `convertStyleToAttrs` (fix [#44](https://github.com/svg/svgo/issues/44))*
* lib/svgo/jsAPI: add `eachAttr()` optional context param
* temporarily remove PhantomJS and `--test` (close [#38](https://github.com/svg/svgo/issues/38))
* q@0.8.10 compatibility: 'end is deprecated, use done instead' fix
* add [Istanbul](https://github.com/gotwarlost/istanbul) code coverage
* update dependencies versions and gitignore
* README: add TODO section with versions milestones
* update README with License section
* update LICENSE with russian translation
* `.editorconfig`: 2 spaces for YAML
### [ [>](//github.com/svg/svgo/tree/v0.0.9) ] 0.0.9 / 29.10.2012

@@ -10,3 +38,3 @@ * [plugins how-to](https://github.com/svg/svgo/tree/master/plugins#readme) (close [#27](https://github.com/svg/svgo/issues/27))

* plugins/convertPathData: do not remove very first M from the path data (fix [#24](https://github.com/svg/svgo/issues/24))
* plugins/convertPathData: optimize path data in <glyph> and <missing-glyph> (close [#20](https://github.com/svg/svgo/issues/20))
* plugins/convertPathData: optimize path data in &lt;glyph&gt; and &lt;missing-glyph&gt; (close [#20](https://github.com/svg/svgo/issues/20))
* plugins/convertTransform: add patternTransform attribute to the process (close [#15](https://github.com/svg/svgo/issues/15))

@@ -13,0 +41,0 @@ * plugins/convertTransform: Firefox: removing extra space in front of negative number is alowed only in path data, but not in transform (fix [#12](https://github.com/svg/svgo/issues/12))

@@ -14,6 +14,9 @@ /**

var INHERIT = require('inherit'),
CONFIG = require('./config'),
SVG2JS = require('./svg2js'),
PLUGINS = require('./plugins'),
JS2SVG = require('./js2svg');
Q = require('q'),
FS = require('fs'),
CONFIG = require('./svgo/config'),
SVG2JS = require('./svgo/svg2js'),
PLUGINS = require('./svgo/plugins'),
JS2SVG = require('./svgo/js2svg'),
decodeSVGDatauri = require('./svgo/tools').decodeSVGDatauri;

@@ -26,3 +29,3 @@ /**

/**
* @param {Object} [config] config to extend
* @param {Object} [config] custom config to extend default
*

@@ -40,18 +43,25 @@ * @constructs

/**
* Main optimize function.
* Optimize SVG data from string.
*
* @param {String} svgdata input data
* @param {String} str input string
*
* @return {String} output data deferred promise
* @return {Object} output string deferred promise
*/
optimize: function(svgdata) {
fromString: function(str) {
str = decodeSVGDatauri(str);
return this.config
.then(function(config) {
return SVG2JS(svgdata, config.svg2js)
return SVG2JS(str, config.svg2js)
.then(function(jsdata) {
return JS2SVG(PLUGINS(jsdata, config.plugins), config.js2svg);
var out = JS2SVG(PLUGINS(jsdata, config.plugins), config.js2svg);
out.info.startBytes = Buffer.byteLength(str, 'utf-8');
out.info.endBytes = Buffer.byteLength(out.data, 'utf-8');
return out;
});

@@ -61,4 +71,50 @@

},
/**
* Optimize SVG data from Stream.
*
* @param {Object} stream input stream
*
* @return {Object} output string deferred promise
*/
fromStream: function(stream) {
var deferred = Q.defer(),
inputData = '',
self = this;
stream.pause();
stream
.on('data', function(chunk) {
inputData += chunk;
})
.once('end', function() {
deferred.resolve(inputData);
})
.resume();
return deferred.promise
.then(function(str) {
return self.fromString(str);
});
},
/**
* Optimize SVG data from file.
*
* @param {String} path file path
*
* @return {Object} output string deferred promise
*/
fromFile: function(path) {
return this.fromStream(FS.createReadStream(path, { encoding: 'utf8' }));
}
});

61

package.json
{
"name": "svgo",
"version": "0.0.9",
"version": "0.1.0",
"description": "Nodejs-based tool for optimizing SVG vector graphics files",
"keywords": [
"svgo",
"svg",
"optimize",
"minify"
],
"keywords": [ "svgo", "svg", "optimize", "minify" ],
"homepage": "http://svg.github.com/svgo/",
"bugs": {
"url": "https://github.com/svg/svgo/issues"
"url": "https://github.com/svg/svgo/issues",
"email": "svgo@soulshine.in"
},
"author": "Kir Belevich <kir@soulshine.in> (https://github.com/deepsweet)",
"contributors": [
"Sergey Belov <peimei@ya.ru> (http://github.com/arikon)"
],
"author": {
"name": "Kir Belevich",
"email": "kir@soulshine.in",
"url": "https://github.com/deepsweet"
},
"contributors": [{
"name": "Sergey Belov",
"email": "peimei@ya.ru",
"url": "http://github.com/arikon"
}],
"repository": {

@@ -24,23 +26,28 @@ "type": "git",

"main": "./lib/svgo.js",
"bin": {
"svgo": "./bin/svgo"
},
"directories": {
"bin": "./bin",
"lib": "./lib"
"lib": "./lib",
"example": "./examples"
},
"bin": {
"svgo": "./bin/svgo"
},
"scripts": {
"test": "./node_modules/.bin/mocha --reporter spec --require should --recursive"
"test": "./node_modules/.bin/mocha --reporter spec --require should --recursive",
"cover": "./node_modules/.bin/istanbul instrument --output lib-cov --no-compact --variable global.__coverage__ lib && ./node_modules/.bin/mocha --reporter mocha-istanbul --require should test/config test/svg2js"
},
"dependencies": {
"sax": "0.4.x",
"q": "0.8.x",
"q-fs": "",
"coa": "0.3.x",
"sax": "~0.4",
"q": "~0.8.10",
"q-fs": "~0.1",
"coa": "~0.3.7",
"inherit": "",
"node.extend": ""
"node.extend": "",
"yamljs": "~0.1.3"
},
"devDependencies": {
"mocha": "1.4.x",
"should": ""
"mocha": "~1.6",
"should": "~1",
"istanbul": "~0.1",
"mocha-istanbul": ""
},

@@ -50,8 +57,6 @@ "engines": {

},
"licenses": [
{
"licenses": [{
"type": "MIT",
"url": "https://raw.github.com/svg/svgo/master/LICENSE"
}
]
}]
}

@@ -0,1 +1,820 @@

// http://www.w3.org/TR/SVG/intro.html#Definitions
var elemsGroups = exports.elemsGroups = {
animation: ['animate', 'animateColor', 'animateMotion', 'animateTransform', 'set'],
descriptive: ['desc', 'metadata', 'title'],
shape: ['circle', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'rect'],
structural: ['defs', 'g', 'svg', 'symbol', 'use'],
gradient: ['linearGradient', 'radialGradient'],
container: ['a', 'defs', 'glyph', 'g', 'marker', 'mask', 'missing-glyph', 'pattern', 'svg', 'switch', 'symbol']
};
// var defaults = exports.defaults = {
// 'externalResourcesRequired': 'false',
// 'xlink:type': 'simple'
// };
// http://www.w3.org/TR/SVG/intro.html#Definitions
var attrsGroups = exports.attrsGroups = {
animationAddition: ['additive', 'accumulate'],
animationAttributeTarget: ['attributeType', 'attributeName'],
animationEvent: ['onbegin', 'onend', 'onrepeat', 'onload'],
animationTiming: ['begin', 'dur', 'end', 'min', 'max', 'restart', 'repeatCount', 'repeatDur', 'fill'],
animationValue: ['calcMode', 'values', 'keyTimes', 'keySplines', 'from', 'to', 'by'],
conditionalProcessing: ['requiredFeatures', 'requiredExtensions', 'systemLanguage'],
core: ['id', 'xml:base', 'xml:lang', 'xml:space'],
graphicalEvent: ['onfocusin', 'onfocusout', 'onactivate', 'onclick', 'onmousedown', 'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout', 'onload'],
presentation: ['alignment-baseline', 'baseline-shift', 'clip', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cursor', 'direction', 'display', 'dominant-baseline', 'enable-background', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'image-rendering', 'kerning', 'letter-spacing', 'lighting-color', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'overflow', 'pointer-events', 'shape-rendering', 'stop-color', 'stop-opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-decoration', 'text-rendering', 'unicode-bidi', 'visibility', 'word-spacing', 'writing-mode'],
xlink: ['xlink:href', 'xlink:show', 'xlink:actuate', 'xlink:type', 'xlink:role', 'xlink:arcrole', 'xlink:title'],
documentEvent: ['onunload', 'onabort', 'onerror', 'onresize', 'onscroll', 'onzoom'],
filterPrimitive: ['x', 'y', 'width', 'height'],
transferFunction: ['type', 'tableValues', 'slope', 'intercept', 'amplitude', 'exponent', 'offset']
};
var groupDefaults = exports.groupDefaults = {
filterPrimitive: {x: '0', y: '0', width: '100%', height: '100%'},
transferFunction: {slope: '1', intercept: '0', amplitude: '1', exponent: '1', offset: '0'}
};
// http://www.w3.org/TR/SVG/eltindex.html
exports.elems = {
a: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.graphicalEvent,
attrsGroups.presentation,
attrsGroups.xlink,
'class',
'style',
'externalResourcesRequired',
'transform',
'target'
],
defaults: {
target: '_self'
},
content: [
elemsGroups.animation,
elemsGroups.descriptive,
elemsGroups.shape,
elemsGroups.structural,
elemsGroups.gradient,
'a',
'altGlyphDef',
'clipPath',
'color-profile',
'cursor',
'filter',
'font',
'font-face',
'foreignObject',
'image',
'marker',
'mask',
'pattern',
'script',
'style',
'switch',
'text',
'view'
]
},
altGlyph: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.graphicalEvent,
attrsGroups.presentation,
attrsGroups.xlink,
'class',
'style',
'externalResourcesRequired',
'x',
'y',
'dx',
'dy',
'glyphRef',
'format',
'rotate'
],
content: []
},
altGlyphDef: {
attrs: [attrsGroups.core],
content: ['glyphRef']
},
altGlyphItem: {
attrs: [attrsGroups.core],
content: [
'glyphRef',
'altGlyphItem'
]
},
animate: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.animationAddition,
attrsGroups.animationAttributeTarget,
attrsGroups.animationEvent,
attrsGroups.animationTiming,
attrsGroups.animationValue,
attrsGroups.presentation,
attrsGroups.xlink,
'externalResourcesRequired'
],
content: [elemsGroups.descriptive]
},
animateColor: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.animationEvent,
attrsGroups.xlink,
attrsGroups.animationAttributeTarget,
attrsGroups.animationTiming,
attrsGroups.animationValue,
attrsGroups.animationAddition,
attrsGroups.presentation,
'externalResourcesRequired'
],
content: [elemsGroups.descriptive]
},
animateMotion: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.animationEvent,
attrsGroups.xlink,
attrsGroups.animationTiming,
attrsGroups.animationValue,
attrsGroups.animationAddition,
'externalResourcesRequired',
'path',
'keyPoints',
'rotate',
'origin'
],
defaults: {
'rotate': '0'
},
content: [
elemsGroups.descriptive,
'mpath'
]
},
animateTransform: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.animationEvent,
attrsGroups.xlink,
attrsGroups.animationAttributeTarget,
attrsGroups.animationTiming,
attrsGroups.animationValue,
attrsGroups.animationAddition,
'externalResourcesRequired',
'type'
],
defaults: {
type: 'translate'
},
content: [elemsGroups.descriptive]
},
circle: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.graphicalEvent,
attrsGroups.presentation,
'class',
'style',
'externalResourcesRequired',
'transform',
'cx',
'cy',
'r'
],
defaults: {
cx: 0,
cy: 0
},
content: [
elemsGroups.animation,
elemsGroups.descriptive
]
},
clipPath: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.presentation,
'class',
'style',
'externalResourcesRequired',
'transform',
'clipPathUnits'
],
defaults: {
clipPathUnits: 'userSpaceOnUse'
},
content: [
elemsGroups.animation,
elemsGroups.descriptive,
elemsGroups.shape,
'text',
'use'
]
},
'color-profile': {
attrs: [
attrsGroups.core,
attrsGroups.xlink,
'local',
'name',
'rendering-intent'
],
defaults: {
name: 'sRGB',
'rendering-intent': 'auto'
},
content: [elemsGroups.descriptive]
},
cursor: {
attrs: [
attrsGroups.core,
attrsGroups.conditionalProcessing,
attrsGroups.xlink,
'externalResourcesRequired',
'x',
'y'
],
defaults: {
x: '0',
y: '0'
},
content: [elemsGroups.descriptive]
},
defs: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.graphicalEvent,
attrsGroups.presentation,
'class',
'style',
'externalResourcesRequired',
'transform'
],
content: [
elemsGroups.animation,
elemsGroups.descriptive,
elemsGroups.shape,
elemsGroups.structural,
elemsGroups.gradient,
'a',
'altGlyphDef',
'clipPath',
'color-profile',
'cursor',
'filter',
'font',
'font-face',
'foreignObject',
'image',
'marker',
'mask',
'pattern',
'script',
'style',
'switch',
'text',
'view'
]
},
desc: {
attrs: [
attrsGroups.core,
'class',
'style'
]
},
ellipse: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.graphicalEvent,
attrsGroups.presentation,
'class',
'style',
'externalResourcesRequired',
'transform',
'cx',
'cy',
'rx',
'ry'
],
defaults: {
cx: '0',
cy: '0'
},
content: [
elemsGroups.animation,
elemsGroups.descriptive
]
},
feBlend: {
attrs: [
attrsGroups.core,
attrsGroups.presentation,
attrsGroups.filterPrimitive,
'class',
'style',
// TODO: in - 'If no value is provided and this is the first filter primitive,
// then this filter primitive will use SourceGraphic as its input'
'in',
'in2',
'mode'
],
groupDefaults: groupDefaults.filterPrimitive,
defaults: {
mode: 'normal'
},
content: [
'animate',
'set'
]
},
feColorMatrix: {
attrs: [
attrsGroups.core,
attrsGroups.presentation,
attrsGroups.filterPrimitive,
'class',
'style',
'in',
'type',
'values'
],
groupDefaults: groupDefaults.filterPrimitive,
defaults: {
type: 'matrix'
},
content: [
'animate',
'set'
]
},
feComponentTransfer: {
attrs: [
attrsGroups.core,
attrsGroups.presentation,
attrsGroups.filterPrimitive,
'class',
'style',
'in'
],
groupDefaults: groupDefaults.filterPrimitive,
content: [
'feFuncA',
'feFuncB',
'feFuncG',
'feFuncR'
]
},
feComposite: {
attrs: [
attrsGroups.core,
attrsGroups.presentation,
attrsGroups.filterPrimitive,
'class',
'style',
'in',
'in2',
'operator',
'k1',
'k2',
'k3',
'k4'
],
groupDefaults: groupDefaults.filterPrimitive,
defaults: {
operator: 'over',
k1: '0',
k2: '0',
k3: '0',
k4: '0'
},
content: [
'animate',
'set'
]
},
feConvolveMatrix: {
attrs: [
attrsGroups.core,
attrsGroups.presentation,
attrsGroups.filterPrimitive,
'class',
'style',
'in',
'order',
'kernelMatrix',
// TODO: divisor - 'The default value is the sum of all values in kernelMatrix,
// with the exception that if the sum is zero, then the divisor is set to 1'
'divisor',
'bias',
// TODO: targetX - 'By default, the convolution matrix is centered in X over each
// pixel of the input image (i.e., targetX = floor ( orderX / 2 ))'
'targetX',
'targetY',
'edgeMode',
// TODO: kernelUnitLength - 'The first number is the <dx> value. The second number
// is the <dy> value. If the <dy> value is not specified, it defaults to the same value as <dx>'
'kernelUnitLength',
'preserveAlpha'
],
groupDefaults: groupDefaults.filterPrimitive,
defaults: {
order: '3',
bias: '0',
edgeMode: 'duplicate',
preserveAlpha: 'false'
},
content: [
'animate',
'set'
]
},
feDiffuseLighting: {
attrs: [
attrsGroups.core,
attrsGroups.presentation,
attrsGroups.filterPrimitive,
'class',
'style',
'in',
'surfaceScale',
'diffuseConstant',
'kernelUnitLength'
],
groupDefaults: groupDefaults.filterPrimitive,
defaults: {
surfaceScale: '1',
diffuseConstant: '1'
},
content: [
elemsGroups.descriptive,
// TODO: 'exactly one light source element, in any order'
'feDistantLight',
'fePointLight',
'feSpotLight'
]
},
feDisplacementMap: {
attrs: [
attrsGroups.core,
attrsGroups.presentation,
attrsGroups.filterPrimitive,
'class',
'style',
'in',
'in2',
'scale',
'xChannelSelector',
'yChannelSelector'
],
groupDefaults: groupDefaults.filterPrimitive,
defaults: {
scale: '0',
xChannelSelector: 'A',
yChannelSelector: 'A'
},
content: [
'animate',
'set'
]
},
feDistantLight: {
attrs: [
attrsGroups.core,
'azimuth',
'elevation'
],
defaults: {
azimuth: '0',
elevation: '0'
},
content: [
'animate',
'set'
]
},
feFlood: {
attrs: [
attrsGroups.core,
attrsGroups.presentation,
attrsGroups.filterPrimitive,
'class',
'style'
],
groupDefaults: groupDefaults.filterPrimitive,
content: [
'animate',
'animateColor',
'set'
]
},
feFuncA: {
attrs: [
attrsGroups.core,
attrsGroups.transferFunction
],
groupDefaults: groupDefaults.transferFunction,
content: [
'set',
'animate'
]
},
feFuncB: {
attrs: [
attrsGroups.core,
attrsGroups.transferFunction
],
groupDefaults: groupDefaults.transferFunction,
content: [
'set',
'animate'
]
},
feFuncG: {
attrs: [
attrsGroups.core,
attrsGroups.transferFunction
],
groupDefaults: groupDefaults.transferFunction,
content: [
'set',
'animate'
]
},
feFuncR: {
attrs: [
attrsGroups.core,
attrsGroups.transferFunction
],
groupDefaults: groupDefaults.transferFunction,
content: [
'set',
'animate'
]
},
feGaussianBlur: {
attrs: [
attrsGroups.core,
attrsGroups.presentation,
attrsGroups.filterPrimitive,
'class',
'style',
'in',
'stdDeviation'
],
groupDefaults: groupDefaults.filterPrimitive,
defaults: {
stdDeviation: '0'
},
content: [
'set',
'animate'
]
},
feImage: {},
feMerge: {},
feMergeNode: {},
feMorphology: {},
feOffset: {},
fePointLight: {},
feSpecularLighting: {},
feSpotLight: {},
feTile: {},
feTurbulence: {},
filter: {},
font: {},
'font-face': {},
'font-face-format': {},
'font-face-name': {},
'font-face-src': {},
'font-face-uri': {},
foreignObject: {},
g: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.graphicalEvent,
attrsGroups.presentation,
'class',
'style',
'externalResourcesRequired',
'transform'
],
content: [
elemsGroups.animation,
elemsGroups.descriptive,
elemsGroups.shape,
elemsGroups.structural,
elemsGroups.gradient,
'a',
'altGlyphDef',
'clipPath',
'color-profile',
'cursor',
'filter',
'font',
'font-face',
'foreignObject',
'image',
'marker',
'mask',
'pattern',
'script',
'style',
'switch',
'text',
'view'
]
},
glyph: {},
glyphRef: {},
hkern: {},
image: {
attrs: [
attrsGroups.core,
attrsGroups.conditionalProcessing,
attrsGroups.graphicalEvent,
attrsGroups.xlink,
attrsGroups.presentation,
'class',
'style',
'externalResourcesRequired',
'preserveAspectRatio',
'transform',
'x',
'y',
'width',
'height',
'xlink:href'
],
defaults: {
x: '0',
y: '0',
preserveAspectRatio: 'xMidYMid meet'
},
content: [
elemsGroups.animation,
elemsGroups.descriptive
]
},
line: {},
linearGradient: {
attrs: [
attrsGroups.core,
attrsGroups.presentation,
attrsGroups.xlink,
'class',
'style',
'externalResourcesRequired',
'x1',
'y1',
'x2',
'y2',
'gradientUnits',
'gradientTransform',
'spreadMethod',
'xlink:href'
],
defaults: {
x1: '0',
y1: '0',
x2: '100%',
y2: '0',
spreadMethod: 'pad'
},
content: [
elemsGroups.descriptive,
'animate',
'animateTransform',
'set',
'stop'
]
},
marker: {},
mask: {},
metadata: {},
'missing-glyph': {},
mpath: {},
path: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.graphicalEvent,
attrsGroups.presentation,
'class',
'style',
'externalResourcesRequired',
'transform',
'd',
'pathLength'
],
content: [
elemsGroups.animation,
elemsGroups.descriptive
]
},
pattern: {},
polygon: {},
polyline: {},
radialGradient: {
defaults: {
cx: '50%',
cy: '50%',
r: '50%'
}
},
rect: {},
script: {},
set: {},
stop: {},
style: {},
svg: {
attrs: [
attrsGroups.conditionalProcessing,
attrsGroups.core,
attrsGroups.documentEvent,
attrsGroups.graphicalEvent,
attrsGroups.presentation,
'class',
'style',
'x',
'y',
'width',
'height',
'viewBox',
'preserveAspectRatio',
'zoomAndPan',
'version',
'baseProfile',
'contentScriptType',
'contentStyleType'
],
defaults: {
x: '0',
y: '0',
width: '100%',
height: '100%',
preserveAspectRatio: 'xMidYMid meet',
zoomAndPan: 'magnify',
version: '1.1',
baseProfile: 'none',
contentScriptType: 'application/ecmascript',
contentStyleType: 'text/css'
},
content: [
elemsGroups.animation,
elemsGroups.descriptive,
elemsGroups.shape,
elemsGroups.structural,
elemsGroups.gradient,
'a',
'altGlyphDef',
'clipPath',
'color-profile',
'cursor',
'filter',
'font',
'font-face',
'foreignObject',
'image',
'marker',
'mask',
'pattern',
'script',
'style',
'switch',
'text',
'view'
]
},
switch: {},
symbol: {},
text: {},
textPath: {},
title: {},
tref: {},
tspan: {},
use: {},
view: {},
vkern: {}
};
// http://wiki.inkscape.org/wiki/index.php/Inkscape-specific_XML_attributes

@@ -82,28 +901,24 @@ exports.editorNamespaces = [

// http://www.w3.org/TR/SVG/intro.html#Definitions
var elems = exports.elems = {
'animation': ['animate', 'animateColor', 'animateMotion', 'animateTransform', 'set'],
'descriptive': ['desc', 'metadata', 'title'],
'shape': ['circle', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'rect'],
'structural': ['defs', 'g', 'svg', 'symbol', 'use'],
'gradient': ['linearGradient', 'radialGradient'],
// http://www.w3.org/TR/SVG/intro.html#TermContainerElement
'container': ['a', 'defs', 'glyph', 'g', 'marker', 'mask', 'missing-glyph', 'pattern', 'svg', 'switch', 'symbol']
};
// http://www.w3.org/TR/SVG/propidx.html
exports.nonInheritedAttrs = [
'alignment-baseline',
'baseline-shift',
'clip',
'clip-path',
'display',
'dominant-baseline',
'enable-background',
'filter',
'flood-color',
'flood-opacity',
'lighting-color',
'mask',
'opacity',
'overflow',
'stop-color',
'stop-opacity',
'text-decoration', // TODO: "see prose"
'unicode-bidi'
];
// http://www.w3.org/TR/SVG/intro.html#Definitions
var attrs = exports.attrs = {
'animationAddition': ['additive', 'accumulate'],
'animationAttributeTarget': ['attributeType', 'attributeName'],
'animationEvent': ['onbegin', 'onend', 'onrepeat', 'onload'],
'animationTiming': ['begin', 'dur', 'end', 'min', 'max', 'restart', 'repeatCount', 'repeatDur', 'fill'],
'animationValue': ['calcMode', 'values', 'keyTimes', 'keySplines', 'from', 'to', 'by'],
'conditionalProcessing': ['requiredFeatures', 'requiredExtensions', 'systemLanguage'],
'core': ['id', 'xml:base', 'xml:lang', 'xml:space'],
'graphicalEvent': ['onfocusin', 'onfocusout', 'onactivate', 'onclick', 'onmousedown', 'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout', 'onload'],
'presentation': ['alignment-baseline', 'baseline-shift', 'clip', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cursor', 'direction', 'display', 'dominant-baseline', 'enable-background', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'image-rendering', 'kerning', 'letter-spacing', 'lighting-color', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'overflow', 'pointer-events', 'shape-rendering', 'stop-color', 'stop-opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-decoration', 'text-rendering', 'unicode-bidi', 'visibility', 'word-spacing', 'writing-mode'],
'xlink': ['xlink:href', 'xlink:show', 'xlink:actuate', 'xlink:type', 'xlink:role', 'xlink:arcrole', 'xlink:title'],
'documentEvent': ['onunload', 'onabort', 'onerror', 'onresize', 'onscroll', 'onzoom']
};
// http://www.w3.org/TR/SVG/single-page.html#types-ColorKeywords

@@ -110,0 +925,0 @@ exports.colorsNames = {

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

var flattenOneLevel = require('../lib/tools').flattenOneLevel;
var flattenOneLevel = require('../lib/svgo/tools').flattenOneLevel;

@@ -3,0 +3,0 @@ /*

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

var cleanupOutData = require('../lib/tools').cleanupOutData,
var cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
regPathInstructions = /([MmLlHhVvCcSsQqTtAaZz])\s*/,

@@ -29,3 +29,3 @@ regPathData = /(?=-)|[\s,]+/,

if (data.length) {
data = convertToRelative(data, params);
data = convertToRelative(data);

@@ -78,3 +78,3 @@ data = filters(data, params);

// very stupid defense strategy
if (!isNaN(data[0])) {
if (typeof data[0] === 'number' && !isNaN(data[0])) {

@@ -120,3 +120,3 @@ var pair = 0;

*/
function convertToRelative(path, params) {
function convertToRelative(path) {

@@ -133,2 +133,3 @@ var instruction,

// data !== !z
if (data) {

@@ -156,107 +157,84 @@

// convert absolute path data coordinates to relative
if (params.convertToRelative) {
// M → m
// L → l
// T → t
if ('MLT'.indexOf(instruction) > -1) {
// M → m
// L → l
// T → t
if ('MLT'.indexOf(instruction) > -1) {
// don't convert M if point is [0, 0]
if (instruction !== 'M' || point[0] !== 0 && point[1] !== 0) {
instruction = instruction.toLowerCase();
}
// x y
// 0 1
data[0] -= point[0];
data[1] -= point[1];
// x y
// 0 1
data[0] -= point[0];
data[1] -= point[1];
point[0] += data[0];
point[1] += data[1];
point[0] += data[0];
point[1] += data[1];
// C → c
} else if (instruction === 'C') {
// C → c
} else if (instruction === 'C') {
instruction = 'c';
instruction = 'c';
// x1 y1 x2 y2 x y
// 0 1 2 3 4 5
data[0] -= point[0];
data[1] -= point[1];
data[2] -= point[0];
data[3] -= point[1];
data[4] -= point[0];
data[5] -= point[1];
// x1 y1 x2 y2 x y
// 0 1 2 3 4 5
data[0] -= point[0];
data[1] -= point[1];
data[2] -= point[0];
data[3] -= point[1];
data[4] -= point[0];
data[5] -= point[1];
point[0] += data[4];
point[1] += data[5];
point[0] += data[4];
point[1] += data[5];
// S → s
// Q → q
} else if ('SQ'.indexOf(instruction) > -1) {
// S → s
// Q → q
} else if ('SQ'.indexOf(instruction) > -1) {
instruction = instruction.toLowerCase();
instruction = instruction.toLowerCase();
// x1 y1 x y
// 0 1 2 3
data[0] -= point[0];
data[1] -= point[1];
data[2] -= point[0];
data[3] -= point[1];
// x1 y1 x y
// 0 1 2 3
data[0] -= point[0];
data[1] -= point[1];
data[2] -= point[0];
data[3] -= point[1];
point[0] += data[2];
point[1] += data[3];
point[0] += data[2];
point[1] += data[3];
// A → a
} else if (instruction === 'A') {
// A → a
} else if (instruction === 'A') {
instruction = 'a';
instruction = 'a';
// rx ry x-axis-rotation large-arc-flag sweep-flag x y
// 0 1 2 3 4 5 6
data[0] -= point[0];
data[1] -= point[1];
data[5] -= point[0];
data[6] -= point[1];
// rx ry x-axis-rotation large-arc-flag sweep-flag x y
// 0 1 2 3 4 5 6
data[5] -= point[0];
data[6] -= point[1];
point[0] += data[5];
point[1] += data[6];
point[0] += data[5];
point[1] += data[6];
// H → h
} else if (instruction === 'H') {
// H → h
} else if (instruction === 'H') {
instruction = 'h';
instruction = 'h';
data[0] -= point[0];
data[0] -= point[0];
point[0] += data[0];
point[0] += data[0];
// V → v
} else if (instruction === 'V') {
// V → v
} else if (instruction === 'V') {
instruction = 'v';
instruction = 'v';
data[0] -= point[1];
data[0] -= point[1];
point[1] += data[0];
point[1] += data[0];
}
// calculate new current point
} else {
if ('MCSLQTA'.indexOf(instruction) > -1) {
newPoint = data.slice(-2);
point[0] = newPoint[0];
point[1] = newPoint[1];
} else if (instruction === 'H') {
point[0] = data[0];
} else if (instruction === 'V') {
point[1] = data[0];
}
}

@@ -270,2 +248,7 @@

// !data === z, reset current point
else {
point = [0, 0];
}
});

@@ -292,4 +275,3 @@

point: [0, 0]
},
index = 0;
};

@@ -302,4 +284,2 @@ path = path.filter(function(item) {

index++;
if (data) {

@@ -311,2 +291,89 @@

// convert straight curves into lines segments
if (params.straightCurves) {
// c
if (
instruction === 'c' &&
isCurveStraightLine(
[ 0, data[0], data[2], data[4] ],
[ 0, data[1], data[3], data[5] ]
)
) {
instruction = 'l';
data = data.slice(-2);
}
// s
else if (instruction === 's') {
if (
isCurveStraightLine(
[ 0, data[0], data[2] ],
[ 0, data[1], data[3] ]
)
) {
instruction = 'l';
data = data.slice(-2);
}
}
// q
else if (
prev.item &&
instruction === 'q' &&
isCurveStraightLine(
[ 0, data[0], data[2] ],
[ 0, data[1], data[3] ]
)
) {
// save the original one for the future potential q + t conversion
item.original = {
instruction: instruction,
data: data
};
instruction = 'l';
data = data.slice(-2);
}
else if (instruction === 't') {
// q (original) + t
if (
prev.item &&
prev.item.original &&
prev.item.original.instruction === 'q'
) {
if (isCurveStraightLine(
[ prev.item.original.data[0], prev.item.original.data[2], data[0] ],
[ prev.item.original.data[1], prev.item.original.data[3], data[1] ]
)) {
instruction = 'l';
data = data.slice(-2);
} else {
prev.item.instruction = 'q';
prev.item.data = prev.item.original.data;
}
}
// [^qt] + t
else if (!prev.item || 'qt'.indexOf(prev.item.instruction) === -1) {
instruction = 'l';
data = data.slice(-2);
}
}
// a
else if (
instruction === 'a' &&
(data[0] === 0 || data[1] === 0)
) {
instruction = 'l';
data = data.slice(-2);
}
}
// horizontal and vertical line shorthands

@@ -317,11 +384,9 @@ // l 50 0 → h 50

params.lineShorthands &&
'Ll'.indexOf(instruction) > -1
instruction === 'l'
) {
var lowerCase = instruction === instruction.toLowerCase();
if (point[1] - prev.point[1] === 0) {
instruction = lowerCase ? 'h' : 'H';
if (data[1] === 0) {
instruction = 'h';
data = [data[0]];
} else if (point[0] - prev.point[0] === 0) {
instruction = lowerCase ? 'v' : 'V';
} else if (data[0] === 0) {
instruction = 'v';
data = [data[1]];

@@ -331,2 +396,67 @@ }

// convert curves into smooth shorthands
if (params.curveSmoothShorthands && prev.item) {
// curveto
if (instruction === 'c') {
// c + c → c + s
if (
prev.item.instruction === 'c' &&
data[0] === -(prev.item.data[2] - prev.item.data[4]) &&
data[1] === -(prev.item.data[3] - prev.item.data[5])
) {
instruction = 's';
data = data.slice(2);
}
// s + c → s + s
else if (
prev.item.instruction === 's' &&
data[0] === -(prev.item.data[0] - prev.item.data[2]) &&
data[1] === -(prev.item.data[1] - prev.item.data[3])
) {
instruction = 's';
data = data.slice(2);
}
// [^cs] + c → [^cs] + s
else if (
'cs'.indexOf(prev.item.instruction) === -1 &&
data[0] === 0 &&
data[1] === 0
) {
instruction = 's';
data = data.slice(2);
}
}
// quadratic Bézier curveto
else if (instruction === 'q') {
// q + q → q + t
if (
prev.item.instruction === 'q' &&
data[0] === (prev.item.data[2] - prev.item.data[0]) &&
data[1] === (prev.item.data[3] - prev.item.data[1])
) {
instruction = 't';
data = data.slice(2);
}
// t + q → t + t
else if (
prev.item.instruction === 't' &&
data[2] === prev.item.data[0] &&
data[3] === prev.item.data[1]
) {
instruction = 't';
data = data.slice(2);
}
}
}
// remove useless non-first path segments

@@ -338,4 +468,3 @@ if (params.removeUseless) {

(
'lhvqtcs'.indexOf(instruction) > -1 ||
(instruction === 'm' && index > 1)
'mlhvqtcs'.indexOf(instruction) > -1
) &&

@@ -347,22 +476,7 @@ data.every(function(i) { return i === 0; })

// M25,25 L25,25 C 25,25 25,25 25,25
if (
'LHVQTCS'.indexOf(instruction) > -1 ||
(instruction === 'M' && index > 1)
) {
var i = -1,
every = data.every(function(d) {
return d - prev.point[++i % 2] === 0;
});
if (every) {
return false;
}
}
// a 25,25 -30 0,1 0,0
if (
'aA'.indexOf(item.instruction) > -1 &&
point[0] - prev.point[0] === 0 &&
point[1] - prev.point[1] === 0
instruction === 'a' &&
data[5] === 0 &&
data[6] === 0
) {

@@ -383,5 +497,2 @@ return false;

prev.item.data[0] += data[0];
// replace previous H or V data with current
} else if (instruction === 'H' || instruction === 'V') {
prev.item.data[0] = data[0];
// concat previous data with current

@@ -392,2 +503,5 @@ } else {

// if there was an original then remove it because of the new data
delete prev.item.original;
// filter current item

@@ -433,2 +547,28 @@ return false;

/**
* Checks if curve is a straight line by calculating a polygon area.
*
* @see http://www.mathopenref.com/coordpolygonarea2.html
*
* @param {Array} xs array of curve points x-coordinates
* @param {Array} ys array of curve points y-coordinates
*
* @return {Boolean}
*/
function isCurveStraightLine(xs, ys) {
var points = xs.length,
area = 0,
j = points - 1;
for (var i=0; i < points; i++) {
area += (xs[j] + xs[i]) * (ys[j] - ys[i]);
j = i;
}
return !+area.toFixed(2);
}
/**
* Convert path array to string.

@@ -435,0 +575,0 @@ *

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

var extend = require('../lib/tools').extend,
var extend = require('../lib/svgo/tools').extend,
stylingProps = require('./_collections').stylingProps,

@@ -3,0 +3,0 @@ regCleanupStyle = /(:|;)\s+/g;

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

var cleanupOutData = require('../lib/tools').cleanupOutData,
var cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
regTransformTypes = /matrix|translate|scale|rotate|skewX|skewY/,

@@ -3,0 +3,0 @@ regTransformSplit = /(matrix|translate|scale|rotate|skewX|skewY)\s*\((.+?)\)[\s,]*/,

@@ -1,5 +0,6 @@

var intersectAttrs = require('../lib/tools').intersectAttrs;
var nonInheritedAttrs = require('./_collections').nonInheritedAttrs;
/**
* Collapse content's intersected attributes to the existing group wrapper.
* Collapse content's intersected and inheritable
* attributes to the existing group wrapper.
*

@@ -38,3 +39,3 @@ * @example

} else {
intersection = intersectAttrs(intersection, g.attrs);
intersection = intersectInheritableAttrs(intersection, g.attrs);

@@ -48,5 +49,6 @@ if (!intersection) return false;

if (every) {
if (every) {
item.content.forEach(function(g) {
for (var name in intersection) {

@@ -64,3 +66,5 @@ g.removeAttr(name);

}
});
}

@@ -71,1 +75,32 @@

};
/**
* Intersect inheritable attributes.
*
* @param {Object} a first attrs object
* @param {Object} b second attrs object
*
* @return {Object} intersected attrs object
*/
function intersectInheritableAttrs(a, b) {
var c = {};
for (var n in a) {
if (
b.hasOwnProperty(n) &&
nonInheritedAttrs.indexOf(n) === -1 &&
a[n].name === b[n].name &&
a[n].value === b[n].value &&
a[n].prefix === b[n].prefix &&
a[n].local === b[n].local
) {
c[n] = a[n];
}
}
if (!Object.keys(c).length) return false;
return c;
}

@@ -16,4 +16,6 @@ /**

return !item.comment;
if (item.comment && item.comment.charAt(0) !== '!') {
return false;
}
};

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

var container = require('./_collections').elems.container;
var container = require('./_collections').elemsGroups.container;

@@ -3,0 +3,0 @@ /**

@@ -1,10 +0,4 @@

```
o-o o o o--o o-o
\ \ / | | | |
o-o o o--o o-o
|
o--o
```
![logo](https://raw.github.com/svg/svgo/master/logo200x200.png)
## SVGO v0.0.9 [![Build Status](https://secure.travis-ci.org/svg/svgo.png)](http://travis-ci.org/svg/svgo)
## SVGO v0.1.0 [![Build Status](https://secure.travis-ci.org/svg/svgo.png)](http://travis-ci.org/svg/svgo)

@@ -36,7 +30,7 @@ **SVG** **O**ptimizer is a Nodejs-based tool for optimizing SVG vector graphics files.

* [ [>](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) ] remove or cleanup enable-background attribute
* [ [>](https://github.com/svg/svgo/blob/master/plugins/cleanupSVGElem.js) ] cleanup SVG element from useless attributes
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js) ] convert styles into attributes
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) ] convert colors (from rgb() to #rrggbb, from #rrggbb to #rgb)
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) ] convert Path data to relative, trim useless delimiters and much more
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) ] convert Path data to relative, convert one segment to another, trim useless delimiters and much more
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js) ] collapse multiple transforms into one, convert matrices to the short aliases and much more
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) ] remove unknown elements content and attributes, remove attrs with default values
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) ] remove unused namespaces declaration

@@ -51,7 +45,7 @@ * [ [>](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup.js) ] move elements attributes to the existing group wrapper

```sh
$ [sudo] npm install -g svgo
```
npm install -g svgo
```
```
```sh
Usage:

@@ -63,4 +57,6 @@ svgo [OPTIONS] [ARGS]

-v, --version : Version
-i INPUT, --input=INPUT : Input: stdin (default) | filename | Data URI base64 string
-o OUTPUT, --output=OUTPUT : Output: stdout (default) | filename
-i INPUT, --input=INPUT : Input file, "-" for STDIN
-s STRING, --string=STRING : Input SVG data string
-f FOLDER, --folder=FOLDER : Input folder, optimize and rewrite all *.svg files
-o OUTPUT, --output=OUTPUT : Output file (by default the same as the input), "-" for STDOUT
-c CONFIG, --config=CONFIG : Local config file to extend default

@@ -71,30 +67,50 @@ --disable=DISABLE : Disable plugin by name

--pretty : Make SVG pretty printed
--test : Make a visual comparison of two files (PhantomJS pre-required)
Arguments:
INPUT : Alias to --input
OUTPUT : Alias to --output
```
With files:
* with files:
```sh
$ svgo test.svg
```
svgo -i test.svg -o test.min.svg
```sh
$ svgo test.svg test.min.svg
```
With stdin / stdout:
* with STDIN / STDOUT:
```sh
$ cat test.svg | svgo -i - -o - > test.min.svg
```
cat test.svg | svgo > test.min.svg
* with folder
```sh
$ svgo -f ../path/to/folder/with/svg/files
```
With Data URI base64 strings:
* with strings (even with Data URI base64):
```sh
$ svgo -s '<svg version="1.1">test</svg>' -o test.min.svg
```
svgo -i 'data:image/svg+xml;base64,…' -o test.min.svg
```sh
$ svgo -s 'data:image/svg+xml;base64,…' -o test.min.svg
```
* with [GUI](https://github.com/svg/svgo-gui) (currently Mac OS X app only)
* as a Nodejs module - [examples](https://github.com/svg/svgo/tree/master/examples)
## TODO
1. batch folder optimization
2. more plugins
3. SVGO GUI (crossplatform?) via awesome [node-webkit](https://github.com/rogerwang/node-webkit)
4. online SVGO web service
5. more unit tests
6. …
* [v0.1.1](https://github.com/svg/svgo/issues?milestone=3&state=open)
* [v0.1.2](https://github.com/svg/svgo/issues?milestone=4&state=open)
## License and copyrights
This software is released under the terms of the [MIT license](https://github.com/svg/svgo/blob/master/LICENSE).
Logo by [Yegor Bolshakov](http://xizzzy.ru/).

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

var config = require('../../lib/config');
var cover = process.argv[3] === 'mocha-istanbul',
config = require(cover ? '../../lib-cov/svgo/config' : '../../lib/svgo/config');

@@ -30,3 +31,3 @@ function getPlugin(name, config) {

})
.end();
.done();
});

@@ -71,3 +72,3 @@

})
.end();
.done();
});

@@ -85,3 +86,3 @@

coa: {
config: './test/config/config.json'
config: './test/config/config.yml'
}

@@ -96,3 +97,3 @@ },

})
.end();
.done();
});

@@ -99,0 +100,0 @@

@@ -52,3 +52,3 @@ var INHERIT = require('inherit'),

})
.end();
.done();
});

@@ -70,3 +70,3 @@

return mySVGO.optimize(input.toString());
return mySVGO.fromString(input.toString());
})

@@ -73,0 +73,0 @@ .then(function(min) {

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

var svg2js = require('../../lib/svg2js');
var cover = process.argv[3] === 'mocha-istanbul',
svg2js = require(cover ? '../../lib-cov/svgo/svg2js' : '../../lib/svgo/svg2js');

@@ -3,0 +4,0 @@ describe('svg2js', function() {

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 not supported yet

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 not supported yet

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 not supported yet

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 not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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