Socket
Socket
Sign inDemoInstall

svgo

Package Overview
Dependencies
16
Maintainers
4
Versions
99
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.1.0 to 3.2.0

6

lib/parser.js

@@ -103,3 +103,3 @@ 'use strict';

/**
* @type {Array<XastParent>}
* @type {XastParent[]}
*/

@@ -217,3 +217,3 @@ const stack = [root];

// prevent trimming of meaningful whitespace inside textual tags
if (textElems.includes(current.name)) {
if (textElems.has(current.name)) {
/**

@@ -254,3 +254,3 @@ * @type {XastText}

data,
from
from,
);

@@ -257,0 +257,0 @@ if (e.message.indexOf('Unexpected end') === -1) {

'use strict';
const { removeLeadingZero } = require('./svgo/tools');
const { removeLeadingZero, toFixed } = require('./svgo/tools');

@@ -138,7 +138,7 @@ /**

/**
* @type {(string: string) => Array<PathDataItem>}
* @type {(string: string) => PathDataItem[]}
*/
const parsePathData = (string) => {
/**
* @type {Array<PathDataItem>}
* @type {PathDataItem[]}
*/

@@ -247,11 +247,16 @@ const pathData = [];

/**
* @type {(number: number, precision?: number) => string}
* @type {(number: number, precision?: number) => {
* roundedStr: string,
* rounded: number
* }}
*/
const stringifyNumber = (number, precision) => {
const roundAndStringify = (number, precision) => {
if (precision != null) {
const ratio = 10 ** precision;
number = Math.round(number * ratio) / ratio;
number = toFixed(number, precision);
}
// remove zero whole from decimal number
return removeLeadingZero(number);
return {
roundedStr: removeLeadingZero(number),
rounded: number,
};
};

@@ -272,6 +277,6 @@

let result = '';
let prev = '';
for (let i = 0; i < args.length; i += 1) {
const number = args[i];
const numberString = stringifyNumber(number, precision);
let previous;
for (let i = 0; i < args.length; i++) {
const { roundedStr, rounded } = roundAndStringify(args[i], precision);
if (

@@ -283,15 +288,21 @@ disableSpaceAfterFlags &&

) {
result += numberString;
} else if (i === 0 || numberString.startsWith('-')) {
result += roundedStr;
} else if (i === 0 || rounded < 0) {
// avoid space before first and negative numbers
result += numberString;
} else if (prev.includes('.') && numberString.startsWith('.')) {
result += roundedStr;
} else if (
!Number.isInteger(previous) &&
rounded != 0 &&
rounded < 1 &&
rounded > -1
) {
// remove space before decimal with zero whole
// only when previous number is also decimal
result += numberString;
result += roundedStr;
} else {
result += ` ${numberString}`;
result += ` ${roundedStr}`;
}
prev = numberString;
previous = rounded;
}
return result;

@@ -302,3 +313,3 @@ };

* @typedef {{
* pathData: Array<PathDataItem>;
* pathData: PathDataItem[];
* precision?: number;

@@ -310,46 +321,66 @@ * disableSpaceAfterFlags?: boolean;

/**
* @type {(options: StringifyPathDataOptions) => string}
* @param {StringifyPathDataOptions} options
* @returns {string}
*/
const stringifyPathData = ({ pathData, precision, disableSpaceAfterFlags }) => {
// combine sequence of the same commands
let combined = [];
for (let i = 0; i < pathData.length; i += 1) {
if (pathData.length === 1) {
const { command, args } = pathData[0];
return (
command + stringifyArgs(command, args, precision, disableSpaceAfterFlags)
);
}
let result = '';
let prev = { ...pathData[0] };
// match leading moveto with following lineto
if (pathData[1].command === 'L') {
prev.command = 'M';
} else if (pathData[1].command === 'l') {
prev.command = 'm';
}
for (let i = 1; i < pathData.length; i++) {
const { command, args } = pathData[i];
if (i === 0) {
combined.push({ command, args });
if (
(prev.command === command &&
prev.command !== 'M' &&
prev.command !== 'm') ||
// combine matching moveto and lineto sequences
(prev.command === 'M' && command === 'L') ||
(prev.command === 'm' && command === 'l')
) {
prev.args = [...prev.args, ...args];
if (i === pathData.length - 1) {
result +=
prev.command +
stringifyArgs(
prev.command,
prev.args,
precision,
disableSpaceAfterFlags,
);
}
} else {
/**
* @type {PathDataItem}
*/
const last = combined[combined.length - 1];
// match leading moveto with following lineto
if (i === 1) {
if (command === 'L') {
last.command = 'M';
}
if (command === 'l') {
last.command = 'm';
}
}
if (
(last.command === command &&
last.command !== 'M' &&
last.command !== 'm') ||
// combine matching moveto and lineto sequences
(last.command === 'M' && command === 'L') ||
(last.command === 'm' && command === 'l')
) {
last.args = [...last.args, ...args];
result +=
prev.command +
stringifyArgs(
prev.command,
prev.args,
precision,
disableSpaceAfterFlags,
);
if (i === pathData.length - 1) {
result +=
command +
stringifyArgs(command, args, precision, disableSpaceAfterFlags);
} else {
combined.push({ command, args });
prev = { command, args };
}
}
}
let result = '';
for (const { command, args } of combined) {
result +=
command + stringifyArgs(command, args, precision, disableSpaceAfterFlags);
}
return result;
};
exports.stringifyPathData = stringifyPathData;

@@ -238,3 +238,3 @@ 'use strict';

openIndent = '';
} else if (textElems.includes(node.name)) {
} else if (textElems.has(node.name)) {
tagOpenEnd = defaults.tagOpenEnd;

@@ -241,0 +241,0 @@ tagCloseStart = defaults.tagCloseStart;

@@ -19,3 +19,2 @@ 'use strict';

const {
// @ts-ignore internal api
syntax: { specificity },

@@ -38,3 +37,3 @@ } = require('csso');

/**
* @type {Array<StylesheetDeclaration>}
* @type {StylesheetDeclaration[]}
*/

@@ -79,6 +78,6 @@ const declarations = [];

/**
* @type {(css: string, dynamic: boolean) => Array<StylesheetRule>}
* @type {(css: string, dynamic: boolean) => StylesheetRule[]}
*/
const parseStylesheet = (css, dynamic) => {
/** @type {Array<StylesheetRule>} */
/** @type {StylesheetRule[]} */
const rules = [];

@@ -114,6 +113,6 @@ const ast = csstree.parse(css, {

/**
* @type {(css: string) => Array<StylesheetDeclaration>}
* @type {(css: string) => StylesheetDeclaration[]}
*/
const parseStyleDeclarations = (css) => {
/** @type {Array<StylesheetDeclaration>} */
/** @type {StylesheetDeclaration[]} */
const declarations = [];

@@ -137,3 +136,5 @@ const ast = csstree.parse(css, {

/**
* @type {(stylesheet: Stylesheet, node: XastElement) => ComputedStyles}
* @param {Stylesheet} stylesheet
* @param {XastElement} node
* @returns {ComputedStyles}
*/

@@ -147,3 +148,3 @@ const computeOwnStyle = (stylesheet, node) => {

for (const [name, value] of Object.entries(node.attributes)) {
if (attrsGroups.presentation.includes(name)) {
if (attrsGroups.presentation.has(name)) {
computedStyle[name] = { type: 'static', inherited: false, value };

@@ -226,25 +227,27 @@ importantStyles.set(name, false);

const collectStylesheet = (root) => {
/** @type {Array<StylesheetRule>} */
/** @type {StylesheetRule[]} */
const rules = [];
/** @type {Map<XastElement, XastParent>} */
const parents = new Map();
visit(root, {
element: {
enter: (node, parentNode) => {
// store parents
parents.set(node, parentNode);
// find and parse all styles
if (node.name === 'style') {
if (node.name !== 'style') {
return;
}
if (
node.attributes.type == null ||
node.attributes.type === '' ||
node.attributes.type === 'text/css'
) {
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') {
rules.push(...parseStylesheet(child.value, dynamic));
}
for (const child of node.children) {
if (child.type === 'text' || child.type === 'cdata') {
rules.push(...parseStylesheet(child.value, dynamic));
}

@@ -263,7 +266,8 @@ }

/**
* @type {(stylesheet: Stylesheet, node: XastElement) => ComputedStyles}
* @param {Stylesheet} stylesheet
* @param {XastElement} node
* @returns {ComputedStyles}
*/
const computeStyle = (stylesheet, node) => {
const { parents } = stylesheet;
// collect inherited styles
const computedStyles = computeOwnStyle(stylesheet, node);

@@ -276,5 +280,4 @@ let parent = parents.get(node);

computedStyles[name] == null &&
// ignore not inheritable styles
inheritableAttrs.includes(name) === true &&
presentationNonInheritableGroupAttrs.includes(name) === false
inheritableAttrs.has(name) &&
!presentationNonInheritableGroupAttrs.has(name)
) {

@@ -307,3 +310,3 @@ computedStyles[name] = { ...computed, inherited: true };

value = null,
traversed = false
traversed = false,
) => {

@@ -310,0 +313,0 @@ const selectors =

@@ -64,7 +64,7 @@ import type { StringifyOptions, DataUri, Plugin as PluginFn } from './types';

configFile: string,
cwd?: string
cwd?: string,
): Promise<Config>;
export declare function loadConfig(
configFile?: null,
cwd?: string
cwd?: string,
): Promise<Config | null>;

@@ -70,3 +70,3 @@ 'use strict';

throw Error(
'malformed config, `plugins` property must be an array.\nSee more info here: https://github.com/svg/svgo#configuration'
'malformed config, `plugins` property must be an array.\nSee more info here: https://github.com/svg/svgo#configuration',
);

@@ -80,3 +80,3 @@ }

console.warn(
'Warning: plugins list includes null or undefined elements, these will be ignored.'
'Warning: plugins list includes null or undefined elements, these will be ignored.',
);

@@ -83,0 +83,0 @@ }

@@ -38,11 +38,11 @@ 'use strict';

'-f, --folder <FOLDER>',
'Input folder, optimize and rewrite all *.svg files'
'Input folder, optimize and rewrite all *.svg files',
)
.option(
'-o, --output <OUTPUT...>',
'Output file or folder (by default the same as the input), "-" for STDOUT'
'Output file or folder (by default the same as the input), "-" for STDOUT',
)
.option(
'-p, --precision <INTEGER>',
'Set number of digits in the fractional part, overrides plugins params'
'Set number of digits in the fractional part, overrides plugins params',
)

@@ -52,7 +52,7 @@ .option('--config <CONFIG>', 'Custom config file, only .js is supported')

'--datauri <FORMAT>',
'Output as Data URI string (base64), URI encoded (enc) or unencoded (unenc)'
'Output as Data URI string (base64), URI encoded (enc) or unencoded (unenc)',
)
.option(
'--multipass',
'Pass over SVGs multiple times to ensure all optimizations are applied'
'Pass over SVGs multiple times to ensure all optimizations are applied',
)

@@ -63,3 +63,3 @@ .option('--pretty', 'Make SVG pretty printed')

'--eol <EOL>',
'Line break to use when outputting SVG: lf, crlf. If unspecified, uses platform default.'
'Line break to use when outputting SVG: lf, crlf. If unspecified, uses platform default.',
)

@@ -69,11 +69,11 @@ .option('--final-newline', 'Ensure SVG ends with a line break')

'-r, --recursive',
"Use with '--folder'. Optimizes *.svg files in folders recursively."
"Use with '--folder'. Optimizes *.svg files in folders recursively.",
)
.option(
'--exclude <PATTERN...>',
"Use with '--folder'. Exclude files matching regular expression pattern."
"Use with '--folder'. Exclude files matching regular expression pattern.",
)
.option(
'-q, --quiet',
'Only output error messages, not regular status messages'
'Only output error messages, not regular status messages',
)

@@ -95,3 +95,3 @@ .option('--show-plugins', 'Show available plugins and exit')

console.error(
"error: option '-p, --precision' argument must be an integer number"
"error: option '-p, --precision' argument must be an integer number",
);

@@ -111,3 +111,3 @@ process.exit(1);

console.error(
"error: option '--datauri' must have one of the following values: 'base64', 'enc' or 'unenc'"
"error: option '--datauri' must have one of the following values: 'base64', 'enc' or 'unenc'",
);

@@ -122,3 +122,3 @@ process.exit(1);

console.error(
"error: option '--indent' argument must be an integer number"
"error: option '--indent' argument must be an integer number",
);

@@ -133,3 +133,3 @@ process.exit(1);

console.error(
"error: option '--eol' must have one of the following values: 'lf' or 'crlf'"
"error: option '--eol' must have one of the following values: 'lf' or 'crlf'",
);

@@ -166,3 +166,3 @@ process.exit(1);

throw Error(
`${PKG.name} requires Node.js version ${nodeVersion} or higher.`
`${PKG.name} requires Node.js version ${nodeVersion} or higher.`,
);

@@ -266,6 +266,3 @@ }

.once('end', () =>
processSVGData(config, { input: 'string' }, data, file).then(
resolve,
reject
)
processSVGData(config, null, data, file).then(resolve, reject),
);

@@ -276,3 +273,3 @@ });

await Promise.all(
input.map((file, n) => optimizeFile(config, file, output[n]))
input.map((file, n) => optimizeFile(config, file, output[n])),
);

@@ -285,3 +282,3 @@ }

return processSVGData(config, { input: 'string' }, data, output[0]);
return processSVGData(config, null, data, output[0]);
}

@@ -326,8 +323,8 @@ }

fileDescription.inputPath,
fileDescription.outputPath
)
)
fileDescription.outputPath,
),
),
)
: Promise.reject(
new Error(`No SVG files have been found in '${dir}' directory.`)
new Error(`No SVG files have been found in '${dir}' directory.`),
);

@@ -350,3 +347,3 @@ }

regSVGFile.test(name) &&
!config.exclude.some((regExclude) => regExclude.test(name))
!config.exclude.some((regExclude) => regExclude.test(name)),
)

@@ -371,6 +368,6 @@ .map((name) => ({

subFolderFiles,
subFolderOutput
subFolderOutput,
);
})
.reduce((a, b) => [].concat(a, b), [])
.reduce((a, b) => [].concat(a, b), []),
)

@@ -390,5 +387,4 @@ : filesInThisFolder;

return fs.promises.readFile(file, 'utf8').then(
(data) =>
processSVGData(config, { input: 'file', path: file }, data, output, file),
(error) => checkOptimizeFileError(config, file, output, error)
(data) => processSVGData(config, { path: file }, data, output, file),
(error) => checkOptimizeFileError(config, file, output, error),
);

@@ -442,5 +438,5 @@ }

? `Error: output '${output}' is not a directory.`
: error
)
)
: error,
),
),
);

@@ -495,3 +491,3 @@ }

'=',
Math.round((outBytes / 1024) * 1000) / 1000 + ' KiB'
Math.round((outBytes / 1024) * 1000) / 1000 + ' KiB',
);

@@ -514,3 +510,3 @@ }

return Promise.reject(
new Error(`Error: no such file or directory '${error.path}'.`)
new Error(`Error: no such file or directory '${error.path}'.`),
);

@@ -535,3 +531,3 @@ }

data,
'utf8'
'utf8',
);

@@ -538,0 +534,0 @@ } else {

@@ -52,3 +52,3 @@ 'use strict';

` '${pluginName}'\n` +
`]\n`
`]\n`,
);

@@ -55,0 +55,0 @@ }

@@ -77,3 +77,3 @@ 'use strict';

*
* @type {(data: Array<number>, params: CleanupOutDataParams, command?: PathDataCommand) => string}
* @type {(data: number[], params: CleanupOutDataParams, command?: PathDataCommand) => string}
*/

