From c06f7ee0a40255214c477e13d9b956a7e07c2900 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Sat, 14 Oct 2023 15:05:55 +0800 Subject: postcss,(plugins): nanocss, postcss-preset-env --- node_modules/svgo/plugins/_collections.js | 2168 ++++++++++++++++++++ node_modules/svgo/plugins/_path.js | 816 ++++++++ node_modules/svgo/plugins/_transforms.js | 379 ++++ .../svgo/plugins/addAttributesToSVGElement.js | 82 + .../svgo/plugins/addClassesToSVGElement.js | 82 + node_modules/svgo/plugins/applyTransforms.js | 379 ++++ node_modules/svgo/plugins/cleanupAttrs.js | 49 + .../svgo/plugins/cleanupEnableBackground.js | 73 + node_modules/svgo/plugins/cleanupIds.js | 287 +++ node_modules/svgo/plugins/cleanupListOfValues.js | 147 ++ node_modules/svgo/plugins/cleanupNumericValues.js | 106 + node_modules/svgo/plugins/collapseGroups.js | 134 ++ node_modules/svgo/plugins/convertColors.js | 144 ++ .../svgo/plugins/convertEllipseToCircle.js | 37 + node_modules/svgo/plugins/convertPathData.js | 1175 +++++++++++ node_modules/svgo/plugins/convertShapeToPath.js | 170 ++ node_modules/svgo/plugins/convertStyleToAttrs.js | 137 ++ node_modules/svgo/plugins/convertTransform.js | 417 ++++ node_modules/svgo/plugins/inlineStyles.js | 386 ++++ node_modules/svgo/plugins/mergePaths.js | 98 + node_modules/svgo/plugins/mergeStyles.js | 98 + node_modules/svgo/plugins/minifyStyles.js | 139 ++ node_modules/svgo/plugins/moveElemsAttrsToGroup.js | 128 ++ node_modules/svgo/plugins/moveGroupAttrsToElems.js | 64 + node_modules/svgo/plugins/plugins-types.ts | 251 +++ node_modules/svgo/plugins/prefixIds.js | 229 +++ node_modules/svgo/plugins/preset-default.js | 82 + .../svgo/plugins/removeAttributesBySelector.js | 97 + node_modules/svgo/plugins/removeAttrs.js | 153 ++ node_modules/svgo/plugins/removeComments.js | 29 + node_modules/svgo/plugins/removeDesc.js | 39 + node_modules/svgo/plugins/removeDimensions.js | 43 + node_modules/svgo/plugins/removeDoctype.js | 40 + node_modules/svgo/plugins/removeEditorsNSData.js | 64 + node_modules/svgo/plugins/removeElementsByAttr.js | 73 + node_modules/svgo/plugins/removeEmptyAttrs.js | 31 + node_modules/svgo/plugins/removeEmptyContainers.js | 56 + node_modules/svgo/plugins/removeEmptyText.js | 51 + node_modules/svgo/plugins/removeHiddenElems.js | 310 +++ node_modules/svgo/plugins/removeMetadata.js | 27 + .../svgo/plugins/removeNonInheritableGroupAttrs.js | 38 + node_modules/svgo/plugins/removeOffCanvasPaths.js | 136 ++ node_modules/svgo/plugins/removeRasterImages.js | 31 + node_modules/svgo/plugins/removeScriptElement.js | 27 + node_modules/svgo/plugins/removeStyleElement.js | 27 + node_modules/svgo/plugins/removeTitle.js | 27 + .../svgo/plugins/removeUnknownsAndDefaults.js | 208 ++ node_modules/svgo/plugins/removeUnusedNS.js | 59 + node_modules/svgo/plugins/removeUselessDefs.js | 65 + .../svgo/plugins/removeUselessStrokeAndFill.js | 138 ++ node_modules/svgo/plugins/removeViewBox.js | 49 + node_modules/svgo/plugins/removeXMLNS.js | 30 + node_modules/svgo/plugins/removeXMLProcInst.js | 28 + node_modules/svgo/plugins/reusePaths.js | 111 + node_modules/svgo/plugins/sortAttrs.js | 108 + node_modules/svgo/plugins/sortDefsChildren.js | 58 + 56 files changed, 10410 insertions(+) create mode 100644 node_modules/svgo/plugins/_collections.js create mode 100644 node_modules/svgo/plugins/_path.js create mode 100644 node_modules/svgo/plugins/_transforms.js create mode 100644 node_modules/svgo/plugins/addAttributesToSVGElement.js create mode 100644 node_modules/svgo/plugins/addClassesToSVGElement.js create mode 100644 node_modules/svgo/plugins/applyTransforms.js create mode 100644 node_modules/svgo/plugins/cleanupAttrs.js create mode 100644 node_modules/svgo/plugins/cleanupEnableBackground.js create mode 100644 node_modules/svgo/plugins/cleanupIds.js create mode 100644 node_modules/svgo/plugins/cleanupListOfValues.js create mode 100644 node_modules/svgo/plugins/cleanupNumericValues.js create mode 100644 node_modules/svgo/plugins/collapseGroups.js create mode 100644 node_modules/svgo/plugins/convertColors.js create mode 100644 node_modules/svgo/plugins/convertEllipseToCircle.js create mode 100644 node_modules/svgo/plugins/convertPathData.js create mode 100644 node_modules/svgo/plugins/convertShapeToPath.js create mode 100644 node_modules/svgo/plugins/convertStyleToAttrs.js create mode 100644 node_modules/svgo/plugins/convertTransform.js create mode 100644 node_modules/svgo/plugins/inlineStyles.js create mode 100644 node_modules/svgo/plugins/mergePaths.js create mode 100644 node_modules/svgo/plugins/mergeStyles.js create mode 100644 node_modules/svgo/plugins/minifyStyles.js create mode 100644 node_modules/svgo/plugins/moveElemsAttrsToGroup.js create mode 100644 node_modules/svgo/plugins/moveGroupAttrsToElems.js create mode 100644 node_modules/svgo/plugins/plugins-types.ts create mode 100644 node_modules/svgo/plugins/prefixIds.js create mode 100644 node_modules/svgo/plugins/preset-default.js create mode 100644 node_modules/svgo/plugins/removeAttributesBySelector.js create mode 100644 node_modules/svgo/plugins/removeAttrs.js create mode 100644 node_modules/svgo/plugins/removeComments.js create mode 100644 node_modules/svgo/plugins/removeDesc.js create mode 100644 node_modules/svgo/plugins/removeDimensions.js create mode 100644 node_modules/svgo/plugins/removeDoctype.js create mode 100644 node_modules/svgo/plugins/removeEditorsNSData.js create mode 100644 node_modules/svgo/plugins/removeElementsByAttr.js create mode 100644 node_modules/svgo/plugins/removeEmptyAttrs.js create mode 100644 node_modules/svgo/plugins/removeEmptyContainers.js create mode 100644 node_modules/svgo/plugins/removeEmptyText.js create mode 100644 node_modules/svgo/plugins/removeHiddenElems.js create mode 100644 node_modules/svgo/plugins/removeMetadata.js create mode 100644 node_modules/svgo/plugins/removeNonInheritableGroupAttrs.js create mode 100644 node_modules/svgo/plugins/removeOffCanvasPaths.js create mode 100644 node_modules/svgo/plugins/removeRasterImages.js create mode 100644 node_modules/svgo/plugins/removeScriptElement.js create mode 100644 node_modules/svgo/plugins/removeStyleElement.js create mode 100644 node_modules/svgo/plugins/removeTitle.js create mode 100644 node_modules/svgo/plugins/removeUnknownsAndDefaults.js create mode 100644 node_modules/svgo/plugins/removeUnusedNS.js create mode 100644 node_modules/svgo/plugins/removeUselessDefs.js create mode 100644 node_modules/svgo/plugins/removeUselessStrokeAndFill.js create mode 100644 node_modules/svgo/plugins/removeViewBox.js create mode 100644 node_modules/svgo/plugins/removeXMLNS.js create mode 100644 node_modules/svgo/plugins/removeXMLProcInst.js create mode 100644 node_modules/svgo/plugins/reusePaths.js create mode 100644 node_modules/svgo/plugins/sortAttrs.js create mode 100644 node_modules/svgo/plugins/sortDefsChildren.js (limited to 'node_modules/svgo/plugins') diff --git a/node_modules/svgo/plugins/_collections.js b/node_modules/svgo/plugins/_collections.js new file mode 100644 index 00000000..dfa8bff6 --- /dev/null +++ b/node_modules/svgo/plugins/_collections.js @@ -0,0 +1,2168 @@ +'use strict'; + +// https://www.w3.org/TR/SVG11/intro.html#Definitions + +/** + * @type {Record>} + */ +exports.elemsGroups = { + animation: [ + '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', + 'linearGradient', + 'radialGradient', + 'meshGradient', + 'pattern', + 'hatch', + ], + nonRendering: [ + 'linearGradient', + 'radialGradient', + 'pattern', + 'clipPath', + 'mask', + 'marker', + 'symbol', + 'filter', + 'solidColor', + ], + container: [ + 'a', + 'defs', + 'g', + 'marker', + 'mask', + 'missing-glyph', + 'pattern', + 'svg', + 'switch', + 'symbol', + 'foreignObject', + ], + textContent: [ + 'altGlyph', + 'altGlyphDef', + 'altGlyphItem', + 'glyph', + 'glyphRef', + 'textPath', + 'text', + 'tref', + 'tspan', + ], + textContentChild: ['altGlyph', 'textPath', 'tref', 'tspan'], + lightSource: [ + 'feDiffuseLighting', + 'feSpecularLighting', + 'feDistantLight', + 'fePointLight', + 'feSpotLight', + ], + filterPrimitive: [ + 'feBlend', + 'feColorMatrix', + 'feComponentTransfer', + 'feComposite', + 'feConvolveMatrix', + 'feDiffuseLighting', + 'feDisplacementMap', + 'feDropShadow', + 'feFlood', + 'feFuncA', + 'feFuncB', + 'feFuncG', + 'feFuncR', + 'feGaussianBlur', + 'feImage', + 'feMerge', + 'feMergeNode', + 'feMorphology', + 'feOffset', + 'feSpecularLighting', + 'feTile', + 'feTurbulence', + ], +}; + +exports.textElems = exports.elemsGroups.textContent.concat('title'); + +exports.pathElems = ['path', 'glyph', 'missing-glyph']; + +// https://www.w3.org/TR/SVG11/intro.html#Definitions +/** + * @type {Record>} + */ +exports.attrsGroups = { + animationAddition: ['additive', 'accumulate'], + animationAttributeTarget: ['attributeType', 'attributeName'], + animationEvent: ['onbegin', 'onend', 'onrepeat', 'onload'], + animationTiming: [ + 'begin', + 'dur', + 'end', + 'min', + 'max', + 'restart', + 'repeatCount', + 'repeatDur', + 'fill', + ], + animationValue: [ + 'calcMode', + 'values', + 'keyTimes', + 'keySplines', + 'from', + 'to', + 'by', + ], + conditionalProcessing: [ + 'requiredFeatures', + 'requiredExtensions', + 'systemLanguage', + ], + core: ['id', 'tabindex', 'xml:base', 'xml:lang', 'xml:space'], + graphicalEvent: [ + 'onfocusin', + 'onfocusout', + 'onactivate', + 'onclick', + 'onmousedown', + 'onmouseup', + 'onmouseover', + 'onmousemove', + 'onmouseout', + 'onload', + ], + presentation: [ + 'alignment-baseline', + 'baseline-shift', + 'clip', + 'clip-path', + 'clip-rule', + 'color', + 'color-interpolation', + 'color-interpolation-filters', + 'color-profile', + 'color-rendering', + 'cursor', + 'direction', + 'display', + 'dominant-baseline', + 'enable-background', + 'fill', + 'fill-opacity', + 'fill-rule', + 'filter', + 'flood-color', + 'flood-opacity', + 'font-family', + 'font-size', + 'font-size-adjust', + 'font-stretch', + 'font-style', + 'font-variant', + 'font-weight', + 'glyph-orientation-horizontal', + 'glyph-orientation-vertical', + 'image-rendering', + 'letter-spacing', + 'lighting-color', + 'marker-end', + 'marker-mid', + 'marker-start', + 'mask', + 'opacity', + 'overflow', + 'paint-order', + 'pointer-events', + 'shape-rendering', + 'stop-color', + 'stop-opacity', + 'stroke', + 'stroke-dasharray', + 'stroke-dashoffset', + 'stroke-linecap', + 'stroke-linejoin', + 'stroke-miterlimit', + 'stroke-opacity', + 'stroke-width', + 'text-anchor', + 'text-decoration', + 'text-overflow', + 'text-rendering', + 'transform', + 'transform-origin', + 'unicode-bidi', + 'vector-effect', + 'visibility', + 'word-spacing', + 'writing-mode', + ], + xlink: [ + 'xlink:href', + 'xlink:show', + 'xlink:actuate', + 'xlink:type', + 'xlink:role', + 'xlink:arcrole', + 'xlink:title', + ], + documentEvent: [ + 'onunload', + 'onabort', + 'onerror', + 'onresize', + 'onscroll', + 'onzoom', + ], + filterPrimitive: ['x', 'y', 'width', 'height', 'result'], + transferFunction: [ + 'type', + 'tableValues', + 'slope', + 'intercept', + 'amplitude', + 'exponent', + 'offset', + ], +}; + +/** + * @type {Record>} + */ +exports.attrsGroupsDefaults = { + core: { 'xml:space': 'default' }, + presentation: { + clip: 'auto', + 'clip-path': 'none', + 'clip-rule': 'nonzero', + mask: 'none', + opacity: '1', + 'stop-color': '#000', + 'stop-opacity': '1', + 'fill-opacity': '1', + 'fill-rule': 'nonzero', + fill: '#000', + stroke: 'none', + 'stroke-width': '1', + 'stroke-linecap': 'butt', + 'stroke-linejoin': 'miter', + 'stroke-miterlimit': '4', + 'stroke-dasharray': 'none', + 'stroke-dashoffset': '0', + 'stroke-opacity': '1', + 'paint-order': 'normal', + 'vector-effect': 'none', + display: 'inline', + visibility: 'visible', + 'marker-start': 'none', + 'marker-mid': 'none', + 'marker-end': 'none', + 'color-interpolation': 'sRGB', + 'color-interpolation-filters': 'linearRGB', + 'color-rendering': 'auto', + 'shape-rendering': 'auto', + 'text-rendering': 'auto', + 'image-rendering': 'auto', + 'font-style': 'normal', + 'font-variant': 'normal', + 'font-weight': 'normal', + 'font-stretch': 'normal', + 'font-size': 'medium', + 'font-size-adjust': 'none', + kerning: 'auto', + 'letter-spacing': 'normal', + 'word-spacing': 'normal', + 'text-decoration': 'none', + 'text-anchor': 'start', + 'text-overflow': 'clip', + 'writing-mode': 'lr-tb', + 'glyph-orientation-vertical': 'auto', + 'glyph-orientation-horizontal': '0deg', + direction: 'ltr', + 'unicode-bidi': 'normal', + 'dominant-baseline': 'auto', + 'alignment-baseline': 'baseline', + 'baseline-shift': 'baseline', + }, + transferFunction: { + slope: '1', + intercept: '0', + amplitude: '1', + exponent: '1', + offset: '0', + }, +}; + +// https://www.w3.org/TR/SVG11/eltindex.html +/** + * @type {Record, + * attrs?: Array, + * defaults?: Record, + * contentGroups?: Array, + * content?: Array, + * }>} + */ +exports.elems = { + a: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'target', + ], + defaults: { + target: '_self', + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer', + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view', + // not spec compliant + 'tspan', + ], + }, + altGlyph: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'dx', + 'dy', + 'glyphRef', + 'format', + 'rotate', + ], + }, + altGlyphDef: { + attrsGroups: ['core'], + content: ['glyphRef'], + }, + altGlyphItem: { + attrsGroups: ['core'], + content: ['glyphRef', 'altGlyphItem'], + }, + animate: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationAddition', + 'animationAttributeTarget', + 'animationEvent', + 'animationTiming', + 'animationValue', + 'presentation', + 'xlink', + ], + attrs: ['externalResourcesRequired'], + contentGroups: ['descriptive'], + }, + animateColor: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationEvent', + 'xlink', + 'animationAttributeTarget', + 'animationTiming', + 'animationValue', + 'animationAddition', + 'presentation', + ], + attrs: ['externalResourcesRequired'], + contentGroups: ['descriptive'], + }, + animateMotion: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationEvent', + 'xlink', + 'animationTiming', + 'animationValue', + 'animationAddition', + ], + attrs: [ + 'externalResourcesRequired', + 'path', + 'keyPoints', + 'rotate', + 'origin', + ], + defaults: { + rotate: '0', + }, + contentGroups: ['descriptive'], + content: ['mpath'], + }, + animateTransform: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animationEvent', + 'xlink', + 'animationAttributeTarget', + 'animationTiming', + 'animationValue', + 'animationAddition', + ], + attrs: ['externalResourcesRequired', 'type'], + contentGroups: ['descriptive'], + }, + circle: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'cx', + 'cy', + 'r', + ], + defaults: { + cx: '0', + cy: '0', + }, + contentGroups: ['animation', 'descriptive'], + }, + clipPath: { + attrsGroups: ['conditionalProcessing', 'core', 'presentation'], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'clipPathUnits', + ], + defaults: { + clipPathUnits: 'userSpaceOnUse', + }, + contentGroups: ['animation', 'descriptive', 'shape'], + content: ['text', 'use'], + }, + 'color-profile': { + attrsGroups: ['core', 'xlink'], + attrs: ['local', 'name', 'rendering-intent'], + defaults: { + name: 'sRGB', + 'rendering-intent': 'auto', + }, + contentGroups: ['descriptive'], + }, + cursor: { + attrsGroups: ['core', 'conditionalProcessing', 'xlink'], + attrs: ['externalResourcesRequired', 'x', 'y'], + defaults: { + x: '0', + y: '0', + }, + contentGroups: ['descriptive'], + }, + defs: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: ['class', 'style', 'externalResourcesRequired', 'transform'], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer', + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view', + ], + }, + desc: { + attrsGroups: ['core'], + attrs: ['class', 'style'], + }, + ellipse: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'cx', + 'cy', + 'rx', + 'ry', + ], + defaults: { + cx: '0', + cy: '0', + }, + contentGroups: ['animation', 'descriptive'], + }, + feBlend: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: [ + 'class', + 'style', + // TODO: in - 'If no value is provided and this is the first filter primitive, + // then this filter primitive will use SourceGraphic as its input' + 'in', + 'in2', + 'mode', + ], + defaults: { + mode: 'normal', + }, + content: ['animate', 'set'], + }, + feColorMatrix: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: ['class', 'style', 'in', 'type', 'values'], + defaults: { + type: 'matrix', + }, + content: ['animate', 'set'], + }, + feComponentTransfer: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: ['class', 'style', 'in'], + content: ['feFuncA', 'feFuncB', 'feFuncG', 'feFuncR'], + }, + feComposite: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: ['class', 'style', 'in', 'in2', 'operator', 'k1', 'k2', 'k3', 'k4'], + defaults: { + operator: 'over', + k1: '0', + k2: '0', + k3: '0', + k4: '0', + }, + content: ['animate', 'set'], + }, + feConvolveMatrix: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: [ + 'class', + 'style', + 'in', + 'order', + 'kernelMatrix', + // 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', + // TODO: targetX - 'By default, the convolution matrix is centered in X over each + // pixel of the input image (i.e., targetX = floor ( orderX / 2 ))' + 'targetX', + 'targetY', + 'edgeMode', + // TODO: kernelUnitLength - 'The first number is the value. The second number + // is the value. If the value is not specified, it defaults to the same value as ' + 'kernelUnitLength', + 'preserveAlpha', + ], + defaults: { + order: '3', + bias: '0', + edgeMode: 'duplicate', + preserveAlpha: 'false', + }, + content: ['animate', 'set'], + }, + feDiffuseLighting: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: [ + 'class', + 'style', + 'in', + 'surfaceScale', + 'diffuseConstant', + 'kernelUnitLength', + ], + defaults: { + surfaceScale: '1', + diffuseConstant: '1', + }, + contentGroups: ['descriptive'], + content: [ + // TODO: 'exactly one light source element, in any order' + 'feDistantLight', + 'fePointLight', + 'feSpotLight', + ], + }, + feDisplacementMap: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: [ + 'class', + 'style', + 'in', + 'in2', + 'scale', + 'xChannelSelector', + 'yChannelSelector', + ], + defaults: { + scale: '0', + xChannelSelector: 'A', + yChannelSelector: 'A', + }, + content: ['animate', 'set'], + }, + feDistantLight: { + attrsGroups: ['core'], + attrs: ['azimuth', 'elevation'], + defaults: { + azimuth: '0', + elevation: '0', + }, + content: ['animate', 'set'], + }, + feFlood: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: ['class', 'style'], + content: ['animate', 'animateColor', 'set'], + }, + feFuncA: { + attrsGroups: ['core', 'transferFunction'], + content: ['set', 'animate'], + }, + feFuncB: { + attrsGroups: ['core', 'transferFunction'], + content: ['set', 'animate'], + }, + feFuncG: { + attrsGroups: ['core', 'transferFunction'], + content: ['set', 'animate'], + }, + feFuncR: { + attrsGroups: ['core', 'transferFunction'], + content: ['set', 'animate'], + }, + feGaussianBlur: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: ['class', 'style', 'in', 'stdDeviation'], + defaults: { + stdDeviation: '0', + }, + content: ['set', 'animate'], + }, + feImage: { + attrsGroups: ['core', 'presentation', 'filterPrimitive', 'xlink'], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'preserveAspectRatio', + 'href', + 'xlink:href', + ], + defaults: { + preserveAspectRatio: 'xMidYMid meet', + }, + content: ['animate', 'animateTransform', 'set'], + }, + feMerge: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: ['class', 'style'], + content: ['feMergeNode'], + }, + feMergeNode: { + attrsGroups: ['core'], + attrs: ['in'], + content: ['animate', 'set'], + }, + feMorphology: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: ['class', 'style', 'in', 'operator', 'radius'], + defaults: { + operator: 'erode', + radius: '0', + }, + content: ['animate', 'set'], + }, + feOffset: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: ['class', 'style', 'in', 'dx', 'dy'], + defaults: { + dx: '0', + dy: '0', + }, + content: ['animate', 'set'], + }, + fePointLight: { + attrsGroups: ['core'], + attrs: ['x', 'y', 'z'], + defaults: { + x: '0', + y: '0', + z: '0', + }, + content: ['animate', 'set'], + }, + feSpecularLighting: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: [ + 'class', + 'style', + 'in', + 'surfaceScale', + 'specularConstant', + 'specularExponent', + 'kernelUnitLength', + ], + defaults: { + surfaceScale: '1', + specularConstant: '1', + specularExponent: '1', + }, + contentGroups: [ + 'descriptive', + // TODO: exactly one 'light source element' + 'lightSource', + ], + }, + feSpotLight: { + attrsGroups: ['core'], + attrs: [ + 'x', + 'y', + 'z', + 'pointsAtX', + 'pointsAtY', + 'pointsAtZ', + 'specularExponent', + 'limitingConeAngle', + ], + defaults: { + x: '0', + y: '0', + z: '0', + pointsAtX: '0', + pointsAtY: '0', + pointsAtZ: '0', + specularExponent: '1', + }, + content: ['animate', 'set'], + }, + feTile: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: ['class', 'style', 'in'], + content: ['animate', 'set'], + }, + feTurbulence: { + attrsGroups: ['core', 'presentation', 'filterPrimitive'], + attrs: [ + 'class', + 'style', + 'baseFrequency', + 'numOctaves', + 'seed', + 'stitchTiles', + 'type', + ], + defaults: { + baseFrequency: '0', + numOctaves: '1', + seed: '0', + stitchTiles: 'noStitch', + type: 'turbulence', + }, + content: ['animate', 'set'], + }, + filter: { + attrsGroups: ['core', 'presentation', 'xlink'], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'width', + 'height', + 'filterRes', + 'filterUnits', + 'primitiveUnits', + 'href', + 'xlink:href', + ], + defaults: { + primitiveUnits: 'userSpaceOnUse', + x: '-10%', + y: '-10%', + width: '120%', + height: '120%', + }, + contentGroups: ['descriptive', 'filterPrimitive'], + content: ['animate', 'set'], + }, + font: { + attrsGroups: ['core', 'presentation'], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'horiz-origin-x', + 'horiz-origin-y', + 'horiz-adv-x', + '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'], + }, + 'font-face': { + attrsGroups: ['core'], + attrs: [ + 'font-family', + 'font-style', + 'font-variant', + 'font-weight', + 'font-stretch', + 'font-size', + 'unicode-range', + 'units-per-em', + 'panose-1', + 'stemv', + 'stemh', + 'slope', + 'cap-height', + 'x-height', + 'accent-height', + 'ascent', + 'descent', + 'widths', + 'bbox', + 'ideographic', + 'alphabetic', + 'mathematical', + 'hanging', + 'v-ideographic', + 'v-alphabetic', + 'v-mathematical', + 'v-hanging', + 'underline-position', + 'underline-thickness', + 'strikethrough-position', + 'strikethrough-thickness', + 'overline-position', + 'overline-thickness', + ], + defaults: { + 'font-style': 'all', + 'font-variant': 'normal', + 'font-weight': 'all', + 'font-stretch': 'normal', + 'unicode-range': 'U+0-10FFFF', + 'units-per-em': '1000', + 'panose-1': '0 0 0 0 0 0 0 0 0 0', + slope: '0', + }, + contentGroups: ['descriptive'], + content: [ + // TODO: "at most one 'font-face-src' element" + 'font-face-src', + ], + }, + // TODO: empty content + 'font-face-format': { + attrsGroups: ['core'], + attrs: ['string'], + }, + 'font-face-name': { + attrsGroups: ['core'], + attrs: ['name'], + }, + 'font-face-src': { + attrsGroups: ['core'], + content: ['font-face-name', 'font-face-uri'], + }, + 'font-face-uri': { + attrsGroups: ['core', 'xlink'], + attrs: ['href', 'xlink:href'], + content: ['font-face-format'], + }, + foreignObject: { + attrsGroups: [ + 'core', + 'conditionalProcessing', + 'graphicalEvent', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x', + 'y', + 'width', + 'height', + ], + defaults: { + x: '0', + y: '0', + }, + }, + g: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: ['class', 'style', 'externalResourcesRequired', 'transform'], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer', + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view', + ], + }, + glyph: { + attrsGroups: ['core', 'presentation'], + attrs: [ + 'class', + 'style', + 'd', + 'horiz-adv-x', + 'vert-origin-x', + 'vert-origin-y', + 'vert-adv-y', + 'unicode', + 'glyph-name', + 'orientation', + 'arabic-form', + 'lang', + ], + defaults: { + 'arabic-form': 'initial', + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer', + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view', + ], + }, + glyphRef: { + attrsGroups: ['core', 'presentation'], + attrs: [ + 'class', + 'style', + 'd', + 'horiz-adv-x', + 'vert-origin-x', + 'vert-origin-y', + 'vert-adv-y', + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer', + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view', + ], + }, + hatch: { + attrsGroups: ['core', 'presentation', 'xlink'], + attrs: [ + 'class', + 'style', + 'x', + 'y', + 'pitch', + 'rotate', + 'hatchUnits', + 'hatchContentUnits', + 'transform', + ], + defaults: { + hatchUnits: 'objectBoundingBox', + hatchContentUnits: 'userSpaceOnUse', + x: '0', + y: '0', + pitch: '0', + rotate: '0', + }, + contentGroups: ['animation', 'descriptive'], + content: ['hatchPath'], + }, + hatchPath: { + attrsGroups: ['core', 'presentation', 'xlink'], + attrs: ['class', 'style', 'd', 'offset'], + defaults: { + offset: '0', + }, + contentGroups: ['animation', 'descriptive'], + }, + hkern: { + attrsGroups: ['core'], + attrs: ['u1', 'g1', 'u2', 'g2', 'k'], + }, + image: { + attrsGroups: [ + 'core', + 'conditionalProcessing', + 'graphicalEvent', + 'xlink', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'preserveAspectRatio', + 'transform', + 'x', + 'y', + 'width', + 'height', + 'href', + 'xlink:href', + ], + defaults: { + x: '0', + y: '0', + preserveAspectRatio: 'xMidYMid meet', + }, + contentGroups: ['animation', 'descriptive'], + }, + line: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x1', + 'y1', + 'x2', + 'y2', + ], + defaults: { + x1: '0', + y1: '0', + x2: '0', + y2: '0', + }, + contentGroups: ['animation', 'descriptive'], + }, + linearGradient: { + attrsGroups: ['core', 'presentation', 'xlink'], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x1', + 'y1', + 'x2', + 'y2', + 'gradientUnits', + 'gradientTransform', + 'spreadMethod', + 'href', + 'xlink:href', + ], + defaults: { + x1: '0', + y1: '0', + x2: '100%', + y2: '0', + spreadMethod: 'pad', + }, + contentGroups: ['descriptive'], + content: ['animate', 'animateTransform', 'set', 'stop'], + }, + marker: { + attrsGroups: ['core', 'presentation'], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'viewBox', + 'preserveAspectRatio', + 'refX', + 'refY', + 'markerUnits', + 'markerWidth', + 'markerHeight', + 'orient', + ], + defaults: { + markerUnits: 'strokeWidth', + refX: '0', + refY: '0', + markerWidth: '3', + markerHeight: '3', + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer', + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view', + ], + }, + mask: { + attrsGroups: ['conditionalProcessing', 'core', 'presentation'], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'width', + 'height', + 'mask-type', + 'maskUnits', + 'maskContentUnits', + ], + defaults: { + maskUnits: 'objectBoundingBox', + maskContentUnits: 'userSpaceOnUse', + x: '-10%', + y: '-10%', + width: '120%', + height: '120%', + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer', + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view', + ], + }, + metadata: { + attrsGroups: ['core'], + }, + 'missing-glyph': { + attrsGroups: ['core', 'presentation'], + attrs: [ + 'class', + 'style', + 'd', + 'horiz-adv-x', + 'vert-origin-x', + 'vert-origin-y', + 'vert-adv-y', + ], + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer', + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view', + ], + }, + mpath: { + attrsGroups: ['core', 'xlink'], + attrs: ['externalResourcesRequired', 'href', 'xlink:href'], + contentGroups: ['descriptive'], + }, + path: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'd', + 'pathLength', + ], + contentGroups: ['animation', 'descriptive'], + }, + pattern: { + attrsGroups: ['conditionalProcessing', 'core', 'presentation', 'xlink'], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'viewBox', + 'preserveAspectRatio', + 'x', + 'y', + 'width', + 'height', + 'patternUnits', + 'patternContentUnits', + 'patternTransform', + 'href', + 'xlink:href', + ], + defaults: { + patternUnits: 'objectBoundingBox', + patternContentUnits: 'userSpaceOnUse', + x: '0', + y: '0', + width: '0', + height: '0', + preserveAspectRatio: 'xMidYMid meet', + }, + contentGroups: [ + 'animation', + 'descriptive', + 'paintServer', + 'shape', + 'structural', + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view', + ], + }, + polygon: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'points', + ], + contentGroups: ['animation', 'descriptive'], + }, + polyline: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'points', + ], + contentGroups: ['animation', 'descriptive'], + }, + radialGradient: { + attrsGroups: ['core', 'presentation', 'xlink'], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'cx', + 'cy', + 'r', + 'fx', + 'fy', + 'fr', + 'gradientUnits', + 'gradientTransform', + 'spreadMethod', + 'href', + 'xlink:href', + ], + defaults: { + gradientUnits: 'objectBoundingBox', + cx: '50%', + cy: '50%', + r: '50%', + }, + contentGroups: ['descriptive'], + content: ['animate', 'animateTransform', 'set', 'stop'], + }, + meshGradient: { + attrsGroups: ['core', 'presentation', 'xlink'], + attrs: ['class', 'style', 'x', 'y', 'gradientUnits', 'transform'], + contentGroups: ['descriptive', 'paintServer', 'animation'], + content: ['meshRow'], + }, + meshRow: { + attrsGroups: ['core', 'presentation'], + attrs: ['class', 'style'], + contentGroups: ['descriptive'], + content: ['meshPatch'], + }, + meshPatch: { + attrsGroups: ['core', 'presentation'], + attrs: ['class', 'style'], + contentGroups: ['descriptive'], + content: ['stop'], + }, + rect: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x', + 'y', + 'width', + 'height', + 'rx', + 'ry', + ], + defaults: { + x: '0', + y: '0', + }, + contentGroups: ['animation', 'descriptive'], + }, + script: { + attrsGroups: ['core', 'xlink'], + attrs: ['externalResourcesRequired', 'type', 'href', 'xlink:href'], + }, + set: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'animation', + 'xlink', + 'animationAttributeTarget', + 'animationTiming', + ], + attrs: ['externalResourcesRequired', 'to'], + contentGroups: ['descriptive'], + }, + solidColor: { + attrsGroups: ['core', 'presentation'], + attrs: ['class', 'style'], + contentGroups: ['paintServer'], + }, + stop: { + attrsGroups: ['core', 'presentation'], + attrs: ['class', 'style', 'offset', 'path'], + content: ['animate', 'animateColor', 'set'], + }, + style: { + attrsGroups: ['core'], + attrs: ['type', 'media', 'title'], + defaults: { + type: 'text/css', + }, + }, + svg: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'documentEvent', + 'graphicalEvent', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'x', + 'y', + 'width', + 'height', + 'viewBox', + 'preserveAspectRatio', + 'zoomAndPan', + 'version', + 'baseProfile', + 'contentScriptType', + 'contentStyleType', + ], + defaults: { + x: '0', + y: '0', + width: '100%', + height: '100%', + preserveAspectRatio: 'xMidYMid meet', + zoomAndPan: 'magnify', + version: '1.1', + baseProfile: 'none', + contentScriptType: 'application/ecmascript', + contentStyleType: 'text/css', + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer', + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view', + ], + }, + switch: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: ['class', 'style', 'externalResourcesRequired', 'transform'], + contentGroups: ['animation', 'descriptive', 'shape'], + content: [ + 'a', + 'foreignObject', + 'g', + 'image', + 'svg', + 'switch', + 'text', + 'use', + ], + }, + symbol: { + attrsGroups: ['core', 'graphicalEvent', 'presentation'], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'preserveAspectRatio', + 'viewBox', + 'refX', + 'refY', + ], + defaults: { + refX: '0', + refY: '0', + }, + contentGroups: [ + 'animation', + 'descriptive', + 'shape', + 'structural', + 'paintServer', + ], + content: [ + 'a', + 'altGlyphDef', + 'clipPath', + 'color-profile', + 'cursor', + 'filter', + 'font', + 'font-face', + 'foreignObject', + 'image', + 'marker', + 'mask', + 'pattern', + 'script', + 'style', + 'switch', + 'text', + 'view', + ], + }, + text: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'lengthAdjust', + 'x', + 'y', + 'dx', + 'dy', + 'rotate', + 'textLength', + ], + defaults: { + x: '0', + y: '0', + lengthAdjust: 'spacing', + }, + contentGroups: ['animation', 'descriptive', 'textContentChild'], + content: ['a'], + }, + textPath: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'href', + 'xlink:href', + 'startOffset', + 'method', + 'spacing', + 'd', + ], + defaults: { + startOffset: '0', + method: 'align', + spacing: 'exact', + }, + contentGroups: ['descriptive'], + content: [ + 'a', + 'altGlyph', + 'animate', + 'animateColor', + 'set', + 'tref', + 'tspan', + ], + }, + title: { + attrsGroups: ['core'], + attrs: ['class', 'style'], + }, + tref: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + 'xlink', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'href', + 'xlink:href', + ], + contentGroups: ['descriptive'], + content: ['animate', 'animateColor', 'set'], + }, + tspan: { + attrsGroups: [ + 'conditionalProcessing', + 'core', + 'graphicalEvent', + 'presentation', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'x', + 'y', + 'dx', + 'dy', + 'rotate', + 'textLength', + 'lengthAdjust', + ], + contentGroups: ['descriptive'], + content: [ + 'a', + 'altGlyph', + 'animate', + 'animateColor', + 'set', + 'tref', + 'tspan', + ], + }, + use: { + attrsGroups: [ + 'core', + 'conditionalProcessing', + 'graphicalEvent', + 'presentation', + 'xlink', + ], + attrs: [ + 'class', + 'style', + 'externalResourcesRequired', + 'transform', + 'x', + 'y', + 'width', + 'height', + 'href', + 'xlink:href', + ], + defaults: { + x: '0', + y: '0', + }, + contentGroups: ['animation', 'descriptive'], + }, + view: { + attrsGroups: ['core'], + attrs: [ + 'externalResourcesRequired', + 'viewBox', + 'preserveAspectRatio', + 'zoomAndPan', + 'viewTarget', + ], + contentGroups: ['descriptive'], + }, + vkern: { + attrsGroups: ['core'], + attrs: ['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', + '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/XPath/1.0/', + 'http://schemas.microsoft.com/visio/2003/SVGExtensions/', + 'http://taptrix.com/vectorillustrator/svg_extensions', + '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.serif.com/', + 'http://www.vector.evaxdesign.sk', +]; + +// https://www.w3.org/TR/SVG11/linking.html#processingIRI +exports.referencesProps = [ + 'clip-path', + 'color-profile', + 'fill', + 'filter', + 'marker-start', + 'marker-mid', + 'marker-end', + 'mask', + 'stroke', + 'style', +]; + +// https://www.w3.org/TR/SVG11/propidx.html +exports.inheritableAttrs = [ + 'clip-rule', + 'color', + 'color-interpolation', + 'color-interpolation-filters', + 'color-profile', + 'color-rendering', + 'cursor', + 'direction', + 'dominant-baseline', + 'fill', + 'fill-opacity', + 'fill-rule', + 'font', + 'font-family', + 'font-size', + 'font-size-adjust', + 'font-stretch', + 'font-style', + 'font-variant', + 'font-weight', + 'glyph-orientation-horizontal', + 'glyph-orientation-vertical', + 'image-rendering', + 'letter-spacing', + 'marker', + 'marker-end', + 'marker-mid', + 'marker-start', + 'paint-order', + 'pointer-events', + 'shape-rendering', + 'stroke', + 'stroke-dasharray', + 'stroke-dashoffset', + 'stroke-linecap', + 'stroke-linejoin', + 'stroke-miterlimit', + 'stroke-opacity', + 'stroke-width', + 'text-anchor', + 'text-rendering', + 'transform', + 'visibility', + 'word-spacing', + 'writing-mode', +]; + +exports.presentationNonInheritableGroupAttrs = [ + 'display', + 'clip-path', + 'filter', + 'mask', + 'opacity', + 'text-decoration', + 'transform', + 'unicode-bidi', +]; + +/** + * https://www.w3.org/TR/SVG11/single-page.html#types-ColorKeywords + * + * @type {Record} + */ +exports.colorsNames = { + aliceblue: '#f0f8ff', + antiquewhite: '#faebd7', + aqua: '#0ff', + aquamarine: '#7fffd4', + azure: '#f0ffff', + beige: '#f5f5dc', + bisque: '#ffe4c4', + black: '#000', + blanchedalmond: '#ffebcd', + blue: '#00f', + blueviolet: '#8a2be2', + brown: '#a52a2a', + burlywood: '#deb887', + cadetblue: '#5f9ea0', + chartreuse: '#7fff00', + chocolate: '#d2691e', + coral: '#ff7f50', + cornflowerblue: '#6495ed', + cornsilk: '#fff8dc', + crimson: '#dc143c', + cyan: '#0ff', + darkblue: '#00008b', + darkcyan: '#008b8b', + darkgoldenrod: '#b8860b', + darkgray: '#a9a9a9', + darkgreen: '#006400', + darkgrey: '#a9a9a9', + darkkhaki: '#bdb76b', + darkmagenta: '#8b008b', + darkolivegreen: '#556b2f', + darkorange: '#ff8c00', + darkorchid: '#9932cc', + darkred: '#8b0000', + darksalmon: '#e9967a', + darkseagreen: '#8fbc8f', + darkslateblue: '#483d8b', + darkslategray: '#2f4f4f', + darkslategrey: '#2f4f4f', + darkturquoise: '#00ced1', + darkviolet: '#9400d3', + deeppink: '#ff1493', + deepskyblue: '#00bfff', + dimgray: '#696969', + dimgrey: '#696969', + dodgerblue: '#1e90ff', + firebrick: '#b22222', + floralwhite: '#fffaf0', + forestgreen: '#228b22', + fuchsia: '#f0f', + gainsboro: '#dcdcdc', + ghostwhite: '#f8f8ff', + gold: '#ffd700', + goldenrod: '#daa520', + gray: '#808080', + green: '#008000', + greenyellow: '#adff2f', + grey: '#808080', + honeydew: '#f0fff0', + hotpink: '#ff69b4', + indianred: '#cd5c5c', + indigo: '#4b0082', + ivory: '#fffff0', + khaki: '#f0e68c', + lavender: '#e6e6fa', + lavenderblush: '#fff0f5', + lawngreen: '#7cfc00', + lemonchiffon: '#fffacd', + lightblue: '#add8e6', + lightcoral: '#f08080', + lightcyan: '#e0ffff', + lightgoldenrodyellow: '#fafad2', + lightgray: '#d3d3d3', + lightgreen: '#90ee90', + lightgrey: '#d3d3d3', + lightpink: '#ffb6c1', + lightsalmon: '#ffa07a', + lightseagreen: '#20b2aa', + lightskyblue: '#87cefa', + lightslategray: '#789', + lightslategrey: '#789', + lightsteelblue: '#b0c4de', + lightyellow: '#ffffe0', + lime: '#0f0', + limegreen: '#32cd32', + linen: '#faf0e6', + magenta: '#f0f', + maroon: '#800000', + mediumaquamarine: '#66cdaa', + mediumblue: '#0000cd', + mediumorchid: '#ba55d3', + mediumpurple: '#9370db', + mediumseagreen: '#3cb371', + mediumslateblue: '#7b68ee', + mediumspringgreen: '#00fa9a', + mediumturquoise: '#48d1cc', + mediumvioletred: '#c71585', + midnightblue: '#191970', + mintcream: '#f5fffa', + mistyrose: '#ffe4e1', + moccasin: '#ffe4b5', + navajowhite: '#ffdead', + navy: '#000080', + oldlace: '#fdf5e6', + olive: '#808000', + olivedrab: '#6b8e23', + orange: '#ffa500', + orangered: '#ff4500', + orchid: '#da70d6', + palegoldenrod: '#eee8aa', + palegreen: '#98fb98', + paleturquoise: '#afeeee', + palevioletred: '#db7093', + papayawhip: '#ffefd5', + peachpuff: '#ffdab9', + peru: '#cd853f', + pink: '#ffc0cb', + plum: '#dda0dd', + powderblue: '#b0e0e6', + purple: '#800080', + rebeccapurple: '#639', + red: '#f00', + rosybrown: '#bc8f8f', + royalblue: '#4169e1', + saddlebrown: '#8b4513', + salmon: '#fa8072', + sandybrown: '#f4a460', + seagreen: '#2e8b57', + seashell: '#fff5ee', + sienna: '#a0522d', + silver: '#c0c0c0', + skyblue: '#87ceeb', + slateblue: '#6a5acd', + slategray: '#708090', + slategrey: '#708090', + snow: '#fffafa', + springgreen: '#00ff7f', + steelblue: '#4682b4', + tan: '#d2b48c', + teal: '#008080', + thistle: '#d8bfd8', + tomato: '#ff6347', + turquoise: '#40e0d0', + violet: '#ee82ee', + wheat: '#f5deb3', + white: '#fff', + whitesmoke: '#f5f5f5', + yellow: '#ff0', + yellowgreen: '#9acd32', +}; + +/** + * @type {Record} + */ +exports.colorsShortNames = { + '#f0ffff': 'azure', + '#f5f5dc': 'beige', + '#ffe4c4': 'bisque', + '#a52a2a': 'brown', + '#ff7f50': 'coral', + '#ffd700': 'gold', + '#808080': 'gray', + '#008000': 'green', + '#4b0082': 'indigo', + '#fffff0': 'ivory', + '#f0e68c': 'khaki', + '#faf0e6': 'linen', + '#800000': 'maroon', + '#000080': 'navy', + '#808000': 'olive', + '#ffa500': 'orange', + '#da70d6': 'orchid', + '#cd853f': 'peru', + '#ffc0cb': 'pink', + '#dda0dd': 'plum', + '#800080': 'purple', + '#f00': 'red', + '#ff0000': 'red', + '#fa8072': 'salmon', + '#a0522d': 'sienna', + '#c0c0c0': 'silver', + '#fffafa': 'snow', + '#d2b48c': 'tan', + '#008080': 'teal', + '#ff6347': 'tomato', + '#ee82ee': 'violet', + '#f5deb3': 'wheat', +}; + +// https://www.w3.org/TR/SVG11/single-page.html#types-DataTypeColor +exports.colorsProps = [ + 'color', + 'fill', + 'stroke', + 'stop-color', + 'flood-color', + 'lighting-color', +]; diff --git a/node_modules/svgo/plugins/_path.js b/node_modules/svgo/plugins/_path.js new file mode 100644 index 00000000..60002d7a --- /dev/null +++ b/node_modules/svgo/plugins/_path.js @@ -0,0 +1,816 @@ +'use strict'; + +/** + * @typedef {import('../lib/types').XastElement} XastElement + * @typedef {import('../lib/types').PathDataItem} PathDataItem + */ + +const { parsePathData, stringifyPathData } = require('../lib/path.js'); + +/** + * @type {[number, number]} + */ +var prevCtrlPoint; + +/** + * Convert path string to JS representation. + * + * @type {(path: XastElement) => Array} + */ +const path2js = (path) => { + // @ts-ignore legacy + if (path.pathJS) return path.pathJS; + /** + * @type {Array} + */ + const pathData = []; // JS representation of the path data + const newPathData = parsePathData(path.attributes.d); + for (const { command, args } of newPathData) { + pathData.push({ command, args }); + } + // First moveto is actually absolute. Subsequent coordinates were separated above. + if (pathData.length && pathData[0].command == 'm') { + pathData[0].command = 'M'; + } + // @ts-ignore legacy + path.pathJS = pathData; + return pathData; +}; +exports.path2js = path2js; + +/** + * Convert relative Path data to absolute. + * + * @type {(data: Array) => Array} + * + */ +const convertRelativeToAbsolute = (data) => { + /** + * @type {Array} + */ + const newData = []; + let start = [0, 0]; + let cursor = [0, 0]; + + for (let { command, args } of data) { + args = args.slice(); + + // moveto (x y) + if (command === 'm') { + args[0] += cursor[0]; + args[1] += cursor[1]; + command = 'M'; + } + if (command === 'M') { + cursor[0] = args[0]; + cursor[1] = args[1]; + start[0] = cursor[0]; + start[1] = cursor[1]; + } + + // horizontal lineto (x) + if (command === 'h') { + args[0] += cursor[0]; + command = 'H'; + } + if (command === 'H') { + cursor[0] = args[0]; + } + + // vertical lineto (y) + if (command === 'v') { + args[0] += cursor[1]; + command = 'V'; + } + if (command === 'V') { + cursor[1] = args[0]; + } + + // lineto (x y) + if (command === 'l') { + args[0] += cursor[0]; + args[1] += cursor[1]; + command = 'L'; + } + if (command === 'L') { + cursor[0] = args[0]; + cursor[1] = args[1]; + } + + // curveto (x1 y1 x2 y2 x y) + if (command === 'c') { + args[0] += cursor[0]; + args[1] += cursor[1]; + args[2] += cursor[0]; + args[3] += cursor[1]; + args[4] += cursor[0]; + args[5] += cursor[1]; + command = 'C'; + } + if (command === 'C') { + cursor[0] = args[4]; + cursor[1] = args[5]; + } + + // smooth curveto (x2 y2 x y) + if (command === 's') { + args[0] += cursor[0]; + args[1] += cursor[1]; + args[2] += cursor[0]; + args[3] += cursor[1]; + command = 'S'; + } + if (command === 'S') { + cursor[0] = args[2]; + cursor[1] = args[3]; + } + + // quadratic Bézier curveto (x1 y1 x y) + if (command === 'q') { + args[0] += cursor[0]; + args[1] += cursor[1]; + args[2] += cursor[0]; + args[3] += cursor[1]; + command = 'Q'; + } + if (command === 'Q') { + cursor[0] = args[2]; + cursor[1] = args[3]; + } + + // smooth quadratic Bézier curveto (x y) + if (command === 't') { + args[0] += cursor[0]; + args[1] += cursor[1]; + command = 'T'; + } + if (command === 'T') { + cursor[0] = args[0]; + cursor[1] = args[1]; + } + + // elliptical arc (rx ry x-axis-rotation large-arc-flag sweep-flag x y) + if (command === 'a') { + args[5] += cursor[0]; + args[6] += cursor[1]; + command = 'A'; + } + if (command === 'A') { + cursor[0] = args[5]; + cursor[1] = args[6]; + } + + // closepath + if (command === 'z' || command === 'Z') { + cursor[0] = start[0]; + cursor[1] = start[1]; + command = 'z'; + } + + newData.push({ command, args }); + } + return newData; +}; + +/** + * @typedef {{ floatPrecision?: number, noSpaceAfterFlags?: boolean }} Js2PathParams + */ + +/** + * Convert path array to string. + * + * @type {(path: XastElement, data: Array, params: Js2PathParams) => void} + */ +exports.js2path = function (path, data, params) { + // @ts-ignore legacy + path.pathJS = data; + + const pathData = []; + for (const item of data) { + // remove moveto commands which are followed by moveto commands + if ( + pathData.length !== 0 && + (item.command === 'M' || item.command === 'm') + ) { + const last = pathData[pathData.length - 1]; + if (last.command === 'M' || last.command === 'm') { + pathData.pop(); + } + } + pathData.push({ + command: item.command, + args: item.args, + }); + } + + path.attributes.d = stringifyPathData({ + pathData, + precision: params.floatPrecision, + disableSpaceAfterFlags: params.noSpaceAfterFlags, + }); +}; + +/** + * @type {(dest: Array, source: Array) => Array} + */ +function set(dest, source) { + dest[0] = source[source.length - 2]; + dest[1] = source[source.length - 1]; + return dest; +} + +/** + * Checks if two paths have an intersection by checking convex hulls + * collision using Gilbert-Johnson-Keerthi distance algorithm + * https://web.archive.org/web/20180822200027/http://entropyinteractive.com/2011/04/gjk-algorithm/ + * + * @type {(path1: Array, path2: Array) => boolean} + */ +exports.intersects = function (path1, path2) { + // Collect points of every subpath. + const points1 = gatherPoints(convertRelativeToAbsolute(path1)); + const points2 = gatherPoints(convertRelativeToAbsolute(path2)); + + // Axis-aligned bounding box check. + if ( + points1.maxX <= points2.minX || + points2.maxX <= points1.minX || + points1.maxY <= points2.minY || + points2.maxY <= points1.minY || + points1.list.every((set1) => { + return points2.list.every((set2) => { + return ( + set1.list[set1.maxX][0] <= set2.list[set2.minX][0] || + set2.list[set2.maxX][0] <= set1.list[set1.minX][0] || + set1.list[set1.maxY][1] <= set2.list[set2.minY][1] || + set2.list[set2.maxY][1] <= set1.list[set1.minY][1] + ); + }); + }) + ) + return false; + + // Get a convex hull from points of each subpath. Has the most complexity O(n·log n). + const hullNest1 = points1.list.map(convexHull); + const hullNest2 = points2.list.map(convexHull); + + // Check intersection of every subpath of the first path with every subpath of the second. + return hullNest1.some(function (hull1) { + if (hull1.list.length < 3) return false; + + return hullNest2.some(function (hull2) { + if (hull2.list.length < 3) return false; + + var simplex = [getSupport(hull1, hull2, [1, 0])], // create the initial simplex + direction = minus(simplex[0]); // set the direction to point towards the origin + + 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.' + ); + return true; // true is the safe value that means “do nothing with paths” + } + // add a new point + simplex.push(getSupport(hull1, hull2, direction)); + // see if the new point was on the correct side of the origin + if (dot(direction, simplex[simplex.length - 1]) <= 0) return false; + // process the simplex + if (processSimplex(simplex, direction)) return true; + } + }); + }); + + /** + * @type {(a: Point, b: Point, direction: Array) => Array} + */ + function getSupport(a, b, direction) { + return sub(supportPoint(a, direction), supportPoint(b, minus(direction))); + } + + // Computes farthest polygon point in particular direction. + // 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) => Array} + */ + function supportPoint(polygon, direction) { + var index = + direction[1] >= 0 + ? direction[0] < 0 + ? polygon.maxY + : polygon.maxX + : direction[0] < 0 + ? polygon.minX + : polygon.minY, + max = -Infinity, + value; + while ((value = dot(polygon.list[index], direction)) > max) { + max = value; + index = ++index % polygon.list.length; + } + return polygon.list[(index || polygon.list.length) - 1]; + } +}; + +/** + * @type {(simplex: Array>, direction: Array) => boolean} + */ +function processSimplex(simplex, direction) { + // we only need to handle to 1-simplex and 2-simplex + if (simplex.length == 2) { + // 1-simplex + let a = simplex[1], + b = simplex[0], + AO = minus(simplex[1]), + AB = sub(b, a); + // AO is in the same direction as AB + if (dot(AO, AB) > 0) { + // get the vector perpendicular to AB facing O + set(direction, orth(AB, a)); + } else { + set(direction, AO); + // only A remains in the simplex + simplex.shift(); + } + } else { + // 2-simplex + let a = simplex[2], // [a, b, c] = simplex + b = simplex[1], + c = simplex[0], + AB = sub(b, a), + AC = sub(c, a), + AO = minus(a), + ACB = orth(AB, AC), // the vector perpendicular to AB facing away from C + ABC = orth(AC, AB); // the vector perpendicular to AC facing away from B + + if (dot(ACB, AO) > 0) { + if (dot(AB, AO) > 0) { + // region 4 + set(direction, ACB); + simplex.shift(); // simplex = [b, a] + } else { + // region 5 + set(direction, AO); + simplex.splice(0, 2); // simplex = [a] + } + } else if (dot(ABC, AO) > 0) { + if (dot(AC, AO) > 0) { + // region 6 + set(direction, ABC); + simplex.splice(1, 1); // simplex = [c, a] + } else { + // region 5 (again) + set(direction, AO); + simplex.splice(0, 2); // simplex = [a] + } + } // region 7 + else return true; + } + return false; +} + +/** + * @type {(v: Array) => Array} + */ +function minus(v) { + return [-v[0], -v[1]]; +} + +/** + * @type {(v1: Array, v2: Array) => Array} + */ +function sub(v1, v2) { + return [v1[0] - v2[0], v1[1] - v2[1]]; +} + +/** + * @type {(v1: Array, v2: Array) => number} + */ +function dot(v1, v2) { + return v1[0] * v2[0] + v1[1] * v2[1]; +} + +/** + * @type {(v1: Array, v2: Array) => Array} + */ +function orth(v, from) { + var o = [-v[1], v[0]]; + return dot(o, minus(from)) < 0 ? minus(o) : o; +} + +/** + * @typedef {{ + * list: Array>, + * minX: number, + * minY: number, + * maxX: number, + * maxY: number + * }} Point + */ + +/** + * @typedef {{ + * list: Array, + * minX: number, + * minY: number, + * maxX: number, + * maxY: number + * }} Points + */ + +/** + * @type {(pathData: Array) => Points} + */ +function gatherPoints(pathData) { + /** + * @type {Points} + */ + const points = { list: [], minX: 0, minY: 0, maxX: 0, maxY: 0 }; + + // Writes data about the extreme points on each axle + /** + * @type {(path: Point, point: Array) => void} + */ + const addPoint = (path, point) => { + if (!path.list.length || point[1] > path.list[path.maxY][1]) { + path.maxY = path.list.length; + points.maxY = points.list.length + ? Math.max(point[1], points.maxY) + : point[1]; + } + if (!path.list.length || point[0] > path.list[path.maxX][0]) { + path.maxX = path.list.length; + points.maxX = points.list.length + ? Math.max(point[0], points.maxX) + : point[0]; + } + if (!path.list.length || point[1] < path.list[path.minY][1]) { + path.minY = path.list.length; + points.minY = points.list.length + ? Math.min(point[1], points.minY) + : point[1]; + } + if (!path.list.length || point[0] < path.list[path.minX][0]) { + path.minX = path.list.length; + points.minX = points.list.length + ? Math.min(point[0], points.minX) + : point[0]; + } + path.list.push(point); + }; + + for (let i = 0; i < pathData.length; i += 1) { + const pathDataItem = pathData[i]; + let subPath = + points.list.length === 0 + ? { list: [], minX: 0, minY: 0, maxX: 0, maxY: 0 } + : points.list[points.list.length - 1]; + let prev = i === 0 ? null : pathData[i - 1]; + let basePoint = + subPath.list.length === 0 ? null : subPath.list[subPath.list.length - 1]; + let data = pathDataItem.args; + let ctrlPoint = basePoint; + + /** + * @type {(n: number, i: number) => number} + * TODO fix null hack + */ + const toAbsolute = (n, i) => n + (basePoint == null ? 0 : basePoint[i % 2]); + + switch (pathDataItem.command) { + case 'M': + subPath = { list: [], minX: 0, minY: 0, maxX: 0, maxY: 0 }; + points.list.push(subPath); + break; + + case 'H': + if (basePoint != null) { + addPoint(subPath, [data[0], basePoint[1]]); + } + break; + + case 'V': + if (basePoint != null) { + addPoint(subPath, [basePoint[0], data[0]]); + } + break; + + case 'Q': + addPoint(subPath, data.slice(0, 2)); + prevCtrlPoint = [data[2] - data[0], data[3] - data[1]]; // Save control point for shorthand + break; + + case 'T': + if ( + basePoint != null && + prev != null && + (prev.command == 'Q' || prev.command == 'T') + ) { + ctrlPoint = [ + basePoint[0] + prevCtrlPoint[0], + basePoint[1] + prevCtrlPoint[1], + ]; + addPoint(subPath, ctrlPoint); + prevCtrlPoint = [data[0] - ctrlPoint[0], data[1] - ctrlPoint[1]]; + } + break; + + case 'C': + if (basePoint != null) { + // Approximate quibic Bezier curve with middle points between control points + addPoint(subPath, [ + 0.5 * (basePoint[0] + data[0]), + 0.5 * (basePoint[1] + data[1]), + ]); + } + addPoint(subPath, [ + 0.5 * (data[0] + data[2]), + 0.5 * (data[1] + data[3]), + ]); + addPoint(subPath, [ + 0.5 * (data[2] + data[4]), + 0.5 * (data[3] + data[5]), + ]); + prevCtrlPoint = [data[4] - data[2], data[5] - data[3]]; // Save control point for shorthand + break; + + case 'S': + if ( + basePoint != null && + prev != null && + (prev.command == 'C' || prev.command == 'S') + ) { + addPoint(subPath, [ + basePoint[0] + 0.5 * prevCtrlPoint[0], + basePoint[1] + 0.5 * prevCtrlPoint[1], + ]); + ctrlPoint = [ + basePoint[0] + prevCtrlPoint[0], + basePoint[1] + prevCtrlPoint[1], + ]; + } + if (ctrlPoint != null) { + addPoint(subPath, [ + 0.5 * (ctrlPoint[0] + data[0]), + 0.5 * (ctrlPoint[1] + data[1]), + ]); + } + addPoint(subPath, [ + 0.5 * (data[0] + data[2]), + 0.5 * (data[1] + data[3]), + ]); + prevCtrlPoint = [data[2] - data[0], data[3] - data[1]]; + break; + + case 'A': + if (basePoint != null) { + // Convert the arc to bezier curves and use the same approximation + // @ts-ignore no idea what's going on here + var curves = a2c.apply(0, basePoint.concat(data)); + for ( + var cData; + (cData = curves.splice(0, 6).map(toAbsolute)).length; + + ) { + if (basePoint != null) { + addPoint(subPath, [ + 0.5 * (basePoint[0] + cData[0]), + 0.5 * (basePoint[1] + cData[1]), + ]); + } + addPoint(subPath, [ + 0.5 * (cData[0] + cData[2]), + 0.5 * (cData[1] + cData[3]), + ]); + addPoint(subPath, [ + 0.5 * (cData[2] + cData[4]), + 0.5 * (cData[3] + cData[5]), + ]); + if (curves.length) addPoint(subPath, (basePoint = cData.slice(-2))); + } + } + break; + } + + // Save final command coordinates + if (data.length >= 2) addPoint(subPath, data.slice(-2)); + } + + return points; +} + +/** + * Forms a convex hull from set of points of every subpath using monotone chain convex hull algorithm. + * https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain + * + * @type {(points: Point) => Point} + */ +function convexHull(points) { + points.list.sort(function (a, b) { + return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]; + }); + + var lower = [], + minY = 0, + bottom = 0; + for (let i = 0; i < points.list.length; i++) { + while ( + lower.length >= 2 && + cross(lower[lower.length - 2], lower[lower.length - 1], points.list[i]) <= + 0 + ) { + lower.pop(); + } + if (points.list[i][1] < points.list[minY][1]) { + minY = i; + bottom = lower.length; + } + lower.push(points.list[i]); + } + + var upper = [], + maxY = points.list.length - 1, + top = 0; + for (let i = points.list.length; i--; ) { + while ( + upper.length >= 2 && + cross(upper[upper.length - 2], upper[upper.length - 1], points.list[i]) <= + 0 + ) { + upper.pop(); + } + if (points.list[i][1] > points.list[maxY][1]) { + maxY = i; + top = upper.length; + } + upper.push(points.list[i]); + } + + // last points are equal to starting points of the other part + upper.pop(); + lower.pop(); + + const hullList = lower.concat(upper); + + /** + * @type {Point} + */ + const hull = { + list: hullList, + minX: 0, // by sorting + maxX: lower.length, + minY: bottom, + maxY: (lower.length + top) % hullList.length, + }; + + return hull; +} + +/** + * @type {(o: Array, a: Array, b: Array) => number} + */ +function cross(o, a, b) { + return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]); +} + +/** + * Based on code from Snap.svg (Apache 2 license). http://snapsvg.io/ + * Thanks to Dmitry Baranovskiy for his great work! + * + * @type {( + * x1: number, + * y1: number, + * rx: number, + * ry: number, + * angle: number, + * large_arc_flag: number, + * sweep_flag: number, + * x2: number, + * y2: number, + * recursive: Array + * ) => Array} + */ +const a2c = ( + x1, + y1, + rx, + ry, + angle, + large_arc_flag, + sweep_flag, + x2, + y2, + 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} + */ + let res = []; + /** + * @type {(x: number, y: number, rad: number) => number} + */ + const rotateX = (x, y, rad) => { + return x * Math.cos(rad) - y * Math.sin(rad); + }; + /** + * @type {(x: number, y: number, rad: number) => number} + */ + const rotateY = (x, y, rad) => { + return x * Math.sin(rad) + y * Math.cos(rad); + }; + if (!recursive) { + x1 = rotateX(x1, y1, -rad); + y1 = rotateY(x1, y1, -rad); + x2 = rotateX(x2, y2, -rad); + y2 = rotateY(x2, y2, -rad); + var x = (x1 - x2) / 2, + y = (y1 - y2) / 2; + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = Math.sqrt(h); + rx = h * rx; + ry = h * ry; + } + var rx2 = rx * rx; + var ry2 = ry * ry; + var k = + (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) + ) + ); + var cx = (k * rx * y) / ry + (x1 + x2) / 2; + var cy = (k * -ry * x) / rx + (y1 + y2) / 2; + var f1 = Math.asin(Number(((y1 - cy) / ry).toFixed(9))); + var f2 = Math.asin(Number(((y2 - cy) / ry).toFixed(9))); + + f1 = x1 < cx ? Math.PI - f1 : f1; + f2 = x2 < cx ? Math.PI - f2 : f2; + f1 < 0 && (f1 = Math.PI * 2 + f1); + f2 < 0 && (f2 = Math.PI * 2 + f2); + if (sweep_flag && f1 > f2) { + f1 = f1 - Math.PI * 2; + } + if (!sweep_flag && f2 > f1) { + f2 = f2 - Math.PI * 2; + } + } else { + f1 = recursive[0]; + f2 = recursive[1]; + cx = recursive[2]; + cy = recursive[3]; + } + var df = f2 - f1; + if (Math.abs(df) > _120) { + var f2old = f2, + x2old = x2, + y2old = y2; + f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); + x2 = cx + rx * Math.cos(f2); + y2 = cy + ry * Math.sin(f2); + res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [ + f2, + f2old, + cx, + cy, + ]); + } + df = f2 - f1; + var c1 = Math.cos(f1), + s1 = Math.sin(f1), + c2 = Math.cos(f2), + s2 = Math.sin(f2), + t = Math.tan(df / 4), + hx = (4 / 3) * rx * t, + hy = (4 / 3) * ry * t, + m = [ + -hx * s1, + hy * c1, + x2 + hx * s2 - x1, + y2 - hy * c2 - y1, + x2 - x1, + y2 - y1, + ]; + if (recursive) { + return m.concat(res); + } else { + res = m.concat(res); + var newres = []; + for (var i = 0, n = res.length; i < n; i++) { + newres[i] = + i % 2 + ? rotateY(res[i - 1], res[i], rad) + : rotateX(res[i], res[i + 1], rad); + } + return newres; + } +}; diff --git a/node_modules/svgo/plugins/_transforms.js b/node_modules/svgo/plugins/_transforms.js new file mode 100644 index 00000000..159f1a3b --- /dev/null +++ b/node_modules/svgo/plugins/_transforms.js @@ -0,0 +1,379 @@ +'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; + +/** + * @typedef {{ name: string, data: Array }} TransformItem + */ + +/** + * Convert transform string to JS representation. + * + * @type {(transformString: string) => Array} + */ +exports.transform2js = (transformString) => { + // JS representation of the transform data + /** + * @type {Array} + */ + const transforms = []; + // current transform context + /** + * @type {null | TransformItem} + */ + let current = 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); + } + } + } + } + } + // return empty array if broken transform (no data) + return current == null || current.data.length == 0 ? [] : transforms; +}; + +/** + * Multiply transforms into one. + * + * @type {(transforms: Array) => 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. + */ +const mth = { + /** + * @type {(deg: number) => number} + */ + rad: (deg) => { + return (deg * Math.PI) / 180; + }, + + /** + * @type {(rad: number) => number} + */ + deg: (rad) => { + return (rad * 180) / Math.PI; + }, + + /** + * @type {(deg: number) => number} + */ + cos: (deg) => { + return Math.cos(mth.rad(deg)); + }, + + /** + * @type {(val: number, floatPrecision: number) => number} + */ + acos: (val, floatPrecision) => { + return Number(mth.deg(Math.acos(val)).toFixed(floatPrecision)); + }, + + /** + * @type {(deg: number) => number} + */ + sin: (deg) => { + return Math.sin(mth.rad(deg)); + }, + + /** + * @type {(val: number, floatPrecision: number) => number} + */ + asin: (val, floatPrecision) => { + return Number(mth.deg(Math.asin(val)).toFixed(floatPrecision)); + }, + + /** + * @type {(deg: number) => number} + */ + tan: (deg) => { + return Math.tan(mth.rad(deg)); + }, + + /** + * @type {(val: number, floatPrecision: number) => number} + */ + atan: (val, floatPrecision) => { + return Number(mth.deg(Math.atan(val)).toFixed(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 + * + * @type {(transform: TransformItem, params: TransformParams) => Array} + */ +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; + + // [..., ..., ..., ..., tx, ty] → translate(tx, ty) + if (data[4] || data[5]) { + transforms.push({ + name: 'translate', + data: data.slice(4, data[5] ? 6 : 5), + }); + } + + // [sx, 0, tan(a)·sy, sy, 0, 0] → skewX(a)·scale(sx, sy) + if (!data[1] && data[2]) { + transforms.push({ + name: 'skewX', + data: [mth.atan(data[2] / sy, floatPrecision)], + }); + + // [sx, sx·tan(a), 0, sy, 0, 0] → skewY(a)·scale(sx, sy) + } else if (data[1] && !data[2]) { + transforms.push({ + name: 'skewY', + data: [mth.atan(data[1] / data[0], floatPrecision)], + }); + sx = data[0]; + sy = data[3]; + + // [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) { + 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]); + 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), + ]; + + if (rotate[0]) transforms.push({ name: 'rotate', data: rotate }); + + if (rowsSum && colsSum) + transforms.push({ + name: 'skewX', + data: [mth.atan(colsSum / (sx * sx), floatPrecision)], + }); + + // 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); + } + + // Too many transformations, return original matrix if it isn't just a scale/translate + } else if (data[1] || data[2]) { + return [transform]; + } + + if ((scaleBefore && (sx != 1 || sy != 1)) || !transforms.length) + transforms.push({ + name: 'scale', + data: sx == sy ? [sx] : [sx, sy], + }); + + return transforms; +}; + +/** + * Convert transform to the matrix data. + * + * @type {(transform: TransformItem) => Array } + */ +const transformToMatrix = (transform) => { + if (transform.name === 'matrix') { + return transform.data; + } + switch (transform.name) { + case 'translate': + // [1, 0, 0, 1, tx, ty] + return [1, 0, 0, 1, transform.data[0], transform.data[1] || 0]; + case 'scale': + // [sx, 0, 0, sy, 0, 0] + return [ + transform.data[0], + 0, + 0, + transform.data[1] || transform.data[0], + 0, + 0, + ]; + case 'rotate': + // [cos(a), sin(a), -sin(a), cos(a), x, y] + var cos = mth.cos(transform.data[0]), + sin = mth.sin(transform.data[0]), + cx = transform.data[1] || 0, + cy = transform.data[2] || 0; + return [ + cos, + sin, + -sin, + cos, + (1 - cos) * cx + sin * cy, + (1 - cos) * cy - sin * cx, + ]; + case 'skewX': + // [1, 0, tan(a), 1, 0, 0] + return [1, 0, mth.tan(transform.data[0]), 1, 0, 0]; + case 'skewY': + // [1, tan(a), 0, 1, 0, 0] + return [1, mth.tan(transform.data[0]), 0, 1, 0, 0]; + default: + throw Error(`Unknown transform ${transform.name}`); + } +}; + +/** + * Applies transformation to an arc. To do so, we represent ellipse as a matrix, multiply it + * by the transformation matrix and use a singular value decomposition to represent in a form + * rotate(θ)·scale(a b)·rotate(φ). This gives us new ellipse params a, b and θ. + * SVD is being done with the formulae provided by Wolffram|Alpha (svd {{m0, m2}, {m1, m3}}) + * + * @type {( + * cursor: [x: number, y: number], + * arc: Array, + * transform: Array + * ) => Array} + */ +exports.transformArc = (cursor, arc, transform) => { + const x = arc[5] - cursor[0]; + const y = arc[6] - cursor[1]; + let a = arc[0]; + let b = arc[1]; + const rot = (arc[2] * Math.PI) / 180; + const cos = Math.cos(rot); + const sin = Math.sin(rot); + // skip if radius is 0 + if (a > 0 && b > 0) { + let h = + Math.pow(x * cos + y * sin, 2) / (4 * a * a) + + Math.pow(y * cos - x * sin, 2) / (4 * b * b); + if (h > 1) { + h = Math.sqrt(h); + a *= h; + b *= h; + } + } + const ellipse = [a * cos, a * sin, -b * sin, b * cos, 0, 0]; + const m = multiplyTransformMatrices(transform, ellipse); + // Decompose the new ellipse matrix + const lastCol = m[2] * m[2] + m[3] * m[3]; + const squareSum = m[0] * m[0] + m[1] * m[1] + lastCol; + const root = + Math.hypot(m[0] - m[3], m[1] + m[2]) * Math.hypot(m[0] + m[3], m[1] - m[2]); + + if (!root) { + // circle + arc[0] = arc[1] = Math.sqrt(squareSum / 2); + arc[2] = 0; + } else { + const majorAxisSqr = (squareSum + root) / 2; + const minorAxisSqr = (squareSum - root) / 2; + const major = Math.abs(majorAxisSqr - lastCol) > 1e-6; + const sub = (major ? majorAxisSqr : minorAxisSqr) - lastCol; + const rowsSum = m[0] * m[2] + m[1] * m[3]; + const term1 = m[0] * sub + m[2] * rowsSum; + const term2 = m[1] * sub + m[3] * rowsSum; + arc[0] = Math.sqrt(majorAxisSqr); + arc[1] = Math.sqrt(minorAxisSqr); + arc[2] = + (((major ? term2 < 0 : term1 > 0) ? -1 : 1) * + Math.acos((major ? term1 : term2) / Math.hypot(term1, term2)) * + 180) / + Math.PI; + } + + if (transform[0] < 0 !== transform[3] < 0) { + // Flip the sweep flag if coordinates are being flipped horizontally XOR vertically + arc[4] = 1 - arc[4]; + } + + return arc; +}; + +/** + * Multiply transformation matrices. + * + * @type {(a: Array, b: Array) => Array} + */ +const multiplyTransformMatrices = (a, b) => { + return [ + a[0] * b[0] + a[2] * b[1], + a[1] * b[0] + a[3] * b[1], + a[0] * b[2] + a[2] * b[3], + a[1] * b[2] + a[3] * b[3], + a[0] * b[4] + a[2] * b[5] + a[4], + a[1] * b[4] + a[3] * b[5] + a[5], + ]; +}; diff --git a/node_modules/svgo/plugins/addAttributesToSVGElement.js b/node_modules/svgo/plugins/addAttributesToSVGElement.js new file mode 100644 index 00000000..845cb056 --- /dev/null +++ b/node_modules/svgo/plugins/addAttributesToSVGElement.js @@ -0,0 +1,82 @@ +'use strict'; + +exports.name = 'addAttributesToSVGElement'; +exports.description = 'adds attributes to an outer element'; + +var ENOCLS = `Error in plugin "addAttributesToSVGElement": absent parameters. +It should have a list of "attributes" or one "attribute". +Config example: + +plugins: [ + { + name: 'addAttributesToSVGElement', + params: { + attribute: "mySvg" + } + } +] + +plugins: [ + { + name: 'addAttributesToSVGElement', + params: { + attributes: ["mySvg", "size-big"] + } + } +] + +plugins: [ + { + name: 'addAttributesToSVGElement', + params: { + attributes: [ + { + focusable: false + }, + { + 'data-image': icon + } + ] + } + } +] +`; + +/** + * Add attributes to an outer element. Example config: + * + * @author April Arcus + * + * @type {import('./plugins-types').Plugin<'addAttributesToSVGElement'>} + */ +exports.fn = (root, params) => { + if (!Array.isArray(params.attributes) && !params.attribute) { + console.error(ENOCLS); + return null; + } + const attributes = params.attributes || [params.attribute]; + return { + element: { + enter: (node, parentNode) => { + if (node.name === 'svg' && parentNode.type === 'root') { + for (const attribute of attributes) { + if (typeof attribute === 'string') { + if (node.attributes[attribute] == null) { + // @ts-ignore disallow explicit nullable attribute value + node.attributes[attribute] = undefined; + } + } + if (typeof attribute === 'object') { + for (const key of Object.keys(attribute)) { + if (node.attributes[key] == null) { + // @ts-ignore disallow explicit nullable attribute value + node.attributes[key] = attribute[key]; + } + } + } + } + } + }, + }, + }; +}; diff --git a/node_modules/svgo/plugins/addClassesToSVGElement.js b/node_modules/svgo/plugins/addClassesToSVGElement.js new file mode 100644 index 00000000..9a015c7b --- /dev/null +++ b/node_modules/svgo/plugins/addClassesToSVGElement.js @@ -0,0 +1,82 @@ +'use strict'; + +exports.name = 'addClassesToSVGElement'; +exports.description = 'adds classnames to an outer element'; + +var ENOCLS = `Error in plugin "addClassesToSVGElement": absent parameters. +It should have a list of classes in "classNames" or one "className". +Config example: + +plugins: [ + { + name: "addClassesToSVGElement", + params: { + className: "mySvg" + } + } +] + +plugins: [ + { + name: "addClassesToSVGElement", + params: { + classNames: ["mySvg", "size-big"] + } + } +] +`; + +/** + * Add classnames to an outer element. Example config: + * + * plugins: [ + * { + * name: "addClassesToSVGElement", + * params: { + * className: "mySvg" + * } + * } + * ] + * + * plugins: [ + * { + * name: "addClassesToSVGElement", + * params: { + * classNames: ["mySvg", "size-big"] + * } + * } + * ] + * + * @author April Arcus + * + * @type {import('./plugins-types').Plugin<'addClassesToSVGElement'>} + */ +exports.fn = (root, params) => { + if ( + !(Array.isArray(params.classNames) && params.classNames.some(String)) && + !params.className + ) { + console.error(ENOCLS); + return null; + } + const classNames = params.classNames || [params.className]; + return { + element: { + enter: (node, parentNode) => { + if (node.name === 'svg' && parentNode.type === 'root') { + const classList = new Set( + node.attributes.class == null + ? null + : node.attributes.class.split(' ') + ); + for (const className of classNames) { + if (className != null) { + classList.add(className); + } + } + node.attributes.class = Array.from(classList).join(' '); + } + }, + }, + }; +}; diff --git a/node_modules/svgo/plugins/applyTransforms.js b/node_modules/svgo/plugins/applyTransforms.js new file mode 100644 index 00000000..bf60ac89 --- /dev/null +++ b/node_modules/svgo/plugins/applyTransforms.js @@ -0,0 +1,379 @@ +'use strict'; + +/** + * @typedef {import('../lib/types').PathDataItem} PathDataItem + * @typedef {import('../lib/types').XastElement} XastElement + */ + +const { collectStylesheet, computeStyle } = require('../lib/style.js'); +const { + transformsMultiply, + transform2js, + transformArc, +} = require('./_transforms.js'); +const { path2js } = require('./_path.js'); +const { removeLeadingZero } = require('../lib/svgo/tools.js'); +const { referencesProps, attrsGroupsDefaults } = require('./_collections.js'); + +/** + * @typedef {Array} PathData + * @typedef {Array} Matrix + */ + +const regNumericValues = /[-+]?(\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g; + +/** + * Apply transformation(s) to the Path data. + * + * @type {import('../lib/types').Plugin<{ + * transformPrecision: number, + * applyTransformsStroked: boolean, + * }>} + */ +const applyTransforms = (root, params) => { + const stylesheet = collectStylesheet(root); + return { + element: { + enter: (node) => { + const computedStyle = computeStyle(stylesheet, node); + + // used only for paths for now + if (node.attributes.d == null) { + return; + } + + // stroke and stroke-width can be redefined with + if (node.attributes.id != null) { + return; + } + + // if there are no 'stroke' attr and references to other objects such as + // gradiends or clip-path which are also subjects to transform. + if ( + node.attributes.transform == null || + node.attributes.transform === '' || + // styles are not considered when applying transform + // can be fixed properly with new style engine + node.attributes.style != null || + Object.entries(node.attributes).some( + ([name, value]) => + referencesProps.includes(name) && value.includes('url(') + ) + ) { + return; + } + + const matrix = transformsMultiply( + transform2js(node.attributes.transform) + ); + const stroke = + computedStyle.stroke != null && computedStyle.stroke.type === 'static' + ? computedStyle.stroke.value + : null; + + const strokeWidth = + computedStyle['stroke-width'] != null && + computedStyle['stroke-width'].type === 'static' + ? computedStyle['stroke-width'].value + : null; + const transformPrecision = params.transformPrecision; + + if ( + (computedStyle.stroke != null && + computedStyle.stroke.type === 'dynamic') || + (computedStyle.strokeWidth != null && + computedStyle['stroke-width'].type === 'dynamic') + ) { + return; + } + + const scale = Number( + Math.sqrt( + matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1] + ).toFixed(transformPrecision) + ); + + if (stroke && stroke != 'none') { + if (params.applyTransformsStroked === false) { + return; + } + + // stroke cannot be transformed with different vertical and horizontal scale or skew + if ( + (matrix.data[0] !== matrix.data[3] || + matrix.data[1] !== -matrix.data[2]) && + (matrix.data[0] !== -matrix.data[3] || + matrix.data[1] !== matrix.data[2]) + ) { + return; + } + + // apply transform to stroke-width, stroke-dashoffset and stroke-dasharray + if (scale !== 1) { + if (node.attributes['vector-effect'] !== 'non-scaling-stroke') { + node.attributes['stroke-width'] = ( + strokeWidth || attrsGroupsDefaults.presentation['stroke-width'] + ) + .trim() + .replace(regNumericValues, (num) => + removeLeadingZero(Number(num) * scale) + ); + + if (node.attributes['stroke-dashoffset'] != null) { + node.attributes['stroke-dashoffset'] = node.attributes[ + 'stroke-dashoffset' + ] + .trim() + .replace(regNumericValues, (num) => + removeLeadingZero(Number(num) * scale) + ); + } + + if (node.attributes['stroke-dasharray'] != null) { + node.attributes['stroke-dasharray'] = node.attributes[ + 'stroke-dasharray' + ] + .trim() + .replace(regNumericValues, (num) => + removeLeadingZero(Number(num) * scale) + ); + } + } + } + } + + const pathData = path2js(node); + applyMatrixToPathData(pathData, matrix.data); + + // remove transform attr + delete node.attributes.transform; + }, + }, + }; +}; +exports.applyTransforms = applyTransforms; + +/** + * @type {(matrix: Matrix, x: number, y: number) => [number, number]} + */ +const transformAbsolutePoint = (matrix, x, y) => { + const newX = matrix[0] * x + matrix[2] * y + matrix[4]; + const newY = matrix[1] * x + matrix[3] * y + matrix[5]; + return [newX, newY]; +}; + +/** + * @type {(matrix: Matrix, x: number, y: number) => [number, number]} + */ +const transformRelativePoint = (matrix, x, y) => { + const newX = matrix[0] * x + matrix[2] * y; + const newY = matrix[1] * x + matrix[3] * y; + return [newX, newY]; +}; + +/** + * @type {(pathData: PathData, matrix: Matrix) => void} + */ +const applyMatrixToPathData = (pathData, matrix) => { + /** + * @type {[number, number]} + */ + const start = [0, 0]; + /** + * @type {[number, number]} + */ + const cursor = [0, 0]; + + for (const pathItem of pathData) { + let { command, args } = pathItem; + + // moveto (x y) + if (command === 'M') { + cursor[0] = args[0]; + cursor[1] = args[1]; + start[0] = cursor[0]; + start[1] = cursor[1]; + const [x, y] = transformAbsolutePoint(matrix, args[0], args[1]); + args[0] = x; + args[1] = y; + } + if (command === 'm') { + cursor[0] += args[0]; + cursor[1] += args[1]; + start[0] = cursor[0]; + start[1] = cursor[1]; + const [x, y] = transformRelativePoint(matrix, args[0], args[1]); + args[0] = x; + args[1] = y; + } + + // horizontal lineto (x) + // convert to lineto to handle two-dimentional transforms + if (command === 'H') { + command = 'L'; + args = [args[0], cursor[1]]; + } + if (command === 'h') { + command = 'l'; + args = [args[0], 0]; + } + + // vertical lineto (y) + // convert to lineto to handle two-dimentional transforms + if (command === 'V') { + command = 'L'; + args = [cursor[0], args[0]]; + } + if (command === 'v') { + command = 'l'; + args = [0, args[0]]; + } + + // lineto (x y) + if (command === 'L') { + cursor[0] = args[0]; + cursor[1] = args[1]; + const [x, y] = transformAbsolutePoint(matrix, args[0], args[1]); + args[0] = x; + args[1] = y; + } + if (command === 'l') { + cursor[0] += args[0]; + cursor[1] += args[1]; + const [x, y] = transformRelativePoint(matrix, args[0], args[1]); + args[0] = x; + args[1] = y; + } + + // curveto (x1 y1 x2 y2 x y) + if (command === 'C') { + cursor[0] = args[4]; + cursor[1] = args[5]; + const [x1, y1] = transformAbsolutePoint(matrix, args[0], args[1]); + const [x2, y2] = transformAbsolutePoint(matrix, args[2], args[3]); + const [x, y] = transformAbsolutePoint(matrix, args[4], args[5]); + args[0] = x1; + args[1] = y1; + args[2] = x2; + args[3] = y2; + args[4] = x; + args[5] = y; + } + if (command === 'c') { + cursor[0] += args[4]; + cursor[1] += args[5]; + const [x1, y1] = transformRelativePoint(matrix, args[0], args[1]); + const [x2, y2] = transformRelativePoint(matrix, args[2], args[3]); + const [x, y] = transformRelativePoint(matrix, args[4], args[5]); + args[0] = x1; + args[1] = y1; + args[2] = x2; + args[3] = y2; + args[4] = x; + args[5] = y; + } + + // smooth curveto (x2 y2 x y) + if (command === 'S') { + cursor[0] = args[2]; + cursor[1] = args[3]; + const [x2, y2] = transformAbsolutePoint(matrix, args[0], args[1]); + const [x, y] = transformAbsolutePoint(matrix, args[2], args[3]); + args[0] = x2; + args[1] = y2; + args[2] = x; + args[3] = y; + } + if (command === 's') { + cursor[0] += args[2]; + cursor[1] += args[3]; + const [x2, y2] = transformRelativePoint(matrix, args[0], args[1]); + const [x, y] = transformRelativePoint(matrix, args[2], args[3]); + args[0] = x2; + args[1] = y2; + args[2] = x; + args[3] = y; + } + + // quadratic Bézier curveto (x1 y1 x y) + if (command === 'Q') { + cursor[0] = args[2]; + cursor[1] = args[3]; + const [x1, y1] = transformAbsolutePoint(matrix, args[0], args[1]); + const [x, y] = transformAbsolutePoint(matrix, args[2], args[3]); + args[0] = x1; + args[1] = y1; + args[2] = x; + args[3] = y; + } + if (command === 'q') { + cursor[0] += args[2]; + cursor[1] += args[3]; + const [x1, y1] = transformRelativePoint(matrix, args[0], args[1]); + const [x, y] = transformRelativePoint(matrix, args[2], args[3]); + args[0] = x1; + args[1] = y1; + args[2] = x; + args[3] = y; + } + + // smooth quadratic Bézier curveto (x y) + if (command === 'T') { + cursor[0] = args[0]; + cursor[1] = args[1]; + const [x, y] = transformAbsolutePoint(matrix, args[0], args[1]); + args[0] = x; + args[1] = y; + } + if (command === 't') { + cursor[0] += args[0]; + cursor[1] += args[1]; + const [x, y] = transformRelativePoint(matrix, args[0], args[1]); + args[0] = x; + args[1] = y; + } + + // elliptical arc (rx ry x-axis-rotation large-arc-flag sweep-flag x y) + if (command === 'A') { + transformArc(cursor, args, matrix); + cursor[0] = args[5]; + cursor[1] = args[6]; + // reduce number of digits in rotation angle + if (Math.abs(args[2]) > 80) { + const a = args[0]; + const rotation = args[2]; + args[0] = args[1]; + args[1] = a; + args[2] = rotation + (rotation > 0 ? -90 : 90); + } + const [x, y] = transformAbsolutePoint(matrix, args[5], args[6]); + args[5] = x; + args[6] = y; + } + if (command === 'a') { + transformArc([0, 0], args, matrix); + cursor[0] += args[5]; + cursor[1] += args[6]; + // reduce number of digits in rotation angle + if (Math.abs(args[2]) > 80) { + const a = args[0]; + const rotation = args[2]; + args[0] = args[1]; + args[1] = a; + args[2] = rotation + (rotation > 0 ? -90 : 90); + } + const [x, y] = transformRelativePoint(matrix, args[5], args[6]); + args[5] = x; + args[6] = y; + } + + // closepath + if (command === 'z' || command === 'Z') { + cursor[0] = start[0]; + cursor[1] = start[1]; + } + + pathItem.command = command; + pathItem.args = args; + } +}; diff --git a/node_modules/svgo/plugins/cleanupAttrs.js b/node_modules/svgo/plugins/cleanupAttrs.js new file mode 100644 index 00000000..399de194 --- /dev/null +++ b/node_modules/svgo/plugins/cleanupAttrs.js @@ -0,0 +1,49 @@ +'use strict'; + +exports.name = 'cleanupAttrs'; +exports.description = + 'cleanups attributes from newlines, trailing and repeating spaces'; + +const regNewlinesNeedSpace = /(\S)\r?\n(\S)/g; +const regNewlines = /\r?\n/g; +const regSpaces = /\s{2,}/g; + +/** + * Cleanup attributes values from newlines, trailing and repeating spaces. + * + * @author Kir Belevich + * + * @type {import('./plugins-types').Plugin<'cleanupAttrs'>} + */ +exports.fn = (root, params) => { + const { newlines = true, trim = true, spaces = true } = params; + return { + element: { + enter: (node) => { + for (const name of Object.keys(node.attributes)) { + if (newlines) { + // new line which requires a space instead of themselve + node.attributes[name] = node.attributes[name].replace( + regNewlinesNeedSpace, + (match, p1, p2) => p1 + ' ' + p2 + ); + // simple new line + node.attributes[name] = node.attributes[name].replace( + regNewlines, + '' + ); + } + if (trim) { + node.attributes[name] = node.attributes[name].trim(); + } + if (spaces) { + node.attributes[name] = node.attributes[name].replace( + regSpaces, + ' ' + ); + } + } + }, + }, + }; +}; diff --git a/node_modules/svgo/plugins/cleanupEnableBackground.js b/node_modules/svgo/plugins/cleanupEnableBackground.js new file mode 100644 index 00000000..80be32be --- /dev/null +++ b/node_modules/svgo/plugins/cleanupEnableBackground.js @@ -0,0 +1,73 @@ +'use strict'; + +const { visit } = require('../lib/xast.js'); + +exports.name = 'cleanupEnableBackground'; +exports.description = + 'remove or cleanup enable-background attribute when possible'; + +/** + * Remove or cleanup enable-background attr which coincides with a width/height box. + * + * @see https://www.w3.org/TR/SVG11/filters.html#EnableBackgroundProperty + * + * @example + * + * ⬇ + * + * + * @author Kir Belevich + * + * @type {import('./plugins-types').Plugin<'cleanupEnableBackground'>} + */ +exports.fn = (root) => { + const regEnableBackground = + /^new\s0\s0\s([-+]?\d*\.?\d+([eE][-+]?\d+)?)\s([-+]?\d*\.?\d+([eE][-+]?\d+)?)$/; + + let hasFilter = false; + visit(root, { + element: { + enter: (node) => { + if (node.name === 'filter') { + hasFilter = true; + } + }, + }, + }); + + return { + element: { + enter: (node) => { + if (node.attributes['enable-background'] == null) { + return; + } + if (hasFilter) { + if ( + (node.name === 'svg' || + node.name === 'mask' || + node.name === 'pattern') && + node.attributes.width != null && + node.attributes.height != null + ) { + const match = + node.attributes['enable-background'].match(regEnableBackground); + if ( + match != null && + node.attributes.width === match[1] && + node.attributes.height === match[3] + ) { + if (node.name === 'svg') { + delete node.attributes['enable-background']; + } else { + node.attributes['enable-background'] = 'new'; + } + } + } + } else { + //we don't need 'enable-background' if we have no filters + delete node.attributes['enable-background']; + } + }, + }, + }; +}; diff --git a/node_modules/svgo/plugins/cleanupIds.js b/node_modules/svgo/plugins/cleanupIds.js new file mode 100644 index 00000000..1d2532b2 --- /dev/null +++ b/node_modules/svgo/plugins/cleanupIds.js @@ -0,0 +1,287 @@ +'use strict'; + +/** + * @typedef {import('../lib/types').XastElement} XastElement + */ + +const { visitSkip } = require('../lib/xast.js'); +const { referencesProps } = require('./_collections.js'); + +exports.name = 'cleanupIds'; +exports.description = 'removes unused IDs and minifies used'; + +const regReferencesUrl = /\burl\((["'])?#(.+?)\1\)/; +const regReferencesHref = /^#(.+?)$/; +const regReferencesBegin = /(\D+)\./; +const generateIdChars = [ + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', +]; +const maxIdIndex = generateIdChars.length - 1; + +/** + * Check if an ID starts with any one of a list of strings. + * + * @type {(string: string, prefixes: Array) => boolean} + */ +const hasStringPrefix = (string, prefixes) => { + for (const prefix of prefixes) { + if (string.startsWith(prefix)) { + return true; + } + } + return false; +}; + +/** + * Generate unique minimal ID. + * + * @type {(currentId: null | Array) => Array} + */ +const generateId = (currentId) => { + if (currentId == null) { + return [0]; + } + currentId[currentId.length - 1] += 1; + for (let i = currentId.length - 1; i > 0; i--) { + if (currentId[i] > maxIdIndex) { + currentId[i] = 0; + if (currentId[i - 1] !== undefined) { + currentId[i - 1]++; + } + } + } + if (currentId[0] > maxIdIndex) { + currentId[0] = 0; + currentId.unshift(0); + } + return currentId; +}; + +/** + * Get string from generated ID array. + * + * @type {(arr: Array) => string} + */ +const getIdString = (arr) => { + return arr.map((i) => generateIdChars[i]).join(''); +}; + +/** + * Remove unused and minify used IDs + * (only if there are no any