Fix code quality violations and exclude Manifest from checks
Document application modes (development/debug/production) Add global file drop handler, order column normalization, SPA hash fix Serve CDN assets via /_vendor/ URLs instead of merging into bundles Add production minification with license preservation Improve JSON formatting for debugging and production optimization Add CDN asset caching with CSS URL inlining for production builds Add three-mode system (development, debug, production) Update Manifest CLAUDE.md to reflect helper class architecture Refactor Manifest.php into helper classes for better organization Pre-manifest-refactor checkpoint: Add app_mode documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
166
node_modules/svgo/plugins/reusePaths.js
generated
vendored
166
node_modules/svgo/plugins/reusePaths.js
generated
vendored
@@ -1,17 +1,8 @@
|
||||
'use strict';
|
||||
import { collectStylesheet } from '../lib/style.js';
|
||||
import { detachNodeFromParent, querySelectorAll } from '../lib/xast.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('../lib/types').XastElement} XastElement
|
||||
* @typedef {import('../lib/types').XastParent} XastParent
|
||||
* @typedef {import('../lib/types').XastNode} XastNode
|
||||
*/
|
||||
|
||||
const JSAPI = require('../lib/svgo/jsAPI.js');
|
||||
|
||||
exports.type = 'visitor';
|
||||
exports.name = 'reusePaths';
|
||||
exports.active = false;
|
||||
exports.description =
|
||||
export const name = 'reusePaths';
|
||||
export const description =
|
||||
'Finds <path> elements with the same d, fill, and ' +
|
||||
'stroke, and converts them to <use> elements ' +
|
||||
'referencing a single <path> def.';
|
||||
@@ -22,17 +13,33 @@ exports.description =
|
||||
*
|
||||
* @author Jacob Howcroft
|
||||
*
|
||||
* @type {import('../lib/types').Plugin<void>}
|
||||
* @type {import('../lib/types.js').Plugin}
|
||||
*/
|
||||
exports.fn = () => {
|
||||
/**
|
||||
* @type {Map<string, Array<XastElement>>}
|
||||
*/
|
||||
export const fn = (root) => {
|
||||
const stylesheet = collectStylesheet(root);
|
||||
|
||||
/** @type {Map<string, import('../lib/types.js').XastElement[]>} */
|
||||
const paths = new Map();
|
||||
|
||||
/**
|
||||
* Reference to the first defs element that is a direct child of the svg
|
||||
* element if one exists.
|
||||
*
|
||||
* @type {import('../lib/types.js').XastElement}
|
||||
* @see https://developer.mozilla.org/docs/Web/SVG/Element/defs
|
||||
*/
|
||||
let svgDefs;
|
||||
|
||||
/**
|
||||
* Set of hrefs that reference the id of another node.
|
||||
*
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
const hrefs = new Set();
|
||||
|
||||
return {
|
||||
element: {
|
||||
enter: (node) => {
|
||||
enter: (node, parentNode) => {
|
||||
if (node.name === 'path' && node.attributes.d != null) {
|
||||
const d = node.attributes.d;
|
||||
const fill = node.attributes.fill || '';
|
||||
@@ -45,58 +52,110 @@ exports.fn = () => {
|
||||
}
|
||||
list.push(node);
|
||||
}
|
||||
|
||||
if (
|
||||
svgDefs == null &&
|
||||
node.name === 'defs' &&
|
||||
parentNode.type === 'element' &&
|
||||
parentNode.name === 'svg'
|
||||
) {
|
||||
svgDefs = node;
|
||||
}
|
||||
|
||||
if (node.name === 'use') {
|
||||
for (const name of ['href', 'xlink:href']) {
|
||||
const href = node.attributes[name];
|
||||
|
||||
if (href != null && href.startsWith('#') && href.length > 1) {
|
||||
hrefs.add(href.slice(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
exit: (node, parentNode) => {
|
||||
if (node.name === 'svg' && parentNode.type === 'root') {
|
||||
/**
|
||||
* @type {XastElement}
|
||||
*/
|
||||
const rawDefs = {
|
||||
type: 'element',
|
||||
name: 'defs',
|
||||
attributes: {},
|
||||
children: [],
|
||||
};
|
||||
/**
|
||||
* @type {XastElement}
|
||||
*/
|
||||
const defsTag = new JSAPI(rawDefs, node);
|
||||
let defsTag = svgDefs;
|
||||
|
||||
if (defsTag == null) {
|
||||
defsTag = {
|
||||
type: 'element',
|
||||
name: 'defs',
|
||||
attributes: {},
|
||||
children: [],
|
||||
};
|
||||
}
|
||||
|
||||
let index = 0;
|
||||
for (const list of paths.values()) {
|
||||
if (list.length > 1) {
|
||||
// add reusable path to defs
|
||||
/**
|
||||
* @type {XastElement}
|
||||
*/
|
||||
const rawPath = {
|
||||
/** @type {import('../lib/types.js').XastElement} */
|
||||
const reusablePath = {
|
||||
type: 'element',
|
||||
name: 'path',
|
||||
attributes: { ...list[0].attributes },
|
||||
attributes: {},
|
||||
children: [],
|
||||
};
|
||||
delete rawPath.attributes.transform;
|
||||
let id;
|
||||
if (rawPath.attributes.id == null) {
|
||||
id = 'reuse-' + index;
|
||||
index += 1;
|
||||
rawPath.attributes.id = id;
|
||||
|
||||
for (const attr of ['fill', 'stroke', 'd']) {
|
||||
if (list[0].attributes[attr] != null) {
|
||||
reusablePath.attributes[attr] = list[0].attributes[attr];
|
||||
}
|
||||
}
|
||||
|
||||
const originalId = list[0].attributes.id;
|
||||
if (
|
||||
originalId == null ||
|
||||
hrefs.has(originalId) ||
|
||||
stylesheet.rules.some(
|
||||
(rule) => rule.selector === `#${originalId}`,
|
||||
)
|
||||
) {
|
||||
reusablePath.attributes.id = 'reuse-' + index++;
|
||||
} else {
|
||||
id = rawPath.attributes.id;
|
||||
reusablePath.attributes.id = originalId;
|
||||
delete list[0].attributes.id;
|
||||
}
|
||||
/**
|
||||
* @type {XastElement}
|
||||
*/
|
||||
const reusablePath = new JSAPI(rawPath, defsTag);
|
||||
defsTag.children.push(reusablePath);
|
||||
// convert paths to <use>
|
||||
for (const pathNode of list) {
|
||||
pathNode.name = 'use';
|
||||
pathNode.attributes['xlink:href'] = '#' + id;
|
||||
delete pathNode.attributes.d;
|
||||
delete pathNode.attributes.stroke;
|
||||
delete pathNode.attributes.fill;
|
||||
|
||||
if (
|
||||
defsTag.children.includes(pathNode) &&
|
||||
pathNode.children.length === 0
|
||||
) {
|
||||
if (Object.keys(pathNode.attributes).length === 0) {
|
||||
detachNodeFromParent(pathNode, defsTag);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
Object.keys(pathNode.attributes).length === 1 &&
|
||||
pathNode.attributes.id != null
|
||||
) {
|
||||
detachNodeFromParent(pathNode, defsTag);
|
||||
const selector = `[xlink\\:href=#${pathNode.attributes.id}], [href=#${pathNode.attributes.id}]`;
|
||||
for (const child of querySelectorAll(node, selector)) {
|
||||
if (child.type !== 'element') {
|
||||
continue;
|
||||
}
|
||||
for (const name of ['href', 'xlink:href']) {
|
||||
if (child.attributes[name] != null) {
|
||||
child.attributes[name] =
|
||||
'#' + reusablePath.attributes.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
pathNode.name = 'use';
|
||||
pathNode.attributes['xlink:href'] =
|
||||
'#' + reusablePath.attributes.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,7 +163,10 @@ exports.fn = () => {
|
||||
if (node.attributes['xmlns:xlink'] == null) {
|
||||
node.attributes['xmlns:xlink'] = 'http://www.w3.org/1999/xlink';
|
||||
}
|
||||
node.children.unshift(defsTag);
|
||||
|
||||
if (svgDefs == null) {
|
||||
node.children.unshift(defsTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user