@@ -128,19 +128,20 @@ exports.cleanupOutData = (data, params, command) => {

*
* @param {number} value
* @returns {string}
* @example
* 0.5 → .5
*
* @example
* -0.5 → -.5
*
* @type {(num: number) => string}
*/
const removeLeadingZero = (num) => {
var strNum = num.toString();
const removeLeadingZero = (value) => {
const strValue = value.toString();
if (0 < num && num < 1 && strNum.charAt(0) === '0') {
strNum = strNum.slice(1);
} else if (-1 < num && num < 0 && strNum.charAt(1) === '0') {
strNum = strNum.charAt(0) + strNum.slice(2);
if (0 < value && value < 1 && strValue.startsWith('0')) {
return strValue.slice(1);
}
return strNum;
if (-1 < value && value < 0 && strValue[1] === '0') {
return strValue[0] + strValue.slice(2);
}
return strValue;
};

@@ -166,3 +167,3 @@ exports.removeLeadingZero = removeLeadingZero;

attrValue != null &&
attrValue.trimStart().startsWith('javascript:')
attrValue.trimStart().startsWith('javascript:'),
);

@@ -210,3 +211,3 @@

if (referencesProps.includes(attribute)) {
if (referencesProps.has(attribute)) {
const matches = value.matchAll(regReferencesUrl);

@@ -235,1 +236,15 @@ for (const match of matches) {

exports.findReferences = findReferences;
/**
* Does the same as {@link Number.toFixed} but without casting
* the return value to a string.
*
* @param {number} num
* @param {number} precision
* @returns {number}
*/
const toFixed = (num, precision) => {
const pow = 10 ** precision;
return Math.round(num * pow) / pow;
};
exports.toFixed = toFixed;

@@ -34,3 +34,3 @@ export type XastDoctype = {

attributes: Record<string, string>;
children: Array<XastChild>;
children: XastChild[];
};

@@ -48,3 +48,3 @@

type: 'root';
children: Array<XastChild>;
children: XastChild[];
};

@@ -113,6 +113,6 @@

params: Params,
info: PluginInfo
info: PluginInfo,
) => null | Visitor;
export type Specificity = [number, number, number, number];
export type Specificity = [number, number, number];

@@ -129,7 +129,7 @@ export type StylesheetDeclaration = {

specificity: Specificity;
declarations: Array<StylesheetDeclaration>;
declarations: StylesheetDeclaration[];
};
export type Stylesheet = {
rules: Array<StylesheetRule>;
rules: StylesheetRule[];
parents: Map<XastElement, XastParent>;

@@ -175,5 +175,5 @@ };

command: PathDataCommand;
args: Array<number>;
args: number[];
};
export type DataUri = 'base64' | 'enc' | 'unenc';

@@ -19,3 +19,3 @@ 'use strict';

/**
* @type {(node: XastNode, selector: string) => Array<XastChild>}
* @type {(node: XastNode, selector: string) => XastChild[]}
*/

@@ -22,0 +22,0 @@ const querySelectorAll = (node, selector) => {

{
"packageManager": "yarn@2.4.3",
"name": "svgo",
"version": "3.1.0",
"version": "3.2.0",
"description": "Nodejs-based tool for optimizing SVG vector graphics files",

@@ -67,4 +67,4 @@ "license": "MIT",

"test": "NODE_OPTIONS=--experimental-vm-modules jest --maxWorkers=4 --coverage",
"lint": "eslint --ignore-path .gitignore . && prettier --check \"**/*.js\" --ignore-path .gitignore",
"fix": "eslint --ignore-path .gitignore --fix . && prettier --write \"**/*.js\" --ignore-path .gitignore",
"lint": "eslint --ignore-path .gitignore . && prettier --check . --ignore-path .gitignore",
"fix": "eslint --ignore-path .gitignore --fix . && prettier --write . --ignore-path .gitignore",
"typecheck": "tsc",

@@ -76,35 +76,2 @@ "test-browser": "rollup -c && node ./test/browser.js",

},
"prettier": {
"singleQuote": true
},
"eslintConfig": {
"parserOptions": {
"ecmaVersion": 2021
},
"env": {
"node": true,
"es2021": true
},
"extends": [
"eslint:recommended"
],
"overrides": [
{
"files": [
"rollup.config.js"
],
"parserOptions": {
"sourceType": "module"
}
},
{
"files": [
"**/*.test.js"
],
"env": {
"jest": true
}
}
]
},
"jest": {

@@ -119,5 +86,5 @@ "coveragePathIgnorePatterns": [

"css-select": "^5.1.0",
"css-tree": "^2.2.1",
"css-tree": "^2.3.1",
"css-what": "^6.1.0",
"csso": "5.0.5",
"csso": "^5.0.5",
"picocolors": "^1.0.0"

@@ -128,18 +95,18 @@ },

"@rollup/plugin-node-resolve": "^14.1.0",
"@types/css-tree": "^2.0.0",
"@types/csso": "~5.0.3",
"@types/css-tree": "^2.3.4",
"@types/csso": "^5.0.4",
"@types/jest": "^29.5.5",
"del": "^6.0.0",
"eslint": "^8.24.0",
"eslint": "^8.55.0",
"jest": "^29.5.5",
"node-fetch": "^2.7.0",
"pixelmatch": "^5.2.1",
"playwright": "^1.14.1",
"pngjs": "^6.0.0",
"prettier": "^2.7.1",
"pixelmatch": "^5.3.0",
"playwright": "^1.40.1",
"pngjs": "^7.0.0",
"prettier": "^3.1.1",
"rollup": "^2.79.1",
"rollup-plugin-terser": "^7.0.2",
"tar-stream": "^3.1.6",
"typescript": "^4.8.4"
"typescript": "^5.3.3"
}
}

@@ -6,6 +6,6 @@ 'use strict';

/**
* @type {Record<string, Array<string>>}
* @type {Record<string, Set<string>>}
*/
exports.elemsGroups = {
animation: [
animation: new Set([
'animate',

@@ -16,28 +16,37 @@ 'animateColor',

'set',
],
descriptive: ['desc', 'metadata', 'title'],
shape: ['circle', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'rect'],
structural: ['defs', 'g', 'svg', 'symbol', 'use'],
paintServer: [
'solidColor',
]),
descriptive: new Set(['desc', 'metadata', 'title']),
shape: new Set([
'circle',
'ellipse',
'line',
'path',
'polygon',
'polyline',
'rect',
]),
structural: new Set(['defs', 'g', 'svg', 'symbol', 'use']),
paintServer: new Set([
'hatch',
'linearGradient',
'radialGradient',
'meshGradient',
'pattern',
'hatch',
],
nonRendering: [
'linearGradient',
'radialGradient',
'pattern',
'solidColor',
]),
nonRendering: new Set([
'clipPath',
'filter',
'linearGradient',
'marker',
'mask',
'marker',
'pattern',
'radialGradient',
'solidColor',
'symbol',
'filter',
'solidColor',
],
container: [
]),
container: new Set([
'a',
'defs',
'foreignObject',
'g',

@@ -51,5 +60,4 @@ 'marker',

'symbol',
'foreignObject',
],
textContent: [
]),
textContent: new Set([
'altGlyph',

@@ -60,16 +68,16 @@ 'altGlyphDef',

'glyphRef',
'text',
'textPath',
'text',
'tref',
'tspan',
],
textContentChild: ['altGlyph', 'textPath', 'tref', 'tspan'],
lightSource: [
]),
textContentChild: new Set(['altGlyph', 'textPath', 'tref', 'tspan']),
lightSource: new Set([
'feDiffuseLighting',
'feSpecularLighting',
'feDistantLight',
'fePointLight',
'feSpecularLighting',
'feSpotLight',
],
filterPrimitive: [
]),
filterPrimitive: new Set([
'feBlend',

@@ -97,3 +105,3 @@ 'feColorMatrix',

'feTurbulence',
],
]),
};

@@ -107,63 +115,67 @@

*/
exports.textElems = [...exports.elemsGroups.textContent, 'title', 'pre'];
exports.textElems = new Set([
...exports.elemsGroups.textContent,
'pre',
'title',
]);
exports.pathElems = ['path', 'glyph', 'missing-glyph'];
exports.pathElems = new Set(['glyph', 'missing-glyph', 'path']);
/**
* @type {Record<string, Array<string>>}
* @type {Record<string, Set<string>>}
* @see https://www.w3.org/TR/SVG11/intro.html#Definitions
*/
exports.attrsGroups = {
animationAddition: ['additive', 'accumulate'],
animationAttributeTarget: ['attributeType', 'attributeName'],
animationEvent: ['onbegin', 'onend', 'onrepeat', 'onload'],
animationTiming: [
animationAddition: new Set(['additive', 'accumulate']),
animationAttributeTarget: new Set(['attributeType', 'attributeName']),
animationEvent: new Set(['onbegin', 'onend', 'onrepeat', 'onload']),
animationTiming: new Set([
'begin',
'dur',
'end',
'fill',
'max',
'min',
'max',
'restart',
'repeatCount',
'repeatDur',
'fill',
],
animationValue: [
'restart',
]),
animationValue: new Set([
'by',
'calcMode',
'values',
'from',
'keySplines',
'keyTimes',
'keySplines',
'from',
'to',
'by',
],
conditionalProcessing: [
'values',
]),
conditionalProcessing: new Set([
'requiredExtensions',
'requiredFeatures',
'requiredExtensions',
'systemLanguage',
],
core: ['id', 'tabindex', 'xml:base', 'xml:lang', 'xml:space'],
graphicalEvent: [
]),
core: new Set(['id', 'tabindex', 'xml:base', 'xml:lang', 'xml:space']),
graphicalEvent: new Set([
'onactivate',
'onclick',
'onfocusin',
'onfocusout',
'onactivate',
'onclick',
'onload',
'onmousedown',
'onmouseup',
'onmouseover',
'onmousemove',
'onmouseout',
'onload',
],
presentation: [
'onmouseover',
'onmouseup',
]),
presentation: new Set([
'alignment-baseline',
'baseline-shift',
'clip',
'clip-path',
'clip-rule',
'color',
'clip',
'color-interpolation-filters',
'color-interpolation',
'color-interpolation-filters',
'color-profile',
'color-rendering',
'color',
'cursor',

@@ -174,5 +186,5 @@ 'direction',

'enable-background',
'fill',
'fill-opacity',
'fill-rule',
'fill',
'filter',

@@ -182,4 +194,4 @@ 'flood-color',

'font-family',
'font-size-adjust',
'font-size',
'font-size-adjust',
'font-stretch',

@@ -205,3 +217,2 @@ 'font-style',

'stop-opacity',
'stroke',
'stroke-dasharray',

@@ -214,2 +225,3 @@ 'stroke-dashoffset',

'stroke-width',
'stroke',
'text-anchor',

@@ -219,4 +231,4 @@ 'text-decoration',

'text-rendering',
'transform-origin',
'transform',
'transform-origin',
'unicode-bidi',

@@ -227,13 +239,13 @@ 'vector-effect',

'writing-mode',
],
xlink: [
]),
xlink: new Set([
'xlink:actuate',
'xlink:arcrole',
'xlink:href',
'xlink:role',
'xlink:show',
'xlink:actuate',
'xlink:title',
'xlink:type',
'xlink:role',
'xlink:arcrole',
'xlink:title',
],
documentEvent: [
]),
documentEvent: new Set([
'onabort',

@@ -245,5 +257,5 @@ 'onerror',

'onzoom',
],
documentElementEvent: ['oncopy', 'oncut', 'onpaste'],
globalEvent: [
]),
documentElementEvent: new Set(['oncopy', 'oncut', 'onpaste']),
globalEvent: new Set([
'oncancel',

@@ -305,13 +317,13 @@ 'oncanplay',

'onwaiting',
],
filterPrimitive: ['x', 'y', 'width', 'height', 'result'],
transferFunction: [
'type',
'tableValues',
'slope',
'intercept',
]),
filterPrimitive: new Set(['x', 'y', 'width', 'height', 'result']),
transferFunction: new Set([
'amplitude',
'exponent',
'intercept',
'offset',
],
'slope',
'tableValues',
'type',
]),
};

@@ -388,7 +400,7 @@

* @type {Record<string, {
* attrsGroups: Array<string>,
* attrs?: Array<string>,
* attrsGroups: Set<string>,
* attrs?: Set<string>,
* defaults?: Record<string, string>,
* contentGroups?: Array<string>,
* content?: Array<string>,
* contentGroups?: Set<string>,
* content?: Set<string>,
* }>}

@@ -399,3 +411,3 @@ * @see https://www.w3.org/TR/SVG11/eltindex.html

a: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -406,21 +418,21 @@ 'core',

'xlink',
],
attrs: [
]),
attrs: new Set([
'class',
'externalResourcesRequired',
'style',
'externalResourcesRequired',
'target',
'transform',
'target',
],
]),
defaults: {
target: '_self',
},
contentGroups: [
contentGroups: new Set([
'animation',
'descriptive',
'paintServer',
'shape',
'structural',
'paintServer',
],
content: [
]),
content: new Set([
'a',

@@ -432,4 +444,4 @@ 'altGlyphDef',

'filter',
'font-face',
'font',
'font-face',
'foreignObject',

@@ -447,6 +459,6 @@ 'image',

'tspan',
],
]),
},
altGlyph: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -457,28 +469,26 @@ 'core',

'xlink',
],
attrs: [
]),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'x',
'y',
'dx',
'dy',
'externalResourcesRequired',
'format',
'glyphRef',
'format',
'rotate',
],
'style',
'x',
'y',
]),
},
altGlyphDef: {
attrsGroups: ['core'],
content: ['glyphRef'],
attrsGroups: new Set(['core']),
content: new Set(['glyphRef']),
},
altGlyphItem: {
attrsGroups: ['core'],
content: ['glyphRef', 'altGlyphItem'],
attrsGroups: new Set(['core']),
content: new Set(['glyphRef', 'altGlyphItem']),
},
animate: {
attrsGroups: [
'conditionalProcessing',
'core',
attrsGroups: new Set([
'animationAddition',

@@ -489,62 +499,64 @@ 'animationAttributeTarget',

'animationValue',
'conditionalProcessing',
'core',
'presentation',
'xlink',
],
attrs: ['externalResourcesRequired'],
contentGroups: ['descriptive'],
]),
attrs: new Set(['externalResourcesRequired']),
contentGroups: new Set(['descriptive']),
},
animateColor: {
attrsGroups: [
'conditionalProcessing',
'core',
attrsGroups: new Set([
'animationAddition',
'animationAttributeTarget',
'animationEvent',
'xlink',
'animationAttributeTarget',
'animationTiming',
'animationValue',
'animationAddition',
'conditionalProcessing',
'core',
'presentation',
],
attrs: ['externalResourcesRequired'],
contentGroups: ['descriptive'],
'xlink',
]),
attrs: new Set(['externalResourcesRequired']),
contentGroups: new Set(['descriptive']),
},
animateMotion: {
attrsGroups: [
attrsGroups: new Set([
'animationAddition',
'animationEvent',
'animationTiming',
'animationValue',
'conditionalProcessing',
'core',
'animationEvent',
'xlink',
'animationTiming',
'animationValue',
'animationAddition',
],
attrs: [
]),
attrs: new Set([
'externalResourcesRequired',
'keyPoints',
'origin',
'path',
'keyPoints',
'rotate',
'origin',
],
]),
defaults: {
rotate: '0',
},
contentGroups: ['descriptive'],
content: ['mpath'],
contentGroups: new Set(['descriptive']),
content: new Set(['mpath']),
},
animateTransform: {
attrsGroups: [
attrsGroups: new Set([
'animationAddition',
'animationAttributeTarget',
'animationEvent',
'animationTiming',
'animationValue',
'conditionalProcessing',
'core',
'animationEvent',
'xlink',
'animationAttributeTarget',
'animationTiming',
'animationValue',
'animationAddition',
],
attrs: ['externalResourcesRequired', 'type'],
contentGroups: ['descriptive'],
]),
attrs: new Set(['externalResourcesRequired', 'type']),
contentGroups: new Set(['descriptive']),
},
circle: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -554,12 +566,12 @@ 'core',

'presentation',
],
attrs: [
]),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'transform',
'cx',
'cy',
'externalResourcesRequired',
'r',
],
'style',
'transform',
]),
defaults: {

@@ -569,22 +581,22 @@ cx: '0',

},
contentGroups: ['animation', 'descriptive'],
contentGroups: new Set(['animation', 'descriptive']),
},
clipPath: {
attrsGroups: ['conditionalProcessing', 'core', 'presentation'],
attrs: [
attrsGroups: new Set(['conditionalProcessing', 'core', 'presentation']),
attrs: new Set([
'class',
'clipPathUnits',
'externalResourcesRequired',
'style',
'externalResourcesRequired',
'transform',
'clipPathUnits',
],
]),
defaults: {
clipPathUnits: 'userSpaceOnUse',
},
contentGroups: ['animation', 'descriptive', 'shape'],
content: ['text', 'use'],
contentGroups: new Set(['animation', 'descriptive', 'shape']),
content: new Set(['text', 'use']),
},
'color-profile': {
attrsGroups: ['core', 'xlink'],
attrs: ['local', 'name', 'rendering-intent'],
attrsGroups: new Set(['core', 'xlink']),
attrs: new Set(['local', 'name', 'rendering-intent']),
defaults: {

@@ -594,7 +606,7 @@ name: 'sRGB',

},
contentGroups: ['descriptive'],
contentGroups: new Set(['descriptive']),
},
cursor: {
attrsGroups: ['core', 'conditionalProcessing', 'xlink'],
attrs: ['externalResourcesRequired', 'x', 'y'],
attrsGroups: new Set(['core', 'conditionalProcessing', 'xlink']),
attrs: new Set(['externalResourcesRequired', 'x', 'y']),
defaults: {

@@ -604,6 +616,6 @@ x: '0',

},
contentGroups: ['descriptive'],
contentGroups: new Set(['descriptive']),
},
defs: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -613,12 +625,17 @@ 'core',

