Comparing version 4.0.0-rc.0 to 4.0.0-rc.1
@@ -56,3 +56,3 @@ import presetDefault from '../plugins/preset-default.js'; | ||
export const builtin = [ | ||
export const builtin = Object.freeze([ | ||
presetDefault, | ||
@@ -74,5 +74,5 @@ addAttributesToSVGElement, | ||
convertTransform, | ||
mergeStyles, | ||
inlineStyles, | ||
mergePaths, | ||
mergeStyles, | ||
minifyStyles, | ||
@@ -113,2 +113,2 @@ moveElemsAttrsToGroup, | ||
sortDefsChildren, | ||
]; | ||
]); |
@@ -6,2 +6,3 @@ import { removeLeadingZero, toFixed } from './svgo/tools.js'; | ||
* @typedef {import('./types.js').PathDataCommand} PathDataCommand | ||
* @typedef {'none' | 'sign' | 'whole' | 'decimal_point' | 'decimal' | 'e' | 'exponent_sign' | 'exponent'} ReadNumberState | ||
*/ | ||
@@ -42,16 +43,12 @@ | ||
/** | ||
* @type {(c: string) => boolean} | ||
* @param {string} c | ||
* @returns {boolean} | ||
*/ | ||
const isWsp = (c) => { | ||
const codePoint = c.codePointAt(0); | ||
return ( | ||
codePoint === 0x20 || | ||
codePoint === 0x9 || | ||
codePoint === 0xd || | ||
codePoint === 0xa | ||
); | ||
const isWhiteSpace = (c) => { | ||
return c === ' ' || c === '\t' || c === '\r' || c === '\n'; | ||
}; | ||
/** | ||
* @type {(c: string) => boolean} | ||
* @param {string} c | ||
* @returns {boolean} | ||
*/ | ||
@@ -67,6 +64,2 @@ const isDigit = (c) => { | ||
/** | ||
* @typedef {'none' | 'sign' | 'whole' | 'decimal_point' | 'decimal' | 'e' | 'exponent_sign' | 'exponent'} ReadNumberState | ||
*/ | ||
/** | ||
* @type {(string: string, cursor: number) => [number, ?number]} | ||
@@ -139,3 +132,4 @@ */ | ||
/** | ||
* @type {(string: string) => PathDataItem[]} | ||
* @param {string} string | ||
* @returns {PathDataItem[]} | ||
*/ | ||
@@ -157,3 +151,3 @@ export const parsePathData = (string) => { | ||
const c = string.charAt(i); | ||
if (isWsp(c)) { | ||
if (isWhiteSpace(c)) { | ||
continue; | ||
@@ -178,7 +172,5 @@ } | ||
} | ||
} else { | ||
} else if (args.length !== 0) { | ||
// stop if previous command arguments are not flushed | ||
if (args.length !== 0) { | ||
return pathData; | ||
} | ||
return pathData; | ||
} | ||
@@ -185,0 +177,0 @@ command = c; |
@@ -87,4 +87,8 @@ import * as csstree from 'css-tree'; | ||
if ( | ||
cssNode.name === 'keyframes' || | ||
cssNode.name === '-webkit-keyframes' | ||
[ | ||
'keyframes', | ||
'-webkit-keyframes', | ||
'-o-keyframes', | ||
'-moz-keyframes', | ||
].includes(cssNode.name) | ||
) { | ||
@@ -91,0 +95,0 @@ return csstreeWalkSkip; |
@@ -9,2 +9,5 @@ import os from 'os'; | ||
builtinPlugins, | ||
querySelector, | ||
querySelectorAll, | ||
_collections, | ||
} from './svgo.js'; | ||
@@ -33,3 +36,9 @@ | ||
export { VERSION, builtinPlugins }; | ||
export { | ||
VERSION, | ||
builtinPlugins, | ||
querySelector, | ||
querySelectorAll, | ||
_collections, | ||
}; | ||
@@ -89,2 +98,5 @@ export const loadConfig = async (configFile, cwd = process.cwd()) => { | ||
optimize, | ||
querySelector, | ||
querySelectorAll, | ||
_collections, | ||
}; |
@@ -1,3 +0,9 @@ | ||
import type { StringifyOptions, DataUri, Plugin } from './types.js'; | ||
import type { | ||
StringifyOptions, | ||
DataUri, | ||
Plugin, | ||
XastChild, | ||
XastNode, | ||
} from './types.js'; | ||
import type { | ||
BuiltinsWithOptionalParams, | ||
@@ -37,2 +43,15 @@ BuiltinsWithRequiredParams, | ||
export type BuiltinPluginOrPreset<Name, Params> = BuiltinPlugin< | ||
Name, | ||
Params | ||
> & { | ||
/** If the plugin is itself a preset that invokes other plugins. */ | ||
isPreset: true | undefined; | ||
/** | ||
* If the plugin is a preset that invokes other plugins, this returns an | ||
* array of the plugins in the preset in the order that they are invoked. | ||
*/ | ||
plugins?: Readonly<BuiltinPlugin<string, Object>[]>; | ||
}; | ||
/** | ||
@@ -44,11 +63,6 @@ * Plugins that are bundled with SVGO. This includes plugin presets, and plugins | ||
{ | ||
[Name in keyof PluginsParams]: BuiltinPlugin<Name, PluginsParams[Name]> & { | ||
/** If the plugin is itself a preset that invokes other plugins. */ | ||
isPreset: true | undefined; | ||
/** | ||
* If the plugin is a preset that invokes other plugins, this returns an | ||
* array of the plugins in the preset in the order that they are invoked. | ||
*/ | ||
plugins?: BuiltinPlugin<unknown, unknown>[]; | ||
}; | ||
[Name in keyof PluginsParams]: BuiltinPluginOrPreset< | ||
Name, | ||
PluginsParams[Name] | ||
>; | ||
}[keyof PluginsParams] | ||
@@ -83,2 +97,72 @@ >; | ||
export declare const _collections: { | ||
elemsGroups: Readonly<Record<string, Set<string>>>; | ||
/** | ||
* Elements where adding or removing whitespace may effect rendering, metadata, | ||
* or semantic meaning. | ||
* | ||
* @see https://developer.mozilla.org/docs/Web/HTML/Element/pre | ||
*/ | ||
textElems: Readonly<Set<string>>; | ||
pathElems: Readonly<Set<string>>; | ||
/** | ||
* @see https://www.w3.org/TR/SVG11/intro.html#Definitions | ||
*/ | ||
attrsGroups: Readonly<Record<string, Set<string>>>; | ||
attrsGroupsDefaults: Readonly<Record<string, Record<string, string>>>; | ||
/** | ||
* @see https://www.w3.org/TR/SVG11/intro.html#Definitions | ||
*/ | ||
attrsGroupsDeprecated: Readonly< | ||
Record<string, { safe?: Set<string>; unsafe?: Set<string> }> | ||
>; | ||
/** | ||
* @see https://www.w3.org/TR/SVG11/eltindex.html | ||
*/ | ||
elems: Readonly< | ||
Record< | ||
string, | ||
{ | ||
attrsGroups: Set<string>; | ||
attrs?: Set<string>; | ||
defaults?: Record<string, string>; | ||
deprecated?: { | ||
safe?: Set<string>; | ||
unsafe?: Set<string>; | ||
}; | ||
contentGroups?: Set<string>; | ||
content?: Set<string>; | ||
} | ||
> | ||
>; | ||
/** | ||
* @see https://wiki.inkscape.org/wiki/index.php/Inkscape-specific_XML_attributes | ||
*/ | ||
editorNamespaces: Readonly<Set<string>>; | ||
/** | ||
* @see https://www.w3.org/TR/SVG11/linking.html#processingIRI | ||
*/ | ||
referencesProps: Readonly<Set<string>>; | ||
/** | ||
* @see https://www.w3.org/TR/SVG11/propidx.html | ||
*/ | ||
inheritableAttrs: Readonly<Set<string>>; | ||
presentationNonInheritableGroupAttrs: Readonly<Set<string>>; | ||
/** | ||
* @see https://www.w3.org/TR/SVG11/single-page.html#types-ColorKeywords | ||
*/ | ||
colorsNames: Readonly<Record<string, string>>; | ||
colorsShortNames: Readonly<Record<string, string>>; | ||
/** | ||
* @see https://www.w3.org/TR/SVG11/single-page.html#types-DataTypeColor | ||
*/ | ||
colorsProps: Readonly<Set<string>>; | ||
/** | ||
* @see https://developer.mozilla.org/docs/Web/CSS/Pseudo-classes | ||
*/ | ||
pseudoClasses: Readonly<Record<string, Set<string>>>; | ||
}; | ||
export type * from './types.d.ts'; | ||
/** Installed version of SVGO. */ | ||
@@ -89,1 +173,21 @@ export declare const VERSION: string; | ||
export declare function optimize(input: string, config?: Config): Output; | ||
/** | ||
* @param node Element to query the children of. | ||
* @param selector CSS selector string. | ||
* @returns First match, or null if there was no match. | ||
*/ | ||
export declare function querySelector( | ||
node: XastNode, | ||
selector: string, | ||
): XastChild | null; | ||
/** | ||
* @param node Element to query the children of. | ||
* @param selector CSS selector string. | ||
* @returns All matching elements. | ||
*/ | ||
export declare function querySelectorAll( | ||
node: XastNode, | ||
selector: string, | ||
): XastChild[]; |
@@ -7,12 +7,33 @@ import { parseSvg } from './parser.js'; | ||
import { VERSION } from './version.js'; | ||
import { querySelector, querySelectorAll } from './xast.js'; | ||
import _collections from '../plugins/_collections.js'; | ||
const pluginsMap = {}; | ||
/** | ||
* @typedef {import('./svgo.js').BuiltinPluginOrPreset<?, ?>} BuiltinPluginOrPreset | ||
*/ | ||
const pluginsMap = new Map(); | ||
for (const plugin of builtin) { | ||
pluginsMap[plugin.name] = plugin; | ||
pluginsMap.set(plugin.name, plugin); | ||
} | ||
/** | ||
* @param {string} name | ||
* @returns {BuiltinPluginOrPreset} | ||
*/ | ||
function getPlugin(name) { | ||
if (name === 'removeScriptElement') { | ||
console.warn( | ||
'Warning: removeScriptElement has been renamed to removeScripts, please update your SVGO config', | ||
); | ||
return pluginsMap.get('removeScripts'); | ||
} | ||
return pluginsMap.get(name); | ||
} | ||
const resolvePluginConfig = (plugin) => { | ||
if (typeof plugin === 'string') { | ||
// resolve builtin plugin specified as string | ||
const builtinPlugin = pluginsMap[plugin]; | ||
const builtinPlugin = getPlugin(plugin); | ||
if (builtinPlugin == null) { | ||
@@ -29,3 +50,3 @@ throw Error(`Unknown builtin plugin "${plugin}" specified.`); | ||
if (plugin.name == null) { | ||
throw Error(`Plugin name should be specified`); | ||
throw Error(`Plugin name must be specified`); | ||
} | ||
@@ -36,3 +57,3 @@ // use custom plugin implementation | ||
// resolve builtin plugin implementation | ||
const builtinPlugin = pluginsMap[plugin.name]; | ||
const builtinPlugin = getPlugin(plugin.name); | ||
if (builtinPlugin == null) { | ||
@@ -52,3 +73,9 @@ throw Error(`Unknown builtin plugin "${plugin.name}" specified.`); | ||
export { VERSION, builtin as builtinPlugins }; | ||
export { | ||
VERSION, | ||
builtin as builtinPlugins, | ||
querySelector, | ||
querySelectorAll, | ||
_collections, | ||
}; | ||
@@ -112,2 +139,5 @@ export const optimize = (input, config) => { | ||
builtinPlugins: builtin, | ||
querySelector, | ||
querySelectorAll, | ||
_collections, | ||
}; |
@@ -532,3 +532,2 @@ import fs from 'fs'; | ||
const list = builtin | ||
.sort((a, b) => a.name.localeCompare(b.name)) | ||
.map((plugin) => ` [ ${colors.green(plugin.name)} ] ${plugin.description}`) | ||
@@ -535,0 +534,0 @@ .join('\n'); |
import { visit } from '../xast.js'; | ||
/** | ||
* @typedef {import('../svgo').BuiltinPlugin<string, Object>} BuiltinPlugin | ||
* @typedef {import('../svgo').BuiltinPluginOrPreset<?, ?>} BuiltinPreset | ||
*/ | ||
/** | ||
* Plugins engine. | ||
@@ -34,2 +39,6 @@ * | ||
/** | ||
* @param {{ name: string, plugins: BuiltinPlugin[] }} arg0 | ||
* @returns {BuiltinPreset} | ||
*/ | ||
export const createPreset = ({ name, plugins }) => { | ||
@@ -39,3 +48,3 @@ return { | ||
isPreset: true, | ||
plugins, | ||
plugins: Object.freeze(plugins), | ||
fn: (ast, params, info) => { | ||
@@ -42,0 +51,0 @@ const { floatPrecision, overrides } = params; |
/** Version of SVGO. */ | ||
export const VERSION = '4.0.0-rc.0'; | ||
export const VERSION = '4.0.0-rc.1'; |
@@ -9,2 +9,4 @@ import { selectAll, selectOne, is } from 'css-select'; | ||
* @typedef {import('./types.js').Visitor} Visitor | ||
* @typedef {import('./svgo.ts').querySelector} querySelector | ||
* @typedef {import('./svgo.ts').querySelectorAll} querySelectorAll | ||
*/ | ||
@@ -18,3 +20,3 @@ | ||
/** | ||
* @type {(node: XastNode, selector: string) => XastChild[]} | ||
* @type {querySelectorAll} | ||
*/ | ||
@@ -26,3 +28,3 @@ export const querySelectorAll = (node, selector) => { | ||
/** | ||
* @type {(node: XastNode, selector: string) => ?XastChild} | ||
* @type {querySelector} | ||
*/ | ||
@@ -29,0 +31,0 @@ export const querySelector = (node, selector) => { |
{ | ||
"packageManager": "yarn@3.8.2", | ||
"name": "svgo", | ||
"version": "4.0.0-rc.0", | ||
"version": "4.0.0-rc.1", | ||
"description": "SVGO is a Node.js library and command-line application for optimizing vector images.", | ||
@@ -101,2 +101,7 @@ "license": "MIT", | ||
"fixtures" | ||
], | ||
"coverageReporters": [ | ||
"html", | ||
"lcov", | ||
"text" | ||
] | ||
@@ -103,0 +108,0 @@ }, |
// https://www.w3.org/TR/SVG11/intro.html#Definitions | ||
/** | ||
* @typedef {import('../lib/svgo.ts')} svgo | ||
*/ | ||
/** | ||
* @type {Record<string, Set<string>>} | ||
* @see svgo#_collections | ||
*/ | ||
@@ -104,9 +109,9 @@ export const elemsGroups = { | ||
/** | ||
* Elements where adding or removing whitespace may effect rendering, metadata, | ||
* or semantic meaning. | ||
* | ||
* @see https://developer.mozilla.org/docs/Web/HTML/Element/pre | ||
* @see svgo#_collections | ||
*/ | ||
export const textElems = new Set([...elemsGroups.textContent, 'pre', 'title']); | ||
/** | ||
* @see svgo#_collections | ||
*/ | ||
export const pathElems = new Set(['glyph', 'missing-glyph', 'path']); | ||
@@ -116,3 +121,3 @@ | ||
* @type {Record<string, Set<string>>} | ||
* @see https://www.w3.org/TR/SVG11/intro.html#Definitions | ||
* @see svgo#_collections | ||
*/ | ||
@@ -316,2 +321,3 @@ export const attrsGroups = { | ||
* @type {Record<string, Record<string, string>>} | ||
* @see svgo#_collections | ||
*/ | ||
@@ -384,3 +390,3 @@ export const attrsGroupsDefaults = { | ||
* @type {Record<string, { safe?: Set<string>, unsafe?: Set<string> }>} | ||
* @see https://www.w3.org/TR/SVG11/intro.html#Definitions | ||
* @see svgo#_collections | ||
*/ | ||
@@ -415,3 +421,3 @@ export const attrsGroupsDeprecated = { | ||
* }>} | ||
* @see https://www.w3.org/TR/SVG11/eltindex.html | ||
* @see svgo#_collections | ||
*/ | ||
@@ -2075,3 +2081,5 @@ export const elems = { | ||
// https://wiki.inkscape.org/wiki/index.php/Inkscape-specific_XML_attributes | ||
/** | ||
* @see svgo#_collections | ||
*/ | ||
export const editorNamespaces = new Set([ | ||
@@ -2103,3 +2111,3 @@ 'http://creativecommons.org/ns#', | ||
/** | ||
* @see https://www.w3.org/TR/SVG11/linking.html#processingIRI | ||
* @see svgo#_collections | ||
*/ | ||
@@ -2120,3 +2128,3 @@ export const referencesProps = new Set([ | ||
/** | ||
* @see https://www.w3.org/TR/SVG11/propidx.html | ||
* @see svgo#_collections | ||
*/ | ||
@@ -2183,5 +2191,4 @@ export const inheritableAttrs = new Set([ | ||
/** | ||
* https://www.w3.org/TR/SVG11/single-page.html#types-ColorKeywords | ||
* | ||
* @type {Record<string, string>} | ||
* @see svgo#_collections | ||
*/ | ||
@@ -2378,3 +2385,3 @@ export const colorsNames = { | ||
/** | ||
* @see https://www.w3.org/TR/SVG11/single-page.html#types-DataTypeColor | ||
* @see svgo#_collections | ||
*/ | ||
@@ -2390,3 +2397,5 @@ export const colorsProps = new Set([ | ||
/** @see https://developer.mozilla.org/docs/Web/CSS/Pseudo-classes */ | ||
/** | ||
* @see svgo#_collections | ||
*/ | ||
export const pseudoClasses = { | ||
@@ -2448,1 +2457,19 @@ displayState: new Set(['fullscreen', 'modal', 'picture-in-picture']), | ||
}; | ||
export default { | ||
elemsGroups, | ||
textElems, | ||
pathElems, | ||
attrsGroups, | ||
attrsGroupsDefaults, | ||
attrsGroupsDeprecated, | ||
elems, | ||
editorNamespaces, | ||
referencesProps, | ||
inheritableAttrs, | ||
presentationNonInheritableGroupAttrs, | ||
colorsNames, | ||
colorsShortNames, | ||
colorsProps, | ||
pseudoClasses, | ||
}; |
@@ -44,3 +44,3 @@ export const name = 'addAttributesToSVGElement'; | ||
/** | ||
* Add attributes to an outer <svg> element. Example config: | ||
* Add attributes to an outer <svg> element. | ||
* | ||
@@ -47,0 +47,0 @@ * @author April Arcus |
@@ -40,3 +40,3 @@ import { removeLeadingZero } from '../lib/svgo/tools.js'; | ||
if (node.attributes.viewBox != null) { | ||
const nums = node.attributes.viewBox.split(/\s,?\s*|,\s*/g); | ||
const nums = node.attributes.viewBox.trim().split(/(?:\s,?|,)\s*/g); | ||
node.attributes.viewBox = nums | ||
@@ -58,3 +58,3 @@ .map((value) => { | ||
const match = value.match(regNumericValues); | ||
const match = regNumericValues.exec(value); | ||
@@ -61,0 +61,0 @@ // if attribute value matches regNumericValues |
@@ -76,5 +76,10 @@ import { colorsNames, colorsProps, colorsShortNames } from './_collections.js'; | ||
let maskCounter = 0; | ||
return { | ||
element: { | ||
enter: (node) => { | ||
if (node.name === 'mask') { | ||
maskCounter++; | ||
} | ||
for (const [name, value] of Object.entries(node.attributes)) { | ||
@@ -85,3 +90,3 @@ if (colorsProps.has(name)) { | ||
// convert colors to currentColor | ||
if (currentColor) { | ||
if (currentColor && maskCounter === 0) { | ||
let matched; | ||
@@ -153,4 +158,9 @@ if (typeof currentColor === 'string') { | ||
}, | ||
exit: (node) => { | ||
if (node.name === 'mask') { | ||
maskCounter--; | ||
} | ||
}, | ||
}, | ||
}; | ||
}; |
@@ -55,3 +55,3 @@ import { attrsGroups } from './_collections.js'; | ||
const usefulChildren = node.children.filter( | ||
(child) => !(child.type === 'text' && /\s*/.test(child.value)), | ||
(child) => child.type !== 'text', | ||
); | ||
@@ -58,0 +58,0 @@ parentNode.children.splice(index, 1, ...usefulChildren); |
@@ -36,6 +36,6 @@ <div align="center"> | ||
Process a directory of files recursively with `-f`/`--folder`: | ||
Process a directory of files recursively with `-r`/`--recursive` and `-f`/`--folder`: | ||
```sh | ||
svgo -f path/to/directory_with_svgs -o path/to/output_directory | ||
svgo -rf path/to/directory_with_svgs -o path/to/output_directory | ||
``` | ||
@@ -170,22 +170,2 @@ | ||
## Other ways to use SVGO | ||
| Method | Reference | | ||
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | ||
| Web app | [SVGOMG](https://jakearchibald.github.io/svgomg/) | | ||
| Grunt task | [grunt-svgmin](https://github.com/sindresorhus/grunt-svgmin) | | ||
| Gulp task | [gulp-svgmin](https://github.com/ben-eb/gulp-svgmin) | | ||
| Webpack loader | [image-minimizer-webpack-plugin](https://github.com/webpack-contrib/image-minimizer-webpack-plugin/#optimize-with-svgo) | | ||
| PostCSS plugin | [postcss-svgo](https://github.com/cssnano/cssnano/tree/master/packages/postcss-svgo) | | ||
| Inkscape plugin | [inkscape-svgo](https://github.com/konsumer/inkscape-svgo) | | ||
| Sketch plugin | [svgo-compressor](https://github.com/BohemianCoding/svgo-compressor) | | ||
| Rollup plugin | [rollup-plugin-svgo](https://github.com/porsager/rollup-plugin-svgo) | | ||
| Visual Studio Code plugin | [vscode-svgo](https://github.com/1000ch/vscode-svgo) | | ||
| Atom plugin | [atom-svgo](https://github.com/1000ch/atom-svgo) | | ||
| Sublime plugin | [Sublime-svgo](https://github.com/1000ch/Sublime-svgo) | | ||
| Figma plugin | [Advanced SVG Export](https://www.figma.com/c/plugin/782713260363070260/Advanced-SVG-Export) | | ||
| Linux app | [Oh My SVG](https://github.com/sonnyp/OhMySVG) | | ||
| Browser extension | [SVG Gobbler](https://github.com/rossmoody/svg-gobbler) | | ||
| API | [Vector Express](https://github.com/smidyo/vectorexpress-api#convertor-svgo) | | ||
## Donors | ||
@@ -192,0 +172,0 @@ |
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
1352245
25323
180