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:
246
node_modules/svgo/plugins/prefixIds.js
generated
vendored
246
node_modules/svgo/plugins/prefixIds.js
generated
vendored
@@ -1,25 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
const csstree = require('css-tree');
|
||||
const { referencesProps } = require('./_collections.js');
|
||||
import * as csstree from 'css-tree';
|
||||
import { referencesProps } from './_collections.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('../lib/types').XastElement} XastElement
|
||||
* @typedef {import('../lib/types').PluginInfo} PluginInfo
|
||||
* @typedef PrefixIdsParams
|
||||
* @property {boolean | string | ((node: import('../lib/types.js').XastElement, info: import('../lib/types.js').PluginInfo) => string)=} prefix
|
||||
* @property {string=} delim
|
||||
* @property {boolean=} prefixIds
|
||||
* @property {boolean=} prefixClassNames
|
||||
*/
|
||||
|
||||
exports.type = 'visitor';
|
||||
exports.name = 'prefixIds';
|
||||
exports.active = false;
|
||||
exports.description = 'prefix IDs';
|
||||
export const name = 'prefixIds';
|
||||
export const description = 'prefix IDs';
|
||||
|
||||
/**
|
||||
* extract basename from path
|
||||
* @type {(path: string) => string}
|
||||
* Extract basename from path.
|
||||
*
|
||||
* @param {string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
const getBasename = (path) => {
|
||||
// extract everything after latest slash or backslash
|
||||
const matched = path.match(/[/\\]?([^/\\]+)$/);
|
||||
const matched = /[/\\]?([^/\\]+)$/.exec(path);
|
||||
if (matched) {
|
||||
return matched[1];
|
||||
}
|
||||
@@ -27,15 +28,18 @@ const getBasename = (path) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* escapes a string for being used as ID
|
||||
* @type {(string: string) => string}
|
||||
* Escapes a string for being used as ID.
|
||||
*
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
const escapeIdentifierName = (str) => {
|
||||
return str.replace(/[. ]/g, '_');
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {(string: string) => string}
|
||||
* @param {string} string
|
||||
* @returns {string}
|
||||
*/
|
||||
const unquote = (string) => {
|
||||
if (
|
||||
@@ -48,59 +52,100 @@ const unquote = (string) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* prefix an ID
|
||||
* @type {(prefix: string, name: string) => string}
|
||||
* Prefix the given string, unless it already starts with the generated prefix.
|
||||
*
|
||||
* @param {(id: string) => string} prefixGenerator Function to generate a prefix.
|
||||
* @param {string} body An arbitrary string.
|
||||
* @returns {string} The given string with a prefix prepended to it.
|
||||
*/
|
||||
const prefixId = (prefix, value) => {
|
||||
if (value.startsWith(prefix)) {
|
||||
return value;
|
||||
const prefixId = (prefixGenerator, body) => {
|
||||
const prefix = prefixGenerator(body);
|
||||
if (body.startsWith(prefix)) {
|
||||
return body;
|
||||
}
|
||||
return prefix + value;
|
||||
return prefix + body;
|
||||
};
|
||||
|
||||
/**
|
||||
* prefix an #ID
|
||||
* @type {(prefix: string, name: string) => string | null}
|
||||
* Insert the prefix in a reference string. A reference string is already
|
||||
* prefixed with #, so the prefix is inserted after the first character.
|
||||
*
|
||||
* @param {(id: string) => string} prefixGenerator Function to generate a prefix.
|
||||
* @param {string} reference An arbitrary string, should start with "#".
|
||||
* @returns {?string} The given string with a prefix inserted, or null if the string did not start with "#".
|
||||
*/
|
||||
const prefixReference = (prefix, value) => {
|
||||
if (value.startsWith('#')) {
|
||||
return '#' + prefixId(prefix, value.slice(1));
|
||||
const prefixReference = (prefixGenerator, reference) => {
|
||||
if (reference.startsWith('#')) {
|
||||
return '#' + prefixId(prefixGenerator, reference.slice(1));
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a prefix for the given string.
|
||||
*
|
||||
* @param {string} body An arbitrary string.
|
||||
* @param {import('../lib/types.js').XastElement} node XML node that the identifier belongs to.
|
||||
* @param {import('../lib/types.js').PluginInfo} info
|
||||
* @param {((node: import('../lib/types.js').XastElement, info: import('../lib/types.js').PluginInfo) => string) | string | boolean | undefined} prefixGenerator Some way of obtaining a prefix.
|
||||
* @param {string} delim Content to insert between the prefix and original value.
|
||||
* @param {Map<string, string>} history Map of previously generated prefixes to IDs.
|
||||
* @returns {string} A generated prefix.
|
||||
*/
|
||||
const generatePrefix = (body, node, info, prefixGenerator, delim, history) => {
|
||||
if (typeof prefixGenerator === 'function') {
|
||||
let prefix = history.get(body);
|
||||
|
||||
if (prefix != null) {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
prefix = prefixGenerator(node, info) + delim;
|
||||
history.set(body, prefix);
|
||||
return prefix;
|
||||
}
|
||||
|
||||
if (typeof prefixGenerator === 'string') {
|
||||
return prefixGenerator + delim;
|
||||
}
|
||||
|
||||
if (prefixGenerator === false) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (info.path != null && info.path.length > 0) {
|
||||
return escapeIdentifierName(getBasename(info.path)) + delim;
|
||||
}
|
||||
|
||||
return 'prefix' + delim;
|
||||
};
|
||||
|
||||
/**
|
||||
* Prefixes identifiers
|
||||
*
|
||||
* @author strarsis <strarsis@gmail.com>
|
||||
*
|
||||
* @type {import('../lib/types').Plugin<{
|
||||
* prefix?: boolean | string | ((node: XastElement, info: PluginInfo) => string),
|
||||
* delim?: string,
|
||||
* prefixIds?: boolean,
|
||||
* prefixClassNames?: boolean,
|
||||
* }>}
|
||||
* @type {import('../lib/types.js').Plugin<PrefixIdsParams>}
|
||||
*/
|
||||
exports.fn = (_root, params, info) => {
|
||||
const { delim = '__', prefixIds = true, prefixClassNames = true } = params;
|
||||
export const fn = (_root, params, info) => {
|
||||
const {
|
||||
delim = '__',
|
||||
prefix,
|
||||
prefixIds = true,
|
||||
prefixClassNames = true,
|
||||
} = params;
|
||||
|
||||
/** @type {Map<string, string>} */
|
||||
const prefixMap = new Map();
|
||||
|
||||
return {
|
||||
element: {
|
||||
enter: (node) => {
|
||||
/**
|
||||
* prefix, from file name or option
|
||||
* @type {string}
|
||||
* @param {string} id A node identifier or class.
|
||||
* @returns {string} Given string with a prefix inserted, or null if the string did not start with "#".
|
||||
*/
|
||||
let prefix = 'prefix' + delim;
|
||||
if (typeof params.prefix === 'function') {
|
||||
prefix = params.prefix(node, info) + delim;
|
||||
} else if (typeof params.prefix === 'string') {
|
||||
prefix = params.prefix + delim;
|
||||
} else if (params.prefix === false) {
|
||||
prefix = '';
|
||||
} else if (info.path != null && info.path.length > 0) {
|
||||
prefix = escapeIdentifierName(getBasename(info.path)) + delim;
|
||||
}
|
||||
const prefixGenerator = (id) =>
|
||||
generatePrefix(id, node, info, prefix, delim, prefixMap);
|
||||
|
||||
// prefix id/class selectors and url() references in styles
|
||||
if (node.name === 'style') {
|
||||
@@ -109,60 +154,44 @@ exports.fn = (_root, params, info) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// parse styles
|
||||
let cssText = '';
|
||||
if (
|
||||
node.children[0].type === 'text' ||
|
||||
node.children[0].type === 'cdata'
|
||||
) {
|
||||
cssText = node.children[0].value;
|
||||
}
|
||||
/**
|
||||
* @type {null | csstree.CssNode}
|
||||
*/
|
||||
let cssAst = null;
|
||||
try {
|
||||
cssAst = csstree.parse(cssText, {
|
||||
parseValue: true,
|
||||
parseCustomProperty: false,
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
for (const child of node.children) {
|
||||
if (child.type !== 'text' && child.type !== 'cdata') {
|
||||
continue;
|
||||
}
|
||||
|
||||
csstree.walk(cssAst, (node) => {
|
||||
// #ID, .class selectors
|
||||
if (
|
||||
(prefixIds && node.type === 'IdSelector') ||
|
||||
(prefixClassNames && node.type === 'ClassSelector')
|
||||
) {
|
||||
node.name = prefixId(prefix, node.name);
|
||||
const cssText = child.value;
|
||||
/** @type {?csstree.CssNode} */
|
||||
let cssAst;
|
||||
try {
|
||||
cssAst = csstree.parse(cssText, {
|
||||
parseValue: true,
|
||||
parseCustomProperty: false,
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
// url(...) references
|
||||
if (
|
||||
node.type === 'Url' &&
|
||||
node.value.value &&
|
||||
node.value.value.length > 0
|
||||
) {
|
||||
const prefixed = prefixReference(
|
||||
prefix,
|
||||
unquote(node.value.value)
|
||||
);
|
||||
if (prefixed != null) {
|
||||
node.value.value = prefixed;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// update styles
|
||||
if (
|
||||
node.children[0].type === 'text' ||
|
||||
node.children[0].type === 'cdata'
|
||||
) {
|
||||
node.children[0].value = csstree.generate(cssAst);
|
||||
csstree.walk(cssAst, (node) => {
|
||||
if (
|
||||
(prefixIds && node.type === 'IdSelector') ||
|
||||
(prefixClassNames && node.type === 'ClassSelector')
|
||||
) {
|
||||
node.name = prefixId(prefixGenerator, node.name);
|
||||
return;
|
||||
}
|
||||
if (node.type === 'Url' && node.value.length > 0) {
|
||||
const prefixed = prefixReference(
|
||||
prefixGenerator,
|
||||
unquote(node.value),
|
||||
);
|
||||
if (prefixed != null) {
|
||||
node.value = prefixed;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
child.value = csstree.generate(cssAst);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// prefix an ID attribute value
|
||||
@@ -171,7 +200,7 @@ exports.fn = (_root, params, info) => {
|
||||
node.attributes.id != null &&
|
||||
node.attributes.id.length !== 0
|
||||
) {
|
||||
node.attributes.id = prefixId(prefix, node.attributes.id);
|
||||
node.attributes.id = prefixId(prefixGenerator, node.attributes.id);
|
||||
}
|
||||
|
||||
// prefix a class attribute value
|
||||
@@ -182,39 +211,42 @@ exports.fn = (_root, params, info) => {
|
||||
) {
|
||||
node.attributes.class = node.attributes.class
|
||||
.split(/\s+/)
|
||||
.map((name) => prefixId(prefix, name))
|
||||
.map((name) => prefixId(prefixGenerator, name))
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
// prefix a href attribute value
|
||||
// prefix an href attribute value
|
||||
// xlink:href is deprecated, must be still supported
|
||||
for (const name of ['href', 'xlink:href']) {
|
||||
if (
|
||||
node.attributes[name] != null &&
|
||||
node.attributes[name].length !== 0
|
||||
) {
|
||||
const prefixed = prefixReference(prefix, node.attributes[name]);
|
||||
const prefixed = prefixReference(
|
||||
prefixGenerator,
|
||||
node.attributes[name],
|
||||
);
|
||||
if (prefixed != null) {
|
||||
node.attributes[name] = prefixed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prefix an URL attribute value
|
||||
// prefix a URL attribute value
|
||||
for (const name of referencesProps) {
|
||||
if (
|
||||
node.attributes[name] != null &&
|
||||
node.attributes[name].length !== 0
|
||||
) {
|
||||
node.attributes[name] = node.attributes[name].replace(
|
||||
/url\((.*?)\)/gi,
|
||||
(match, url) => {
|
||||
const prefixed = prefixReference(prefix, url);
|
||||
/\burl\((["'])?(#.+?)\1\)/gi,
|
||||
(match, _, url) => {
|
||||
const prefixed = prefixReference(prefixGenerator, url);
|
||||
if (prefixed == null) {
|
||||
return match;
|
||||
}
|
||||
return `url(${prefixed})`;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -228,7 +260,7 @@ exports.fn = (_root, params, info) => {
|
||||
const parts = node.attributes[name].split(/\s*;\s+/).map((val) => {
|
||||
if (val.endsWith('.end') || val.endsWith('.start')) {
|
||||
const [id, postfix] = val.split('.');
|
||||
return `${prefixId(prefix, id)}.${postfix}`;
|
||||
return `${prefixId(prefixGenerator, id)}.${postfix}`;
|
||||
}
|
||||
return val;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user