'presentation',
],
attrs: ['class', 'style', 'externalResourcesRequired', 'transform'],
contentGroups: [
]),
attrs: new Set([
'class',
'externalResourcesRequired',
'style',
'transform',
]),
contentGroups: new Set([
'animation',
'descriptive',
'paintServer',
'shape',
'structural',
'paintServer',
],
content: [
]),
content: new Set([
'a',

@@ -630,4 +647,4 @@ 'altGlyphDef',

'filter',
'font-face',
'font',
'font-face',
'foreignObject',

@@ -643,10 +660,10 @@ 'image',

'view',
],
]),
},
desc: {
attrsGroups: ['core'],
attrs: ['class', 'style'],
attrsGroups: new Set(['core']),
attrs: new Set(['class', 'style']),
},
ellipse: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -656,13 +673,13 @@ 'core',

'presentation',
],
attrs: [
]),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'transform',
'cx',
'cy',
'externalResourcesRequired',
'rx',
'ry',
],
'style',
'transform',
]),
defaults: {

@@ -672,7 +689,7 @@ cx: '0',

},
contentGroups: ['animation', 'descriptive'],
contentGroups: new Set(['animation', 'descriptive']),
},
feBlend: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: [
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set([
'class',

@@ -685,24 +702,34 @@ 'style',

'mode',
],
]),
defaults: {
mode: 'normal',
},
content: ['animate', 'set'],
content: new Set(['animate', 'set']),
},
feColorMatrix: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: ['class', 'style', 'in', 'type', 'values'],
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set(['class', 'style', 'in', 'type', 'values']),
defaults: {
type: 'matrix',
},
content: ['animate', 'set'],
content: new Set(['animate', 'set']),
},
feComponentTransfer: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: ['class', 'style', 'in'],
content: ['feFuncA', 'feFuncB', 'feFuncG', 'feFuncR'],
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set(['class', 'style', 'in']),
content: new Set(['feFuncA', 'feFuncB', 'feFuncG', 'feFuncR']),
},
feComposite: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: ['class', 'style', 'in', 'in2', 'operator', 'k1', 'k2', 'k3', 'k4'],
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set([
'class',
'in',
'in2',
'k1',
'k2',
'k3',
'k4',
'operator',
'style',
]),
defaults: {

@@ -715,21 +742,21 @@ operator: 'over',

},
content: ['animate', 'set'],
content: new Set(['animate', 'set']),
},
feConvolveMatrix: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: [
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set([
'class',
'style',
'in',
'kernelMatrix',
'order',
'kernelMatrix',
'style',
// 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'
'bias',
'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 ))'
'edgeMode',
'targetX',
'targetY',
'edgeMode',
// TODO: kernelUnitLength - 'The first number is the <dx> value. The second number

@@ -739,3 +766,3 @@ // is the <dy> value. If the <dy> value is not specified, it defaults to the same value as <dx>'

'preserveAlpha',
],
]),
defaults: {

@@ -747,14 +774,14 @@ order: '3',

},
content: ['animate', 'set'],
content: new Set(['animate', 'set']),
},
feDiffuseLighting: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: [
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set([
'class',
'diffuseConstant',
'in',
'kernelUnitLength',
'style',
'in',
'surfaceScale',
'diffuseConstant',
'kernelUnitLength',
],
]),
defaults: {

@@ -764,4 +791,4 @@ surfaceScale: '1',

},
contentGroups: ['descriptive'],
content: [
contentGroups: new Set(['descriptive']),
content: new Set([
// TODO: 'exactly one light source element, in any order'

@@ -771,15 +798,15 @@ 'feDistantLight',

'feSpotLight',
],
]),
},
feDisplacementMap: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: [
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set([
'class',
'style',
'in',
'in2',
'scale',
'style',
'xChannelSelector',
'yChannelSelector',
],
]),
defaults: {

@@ -790,7 +817,7 @@ scale: '0',

},
content: ['animate', 'set'],
content: new Set(['animate', 'set']),
},
feDistantLight: {
attrsGroups: ['core'],
attrs: ['azimuth', 'elevation'],
attrsGroups: new Set(['core']),
attrs: new Set(['azimuth', 'elevation']),
defaults: {

@@ -800,61 +827,61 @@ azimuth: '0',

},
content: ['animate', 'set'],
content: new Set(['animate', 'set']),
},
feFlood: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: ['class', 'style'],
content: ['animate', 'animateColor', 'set'],
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set(['class', 'style']),
content: new Set(['animate', 'animateColor', 'set']),
},
feFuncA: {
attrsGroups: ['core', 'transferFunction'],
content: ['set', 'animate'],
attrsGroups: new Set(['core', 'transferFunction']),
content: new Set(['set', 'animate']),
},
feFuncB: {
attrsGroups: ['core', 'transferFunction'],
content: ['set', 'animate'],
attrsGroups: new Set(['core', 'transferFunction']),
content: new Set(['set', 'animate']),
},
feFuncG: {
attrsGroups: ['core', 'transferFunction'],
content: ['set', 'animate'],
attrsGroups: new Set(['core', 'transferFunction']),
content: new Set(['set', 'animate']),
},
feFuncR: {
attrsGroups: ['core', 'transferFunction'],
content: ['set', 'animate'],
attrsGroups: new Set(['core', 'transferFunction']),
content: new Set(['set', 'animate']),
},
feGaussianBlur: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: ['class', 'style', 'in', 'stdDeviation'],
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set(['class', 'style', 'in', 'stdDeviation']),
defaults: {
stdDeviation: '0',
},
content: ['set', 'animate'],
content: new Set(['set', 'animate']),
},
feImage: {
attrsGroups: ['core', 'presentation', 'filterPrimitive', 'xlink'],
attrs: [
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive', 'xlink']),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'href',
'preserveAspectRatio',
'href',
'style',
'xlink:href',
],
]),
defaults: {
preserveAspectRatio: 'xMidYMid meet',
},
content: ['animate', 'animateTransform', 'set'],
content: new Set(['animate', 'animateTransform', 'set']),
},
feMerge: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: ['class', 'style'],
content: ['feMergeNode'],
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set(['class', 'style']),
content: new Set(['feMergeNode']),
},
feMergeNode: {
attrsGroups: ['core'],
attrs: ['in'],
content: ['animate', 'set'],
attrsGroups: new Set(['core']),
attrs: new Set(['in']),
content: new Set(['animate', 'set']),
},
feMorphology: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: ['class', 'style', 'in', 'operator', 'radius'],
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set(['class', 'style', 'in', 'operator', 'radius']),
defaults: {

@@ -864,7 +891,7 @@ operator: 'erode',

},
content: ['animate', 'set'],
content: new Set(['animate', 'set']),
},
feOffset: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: ['class', 'style', 'in', 'dx', 'dy'],
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set(['class', 'style', 'in', 'dx', 'dy']),
defaults: {

@@ -874,7 +901,7 @@ dx: '0',

},
content: ['animate', 'set'],
content: new Set(['animate', 'set']),
},
fePointLight: {
attrsGroups: ['core'],
attrs: ['x', 'y', 'z'],
attrsGroups: new Set(['core']),
attrs: new Set(['x', 'y', 'z']),
defaults: {

@@ -885,15 +912,15 @@ x: '0',

},
content: ['animate', 'set'],
content: new Set(['animate', 'set']),
},
feSpecularLighting: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: [
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set([
'class',
'style',
'in',
'surfaceScale',
'kernelUnitLength',
'specularConstant',
'specularExponent',
'kernelUnitLength',
],
'style',
'surfaceScale',
]),
defaults: {

@@ -904,14 +931,12 @@ surfaceScale: '1',

},
contentGroups: [
contentGroups: new Set([
'descriptive',
// TODO: exactly one 'light source element'
'lightSource',
],
]),
},
feSpotLight: {
attrsGroups: ['core'],
attrs: [
'x',
'y',
'z',
attrsGroups: new Set(['core']),
attrs: new Set([
'limitingConeAngle',
'pointsAtX',

@@ -921,4 +946,6 @@ 'pointsAtY',

'specularExponent',
'limitingConeAngle',
],
'x',
'y',
'z',
]),
defaults: {

@@ -933,20 +960,20 @@ x: '0',

},
content: ['animate', 'set'],
content: new Set(['animate', 'set']),
},
feTile: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: ['class', 'style', 'in'],
content: ['animate', 'set'],
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set(['class', 'style', 'in']),
content: new Set(['animate', 'set']),
},
feTurbulence: {
attrsGroups: ['core', 'presentation', 'filterPrimitive'],
attrs: [
attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']),
attrs: new Set([
'baseFrequency',
'class',
'style',
'baseFrequency',
'numOctaves',
'seed',
'stitchTiles',
'style',
'type',
],
]),
defaults: {

@@ -959,20 +986,20 @@ baseFrequency: '0',

},
content: ['animate', 'set'],
content: new Set(['animate', 'set']),
},
filter: {
attrsGroups: ['core', 'presentation', 'xlink'],
attrs: [
attrsGroups: new Set(['core', 'presentation', 'xlink']),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'x',
'y',
'width',
'height',
'filterRes',
'filterUnits',
'height',
'href',
'primitiveUnits',
'href',
'style',
'width',
'x',
'xlink:href',
],
'y',
]),
defaults: {

@@ -985,18 +1012,18 @@ primitiveUnits: 'userSpaceOnUse',

},
contentGroups: ['descriptive', 'filterPrimitive'],
content: ['animate', 'set'],
contentGroups: new Set(['descriptive', 'filterPrimitive']),
content: new Set(['animate', 'set']),
},
font: {
attrsGroups: ['core', 'presentation'],
attrs: [
attrsGroups: new Set(['core', 'presentation']),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'horiz-adv-x',
'horiz-origin-x',
'horiz-origin-y',
'horiz-adv-x',
'style',
'vert-adv-y',
'vert-origin-x',
'vert-origin-y',
'vert-adv-y',
],
]),
defaults: {

@@ -1006,8 +1033,8 @@ 'horiz-origin-x': '0',

},
contentGroups: ['descriptive'],
content: ['font-face', 'glyph', 'hkern', 'missing-glyph', 'vkern'],
contentGroups: new Set(['descriptive']),
content: new Set(['font-face', 'glyph', 'hkern', 'missing-glyph', 'vkern']),
},
'font-face': {
attrsGroups: ['core'],
attrs: [
attrsGroups: new Set(['core']),
attrs: new Set([
'font-family',

@@ -1046,3 +1073,3 @@ 'font-style',

'overline-thickness',
],
]),
defaults: {

@@ -1058,43 +1085,43 @@ 'font-style': 'all',

},
contentGroups: ['descriptive'],
content: [
contentGroups: new Set(['descriptive']),
content: new Set([
// TODO: "at most one 'font-face-src' element"
'font-face-src',
],
]),
},
// TODO: empty content
'font-face-format': {
attrsGroups: ['core'],
attrs: ['string'],
attrsGroups: new Set(['core']),
attrs: new Set(['string']),
},
'font-face-name': {
attrsGroups: ['core'],
attrs: ['name'],
attrsGroups: new Set(['core']),
attrs: new Set(['name']),
},
'font-face-src': {
attrsGroups: ['core'],
content: ['font-face-name', 'font-face-uri'],
attrsGroups: new Set(['core']),
content: new Set(['font-face-name', 'font-face-uri']),
},
'font-face-uri': {
attrsGroups: ['core', 'xlink'],
attrs: ['href', 'xlink:href'],
content: ['font-face-format'],
attrsGroups: new Set(['core', 'xlink']),
attrs: new Set(['href', 'xlink:href']),
content: new Set(['font-face-format']),
},
foreignObject: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',
'core',
'conditionalProcessing',
'graphicalEvent',
'presentation',
],
attrs: [
]),
attrs: new Set([
'class',
'externalResourcesRequired',
'height',
'style',
'externalResourcesRequired',
'transform',
'width',
'x',
'y',
'width',
'height',
],
]),
defaults: {

@@ -1106,3 +1133,3 @@ x: '0',

g: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1112,12 +1139,17 @@ 'core',

'presentation',
],
attrs: ['class', 'style', 'externalResourcesRequired', 'transform'],
contentGroups: [
]),
attrs: new Set([
'class',
'externalResourcesRequired',
'style',
'transform',
]),
contentGroups: new Set([
'animation',
'descriptive',
'paintServer',
'shape',
'structural',
'paintServer',
],
content: [
]),
content: new Set([
'a',

@@ -1129,4 +1161,4 @@ 'altGlyphDef',

'filter',
'font-face',
'font',
'font-face',
'foreignObject',

@@ -1142,31 +1174,31 @@ 'image',

'view',
],
]),
},
glyph: {
attrsGroups: ['core', 'presentation'],
attrs: [
attrsGroups: new Set(['core', 'presentation']),
attrs: new Set([
'arabic-form',
'class',
'style',
'd',
'glyph-name',
'horiz-adv-x',
'lang',
'orientation',
'style',
'unicode',
'vert-adv-y',
'vert-origin-x',
'vert-origin-y',
'vert-adv-y',
'unicode',
'glyph-name',
'orientation',
'arabic-form',
'lang',
],
]),
defaults: {
'arabic-form': 'initial',
},
contentGroups: [
contentGroups: new Set([
'animation',
'descriptive',
'paintServer',
'shape',
'structural',
'paintServer',
],
content: [
]),
content: new Set([
'a',

@@ -1178,4 +1210,4 @@ 'altGlyphDef',

'filter',
'font-face',
'font',
'font-face',
'foreignObject',

@@ -1191,23 +1223,23 @@ 'image',

'view',
],
]),
},
glyphRef: {
attrsGroups: ['core', 'presentation'],
attrs: [
attrsGroups: new Set(['core', 'presentation']),
attrs: new Set([
'class',
'style',
'd',
'horiz-adv-x',
'style',
'vert-adv-y',
'vert-origin-x',
'vert-origin-y',
'vert-adv-y',
],
contentGroups: [
]),
contentGroups: new Set([
'animation',
'descriptive',
'paintServer',
'shape',
'structural',
'paintServer',
],
content: [
]),
content: new Set([
'a',

@@ -1219,4 +1251,4 @@ 'altGlyphDef',

'filter',
'font-face',
'font',
'font-face',
'foreignObject',

@@ -1232,17 +1264,17 @@ 'image',

'view',
],
]),
},
hatch: {
attrsGroups: ['core', 'presentation', 'xlink'],
attrs: [
attrsGroups: new Set(['core', 'presentation', 'xlink']),
attrs: new Set([
'class',
'hatchContentUnits',
'hatchUnits',
'pitch',
'rotate',
'style',
'transform',
'x',
'y',
'pitch',
'rotate',
'hatchUnits',
'hatchContentUnits',
'transform',
],
]),
defaults: {

@@ -1256,38 +1288,38 @@ hatchUnits: 'objectBoundingBox',

},
contentGroups: ['animation', 'descriptive'],
content: ['hatchPath'],
contentGroups: new Set(['animation', 'descriptive']),
content: new Set(['hatchPath']),
},
hatchPath: {
attrsGroups: ['core', 'presentation', 'xlink'],
attrs: ['class', 'style', 'd', 'offset'],
attrsGroups: new Set(['core', 'presentation', 'xlink']),
attrs: new Set(['class', 'style', 'd', 'offset']),
defaults: {
offset: '0',
},
contentGroups: ['animation', 'descriptive'],
contentGroups: new Set(['animation', 'descriptive']),
},
hkern: {
attrsGroups: ['core'],
attrs: ['u1', 'g1', 'u2', 'g2', 'k'],
attrsGroups: new Set(['core']),
attrs: new Set(['u1', 'g1', 'u2', 'g2', 'k']),
},
image: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',
'core',
'conditionalProcessing',
'graphicalEvent',
'presentation',
'xlink',
'presentation',
],
attrs: [
]),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'height',
'href',
'preserveAspectRatio',
'style',
'transform',
'width',
'x',
'xlink:href',
'y',
'width',
'height',
'href',
'xlink:href',
],
]),
defaults: {

@@ -1298,6 +1330,6 @@ x: '0',

},
contentGroups: ['animation', 'descriptive'],
contentGroups: new Set(['animation', 'descriptive']),
},
line: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1307,13 +1339,13 @@ 'core',

