Comparing version 2.3.1 to 2.4.0
@@ -281,3 +281,4 @@ 'use strict'; | ||
(command === 'A' || command === 'a') && | ||
(i === 4 || i === 5) | ||
// consider combined arcs | ||
(i % 7 === 4 || i % 7 === 5) | ||
) { | ||
@@ -284,0 +285,0 @@ result += numberString; |
@@ -6,4 +6,3 @@ 'use strict'; | ||
const specificity = require('csso/lib/restructure/prepare/specificity'); | ||
const { selectAll, is } = require('css-select'); | ||
const svgoCssSelectAdapter = require('./svgo/css-select-adapter.js'); | ||
const { visit, matches } = require('./xast.js'); | ||
const { compareSpecificity } = require('./css-tools.js'); | ||
@@ -16,7 +15,2 @@ const { | ||
const cssSelectOptions = { | ||
xmlMode: true, | ||
adapter: svgoCssSelectAdapter, | ||
}; | ||
const parseRule = (ruleNode, dynamic) => { | ||
@@ -81,3 +75,3 @@ let selectors; | ||
const computeOwnStyle = (node, stylesheet) => { | ||
const computeOwnStyle = (stylesheet, node) => { | ||
const computedStyle = {}; | ||
@@ -96,3 +90,3 @@ const importantStyles = new Map(); | ||
for (const { selectors, declarations, dynamic } of stylesheet) { | ||
if (is(node, selectors, cssSelectOptions)) { | ||
if (matches(node, selectors)) { | ||
for (const { name, value, important } of declarations) { | ||
@@ -139,29 +133,27 @@ const computed = computedStyle[name]; | ||
const computeStyle = (node) => { | ||
// find root | ||
let root = node; | ||
while (root.parentNode) { | ||
root = root.parentNode; | ||
} | ||
// find all styles | ||
const styleNodes = selectAll('style', root, cssSelectOptions); | ||
// parse all styles | ||
const collectStylesheet = (root) => { | ||
const stylesheet = []; | ||
for (const styleNode of styleNodes) { | ||
const dynamic = | ||
styleNode.attributes.media != null && | ||
styleNode.attributes.media !== 'all'; | ||
if ( | ||
styleNode.attributes.type == null || | ||
styleNode.attributes.type === '' || | ||
styleNode.attributes.type === 'text/css' | ||
) { | ||
const children = styleNode.children; | ||
for (const child of children) { | ||
if (child.type === 'text' || child.type === 'cdata') { | ||
stylesheet.push(...parseStylesheet(child.value, dynamic)); | ||
// find and parse all styles | ||
visit(root, { | ||
element: { | ||
enter: (node) => { | ||
if (node.name === 'style') { | ||
const dynamic = | ||
node.attributes.media != null && node.attributes.media !== 'all'; | ||
if ( | ||
node.attributes.type == null || | ||
node.attributes.type === '' || | ||
node.attributes.type === 'text/css' | ||
) { | ||
const children = node.children; | ||
for (const child of children) { | ||
if (child.type === 'text' || child.type === 'cdata') { | ||
stylesheet.push(...parseStylesheet(child.value, dynamic)); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
}, | ||
}); | ||
// sort by selectors specificity | ||
@@ -171,8 +163,12 @@ stable.inplace(stylesheet, (a, b) => | ||
); | ||
return stylesheet; | ||
}; | ||
exports.collectStylesheet = collectStylesheet; | ||
const computeStyle = (stylesheet, node) => { | ||
// collect inherited styles | ||
const computedStyles = computeOwnStyle(node, stylesheet); | ||
const computedStyles = computeOwnStyle(stylesheet, node); | ||
let parent = node; | ||
while (parent.parentNode && parent.parentNode.type !== 'root') { | ||
const inheritedStyles = computeOwnStyle(parent.parentNode, stylesheet); | ||
const inheritedStyles = computeOwnStyle(stylesheet, parent.parentNode); | ||
for (const [name, computed] of Object.entries(inheritedStyles)) { | ||
@@ -179,0 +175,0 @@ if ( |
@@ -10,3 +10,3 @@ 'use strict'; | ||
const js2svg = require('./svgo/js2svg.js'); | ||
const invokePlugins = require('./svgo/plugins.js'); | ||
const { invokePlugins } = require('./svgo/plugins.js'); | ||
const JSAPI = require('./svgo/jsAPI.js'); | ||
@@ -46,6 +46,8 @@ const { encodeSVGDatauri } = require('./svgo/tools.js'); | ||
} | ||
const resolvedPlugins = plugins.map((plugin) => | ||
resolvePluginConfig(plugin, config) | ||
); | ||
svgjs = invokePlugins(svgjs, info, resolvedPlugins); | ||
const resolvedPlugins = plugins.map(resolvePluginConfig); | ||
const globalOverrides = {}; | ||
if (config.floatPrecision != null) { | ||
globalOverrides.floatPrecision = config.floatPrecision; | ||
} | ||
svgjs = invokePlugins(svgjs, info, resolvedPlugins, null, globalOverrides); | ||
svgjs = js2svg(svgjs, config.js2svg); | ||
@@ -52,0 +54,0 @@ if (svgjs.error) { |
@@ -5,3 +5,3 @@ 'use strict'; | ||
const PATH = require('path'); | ||
const chalk = require('chalk'); | ||
const { green } = require('colorette'); | ||
const { loadConfig, optimize } = require('../svgo-node.js'); | ||
@@ -437,3 +437,3 @@ const pluginsMap = require('../../plugins/plugins.js'); | ||
(profitPercents < 0 ? ' + ' : ' - ') + | ||
chalk.green(Math.abs(Math.round(profitPercents * 10) / 10) + '%') + | ||
green(Math.abs(Math.round(profitPercents * 10) / 10) + '%') + | ||
' = ' + | ||
@@ -490,3 +490,3 @@ Math.round((outBytes / 1024) * 1000) / 1000 + | ||
.sort(([a], [b]) => a.localeCompare(b)) | ||
.map(([name, plugin]) => ` [ ${chalk.green(name)} ] ${plugin.description}`) | ||
.map(([name, plugin]) => ` [ ${green(name)} ] ${plugin.description}`) | ||
.join('\n'); | ||
@@ -493,0 +493,0 @@ console.log('Currently available plugins:\n' + list); |
@@ -61,2 +61,20 @@ 'use strict'; | ||
const extendDefaultPlugins = (plugins) => { | ||
console.warn( | ||
'\n"extendDefaultPlugins" utility is deprecated.\n' + | ||
'Use "preset-default" plugin with overrides instead.\n' + | ||
'For example:\n' + | ||
`{\n` + | ||
` name: 'preset-default',\n` + | ||
` params: {\n` + | ||
` overrides: {\n` + | ||
` // customize plugin options\n` + | ||
` convertShapeToPath: {\n` + | ||
` convertArcs: true\n` + | ||
` },\n` + | ||
` // disable plugins\n` + | ||
` convertPathData: false\n` + | ||
` }\n` + | ||
` }\n` + | ||
`}\n` | ||
); | ||
const extendedPlugins = pluginsOrder.map((name) => ({ | ||
@@ -67,3 +85,3 @@ name, | ||
for (const plugin of plugins) { | ||
const resolvedPlugin = resolvePluginConfig(plugin, {}); | ||
const resolvedPlugin = resolvePluginConfig(plugin); | ||
const index = pluginsOrder.indexOf(resolvedPlugin.name); | ||
@@ -80,7 +98,4 @@ if (index === -1) { | ||
const resolvePluginConfig = (plugin, config) => { | ||
const resolvePluginConfig = (plugin) => { | ||
let configParams = {}; | ||
if ('floatPrecision' in config) { | ||
configParams.floatPrecision = config.floatPrecision; | ||
} | ||
if (typeof plugin === 'string') { | ||
@@ -87,0 +102,0 @@ // resolve builtin plugin specified as string |
@@ -335,3 +335,3 @@ 'use strict'; | ||
// newly added class attribute | ||
this.class.hasClass(); | ||
this.class.addClassValueHandler(); | ||
} | ||
@@ -341,3 +341,3 @@ | ||
// newly added style attribute | ||
this.style.hasStyle(); | ||
this.style.addStyleValueHandler(); | ||
} | ||
@@ -344,0 +344,0 @@ |
@@ -10,43 +10,36 @@ 'use strict'; | ||
* | ||
* @param {Object} data input data | ||
* @param {Object} ast input ast | ||
* @param {Object} info extra information | ||
* @param {Array} plugins plugins object from config | ||
* @return {Object} output data | ||
* @return {Object} output ast | ||
*/ | ||
module.exports = function (data, info, plugins) { | ||
// Try to group sequential elements of plugins array | ||
// to optimize ast traversing | ||
const groups = []; | ||
let prev; | ||
const invokePlugins = (ast, info, plugins, overrides, globalOverrides) => { | ||
for (const plugin of plugins) { | ||
if (prev && plugin.type == prev[0].type) { | ||
prev.push(plugin); | ||
} else { | ||
prev = [plugin]; | ||
groups.push(prev); | ||
const override = overrides == null ? null : overrides[plugin.name]; | ||
if (override === false) { | ||
continue; | ||
} | ||
} | ||
for (const group of groups) { | ||
switch (group[0].type) { | ||
case 'perItem': | ||
data = perItem(data, info, group); | ||
break; | ||
case 'perItemReverse': | ||
data = perItem(data, info, group, true); | ||
break; | ||
case 'full': | ||
data = full(data, info, group); | ||
break; | ||
case 'visitor': | ||
for (const plugin of group) { | ||
if (plugin.active) { | ||
const visitor = plugin.fn(data, plugin.params, info); | ||
visit(data, visitor); | ||
} | ||
} | ||
break; | ||
const params = { ...plugin.params, ...globalOverrides, ...override }; | ||
if (plugin.type === 'perItem') { | ||
ast = perItem(ast, info, plugin, params); | ||
} | ||
if (plugin.type === 'perItemReverse') { | ||
ast = perItem(ast, info, plugin, params, true); | ||
} | ||
if (plugin.type === 'full') { | ||
if (plugin.active) { | ||
ast = plugin.fn(ast, params, info); | ||
} | ||
} | ||
if (plugin.type === 'visitor') { | ||
if (plugin.active) { | ||
const visitor = plugin.fn(ast, params, info); | ||
visit(ast, visitor); | ||
} | ||
} | ||
} | ||
return data; | ||
return ast; | ||
}; | ||
exports.invokePlugins = invokePlugins; | ||
@@ -62,3 +55,3 @@ /** | ||
*/ | ||
function perItem(data, info, plugins, reverse) { | ||
function perItem(data, info, plugin, params, reverse) { | ||
function monkeys(items) { | ||
@@ -70,14 +63,7 @@ items.children = items.children.filter(function (item) { | ||
} | ||
// main filter | ||
var filter = true; | ||
for (var i = 0; filter && i < plugins.length; i++) { | ||
var plugin = plugins[i]; | ||
if (plugin.active && plugin.fn(item, plugin.params, info) === false) { | ||
filter = false; | ||
} | ||
let kept = true; | ||
if (plugin.active) { | ||
kept = plugin.fn(item, params, info) !== false; | ||
} | ||
// direct pass | ||
@@ -87,28 +73,23 @@ if (!reverse && item.children) { | ||
} | ||
return filter; | ||
return kept; | ||
}); | ||
return items; | ||
} | ||
return monkeys(data); | ||
} | ||
/** | ||
* "Full" plugins. | ||
* | ||
* @param {Object} data input data | ||
* @param {Object} info extra information | ||
* @param {Array} plugins plugins list to process | ||
* @return {Object} output data | ||
*/ | ||
function full(data, info, plugins) { | ||
plugins.forEach(function (plugin) { | ||
if (plugin.active) { | ||
data = plugin.fn(data, plugin.params, info); | ||
} | ||
}); | ||
return data; | ||
} | ||
const createPreset = ({ name, plugins }) => { | ||
return { | ||
name, | ||
type: 'full', | ||
fn: (ast, params, info) => { | ||
const { floatPrecision, overrides } = params; | ||
const globalOverrides = {}; | ||
if (floatPrecision != null) { | ||
globalOverrides.floatPrecision = floatPrecision; | ||
} | ||
return invokePlugins(ast, info, plugins, overrides, globalOverrides); | ||
}, | ||
}; | ||
}; | ||
exports.createPreset = createPreset; |
@@ -55,12 +55,2 @@ 'use strict'; | ||
/** | ||
* @param {any[]} a | ||
* @param {any[]} b | ||
*/ | ||
exports.intersectArrays = function (a, b) { | ||
return a.filter(function (n) { | ||
return b.indexOf(n) > -1; | ||
}); | ||
}; | ||
/** | ||
* Convert a row of numbers to an optimized string view. | ||
@@ -67,0 +57,0 @@ * |
@@ -55,6 +55,6 @@ 'use strict'; | ||
const visit = (node, visitor) => { | ||
const visit = (node, visitor, parentNode = null) => { | ||
const callbacks = visitor[node.type]; | ||
if (callbacks && callbacks.enter) { | ||
callbacks.enter(node); | ||
callbacks.enter(node, parentNode); | ||
} | ||
@@ -65,3 +65,3 @@ // visit root children | ||
for (const child of node.children) { | ||
visit(child, visitor); | ||
visit(child, visitor, node); | ||
} | ||
@@ -71,5 +71,5 @@ } | ||
if (node.type === 'element') { | ||
if (node.parentNode.children.includes(node)) { | ||
if (parentNode.children.includes(node)) { | ||
for (const child of node.children) { | ||
visit(child, visitor); | ||
visit(child, visitor, node); | ||
} | ||
@@ -79,3 +79,3 @@ } | ||
if (callbacks && callbacks.exit) { | ||
callbacks.exit(node); | ||
callbacks.exit(node, parentNode); | ||
} | ||
@@ -85,4 +85,3 @@ }; | ||
const detachNodeFromParent = (node) => { | ||
const parentNode = node.parentNode; | ||
const detachNodeFromParent = (node, parentNode) => { | ||
// avoid splice to not break for loops | ||
@@ -89,0 +88,0 @@ parentNode.children = parentNode.children.filter((child) => child !== node); |
{ | ||
"name": "svgo", | ||
"version": "2.3.1", | ||
"version": "2.4.0", | ||
"description": "Nodejs-based tool for optimizing SVG vector graphics files", | ||
@@ -49,7 +49,8 @@ "keywords": [ | ||
"plugins", | ||
"dist" | ||
"dist", | ||
"!**/**.test.js" | ||
], | ||
"scripts": { | ||
"test": "c8 --reporter=html --reporter=text mocha \"test/*/_index.js\" \"**/*.test.js\" --ignore=\"node_modules/**\"", | ||
"lint": "eslint --ignore-path .gitignore . && prettier --list-different \"**/*.js\" --ignore-path .gitignore", | ||
"test": "jest --coverage", | ||
"lint": "eslint --ignore-path .gitignore . && prettier --check \"**/*.js\" --ignore-path .gitignore", | ||
"fix": "eslint --ignore-path .gitignore --fix . && prettier --write \"**/*.js\" --ignore-path .gitignore", | ||
@@ -86,7 +87,6 @@ "typecheck": "tsc", | ||
"files": [ | ||
"test/**/*.js", | ||
"**/*.test.js" | ||
], | ||
"env": { | ||
"mocha": true | ||
"jest": true | ||
} | ||
@@ -98,3 +98,3 @@ } | ||
"@trysound/sax": "0.1.1", | ||
"chalk": "^4.1.0", | ||
"colorette": "^1.2.2", | ||
"commander": "^7.1.0", | ||
@@ -110,8 +110,6 @@ "css-select": "^4.1.3", | ||
"@rollup/plugin-node-resolve": "^11.2.0", | ||
"@types/mocha": "^8.2.2", | ||
"c8": "^7.6.0", | ||
"chai": "^4.3.4", | ||
"@types/jest": "^27.0.0", | ||
"del": "^6.0.0", | ||
"eslint": "^7.22.0", | ||
"mocha": "^8.3.2", | ||
"jest": "^27.0.6", | ||
"mock-stdin": "^1.0.0", | ||
@@ -118,0 +116,0 @@ "node-fetch": "^2.6.1", |
@@ -326,2 +326,7 @@ 'use strict'; | ||
if (command === 'z' || command === 'Z') { | ||
cursor[0] = start[0]; | ||
cursor[1] = start[1]; | ||
} | ||
pathItem.instruction = command; | ||
@@ -328,0 +333,0 @@ pathItem.data = args; |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'addAttributesToSVGElement'; | ||
exports.type = 'perItem'; | ||
@@ -7,0 +9,0 @@ |
'use strict'; | ||
exports.name = 'addClassesToSVGElement'; | ||
exports.type = 'full'; | ||
@@ -4,0 +6,0 @@ |
'use strict'; | ||
exports.type = 'perItem'; | ||
exports.name = 'cleanupAttrs'; | ||
exports.type = 'visitor'; | ||
exports.active = true; | ||
exports.description = | ||
'cleanups attributes from newlines, trailing and repeating spaces'; | ||
exports.params = { | ||
newlines: true, | ||
trim: true, | ||
spaces: true, | ||
}; | ||
const regNewlinesNeedSpace = /(\S)\r?\n(\S)/g; | ||
const regNewlines = /\r?\n/g; | ||
const regSpaces = /\s{2,}/g; | ||
var regNewlinesNeedSpace = /(\S)\r?\n(\S)/g, | ||
regNewlines = /\r?\n/g, | ||
regSpaces = /\s{2,}/g; | ||
/** | ||
* Cleanup attributes values from newlines, trailing and repeating spaces. | ||
* | ||
* @param {Object} item current iteration item | ||
* @param {Object} params plugin params | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Kir Belevich | ||
*/ | ||
exports.fn = function (item, params) { | ||
if (item.type === 'element') { | ||
for (const name of Object.keys(item.attributes)) { | ||
if (params.newlines) { | ||
// new line which requires a space instead of themselve | ||
item.attributes[name] = item.attributes[name].replace( | ||
regNewlinesNeedSpace, | ||
(match, p1, p2) => p1 + ' ' + p2 | ||
); | ||
// simple new line | ||
item.attributes[name] = item.attributes[name].replace(regNewlines, ''); | ||
} | ||
if (params.trim) { | ||
item.attributes[name] = item.attributes[name].trim(); | ||
} | ||
if (params.spaces) { | ||
item.attributes[name] = item.attributes[name].replace(regSpaces, ' '); | ||
} | ||
} | ||
} | ||
exports.fn = (root, params) => { | ||
const { newlines = true, trim = true, spaces = true } = params; | ||
return { | ||
element: { | ||
enter: (node) => { | ||
for (const name of Object.keys(node.attributes)) { | ||
if (newlines) { | ||
// new line which requires a space instead of themselve | ||
node.attributes[name] = node.attributes[name].replace( | ||
regNewlinesNeedSpace, | ||
(match, p1, p2) => p1 + ' ' + p2 | ||
); | ||
// simple new line | ||
node.attributes[name] = node.attributes[name].replace( | ||
regNewlines, | ||
'' | ||
); | ||
} | ||
if (trim) { | ||
node.attributes[name] = node.attributes[name].trim(); | ||
} | ||
if (spaces) { | ||
node.attributes[name] = node.attributes[name].replace( | ||
regSpaces, | ||
' ' | ||
); | ||
} | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'cleanupEnableBackground'; | ||
exports.type = 'full'; | ||
@@ -7,0 +9,0 @@ |
@@ -6,2 +6,4 @@ 'use strict'; | ||
exports.name = 'cleanupIDs'; | ||
exports.type = 'full'; | ||
@@ -8,0 +10,0 @@ |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'cleanupListOfValues'; | ||
exports.type = 'perItem'; | ||
@@ -7,0 +9,0 @@ |
'use strict'; | ||
exports.name = 'cleanupNumericValues'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'collapseGroups'; | ||
exports.type = 'perItemReverse'; | ||
@@ -7,0 +9,0 @@ |
'use strict'; | ||
exports.name = 'convertColors'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
'use strict'; | ||
exports.type = 'perItem'; | ||
exports.name = 'convertEllipseToCircle'; | ||
exports.type = 'visitor'; | ||
exports.active = true; | ||
exports.description = 'converts non-eccentric <ellipse>s to <circle>s'; | ||
@@ -14,24 +13,26 @@ | ||
* | ||
* @param {Object} item current iteration item | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Taylor Hunt | ||
*/ | ||
exports.fn = function (item) { | ||
if (item.isElem('ellipse')) { | ||
const rx = item.attributes.rx || 0; | ||
const ry = item.attributes.ry || 0; | ||
if ( | ||
rx === ry || | ||
rx === 'auto' || | ||
ry === 'auto' // SVG2 | ||
) { | ||
var radius = rx !== 'auto' ? rx : ry; | ||
item.renameElem('circle'); | ||
delete item.attributes.rx; | ||
delete item.attributes.ry; | ||
item.attributes.r = radius; | ||
} | ||
} | ||
exports.fn = () => { | ||
return { | ||
element: { | ||
enter: (node) => { | ||
if (node.name === 'ellipse') { | ||
const rx = node.attributes.rx || 0; | ||
const ry = node.attributes.ry || 0; | ||
if ( | ||
rx === ry || | ||
rx === 'auto' || | ||
ry === 'auto' // SVG2 | ||
) { | ||
node.name = 'circle'; | ||
const radius = rx === 'auto' ? ry : rx; | ||
delete node.attributes.rx; | ||
delete node.attributes.ry; | ||
node.attributes.r = radius; | ||
} | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
'use strict'; | ||
const { computeStyle } = require('../lib/style.js'); | ||
const { collectStylesheet, computeStyle } = require('../lib/style.js'); | ||
const { pathElems } = require('./_collections.js'); | ||
@@ -9,2 +9,3 @@ const { path2js, js2path } = require('./_path.js'); | ||
exports.name = 'convertPathData'; | ||
exports.type = 'visitor'; | ||
@@ -59,2 +60,3 @@ exports.active = true; | ||
exports.fn = (root, params) => { | ||
const stylesheet = collectStylesheet(root); | ||
return { | ||
@@ -64,3 +66,3 @@ element: { | ||
if (pathElems.includes(node.name) && node.attributes.d != null) { | ||
const computedStyle = computeStyle(node); | ||
const computedStyle = computeStyle(stylesheet, node); | ||
precision = params.floatPrecision; | ||
@@ -67,0 +69,0 @@ error = |
'use strict'; | ||
const { stringifyPathData } = require('../lib/path.js'); | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
exports.type = 'perItem'; | ||
exports.name = 'convertShapeToPath'; | ||
exports.type = 'visitor'; | ||
exports.active = true; | ||
exports.description = 'converts basic shapes to more compact path form'; | ||
exports.params = { | ||
convertArcs: false, | ||
floatPrecision: null, | ||
}; | ||
const regNumber = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g; | ||
@@ -25,122 +20,133 @@ | ||
* | ||
* @param {Object} item current iteration item | ||
* @param {Object} params plugin params | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Lev Solntsev | ||
*/ | ||
exports.fn = function (item, params) { | ||
const precision = params ? params.floatPrecision : null; | ||
const convertArcs = params && params.convertArcs; | ||
exports.fn = (root, params) => { | ||
const { convertArcs = false, floatPrecision: precision = null } = params; | ||
if ( | ||
item.isElem('rect') && | ||
item.attributes.width != null && | ||
item.attributes.height != null && | ||
item.attributes.rx == null && | ||
item.attributes.ry == null | ||
) { | ||
const x = Number(item.attributes.x || '0'); | ||
const y = Number(item.attributes.y || '0'); | ||
const width = Number(item.attributes.width); | ||
const height = Number(item.attributes.height); | ||
// Values like '100%' compute to NaN, thus running after | ||
// cleanupNumericValues when 'px' units has already been removed. | ||
// TODO: Calculate sizes from % and non-px units if possible. | ||
if (isNaN(x - y + width - height)) return; | ||
const pathData = [ | ||
{ command: 'M', args: [x, y] }, | ||
{ command: 'H', args: [x + width] }, | ||
{ command: 'V', args: [y + height] }, | ||
{ command: 'H', args: [x] }, | ||
{ command: 'z', args: [] }, | ||
]; | ||
item.attributes.d = stringifyPathData({ pathData, precision }); | ||
item.renameElem('path'); | ||
delete item.attributes.x; | ||
delete item.attributes.y; | ||
delete item.attributes.width; | ||
delete item.attributes.height; | ||
} | ||
return { | ||
element: { | ||
enter: (node, parentNode) => { | ||
// convert rect to path | ||
if ( | ||
node.name === 'rect' && | ||
node.attributes.width != null && | ||
node.attributes.height != null && | ||
node.attributes.rx == null && | ||
node.attributes.ry == null | ||
) { | ||
const x = Number(node.attributes.x || '0'); | ||
const y = Number(node.attributes.y || '0'); | ||
const width = Number(node.attributes.width); | ||
const height = Number(node.attributes.height); | ||
// Values like '100%' compute to NaN, thus running after | ||
// cleanupNumericValues when 'px' units has already been removed. | ||
// TODO: Calculate sizes from % and non-px units if possible. | ||
if (Number.isNaN(x - y + width - height)) return; | ||
const pathData = [ | ||
{ command: 'M', args: [x, y] }, | ||
{ command: 'H', args: [x + width] }, | ||
{ command: 'V', args: [y + height] }, | ||
{ command: 'H', args: [x] }, | ||
{ command: 'z', args: [] }, | ||
]; | ||
node.name = 'path'; | ||
node.attributes.d = stringifyPathData({ pathData, precision }); | ||
delete node.attributes.x; | ||
delete node.attributes.y; | ||
delete node.attributes.width; | ||
delete node.attributes.height; | ||
} | ||
if (item.isElem('line')) { | ||
const x1 = Number(item.attributes.x1 || '0'); | ||
const y1 = Number(item.attributes.y1 || '0'); | ||
const x2 = Number(item.attributes.x2 || '0'); | ||
const y2 = Number(item.attributes.y2 || '0'); | ||
if (isNaN(x1 - y1 + x2 - y2)) return; | ||
const pathData = [ | ||
{ command: 'M', args: [x1, y1] }, | ||
{ command: 'L', args: [x2, y2] }, | ||
]; | ||
item.attributes.d = stringifyPathData({ pathData, precision }); | ||
item.renameElem('path'); | ||
delete item.attributes.x1; | ||
delete item.attributes.y1; | ||
delete item.attributes.x2; | ||
delete item.attributes.y2; | ||
} | ||
// convert line to path | ||
if (node.name === 'line') { | ||
const x1 = Number(node.attributes.x1 || '0'); | ||
const y1 = Number(node.attributes.y1 || '0'); | ||
const x2 = Number(node.attributes.x2 || '0'); | ||
const y2 = Number(node.attributes.y2 || '0'); | ||
if (Number.isNaN(x1 - y1 + x2 - y2)) return; | ||
const pathData = [ | ||
{ command: 'M', args: [x1, y1] }, | ||
{ command: 'L', args: [x2, y2] }, | ||
]; | ||
node.name = 'path'; | ||
node.attributes.d = stringifyPathData({ pathData, precision }); | ||
delete node.attributes.x1; | ||
delete node.attributes.y1; | ||
delete node.attributes.x2; | ||
delete node.attributes.y2; | ||
} | ||
if ( | ||
(item.isElem('polyline') || item.isElem('polygon')) && | ||
item.attributes.points != null | ||
) { | ||
const coords = (item.attributes.points.match(regNumber) || []).map(Number); | ||
if (coords.length < 4) return false; | ||
const pathData = []; | ||
for (let i = 0; i < coords.length; i += 2) { | ||
pathData.push({ | ||
command: i === 0 ? 'M' : 'L', | ||
args: coords.slice(i, i + 2), | ||
}); | ||
} | ||
if (item.isElem('polygon')) { | ||
pathData.push({ command: 'z', args: [] }); | ||
} | ||
item.attributes.d = stringifyPathData({ pathData, precision }); | ||
item.renameElem('path'); | ||
delete item.attributes.points; | ||
} | ||
// convert polyline and polygon to path | ||
if ( | ||
(node.name === 'polyline' || node.name === 'polygon') && | ||
node.attributes.points != null | ||
) { | ||
const coords = (node.attributes.points.match(regNumber) || []).map( | ||
Number | ||
); | ||
if (coords.length < 4) { | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
} | ||
const pathData = []; | ||
for (let i = 0; i < coords.length; i += 2) { | ||
pathData.push({ | ||
command: i === 0 ? 'M' : 'L', | ||
args: coords.slice(i, i + 2), | ||
}); | ||
} | ||
if (node.name === 'polygon') { | ||
pathData.push({ command: 'z', args: [] }); | ||
} | ||
node.name = 'path'; | ||
node.attributes.d = stringifyPathData({ pathData, precision }); | ||
delete node.attributes.points; | ||
} | ||
if (item.isElem('circle') && convertArcs) { | ||
const cx = Number(item.attributes.cx || '0'); | ||
const cy = Number(item.attributes.cy || '0'); | ||
const r = Number(item.attributes.r || '0'); | ||
if (isNaN(cx - cy + r)) { | ||
return; | ||
} | ||
const pathData = [ | ||
{ command: 'M', args: [cx, cy - r] }, | ||
{ command: 'A', args: [r, r, 0, 1, 0, cx, cy + r] }, | ||
{ command: 'A', args: [r, r, 0, 1, 0, cx, cy - r] }, | ||
{ command: 'z', args: [] }, | ||
]; | ||
item.attributes.d = stringifyPathData({ pathData, precision }); | ||
item.renameElem('path'); | ||
delete item.attributes.cx; | ||
delete item.attributes.cy; | ||
delete item.attributes.r; | ||
} | ||
// optionally convert circle | ||
if (node.name === 'circle' && convertArcs) { | ||
const cx = Number(node.attributes.cx || '0'); | ||
const cy = Number(node.attributes.cy || '0'); | ||
const r = Number(node.attributes.r || '0'); | ||
if (Number.isNaN(cx - cy + r)) { | ||
return; | ||
} | ||
const pathData = [ | ||
{ command: 'M', args: [cx, cy - r] }, | ||
{ command: 'A', args: [r, r, 0, 1, 0, cx, cy + r] }, | ||
{ command: 'A', args: [r, r, 0, 1, 0, cx, cy - r] }, | ||
{ command: 'z', args: [] }, | ||
]; | ||
node.name = 'path'; | ||
node.attributes.d = stringifyPathData({ pathData, precision }); | ||
delete node.attributes.cx; | ||
delete node.attributes.cy; | ||
delete node.attributes.r; | ||
} | ||
if (item.isElem('ellipse') && convertArcs) { | ||
const ecx = Number(item.attributes.cx || '0'); | ||
const ecy = Number(item.attributes.cy || '0'); | ||
const rx = Number(item.attributes.rx || '0'); | ||
const ry = Number(item.attributes.ry || '0'); | ||
if (isNaN(ecx - ecy + rx - ry)) { | ||
return; | ||
} | ||
const pathData = [ | ||
{ command: 'M', args: [ecx, ecy - ry] }, | ||
{ command: 'A', args: [rx, ry, 0, 1, 0, ecx, ecy + ry] }, | ||
{ command: 'A', args: [rx, ry, 0, 1, 0, ecx, ecy - ry] }, | ||
{ command: 'z', args: [] }, | ||
]; | ||
item.attributes.d = stringifyPathData({ pathData, precision }); | ||
item.renameElem('path'); | ||
delete item.attributes.cx; | ||
delete item.attributes.cy; | ||
delete item.attributes.rx; | ||
delete item.attributes.ry; | ||
} | ||
// optionally covert ellipse | ||
if (node.name === 'ellipse' && convertArcs) { | ||
const ecx = Number(node.attributes.cx || '0'); | ||
const ecy = Number(node.attributes.cy || '0'); | ||
const rx = Number(node.attributes.rx || '0'); | ||
const ry = Number(node.attributes.ry || '0'); | ||
if (Number.isNaN(ecx - ecy + rx - ry)) { | ||
return; | ||
} | ||
const pathData = [ | ||
{ command: 'M', args: [ecx, ecy - ry] }, | ||
{ command: 'A', args: [rx, ry, 0, 1, 0, ecx, ecy + ry] }, | ||
{ command: 'A', args: [rx, ry, 0, 1, 0, ecx, ecy - ry] }, | ||
{ command: 'z', args: [] }, | ||
]; | ||
node.name = 'path'; | ||
node.attributes.d = stringifyPathData({ pathData, precision }); | ||
delete node.attributes.cx; | ||
delete node.attributes.cy; | ||
delete node.attributes.rx; | ||
delete node.attributes.ry; | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
'use strict'; | ||
exports.name = 'convertStyleToAttrs'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
'use strict'; | ||
exports.name = 'convertTransform'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
@@ -7,2 +7,4 @@ 'use strict'; | ||
exports.name = 'inlineStyles'; | ||
exports.type = 'full'; | ||
@@ -9,0 +11,0 @@ |
'use strict'; | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
const { computeStyle } = require('../lib/style.js'); | ||
const { collectStylesheet, computeStyle } = require('../lib/style.js'); | ||
const { path2js, js2path, intersects } = require('./_path.js'); | ||
exports.name = 'mergePaths'; | ||
exports.type = 'visitor'; | ||
@@ -25,2 +26,3 @@ exports.active = true; | ||
} = params; | ||
const stylesheet = collectStylesheet(root); | ||
@@ -57,3 +59,3 @@ return { | ||
// preserve paths with markers | ||
const computedStyle = computeStyle(child); | ||
const computedStyle = computeStyle(stylesheet, child); | ||
if ( | ||
@@ -92,3 +94,3 @@ computedStyle['marker-start'] || | ||
}); | ||
detachNodeFromParent(child); | ||
detachNodeFromParent(child, node); | ||
continue; | ||
@@ -95,0 +97,0 @@ } |
@@ -6,2 +6,3 @@ 'use strict'; | ||
exports.name = 'mergeStyles'; | ||
exports.type = 'visitor'; | ||
@@ -21,3 +22,3 @@ exports.active = true; | ||
const enterElement = (node) => { | ||
const enterElement = (node, parentNode) => { | ||
// collect style elements | ||
@@ -56,3 +57,3 @@ if (node.name !== 'style') { | ||
if (css.trim().length === 0) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -73,3 +74,3 @@ } | ||
} else { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
firstStyleElement.children = [ | ||
@@ -76,0 +77,0 @@ new JSAPI( |
@@ -6,2 +6,4 @@ 'use strict'; | ||
exports.name = 'minifyStyles'; | ||
exports.type = 'full'; | ||
@@ -8,0 +10,0 @@ |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'moveElemsAttrsToGroup'; | ||
exports.type = 'perItemReverse'; | ||
@@ -7,0 +9,0 @@ |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'moveGroupAttrsToElems'; | ||
exports.type = 'perItem'; | ||
@@ -7,0 +9,0 @@ |
'use strict'; | ||
// builtin presets | ||
exports['preset-default'] = require('./preset-default.js'); | ||
// builtin plugins | ||
exports.addAttributesToSVGElement = require('./addAttributesToSVGElement.js'); | ||
@@ -4,0 +8,0 @@ exports.addClassesToSVGElement = require('./addClassesToSVGElement.js'); |
'use strict'; | ||
exports.name = 'prefixIds'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
'use strict'; | ||
exports.name = 'removeAttributesBySelector'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'removeAttrs'; | ||
exports.type = 'perItem'; | ||
@@ -7,0 +9,0 @@ |
'use strict'; | ||
exports.type = 'perItem'; | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
exports.name = 'removeComments'; | ||
exports.type = 'visitor'; | ||
exports.active = true; | ||
exports.description = 'removes comments'; | ||
@@ -16,11 +17,14 @@ | ||
* | ||
* @param {Object} item current iteration item | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Kir Belevich | ||
*/ | ||
exports.fn = function (item) { | ||
if (item.type === 'comment' && item.value.charAt(0) !== '!') { | ||
return false; | ||
} | ||
exports.fn = () => { | ||
return { | ||
comment: { | ||
enter: (node, parentNode) => { | ||
if (node.value.charAt(0) !== '!') { | ||
detachNodeFromParent(node, parentNode); | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
'use strict'; | ||
exports.type = 'perItem'; | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
exports.name = 'removeDesc'; | ||
exports.type = 'visitor'; | ||
exports.active = true; | ||
exports.params = { | ||
removeAny: true, | ||
}; | ||
exports.description = 'removes <desc>'; | ||
var standardDescs = /^(Created with|Created using)/; | ||
const standardDescs = /^(Created with|Created using)/; | ||
@@ -22,17 +19,22 @@ /** | ||
* | ||
* @param {Object} item current iteration item | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Daniel Wabyick | ||
*/ | ||
exports.fn = function (item, params) { | ||
return ( | ||
!item.isElem('desc') || | ||
!( | ||
params.removeAny || | ||
item.children.length === 0 || | ||
(item.children[0].type === 'text' && | ||
standardDescs.test(item.children[0].value)) | ||
) | ||
); | ||
exports.fn = (root, params) => { | ||
const { removeAny = true } = params; | ||
return { | ||
element: { | ||
enter: (node, parentNode) => { | ||
if (node.name === 'desc') { | ||
if ( | ||
removeAny || | ||
node.children.length === 0 || | ||
(node.children[0].type === 'text' && | ||
standardDescs.test(node.children[0].value)) | ||
) { | ||
detachNodeFromParent(node, parentNode); | ||
} | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
'use strict'; | ||
exports.name = 'removeDimensions'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
'use strict'; | ||
exports.type = 'perItem'; | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
exports.name = 'removeDoctype'; | ||
exports.type = 'visitor'; | ||
exports.active = true; | ||
exports.description = 'removes doctype declaration'; | ||
@@ -29,11 +30,12 @@ | ||
* | ||
* @param {Object} item current iteration item | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Kir Belevich | ||
*/ | ||
exports.fn = function (item) { | ||
if (item.type === 'doctype') { | ||
return false; | ||
} | ||
exports.fn = () => { | ||
return { | ||
doctype: { | ||
enter: (node, parentNode) => { | ||
detachNodeFromParent(node, parentNode); | ||
}, | ||
}, | ||
}; | ||
}; |
@@ -6,2 +6,4 @@ 'use strict'; | ||
exports.name = 'removeEditorsNSData'; | ||
exports.type = 'perItem'; | ||
@@ -8,0 +10,0 @@ |
'use strict'; | ||
exports.name = 'removeElementsByAttr'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'removeEmptyAttrs'; | ||
exports.type = 'perItem'; | ||
@@ -7,0 +9,0 @@ |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'removeEmptyContainers'; | ||
exports.type = 'perItemReverse'; | ||
@@ -7,0 +9,0 @@ |
'use strict'; | ||
exports.type = 'perItem'; | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
exports.name = 'removeEmptyText'; | ||
exports.type = 'visitor'; | ||
exports.active = true; | ||
exports.description = 'removes empty <text> elements'; | ||
exports.params = { | ||
text: true, | ||
tspan: true, | ||
tref: true, | ||
}; | ||
/** | ||
@@ -30,29 +25,28 @@ * Remove empty Text elements. | ||
* | ||
* @param {Object} item current iteration item | ||
* @param {Object} params plugin params | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Kir Belevich | ||
*/ | ||
exports.fn = function (item, params) { | ||
if (item.type === 'element') { | ||
// Remove empty text element | ||
if (params.text && item.name === 'text' && item.children.length === 0) { | ||
return false; | ||
} | ||
// Remove empty tspan element | ||
if (params.tspan && item.name === 'tspan' && item.children.length === 0) { | ||
return false; | ||
} | ||
// Remove tref with empty xlink:href attribute | ||
if ( | ||
params.tref && | ||
item.name === 'tref' && | ||
item.attributes['xlink:href'] == null | ||
) { | ||
return false; | ||
} | ||
} | ||
exports.fn = (root, params) => { | ||
const { text = true, tspan = true, tref = true } = params; | ||
return { | ||
element: { | ||
enter: (node, parentNode) => { | ||
// Remove empty text element | ||
if (text && node.name === 'text' && node.children.length === 0) { | ||
detachNodeFromParent(node, parentNode); | ||
} | ||
// Remove empty tspan element | ||
if (tspan && node.name === 'tspan' && node.children.length === 0) { | ||
detachNodeFromParent(node, parentNode); | ||
} | ||
// Remove tref with empty xlink:href attribute | ||
if ( | ||
tref && | ||
node.name === 'tref' && | ||
node.attributes['xlink:href'] == null | ||
) { | ||
detachNodeFromParent(node, parentNode); | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
@@ -8,5 +8,6 @@ 'use strict'; | ||
} = require('../lib/xast.js'); | ||
const { computeStyle } = require('../lib/style.js'); | ||
const { collectStylesheet, computeStyle } = require('../lib/style.js'); | ||
const { parsePathData } = require('../lib/path.js'); | ||
exports.name = 'removeHiddenElems'; | ||
exports.type = 'visitor'; | ||
@@ -53,8 +54,10 @@ exports.active = true; | ||
} = params; | ||
const stylesheet = collectStylesheet(root); | ||
return { | ||
element: { | ||
enter: (node) => { | ||
enter: (node, parentNode) => { | ||
// Removes hidden elements | ||
// https://www.w3schools.com/cssref/pr_class_visibility.asp | ||
const computedStyle = computeStyle(node); | ||
const computedStyle = computeStyle(stylesheet, node); | ||
if ( | ||
@@ -68,3 +71,3 @@ isHidden && | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -86,3 +89,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -102,3 +105,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -119,3 +122,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -136,3 +139,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -153,3 +156,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -170,3 +173,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -188,3 +191,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -204,3 +207,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -220,3 +223,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -236,3 +239,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -252,3 +255,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -264,3 +267,3 @@ } | ||
if (node.attributes.d == null) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -270,3 +273,3 @@ } | ||
if (pathData.length === 0) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -280,3 +283,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -297,3 +300,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -312,3 +315,3 @@ } | ||
) { | ||
detachNodeFromParent(node); | ||
detachNodeFromParent(node, parentNode); | ||
return; | ||
@@ -315,0 +318,0 @@ } |
'use strict'; | ||
exports.type = 'perItem'; | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
exports.name = 'removeMetadata'; | ||
exports.type = 'visitor'; | ||
exports.active = true; | ||
exports.description = 'removes <metadata>'; | ||
@@ -14,9 +15,14 @@ | ||
* | ||
* @param {Object} item current iteration item | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Kir Belevich | ||
*/ | ||
exports.fn = function (item) { | ||
return !item.isElem('metadata'); | ||
exports.fn = () => { | ||
return { | ||
element: { | ||
enter: (node, parentNode) => { | ||
if (node.name === 'metadata') { | ||
detachNodeFromParent(node, parentNode); | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
'use strict'; | ||
exports.name = 'removeNonInheritableGroupAttrs'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
'use strict'; | ||
exports.name = 'removeOffCanvasPaths'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
'use strict'; | ||
exports.type = 'perItem'; | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
exports.name = 'removeRasterImages'; | ||
exports.type = 'visitor'; | ||
exports.active = false; | ||
exports.description = 'removes raster images (disabled by default)'; | ||
@@ -14,16 +15,18 @@ | ||
* | ||
* @param {Object} item current iteration item | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Kir Belevich | ||
*/ | ||
exports.fn = function (item) { | ||
if ( | ||
item.type === 'element' && | ||
item.name === 'image' && | ||
item.attributes['xlink:href'] != null && | ||
/(\.|image\/)(jpg|png|gif)/.test(item.attributes['xlink:href']) | ||
) { | ||
return false; | ||
} | ||
exports.fn = () => { | ||
return { | ||
element: { | ||
enter: (node, parentNode) => { | ||
if ( | ||
node.name === 'image' && | ||
node.attributes['xlink:href'] != null && | ||
/(\.|image\/)(jpg|png|gif)/.test(node.attributes['xlink:href']) | ||
) { | ||
detachNodeFromParent(node, parentNode); | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
'use strict'; | ||
exports.type = 'perItem'; | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
exports.name = 'removeScriptElement'; | ||
exports.type = 'visitor'; | ||
exports.active = false; | ||
exports.description = 'removes <script> elements (disabled by default)'; | ||
@@ -14,9 +15,15 @@ | ||
* | ||
* @param {Object} item current iteration item | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Patrick Klingemann | ||
*/ | ||
exports.fn = function (item) { | ||
return !item.isElem('script'); | ||
exports.fn = () => { | ||
return { | ||
element: { | ||
enter: (node, parentNode) => { | ||
if (node.name === 'script') { | ||
detachNodeFromParent(node, parentNode); | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
'use strict'; | ||
exports.type = 'perItem'; | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
exports.name = 'removeStyleElement'; | ||
exports.type = 'visitor'; | ||
exports.active = false; | ||
exports.description = 'removes <style> element (disabled by default)'; | ||
@@ -14,9 +15,14 @@ | ||
* | ||
* @param {Object} item current iteration item | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Betsy Dupuis | ||
*/ | ||
exports.fn = function (item) { | ||
return !item.isElem('style'); | ||
exports.fn = () => { | ||
return { | ||
element: { | ||
enter: (node, parentNode) => { | ||
if (node.name === 'style') { | ||
detachNodeFromParent(node, parentNode); | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
'use strict'; | ||
exports.type = 'perItem'; | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
exports.name = 'removeTitle'; | ||
exports.type = 'visitor'; | ||
exports.active = true; | ||
exports.description = 'removes <title>'; | ||
@@ -14,9 +15,14 @@ | ||
* | ||
* @param {Object} item current iteration item | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Igor Kalashnikov | ||
*/ | ||
exports.fn = function (item) { | ||
return !item.isElem('title'); | ||
exports.fn = () => { | ||
return { | ||
element: { | ||
enter: (node, parentNode) => { | ||
if (node.name === 'title') { | ||
detachNodeFromParent(node, parentNode); | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'removeUnknownsAndDefaults'; | ||
exports.type = 'perItem'; | ||
@@ -7,0 +9,0 @@ |
@@ -6,2 +6,4 @@ 'use strict'; | ||
exports.name = 'removeUnusedNS'; | ||
exports.type = 'full'; | ||
@@ -8,0 +10,0 @@ |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'removeUselessDefs'; | ||
exports.type = 'perItem'; | ||
@@ -7,0 +9,0 @@ |
'use strict'; | ||
exports.name = 'removeUselessStrokeAndFill'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'removeViewBox'; | ||
exports.type = 'perItem'; | ||
@@ -7,0 +9,0 @@ |
'use strict'; | ||
exports.name = 'removeXMLNS'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
'use strict'; | ||
exports.type = 'perItem'; | ||
const { detachNodeFromParent } = require('../lib/xast.js'); | ||
exports.name = 'removeXMLProcInst'; | ||
exports.type = 'visitor'; | ||
exports.active = true; | ||
exports.description = 'removes XML processing instructions'; | ||
@@ -15,12 +16,14 @@ | ||
* | ||
* @param {Object} item current iteration item | ||
* @return {Boolean} if false, item will be filtered out | ||
* | ||
* @author Kir Belevich | ||
*/ | ||
exports.fn = function (item) { | ||
if (item.type === 'instruction' && item.name === 'xml') { | ||
return false; | ||
} | ||
return true; | ||
exports.fn = () => { | ||
return { | ||
instruction: { | ||
enter: (node, parentNode) => { | ||
if (node.name === 'xml') { | ||
detachNodeFromParent(node, parentNode); | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
@@ -6,2 +6,4 @@ 'use strict'; | ||
exports.name = 'reusePaths'; | ||
exports.type = 'full'; | ||
@@ -8,0 +10,0 @@ |
@@ -5,2 +5,4 @@ 'use strict'; | ||
exports.name = 'sortAttrs'; | ||
exports.type = 'perItem'; | ||
@@ -7,0 +9,0 @@ |
'use strict'; | ||
exports.name = 'sortDefsChildren'; | ||
exports.type = 'perItem'; | ||
@@ -4,0 +6,0 @@ |
299
README.md
@@ -5,3 +5,2 @@ <div align="center"> | ||
## SVGO [![npm version](https://img.shields.io/npm/v/svgo)](https://npmjs.org/package/svgo) [![Discord](https://img.shields.io/discord/815166721315831868)](https://discord.gg/z8jX8NYxrE) | ||
@@ -57,4 +56,4 @@ | ||
pretty: true, // boolean, false by default | ||
} | ||
} | ||
}, | ||
}; | ||
``` | ||
@@ -72,3 +71,3 @@ | ||
{ | ||
name: 'builtinPluginName' | ||
name: 'builtinPluginName', | ||
}, | ||
@@ -79,87 +78,73 @@ // some plugins allow/require to pass options | ||
params: { | ||
optionName: 'optionValue' | ||
} | ||
} | ||
] | ||
} | ||
optionName: 'optionValue', | ||
}, | ||
}, | ||
], | ||
}; | ||
``` | ||
The default list is fully overridden if the `plugins` field is specified. To extend the default | ||
list use the `extendDefaultPlugins` utility: | ||
The default preset of plugins is fully overridden if the `plugins` field is specified. | ||
Use `preset-default` plugin to customize plugins options. | ||
```js | ||
const { extendDefaultPlugins } = require('svgo'); | ||
module.exports = { | ||
plugins: extendDefaultPlugins([ | ||
plugins: [ | ||
{ | ||
name: 'builtinPluginName', | ||
name: 'preset-default', | ||
params: { | ||
optionName: 'optionValue' | ||
} | ||
} | ||
]) | ||
} | ||
overrides: { | ||
// customize options | ||
builtinPluginName: { | ||
optionName: 'optionValue', | ||
}, | ||
// or disable plugins | ||
anotherBuiltinPlugin: false, | ||
}, | ||
}, | ||
}, | ||
], | ||
}; | ||
``` | ||
To disable one of the default plugins use the `active` field: | ||
Default preset includes the following list of plugins: | ||
```js | ||
const { extendDefaultPlugins } = require('svgo'); | ||
module.exports = { | ||
plugins: extendDefaultPlugins([ | ||
{ | ||
name: 'builtinPluginName', | ||
active: false | ||
} | ||
]) | ||
} | ||
``` | ||
- removeDoctype | ||
- removeXMLProcInst | ||
- removeComments | ||
- removeMetadata | ||
- removeEditorsNSData | ||
- cleanupAttrs | ||
- mergeStyles | ||
- inlineStyles | ||
- minifyStyles | ||
- cleanupIDs | ||
- removeUselessDefs | ||
- cleanupNumericValues | ||
- convertColors | ||
- removeUnknownsAndDefaults | ||
- removeNonInheritableGroupAttrs | ||
- removeUselessStrokeAndFill | ||
- removeViewBox | ||
- cleanupEnableBackground | ||
- removeHiddenElems | ||
- removeEmptyText | ||
- convertShapeToPath | ||
- convertEllipseToCircle | ||
- moveElemsAttrsToGroup | ||
- moveGroupAttrsToElems | ||
- collapseGroups | ||
- convertPathData | ||
- convertTransform | ||
- removeEmptyAttrs | ||
- removeEmptyContainers | ||
- mergePaths | ||
- removeUnusedNS | ||
- sortDefsChildren | ||
- removeTitle | ||
- removeDesc | ||
See the list of the default plugins: | ||
```js | ||
module.exports = { | ||
plugins: [ | ||
'removeDoctype', | ||
'removeXMLProcInst', | ||
'removeComments', | ||
'removeMetadata', | ||
'removeEditorsNSData', | ||
'cleanupAttrs', | ||
'mergeStyles', | ||
'inlineStyles', | ||
'minifyStyles', | ||
'cleanupIDs', | ||
'removeUselessDefs', | ||
'cleanupNumericValues', | ||
'convertColors', | ||
'removeUnknownsAndDefaults', | ||
'removeNonInheritableGroupAttrs', | ||
'removeUselessStrokeAndFill', | ||
'removeViewBox', | ||
'cleanupEnableBackground', | ||
'removeHiddenElems', | ||
'removeEmptyText', | ||
'convertShapeToPath', | ||
'convertEllipseToCircle', | ||
'moveElemsAttrsToGroup', | ||
'moveGroupAttrsToElems', | ||
'collapseGroups', | ||
'convertPathData', | ||
'convertTransform', | ||
'removeEmptyAttrs', | ||
'removeEmptyContainers', | ||
'mergePaths', | ||
'removeUnusedNS', | ||
'sortDefsChildren', | ||
'removeTitle', | ||
'removeDesc' | ||
] | ||
} | ||
``` | ||
It's also possible to specify a custom plugin: | ||
```js | ||
const anotherCustomPlugin = require('./another-custom-plugin.js') | ||
const anotherCustomPlugin = require('./another-custom-plugin.js'); | ||
module.exports = { | ||
@@ -173,7 +158,7 @@ plugins: [ | ||
}, | ||
fn: (ast, params, info) => {} | ||
fn: (ast, params, info) => {}, | ||
}, | ||
anotherCustomPlugin | ||
] | ||
} | ||
anotherCustomPlugin, | ||
], | ||
}; | ||
``` | ||
@@ -195,5 +180,5 @@ | ||
// all config fields are also available here | ||
multipass: true | ||
}) | ||
const optimizedSvgString = result.data | ||
multipass: true, | ||
}); | ||
const optimizedSvgString = result.data; | ||
``` | ||
@@ -207,6 +192,6 @@ | ||
const { loadConfig } = require('svgo'); | ||
const config = await loadConfig() | ||
const config = await loadConfig(); | ||
// you can also specify a relative or absolute path and customize the current working directory | ||
const config = await loadConfig(configFile, cwd) | ||
const config = await loadConfig(configFile, cwd); | ||
``` | ||
@@ -216,75 +201,77 @@ | ||
| Plugin | Description | Default | | ||
| ------ | ----------- | ------- | | ||
| [cleanupAttrs](https://github.com/svg/svgo/blob/master/plugins/cleanupAttrs.js) | cleanup attributes from newlines, trailing, and repeating spaces | `enabled` | | ||
| [mergeStyles](https://github.com/svg/svgo/blob/master/plugins/mergeStyles.js) | merge multiple style elements into one | `enabled` | | ||
| [inlineStyles](https://github.com/svg/svgo/blob/master/plugins/inlineStyles.js) | move and merge styles from `<style>` elements to element `style` attributes | `enabled` | | ||
| [removeDoctype](https://github.com/svg/svgo/blob/master/plugins/removeDoctype.js) | remove `doctype` declaration | `enabled` | | ||
| [removeXMLProcInst](https://github.com/svg/svgo/blob/master/plugins/removeXMLProcInst.js) | remove XML processing instructions | `enabled` | | ||
| [removeComments](https://github.com/svg/svgo/blob/master/plugins/removeComments.js) | remove comments | `enabled` | | ||
| [removeMetadata](https://github.com/svg/svgo/blob/master/plugins/removeMetadata.js) | remove `<metadata>` | `enabled` | | ||
| [removeTitle](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) | remove `<title>` | `enabled` | | ||
| [removeDesc](https://github.com/svg/svgo/blob/master/plugins/removeDesc.js) | remove `<desc>` | `enabled` | | ||
| [removeUselessDefs](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) | remove elements of `<defs>` without `id` | `enabled` | | ||
| [removeXMLNS](https://github.com/svg/svgo/blob/master/plugins/removeXMLNS.js) | removes the `xmlns` attribute (for inline SVG) | `disabled` | | ||
| [removeEditorsNSData](https://github.com/svg/svgo/blob/master/plugins/removeEditorsNSData.js) | remove editors namespaces, elements, and attributes | `enabled` | | ||
| [removeEmptyAttrs](https://github.com/svg/svgo/blob/master/plugins/removeEmptyAttrs.js) | remove empty attributes | `enabled` | | ||
| [removeHiddenElems](https://github.com/svg/svgo/blob/master/plugins/removeHiddenElems.js) | remove hidden elements | `enabled` | | ||
| [removeEmptyText](https://github.com/svg/svgo/blob/master/plugins/removeEmptyText.js) | remove empty Text elements | `enabled` | | ||
| [removeEmptyContainers](https://github.com/svg/svgo/blob/master/plugins/removeEmptyContainers.js) | remove empty Container elements | `enabled` | | ||
| [removeViewBox](https://github.com/svg/svgo/blob/master/plugins/removeViewBox.js) | remove `viewBox` attribute when possible | `enabled` | | ||
| [cleanupEnableBackground](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) | remove or cleanup `enable-background` attribute when possible | `enabled` | | ||
| [minifyStyles](https://github.com/svg/svgo/blob/master/plugins/minifyStyles.js) | minify `<style>` elements content with [CSSO](https://github.com/css/csso) | `enabled` | | ||
| [convertStyleToAttrs](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js) | convert styles into attributes | `disabled ` | | ||
| [convertColors](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) | convert colors (from `rgb()` to `#rrggbb`, from `#rrggbb` to `#rgb`) | `enabled` | | ||
| [convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) | convert Path data to relative or absolute (whichever is shorter), convert one segment to another, trim useless delimiters, smart rounding, and much more | `enabled` | | ||
| [convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js) | collapse multiple transforms into one, convert matrices to the short aliases, and much more | `enabled` | | ||
| [removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) | remove unknown elements content and attributes, remove attributes with default values | `enabled` | | ||
| [removeNonInheritableGroupAttrs](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) | remove non-inheritable group's "presentation" attributes | `enabled` | | ||
| [removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) | remove useless `stroke` and `fill` attributes | `enabled` | | ||
| [removeUnusedNS](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) | remove unused namespaces declaration | `enabled` | | ||
| [prefixIds](https://github.com/svg/svgo/blob/master/plugins/prefixIds.js) | prefix IDs and classes with the SVG filename or an arbitrary string | `disabled` | | ||
| [cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) | remove unused and minify used IDs | `enabled` | | ||
| [cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) | round numeric values to the fixed precision, remove default `px` units | `enabled` | | ||
| [cleanupListOfValues](https://github.com/svg/svgo/blob/master/plugins/cleanupListOfValues.js) | round numeric values in attributes that take a list of numbers (like `viewBox` or `enable-background`) | `disabled` | | ||
| [moveElemsAttrsToGroup](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup.js) | move elements' attributes to their enclosing group | `enabled` | | ||
| [moveGroupAttrsToElems](https://github.com/svg/svgo/blob/master/plugins/moveGroupAttrsToElems.js) | move some group attributes to the contained elements | `enabled` | | ||
| [collapseGroups](https://github.com/svg/svgo/blob/master/plugins/collapseGroups.js) | collapse useless groups | `enabled` | | ||
| [removeRasterImages](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) | remove raster images | `disabled` | | ||
| [mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) | merge multiple Paths into one | `enabled` | | ||
| [convertShapeToPath](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) | convert some basic shapes to `<path>` | `enabled` | | ||
| [convertEllipseToCircle](https://github.com/svg/svgo/blob/master/plugins/convertEllipseToCircle.js) | convert non-eccentric `<ellipse>` to `<circle>` | `enabled` | | ||
| [sortAttrs](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) | sort element attributes for epic readability | `disabled` | | ||
| [sortDefsChildren](https://github.com/svg/svgo/blob/master/plugins/sortDefsChildren.js) | sort children of `<defs>` in order to improve compression | `enabled` | | ||
| [removeDimensions](https://github.com/svg/svgo/blob/master/plugins/removeDimensions.js) | remove `width`/`height` and add `viewBox` if it's missing (opposite to removeViewBox, disable it first) | `disabled` | | ||
| [removeAttrs](https://github.com/svg/svgo/blob/master/plugins/removeAttrs.js) | remove attributes by pattern | `disabled` | | ||
| [removeAttributesBySelector](https://github.com/svg/svgo/blob/master/plugins/removeAttributesBySelector.js) | removes attributes of elements that match a CSS selector | `disabled` | | ||
| [removeElementsByAttr](https://github.com/svg/svgo/blob/master/plugins/removeElementsByAttr.js) | remove arbitrary elements by `ID` or `className` | `disabled` | | ||
| [addClassesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addClassesToSVGElement.js) | add classnames to an outer `<svg>` element | `disabled` | | ||
| [addAttributesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addAttributesToSVGElement.js) | adds attributes to an outer `<svg>` element | `disabled` | | ||
| [removeOffCanvasPaths](https://github.com/svg/svgo/blob/master/plugins/removeOffCanvasPaths.js) | removes elements that are drawn outside of the viewbox | `disabled` | | ||
| [removeStyleElement](https://github.com/svg/svgo/blob/master/plugins/removeStyleElement.js) | remove `<style>` elements | `disabled` | | ||
| [removeScriptElement](https://github.com/svg/svgo/blob/master/plugins/removeScriptElement.js) | remove `<script>` elements | `disabled` | | ||
| [reusePaths](https://github.com/svg/svgo/blob/master/plugins/reusePaths.js) | Find duplicated <path> elements and replace them with <use> links | `disabled` | | ||
| Plugin | Description | Default | | ||
| ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | | ||
| [cleanupAttrs](https://github.com/svg/svgo/blob/master/plugins/cleanupAttrs.js) | cleanup attributes from newlines, trailing, and repeating spaces | `enabled` | | ||
| [mergeStyles](https://github.com/svg/svgo/blob/master/plugins/mergeStyles.js) | merge multiple style elements into one | `enabled` | | ||
| [inlineStyles](https://github.com/svg/svgo/blob/master/plugins/inlineStyles.js) | move and merge styles from `<style>` elements to element `style` attributes | `enabled` | | ||
| [removeDoctype](https://github.com/svg/svgo/blob/master/plugins/removeDoctype.js) | remove `doctype` declaration | `enabled` | | ||
| [removeXMLProcInst](https://github.com/svg/svgo/blob/master/plugins/removeXMLProcInst.js) | remove XML processing instructions | `enabled` | | ||
| [removeComments](https://github.com/svg/svgo/blob/master/plugins/removeComments.js) | remove comments | `enabled` | | ||
| [removeMetadata](https://github.com/svg/svgo/blob/master/plugins/removeMetadata.js) | remove `<metadata>` | `enabled` | | ||
| [removeTitle](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) | remove `<title>` | `enabled` | | ||
| [removeDesc](https://github.com/svg/svgo/blob/master/plugins/removeDesc.js) | remove `<desc>` | `enabled` | | ||
| [removeUselessDefs](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) | remove elements of `<defs>` without `id` | `enabled` | | ||
| [removeXMLNS](https://github.com/svg/svgo/blob/master/plugins/removeXMLNS.js) | removes the `xmlns` attribute (for inline SVG) | `disabled` | | ||
| [removeEditorsNSData](https://github.com/svg/svgo/blob/master/plugins/removeEditorsNSData.js) | remove editors namespaces, elements, and attributes | `enabled` | | ||
| [removeEmptyAttrs](https://github.com/svg/svgo/blob/master/plugins/removeEmptyAttrs.js) | remove empty attributes | `enabled` | | ||
| [removeHiddenElems](https://github.com/svg/svgo/blob/master/plugins/removeHiddenElems.js) | remove hidden elements | `enabled` | | ||
| [removeEmptyText](https://github.com/svg/svgo/blob/master/plugins/removeEmptyText.js) | remove empty Text elements | `enabled` | | ||
| [removeEmptyContainers](https://github.com/svg/svgo/blob/master/plugins/removeEmptyContainers.js) | remove empty Container elements | `enabled` | | ||
| [removeViewBox](https://github.com/svg/svgo/blob/master/plugins/removeViewBox.js) | remove `viewBox` attribute when possible | `enabled` | | ||
| [cleanupEnableBackground](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) | remove or cleanup `enable-background` attribute when possible | `enabled` | | ||
| [minifyStyles](https://github.com/svg/svgo/blob/master/plugins/minifyStyles.js) | minify `<style>` elements content with [CSSO](https://github.com/css/csso) | `enabled` | | ||
| [convertStyleToAttrs](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js) | convert styles into attributes | `disabled` | | ||
| [convertColors](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) | convert colors (from `rgb()` to `#rrggbb`, from `#rrggbb` to `#rgb`) | `enabled` | | ||
| [convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) | convert Path data to relative or absolute (whichever is shorter), convert one segment to another, trim useless delimiters, smart rounding, and much more | `enabled` | | ||
| [convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js) | collapse multiple transforms into one, convert matrices to the short aliases, and much more | `enabled` | | ||
| [removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) | remove unknown elements content and attributes, remove attributes with default values | `enabled` | | ||
| [removeNonInheritableGroupAttrs](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) | remove non-inheritable group's "presentation" attributes | `enabled` | | ||
| [removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) | remove useless `stroke` and `fill` attributes | `enabled` | | ||
| [removeUnusedNS](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) | remove unused namespaces declaration | `enabled` | | ||
| [prefixIds](https://github.com/svg/svgo/blob/master/plugins/prefixIds.js) | prefix IDs and classes with the SVG filename or an arbitrary string | `disabled` | | ||
| [cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) | remove unused and minify used IDs | `enabled` | | ||
| [cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) | round numeric values to the fixed precision, remove default `px` units | `enabled` | | ||
| [cleanupListOfValues](https://github.com/svg/svgo/blob/master/plugins/cleanupListOfValues.js) | round numeric values in attributes that take a list of numbers (like `viewBox` or `enable-background`) | `disabled` | | ||
| [moveElemsAttrsToGroup](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup.js) | move elements' attributes to their enclosing group | `enabled` | | ||
| [moveGroupAttrsToElems](https://github.com/svg/svgo/blob/master/plugins/moveGroupAttrsToElems.js) | move some group attributes to the contained elements | `enabled` | | ||
| [collapseGroups](https://github.com/svg/svgo/blob/master/plugins/collapseGroups.js) | collapse useless groups | `enabled` | | ||
| [removeRasterImages](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) | remove raster images | `disabled` | | ||
| [mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) | merge multiple Paths into one | `enabled` | | ||
| [convertShapeToPath](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) | convert some basic shapes to `<path>` | `enabled` | | ||
| [convertEllipseToCircle](https://github.com/svg/svgo/blob/master/plugins/convertEllipseToCircle.js) | convert non-eccentric `<ellipse>` to `<circle>` | `enabled` | | ||
| [sortAttrs](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) | sort element attributes for epic readability | `disabled` | | ||
| [sortDefsChildren](https://github.com/svg/svgo/blob/master/plugins/sortDefsChildren.js) | sort children of `<defs>` in order to improve compression | `enabled` | | ||
| [removeDimensions](https://github.com/svg/svgo/blob/master/plugins/removeDimensions.js) | remove `width`/`height` and add `viewBox` if it's missing (opposite to removeViewBox, disable it first) | `disabled` | | ||
| [removeAttrs](https://github.com/svg/svgo/blob/master/plugins/removeAttrs.js) | remove attributes by pattern | `disabled` | | ||
| [removeAttributesBySelector](https://github.com/svg/svgo/blob/master/plugins/removeAttributesBySelector.js) | removes attributes of elements that match a CSS selector | `disabled` | | ||
| [removeElementsByAttr](https://github.com/svg/svgo/blob/master/plugins/removeElementsByAttr.js) | remove arbitrary elements by `ID` or `className` | `disabled` | | ||
| [addClassesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addClassesToSVGElement.js) | add classnames to an outer `<svg>` element | `disabled` | | ||
| [addAttributesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addAttributesToSVGElement.js) | adds attributes to an outer `<svg>` element | `disabled` | | ||
| [removeOffCanvasPaths](https://github.com/svg/svgo/blob/master/plugins/removeOffCanvasPaths.js) | removes elements that are drawn outside of the viewbox | `disabled` | | ||
| [removeStyleElement](https://github.com/svg/svgo/blob/master/plugins/removeStyleElement.js) | remove `<style>` elements | `disabled` | | ||
| [removeScriptElement](https://github.com/svg/svgo/blob/master/plugins/removeScriptElement.js) | remove `<script>` elements | `disabled` | | ||
| [reusePaths](https://github.com/svg/svgo/blob/master/plugins/reusePaths.js) | Find duplicated <path> elements and replace them with <use> links | `disabled` | | ||
## Other Ways to Use SVGO | ||
* as a web app – [SVGOMG](https://jakearchibald.github.io/svgomg/) | ||
* as a GitHub Action – [SVGO Action](https://github.com/marketplace/actions/svgo-action) | ||
* as a Node.js module – [examples](https://github.com/svg/svgo/tree/master/examples) | ||
* as a Grunt task – [grunt-svgmin](https://github.com/sindresorhus/grunt-svgmin) | ||
* as a Gulp task – [gulp-svgmin](https://github.com/ben-eb/gulp-svgmin) | ||
* as a Mimosa module – [mimosa-minify-svg](https://github.com/dbashford/mimosa-minify-svg) | ||
* as an OSX Folder Action – [svgo-osx-folder-action](https://github.com/svg/svgo-osx-folder-action) | ||
* as a webpack loader – [image-webpack-loader](https://github.com/tcoopman/image-webpack-loader) | ||
* as a Telegram Bot – [svgo_bot](https://github.com/maksugr/svgo_bot) | ||
* as a PostCSS plugin – [postcss-svgo](https://github.com/ben-eb/postcss-svgo) | ||
* as an Inkscape plugin – [inkscape-svgo](https://github.com/konsumer/inkscape-svgo) | ||
* as a Sketch plugin - [svgo-compressor](https://github.com/BohemianCoding/svgo-compressor) | ||
* as macOS app - [Image Shrinker](https://image-shrinker.com) | ||
* as a Rollup plugin - [rollup-plugin-svgo](https://github.com/porsager/rollup-plugin-svgo) | ||
* as a VS Code plugin - [vscode-svgo](https://github.com/1000ch/vscode-svgo) | ||
* as a Atom plugin - [atom-svgo](https://github.com/1000ch/atom-svgo) | ||
* as a Sublime plugin - [Sublime-svgo](https://github.com/1000ch/Sublime-svgo) | ||
* as a Figma plugin - [Advanced SVG Export](https://www.figma.com/c/plugin/782713260363070260/Advanced-SVG-Export) | ||
- as a web app – [SVGOMG](https://jakearchibald.github.io/svgomg/) | ||
- as a GitHub Action – [SVGO Action](https://github.com/marketplace/actions/svgo-action) | ||
- as a Grunt task – [grunt-svgmin](https://github.com/sindresorhus/grunt-svgmin) | ||
- as a Gulp task – [gulp-svgmin](https://github.com/ben-eb/gulp-svgmin) | ||
- as a Mimosa module – [mimosa-minify-svg](https://github.com/dbashford/mimosa-minify-svg) | ||
- as an OSX Folder Action – [svgo-osx-folder-action](https://github.com/svg/svgo-osx-folder-action) | ||
- as a webpack loader – [image-webpack-loader](https://github.com/tcoopman/image-webpack-loader) | ||
- as a Telegram Bot – [svgo_bot](https://github.com/maksugr/svgo_bot) | ||
- as a PostCSS plugin – [postcss-svgo](https://github.com/ben-eb/postcss-svgo) | ||
- as an Inkscape plugin – [inkscape-svgo](https://github.com/konsumer/inkscape-svgo) | ||
- as a Sketch plugin - [svgo-compressor](https://github.com/BohemianCoding/svgo-compressor) | ||
- as a macOS app - [Image Shrinker](https://image-shrinker.com) | ||
- as a Rollup plugin - [rollup-plugin-svgo](https://github.com/porsager/rollup-plugin-svgo) | ||
- as a VS Code plugin - [vscode-svgo](https://github.com/1000ch/vscode-svgo) | ||
- as a Atom plugin - [atom-svgo](https://github.com/1000ch/atom-svgo) | ||
- as a Sublime plugin - [Sublime-svgo](https://github.com/1000ch/Sublime-svgo) | ||
- as a Figma plugin - [Advanced SVG Export](https://www.figma.com/c/plugin/782713260363070260/Advanced-SVG-Export) | ||
- as a Linux app - [Oh My SVG](https://github.com/sonnyp/OhMySVG) | ||
- as a Browser extension - [SVG Gobbler](https://github.com/rossmoody/svg-gobbler) | ||
- as an API - [Vector Express](https://github.com/smidyo/vectorexpress-api#convertor-svgo) | ||
@@ -294,4 +281,4 @@ ## Donators | ||
| [<img src="https://sheetjs.com/sketch128.png" width="80">](https://sheetjs.com/) | [<img src="https://raw.githubusercontent.com/fontello/fontello/master/fontello-image.svg" width="80">](https://fontello.com/) | | ||
|:-:|:-:| | ||
| [SheetJS LLC](https://sheetjs.com/) | [Fontello](https://fontello.com/) | | ||
| :------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------: | | ||
| [SheetJS LLC](https://sheetjs.com/) | [Fontello](https://fontello.com/) | | ||
@@ -298,0 +285,0 @@ ## License and Copyright |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
921718
17
77
13780
281
+ Addedcolorette@^1.2.2
+ Addedcolorette@1.4.0(transitive)
- Removedchalk@^4.1.0
- Removedansi-styles@4.3.0(transitive)
- Removedchalk@4.1.2(transitive)
- Removedcolor-convert@2.0.1(transitive)
- Removedcolor-name@1.1.4(transitive)
- Removedhas-flag@4.0.0(transitive)
- Removedsupports-color@7.2.0(transitive)