source: trip-planner-front/node_modules/svgo/plugins/collapseGroups.js@ e29cc2e

Last change on this file since e29cc2e was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 3.8 KB
Line 
1'use strict';
2
3/**
4 * @typedef {import('../lib/types').XastNode} XastNode
5 */
6
7const { inheritableAttrs, elemsGroups } = require('./_collections.js');
8
9exports.type = 'visitor';
10exports.name = 'collapseGroups';
11exports.active = true;
12exports.description = 'collapses useless groups';
13
14/**
15 * @type {(node: XastNode, name: string) => boolean}
16 */
17const hasAnimatedAttr = (node, name) => {
18 if (node.type === 'element') {
19 if (
20 elemsGroups.animation.includes(node.name) &&
21 node.attributes.attributeName === name
22 ) {
23 return true;
24 }
25 for (const child of node.children) {
26 if (hasAnimatedAttr(child, name)) {
27 return true;
28 }
29 }
30 }
31 return false;
32};
33
34/**
35 * Collapse useless groups.
36 *
37 * @example
38 * <g>
39 * <g attr1="val1">
40 * <path d="..."/>
41 * </g>
42 * </g>
43 * ⬇
44 * <g>
45 * <g>
46 * <path attr1="val1" d="..."/>
47 * </g>
48 * </g>
49 * ⬇
50 * <path attr1="val1" d="..."/>
51 *
52 * @author Kir Belevich
53 *
54 * @type {import('../lib/types').Plugin<void>}
55 */
56exports.fn = () => {
57 return {
58 element: {
59 exit: (node, parentNode) => {
60 if (parentNode.type === 'root' || parentNode.name === 'switch') {
61 return;
62 }
63 // non-empty groups
64 if (node.name !== 'g' || node.children.length === 0) {
65 return;
66 }
67
68 // move group attibutes to the single child element
69 if (
70 Object.keys(node.attributes).length !== 0 &&
71 node.children.length === 1
72 ) {
73 const firstChild = node.children[0];
74 // TODO untangle this mess
75 if (
76 firstChild.type === 'element' &&
77 firstChild.attributes.id == null &&
78 node.attributes.filter == null &&
79 (node.attributes.class == null ||
80 firstChild.attributes.class == null) &&
81 ((node.attributes['clip-path'] == null &&
82 node.attributes.mask == null) ||
83 (firstChild.name === 'g' &&
84 node.attributes.transform == null &&
85 firstChild.attributes.transform == null))
86 ) {
87 for (const [name, value] of Object.entries(node.attributes)) {
88 // avoid copying to not conflict with animated attribute
89 if (hasAnimatedAttr(firstChild, name)) {
90 return;
91 }
92 if (firstChild.attributes[name] == null) {
93 firstChild.attributes[name] = value;
94 } else if (name === 'transform') {
95 firstChild.attributes[name] =
96 value + ' ' + firstChild.attributes[name];
97 } else if (firstChild.attributes[name] === 'inherit') {
98 firstChild.attributes[name] = value;
99 } else if (
100 inheritableAttrs.includes(name) === false &&
101 firstChild.attributes[name] !== value
102 ) {
103 return;
104 }
105 delete node.attributes[name];
106 }
107 }
108 }
109
110 // collapse groups without attributes
111 if (Object.keys(node.attributes).length === 0) {
112 // animation elements "add" attributes to group
113 // group should be preserved
114 for (const child of node.children) {
115 if (
116 child.type === 'element' &&
117 elemsGroups.animation.includes(child.name)
118 ) {
119 return;
120 }
121 }
122 // replace current node with all its children
123 const index = parentNode.children.indexOf(node);
124 parentNode.children.splice(index, 1, ...node.children);
125 // TODO remove in v3
126 for (const child of node.children) {
127 // @ts-ignore parentNode is forbidden for public usage
128 // and will be moved in v3
129 child.parentNode = parentNode;
130 }
131 }
132 },
133 },
134 };
135};
Note: See TracBrowser for help on using the repository browser.