'presentation',
],
attrs: [
]),
attrs: new Set([
'class',
'externalResourcesRequired',
'style',
'externalResourcesRequired',
'transform',
'x1',
'x2',
'y1',
'x2',
'y2',
],
]),
defaults: {

@@ -1325,20 +1357,20 @@ x1: '0',

},
contentGroups: ['animation', 'descriptive'],
contentGroups: new Set(['animation', 'descriptive']),
},
linearGradient: {
attrsGroups: ['core', 'presentation', 'xlink'],
attrs: [
attrsGroups: new Set(['core', 'presentation', 'xlink']),
attrs: new Set([
'class',
'externalResourcesRequired',
'gradientTransform',
'gradientUnits',
'href',
'spreadMethod',
'style',
'externalResourcesRequired',
'x1',
'x2',
'xlink:href',
'y1',
'x2',
'y2',
'gradientUnits',
'gradientTransform',
'spreadMethod',
'href',
'xlink:href',
],
]),
defaults: {

@@ -1351,20 +1383,20 @@ x1: '0',

},
contentGroups: ['descriptive'],
content: ['animate', 'animateTransform', 'set', 'stop'],
contentGroups: new Set(['descriptive']),
content: new Set(['animate', 'animateTransform', 'set', 'stop']),
},
marker: {
attrsGroups: ['core', 'presentation'],
attrs: [
attrsGroups: new Set(['core', 'presentation']),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'viewBox',
'markerHeight',
'markerUnits',
'markerWidth',
'orient',
'preserveAspectRatio',
'refX',
'refY',
'markerUnits',
'markerWidth',
'markerHeight',
'orient',
],
'style',
'viewBox',
]),
defaults: {

@@ -1377,10 +1409,10 @@ markerUnits: 'strokeWidth',

},
contentGroups: [
contentGroups: new Set([
'animation',
'descriptive',
'paintServer',
'shape',
'structural',
'paintServer',
],
content: [
]),
content: new Set([
'a',

@@ -1392,4 +1424,4 @@ 'altGlyphDef',

'filter',
'font-face',
'font',
'font-face',
'foreignObject',

@@ -1405,18 +1437,18 @@ 'image',

'view',
],
]),
},
mask: {
attrsGroups: ['conditionalProcessing', 'core', 'presentation'],
attrs: [
attrsGroups: new Set(['conditionalProcessing', 'core', 'presentation']),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'x',
'y',
'width',
'height',
'mask-type',
'maskContentUnits',
'maskUnits',
'maskContentUnits',
],
'style',
'width',
'x',
'y',
]),
defaults: {

@@ -1430,10 +1462,10 @@ maskUnits: 'objectBoundingBox',

},
contentGroups: [
contentGroups: new Set([
'animation',
'descriptive',
'paintServer',
'shape',
'structural',
'paintServer',
],
content: [
]),
content: new Set([
'a',

@@ -1445,4 +1477,4 @@ 'altGlyphDef',

'filter',
'font-face',
'font',
'font-face',
'foreignObject',

@@ -1458,26 +1490,26 @@ 'image',

'view',
],
]),
},
metadata: {
attrsGroups: ['core'],
attrsGroups: new Set(['core']),
},
'missing-glyph': {
attrsGroups: ['core', 'presentation'],
attrs: [
attrsGroups: new Set(['core', 'presentation']),
attrs: new Set([
'class',
'style',
'd',
'horiz-adv-x',
'style',
'vert-adv-y',
'vert-origin-x',
'vert-origin-y',
'vert-adv-y',
],
contentGroups: [
]),
contentGroups: new Set([
'animation',
'descriptive',
'paintServer',
'shape',
'structural',
'paintServer',
],
content: [
]),
content: new Set([
'a',

@@ -1489,4 +1521,4 @@ 'altGlyphDef',

'filter',
'font-face',
'font',
'font-face',
'foreignObject',

@@ -1502,11 +1534,11 @@ 'image',

'view',
],
]),
},
mpath: {
attrsGroups: ['core', 'xlink'],
attrs: ['externalResourcesRequired', 'href', 'xlink:href'],
contentGroups: ['descriptive'],
attrsGroups: new Set(['core', 'xlink']),
attrs: new Set(['externalResourcesRequired', 'href', 'xlink:href']),
contentGroups: new Set(['descriptive']),
},
path: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1516,31 +1548,36 @@ 'core',

'presentation',
],
attrs: [
]),
attrs: new Set([
'class',
'd',
'externalResourcesRequired',
'pathLength',
'style',
'externalResourcesRequired',
'transform',
'd',
'pathLength',
],
contentGroups: ['animation', 'descriptive'],
]),
contentGroups: new Set(['animation', 'descriptive']),
},
pattern: {
attrsGroups: ['conditionalProcessing', 'core', 'presentation', 'xlink'],
attrs: [
attrsGroups: new Set([
'conditionalProcessing',
'core',
'presentation',
'xlink',
]),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'viewBox',
'preserveAspectRatio',
'x',
'y',
'width',
'height',
'patternUnits',
'href',
'patternContentUnits',
'patternTransform',
'href',
'patternUnits',
'preserveAspectRatio',
'style',
'viewBox',
'width',
'x',
'xlink:href',
],
'y',
]),
defaults: {

@@ -1555,3 +1592,3 @@ patternUnits: 'objectBoundingBox',

},
contentGroups: [
contentGroups: new Set([
'animation',

@@ -1562,4 +1599,4 @@ 'descriptive',

'structural',
],
content: [
]),
content: new Set([
'a',

@@ -1571,4 +1608,4 @@ 'altGlyphDef',

'filter',
'font-face',
'font',
'font-face',
'foreignObject',

@@ -1584,6 +1621,6 @@ 'image',

'view',
],
]),
},
polygon: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1593,14 +1630,14 @@ 'core',

'presentation',
],
attrs: [
]),
attrs: new Set([
'class',
'externalResourcesRequired',
'points',
'style',
'externalResourcesRequired',
'transform',
'points',
],
contentGroups: ['animation', 'descriptive'],
]),
contentGroups: new Set(['animation', 'descriptive']),
},
polyline: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1610,30 +1647,30 @@ 'core',

'presentation',
],
attrs: [
]),
attrs: new Set([
'class',
'externalResourcesRequired',
'points',
'style',
'externalResourcesRequired',
'transform',
'points',
],
contentGroups: ['animation', 'descriptive'],
]),
contentGroups: new Set(['animation', 'descriptive']),
},
radialGradient: {
attrsGroups: ['core', 'presentation', 'xlink'],
attrs: [
attrsGroups: new Set(['core', 'presentation', 'xlink']),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'cx',
'cy',
'r',
'externalResourcesRequired',
'fr',
'fx',
'fy',
'fr',
'gradientTransform',
'gradientUnits',
'gradientTransform',
'href',
'r',
'spreadMethod',
'href',
'style',
'xlink:href',
],
]),
defaults: {

@@ -1645,25 +1682,25 @@ gradientUnits: 'objectBoundingBox',

},
contentGroups: ['descriptive'],
content: ['animate', 'animateTransform', 'set', 'stop'],
contentGroups: new Set(['descriptive']),
content: new Set(['animate', 'animateTransform', 'set', 'stop']),
},
meshGradient: {
attrsGroups: ['core', 'presentation', 'xlink'],
attrs: ['class', 'style', 'x', 'y', 'gradientUnits', 'transform'],
contentGroups: ['descriptive', 'paintServer', 'animation'],
content: ['meshRow'],
attrsGroups: new Set(['core', 'presentation', 'xlink']),
attrs: new Set(['class', 'style', 'x', 'y', 'gradientUnits', 'transform']),
contentGroups: new Set(['descriptive', 'paintServer', 'animation']),
content: new Set(['meshRow']),
},
meshRow: {
attrsGroups: ['core', 'presentation'],
attrs: ['class', 'style'],
contentGroups: ['descriptive'],
content: ['meshPatch'],
attrsGroups: new Set(['core', 'presentation']),
attrs: new Set(['class', 'style']),
contentGroups: new Set(['descriptive']),
content: new Set(['meshPatch']),
},
meshPatch: {
attrsGroups: ['core', 'presentation'],
attrs: ['class', 'style'],
contentGroups: ['descriptive'],
content: ['stop'],
attrsGroups: new Set(['core', 'presentation']),
attrs: new Set(['class', 'style']),
contentGroups: new Set(['descriptive']),
content: new Set(['stop']),
},
rect: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1673,15 +1710,15 @@ 'core',

'presentation',
],
attrs: [
]),
attrs: new Set([
'class',
'externalResourcesRequired',
'height',
'rx',
'ry',
'style',
'externalResourcesRequired',
'transform',
'width',
'x',
'y',
'width',
'height',
'rx',
'ry',
],
]),
defaults: {

@@ -1691,33 +1728,33 @@ x: '0',

},
contentGroups: ['animation', 'descriptive'],
contentGroups: new Set(['animation', 'descriptive']),
},
script: {
attrsGroups: ['core', 'xlink'],
attrs: ['externalResourcesRequired', 'type', 'href', 'xlink:href'],
attrsGroups: new Set(['core', 'xlink']),
attrs: new Set(['externalResourcesRequired', 'type', 'href', 'xlink:href']),
},
set: {
attrsGroups: [
attrsGroups: new Set([
'animation',
'animationAttributeTarget',
'animationTiming',
'conditionalProcessing',
'core',
'animation',
'xlink',
'animationAttributeTarget',
'animationTiming',
],
attrs: ['externalResourcesRequired', 'to'],
contentGroups: ['descriptive'],
]),
attrs: new Set(['externalResourcesRequired', 'to']),
contentGroups: new Set(['descriptive']),
},
solidColor: {
attrsGroups: ['core', 'presentation'],
attrs: ['class', 'style'],
contentGroups: ['paintServer'],
attrsGroups: new Set(['core', 'presentation']),
attrs: new Set(['class', 'style']),
contentGroups: new Set(['paintServer']),
},
stop: {
attrsGroups: ['core', 'presentation'],
attrs: ['class', 'style', 'offset', 'path'],
content: ['animate', 'animateColor', 'set'],
attrsGroups: new Set(['core', 'presentation']),
attrs: new Set(['class', 'style', 'offset', 'path']),
content: new Set(['animate', 'animateColor', 'set']),
},
style: {
attrsGroups: ['core'],
attrs: ['type', 'media', 'title'],
attrsGroups: new Set(['core']),
attrs: new Set(['type', 'media', 'title']),
defaults: {

@@ -1728,3 +1765,3 @@ type: 'text/css',

svg: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1735,18 +1772,18 @@ 'core',

'presentation',
],
attrs: [
]),
attrs: new Set([
'baseProfile',
'class',
'contentScriptType',
'contentStyleType',
'height',
'preserveAspectRatio',
'style',
'version',
'viewBox',
'width',
'x',
'y',
'width',
'height',
'viewBox',
'preserveAspectRatio',
'zoomAndPan',
'version',
'baseProfile',
'contentScriptType',
'contentStyleType',
],
]),
defaults: {

@@ -1764,10 +1801,10 @@ x: '0',

},
contentGroups: [
contentGroups: new Set([
'animation',
'descriptive',
'paintServer',
'shape',
'structural',
'paintServer',
],
content: [
]),
content: new Set([
'a',

@@ -1779,4 +1816,4 @@ 'altGlyphDef',

'filter',
'font-face',
'font',
'font-face',
'foreignObject',

@@ -1792,6 +1829,6 @@ 'image',

'view',
],
]),
},
switch: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1801,6 +1838,11 @@ 'core',

'presentation',
],
attrs: ['class', 'style', 'externalResourcesRequired', 'transform'],
contentGroups: ['animation', 'descriptive', 'shape'],
content: [
]),
attrs: new Set([
'class',
'externalResourcesRequired',
'style',
'transform',
]),
contentGroups: new Set(['animation', 'descriptive', 'shape']),
content: new Set([
'a',

@@ -1814,15 +1856,15 @@ 'foreignObject',

'use',
],
]),
},
symbol: {
attrsGroups: ['core', 'graphicalEvent', 'presentation'],
attrs: [
attrsGroups: new Set(['core', 'graphicalEvent', 'presentation']),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'preserveAspectRatio',
'viewBox',
'refX',
'refY',
],
'style',
'viewBox',
]),
defaults: {

@@ -1832,10 +1874,10 @@ refX: '0',

},
contentGroups: [
contentGroups: new Set([
'animation',
'descriptive',
'paintServer',
'shape',
'structural',
'paintServer',
],
content: [
]),
content: new Set([
'a',

@@ -1847,4 +1889,4 @@ 'altGlyphDef',

'filter',
'font-face',
'font',
'font-face',
'foreignObject',

@@ -1860,6 +1902,6 @@ 'image',

'view',
],
]),
},
text: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1869,16 +1911,16 @@ 'core',

'presentation',
],
attrs: [
]),
attrs: new Set([
'class',
'dx',
'dy',
'externalResourcesRequired',
'lengthAdjust',
'rotate',
'style',
'externalResourcesRequired',
'textLength',
'transform',
'lengthAdjust',
'x',
'y',
'dx',
'dy',
'rotate',
'textLength',
],
]),
defaults: {

@@ -1889,7 +1931,7 @@ x: '0',

},
contentGroups: ['animation', 'descriptive', 'textContentChild'],
content: ['a'],
contentGroups: new Set(['animation', 'descriptive', 'textContentChild']),
content: new Set(['a']),
},
textPath: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1900,14 +1942,14 @@ 'core',

'xlink',
],
attrs: [
]),
attrs: new Set([
'class',
'style',
'd',
'externalResourcesRequired',
'href',
'xlink:href',
'startOffset',
'method',
'spacing',
'd',
],
'startOffset',
'style',
'xlink:href',
]),
defaults: {

@@ -1918,4 +1960,4 @@ startOffset: '0',

},
contentGroups: ['descriptive'],
content: [
contentGroups: new Set(['descriptive']),
content: new Set([
'a',

@@ -1928,10 +1970,10 @@ 'altGlyph',

'tspan',
],
]),
},
title: {
attrsGroups: ['core'],
attrs: ['class', 'style'],
attrsGroups: new Set(['core']),
attrs: new Set(['class', 'style']),
},
tref: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1942,15 +1984,15 @@ 'core',

'xlink',
],
attrs: [
]),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'href',
'style',
'xlink:href',
],
contentGroups: ['descriptive'],
content: ['animate', 'animateColor', 'set'],
]),
contentGroups: new Set(['descriptive']),
content: new Set(['animate', 'animateColor', 'set']),
},
tspan: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',

@@ -1960,17 +2002,17 @@ 'core',

'presentation',
],
attrs: [
]),
attrs: new Set([
'class',
'style',
'externalResourcesRequired',
'x',
'y',
'dx',
'dy',
'externalResourcesRequired',
'lengthAdjust',
'rotate',
'style',
'textLength',
'lengthAdjust',
],
contentGroups: ['descriptive'],
content: [
'x',
'y',
]),
contentGroups: new Set(['descriptive']),
content: new Set([
'a',

@@ -1983,24 +2025,24 @@ 'altGlyph',

'tspan',
],
]),
},
use: {
attrsGroups: [
attrsGroups: new Set([
'conditionalProcessing',
'core',
'conditionalProcessing',
'graphicalEvent',
'presentation',
'xlink',
],
attrs: [
]),
attrs: new Set([
'class',
'externalResourcesRequired',
'height',
'href',
'style',
'externalResourcesRequired',
'transform',
'width',
'x',
'xlink:href',
'y',
'width',
'height',
'href',
'xlink:href',
],
]),
defaults: {

@@ -2010,18 +2052,18 @@ x: '0',

},
contentGroups: ['animation', 'descriptive'],
contentGroups: new Set(['animation', 'descriptive']),
},
view: {
attrsGroups: ['core'],
attrs: [
attrsGroups: new Set(['core']),
attrs: new Set([
'externalResourcesRequired',
'preserveAspectRatio',
'viewBox',
'preserveAspectRatio',
'viewTarget',
'zoomAndPan',
'viewTarget',
],
contentGroups: ['descriptive'],
]),
contentGroups: new Set(['descriptive']),
},
vkern: {
attrsGroups: ['core'],
attrs: ['u1', 'g1', 'u2', 'g2', 'k'],
attrsGroups: new Set(['core']),
attrs: new Set(['u1', 'g1', 'u2', 'g2', 'k']),
},

@@ -2031,26 +2073,26 @@ };

