summaryrefslogtreecommitdiff
path: root/node_modules/svgo/plugins/mergePaths.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/svgo/plugins/mergePaths.js')
-rw-r--r--node_modules/svgo/plugins/mergePaths.js108
1 files changed, 79 insertions, 29 deletions
diff --git a/node_modules/svgo/plugins/mergePaths.js b/node_modules/svgo/plugins/mergePaths.js
index 05c7ac70..fe982c13 100644
--- a/node_modules/svgo/plugins/mergePaths.js
+++ b/node_modules/svgo/plugins/mergePaths.js
@@ -1,6 +1,11 @@
'use strict';
-const { detachNodeFromParent } = require('../lib/xast.js');
+/**
+ * @typedef {import("../lib/types").PathDataItem} PathDataItem
+ * @typedef {import('../lib/types').XastChild} XastChild
+ * @typedef {import('../lib/types').XastElement} XastElement
+ */
+
const { collectStylesheet, computeStyle } = require('../lib/style.js');
const { path2js, js2path, intersects } = require('./_path.js');
@@ -25,73 +30,118 @@ exports.fn = (root, params) => {
return {
element: {
enter: (node) => {
- let prevChild = null;
+ if (node.children.length <= 1) {
+ return;
+ }
+
+ /** @type {XastChild[]} */
+ const elementsToRemove = [];
+ let prevChild = node.children[0];
+ let prevPathData = null;
+
+ /**
+ * @param {XastElement} child
+ * @param {PathDataItem[]} pathData
+ */
+ const updatePreviousPath = (child, pathData) => {
+ js2path(child, pathData, {
+ floatPrecision,
+ noSpaceAfterFlags,
+ });
+ prevPathData = null;
+ };
+
+ for (let i = 1; i < node.children.length; i++) {
+ const child = node.children[i];
- for (const child of node.children) {
- // skip if previous element is not path or contains animation elements
if (
- prevChild == null ||
prevChild.type !== 'element' ||
prevChild.name !== 'path' ||
prevChild.children.length !== 0 ||
prevChild.attributes.d == null
) {
+ if (prevPathData && prevChild.type === 'element') {
+ updatePreviousPath(prevChild, prevPathData);
+ }
prevChild = child;
continue;
}
- // skip if element is not path or contains animation elements
if (
child.type !== 'element' ||
child.name !== 'path' ||
child.children.length !== 0 ||
child.attributes.d == null
) {
+ if (prevPathData) {
+ updatePreviousPath(prevChild, prevPathData);
+ }
prevChild = child;
continue;
}
- // preserve paths with markers
const computedStyle = computeStyle(stylesheet, child);
if (
computedStyle['marker-start'] ||
computedStyle['marker-mid'] ||
computedStyle['marker-end']
) {
+ if (prevPathData) {
+ updatePreviousPath(prevChild, prevPathData);
+ }
prevChild = child;
continue;
}
-
- const prevChildAttrs = Object.keys(prevChild.attributes);
const childAttrs = Object.keys(child.attributes);
- let attributesAreEqual = prevChildAttrs.length === childAttrs.length;
- for (const name of childAttrs) {
- if (name !== 'd') {
- if (
- prevChild.attributes[name] == null ||
- prevChild.attributes[name] !== child.attributes[name]
- ) {
- attributesAreEqual = false;
- }
+ if (childAttrs.length !== Object.keys(prevChild.attributes).length) {
+ if (prevPathData) {
+ updatePreviousPath(prevChild, prevPathData);
}
+ prevChild = child;
+ continue;
}
- const prevPathJS = path2js(prevChild);
- const curPathJS = path2js(child);
- if (
- attributesAreEqual &&
- (force || !intersects(prevPathJS, curPathJS))
- ) {
- js2path(prevChild, prevPathJS.concat(curPathJS), {
- floatPrecision,
- noSpaceAfterFlags,
- });
- detachNodeFromParent(child, node);
+ const areAttrsEqual = childAttrs.some((attr) => {
+ return (
+ attr !== 'd' &&
+ prevChild.type === 'element' &&
+ prevChild.attributes[attr] !== child.attributes[attr]
+ );
+ });
+
+ if (areAttrsEqual) {
+ if (prevPathData) {
+ updatePreviousPath(prevChild, prevPathData);
+ }
+ prevChild = child;
continue;
}
+ const hasPrevPath = prevPathData != null;
+ const currentPathData = path2js(child);
+ prevPathData = prevPathData ?? path2js(prevChild);
+
+ if (force || !intersects(prevPathData, currentPathData)) {
+ prevPathData.push(...currentPathData);
+ elementsToRemove.push(child);
+ continue;
+ }
+
+ if (hasPrevPath) {
+ updatePreviousPath(prevChild, prevPathData);
+ }
+
prevChild = child;
+ prevPathData = null;
}
+
+ if (prevPathData && prevChild.type === 'element') {
+ updatePreviousPath(prevChild, prevPathData);
+ }
+
+ node.children = node.children.filter(
+ (child) => !elementsToRemove.includes(child),
+ );
},
},
};