Skip to content

Commit e045b46

Browse files
authored
add minifyPatterns plugin (#181)
1 parent b18eb82 commit e045b46

21 files changed

+995
-182
lines changed

lib/tools-ast.js

Lines changed: 73 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { PaintAttValue } from './attrs/paintAttValue.js';
77
import { PresentationAttUrl } from './types/presentationAttUrl.js';
88

99
/**
10+
* @deprecated
1011
* @typedef {Map<string,{referencingEl:import('./types.js').XastElement,referencingAtt:string}[]>} IdReferenceMap
1112
*/
1213

@@ -50,15 +51,16 @@ export function addReferencedIdsInStyleAttribute(refs, properties) {
5051
}
5152

5253
/**
53-
* @param {{id:string,type:'p'|'a',name:string}[]} refs
54+
* @param {import('../types/types.js').ReferenceInfo[]} refs
55+
* @param {import('./types.js').XastElement} element
5456
* @param {IterableIterator<[string,import('./types.js').AttValue]>} properties
5557
* @returns {void}
5658
*/
57-
export function addReferencedIdsInStyleAttribute2(refs, properties) {
59+
export function addReferencedIdsInStyleAttribute2(refs, element, properties) {
5860
for (const [name, value] of properties) {
5961
const id = value.getReferencedID();
6062
if (id) {
61-
refs.push({ id: id, type: 'p', name: name });
63+
refs.push({ element: element, id: id, type: 'p', name: name });
6264
}
6365
}
6466
}
@@ -183,22 +185,24 @@ export function getReferencedIds(element) {
183185
* @returns {import('../types/types.js').ReferenceInfo[]}
184186
*/
185187
export function getReferencedIds2(element) {
186-
/** @type {{id:string,type:'p'|'a',name:string}[]} */
188+
/** @type {import('../types/types.js').ReferenceInfo[]} */
187189
const refs = [];
188190
for (let [attName, value] of element.svgAtts.entries()) {
189191
switch (attName) {
190192
case 'style':
191-
{
192-
const attValue =
193-
/** @type {import('../types/types.js').StyleAttValue} */ (value);
194-
addReferencedIdsInStyleAttribute2(refs, attValue.entries());
195-
}
193+
addReferencedIdsInStyleAttribute2(
194+
refs,
195+
element,
196+
/** @type {import('../types/types.js').StyleAttValue} */ (
197+
value
198+
).entries(),
199+
);
196200
break;
197201
default:
198202
{
199203
const id = value.getReferencedID();
200204
if (id) {
201-
refs.push({ id: id, type: 'a', name: attName });
205+
refs.push({ element: element, id: id, type: 'a', name: attName });
202206
}
203207
}
204208
break;
@@ -207,7 +211,12 @@ export function getReferencedIds2(element) {
207211

208212
const href = getXlinkHref(element);
209213
if (href && href.value.startsWith('#')) {
210-
refs.push({ id: href.value.substring(1), type: 'a', name: 'xlink:href' });
214+
refs.push({
215+
element: element,
216+
id: href.value.substring(1),
217+
type: 'a',
218+
name: 'xlink:href',
219+
});
211220
}
212221
return refs;
213222
}
@@ -282,6 +291,15 @@ export function isDescendantOf(ancestor, descendant) {
282291
}
283292
}
284293

294+
/**
295+
* @param {import('./types.js').XastChild[]} children
296+
* @param {import('./types.js').XastParent} newParent
297+
*/
298+
export function moveChildren(children, newParent) {
299+
children.forEach((child) => (child.parentNode = newParent));
300+
newParent.children = children;
301+
}
302+
285303
/**
286304
* @param {import('./types.js').XastElement} element
287305
* @param {IdReferenceMap} allReferencedIds
@@ -302,10 +320,44 @@ export function recordReferencedIds(element, allReferencedIds) {
302320
}
303321
}
304322

323+
/**
324+
* @param {import('../types/types.js').ReferenceInfo} refInfo
325+
* @param {string} newId
326+
*/
327+
export function updateReferencedId2(refInfo, newId) {
328+
const element = refInfo.element;
329+
330+
if (refInfo.type === 'p') {
331+
/** @type {import('../types/types.js').StyleAttValue} */
332+
const att = element.svgAtts.getAtt('style');
333+
updateReferencedProp(att, refInfo.name, newId);
334+
return;
335+
}
336+
337+
switch (refInfo.name) {
338+
case 'href':
339+
element.svgAtts.set('href', new HrefAttValue('#' + newId));
340+
break;
341+
case 'xlink:href':
342+
{
343+
const href = getXlinkHref(element);
344+
if (href === undefined) {
345+
throw new Error();
346+
}
347+
href.value = '#' + newId;
348+
}
349+
break;
350+
default:
351+
updateReferencedProp(element.svgAtts, refInfo.name, newId);
352+
break;
353+
}
354+
}
355+
305356
/**
306357
* @param {import('./types.js').XastElement} element
307358
* @param {string} attName
308359
* @param {Map<string,string>} idMap
360+
* @deprecated
309361
*/
310362
export function updateReferencedId(element, attName, idMap) {
311363
switch (attName) {
@@ -338,12 +390,7 @@ export function updateReferencedId(element, attName, idMap) {
338390
default:
339391
{
340392
const att = element.svgAtts.getAtt(attName);
341-
updateReferencedAtt(
342-
element.svgAtts,
343-
attName,
344-
att,
345-
getNewId(att, idMap),
346-
);
393+
updateReferencedProp(element.svgAtts, attName, getNewId(att, idMap));
347394
}
348395
break;
349396
}
@@ -364,7 +411,7 @@ export function updateReferencedDeclarationIds(attMap, idMap) {
364411
if (newId === undefined) {
365412
continue;
366413
}
367-
updateReferencedAtt(attMap, propName, v, newId);
414+
updateReferencedProp(attMap, propName, newId, v.isImportant());
368415
}
369416
}
370417

@@ -393,33 +440,31 @@ function getNewId(att, idMap) {
393440
/**
394441
* @param {import('./types.js').SvgAttValues} attMap
395442
* @param {string} attName
396-
* @param {import('./types.js').AttValue} attValue
397443
* @param {string} newId
444+
* @param {boolean} [isImportant]
398445
*/
399-
function updateReferencedAtt(attMap, attName, attValue, newId) {
446+
function updateReferencedProp(attMap, attName, newId, isImportant = false) {
400447
const newURL = '#' + newId;
401448
switch (attName) {
402449
case 'clip-path':
403450
attMap.set(
404451
attName,
405452
new ClipPathAttValue(
406453
undefined,
407-
attValue.isImportant(),
454+
isImportant,
408455
new PresentationAttUrl(undefined, newURL),
409456
),
410457
);
411458
break;
412459
case 'fill':
413460
case 'stroke':
414461
{
415-
/** @type {PaintAttValue} */
416-
const att = attMap.getAtt(attName);
417462
attMap.set(
418463
attName,
419464
new PaintAttValue(
420465
undefined,
421-
att.isImportant(),
422-
att.getColor(),
466+
isImportant,
467+
/** @type {PaintAttValue} */ (attMap.get(attName)).getColor(),
423468
new PresentationAttUrl(undefined, newURL),
424469
),
425470
);
@@ -430,7 +475,7 @@ function updateReferencedAtt(attMap, attName, attValue, newId) {
430475
attName,
431476
new FilterAttValue(
432477
undefined,
433-
attValue.isImportant(),
478+
isImportant,
434479
new PresentationAttUrl(undefined, newURL),
435480
),
436481
);
@@ -442,7 +487,7 @@ function updateReferencedAtt(attMap, attName, attValue, newId) {
442487
attName,
443488
new MarkerAttValue(
444489
undefined,
445-
attValue.isImportant(),
490+
isImportant,
446491
new PresentationAttUrl(undefined, newURL),
447492
),
448493
);
@@ -453,7 +498,7 @@ function updateReferencedAtt(attMap, attName, attValue, newId) {
453498
attName,
454499
new MaskAttValue(
455500
undefined,
456-
attValue.isImportant(),
501+
isImportant,
457502
new PresentationAttUrl(undefined, newURL),
458503
),
459504
);

lib/utils/tools-dups.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* @param {import('../types.js').XastElement} element
3+
* @param {string} [localName]
4+
* @returns {string}
5+
*/
6+
export function getElementKey(element, localName = element.local) {
7+
/** @type {{n:string,a:Array<string>,c:Array<{}>}} */
8+
const obj = {
9+
n: element.local,
10+
a: getAttributeKey(element, localName),
11+
c: getChildKey(element, localName),
12+
};
13+
return JSON.stringify(obj);
14+
}
15+
16+
// Internal functions
17+
18+
/**
19+
* @param {import('../types.js').XastElement} element
20+
* @param {string} localName
21+
* @returns {Array<string>}
22+
*/
23+
function getAttributeKey(element, localName) {
24+
/** @type {string[]} */
25+
const attStrs = [];
26+
for (const [k, v] of element.svgAtts.entries()) {
27+
if (k === 'id' && element.local === localName) {
28+
continue;
29+
}
30+
attStrs.push(`${k}="${v}"`);
31+
}
32+
return attStrs.sort();
33+
}
34+
35+
/**
36+
* @param {import('../types.js').XastElement} element
37+
* @param {string} localName
38+
* @returns {Array<{}>}
39+
*/
40+
function getChildKey(element, localName) {
41+
/** @type {string[]} */
42+
const childstrs = [];
43+
for (const child of element.children) {
44+
if (child.type === 'element') {
45+
childstrs.push(getElementKey(child, localName));
46+
}
47+
}
48+
return childstrs;
49+
}

0 commit comments

Comments
 (0)