// https://wiki.inkscape.org/wiki/index.php/Inkscape-specific_XML_attributes
exports.editorNamespaces = [
'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd',
exports.editorNamespaces = new Set([
'http://creativecommons.org/ns#',
'http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd',
'http://www.inkscape.org/namespaces/inkscape',
'http://www.bohemiancoding.com/sketch/ns',
'http://ns.adobe.com/AdobeIllustrator/10.0/',
'http://ns.adobe.com/Graphs/1.0/',
'http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/',
'http://ns.adobe.com/Variables/1.0/',
'http://ns.adobe.com/SaveForWeb/1.0/',
'http://ns.adobe.com/Extensibility/1.0/',
'http://ns.adobe.com/Flows/1.0/',
'http://ns.adobe.com/GenericCustomNamespace/1.0/',
'http://ns.adobe.com/Graphs/1.0/',
'http://ns.adobe.com/ImageReplacement/1.0/',
'http://ns.adobe.com/GenericCustomNamespace/1.0/',
'http://ns.adobe.com/SaveForWeb/1.0/',
'http://ns.adobe.com/Variables/1.0/',
'http://ns.adobe.com/XPath/1.0/',
'http://purl.org/dc/elements/1.1/',
'http://schemas.microsoft.com/visio/2003/SVGExtensions/',
'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd',
'http://taptrix.com/vectorillustrator/svg_extensions',
'http://www.bohemiancoding.com/sketch/ns',
'http://www.figma.com/figma/ns',
'http://purl.org/dc/elements/1.1/',
'http://creativecommons.org/ns#',
'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'http://www.inkscape.org/namespaces/inkscape',
'http://www.serif.com/',
'http://www.vector.evaxdesign.sk',
];
'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
]);

@@ -2060,3 +2102,3 @@ /**

*/
exports.referencesProps = [
exports.referencesProps = new Set([
'clip-path',

@@ -2066,9 +2108,9 @@ 'color-profile',

'filter',
'marker-end',
'marker-mid',
'marker-start',
'marker-mid',
'marker-end',
'mask',
'stroke',
'style',
];
]);

@@ -2078,19 +2120,18 @@ /**

*/
exports.inheritableAttrs = [
exports.inheritableAttrs = new Set([
'clip-rule',
'color',
'color-interpolation-filters',
'color-interpolation',
'color-interpolation-filters',
'color-profile',
'color-rendering',
'color',
'cursor',
'direction',
'dominant-baseline',
'fill',
'fill-opacity',
'fill-rule',
'font',
'fill',
'font-family',
'font-size-adjust',
'font-size',
'font-size-adjust',
'font-stretch',

@@ -2100,2 +2141,3 @@ 'font-style',

'font-weight',
'font',
'glyph-orientation-horizontal',

@@ -2105,10 +2147,9 @@ 'glyph-orientation-vertical',

'letter-spacing',
'marker',
'marker-end',
'marker-mid',
'marker-start',
'marker',
'paint-order',
'pointer-events',
'shape-rendering',
'stroke',
'stroke-dasharray',

@@ -2121,2 +2162,3 @@ 'stroke-dashoffset',

'stroke-width',
'stroke',
'text-anchor',

@@ -2128,7 +2170,7 @@ 'text-rendering',

'writing-mode',
];
]);
exports.presentationNonInheritableGroupAttrs = [
exports.presentationNonInheritableGroupAttrs = new Set([
'clip-path',
'display',
'clip-path',
'filter',

@@ -2140,3 +2182,3 @@ 'mask',

'unicode-bidi',
];
]);

@@ -2340,61 +2382,67 @@ /**

*/
exports.colorsProps = [
exports.colorsProps = new Set([
'color',
'fill',
'stroke',
'stop-color',
'flood-color',
'lighting-color',
];
'stop-color',
'stroke',
]);
/** @see https://developer.mozilla.org/docs/Web/CSS/Pseudo-classes */
exports.pseudoClasses = {
displayState: ['fullscreen', 'modal', 'picture-in-picture'],
input: [
displayState: new Set(['fullscreen', 'modal', 'picture-in-picture']),
input: new Set([
'autofill',
'blank',
'checked',
'default',
'disabled',
'enabled',
'disabled',
'read-only',
'read-write',
'placeholder-shown',
'default',
'checked',
'in-range',
'indetermined',
'blank',
'valid',
'invalid',
'in-range',
'optional',
'out-of-range',
'placeholder-shown',
'read-only',
'read-write',
'required',
'optional',
'user-invalid',
],
linguistic: ['dir', 'lang'],
location: [
'valid',
]),
linguistic: new Set(['dir', 'lang']),
location: new Set([
'any-link',
'link',
'visited',
'local-link',
'scope',
'target-within',
'target',
'target-within',
'scope',
],
resourceState: ['playing', 'paused'],
timeDimensional: ['current', 'past', 'future'],
treeStructural: [
'root',
'visited',
]),
resourceState: new Set(['playing', 'paused']),
timeDimensional: new Set(['current', 'past', 'future']),
treeStructural: new Set([
'empty',
'first-child',
'first-of-type',
'last-child',
'last-of-type',
'nth-child',
'nth-last-child',
'first-child',
'last-child',
'nth-last-of-type',
'nth-of-type',
'only-child',
'nth-of-type',
'nth-last-of-type',
'first-of-type',
'last-of-type',
'only-of-type',
],
userAction: ['hover', 'active', 'focus', 'focus-visible', 'focus-within'],
functional: ['is', 'not', 'where', 'has'],
'root',
]),
userAction: new Set([
'active',
'focus-visible',
'focus-within',
'focus',
'hover',
]),
functional: new Set(['is', 'not', 'where', 'has']),
};

@@ -18,3 +18,3 @@ 'use strict';

*
* @type {(path: XastElement) => Array<PathDataItem>}
* @type {(path: XastElement) => PathDataItem[]}
*/

