diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2024-01-04 11:07:54 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2024-01-04 11:07:54 +0800 |
| commit | 275f9dc0bdf3e58aa36b800f55f8648fbc55d8af (patch) | |
| tree | 81c7cf120fb703cfd5e3162f2366033d9fe5c7f8 /node_modules/svgo/plugins | |
| parent | 2b4ab36917baef56c7ce1602966f941be15af785 (diff) | |
upgrade
Diffstat (limited to 'node_modules/svgo/plugins')
38 files changed, 1336 insertions, 1138 deletions
diff --git a/node_modules/svgo/plugins/_collections.js b/node_modules/svgo/plugins/_collections.js index b9e67cb7..6f11b136 100644 --- a/node_modules/svgo/plugins/_collections.js +++ b/node_modules/svgo/plugins/_collections.js @@ -3,41 +3,50 @@ // https://www.w3.org/TR/SVG11/intro.html#Definitions /** - * @type {Record<string, Array<string>>} + * @type {Record<string, Set<string>>} */ exports.elemsGroups = { - animation: [ + animation: new Set([ 'animate', 'animateColor', 'animateMotion', 'animateTransform', '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', - 'mask', - 'marker', - 'symbol', 'filter', + 'linearGradient', + 'marker', + 'mask', + 'pattern', + 'radialGradient', 'solidColor', - ], - container: [ + 'symbol', + ]), + container: new Set([ 'a', 'defs', + 'foreignObject', 'g', 'marker', 'mask', @@ -46,28 +55,27 @@ exports.elemsGroups = { 'svg', 'switch', 'symbol', - 'foreignObject', - ], - textContent: [ + ]), + textContent: new Set([ 'altGlyph', 'altGlyphDef', 'altGlyphItem', 'glyph', 'glyphRef', - 'textPath', 'text', + 'textPath', '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', 'feColorMatrix', 'feComponentTransfer', @@ -90,7 +98,7 @@ exports.elemsGroups = { 'feSpecularLighting', 'feTile', 'feTurbulence', - ], + ]), }; /** @@ -99,81 +107,85 @@ exports.elemsGroups = { * * @see https://developer.mozilla.org/docs/Web/HTML/Element/pre */ -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', - 'min', + 'fill', 'max', - 'restart', + 'min', 'repeatCount', 'repeatDur', - 'fill', - ], - animationValue: [ + 'restart', + ]), + animationValue: new Set([ + 'by', 'calcMode', - 'values', - 'keyTimes', - 'keySplines', 'from', + 'keySplines', + 'keyTimes', 'to', - 'by', - ], - conditionalProcessing: [ - 'requiredFeatures', + 'values', + ]), + conditionalProcessing: new Set([ 'requiredExtensions', + 'requiredFeatures', 'systemLanguage', - ], - core: ['id', 'tabindex', 'xml:base', 'xml:lang', 'xml:space'], - graphicalEvent: [ - 'onfocusin', - 'onfocusout', + ]), + core: new Set(['id', 'tabindex', 'xml:base', 'xml:lang', 'xml:space']), + graphicalEvent: new Set([ 'onactivate', 'onclick', + 'onfocusin', + 'onfocusout', + 'onload', 'onmousedown', - 'onmouseup', - 'onmouseover', 'onmousemove', 'onmouseout', - 'onload', - ], - presentation: [ + 'onmouseover', + 'onmouseup', + ]), + presentation: new Set([ 'alignment-baseline', 'baseline-shift', - 'clip', 'clip-path', 'clip-rule', - 'color', - 'color-interpolation', + 'clip', 'color-interpolation-filters', + 'color-interpolation', 'color-profile', 'color-rendering', + 'color', 'cursor', 'direction', 'display', 'dominant-baseline', 'enable-background', - 'fill', 'fill-opacity', 'fill-rule', + 'fill', 'filter', 'flood-color', 'flood-opacity', 'font-family', - 'font-size', 'font-size-adjust', + 'font-size', 'font-stretch', 'font-style', 'font-variant', @@ -194,7 +206,6 @@ exports.attrsGroups = { 'shape-rendering', 'stop-color', 'stop-opacity', - 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', @@ -202,37 +213,38 @@ exports.attrsGroups = { 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', + 'stroke', 'text-anchor', 'text-decoration', 'text-overflow', 'text-rendering', - 'transform', 'transform-origin', + 'transform', 'unicode-bidi', 'vector-effect', 'visibility', 'word-spacing', 'writing-mode', - ], - xlink: [ - 'xlink:href', - 'xlink:show', + ]), + xlink: new Set([ 'xlink:actuate', - 'xlink:type', - 'xlink:role', 'xlink:arcrole', + 'xlink:href', + 'xlink:role', + 'xlink:show', 'xlink:title', - ], - documentEvent: [ + 'xlink:type', + ]), + documentEvent: new Set([ 'onabort', 'onerror', 'onresize', 'onscroll', 'onunload', 'onzoom', - ], - documentElementEvent: ['oncopy', 'oncut', 'onpaste'], - globalEvent: [ + ]), + documentElementEvent: new Set(['oncopy', 'oncut', 'onpaste']), + globalEvent: new Set([ 'oncancel', 'oncanplay', 'oncanplaythrough', @@ -289,17 +301,17 @@ exports.attrsGroups = { 'ontoggle', 'onvolumechange', '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', + ]), }; /** @@ -371,49 +383,49 @@ exports.attrsGroupsDefaults = { /** * @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>, * }>} * @see https://www.w3.org/TR/SVG11/eltindex.html */ exports.elems = { a: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', 'presentation', 'xlink', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', 'externalResourcesRequired', - 'transform', + 'style', 'target', - ], + 'transform', + ]), defaults: { target: '_self', }, - contentGroups: [ + contentGroups: new Set([ 'animation', 'descriptive', + 'paintServer', 'shape', 'structural', - 'paintServer', - ], - content: [ + ]), + content: new Set([ 'a', 'altGlyphDef', 'clipPath', 'color-profile', 'cursor', 'filter', - 'font', 'font-face', + 'font', 'foreignObject', 'image', 'marker', @@ -426,183 +438,188 @@ exports.elems = { 'view', // not spec compliant 'tspan', - ], + ]), }, altGlyph: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', 'presentation', 'xlink', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', - 'externalResourcesRequired', - 'x', - 'y', 'dx', 'dy', - 'glyphRef', + 'externalResourcesRequired', 'format', + 'glyphRef', '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', 'animationAttributeTarget', 'animationEvent', 'animationTiming', 'animationValue', + 'conditionalProcessing', + 'core', 'presentation', 'xlink', - ], - attrs: ['externalResourcesRequired'], - contentGroups: ['descriptive'], + ]), + attrs: new Set(['externalResourcesRequired']), + contentGroups: new Set(['descriptive']), }, animateColor: { - attrsGroups: [ - 'conditionalProcessing', - 'core', - 'animationEvent', - 'xlink', + attrsGroups: new Set([ + 'animationAddition', 'animationAttributeTarget', + 'animationEvent', 'animationTiming', 'animationValue', - 'animationAddition', + 'conditionalProcessing', + 'core', 'presentation', - ], - attrs: ['externalResourcesRequired'], - contentGroups: ['descriptive'], + 'xlink', + ]), + attrs: new Set(['externalResourcesRequired']), + contentGroups: new Set(['descriptive']), }, animateMotion: { - attrsGroups: [ - 'conditionalProcessing', - 'core', + attrsGroups: new Set([ + 'animationAddition', 'animationEvent', - 'xlink', 'animationTiming', 'animationValue', - 'animationAddition', - ], - attrs: [ + 'conditionalProcessing', + 'core', + 'xlink', + ]), + attrs: new Set([ 'externalResourcesRequired', - 'path', 'keyPoints', - 'rotate', 'origin', - ], + 'path', + 'rotate', + ]), defaults: { rotate: '0', }, - contentGroups: ['descriptive'], - content: ['mpath'], + contentGroups: new Set(['descriptive']), + content: new Set(['mpath']), }, animateTransform: { - attrsGroups: [ - 'conditionalProcessing', - 'core', - 'animationEvent', - 'xlink', + attrsGroups: new Set([ + 'animationAddition', 'animationAttributeTarget', + 'animationEvent', 'animationTiming', 'animationValue', - 'animationAddition', - ], - attrs: ['externalResourcesRequired', 'type'], - contentGroups: ['descriptive'], + 'conditionalProcessing', + 'core', + 'xlink', + ]), + attrs: new Set(['externalResourcesRequired', 'type']), + contentGroups: new Set(['descriptive']), }, circle: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', 'presentation', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', - 'externalResourcesRequired', - 'transform', 'cx', 'cy', + 'externalResourcesRequired', 'r', - ], + 'style', + 'transform', + ]), defaults: { cx: '0', cy: '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', - 'style', + 'clipPathUnits', 'externalResourcesRequired', + 'style', '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: { name: 'sRGB', 'rendering-intent': 'auto', }, - 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: { x: '0', y: '0', }, - contentGroups: ['descriptive'], + contentGroups: new Set(['descriptive']), }, defs: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', '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', 'altGlyphDef', 'clipPath', 'color-profile', 'cursor', 'filter', - 'font', 'font-face', + 'font', 'foreignObject', 'image', 'marker', @@ -613,38 +630,38 @@ exports.elems = { 'switch', 'text', 'view', - ], + ]), }, desc: { - attrsGroups: ['core'], - attrs: ['class', 'style'], + attrsGroups: new Set(['core']), + attrs: new Set(['class', 'style']), }, ellipse: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', 'presentation', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', - 'externalResourcesRequired', - 'transform', 'cx', 'cy', + 'externalResourcesRequired', 'rx', 'ry', - ], + 'style', + 'transform', + ]), defaults: { cx: '0', cy: '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', 'style', // TODO: in - 'If no value is provided and this is the first filter primitive, @@ -652,28 +669,38 @@ exports.elems = { 'in', 'in2', '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: { operator: 'over', k1: '0', @@ -681,203 +708,203 @@ exports.elems = { k3: '0', k4: '0', }, - 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', - 'order', 'kernelMatrix', + 'order', + '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' - 'divisor', 'bias', + 'divisor', // 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 // is the <dy> value. If the <dy> value is not specified, it defaults to the same value as <dx>' 'kernelUnitLength', 'preserveAlpha', - ], + ]), defaults: { order: '3', bias: '0', edgeMode: 'duplicate', preserveAlpha: 'false', }, - content: ['animate', 'set'], + content: new Set(['animate', 'set']), }, feDiffuseLighting: { - attrsGroups: ['core', 'presentation', 'filterPrimitive'], - attrs: [ + attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']), + attrs: new Set([ 'class', - 'style', - 'in', - 'surfaceScale', 'diffuseConstant', + 'in', 'kernelUnitLength', - ], + 'style', + 'surfaceScale', + ]), defaults: { surfaceScale: '1', diffuseConstant: '1', }, - contentGroups: ['descriptive'], - content: [ + contentGroups: new Set(['descriptive']), + content: new Set([ // TODO: 'exactly one light source element, in any order' 'feDistantLight', 'fePointLight', '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: { scale: '0', xChannelSelector: 'A', yChannelSelector: 'A', }, - content: ['animate', 'set'], + content: new Set(['animate', 'set']), }, feDistantLight: { - attrsGroups: ['core'], - attrs: ['azimuth', 'elevation'], + attrsGroups: new Set(['core']), + attrs: new Set(['azimuth', 'elevation']), defaults: { azimuth: '0', elevation: '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', - 'preserveAspectRatio', 'href', + 'preserveAspectRatio', + '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: { operator: 'erode', radius: '0', }, - 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: { dx: '0', dy: '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: { x: '0', y: '0', z: '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: { surfaceScale: '1', specularConstant: '1', specularExponent: '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', 'pointsAtY', 'pointsAtZ', 'specularExponent', - 'limitingConeAngle', - ], + 'x', + 'y', + 'z', + ]), defaults: { x: '0', y: '0', @@ -887,24 +914,24 @@ exports.elems = { pointsAtZ: '0', specularExponent: '1', }, - 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: [ - 'class', - 'style', + attrsGroups: new Set(['core', 'presentation', 'filterPrimitive']), + attrs: new Set([ 'baseFrequency', + 'class', 'numOctaves', 'seed', 'stitchTiles', + 'style', 'type', - ], + ]), defaults: { baseFrequency: '0', numOctaves: '1', @@ -912,24 +939,24 @@ exports.elems = { stitchTiles: 'noStitch', type: 'turbulence', }, - 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', - 'primitiveUnits', + 'height', 'href', + 'primitiveUnits', + 'style', + 'width', + 'x', 'xlink:href', - ], + 'y', + ]), defaults: { primitiveUnits: 'userSpaceOnUse', x: '-10%', @@ -937,32 +964,32 @@ exports.elems = { width: '120%', height: '120%', }, - 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: { 'horiz-origin-x': '0', 'horiz-origin-y': '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', 'font-style', 'font-variant', @@ -996,7 +1023,7 @@ exports.elems = { 'strikethrough-thickness', 'overline-position', 'overline-thickness', - ], + ]), defaults: { 'font-style': 'all', 'font-variant': 'normal', @@ -1007,76 +1034,81 @@ exports.elems = { 'panose-1': '0 0 0 0 0 0 0 0 0 0', slope: '0', }, - 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: [ - 'core', + attrsGroups: new Set([ 'conditionalProcessing', + 'core', 'graphicalEvent', 'presentation', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', 'externalResourcesRequired', + 'height', + 'style', 'transform', + 'width', 'x', 'y', - 'width', - 'height', - ], + ]), defaults: { x: '0', y: '0', }, }, g: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', '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', 'altGlyphDef', 'clipPath', 'color-profile', 'cursor', 'filter', - 'font', 'font-face', + 'font', 'foreignObject', 'image', 'marker', @@ -1087,43 +1119,43 @@ exports.elems = { 'switch', 'text', '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', 'altGlyphDef', 'clipPath', 'color-profile', 'cursor', 'filter', - 'font', 'font-face', + 'font', 'foreignObject', 'image', 'marker', @@ -1134,35 +1166,35 @@ exports.elems = { 'switch', 'text', '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', 'altGlyphDef', 'clipPath', 'color-profile', 'cursor', 'filter', - 'font', 'font-face', + 'font', 'foreignObject', 'image', 'marker', @@ -1173,21 +1205,21 @@ exports.elems = { 'switch', 'text', 'view', - ], + ]), }, hatch: { - attrsGroups: ['core', 'presentation', 'xlink'], - attrs: [ + attrsGroups: new Set(['core', 'presentation', 'xlink']), + attrs: new Set([ 'class', - 'style', - 'x', - 'y', + 'hatchContentUnits', + 'hatchUnits', 'pitch', 'rotate', - 'hatchUnits', - 'hatchContentUnits', + 'style', 'transform', - ], + 'x', + 'y', + ]), defaults: { hatchUnits: 'objectBoundingBox', hatchContentUnits: 'userSpaceOnUse', @@ -1196,90 +1228,90 @@ exports.elems = { pitch: '0', rotate: '0', }, - 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: [ - 'core', + attrsGroups: new Set([ 'conditionalProcessing', + 'core', 'graphicalEvent', - 'xlink', 'presentation', - ], - attrs: [ + 'xlink', + ]), + attrs: new Set([ 'class', - 'style', 'externalResourcesRequired', + 'height', + 'href', 'preserveAspectRatio', + 'style', 'transform', - 'x', - 'y', 'width', - 'height', - 'href', + 'x', 'xlink:href', - ], + 'y', + ]), defaults: { x: '0', y: '0', preserveAspectRatio: 'xMidYMid meet', }, - contentGroups: ['animation', 'descriptive'], + contentGroups: new Set(['animation', 'descriptive']), }, line: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', 'presentation', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', 'externalResourcesRequired', + 'style', 'transform', 'x1', - 'y1', 'x2', + 'y1', 'y2', - ], + ]), defaults: { x1: '0', y1: '0', x2: '0', y2: '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', - 'style', 'externalResourcesRequired', - 'x1', - 'y1', - 'x2', - 'y2', - 'gradientUnits', 'gradientTransform', - 'spreadMethod', + 'gradientUnits', 'href', + 'spreadMethod', + 'style', + 'x1', + 'x2', 'xlink:href', - ], + 'y1', + 'y2', + ]), defaults: { x1: '0', y1: '0', @@ -1287,24 +1319,24 @@ exports.elems = { y2: '0', spreadMethod: 'pad', }, - 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', - 'preserveAspectRatio', - 'refX', - 'refY', + 'markerHeight', 'markerUnits', 'markerWidth', - 'markerHeight', 'orient', - ], + 'preserveAspectRatio', + 'refX', + 'refY', + 'style', + 'viewBox', + ]), defaults: { markerUnits: 'strokeWidth', refX: '0', @@ -1312,22 +1344,22 @@ exports.elems = { markerWidth: '3', markerHeight: '3', }, - contentGroups: [ + contentGroups: new Set([ 'animation', 'descriptive', + 'paintServer', 'shape', 'structural', - 'paintServer', - ], - content: [ + ]), + content: new Set([ 'a', 'altGlyphDef', 'clipPath', 'color-profile', 'cursor', 'filter', - 'font', 'font-face', + 'font', 'foreignObject', 'image', 'marker', @@ -1338,22 +1370,22 @@ exports.elems = { 'switch', 'text', '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', - 'maskUnits', 'maskContentUnits', - ], + 'maskUnits', + 'style', + 'width', + 'x', + 'y', + ]), defaults: { maskUnits: 'objectBoundingBox', maskContentUnits: 'userSpaceOnUse', @@ -1362,22 +1394,22 @@ exports.elems = { width: '120%', height: '120%', }, - contentGroups: [ + contentGroups: new Set([ 'animation', 'descriptive', + 'paintServer', 'shape', 'structural', - 'paintServer', - ], - content: [ + ]), + content: new Set([ 'a', 'altGlyphDef', 'clipPath', 'color-profile', 'cursor', 'filter', - 'font', 'font-face', + 'font', 'foreignObject', 'image', 'marker', @@ -1388,38 +1420,38 @@ exports.elems = { 'switch', 'text', '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', 'altGlyphDef', 'clipPath', 'color-profile', 'cursor', 'filter', - 'font', 'font-face', + 'font', 'foreignObject', 'image', 'marker', @@ -1430,48 +1462,53 @@ exports.elems = { 'switch', 'text', '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', 'core', 'graphicalEvent', 'presentation', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', - 'externalResourcesRequired', - 'transform', 'd', + 'externalResourcesRequired', 'pathLength', - ], - contentGroups: ['animation', 'descriptive'], + 'style', + 'transform', + ]), + 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: { patternUnits: 'objectBoundingBox', patternContentUnits: 'userSpaceOnUse', @@ -1481,22 +1518,22 @@ exports.elems = { height: '0', preserveAspectRatio: 'xMidYMid meet', }, - contentGroups: [ + contentGroups: new Set([ 'animation', 'descriptive', 'paintServer', 'shape', 'structural', - ], - content: [ + ]), + content: new Set([ 'a', 'altGlyphDef', 'clipPath', 'color-profile', 'cursor', 'filter', - 'font', 'font-face', + 'font', 'foreignObject', 'image', 'marker', @@ -1507,166 +1544,166 @@ exports.elems = { 'switch', 'text', 'view', - ], + ]), }, polygon: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', 'presentation', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', 'externalResourcesRequired', - 'transform', 'points', - ], - contentGroups: ['animation', 'descriptive'], + 'style', + 'transform', + ]), + contentGroups: new Set(['animation', 'descriptive']), }, polyline: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', 'presentation', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', 'externalResourcesRequired', - 'transform', 'points', - ], - contentGroups: ['animation', 'descriptive'], + 'style', + 'transform', + ]), + 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', - 'gradientUnits', 'gradientTransform', - 'spreadMethod', + 'gradientUnits', 'href', + 'r', + 'spreadMethod', + 'style', 'xlink:href', - ], + ]), defaults: { gradientUnits: 'objectBoundingBox', cx: '50%', cy: '50%', r: '50%', }, - 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', 'core', 'graphicalEvent', 'presentation', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', 'externalResourcesRequired', - 'transform', - 'x', - 'y', - 'width', 'height', 'rx', 'ry', - ], + 'style', + 'transform', + 'width', + 'x', + 'y', + ]), defaults: { x: '0', y: '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: [ - 'conditionalProcessing', - 'core', + attrsGroups: new Set([ 'animation', - 'xlink', 'animationAttributeTarget', 'animationTiming', - ], - attrs: ['externalResourcesRequired', 'to'], - contentGroups: ['descriptive'], + 'conditionalProcessing', + 'core', + 'xlink', + ]), + 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: { type: 'text/css', }, }, svg: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'documentEvent', 'graphicalEvent', '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: { x: '0', y: '0', @@ -1679,22 +1716,22 @@ exports.elems = { contentScriptType: 'application/ecmascript', contentStyleType: 'text/css', }, - contentGroups: [ + contentGroups: new Set([ 'animation', 'descriptive', + 'paintServer', 'shape', 'structural', - 'paintServer', - ], - content: [ + ]), + content: new Set([ 'a', 'altGlyphDef', 'clipPath', 'color-profile', 'cursor', 'filter', - 'font', 'font-face', + 'font', 'foreignObject', 'image', 'marker', @@ -1705,18 +1742,23 @@ exports.elems = { 'switch', 'text', 'view', - ], + ]), }, switch: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', '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', 'foreignObject', 'g', @@ -1725,39 +1767,39 @@ exports.elems = { 'switch', 'text', '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: { refX: '0', refY: '0', }, - contentGroups: [ + contentGroups: new Set([ 'animation', 'descriptive', + 'paintServer', 'shape', 'structural', - 'paintServer', - ], - content: [ + ]), + content: new Set([ 'a', 'altGlyphDef', 'clipPath', 'color-profile', 'cursor', 'filter', - 'font', 'font-face', + 'font', 'foreignObject', 'image', 'marker', @@ -1768,62 +1810,62 @@ exports.elems = { 'switch', 'text', 'view', - ], + ]), }, text: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', 'presentation', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', - 'externalResourcesRequired', - 'transform', - 'lengthAdjust', - 'x', - 'y', 'dx', 'dy', + 'externalResourcesRequired', + 'lengthAdjust', 'rotate', + 'style', 'textLength', - ], + 'transform', + 'x', + 'y', + ]), defaults: { x: '0', y: '0', lengthAdjust: 'spacing', }, - contentGroups: ['animation', 'descriptive', 'textContentChild'], - content: ['a'], + contentGroups: new Set(['animation', 'descriptive', 'textContentChild']), + content: new Set(['a']), }, textPath: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', 'presentation', 'xlink', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', + 'd', 'externalResourcesRequired', 'href', - 'xlink:href', - 'startOffset', 'method', 'spacing', - 'd', - ], + 'startOffset', + 'style', + 'xlink:href', + ]), defaults: { startOffset: '0', method: 'align', spacing: 'exact', }, - contentGroups: ['descriptive'], - content: [ + contentGroups: new Set(['descriptive']), + content: new Set([ 'a', 'altGlyph', 'animate', @@ -1831,51 +1873,51 @@ exports.elems = { 'set', 'tref', 'tspan', - ], + ]), }, title: { - attrsGroups: ['core'], - attrs: ['class', 'style'], + attrsGroups: new Set(['core']), + attrs: new Set(['class', 'style']), }, tref: { - attrsGroups: [ + attrsGroups: new Set([ 'conditionalProcessing', 'core', 'graphicalEvent', 'presentation', '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', 'core', 'graphicalEvent', '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', 'altGlyph', 'animate', @@ -1883,129 +1925,128 @@ exports.elems = { 'set', 'tref', 'tspan', - ], + ]), }, use: { - attrsGroups: [ - 'core', + attrsGroups: new Set([ 'conditionalProcessing', + 'core', 'graphicalEvent', 'presentation', 'xlink', - ], - attrs: [ + ]), + attrs: new Set([ 'class', - 'style', 'externalResourcesRequired', - 'transform', - 'x', - 'y', - 'width', 'height', 'href', + 'style', + 'transform', + 'width', + 'x', 'xlink:href', - ], + 'y', + ]), defaults: { x: '0', y: '0', }, - contentGroups: ['animation', 'descriptive'], + contentGroups: new Set(['animation', 'descriptive']), }, view: { - attrsGroups: ['core'], - attrs: [ + attrsGroups: new Set(['core']), + attrs: new Set([ 'externalResourcesRequired', - 'viewBox', 'preserveAspectRatio', - 'zoomAndPan', + 'viewBox', 'viewTarget', - ], - contentGroups: ['descriptive'], + 'zoomAndPan', + ]), + 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']), }, }; // 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/ImageReplacement/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/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#', +]); /** * @see https://www.w3.org/TR/SVG11/linking.html#processingIRI */ -exports.referencesProps = [ +exports.referencesProps = new Set([ 'clip-path', 'color-profile', 'fill', 'filter', - 'marker-start', - 'marker-mid', 'marker-end', + 'marker-mid', + 'marker-start', 'mask', 'stroke', 'style', -]; +]); /** * @see https://www.w3.org/TR/SVG11/propidx.html */ -exports.inheritableAttrs = [ +exports.inheritableAttrs = new Set([ 'clip-rule', - 'color', - 'color-interpolation', 'color-interpolation-filters', + 'color-interpolation', 'color-profile', 'color-rendering', + 'color', 'cursor', 'direction', 'dominant-baseline', - 'fill', 'fill-opacity', 'fill-rule', - 'font', + 'fill', 'font-family', - 'font-size', 'font-size-adjust', + 'font-size', 'font-stretch', 'font-style', 'font-variant', 'font-weight', + 'font', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'image-rendering', 'letter-spacing', - 'marker', 'marker-end', 'marker-mid', 'marker-start', + 'marker', 'paint-order', 'pointer-events', 'shape-rendering', - 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', @@ -2013,24 +2054,25 @@ exports.inheritableAttrs = [ 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', + 'stroke', 'text-anchor', 'text-rendering', 'transform', 'visibility', 'word-spacing', 'writing-mode', -]; +]); -exports.presentationNonInheritableGroupAttrs = [ - 'display', +exports.presentationNonInheritableGroupAttrs = new Set([ 'clip-path', + 'display', 'filter', 'mask', 'opacity', 'text-decoration', 'transform', 'unicode-bidi', -]; +]); /** * https://www.w3.org/TR/SVG11/single-page.html#types-ColorKeywords @@ -2229,63 +2271,69 @@ exports.colorsShortNames = { /** * @see https://www.w3.org/TR/SVG11/single-page.html#types-DataTypeColor */ -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', - 'enabled', - 'disabled', - 'read-only', - 'read-write', - 'placeholder-shown', - 'default', + 'blank', 'checked', + 'default', + 'disabled', + 'enabled', + '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', - 'target', - 'target-within', 'scope', - ], - resourceState: ['playing', 'paused'], - timeDimensional: ['current', 'past', 'future'], - treeStructural: [ - 'root', + 'target-within', + 'target', + 'visited', + ]), + resourceState: new Set(['playing', 'paused']), + timeDimensional: new Set(['current', 'past', 'future']), + treeStructural: new Set([ 'empty', - 'nth-child', - 'nth-last-child', 'first-child', - 'last-child', - 'only-child', - 'nth-of-type', - 'nth-last-of-type', 'first-of-type', + 'last-child', 'last-of-type', + 'nth-child', + 'nth-last-child', + 'nth-last-of-type', + 'nth-of-type', + 'only-child', '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']), }; diff --git a/node_modules/svgo/plugins/_path.js b/node_modules/svgo/plugins/_path.js index 60002d7a..7c3a28b9 100644 --- a/node_modules/svgo/plugins/_path.js +++ b/node_modules/svgo/plugins/_path.js @@ -15,13 +15,13 @@ var prevCtrlPoint; /** * Convert path string to JS representation. * - * @type {(path: XastElement) => Array<PathDataItem>} + * @type {(path: XastElement) => PathDataItem[]} */ const path2js = (path) => { // @ts-ignore legacy if (path.pathJS) return path.pathJS; /** - * @type {Array<PathDataItem>} + * @type {PathDataItem[]} */ const pathData = []; // JS representation of the path data const newPathData = parsePathData(path.attributes.d); @@ -41,12 +41,12 @@ exports.path2js = path2js; /** * Convert relative Path data to absolute. * - * @type {(data: Array<PathDataItem>) => Array<PathDataItem>} + * @type {(data: PathDataItem[]) => PathDataItem[]} * */ const convertRelativeToAbsolute = (data) => { /** - * @type {Array<PathDataItem>} + * @type {PathDataItem[]} */ const newData = []; let start = [0, 0]; @@ -179,7 +179,7 @@ const convertRelativeToAbsolute = (data) => { /** * Convert path array to string. * - * @type {(path: XastElement, data: Array<PathDataItem>, params: Js2PathParams) => void} + * @type {(path: XastElement, data: PathDataItem[], params: Js2PathParams) => void} */ exports.js2path = function (path, data, params) { // @ts-ignore legacy @@ -211,7 +211,7 @@ exports.js2path = function (path, data, params) { }; /** - * @type {(dest: Array<number>, source: Array<number>) => Array<number>} + * @type {(dest: number[], source: number[]) => number[]} */ function set(dest, source) { dest[0] = source[source.length - 2]; @@ -224,7 +224,7 @@ function set(dest, source) { * collision using Gilbert-Johnson-Keerthi distance algorithm * https://web.archive.org/web/20180822200027/http://entropyinteractive.com/2011/04/gjk-algorithm/ * - * @type {(path1: Array<PathDataItem>, path2: Array<PathDataItem>) => boolean} + * @type {(path1: PathDataItem[], path2: PathDataItem[]) => boolean} */ exports.intersects = function (path1, path2) { // Collect points of every subpath. @@ -267,10 +267,9 @@ exports.intersects = function (path1, path2) { var iterations = 1e4; // infinite loop protection, 10 000 iterations is more than enough // eslint-disable-next-line no-constant-condition 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.', ); return true; // true is the safe value that means “do nothing with paths” } @@ -285,7 +284,7 @@ exports.intersects = function (path1, path2) { }); /** - * @type {(a: Point, b: Point, direction: Array<number>) => Array<number>} + * @type {(a: Point, b: Point, direction: number[]) => number[]} */ function getSupport(a, b, direction) { return sub(supportPoint(a, direction), supportPoint(b, minus(direction))); @@ -295,7 +294,7 @@ exports.intersects = function (path1, path2) { // Thanks to knowledge of min/max x and y coordinates we can choose a quadrant to search in. // Since we're working on convex hull, the dot product is increasing until we find the farthest point. /** - * @type {(polygon: Point, direction: Array<number>) => Array<number>} + * @type {(polygon: Point, direction: number[]) => number[]} */ function supportPoint(polygon, direction) { var index = @@ -304,8 +303,8 @@ exports.intersects = function (path1, path2) { ? polygon.maxY : polygon.maxX : direction[0] < 0 - ? polygon.minX - : polygon.minY, + ? polygon.minX + : polygon.minY, max = -Infinity, value; while ((value = dot(polygon.list[index], direction)) > max) { @@ -317,7 +316,7 @@ exports.intersects = function (path1, path2) { }; /** - * @type {(simplex: Array<Array<number>>, direction: Array<number>) => boolean} + * @type {(simplex: number[][], direction: number[]) => boolean} */ function processSimplex(simplex, direction) { // we only need to handle to 1-simplex and 2-simplex @@ -374,28 +373,28 @@ function processSimplex(simplex, direction) { } /** - * @type {(v: Array<number>) => Array<number>} + * @type {(v: number[]) => number[]} */ function minus(v) { return [-v[0], -v[1]]; } /** - * @type {(v1: Array<number>, v2: Array<number>) => Array<number>} + * @type {(v1: number[], v2: number[]) => number[]} */ function sub(v1, v2) { return [v1[0] - v2[0], v1[1] - v2[1]]; } /** - * @type {(v1: Array<number>, v2: Array<number>) => number} + * @type {(v1: number[], v2: number[]) => number} */ function dot(v1, v2) { return v1[0] * v2[0] + v1[1] * v2[1]; } /** - * @type {(v1: Array<number>, v2: Array<number>) => Array<number>} + * @type {(v1: number[], v2: number[]) => number[]} */ function orth(v, from) { var o = [-v[1], v[0]]; @@ -404,7 +403,7 @@ function orth(v, from) { /** * @typedef {{ - * list: Array<Array<number>>, + * list: number[][], * minX: number, * minY: number, * maxX: number, @@ -414,7 +413,7 @@ function orth(v, from) { /** * @typedef {{ - * list: Array<Point>, + * list: Point[], * minX: number, * minY: number, * maxX: number, @@ -423,7 +422,7 @@ function orth(v, from) { */ /** - * @type {(pathData: Array<PathDataItem>) => Points} + * @type {(pathData: PathDataItem[]) => Points} */ function gatherPoints(pathData) { /** @@ -433,7 +432,7 @@ function gatherPoints(pathData) { // Writes data about the extreme points on each axle /** - * @type {(path: Point, point: Array<number>) => void} + * @type {(path: Point, point: number[]) => void} */ const addPoint = (path, point) => { if (!path.list.length || point[1] > path.list[path.maxY][1]) { @@ -671,7 +670,7 @@ function convexHull(points) { } /** - * @type {(o: Array<number>, a: Array<number>, b: Array<number>) => number} + * @type {(o: number[], a: number[], b: number[]) => number} */ function cross(o, a, b) { return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]); @@ -691,8 +690,8 @@ function cross(o, a, b) { * sweep_flag: number, * x2: number, * y2: number, - * recursive: Array<number> - * ) => Array<number>} + * recursive: number[] + * ) => number[]} */ const a2c = ( x1, @@ -704,14 +703,14 @@ const a2c = ( sweep_flag, x2, y2, - recursive + recursive, ) => { // for more information of where this Math came from visit: // https://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes const _120 = (Math.PI * 120) / 180; const rad = (Math.PI / 180) * (+angle || 0); /** - * @type {Array<number>} + * @type {number[]} */ let res = []; /** @@ -745,8 +744,8 @@ const a2c = ( (large_arc_flag == sweep_flag ? -1 : 1) * Math.sqrt( 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), + ), ); var cx = (k * rx * y) / ry + (x1 + x2) / 2; var cy = (k * -ry * x) / rx + (y1 + y2) / 2; diff --git a/node_modules/svgo/plugins/_transforms.js b/node_modules/svgo/plugins/_transforms.js index efc141c7..1ab6d648 100644 --- a/node_modules/svgo/plugins/_transforms.js +++ b/node_modules/svgo/plugins/_transforms.js @@ -1,176 +1,182 @@ 'use strict'; -const regTransformTypes = /matrix|translate|scale|rotate|skewX|skewY/; -const regTransformSplit = - /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/; -const regNumericValues = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g; +const { toFixed } = require('../lib/svgo/tools'); /** - * @typedef {{ name: string, data: Array<number> }} TransformItem + * @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 = + /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/; +const regNumericValues = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g; + /** * 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); } } } } - // return empty array if broken transform (no data) - return current == null || current.data.length == 0 ? [] : transforms; + + return currentTransform == null || currentTransform.data.length == 0 + ? [] + : transforms; }; /** * Multiply transforms into one. * - * @type {(transforms: Array<TransformItem>) => TransformItem} + * @param {TransformItem[]} transforms + * @returns {TransformItem} */ exports.transformsMultiply = (transforms) => { - // convert transforms objects to the matrices const matrixData = transforms.map((transform) => { if (transform.name === 'matrix') { return transform.data; } return transformToMatrix(transform); }); - // multiply all matrices into one + const matrixTransform = { name: 'matrix', data: matrixData.length > 0 ? matrixData.reduce(multiplyTransformMatrices) : [], }; + return matrixTransform; }; /** - * math utilities in radians. + * Math utilities in radians. */ const mth = { /** - * @type {(deg: number) => number} + * @param {number} deg + * @returns {number} */ rad: (deg) => { return (deg * Math.PI) / 180; }, /** - * @type {(rad: number) => number} + * @param {number} rad + * @returns {number} */ deg: (rad) => { return (rad * 180) / Math.PI; }, /** - * @type {(deg: number) => number} + * @param {number} deg + * @returns {number} */ cos: (deg) => { return Math.cos(mth.rad(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} */ sin: (deg) => { return Math.sin(mth.rad(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} */ tan: (deg) => { return Math.tan(mth.rad(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); }, }; /** - * @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 = []; // [..., ..., ..., ..., tx, ty] → translate(tx, ty) if (data[4] || data[5]) { @@ -180,6 +186,15 @@ exports.matrixToTransform = (transform, params) => { }); } + 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) if (!data[1] && data[2]) { transforms.push({ @@ -198,19 +213,34 @@ exports.matrixToTransform = (transform, params) => { // [sx·cos(a), sx·sin(a), sy·-sin(a), sy·cos(a), x, y] → rotate(a[, cx, cy])·(scale or skewX) or // [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 }); + } if (rowsSum && colsSum) transforms.push({ @@ -221,15 +251,15 @@ exports.matrixToTransform = (transform, params) => { // rotate(a, cx, cy) can consume translate() within optional arguments cx, cy (rotation point) if (rotate[0] && (data[4] || data[5])) { 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, + ); } // Too many transformations, return original matrix if it isn't just a scale/translate @@ -237,11 +267,12 @@ exports.matrixToTransform = (transform, params) => { return [transform]; } - if ((scaleBefore && (sx != 1 || sy != 1)) || !transforms.length) + if ((scaleBefore && (sx != 1 || sy != 1)) || !transforms.length) { transforms.push({ name: 'scale', data: sx == sy ? [sx] : [sx, sy], }); + } return transforms; }; @@ -249,7 +280,7 @@ exports.matrixToTransform = (transform, params) => { /** * Convert transform to the matrix data. * - * @type {(transform: TransformItem) => Array<number> } + * @type {(transform: TransformItem) => number[] } */ const transformToMatrix = (transform) => { if (transform.name === 'matrix') { @@ -302,9 +333,9 @@ const transformToMatrix = (transform) => { * * @type {( * cursor: [x: number, y: number], - * arc: Array<number>, - * transform: Array<number> - * ) => Array<number>} + * arc: number[], + * transform: number[] + * ) => number[]} */ exports.transformArc = (cursor, arc, transform) => { const x = arc[5] - cursor[0]; @@ -365,7 +396,7 @@ exports.transformArc = (cursor, arc, transform) => { /** * Multiply transformation matrices. * - * @type {(a: Array<number>, b: Array<number>) => Array<number>} + * @type {(a: number[], b: number[]) => number[]} */ const multiplyTransformMatrices = (a, b) => { return [ diff --git a/node_modules/svgo/plugins/addClassesToSVGElement.js b/node_modules/svgo/plugins/addClassesToSVGElement.js index 9a015c7b..1e773d85 100644 --- a/node_modules/svgo/plugins/addClassesToSVGElement.js +++ b/node_modules/svgo/plugins/addClassesToSVGElement.js @@ -67,7 +67,7 @@ exports.fn = (root, params) => { const classList = new Set( node.attributes.class == null ? null - : node.attributes.class.split(' ') + : node.attributes.class.split(' '), ); for (const className of classNames) { if (className != null) { diff --git a/node_modules/svgo/plugins/applyTransforms.js b/node_modules/svgo/plugins/applyTransforms.js index c0b848c9..ae492d54 100644 --- a/node_modules/svgo/plugins/applyTransforms.js +++ b/node_modules/svgo/plugins/applyTransforms.js @@ -19,8 +19,8 @@ const { const { referencesProps, attrsGroupsDefaults } = require('./_collections.js'); /** - * @typedef {Array<PathDataItem>} PathData - * @typedef {Array<number>} Matrix + * @typedef {PathDataItem[]} PathData + * @typedef {number[]} Matrix */ const regNumericValues = /[-+]?(\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g; @@ -57,7 +57,7 @@ const applyTransforms = (root, params) => { node.attributes.style != null || Object.entries(node.attributes).some( ([name, value]) => - referencesProps.includes(name) && includesUrlReference(value) + referencesProps.has(name) && includesUrlReference(value), ) ) { return; @@ -75,7 +75,7 @@ const applyTransforms = (root, params) => { } const matrix = transformsMultiply( - transform2js(node.attributes.transform) + transform2js(node.attributes.transform), ); const stroke = @@ -98,8 +98,8 @@ const applyTransforms = (root, params) => { const scale = Number( 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), ); if (stroke && stroke != 'none') { @@ -125,7 +125,7 @@ const applyTransforms = (root, params) => { ) .trim() .replace(regNumericValues, (num) => - removeLeadingZero(Number(num) * scale) + removeLeadingZero(Number(num) * scale), ); if (node.attributes['stroke-dashoffset'] != null) { @@ -134,7 +134,7 @@ const applyTransforms = (root, params) => { ] .trim() .replace(regNumericValues, (num) => - removeLeadingZero(Number(num) * scale) + removeLeadingZero(Number(num) * scale), ); } @@ -144,7 +144,7 @@ const applyTransforms = (root, params) => { ] .trim() .replace(regNumericValues, (num) => - removeLeadingZero(Number(num) * scale) + removeLeadingZero(Number(num) * scale), ); } } diff --git a/node_modules/svgo/plugins/cleanupAttrs.js b/node_modules/svgo/plugins/cleanupAttrs.js index af66193a..7b4c6b70 100644 --- a/node_modules/svgo/plugins/cleanupAttrs.js +++ b/node_modules/svgo/plugins/cleanupAttrs.js @@ -25,12 +25,12 @@ exports.fn = (root, params) => { // new line which requires a space instead of themself node.attributes[name] = node.attributes[name].replace( regNewlinesNeedSpace, - (match, p1, p2) => p1 + ' ' + p2 + (match, p1, p2) => p1 + ' ' + p2, ); // simple new line node.attributes[name] = node.attributes[name].replace( regNewlines, - '' + '', ); } if (trim) { @@ -39,7 +39,7 @@ exports.fn = (root, params) => { if (spaces) { node.attributes[name] = node.attributes[name].replace( regSpaces, - ' ' + ' ', ); } } diff --git a/node_modules/svgo/plugins/cleanupEnableBackground.js b/node_modules/svgo/plugins/cleanupEnableBackground.js index 1d2690d8..330cfb57 100644 --- a/node_modules/svgo/plugins/cleanupEnableBackground.js +++ b/node_modules/svgo/plugins/cleanupEnableBackground.js @@ -99,7 +99,7 @@ exports.fn = (root) => { attrValue, node.name, node.attributes.width, - node.attributes.height + node.attributes.height, ); if (attrCleaned) { @@ -114,13 +114,13 @@ exports.fn = (root) => { ) { const styleValue = csstree.generate( // @ts-ignore - enableBackgroundDeclaration.data.value + enableBackgroundDeclaration.data.value, ); const styleCleaned = cleanupValue( styleValue, node.name, node.attributes.width, - node.attributes.height + node.attributes.height, ); if (styleCleaned) { diff --git a/node_modules/svgo/plugins/cleanupIds.js b/node_modules/svgo/plugins/cleanupIds.js index 65b38d16..bfabcca5 100644 --- a/node_modules/svgo/plugins/cleanupIds.js +++ b/node_modules/svgo/plugins/cleanupIds.js @@ -69,7 +69,7 @@ const maxIdIndex = generateIdChars.length - 1; /** * Check if an ID starts with any one of a list of strings. * - * @type {(string: string, prefixes: Array<string>) => boolean} + * @type {(string: string, prefixes: string[]) => boolean} */ const hasStringPrefix = (string, prefixes) => { for (const prefix of prefixes) { @@ -109,7 +109,7 @@ const generateId = (currentId) => { /** * Get string from generated ID array. * - * @type {(arr: Array<number>) => string} + * @type {(arr: number[]) => string} */ const getIdString = (arr) => { return arr.map((i) => generateIdChars[i]).join(''); @@ -132,19 +132,19 @@ exports.fn = (_root, params) => { force = false, } = params; const preserveIds = new Set( - Array.isArray(preserve) ? preserve : preserve ? [preserve] : [] + Array.isArray(preserve) ? preserve : preserve ? [preserve] : [], ); const preserveIdPrefixes = Array.isArray(preservePrefixes) ? preservePrefixes : preservePrefixes - ? [preservePrefixes] - : []; + ? [preservePrefixes] + : []; /** * @type {Map<string, XastElement>} */ const nodeById = new Map(); /** - * @type {Map<string, Array<{element: XastElement, name: string }>>} + * @type {Map<string, {element: XastElement, name: string }[]>} */ const referencesById = new Map(); let deoptimized = false; @@ -236,13 +236,13 @@ exports.fn = (_root, params) => { // replace id in href and url() element.attributes[name] = value.replace( `#${encodeURI(id)}`, - `#${currentIdString}` + `#${currentIdString}`, ); } else { // replace id in begin attribute element.attributes[name] = value.replace( `${id}.`, - `${currentIdString}.` + `${currentIdString}.`, ); } } diff --git a/node_modules/svgo/plugins/cleanupListOfValues.js b/node_modules/svgo/plugins/cleanupListOfValues.js index 7150449e..618fd062 100644 --- a/node_modules/svgo/plugins/cleanupListOfValues.js +++ b/node_modules/svgo/plugins/cleanupListOfValues.js @@ -68,7 +68,7 @@ exports.fn = (_root, params) => { // convert absolute values to pixels if (convertToPx && units && units in absoluteLengths) { const pxNum = Number( - (absoluteLengths[units] * Number(match[1])).toFixed(floatPrecision) + (absoluteLengths[units] * Number(match[1])).toFixed(floatPrecision), ); if (pxNum.toString().length < match[0].length) { @@ -112,7 +112,7 @@ exports.fn = (_root, params) => { if (node.attributes['enable-background'] != null) { node.attributes['enable-background'] = roundValues( - node.attributes['enable-background'] + node.attributes['enable-background'], ); } @@ -122,7 +122,7 @@ exports.fn = (_root, params) => { if (node.attributes['stroke-dasharray'] != null) { node.attributes['stroke-dasharray'] = roundValues( - node.attributes['stroke-dasharray'] + node.attributes['stroke-dasharray'], ); } diff --git a/node_modules/svgo/plugins/cleanupNumericValues.js b/node_modules/svgo/plugins/cleanupNumericValues.js index 6a15dddd..9b782c3d 100644 --- a/node_modules/svgo/plugins/cleanupNumericValues.js +++ b/node_modules/svgo/plugins/cleanupNumericValues.js @@ -75,8 +75,8 @@ exports.fn = (_root, params) => { if (convertToPx && units !== '' && units in absoluteLengths) { const pxNum = Number( (absoluteLengths[units] * Number(match[1])).toFixed( - floatPrecision - ) + floatPrecision, + ), ); if (pxNum.toString().length < match[0].length) { num = pxNum; diff --git a/node_modules/svgo/plugins/collapseGroups.js b/node_modules/svgo/plugins/collapseGroups.js index 6042a01c..0534ad77 100644 --- a/node_modules/svgo/plugins/collapseGroups.js +++ b/node_modules/svgo/plugins/collapseGroups.js @@ -15,7 +15,7 @@ exports.description = 'collapses useless groups'; const hasAnimatedAttr = (node, name) => { if (node.type === 'element') { if ( - elemsGroups.animation.includes(node.name) && + elemsGroups.animation.has(node.name) && node.attributes.attributeName === name ) { return true; @@ -95,7 +95,7 @@ exports.fn = () => { } else if (firstChild.attributes[name] === 'inherit') { firstChild.attributes[name] = value; } else if ( - inheritableAttrs.includes(name) === false && + inheritableAttrs.has(name) === false && firstChild.attributes[name] !== value ) { return; @@ -112,7 +112,7 @@ exports.fn = () => { for (const child of node.children) { if ( child.type === 'element' && - elemsGroups.animation.includes(child.name) + elemsGroups.animation.has(child.name) ) { return; } diff --git a/node_modules/svgo/plugins/convertColors.js b/node_modules/svgo/plugins/convertColors.js index c9609d8b..d894283f 100644 --- a/node_modules/svgo/plugins/convertColors.js +++ b/node_modules/svgo/plugins/convertColors.js @@ -8,7 +8,7 @@ exports.description = 'converts colors: rgb() to #rrggbb and #rrggbb to #rgb'; const rNumber = '([+-]?(?:\\d*\\.\\d+|\\d+\\.?)%?)'; const rComma = '\\s*,\\s*'; const regRGB = new RegExp( - '^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$' + '^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$', ); const regHEX = /^#(([a-fA-F0-9])\2){3}$/; @@ -22,7 +22,7 @@ const regHEX = /^#(([a-fA-F0-9])\2){3}$/; * * @author Jed Schmidt * - * @type {(rgb: Array<number>) => string} + * @type {(rgb: number[]) => string} */ const convertRgbToHex = ([r, g, b]) => { // combine the octets into a 32-bit integer as: [1][r][g][b] @@ -76,7 +76,7 @@ exports.fn = (_root, params) => { element: { enter: (node) => { for (const [name, value] of Object.entries(node.attributes)) { - if (collections.colorsProps.includes(name)) { + if (collections.colorsProps.has(name)) { let val = value; // convert colors to currentColor diff --git a/node_modules/svgo/plugins/convertOneStopGradients.js b/node_modules/svgo/plugins/convertOneStopGradients.js index e5f4625d..1cf0d66b 100644 --- a/node_modules/svgo/plugins/convertOneStopGradients.js +++ b/node_modules/svgo/plugins/convertOneStopGradients.js @@ -104,7 +104,7 @@ exports.fn = (root) => { const selectorVal = `url(#${node.attributes.id})`; - const selector = colorsProps + const selector = [...colorsProps] .map((attr) => `[${attr}="${selectorVal}"]`) .join(','); const elements = querySelectorAll(root, selector); @@ -128,7 +128,7 @@ exports.fn = (root) => { const styledElements = querySelectorAll( root, - `[style*=${selectorVal}]` + `[style*=${selectorVal}]`, ); for (const element of styledElements) { if (element.type !== 'element') { @@ -137,7 +137,7 @@ exports.fn = (root) => { element.attributes.style = element.attributes.style.replace( selectorVal, - color || attrsGroupsDefaults.presentation['stop-color'] + color || attrsGroupsDefaults.presentation['stop-color'], ); } }, diff --git a/node_modules/svgo/plugins/convertPathData.js b/node_modules/svgo/plugins/convertPathData.js index 6229d9f7..de7b357f 100644 --- a/node_modules/svgo/plugins/convertPathData.js +++ b/node_modules/svgo/plugins/convertPathData.js @@ -9,31 +9,21 @@ const { visit } = require('../lib/xast.js'); const { pathElems } = require('./_collections.js'); const { path2js, js2path } = require('./_path.js'); const { applyTransforms } = require('./applyTransforms.js'); -const { cleanupOutData } = require('../lib/svgo/tools'); +const { cleanupOutData, toFixed } = require('../lib/svgo/tools'); exports.name = 'convertPathData'; exports.description = 'optimizes path data: writes in shorter form, applies transformations'; -/** - * @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; /** @@ -45,11 +35,13 @@ let arcTolerance; * tolerance: number, * }, * straightCurves: boolean, + * convertToQ: boolean, * lineShorthands: boolean, * convertToZ: boolean, * curveSmoothShorthands: boolean, * floatPrecision: number | false, * transformPrecision: number, + * smartArcRounding: boolean, * removeUseless: boolean, * collapseRepeated: boolean, * utilizeAbsolute: boolean, @@ -95,11 +87,13 @@ exports.fn = (root, params) => { tolerance: 0.5, // percentage of radius }, straightCurves = true, + convertToQ = true, lineShorthands = true, convertToZ = true, curveSmoothShorthands = true, floatPrecision = 3, transformPrecision = 5, + smartArcRounding = true, removeUseless = true, collapseRepeated = true, utilizeAbsolute = true, @@ -117,11 +111,13 @@ exports.fn = (root, params) => { applyTransformsStroked, makeArcs, straightCurves, + convertToQ, lineShorthands, convertToZ, curveSmoothShorthands, floatPrecision, transformPrecision, + smartArcRounding, removeUseless, collapseRepeated, utilizeAbsolute, @@ -139,7 +135,7 @@ exports.fn = (root, params) => { applyTransforms(root, { transformPrecision, applyTransformsStroked, - }) + }), ); } @@ -147,14 +143,15 @@ exports.fn = (root, params) => { return { element: { 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); precision = floatPrecision; error = precision !== false ? +Math.pow(0.1, precision).toFixed(precision) : 1e-2; - roundData = precision > 0 && precision < 20 ? strongRound : round; + roundData = + precision && precision > 0 && precision < 20 ? strongRound : round; if (makeArcs) { arcThreshold = makeArcs.threshold; arcTolerance = makeArcs.tolerance; @@ -387,14 +384,20 @@ const convertToRelative = (pathData) => { function filters( path, 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; let data = item.args; let next = path[index + 1]; @@ -406,9 +409,8 @@ function filters( if (command === 's') { sdata = [0, 0].concat(data); - // @ts-ignore - var pdata = prev.args, - n = pdata.length; + const pdata = prev.args; + const n = pdata.length; // (-x, -y) of the prev tangent point relative to the current point sdata[0] = pdata[n - 2] - pdata[n - 4]; @@ -455,16 +457,11 @@ function filters( nextLonghand; 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); // @ts-ignore arc.base = prev.base; @@ -472,7 +469,6 @@ function filters( arc.args[5] = arc.coords[0] - arc.base[0]; // @ts-ignore arc.args[6] = arc.coords[1] - arc.base[1]; - // @ts-ignore var prevData = prev.command == 'a' ? prev.sdata : prev.args; var prevAngle = findArcAngle(prevData, { center: [ @@ -489,14 +485,14 @@ function filters( // check if next curves are fitting the arc for ( var j = index; - (next = path[++j]) && ~'cs'.indexOf(next.command); + (next = path[++j]) && (next.command === 'c' || next.command === 's'); ) { var nextData = next.args; if (next.command == 's') { nextLonghand = makeLonghand( { command: 's', args: next.args.slice() }, - path[j - 1].args + path[j - 1].args, ); nextData = nextLonghand.args; nextLonghand.args = nextData.slice(0, 2); @@ -565,7 +561,6 @@ function filters( relSubpoint[0] += prevArc.args[5] - prev.args[prev.args.length - 2]; // @ts-ignore relSubpoint[1] += prevArc.args[6] - prev.args[prev.args.length - 1]; - // @ts-ignore prev.command = 'a'; // @ts-ignore prev.args = prevArc.args; @@ -579,11 +574,7 @@ function filters( item.sdata = sdata.slice(); // preserve curve data for future checks } else if (arcCurves.length - 1 - hasPrev > 0) { // 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); } if (!arc) return false; command = 'a'; @@ -637,6 +628,24 @@ function filters( } } + // 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 if (params.straightCurves) { if ( @@ -652,19 +661,60 @@ function filters( data = data.slice(-2); } else if ( command === 't' && - // @ts-ignore prev.command !== 'q' && - // @ts-ignore prev.command !== 't' ) { command = 'l'; 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'; 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 // l 50 0 → h 50 // l 0 50 → v 50 @@ -678,64 +728,36 @@ function filters( } } - // 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 // h 20 h 30 -> h 50 if ( params.collapseRepeated && hasMarkerMid === false && (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]; } // @ts-ignore prev.coords = item.coords; - // @ts-ignore path[index] = prev; return false; } // convert curves into smooth shorthands - // @ts-ignore if (params.curveSmoothShorthands && prev.command) { // curveto if (command === 'c') { // c + c → c + s 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 ) { command = 's'; data = data.slice(2); @@ -743,12 +765,9 @@ function filters( // s + c → s + 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 ) { command = 's'; data = data.slice(2); @@ -756,12 +775,10 @@ function filters( // [^cs] + c → [^cs] + 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 ) { command = 's'; data = data.slice(2); @@ -772,28 +789,36 @@ function filters( else if (command === 'q') { // q + q → q + t 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 ) { command = 't'; data = data.slice(2); } // 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); + } } } } @@ -813,26 +838,41 @@ function filters( return i === 0; }) ) { - // @ts-ignore path[index] = prev; return false; } // a 25,25 -30 0,1 0,0 if (command === 'a' && data[5] === 0 && data[6] === 0) { - // @ts-ignore path[index] = prev; 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; item.args = data; } else { // z resets coordinates relSubpoint[0] = pathBase[0]; relSubpoint[1] = pathBase[1]; - // @ts-ignore if (prev.command === 'Z' || prev.command === 'z') return false; } if ( @@ -846,6 +886,18 @@ function filters( ) return false; + 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; return true; }); @@ -870,7 +922,8 @@ function convertToMixed(path, params) { var command = item.command, data = item.args, - adata = data.slice(); + adata = data.slice(), + rdata = data.slice(); if ( command === 'm' || @@ -898,9 +951,10 @@ function convertToMixed(path, params) { } roundData(adata); + roundData(rdata); var absoluteDataStr = cleanupOutData(adata, params), - relativeDataStr = cleanupOutData(data, params); + relativeDataStr = cleanupOutData(rdata, params); // Convert to absolute coordinates if it's shorter or forceAbsolutePath is true. // v-20 -> V0 @@ -915,8 +969,9 @@ function convertToMixed(path, params) { prev.command.charCodeAt(0) > 96 && absoluteDataStr.length == relativeDataStr.length - 1 && (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)) )) ) { // @ts-ignore @@ -925,7 +980,6 @@ function convertToMixed(path, params) { } prev = item; - return true; }); @@ -992,16 +1046,6 @@ function getIntersection(coords) { } /** - * 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 * in path data keeping a specified number of decimals. * Smart rounds values like 2.3491 to 2.35 instead of 2.349. @@ -1042,7 +1086,6 @@ function round(data) { * * @type {(data: number[]) => boolean} */ - function isCurveStraightLine(data) { // Get line equation a·x + b·y + c = 0 coefficients a, b (c = 0) by start and end points. var i = data.length - 2, @@ -1062,11 +1105,25 @@ function isCurveStraightLine(data) { } /** + * 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. * * @type {(item: PathDataItem, data: number[]) => PathDataItem} */ - function makeLonghand(item, data) { switch (item.command) { case 's': @@ -1078,7 +1135,7 @@ function makeLonghand(item, data) { } item.args.unshift( data[data.length - 2] - data[data.length - 4], - data[data.length - 1] - data[data.length - 3] + data[data.length - 1] - data[data.length - 3], ); return item; } @@ -1088,9 +1145,19 @@ function makeLonghand(item, data) { * * @type {(point1: Point, point2: Point) => number} */ - 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]]; } /** @@ -1100,7 +1167,6 @@ function getDistance(point1, point2) { * * @type {(curve: number[], t: number) => Point} */ - function getCubicBezierPoint(curve, t) { var sqrT = t * t, cubT = sqrT * t, @@ -1118,7 +1184,6 @@ function getCubicBezierPoint(curve, t) { * * @type {(curve: number[]) => undefined | Circle} */ - function findCircle(curve) { var midPoint = getCubicBezierPoint(curve, 1 / 2), m1 = [midPoint[0] / 2, midPoint[1] / 2], @@ -1145,7 +1210,7 @@ function findCircle(curve) { return ( Math.abs( // @ts-ignore - getDistance(getCubicBezierPoint(curve, point), center) - radius + getDistance(getCubicBezierPoint(curve, point), center) - radius, ) <= tolerance ); }) @@ -1159,18 +1224,17 @@ function findCircle(curve) { * * @type {(curve: number[], circle: Circle) => boolean} */ - function isArc(curve, circle) { var tolerance = Math.min( arcThreshold * error, - (arcTolerance * circle.radius) / 100 + (arcTolerance * circle.radius) / 100, ); return [0, 1 / 4, 1 / 2, 3 / 4, 1].every(function (point) { return ( Math.abs( getDistance(getCubicBezierPoint(curve, point), circle.center) - - circle.radius + circle.radius, ) <= tolerance ); }); @@ -1181,7 +1245,6 @@ function isArc(curve, circle) { * * @type {(curve: number[], circle: Circle) => boolean} */ - function isArcPrev(curve, circle) { return isArc(curve, { center: [circle.center[0] + curve[4], circle.center[1] + curve[5]], @@ -1194,7 +1257,6 @@ function isArcPrev(curve, circle) { * @type {(curve: number[], relCircle: Circle) => number} */ - function findArcAngle(curve, relCircle) { var x1 = -relCircle.center[0], y1 = -relCircle.center[1], @@ -1202,7 +1264,7 @@ function findArcAngle(curve, relCircle) { y2 = curve[5] - relCircle.center[1]; 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)), ); } @@ -1211,7 +1273,6 @@ function findArcAngle(curve, relCircle) { * * @type {(params: InternalParams, pathData: PathDataItem[]) => string} */ - function data2Path(params, pathData) { return pathData.reduce(function (pathString, item) { var strData = ''; diff --git a/node_modules/svgo/plugins/convertShapeToPath.js b/node_modules/svgo/plugins/convertShapeToPath.js index 8a3b5a1f..f0ba0fd8 100644 --- a/node_modules/svgo/plugins/convertShapeToPath.js +++ b/node_modules/svgo/plugins/convertShapeToPath.js @@ -46,7 +46,7 @@ exports.fn = (root, params) => { // TODO: Calculate sizes from % and non-px units if possible. if (Number.isNaN(x - y + width - height)) return; /** - * @type {Array<PathDataItem>} + * @type {PathDataItem[]} */ const pathData = [ { command: 'M', args: [x, y] }, @@ -71,7 +71,7 @@ exports.fn = (root, params) => { const y2 = Number(node.attributes.y2 || '0'); if (Number.isNaN(x1 - y1 + x2 - y2)) return; /** - * @type {Array<PathDataItem>} + * @type {PathDataItem[]} */ const pathData = [ { command: 'M', args: [x1, y1] }, @@ -91,14 +91,14 @@ exports.fn = (root, params) => { node.attributes.points != null ) { const coords = (node.attributes.points.match(regNumber) || []).map( - Number + Number, ); if (coords.length < 4) { detachNodeFromParent(node, parentNode); return; } /** - * @type {Array<PathDataItem>} + * @type {PathDataItem[]} */ const pathData = []; for (let i = 0; i < coords.length; i += 2) { @@ -124,7 +124,7 @@ exports.fn = (root, params) => { return; } /** - * @type {Array<PathDataItem>} + * @type {PathDataItem[]} */ const pathData = [ { command: 'M', args: [cx, cy - r] }, @@ -149,7 +149,7 @@ exports.fn = (root, params) => { return; } /** - * @type {Array<PathDataItem>} + * @type {PathDataItem[]} */ const pathData = [ { command: 'M', args: [ecx, ecy - ry] }, diff --git a/node_modules/svgo/plugins/convertStyleToAttrs.js b/node_modules/svgo/plugins/convertStyleToAttrs.js index 662119e4..a9305fc4 100644 --- a/node_modules/svgo/plugins/convertStyleToAttrs.js +++ b/node_modules/svgo/plugins/convertStyleToAttrs.js @@ -31,7 +31,7 @@ const rValue = rSingleQuotes, rQuotes, rParenthesis, - '[^;]*?' + '[^;]*?', ) + '*?' + ')'; @@ -42,12 +42,12 @@ const rImportant = '(\\s*!important(?![-(\\w]))?'; // Final RegExp to parse CSS declarations. const regDeclarationBlock = new RegExp( rAttr + ':' + rValue + rImportant + rDeclEnd, - 'ig' + 'ig', ); // Comments expression. Honors escape sequences and strings. const regStripComments = new RegExp( g(rEscape, rSingleQuotes, rQuotes, '/\\*[^]*?\\*/'), - 'ig' + 'ig', ); /** @@ -87,13 +87,12 @@ exports.fn = (_root, params) => { return match[0] == '/' ? '' : 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)); ) { if (!keepImportant || !rule[3]) { styles.push([rule[1], rule[2]]); @@ -110,7 +109,7 @@ exports.fn = (_root, params) => { val = val.slice(1, -1); } - if (stylingProps.includes(prop)) { + if (stylingProps.has(prop)) { newAttributes[prop] = val; return false; diff --git a/node_modules/svgo/plugins/convertTransform.js b/node_modules/svgo/plugins/convertTransform.js index b69e17a3..6f399078 100644 --- a/node_modules/svgo/plugins/convertTransform.js +++ b/node_modules/svgo/plugins/convertTransform.js @@ -1,10 +1,12 @@ '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 { transform2js, transformsMultiply, @@ -59,15 +61,14 @@ exports.fn = (_root, params) => { return { element: { 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) { convertTransform(node, 'patternTransform', newParams); } @@ -94,13 +95,13 @@ exports.fn = (_root, params) => { */ /** - * @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 */ const convertTransform = (item, attrName, params) => { let data = transform2js(item.attributes[attrName]); @@ -134,7 +135,7 @@ const convertTransform = (item, attrName, params) => { * degPrecision - for rotate and skew. By default it's equal to (roughly) * transformPrecision - 2 or floatPrecision whichever is lower. Can be set in params. * - * @type {(data: Array<TransformItem>, params: TransformParams) => TransformParams} + * @type {(data: TransformItem[], params: TransformParams) => TransformParams} * * clone params so it don't affect other elements transformations. */ @@ -145,33 +146,33 @@ const definePrecision = (data, { ...newParams }) => { matrixData.push(...item.data.slice(0, 4)); } } - let significantDigits = newParams.transformPrecision; + let numberOfDigits = newParams.transformPrecision; // Limit transform precision with matrix one. Calculating with larger precision doesn't add any value. if (matrixData.length) { newParams.transformPrecision = Math.min( newParams.transformPrecision, 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 + ), ); } // No sense in angle precision more then number of significant digits in matrix. if (newParams.degPrecision == null) { newParams.degPrecision = Math.max( 0, - Math.min(newParams.floatPrecision, significantDigits - 2) + Math.min(newParams.floatPrecision, numberOfDigits - 2), ); } return newParams; }; /** - * @type {(data: Array<number>, params: TransformParams) => Array<number>} + * @type {(data: number[], params: TransformParams) => number[]} */ const degRound = (data, params) => { if ( @@ -185,7 +186,7 @@ const degRound = (data, params) => { } }; /** - * @type {(data: Array<number>, params: TransformParams) => Array<number>} + * @type {(data: number[], params: TransformParams) => number[]} */ const floatRound = (data, params) => { if (params.floatPrecision >= 1 && params.floatPrecision < 20) { @@ -196,7 +197,7 @@ const floatRound = (data, params) => { }; /** - * @type {(data: Array<number>, params: TransformParams) => Array<number>} + * @type {(data: number[], params: TransformParams) => number[]} */ const transformRound = (data, params) => { if (params.transformPrecision >= 1 && params.floatPrecision < 20) { @@ -219,11 +220,13 @@ const floatDigits = (n) => { /** * Convert transforms to the shorthand alternatives. * - * @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]; // convert matrix to the short aliases if (params.matrixToTransform && transform.name === 'matrix') { @@ -267,8 +270,7 @@ const convertToShorts = (transforms, params) => { // translate(cx cy) rotate(a) translate(-cx -cy) → rotate(a cx cy) if ( params.shortRotate && - transforms[i - 2] && - transforms[i - 2].name === 'translate' && + transforms[i - 2]?.name === 'translate' && transforms[i - 1].name === 'rotate' && transforms[i].name === 'translate' && transforms[i - 2].data[0] === -transforms[i].data[0] && @@ -294,7 +296,7 @@ const convertToShorts = (transforms, params) => { /** * Remove useless transforms. * - * @type {(transforms: Array<TransformItem>) => Array<TransformItem>} + * @type {(transforms: TransformItem[]) => TransformItem[]} */ const removeUseless = (transforms) => { return transforms.filter((transform) => { @@ -332,7 +334,9 @@ const removeUseless = (transforms) => { /** * Convert transforms JS representation to string. * - * @type {(transformJS: Array<TransformItem>, params: TransformParams) => string} + * @param {TransformItem[]} transformJS + * @param {TransformParams} params + * @returns {string} */ const js2transform = (transformJS, params) => { const transformString = transformJS @@ -379,7 +383,7 @@ const roundTransform = (transform, params) => { /** * Rounds numbers in array. * - * @type {(data: Array<number>) => Array<number>} + * @type {(data: number[]) => number[]} */ const round = (data) => { return data.map(Math.round); @@ -390,7 +394,9 @@ const round = (data) => { * in transforms keeping a specified number of decimals. * Smart rounds values like 2.349 to 2.35. * - * @type {(precision: number, data: Array<number>) => Array<number>} + * @param {number} precision + * @param {number[]} data + * @returns {number[]} */ const smartRound = (precision, data) => { for ( @@ -399,7 +405,7 @@ const smartRound = (precision, data) => { i--; ) { - if (Number(data[i].toFixed(precision)) !== data[i]) { + if (toFixed(data[i], precision) !== data[i]) { var rounded = +data[i].toFixed(precision - 1); data[i] = +Math.abs(rounded - data[i]).toFixed(precision + 1) >= tolerance @@ -407,5 +413,6 @@ const smartRound = (precision, data) => { : rounded; } } + return data; }; diff --git a/node_modules/svgo/plugins/inlineStyles.js b/node_modules/svgo/plugins/inlineStyles.js index 1cdcebe7..e09988de 100644 --- a/node_modules/svgo/plugins/inlineStyles.js +++ b/node_modules/svgo/plugins/inlineStyles.js @@ -7,7 +7,6 @@ const csstree = require('css-tree'); const { - // @ts-ignore internal api syntax: { specificity }, } = require('csso'); const { @@ -51,16 +50,16 @@ exports.fn = (root, params) => { } = params; /** - * @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[] + * }[]} */ let selectors = []; @@ -123,10 +122,10 @@ exports.fn = (root, params) => { node.prelude.children.forEach((childNode, item) => { if (childNode.type === 'Selector') { /** - * @type {Array<{ + * @type {{ * item: csstree.ListItem<csstree.CssNode>, * list: csstree.List<csstree.CssNode> - * }>} + * }[]} */ const pseudos = []; @@ -145,13 +144,13 @@ exports.fn = (root, params) => { list: grandchildList, }); } - } + }, ); const pseudoSelectors = csstree.generate({ type: 'Selector', children: new csstree.List().fromArray( - pseudos.map((pseudo) => pseudo.item.data) + pseudos.map((pseudo) => pseudo.item.data), ), }); @@ -187,7 +186,7 @@ exports.fn = (root, params) => { for (const selector of sortedSelectors) { // match selectors const selectorText = csstree.generate(selector.item.data); - /** @type {Array<XastElement>} */ + /** @type {XastElement[]} */ const matchedElements = []; try { for (const node of querySelectorAll(root, selectorText)) { @@ -216,7 +215,7 @@ exports.fn = (root, params) => { { context: 'declarationList', parseValue: false, - } + }, ); if (styleDeclarationList.type !== 'DeclarationList') { continue; @@ -247,9 +246,9 @@ exports.fn = (root, params) => { const property = ruleDeclaration.property; if ( - attrsGroups.presentation.includes(property) && + attrsGroups.presentation.has(property) && !selectors.some((selector) => - includesAttrSelector(selector.item, property) + includesAttrSelector(selector.item, property), ) ) { delete selectedEl.attributes[property]; @@ -261,7 +260,7 @@ exports.fn = (root, params) => { if (matchedItem == null) { styleDeclarationList.children.insert( ruleDeclarationItem, - firstListItem + firstListItem, ); } else if ( matchedItem.data.important !== true && @@ -269,7 +268,7 @@ exports.fn = (root, params) => { ) { styleDeclarationList.children.replace( matchedItem, - ruleDeclarationItem + ruleDeclarationItem, ); styleDeclarationItems.set(property, ruleDeclarationItem); } @@ -314,14 +313,19 @@ exports.fn = (root, params) => { const classList = new Set( selectedEl.attributes.class == null ? null - : selectedEl.attributes.class.split(' ') + : selectedEl.attributes.class.split(' '), ); for (const child of selector.node.children) { if ( child.type === 'ClassSelector' && !selectors.some((selector) => - includesAttrSelector(selector.item, 'class', child.name, true) + includesAttrSelector( + selector.item, + 'class', + child.name, + true, + ), ) ) { classList.delete(child.name); @@ -344,8 +348,8 @@ exports.fn = (root, params) => { selector.item, 'id', firstSubSelector.name, - true - ) + true, + ), ) ) { delete selectedEl.attributes.id; diff --git a/node_modules/svgo/plugins/mergePaths.js b/node_modules/svgo/plugins/mergePaths.js index 05c7ac70..fe982c13 100644 --- a/node_modules/svgo/plugins/mergePaths.js +++ b/node_modules/svgo/plugins/mergePaths.js @@ -1,6 +1,11 @@ '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'); const { path2js, js2path, intersects } = require('./_path.js'); @@ -25,73 +30,118 @@ exports.fn = (root, params) => { return { element: { enter: (node) => { - let prevChild = null; + if (node.children.length <= 1) { + return; + } + + /** @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]; - for (const child of node.children) { - // skip if previous element is not path or contains animation elements if ( - prevChild == null || prevChild.type !== 'element' || prevChild.name !== 'path' || prevChild.children.length !== 0 || prevChild.attributes.d == null ) { + if (prevPathData && prevChild.type === 'element') { + updatePreviousPath(prevChild, prevPathData); + } prevChild = child; continue; } - // skip if element is not path or contains animation elements if ( child.type !== 'element' || child.name !== 'path' || child.children.length !== 0 || child.attributes.d == null ) { + if (prevPathData) { + updatePreviousPath(prevChild, prevPathData); + } prevChild = child; continue; } - // preserve paths with markers const computedStyle = computeStyle(stylesheet, child); if ( computedStyle['marker-start'] || computedStyle['marker-mid'] || computedStyle['marker-end'] ) { + 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), + ); }, }, }; diff --git a/node_modules/svgo/plugins/minifyStyles.js b/node_modules/svgo/plugins/minifyStyles.js index 598b6db3..ade441b3 100644 --- a/node_modules/svgo/plugins/minifyStyles.js +++ b/node_modules/svgo/plugins/minifyStyles.js @@ -22,7 +22,7 @@ exports.fn = (_root, { usage, ...params }) => { /** @type {Map<XastElement, XastParent>} */ const styleElements = new Map(); - /** @type {Array<XastElement>} */ + /** @type {XastElement[]} */ const elementsWithStyleAttributes = []; /** @type {Set<string>} */ diff --git a/node_modules/svgo/plugins/moveElemsAttrsToGroup.js b/node_modules/svgo/plugins/moveElemsAttrsToGroup.js index 5f46e632..633f4439 100644 --- a/node_modules/svgo/plugins/moveElemsAttrsToGroup.js +++ b/node_modules/svgo/plugins/moveElemsAttrsToGroup.js @@ -64,7 +64,7 @@ exports.fn = (root) => { let everyChildIsPath = true; for (const child of node.children) { if (child.type === 'element') { - if (pathElems.includes(child.name) === false) { + if (!pathElems.has(child.name)) { everyChildIsPath = false; } if (initial) { @@ -72,7 +72,7 @@ exports.fn = (root) => { // collect all inheritable attributes from first child element for (const [name, value] of Object.entries(child.attributes)) { // consider only inheritable attributes - if (inheritableAttrs.includes(name)) { + if (inheritableAttrs.has(name)) { commonAttributes.set(name, value); } } diff --git a/node_modules/svgo/plugins/moveGroupAttrsToElems.js b/node_modules/svgo/plugins/moveGroupAttrsToElems.js index acadd894..450fb265 100644 --- a/node_modules/svgo/plugins/moveGroupAttrsToElems.js +++ b/node_modules/svgo/plugins/moveGroupAttrsToElems.js @@ -37,13 +37,13 @@ exports.fn = () => { node.attributes.transform != null && Object.entries(node.attributes).some( ([name, value]) => - referencesProps.includes(name) && includesUrlReference(value) + referencesProps.has(name) && includesUrlReference(value), ) === false && node.children.every( (child) => child.type === 'element' && pathElemsWithGroupsAndText.includes(child.name) && - child.attributes.id == null + child.attributes.id == null, ) ) { for (const child of node.children) { diff --git a/node_modules/svgo/plugins/plugins-types.d.ts b/node_modules/svgo/plugins/plugins-types.d.ts index 7cd56706..e94e7137 100644 --- a/node_modules/svgo/plugins/plugins-types.d.ts +++ b/node_modules/svgo/plugins/plugins-types.d.ts @@ -41,11 +41,13 @@ type DefaultPlugins = { tolerance: number; }; straightCurves?: boolean; + convertToQ?: boolean; lineShorthands?: boolean; convertToZ?: boolean; curveSmoothShorthands?: boolean; floatPrecision?: number | false; transformPrecision?: number; + smartArcRounding?: boolean; removeUseless?: boolean; collapseRepeated?: boolean; utilizeAbsolute?: boolean; @@ -255,7 +257,7 @@ export type BuiltinsWithOptionalParams = DefaultPlugins & { * * @default false */ - includeLegacy: boolean + includeLegacy: boolean; }; removeXMLNS: void; reusePaths: void; diff --git a/node_modules/svgo/plugins/prefixIds.js b/node_modules/svgo/plugins/prefixIds.js index 2f23971e..ec305c6b 100644 --- a/node_modules/svgo/plugins/prefixIds.js +++ b/node_modules/svgo/plugins/prefixIds.js @@ -173,15 +173,12 @@ exports.fn = (_root, params, info) => { node.name = prefixId(prefixGenerator, node.name); return; } - // @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; } } @@ -222,7 +219,7 @@ exports.fn = (_root, params, info) => { ) { const prefixed = prefixReference( prefixGenerator, - node.attributes[name] + node.attributes[name], ); if (prefixed != null) { node.attributes[name] = prefixed; @@ -244,7 +241,7 @@ exports.fn = (_root, params, info) => { return match; } return `url(${prefixed})`; - } + }, ); } } diff --git a/node_modules/svgo/plugins/removeComments.js b/node_modules/svgo/plugins/removeComments.js index 67f8efd1..46a32590 100644 --- a/node_modules/svgo/plugins/removeComments.js +++ b/node_modules/svgo/plugins/removeComments.js @@ -31,7 +31,7 @@ exports.fn = (_root, params) => { if (preservePatterns) { if (!Array.isArray(preservePatterns)) { throw Error( - `Expected array in removeComments preservePatterns parameter but received ${preservePatterns}` + `Expected array in removeComments preservePatterns parameter but received ${preservePatterns}`, ); } diff --git a/node_modules/svgo/plugins/removeEditorsNSData.js b/node_modules/svgo/plugins/removeEditorsNSData.js index e85bef89..852681bf 100644 --- a/node_modules/svgo/plugins/removeEditorsNSData.js +++ b/node_modules/svgo/plugins/removeEditorsNSData.js @@ -19,12 +19,12 @@ exports.description = 'removes editors namespaces, elements and attributes'; * @type {import('./plugins-types').Plugin<'removeEditorsNSData'>} */ exports.fn = (_root, params) => { - let namespaces = editorNamespaces; + let namespaces = [...editorNamespaces]; if (Array.isArray(params.additionalNamespaces)) { namespaces = [...editorNamespaces, ...params.additionalNamespaces]; } /** - * @type {Array<string>} + * @type {string[]} */ const prefixes = []; return { diff --git a/node_modules/svgo/plugins/removeElementsByAttr.js b/node_modules/svgo/plugins/removeElementsByAttr.js index b5fd91ba..9c9915f0 100644 --- a/node_modules/svgo/plugins/removeElementsByAttr.js +++ b/node_modules/svgo/plugins/removeElementsByAttr.js @@ -46,8 +46,8 @@ exports.fn = (root, params) => { params.class == null ? [] : Array.isArray(params.class) - ? params.class - : [params.class]; + ? params.class + : [params.class]; return { element: { enter: (node, parentNode) => { diff --git a/node_modules/svgo/plugins/removeEmptyAttrs.js b/node_modules/svgo/plugins/removeEmptyAttrs.js index 83f567c3..194d27b8 100644 --- a/node_modules/svgo/plugins/removeEmptyAttrs.js +++ b/node_modules/svgo/plugins/removeEmptyAttrs.js @@ -20,7 +20,7 @@ exports.fn = () => { if ( value === '' && // empty conditional processing attributes prevents elements from rendering - attrsGroups.conditionalProcessing.includes(name) === false + !attrsGroups.conditionalProcessing.has(name) ) { delete node.attributes[name]; } diff --git a/node_modules/svgo/plugins/removeEmptyContainers.js b/node_modules/svgo/plugins/removeEmptyContainers.js index bff3ab9c..03907344 100644 --- a/node_modules/svgo/plugins/removeEmptyContainers.js +++ b/node_modules/svgo/plugins/removeEmptyContainers.js @@ -28,7 +28,7 @@ exports.fn = () => { // remove only empty non-svg containers if ( node.name === 'svg' || - elemsGroups.container.includes(node.name) === false || + !elemsGroups.container.has(node.name) || node.children.length !== 0 ) { return; diff --git a/node_modules/svgo/plugins/removeHiddenElems.js b/node_modules/svgo/plugins/removeHiddenElems.js index 6ed2750b..75720a06 100644 --- a/node_modules/svgo/plugins/removeHiddenElems.js +++ b/node_modules/svgo/plugins/removeHiddenElems.js @@ -114,7 +114,7 @@ exports.fn = (root, params) => { element: { enter: (node, parentNode) => { // transparent non-rendering elements still apply where referenced - if (nonRendering.includes(node.name)) { + if (nonRendering.has(node.name)) { if (node.attributes.id == null) { detachNodeFromParent(node, parentNode); return visitSkip; diff --git a/node_modules/svgo/plugins/removeNonInheritableGroupAttrs.js b/node_modules/svgo/plugins/removeNonInheritableGroupAttrs.js index faa93dff..73e6bcda 100644 --- a/node_modules/svgo/plugins/removeNonInheritableGroupAttrs.js +++ b/node_modules/svgo/plugins/removeNonInheritableGroupAttrs.js @@ -24,9 +24,9 @@ exports.fn = () => { if (node.name === 'g') { for (const name of Object.keys(node.attributes)) { if ( - attrsGroups.presentation.includes(name) === true && - inheritableAttrs.includes(name) === false && - presentationNonInheritableGroupAttrs.includes(name) === false + attrsGroups.presentation.has(name) && + !inheritableAttrs.has(name) && + !presentationNonInheritableGroupAttrs.has(name) ) { delete node.attributes[name]; } diff --git a/node_modules/svgo/plugins/removeOffCanvasPaths.js b/node_modules/svgo/plugins/removeOffCanvasPaths.js index 8afd1e9a..60a69fb1 100644 --- a/node_modules/svgo/plugins/removeOffCanvasPaths.js +++ b/node_modules/svgo/plugins/removeOffCanvasPaths.js @@ -57,7 +57,7 @@ exports.fn = () => { // ensure that the dimensions are 4 values separated by space const m = /^(-?\d*\.?\d+) (-?\d*\.?\d+) (\d*\.?\d+) (\d*\.?\d+)$/.exec( - viewBox + viewBox, ); if (m == null) { return; @@ -116,7 +116,7 @@ exports.fn = () => { const { left, top, width, height } = viewBoxData; /** - * @type {Array<PathDataItem>} + * @type {PathDataItem[]} */ const viewBoxPathData = [ { command: 'M', args: [left, top] }, diff --git a/node_modules/svgo/plugins/removeUnknownsAndDefaults.js b/node_modules/svgo/plugins/removeUnknownsAndDefaults.js index 7462e8dc..e76e4e5f 100644 --- a/node_modules/svgo/plugins/removeUnknownsAndDefaults.js +++ b/node_modules/svgo/plugins/removeUnknownsAndDefaults.js @@ -129,7 +129,7 @@ exports.fn = (root, params) => { // remove unknown element's content if (unknownContent && parentNode.type === 'element') { const allowedChildren = allowedChildrenPerElement.get( - parentNode.name + parentNode.name, ); if (allowedChildren == null || allowedChildren.size === 0) { // remove unknown elements @@ -197,7 +197,7 @@ exports.fn = (root, params) => { if (uselessOverrides && node.attributes.id == null) { const style = computedParentStyle?.[name]; if ( - presentationNonInheritableGroupAttrs.includes(name) === false && + presentationNonInheritableGroupAttrs.has(name) === false && style != null && style.type === 'static' && style.value === value diff --git a/node_modules/svgo/plugins/removeUselessDefs.js b/node_modules/svgo/plugins/removeUselessDefs.js index 46461a98..5d19810e 100644 --- a/node_modules/svgo/plugins/removeUselessDefs.js +++ b/node_modules/svgo/plugins/removeUselessDefs.js @@ -23,7 +23,7 @@ exports.fn = () => { enter: (node, parentNode) => { if (node.name === 'defs') { /** - * @type {Array<XastElement>} + * @type {XastElement[]} */ const usefulNodes = []; collectUsefulNodes(node, usefulNodes); @@ -39,7 +39,7 @@ exports.fn = () => { } node.children = usefulNodes; } else if ( - elemsGroups.nonRendering.includes(node.name) && + elemsGroups.nonRendering.has(node.name) && node.attributes.id == null ) { detachNodeFromParent(node, parentNode); @@ -50,7 +50,7 @@ exports.fn = () => { }; /** - * @type {(node: XastElement, usefulNodes: Array<XastElement>) => void} + * @type {(node: XastElement, usefulNodes: XastElement[]) => void} */ const collectUsefulNodes = (node, usefulNodes) => { for (const child of node.children) { diff --git a/node_modules/svgo/plugins/removeUselessStrokeAndFill.js b/node_modules/svgo/plugins/removeUselessStrokeAndFill.js index f5f99855..95193fa6 100644 --- a/node_modules/svgo/plugins/removeUselessStrokeAndFill.js +++ b/node_modules/svgo/plugins/removeUselessStrokeAndFill.js @@ -46,7 +46,7 @@ exports.fn = (root, params) => { if (node.attributes.id != null) { return visitSkip; } - if (elemsGroups.shape.includes(node.name) == false) { + if (!elemsGroups.shape.has(node.name)) { return; } const computedStyle = computeStyle(stylesheet, node); diff --git a/node_modules/svgo/plugins/removeViewBox.js b/node_modules/svgo/plugins/removeViewBox.js index 5618d8bd..c0f23de2 100644 --- a/node_modules/svgo/plugins/removeViewBox.js +++ b/node_modules/svgo/plugins/removeViewBox.js @@ -3,7 +3,7 @@ exports.name = 'removeViewBox'; exports.description = 'removes viewBox attribute when possible'; -const viewBoxElems = ['svg', 'pattern', 'symbol']; +const viewBoxElems = new Set(['pattern', 'svg', 'symbol']); /** * Remove viewBox attr which coincides with a width/height box. @@ -24,7 +24,7 @@ exports.fn = () => { element: { enter: (node, parentNode) => { if ( - viewBoxElems.includes(node.name) && + viewBoxElems.has(node.name) && node.attributes.viewBox != null && node.attributes.width != null && node.attributes.height != null diff --git a/node_modules/svgo/plugins/removeXlink.js b/node_modules/svgo/plugins/removeXlink.js index d341b673..0411cc14 100644 --- a/node_modules/svgo/plugins/removeXlink.js +++ b/node_modules/svgo/plugins/removeXlink.js @@ -28,17 +28,17 @@ const SHOW_TO_TARGET = { * Elements that use xlink:href, but were deprecated in SVG 2 and therefore * don't support the SVG 2 href attribute. * - * @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', 'filter', 'font-face-uri', 'glyphRef', 'tref', -]; +]); /** * @param {XastElement} node @@ -136,7 +136,7 @@ exports.fn = (_, params) => { const attr = titleAttrs[i]; const value = node.attributes[attr]; const hasTitle = node.children.filter( - (child) => child.type === 'element' && child.name === 'title' + (child) => child.type === 'element' && child.name === 'title', ); if (hasTitle.length > 0) { @@ -170,7 +170,7 @@ exports.fn = (_, params) => { if ( hrefAttrs.length > 0 && - LEGACY_ELEMENTS.includes(node.name) && + LEGACY_ELEMENTS.has(node.name) && !includeLegacy ) { hrefAttrs diff --git a/node_modules/svgo/plugins/reusePaths.js b/node_modules/svgo/plugins/reusePaths.js index 89ff1f6b..8c2ddf0d 100644 --- a/node_modules/svgo/plugins/reusePaths.js +++ b/node_modules/svgo/plugins/reusePaths.js @@ -27,7 +27,7 @@ exports.fn = (root) => { const stylesheet = collectStylesheet(root); /** - * @type {Map<string, Array<XastElement>>} + * @type {Map<string, XastElement[]>} */ const paths = new Map(); @@ -123,7 +123,7 @@ exports.fn = (root) => { originalId == null || hrefs.has(originalId) || stylesheet.rules.some( - (rule) => rule.selector === `#${originalId}` + (rule) => rule.selector === `#${originalId}`, ) ) { reusablePath.attributes.id = 'reuse-' + index++; |
