svgo
Advanced tools
Comparing version 3.1.0 to 3.2.0
@@ -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) { |
141
lib/path.js
'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
1300798
16896
200
Updatedcss-tree@^2.3.1
Updatedcsso@^5.0.5