@@ -25,3 +25,3 @@ const path2js = (path) => {

/**
* @type {Array<PathDataItem>}
* @type {PathDataItem[]}
*/

@@ -46,3 +46,3 @@ const pathData = []; // JS representation of the path data

*
* @type {(data: Array<PathDataItem>) => Array<PathDataItem>}
* @type {(data: PathDataItem[]) => PathDataItem[]}
*

@@ -52,3 +52,3 @@ */

/**
* @type {Array<PathDataItem>}
* @type {PathDataItem[]}
*/

@@ -186,3 +186,3 @@ const newData = [];

*
* @type {(path: XastElement, data: Array<PathDataItem>, params: Js2PathParams) => void}
* @type {(path: XastElement, data: PathDataItem[], params: Js2PathParams) => void}
*/

@@ -219,3 +219,3 @@ exports.js2path = function (path, data, params) {

/**
* @type {(dest: Array<number>, source: Array<number>) => Array<number>}
* @type {(dest: number[], source: number[]) => number[]}
*/

@@ -233,3 +233,3 @@ function set(dest, source) {

*
* @type {(path1: Array<PathDataItem>, path2: Array<PathDataItem>) => boolean}
* @type {(path1: PathDataItem[], path2: PathDataItem[]) => boolean}
*/

@@ -277,6 +277,5 @@ exports.intersects = function (path1, path2) {

while (true) {
// eslint-disable-next-line no-constant-condition
if (iterations-- == 0) {
console.error(
'Error: infinite loop while processing mergePaths plugin.'
'Error: infinite loop while processing mergePaths plugin.',
);

@@ -296,3 +295,3 @@ return true; // true is the safe value that means “do nothing with paths”

/**
* @type {(a: Point, b: Point, direction: Array<number>) => Array<number>}
* @type {(a: Point, b: Point, direction: number[]) => number[]}
*/

@@ -307,3 +306,3 @@ function getSupport(a, b, direction) {

/**
* @type {(polygon: Point, direction: Array<number>) => Array<number>}
* @type {(polygon: Point, direction: number[]) => number[]}
*/

@@ -317,4 +316,4 @@ function supportPoint(polygon, direction) {

: direction[0] < 0
? polygon.minX
: polygon.minY,
? polygon.minX
: polygon.minY,
max = -Infinity,

@@ -331,3 +330,3 @@ value;

/**
* @type {(simplex: Array<Array<number>>, direction: Array<number>) => boolean}
* @type {(simplex: number[][], direction: number[]) => boolean}
*/

@@ -389,3 +388,3 @@ function processSimplex(simplex, direction) {

/**
* @type {(v: Array<number>) => Array<number>}
* @type {(v: number[]) => number[]}
*/

@@ -397,3 +396,3 @@ function minus(v) {

/**
* @type {(v1: Array<number>, v2: Array<number>) => Array<number>}
* @type {(v1: number[], v2: number[]) => number[]}
*/

@@ -405,3 +404,3 @@ function sub(v1, v2) {

/**
* @type {(v1: Array<number>, v2: Array<number>) => number}
* @type {(v1: number[], v2: number[]) => number}
*/

@@ -413,3 +412,3 @@ function dot(v1, v2) {

/**
* @type {(v1: Array<number>, v2: Array<number>) => Array<number>}
* @type {(v1: number[], v2: number[]) => number[]}
*/

@@ -423,3 +422,3 @@ function orth(v, from) {

* @typedef {{
* list: Array<Array<number>>,
* list: number[][],
* minX: number,

@@ -434,3 +433,3 @@ * minY: number,

* @typedef {{
* list: Array<Point>,
* list: Point[],
* minX: number,

@@ -444,3 +443,3 @@ * minY: number,

/**
* @type {(pathData: Array<PathDataItem>) => Points}
* @type {(pathData: PathDataItem[]) => Points}
*/

@@ -455,3 +454,3 @@ function gatherPoints(pathData) {

/**
* @type {(path: Point, point: Array<number>) => void}
* @type {(path: Point, point: number[]) => void}
*/

@@ -694,3 +693,3 @@ const addPoint = (path, point) => {

/**
* @type {(o: Array<number>, a: Array<number>, b: Array<number>) => number}
* @type {(o: number[], a: number[], b: number[]) => number}
*/

@@ -715,4 +714,4 @@ function cross(o, a, b) {

* y2: number,
* recursive: Array<number>
* ) => Array<number>}
* recursive: number[]
* ) => number[]}
*/

@@ -729,3 +728,3 @@ const a2c = (

y2,
recursive
recursive,
) => {

@@ -737,3 +736,3 @@ // for more information of where this Math came from visit:

/**
* @type {Array<number>}
* @type {number[]}
*/

@@ -772,4 +771,4 @@ let res = [];

Math.abs(
(rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x)
)
(rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x),
),
);

@@ -776,0 +775,0 @@ var cx = (k * rx * y) / ry + (x1 + x2) / 2;

'use strict';
const regTransformTypes = /matrix|translate|scale|rotate|skewX|skewY/;
const { toFixed } = require('../lib/svgo/tools');
/**
* @typedef {{ name: string, data: number[] }} TransformItem
* @typedef {{
* convertToShorts: boolean,
* floatPrecision: number,
* transformPrecision: number,
* matrixToTransform: boolean,
* shortTranslate: boolean,
* shortScale: boolean,
* shortRotate: boolean,
* removeUseless: boolean,
* collapseIntoOne: boolean,
* leadingZero: boolean,
* negativeExtraSpace: boolean,
* }} TransformParams
*/
const transformTypes = new Set([
'matrix',
'rotate',
'scale',
'skewX',
'skewY',
'translate',
]);
const regTransformSplit =

@@ -9,39 +36,29 @@ /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/;

/**
* @typedef {{ name: string, data: Array<number> }} TransformItem
*/
/**
* Convert transform string to JS representation.
*
* @type {(transformString: string) => Array<TransformItem>}
* @param {string} transformString
* @returns {TransformItem[]} Object representation of transform, or an empty array if it was malformed.
*/
exports.transform2js = (transformString) => {
// JS representation of the transform data
/**
* @type {Array<TransformItem>}
*/
/** @type {TransformItem[]} */
const transforms = [];
// current transform context
/**
* @type {?TransformItem}
*/
let current = null;
/** @type {?TransformItem} */
let currentTransform = null;
// split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', '']
for (const item of transformString.split(regTransformSplit)) {
var num;
if (item) {
// if item is a translate function
if (regTransformTypes.test(item)) {
// then collect it and change current context
current = { name: item, data: [] };
transforms.push(current);
// else if item is data
} else {
// then split it into [10, 50] and collect as context.data
// eslint-disable-next-line no-cond-assign
while ((num = regNumericValues.exec(item))) {
num = Number(num);
if (current != null) {
current.data.push(num);
}
if (!item) {
continue;
}
if (transformTypes.has(item)) {
currentTransform = { name: item, data: [] };
transforms.push(currentTransform);
} else {
let num;
// then split it into [10, 50] and collect as context.data
while ((num = regNumericValues.exec(item))) {
num = Number(num);
if (currentTransform != null) {
currentTransform.data.push(num);
}

@@ -51,4 +68,6 @@ }

}
// return empty array if broken transform (no data)
return current == null || current.data.length == 0 ? [] : transforms;
return currentTransform == null || currentTransform.data.length == 0
? []
: transforms;
};

@@ -59,6 +78,6 @@

*
* @type {(transforms: Array<TransformItem>) => TransformItem}
* @param {TransformItem[]} transforms
* @returns {TransformItem}
*/
exports.transformsMultiply = (transforms) => {
// convert transforms objects to the matrices
const matrixData = transforms.map((transform) => {

@@ -70,3 +89,3 @@ if (transform.name === 'matrix') {

});
// multiply all matrices into one
const matrixTransform = {

@@ -77,2 +96,3 @@ name: 'matrix',

};
return matrixTransform;

@@ -82,7 +102,8 @@ };

/**
* math utilities in radians.
* Math utilities in radians.
*/
const mth = {
/**
* @type {(deg: number) => number}
* @param {number} deg
* @returns {number}
*/

@@ -94,3 +115,4 @@ rad: (deg) => {

/**
* @type {(rad: number) => number}
* @param {number} rad
* @returns {number}
*/

@@ -102,3 +124,4 @@ deg: (rad) => {

/**
* @type {(deg: number) => number}
* @param {number} deg
* @returns {number}
*/

@@ -110,10 +133,13 @@ cos: (deg) => {

/**
* @type {(val: number, floatPrecision: number) => number}
* @param {number} val
* @param {number} floatPrecision
* @returns {number}
*/
acos: (val, floatPrecision) => {
return Number(mth.deg(Math.acos(val)).toFixed(floatPrecision));
return toFixed(mth.deg(Math.acos(val)), floatPrecision);
},
/**
* @type {(deg: number) => number}
* @param {number} deg
* @returns {number}
*/

@@ -125,10 +151,13 @@ sin: (deg) => {

/**
* @type {(val: number, floatPrecision: number) => number}
* @param {number} val
* @param {number} floatPrecision
* @returns {number}
*/
asin: (val, floatPrecision) => {
return Number(mth.deg(Math.asin(val)).toFixed(floatPrecision));
return toFixed(mth.deg(Math.asin(val)), floatPrecision);
},
/**
* @type {(deg: number) => number}
* @param {number} deg
* @returns {number}
*/

@@ -140,6 +169,8 @@ tan: (deg) => {

/**
* @type {(val: number, floatPrecision: number) => number}
* @param {number} val
* @param {number} floatPrecision
* @returns {number}
*/
atan: (val, floatPrecision) => {
return Number(mth.deg(Math.atan(val)).toFixed(floatPrecision));
return toFixed(mth.deg(Math.atan(val)), floatPrecision);
},

@@ -149,38 +180,13 @@ };

/**
* @typedef {{
* convertToShorts: boolean,
* floatPrecision: number,
* transformPrecision: number,
* matrixToTransform: boolean,
* shortTranslate: boolean,
* shortScale: boolean,
* shortRotate: boolean,
* removeUseless: boolean,
* collapseIntoOne: boolean,
* leadingZero: boolean,
* negativeExtraSpace: boolean,
* }} TransformParams
*/
/**
* Decompose matrix into simple transforms. See
* https://frederic-wang.fr/decomposition-of-2d-transform-matrices.html
* Decompose matrix into simple transforms.
*
* @type {(transform: TransformItem, params: TransformParams) => Array<TransformItem>}
* @param {TransformItem} transform
* @param {TransformParams} params
* @returns {TransformItem[]}
* @see https://frederic-wang.fr/decomposition-of-2d-transform-matrices.html
*/
exports.matrixToTransform = (transform, params) => {
let floatPrecision = params.floatPrecision;
let data = transform.data;
let transforms = [];
let sx = Number(
Math.hypot(data[0], data[1]).toFixed(params.transformPrecision)
);
let sy = Number(
((data[0] * data[3] - data[1] * data[2]) / sx).toFixed(
params.transformPrecision
)
);
let colsSum = data[0] * data[2] + data[1] * data[3];
let rowsSum = data[0] * data[1] + data[2] * data[3];
let scaleBefore = rowsSum != 0 || sx == sy;
const floatPrecision = params.floatPrecision;
const data = transform.data;
const transforms = [];

@@ -195,2 +201,11 @@ // [..., ..., ..., ..., tx, ty] → translate(tx, ty)

let sx = toFixed(Math.hypot(data[0], data[1]), params.transformPrecision);
let sy = toFixed(
(data[0] * data[3] - data[1] * data[2]) / sx,
params.transformPrecision,
);
const colsSum = data[0] * data[2] + data[1] * data[3];
const rowsSum = data[0] * data[1] + data[2] * data[3];
const scaleBefore = rowsSum !== 0 || sx === sy;
// [sx, 0, tan(a)·sy, sy, 0, 0] → skewX(a)·scale(sx, sy)

@@ -214,15 +229,30 @@ if (!data[1] && data[2]) {

// [sx·cos(a), sy·sin(a), sx·-sin(a), sy·cos(a), x, y] → scale(sx, sy)·rotate(a[, cx, cy]) (if !scaleBefore)
} else if (!colsSum || (sx == 1 && sy == 1) || !scaleBefore) {
} else if (!colsSum || (sx === 1 && sy === 1) || !scaleBefore) {
if (!scaleBefore) {
sx = (data[0] < 0 ? -1 : 1) * Math.hypot(data[0], data[2]);
sy = (data[3] < 0 ? -1 : 1) * Math.hypot(data[1], data[3]);
sx = Math.hypot(data[0], data[2]);
sy = Math.hypot(data[1], data[3]);
if (toFixed(data[0], params.transformPrecision) < 0) {
sx = -sx;
}
if (
data[3] < 0 ||
(Math.sign(data[1]) === Math.sign(data[2]) &&
toFixed(data[3], params.transformPrecision) === 0)
) {
sy = -sy;
}
transforms.push({ name: 'scale', data: [sx, sy] });
}
var angle = Math.min(Math.max(-1, data[0] / sx), 1),
rotate = [
mth.acos(angle, floatPrecision) *
((scaleBefore ? 1 : sy) * data[1] < 0 ? -1 : 1),
];
const angle = Math.min(Math.max(-1, data[0] / sx), 1);
const rotate = [
mth.acos(angle, floatPrecision) *
((scaleBefore ? 1 : sy) * data[1] < 0 ? -1 : 1),
];
if (rotate[0]) transforms.push({ name: 'rotate', data: rotate });
if (rotate[0]) {
transforms.push({ name: 'rotate', data: rotate });
}

@@ -238,11 +268,11 @@ if (rowsSum && colsSum)

transforms.shift();
var cos = data[0] / sx,
sin = data[1] / (scaleBefore ? sx : sy),
x = data[4] * (scaleBefore ? 1 : sy),
y = data[5] * (scaleBefore ? 1 : sx),
denom =
(Math.pow(1 - cos, 2) + Math.pow(sin, 2)) *
(scaleBefore ? 1 : sx * sy);
rotate.push(((1 - cos) * x - sin * y) / denom);
rotate.push(((1 - cos) * y + sin * x) / denom);
const oneOverCos = 1 - data[0] / sx;
const sin = data[1] / (scaleBefore ? sx : sy);
const x = data[4] * (scaleBefore ? 1 : sy);
const y = data[5] * (scaleBefore ? 1 : sx);
const denom = (oneOverCos ** 2 + sin ** 2) * (scaleBefore ? 1 : sx * sy);
rotate.push(
(oneOverCos * x - sin * y) / denom,
(oneOverCos * y + sin * x) / denom,
);
}

@@ -255,3 +285,3 @@

if ((scaleBefore && (sx != 1 || sy != 1)) || !transforms.length)
if ((scaleBefore && (sx != 1 || sy != 1)) || !transforms.length) {
transforms.push({

@@ -261,2 +291,3 @@ name: 'scale',

});
}

@@ -269,3 +300,3 @@ return transforms;

*
* @type {(transform: TransformItem) => Array<number> }
* @type {(transform: TransformItem) => number[] }
*/

@@ -323,5 +354,5 @@ const transformToMatrix = (transform) => {

* cursor: [x: number, y: number],
* arc: Array<number>,
* transform: Array<number>
* ) => Array<number>}
* arc: number[],
* transform: number[]
* ) => number[]}
*/

@@ -387,3 +418,3 @@ exports.transformArc = (cursor, arc, transform) => {

*
* @type {(a: Array<number>, b: Array<number>) => Array<number>}
* @type {(a: number[], b: number[]) => number[]}
*/

@@ -390,0 +421,0 @@ const multiplyTransformMatrices = (a, b) => {

@@ -70,3 +70,3 @@ 'use strict';

? null
: node.attributes.class.split(' ')
: node.attributes.class.split(' '),
);

@@ -73,0 +73,0 @@ for (const className of classNames) {

@@ -22,4 +22,4 @@ 'use strict';

/**
* @typedef {Array<PathDataItem>} PathData
* @typedef {Array<number>} Matrix
* @typedef {PathDataItem[]} PathData
* @typedef {number[]} Matrix
*/

@@ -61,3 +61,3 @@

([name, value]) =>
referencesProps.includes(name) && includesUrlReference(value)
referencesProps.has(name) && includesUrlReference(value),
)

@@ -80,3 +80,3 @@ ) {

const matrix = transformsMultiply(
transform2js(node.attributes.transform)
transform2js(node.attributes.transform),
);

@@ -104,4 +104,4 @@

Math.sqrt(
matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1]
).toFixed(transformPrecision)
matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1],
).toFixed(transformPrecision),
);

@@ -132,3 +132,3 @@

.replace(regNumericValues, (num) =>
removeLeadingZero(Number(num) * scale)
removeLeadingZero(Number(num) * scale),
);

@@ -142,3 +142,3 @@

.replace(regNumericValues, (num) =>
removeLeadingZero(Number(num) * scale)
removeLeadingZero(Number(num) * scale),
);

@@ -153,3 +153,3 @@ }

.replace(regNumericValues, (num) =>
removeLeadingZero(Number(num) * scale)
removeLeadingZero(Number(num) * scale),
);

@@ -156,0 +156,0 @@ }

@@ -28,3 +28,3 @@ 'use strict';

regNewlinesNeedSpace,
(match, p1, p2) => p1 + ' ' + p2
(match, p1, p2) => p1 + ' ' + p2,
);

@@ -34,3 +34,3 @@ // simple new line

regNewlines,
''
'',
);

@@ -44,3 +44,3 @@ }

regSpaces,
' '
' ',
);

@@ -47,0 +47,0 @@ }

@@ -102,3 +102,3 @@ 'use strict';

node.attributes.width,
node.attributes.height
node.attributes.height,
);

@@ -118,3 +118,3 @@

// @ts-ignore
enableBackgroundDeclaration.data.value
enableBackgroundDeclaration.data.value,
);

@@ -125,3 +125,3 @@ const styleCleaned = cleanupValue(

node.attributes.width,
node.attributes.height
node.attributes.height,
);

@@ -128,0 +128,0 @@

@@ -72,3 +72,3 @@ 'use strict';

*
* @type {(string: string, prefixes: Array<string>) => boolean}
* @type {(string: string, prefixes: string[]) => boolean}
*/

@@ -113,3 +113,3 @@ const hasStringPrefix = (string, prefixes) => {

*
* @type {(arr: Array<number>) => string}
* @type {(arr: number[]) => string}
*/

@@ -137,3 +137,3 @@ const getIdString = (arr) => {

const preserveIds = new Set(
Array.isArray(preserve) ? preserve : preserve ? [preserve] : []
Array.isArray(preserve) ? preserve : preserve ? [preserve] : [],
);

@@ -143,4 +143,4 @@ const preserveIdPrefixes = Array.isArray(preservePrefixes)

: preservePrefixes
? [preservePrefixes]
: [];
? [preservePrefixes]
: [];
/**

@@ -151,3 +151,3 @@ * @type {Map<string, XastElement>}

/**
* @type {Map<string, Array<{element: XastElement, name: string }>>}
* @type {Map<string, {element: XastElement, name: string }[]>}
*/

@@ -244,3 +244,3 @@ const referencesById = new Map();

`#${encodeURI(id)}`,
`#${currentIdString}`
`#${currentIdString}`,
);

@@ -251,3 +251,3 @@ } else {

`${id}.`,
`${currentIdString}.`
`${currentIdString}.`,
);

@@ -254,0 +254,0 @@ }

@@ -71,3 +71,3 @@ 'use strict';

const pxNum = Number(
(absoluteLengths[units] * Number(match[1])).toFixed(floatPrecision)
(absoluteLengths[units] * Number(match[1])).toFixed(floatPrecision),
);

@@ -116,3 +116,3 @@

node.attributes['enable-background'] = roundValues(
node.attributes['enable-background']
node.attributes['enable-background'],
);

@@ -127,3 +127,3 @@ }

node.attributes['stroke-dasharray'] = roundValues(
node.attributes['stroke-dasharray']
node.attributes['stroke-dasharray'],
);

@@ -130,0 +130,0 @@ }

@@ -78,4 +78,4 @@ 'use strict';

(absoluteLengths[units] * Number(match[1])).toFixed(
floatPrecision
)
floatPrecision,
),
);

@@ -82,0 +82,0 @@ if (pxNum.toString().length < match[0].length) {

@@ -18,3 +18,3 @@ 'use strict';

if (
elemsGroups.animation.includes(node.name) &&
elemsGroups.animation.has(node.name) &&
node.attributes.attributeName === name

@@ -99,3 +99,3 @@ ) {

} else if (
inheritableAttrs.includes(name) === false &&
inheritableAttrs.has(name) === false &&
firstChild.attributes[name] !== value

@@ -117,3 +117,3 @@ ) {

child.type === 'element' &&
elemsGroups.animation.includes(child.name)
elemsGroups.animation.has(child.name)
) {

@@ -120,0 +120,0 @@ return;

@@ -11,3 +11,3 @@ 'use strict';

const regRGB = new RegExp(
'^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$'
'^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$',
);

@@ -26,3 +26,3 @@ const regHEX = /^#(([a-fA-F0-9])\2){3}$/;

*
* @type {(rgb: Array<number>) => string}
* @type {(rgb: number[]) => string}
*/

@@ -81,3 +81,3 @@ const convertRgbToHex = ([r, g, b]) => {

for (const [name, value] of Object.entries(node.attributes)) {
if (collections.colorsProps.includes(name)) {
if (collections.colorsProps.has(name)) {
let val = value;

@@ -84,0 +84,0 @@

@@ -107,3 +107,3 @@ 'use strict';

const selector = colorsProps
const selector = [...colorsProps]
.map((attr) => `[${attr}="${selectorVal}"]`)

@@ -132,3 +132,3 @@ .join(',');

root,
`[style*=${selectorVal}]`
`[style*=${selectorVal}]`,
);

@@ -142,3 +142,3 @@ for (const element of styledElements) {

selectorVal,
color || attrsGroupsDefaults.presentation['stop-color']
color || attrsGroupsDefaults.presentation['stop-color'],
);

@@ -145,0 +145,0 @@ }

@@ -12,3 +12,3 @@ 'use strict';

const { applyTransforms } = require('./applyTransforms.js');
const { cleanupOutData } = require('../lib/svgo/tools');
const { cleanupOutData, toFixed } = require('../lib/svgo/tools');

@@ -19,21 +19,11 @@ exports.name = 'convertPathData';

/**
* @type {(data: number[]) => number[]}
*/
/** @type {(data: number[]) => number[]} */
let roundData;
/**
* @type {number | false}
*/
/** @type {number | false} */
let precision;
/**
* @type {number}
*/
/** @type {number} */
let error;
/**
* @type {number}
*/
/** @type {number} */
let arcThreshold;
/**
* @type {number}
*/
/** @type {number} */
let arcTolerance;

@@ -50,2 +40,3 @@

* straightCurves: boolean,
* convertToQ: boolean,
* lineShorthands: boolean,

@@ -56,2 +47,3 @@ * convertToZ: boolean,

* transformPrecision: number,
* smartArcRounding: boolean,
* removeUseless: boolean,

@@ -102,2 +94,3 @@ * collapseRepeated: boolean,

straightCurves = true,
convertToQ = true,
lineShorthands = true,

@@ -108,2 +101,3 @@ convertToZ = true,

transformPrecision = 5,
smartArcRounding = true,
removeUseless = true,

@@ -126,2 +120,3 @@ collapseRepeated = true,

straightCurves,
convertToQ,
lineShorthands,

@@ -132,2 +127,3 @@ convertToZ,

transformPrecision,
smartArcRounding,
removeUseless,

@@ -150,3 +146,3 @@ collapseRepeated,

applyTransformsStroked,
})
}),
);

@@ -159,3 +155,3 @@ }

enter: (node) => {
if (pathElems.includes(node.name) && node.attributes.d != null) {
if (pathElems.has(node.name) && node.attributes.d != null) {
const computedStyle = computeStyle(stylesheet, node);

@@ -167,3 +163,4 @@ precision = floatPrecision;

: 1e-2;
roundData = precision > 0 && precision < 20 ? strongRound : round;
roundData =
precision && precision > 0 && precision < 20 ? strongRound : round;
if (makeArcs) {

@@ -401,10 +398,16 @@ arcThreshold = makeArcs.threshold;

params,
{ isSafeToUseZ, maybeHasStrokeAndLinecap, hasMarkerMid }
{ isSafeToUseZ, maybeHasStrokeAndLinecap, hasMarkerMid },
) {
var stringify = data2Path.bind(null, params),
relSubpoint = [0, 0],
pathBase = [0, 0],
prev = {};
const stringify = data2Path.bind(null, params);
const relSubpoint = [0, 0];
const pathBase = [0, 0];
/** @type {any} */
let prev = {};
/** @type {Point | undefined} */
let prevQControlPoint;
path = path.filter(function (item, index, path) {
const qControlPoint = prevQControlPoint;
prevQControlPoint = undefined;
let command = item.command;

@@ -421,5 +424,4 @@ let data = item.args;

// @ts-ignore
var pdata = prev.args,
n = pdata.length;
const pdata = prev.args;
const n = pdata.length;

@@ -471,12 +473,7 @@ // (-x, -y) of the prev tangent point relative to the current point

if (
// @ts-ignore
(prev.command == 'c' &&
// @ts-ignore
isConvex(prev.args) &&
// @ts-ignore
isArcPrev(prev.args, circle)) ||
// @ts-ignore
(prev.command == 'a' && prev.sdata && isArcPrev(prev.sdata, circle))
) {
// @ts-ignore
arcCurves.unshift(prev);

@@ -489,3 +486,2 @@ // @ts-ignore

arc.args[6] = arc.coords[1] - arc.base[1];
// @ts-ignore
var prevData = prev.command == 'a' ? prev.sdata : prev.args;

@@ -507,3 +503,3 @@ var prevAngle = findArcAngle(prevData, {

var j = index;
(next = path[++j]) && ~'cs'.indexOf(next.command);
(next = path[++j]) && (next.command === 'c' || next.command === 's');

@@ -515,3 +511,3 @@ ) {

{ command: 's', args: next.args.slice() },
path[j - 1].args
path[j - 1].args,
);

@@ -585,3 +581,2 @@ nextData = nextLonghand.args;

relSubpoint[1] += prevArc.args[6] - prev.args[prev.args.length - 1];
// @ts-ignore
prev.command = 'a';

@@ -600,7 +595,3 @@ // @ts-ignore

// filter out consumed next items
path.splice.apply(
path,
// @ts-ignore
[index + 1, arcCurves.length - 1 - hasPrev].concat(output)
);
path.splice(index + 1, arcCurves.length - 1 - hasPrev, ...output);
}

@@ -659,2 +650,20 @@ if (!arc) return false;

// round arc radius more accurately
// eg m 0 0 a 1234.567 1234.567 0 0 1 10 0 -> m 0 0 a 1235 1235 0 0 1 10 0
const sagitta = command === 'a' ? calculateSagitta(data) : undefined;
if (params.smartArcRounding && sagitta !== undefined && precision) {
for (let precisionNew = precision; precisionNew >= 0; precisionNew--) {
const radius = toFixed(data[0], precisionNew);
const sagittaNew = /** @type {number} */ (
calculateSagitta([radius, radius, ...data.slice(2)])
);
if (Math.abs(sagitta - sagittaNew) < error) {
data[0] = radius;
data[1] = radius;
} else {
break;
}
}
}
// convert straight curves into lines segments

@@ -675,5 +684,3 @@ if (params.straightCurves) {

command === 't' &&
// @ts-ignore
prev.command !== 'q' &&
// @ts-ignore
prev.command !== 't'

@@ -683,3 +690,8 @@ ) {

data = data.slice(-2);
} else if (command === 'a' && (data[0] === 0 || data[1] === 0)) {
} else if (
command === 'a' &&
(data[0] === 0 ||
data[1] === 0 ||
(sagitta !== undefined && sagitta < error))
) {
command = 'l';

@@ -690,2 +702,40 @@ data = data.slice(-2);

// degree-lower c to q when possible
// m 0 12 C 4 4 8 4 12 12 → M 0 12 Q 6 0 12 12
if (params.convertToQ && command == 'c') {
const x1 =
// @ts-ignore
0.75 * (item.base[0] + data[0]) - 0.25 * item.base[0];
const x2 =
// @ts-ignore
0.75 * (item.base[0] + data[2]) - 0.25 * (item.base[0] + data[4]);
if (Math.abs(x1 - x2) < error * 2) {
const y1 =
// @ts-ignore
0.75 * (item.base[1] + data[1]) - 0.25 * item.base[1];
const y2 =
// @ts-ignore
0.75 * (item.base[1] + data[3]) - 0.25 * (item.base[1] + data[5]);
if (Math.abs(y1 - y2) < error * 2) {
const newData = data.slice();
newData.splice(
0,
4,
// @ts-ignore
x1 + x2 - item.base[0],
// @ts-ignore
y1 + y2 - item.base[1],
);
roundData(newData);
const originalLength = cleanupOutData(data, params).length,
newLength = cleanupOutData(newData, params).length;
if (newLength < originalLength) {
command = 'q';
data = newData;
if (next && next.command == 's') makeLonghand(next, data); // fix up next curve
}
}
}
}
// horizontal and vertical line shorthands

@@ -704,20 +754,2 @@ // l 50 0 → h 50

// convert going home to z
// m 0 0 h 5 v 5 l -5 -5 -> m 0 0 h 5 v 5 z
if (
params.convertToZ &&
(isSafeToUseZ || next?.command === 'Z' || next?.command === 'z') &&
(command === 'l' || command === 'h' || command === 'v')
) {
if (
// @ts-ignore
Math.abs(pathBase[0] - item.coords[0]) < error &&
// @ts-ignore
Math.abs(pathBase[1] - item.coords[1]) < error
) {
command = 'z';
data = [];
}
}
// collapse repeated commands

@@ -729,14 +761,9 @@ // h 20 h 30 -> h 50

(command === 'm' || command === 'h' || command === 'v') &&
// @ts-ignore
prev.command &&
// @ts-ignore
command == prev.command.toLowerCase() &&
((command != 'h' && command != 'v') ||
// @ts-ignore
prev.args[0] >= 0 == data[0] >= 0)
) {
// @ts-ignore
prev.args[0] += data[0];
if (command != 'h' && command != 'v') {
// @ts-ignore
prev.args[1] += data[1];

@@ -746,3 +773,2 @@ }

prev.coords = item.coords;
// @ts-ignore
path[index] = prev;

@@ -753,3 +779,2 @@ return false;

// convert curves into smooth shorthands
// @ts-ignore
if (params.curveSmoothShorthands && prev.command) {

@@ -760,8 +785,5 @@ // curveto

if (
// @ts-ignore
prev.command === 'c' &&
// @ts-ignore
data[0] === -(prev.args[2] - prev.args[4]) &&
// @ts-ignore
data[1] === -(prev.args[3] - prev.args[5])
Math.abs(data[0] - -(prev.args[2] - prev.args[4])) < error &&
Math.abs(data[1] - -(prev.args[3] - prev.args[5])) < error
) {

@@ -774,8 +796,5 @@ command = 's';

else if (
// @ts-ignore
prev.command === 's' &&
// @ts-ignore
data[0] === -(prev.args[0] - prev.args[2]) &&
// @ts-ignore
data[1] === -(prev.args[1] - prev.args[3])
Math.abs(data[0] - -(prev.args[0] - prev.args[2])) < error &&
Math.abs(data[1] - -(prev.args[1] - prev.args[3])) < error
) {

@@ -788,8 +807,6 @@ command = 's';

else if (
// @ts-ignore
prev.command !== 'c' &&
// @ts-ignore
prev.command !== 's' &&
data[0] === 0 &&
data[1] === 0
Math.abs(data[0]) < error &&
Math.abs(data[1]) < error
) {

@@ -805,8 +822,5 @@ command = 's';

if (
// @ts-ignore
prev.command === 'q' &&
// @ts-ignore
data[0] === prev.args[2] - prev.args[0] &&
// @ts-ignore
data[1] === prev.args[3] - prev.args[1]
Math.abs(data[0] - (prev.args[2] - prev.args[0])) < error &&
Math.abs(data[1] - (prev.args[3] - prev.args[1])) < error
) {

@@ -818,12 +832,23 @@ command = 't';

// t + q → t + t
else if (
// @ts-ignore
prev.command === 't' &&
// @ts-ignore
data[2] === prev.args[0] &&
// @ts-ignore
data[3] === prev.args[1]
) {
command = 't';
data = data.slice(2);
else if (prev.command === 't') {
const predictedControlPoint = reflectPoint(
// @ts-ignore
qControlPoint,
// @ts-ignore
item.base,
);
const realControlPoint = [
// @ts-ignore
data[0] + item.base[0],
// @ts-ignore
data[1] + item.base[1],
];
if (
Math.abs(predictedControlPoint[0] - realControlPoint[0]) <
error &&
Math.abs(predictedControlPoint[1] - realControlPoint[1]) < error
) {
command = 't';
data = data.slice(2);
}
}

@@ -848,3 +873,2 @@ }

) {
// @ts-ignore
path[index] = prev;

@@ -856,3 +880,2 @@ return false;

if (command === 'a' && data[5] === 0 && data[6] === 0) {
// @ts-ignore
path[index] = prev;

@@ -863,2 +886,20 @@ return false;

// convert going home to z
// m 0 0 h 5 v 5 l -5 -5 -> m 0 0 h 5 v 5 z
if (
params.convertToZ &&
(isSafeToUseZ || next?.command === 'Z' || next?.command === 'z') &&
(command === 'l' || command === 'h' || command === 'v')
) {
if (
// @ts-ignore
Math.abs(pathBase[0] - item.coords[0]) < error &&
// @ts-ignore
Math.abs(pathBase[1] - item.coords[1]) < error
) {
command = 'z';
data = [];
}
}
item.command = command;

@@ -870,3 +911,2 @@ item.args = data;

relSubpoint[1] = pathBase[1];
// @ts-ignore
if (prev.command === 'Z' || prev.command === 'z') return false;

@@ -885,2 +925,14 @@ }

if (command === 'q') {
// @ts-ignore
prevQControlPoint = [data[0] + item.base[0], data[1] + item.base[1]];
} else if (command === 't') {
if (qControlPoint) {
// @ts-ignore
prevQControlPoint = reflectPoint(qControlPoint, item.base);
} else {
// @ts-ignore
prevQControlPoint = item.coords;
}
}
prev = item;

@@ -910,3 +962,4 @@ return true;

data = item.args,
adata = data.slice();
adata = data.slice(),
rdata = data.slice();

@@ -939,5 +992,6 @@ if (

roundData(adata);
roundData(rdata);
var absoluteDataStr = cleanupOutData(adata, params),
relativeDataStr = cleanupOutData(data, params);
relativeDataStr = cleanupOutData(rdata, params);

@@ -957,4 +1011,5 @@ // Convert to absolute coordinates if it's shorter or forceAbsolutePath is true.

(data[0] < 0 ||
// @ts-ignore
(/^0\./.test(data[0]) && prev.args[prev.args.length - 1] % 1))
(Math.floor(data[0]) === 0 &&
!Number.isInteger(data[0]) &&
prev.args[prev.args.length - 1] % 1))
))

@@ -968,3 +1023,2 @@ ) {

prev = item;
return true;

@@ -1036,12 +1090,2 @@ });

/**
* Does the same as `Number.prototype.toFixed` but without casting
* the return value to a string.
* @type {(num: number, precision: number) => number}
*/
function toFixed(num, precision) {
const pow = 10 ** precision;
return Math.round(num * pow) / pow;
}
/**
* Decrease accuracy of floating-point numbers

@@ -1087,3 +1131,2 @@ * in path data keeping a specified number of decimals.

*/
function isCurveStraightLine(data) {

@@ -1108,2 +1151,17 @@ // Get line equation a·x + b·y + c = 0 coefficients a, b (c = 0) by start and end points.

/**
* Calculates the sagitta of an arc if possible.
*
* @type {(data: number[]) => number | undefined}
* @see https://wikipedia.org/wiki/Sagitta_(geometry)#Formulas
*/
function calculateSagitta(data) {
if (data[3] === 1) return undefined;
const [rx, ry] = data;
if (Math.abs(rx - ry) > error) return undefined;
const chord = Math.sqrt(data[5] ** 2 + data[6] ** 2);
if (chord > rx * 2) return undefined;
return rx - Math.sqrt(rx ** 2 - 0.25 * chord ** 2);
}
/**
* Converts next curve from shorthand to full form using the current curve data.

@@ -1113,3 +1171,2 @@ *

*/
function makeLonghand(item, data) {

@@ -1126,3 +1183,3 @@ switch (item.command) {

data[data.length - 2] - data[data.length - 4],
data[data.length - 1] - data[data.length - 3]
data[data.length - 1] - data[data.length - 3],
);

@@ -1137,8 +1194,18 @@ return item;

*/
function getDistance(point1, point2) {
return Math.hypot(point1[0] - point2[0], point1[1] - point2[1]);
return Math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2);
}
/**
* Reflects point across another point.
*
* @param {Point} controlPoint
* @param {Point} base
* @returns {Point}
*/
function reflectPoint(controlPoint, base) {
return [2 * base[0] - controlPoint[0], 2 * base[1] - controlPoint[1]];
}
/**
* Returns coordinates of the curve point corresponding to the certain t

@@ -1150,3 +1217,2 @@ * a·(1 - t)³·p1 + b·(1 - t)²·t·p2 + c·(1 - t)·t²·p3 + d·t³·p4,

*/
function getCubicBezierPoint(curve, t) {

@@ -1169,3 +1235,2 @@ var sqrT = t * t,

*/
function findCircle(curve) {

@@ -1197,3 +1262,3 @@ var midPoint = getCubicBezierPoint(curve, 1 / 2),

// @ts-ignore
getDistance(getCubicBezierPoint(curve, point), center) - radius
getDistance(getCubicBezierPoint(curve, point), center) - radius,
) <= tolerance

@@ -1212,7 +1277,6 @@ );

*/
function isArc(curve, circle) {
var tolerance = Math.min(
arcThreshold * error,
(arcTolerance * circle.radius) / 100
(arcTolerance * circle.radius) / 100,
);

@@ -1224,3 +1288,3 @@

getDistance(getCubicBezierPoint(curve, point), circle.center) -
circle.radius
circle.radius,
) <= tolerance

@@ -1236,3 +1300,2 @@ );

*/
function isArcPrev(curve, circle) {

@@ -1250,3 +1313,2 @@ return isArc(curve, {

*/
function findArcAngle(curve, relCircle) {

@@ -1259,3 +1321,3 @@ var x1 = -relCircle.center[0],

return Math.acos(
(x1 * x2 + y1 * y2) / Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2))
(x1 * x2 + y1 * y2) / Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2)),
);

@@ -1269,3 +1331,2 @@ }

*/
function data2Path(params, pathData) {

@@ -1272,0 +1333,0 @@ return pathData.reduce(function (pathString, item) {

@@ -49,3 +49,3 @@ 'use strict';

/**
* @type {Array<PathDataItem>}
* @type {PathDataItem[]}
*/

@@ -75,3 +75,3 @@ const pathData = [

/**
* @type {Array<PathDataItem>}
* @type {PathDataItem[]}
*/

@@ -96,3 +96,3 @@ const pathData = [

const coords = (node.attributes.points.match(regNumber) || []).map(
Number
Number,
);

@@ -104,3 +104,3 @@ if (coords.length < 4) {

/**
* @type {Array<PathDataItem>}
* @type {PathDataItem[]}
*/

@@ -131,3 +131,3 @@ const pathData = [];

/**
* @type {Array<PathDataItem>}
* @type {PathDataItem[]}
*/

@@ -157,3 +157,3 @@ const pathData = [

/**
* @type {Array<PathDataItem>}
* @type {PathDataItem[]}
*/

@@ -160,0 +160,0 @@ const pathData = [

@@ -34,3 +34,3 @@ 'use strict';

rParenthesis,
'[^;]*?'
'[^;]*?',
) +

@@ -46,3 +46,3 @@ '*?' +

rAttr + ':' + rValue + rImportant + rDeclEnd,
'ig'
'ig',
);

@@ -52,3 +52,3 @@ // Comments expression. Honors escape sequences and strings.

g(rEscape, rSingleQuotes, rQuotes, '/\\*[^]*?\\*/'),
'ig'
'ig',
);

@@ -93,9 +93,8 @@

: match[0] == '\\' && /[-g-z]/i.test(match[1])
? match[1]
: match;
}
? match[1]
: match;
},
);
regDeclarationBlock.lastIndex = 0;
// eslint-disable-next-line no-cond-assign
for (var rule; (rule = regDeclarationBlock.exec(styleValue)); ) {

@@ -117,3 +116,3 @@ if (!keepImportant || !rule[3]) {

if (stylingProps.includes(prop)) {
if (stylingProps.has(prop)) {
newAttributes[prop] = val;

@@ -120,0 +119,0 @@

'use strict';
/**
* @typedef {import('../lib/types').XastChild} XastChild
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types').XastParent} XastParent
*/
const { cleanupOutData } = require('../lib/svgo/tools.js');
const { cleanupOutData, toFixed } = require('../lib/svgo/tools.js');
const {

@@ -62,11 +64,10 @@ transform2js,

enter: (node) => {
// transform
if (node.attributes.transform != null) {
convertTransform(node, 'transform', newParams);
}
// gradientTransform
if (node.attributes.gradientTransform != null) {
convertTransform(node, 'gradientTransform', newParams);
}
// patternTransform
if (node.attributes.patternTransform != null) {

@@ -98,9 +99,9 @@ convertTransform(node, 'patternTransform', newParams);

/**
* @typedef {{ name: string, data: Array<number> }} TransformItem
* @typedef {{ name: string, data: number[] }} TransformItem
*/
/**
* Main function.
*
* @type {(item: XastElement, attrName: string, params: TransformParams) => void}
* @param {XastElement} item
* @param {string} attrName
* @param {TransformParams} params
*/

@@ -139,3 +140,3 @@ const convertTransform = (item, attrName, params) => {

*
* @type {(data: Array<TransformItem>, params: TransformParams) => TransformParams}
* @type {(data: TransformItem[], params: TransformParams) => TransformParams}
*

@@ -151,3 +152,3 @@ * clone params so it don't affect other elements transformations.

}
let significantDigits = newParams.transformPrecision;
let numberOfDigits = newParams.transformPrecision;
// Limit transform precision with matrix one. Calculating with larger precision doesn't add any value.

@@ -158,9 +159,9 @@ if (matrixData.length) {

Math.max.apply(Math, matrixData.map(floatDigits)) ||
newParams.transformPrecision
newParams.transformPrecision,
);
significantDigits = Math.max.apply(
numberOfDigits = Math.max.apply(
Math,
matrixData.map(
(n) => n.toString().replace(/\D+/g, '').length // Number of digits in a number. 123.45 → 5
)
(n) => n.toString().replace(/\D+/g, '').length, // Number of digits in a number. 123.45 → 5
),
);

@@ -172,3 +173,3 @@ }

0,
Math.min(newParams.floatPrecision, significantDigits - 2)
Math.min(newParams.floatPrecision, numberOfDigits - 2),
);

@@ -180,3 +181,3 @@ }

/**
* @type {(data: Array<number>, params: TransformParams) => Array<number>}
* @type {(data: number[], params: TransformParams) => number[]}
*/

@@ -195,3 +196,3 @@ const degRound = (data, params) => {

/**
* @type {(data: Array<number>, params: TransformParams) => Array<number>}
* @type {(data: number[], params: TransformParams) => number[]}
*/

@@ -207,3 +208,3 @@ const floatRound = (data, params) => {

/**
* @type {(data: Array<number>, params: TransformParams) => Array<number>}
* @type {(data: number[], params: TransformParams) => number[]}
*/

@@ -231,7 +232,9 @@ const transformRound = (data, params) => {

*
* @type {(transforms: Array<TransformItem>, params: TransformParams) => Array<TransformItem>}
* @param {TransformItem[]} transforms
* @param {TransformParams} params
* @returns {TransformItem[]}
*/
const convertToShorts = (transforms, params) => {
for (var i = 0; i < transforms.length; i++) {
var transform = transforms[i];
let transform = transforms[i];

@@ -280,4 +283,3 @@ // convert matrix to the short aliases

params.shortRotate &&
transforms[i - 2] &&
transforms[i - 2].name === 'translate' &&
transforms[i - 2]?.name === 'translate' &&
transforms[i - 1].name === 'rotate' &&

@@ -308,3 +310,3 @@ transforms[i].name === 'translate' &&

*
* @type {(transforms: Array<TransformItem>) => Array<TransformItem>}
* @type {(transforms: TransformItem[]) => TransformItem[]}
*/

@@ -347,3 +349,5 @@ const removeUseless = (transforms) => {

*
* @type {(transformJS: Array<TransformItem>, params: TransformParams) => string}
* @param {TransformItem[]} transformJS
* @param {TransformParams} params
* @returns {string}
*/

@@ -395,3 +399,3 @@ const js2transform = (transformJS, params) => {

*
* @type {(data: Array<number>) => Array<number>}
* @type {(data: number[]) => number[]}
*/

@@ -407,3 +411,5 @@ const round = (data) => {

*
* @type {(precision: number, data: Array<number>) => Array<number>}
* @param {number} precision
* @param {number[]} data
* @returns {number[]}
*/

@@ -417,3 +423,3 @@ const smartRound = (precision, data) => {

) {
if (Number(data[i].toFixed(precision)) !== data[i]) {
if (toFixed(data[i], precision) !== data[i]) {
var rounded = +data[i].toFixed(precision - 1);

@@ -426,3 +432,4 @@ data[i] =

}
return data;
};

@@ -10,3 +10,2 @@ 'use strict';

const {
// @ts-ignore internal api
syntax: { specificity },

@@ -55,12 +54,12 @@ } = require('csso');

/**
* @type {Array<{ node: XastElement, parentNode: XastParent, cssAst: csstree.StyleSheet }>}
* @type {{ node: XastElement, parentNode: XastParent, cssAst: csstree.StyleSheet }[]}
*/
const styles = [];
/**
* @type {Array<{
* @type {{
* node: csstree.Selector,
* item: csstree.ListItem<csstree.CssNode>,
* rule: csstree.Rule,
* matchedElements?: Array<XastElement>
* }>}
* matchedElements?: XastElement[]
* }[]}
*/

@@ -128,6 +127,6 @@ let selectors = [];

/**
* @type {Array<{
* @type {{
* item: csstree.ListItem<csstree.CssNode>,
* list: csstree.List<csstree.CssNode>
* }>}
* }[]}
*/

@@ -151,3 +150,3 @@ const pseudos = [];

}
}
},
);

@@ -158,3 +157,3 @@

children: new csstree.List().fromArray(
pseudos.map((pseudo) => pseudo.item.data)
pseudos.map((pseudo) => pseudo.item.data),
),

@@ -195,3 +194,3 @@ });

const selectorText = csstree.generate(selector.item.data);
/** @type {Array<XastElement>} */
/** @type {XastElement[]} */
const matchedElements = [];

@@ -225,3 +224,3 @@ try {

parseValue: false,
}
},
);

@@ -257,5 +256,5 @@ if (styleDeclarationList.type !== 'DeclarationList') {

if (
attrsGroups.presentation.includes(property) &&
attrsGroups.presentation.has(property) &&
!selectors.some((selector) =>
includesAttrSelector(selector.item, property)
includesAttrSelector(selector.item, property),
)

@@ -272,3 +271,3 @@ ) {

ruleDeclarationItem,
firstListItem
firstListItem,
);

@@ -281,3 +280,3 @@ } else if (

matchedItem,
ruleDeclarationItem
ruleDeclarationItem,
);

@@ -327,3 +326,3 @@ styleDeclarationItems.set(property, ruleDeclarationItem);

? null
: selectedEl.attributes.class.split(' ')
: selectedEl.attributes.class.split(' '),
);

@@ -335,3 +334,8 @@

!selectors.some((selector) =>
includesAttrSelector(selector.item, 'class', child.name, true)
includesAttrSelector(
selector.item,
'class',
child.name,
true,
),
)

@@ -359,4 +363,4 @@ ) {

firstSubSelector.name,
true
)
true,
),
)

@@ -363,0 +367,0 @@ ) {

'use strict';
const { detachNodeFromParent } = require('../lib/xast.js');
/**
* @typedef {import("../lib/types").PathDataItem} PathDataItem
* @typedef {import('../lib/types').XastChild} XastChild
* @typedef {import('../lib/types').XastElement} XastElement
*/
const { collectStylesheet, computeStyle } = require('../lib/style.js');

@@ -28,8 +33,27 @@ const { path2js, js2path, intersects } = require('./_path.js');

enter: (node) => {
let prevChild = null;
if (node.children.length <= 1) {
return;
}
for (const child of node.children) {
// skip if previous element is not path or contains animation elements
/** @type {XastChild[]} */
const elementsToRemove = [];
let prevChild = node.children[0];
let prevPathData = null;
/**
* @param {XastElement} child
* @param {PathDataItem[]} pathData
*/
const updatePreviousPath = (child, pathData) => {
js2path(child, pathData, {
floatPrecision,
noSpaceAfterFlags,
});
prevPathData = null;
};
for (let i = 1; i < node.children.length; i++) {
const child = node.children[i];
if (
prevChild == null ||
prevChild.type !== 'element' ||

@@ -40,2 +64,5 @@ prevChild.name !== 'path' ||

) {
if (prevPathData && prevChild.type === 'element') {
updatePreviousPath(prevChild, prevPathData);
}
prevChild = child;

@@ -45,3 +72,2 @@ continue;

// skip if element is not path or contains animation elements
if (

@@ -53,2 +79,5 @@ child.type !== 'element' ||

) {
if (prevPathData) {
updatePreviousPath(prevChild, prevPathData);
}
prevChild = child;

@@ -58,3 +87,2 @@ continue;

// preserve paths with markers
const computedStyle = computeStyle(stylesheet, child);

@@ -66,36 +94,58 @@ if (

) {
if (prevPathData) {
updatePreviousPath(prevChild, prevPathData);
}
prevChild = child;
continue;
}
const prevChildAttrs = Object.keys(prevChild.attributes);
const childAttrs = Object.keys(child.attributes);
let attributesAreEqual = prevChildAttrs.length === childAttrs.length;
for (const name of childAttrs) {
if (name !== 'd') {
if (
prevChild.attributes[name] == null ||
prevChild.attributes[name] !== child.attributes[name]
) {
attributesAreEqual = false;
}
if (childAttrs.length !== Object.keys(prevChild.attributes).length) {
if (prevPathData) {
updatePreviousPath(prevChild, prevPathData);
}
prevChild = child;
continue;
}
const prevPathJS = path2js(prevChild);
const curPathJS = path2js(child);
if (
attributesAreEqual &&
(force || !intersects(prevPathJS, curPathJS))
) {
js2path(prevChild, prevPathJS.concat(curPathJS), {
floatPrecision,
noSpaceAfterFlags,
});
detachNodeFromParent(child, node);
const areAttrsEqual = childAttrs.some((attr) => {
return (
attr !== 'd' &&
prevChild.type === 'element' &&
prevChild.attributes[attr] !== child.attributes[attr]
);
});
if (areAttrsEqual) {
if (prevPathData) {
updatePreviousPath(prevChild, prevPathData);
}
prevChild = child;
continue;
}
const hasPrevPath = prevPathData != null;
const currentPathData = path2js(child);
prevPathData = prevPathData ?? path2js(prevChild);
if (force || !intersects(prevPathData, currentPathData)) {
prevPathData.push(...currentPathData);
elementsToRemove.push(child);
continue;
}
if (hasPrevPath) {
updatePreviousPath(prevChild, prevPathData);
}
prevChild = child;
prevPathData = null;
}
if (prevPathData && prevChild.type === 'element') {
updatePreviousPath(prevChild, prevPathData);
}
node.children = node.children.filter(
(child) => !elementsToRemove.includes(child),
);
},

@@ -102,0 +152,0 @@ },

@@ -25,3 +25,3 @@ 'use strict';

/** @type {Array<XastElement>} */
/** @type {XastElement[]} */
const elementsWithStyleAttributes = [];

@@ -28,0 +28,0 @@

@@ -67,3 +67,3 @@ 'use strict';

if (child.type === 'element') {
if (pathElems.includes(child.name) === false) {
if (!pathElems.has(child.name)) {
everyChildIsPath = false;

@@ -76,3 +76,3 @@ }

// consider only inheritable attributes
if (inheritableAttrs.includes(name)) {
if (inheritableAttrs.has(name)) {
commonAttributes.set(name, value);

@@ -79,0 +79,0 @@ }

@@ -40,3 +40,3 @@ 'use strict';

([name, value]) =>
referencesProps.includes(name) && includesUrlReference(value)
referencesProps.has(name) && includesUrlReference(value),
) === false &&

@@ -47,3 +47,3 @@ node.children.every(

pathElemsWithGroupsAndText.includes(child.name) &&
child.attributes.id == null
child.attributes.id == null,
)

@@ -50,0 +50,0 @@ ) {

@@ -44,2 +44,3 @@ import type {

straightCurves?: boolean;
convertToQ?: boolean;
lineShorthands?: boolean;

@@ -50,2 +51,3 @@ convertToZ?: boolean;

transformPrecision?: number;
smartArcRounding?: boolean;
removeUseless?: boolean;

@@ -260,3 +262,3 @@ collapseRepeated?: boolean;

*/
includeLegacy: boolean
includeLegacy: boolean;
};

@@ -263,0 +265,0 @@ removeXMLNS: void;

@@ -176,11 +176,8 @@ 'use strict';

}
// @ts-ignore csstree v2 changed this type
if (node.type === 'Url' && node.value.length > 0) {
const prefixed = prefixReference(
prefixGenerator,
// @ts-ignore
unquote(node.value)
unquote(node.value),
);
if (prefixed != null) {
// @ts-ignore
node.value = prefixed;

@@ -226,3 +223,3 @@ }

prefixGenerator,
node.attributes[name]
node.attributes[name],
);

@@ -249,3 +246,3 @@ if (prefixed != null) {

return `url(${prefixed})`;
}
},
);

@@ -252,0 +249,0 @@ }

@@ -34,3 +34,3 @@ 'use strict';

throw Error(
`Expected array in removeComments preservePatterns parameter but received ${preservePatterns}`
`Expected array in removeComments preservePatterns parameter but received ${preservePatterns}`,
);

@@ -37,0 +37,0 @@ }

@@ -22,3 +22,3 @@ 'use strict';

exports.fn = (_root, params) => {
let namespaces = editorNamespaces;
let namespaces = [...editorNamespaces];
if (Array.isArray(params.additionalNamespaces)) {

@@ -28,3 +28,3 @@ namespaces = [...editorNamespaces, ...params.additionalNamespaces];

/**
* @type {Array<string>}
* @type {string[]}
*/

@@ -31,0 +31,0 @@ const prefixes = [];

@@ -49,4 +49,4 @@ 'use strict';

: Array.isArray(params.class)
? params.class
: [params.class];
? params.class
: [params.class];
return {

@@ -53,0 +53,0 @@ element: {

@@ -23,3 +23,3 @@ 'use strict';

// empty conditional processing attributes prevents elements from rendering
attrsGroups.conditionalProcessing.includes(name) === false
!attrsGroups.conditionalProcessing.has(name)
) {

@@ -26,0 +26,0 @@ delete node.attributes[name];

@@ -31,3 +31,3 @@ 'use strict';

node.name === 'svg' ||
elemsGroups.container.includes(node.name) === false ||
!elemsGroups.container.has(node.name) ||
node.children.length !== 0

@@ -34,0 +34,0 @@ ) {

@@ -117,3 +117,3 @@ 'use strict';

// transparent non-rendering elements still apply where referenced
if (nonRendering.includes(node.name)) {
if (nonRendering.has(node.name)) {
if (node.attributes.id == null) {

@@ -120,0 +120,0 @@ detachNodeFromParent(node, parentNode);

@@ -27,5 +27,5 @@ 'use strict';

if (
attrsGroups.presentation.includes(name) === true &&
inheritableAttrs.includes(name) === false &&
presentationNonInheritableGroupAttrs.includes(name) === false
attrsGroups.presentation.has(name) &&
!inheritableAttrs.has(name) &&
!presentationNonInheritableGroupAttrs.has(name)
) {

@@ -32,0 +32,0 @@ delete node.attributes[name];

@@ -60,3 +60,3 @@ 'use strict';

/^(-?\d*\.?\d+) (-?\d*\.?\d+) (\d*\.?\d+) (\d*\.?\d+)$/.exec(
viewBox
viewBox,
);

@@ -120,3 +120,3 @@ if (m == null) {

/**
* @type {Array<PathDataItem>}
* @type {PathDataItem[]}
*/

@@ -123,0 +123,0 @@ const viewBoxPathData = [

@@ -132,3 +132,3 @@ 'use strict';

const allowedChildren = allowedChildrenPerElement.get(
parentNode.name
parentNode.name,
);

@@ -201,3 +201,3 @@ if (allowedChildren == null || allowedChildren.size === 0) {

if (
presentationNonInheritableGroupAttrs.includes(name) === false &&
presentationNonInheritableGroupAttrs.has(name) === false &&
style != null &&

@@ -204,0 +204,0 @@ style.type === 'static' &&

@@ -26,3 +26,3 @@ 'use strict';

/**
* @type {Array<XastElement>}
* @type {XastElement[]}
*/

@@ -43,3 +43,3 @@ const usefulNodes = [];

} else if (
elemsGroups.nonRendering.includes(node.name) &&
elemsGroups.nonRendering.has(node.name) &&
node.attributes.id == null

@@ -55,3 +55,3 @@ ) {

/**
* @type {(node: XastElement, usefulNodes: Array<XastElement>) => void}
* @type {(node: XastElement, usefulNodes: XastElement[]) => void}
*/

@@ -58,0 +58,0 @@ const collectUsefulNodes = (node, usefulNodes) => {

@@ -49,3 +49,3 @@ 'use strict';

}
if (elemsGroups.shape.includes(node.name) == false) {
if (!elemsGroups.shape.has(node.name)) {
return;

@@ -52,0 +52,0 @@ }

@@ -6,3 +6,3 @@ 'use strict';

const viewBoxElems = ['svg', 'pattern', 'symbol'];
const viewBoxElems = new Set(['pattern', 'svg', 'symbol']);

@@ -28,3 +28,3 @@ /**

if (
viewBoxElems.includes(node.name) &&
viewBoxElems.has(node.name) &&
node.attributes.viewBox != null &&

@@ -31,0 +31,0 @@ node.attributes.width != null &&

@@ -31,7 +31,7 @@ 'use strict';

*
* @type {string[]}
* @type {Set<string>}
* @see https://developer.mozilla.org/docs/Web/SVG/Attribute/xlink:href
* @see https://developer.mozilla.org/docs/Web/SVG/Attribute/href
*/
const LEGACY_ELEMENTS = [
const LEGACY_ELEMENTS = new Set([
'cursor',

@@ -42,3 +42,3 @@ 'filter',

'tref',
];
]);

@@ -141,3 +141,3 @@ /**

const hasTitle = node.children.filter(
(child) => child.type === 'element' && child.name === 'title'
(child) => child.type === 'element' && child.name === 'title',
);

@@ -176,3 +176,3 @@

hrefAttrs.length > 0 &&
LEGACY_ELEMENTS.includes(node.name) &&
LEGACY_ELEMENTS.has(node.name) &&
!includeLegacy

@@ -179,0 +179,0 @@ ) {

@@ -30,3 +30,3 @@ 'use strict';

/**
* @type {Map<string, Array<XastElement>>}
* @type {Map<string, XastElement[]>}
*/

@@ -127,3 +127,3 @@ const paths = new Map();

stylesheet.rules.some(
(rule) => rule.selector === `#${originalId}`
(rule) => rule.selector === `#${originalId}`,
)

@@ -130,0 +130,0 @@ ) {

@@ -35,2 +35,3 @@ <div align="center">

```
Process a directory of files recursively with `-f`/`--folder`:

@@ -55,2 +56,3 @@

**`svgo.config.js`**
```js

@@ -62,3 +64,3 @@ module.exports = {

indent: 4, // number
pretty: false // boolean
pretty: false, // boolean
},

@@ -73,8 +75,9 @@ plugins: [

params: {
prefix: 'uwu'
}
}
]
prefix: 'uwu',
},
},
],
};
```
### Default preset

@@ -85,2 +88,3 @@

**`svgo.config.js`**
```js

@@ -99,7 +103,7 @@ module.exports = {

onlyMatchedOnce: false,
}
}
}
}
]
},
},
},
},
],
};

@@ -115,2 +119,3 @@ ```

**`svgo.config.js`**
```js

@@ -130,5 +135,5 @@ const importedPlugin = require('./imported-plugin');

},
fn: (ast, params, info) => {}
}
]
fn: (ast, params, info) => {},
},
],
};

@@ -150,3 +155,3 @@ ```

path: 'path-to.svg', // recommended
multipass: true // all other config fields are available here
multipass: true, // all other config fields are available here
});

@@ -175,19 +180,19 @@

| 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) |
| 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) |

@@ -197,4 +202,4 @@ ## Donors

| [<img src="https://sheetjs.com/sketch128.png" width="80">](https://sheetjs.com/) | [<img src="https://raw.githubusercontent.com/fontello/fontello/8.0.0/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/) |

@@ -201,0 +206,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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc