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>
144 lines
3.9 KiB
JavaScript
Executable File
144 lines
3.9 KiB
JavaScript
Executable File
import { builtinPlugins } from './builtin.js';
|
|
import { encodeSVGDatauri } from './svgo/tools.js';
|
|
import { invokePlugins } from './svgo/plugins.js';
|
|
import { querySelector, querySelectorAll } from './xast.js';
|
|
import { mapNodesToParents } from './util/map-nodes-to-parents.js';
|
|
import { parseSvg } from './parser.js';
|
|
import { stringifySvg } from './stringifier.js';
|
|
import { VERSION } from './version.js';
|
|
import * as _collections from '../plugins/_collections.js';
|
|
|
|
const pluginsMap = new Map();
|
|
for (const plugin of builtinPlugins) {
|
|
pluginsMap.set(plugin.name, plugin);
|
|
}
|
|
|
|
/**
|
|
* @param {string} name
|
|
* @returns {import('./types.js').BuiltinPluginOrPreset<?, ?>}
|
|
*/
|
|
function getPlugin(name) {
|
|
if (name === 'removeScriptElement') {
|
|
console.warn(
|
|
'Warning: removeScriptElement has been renamed to removeScripts, please update your SVGO config',
|
|
);
|
|
return pluginsMap.get('removeScripts');
|
|
}
|
|
|
|
return pluginsMap.get(name);
|
|
}
|
|
|
|
/**
|
|
* @param {string | import('./types.js').PluginConfig} plugin
|
|
* @returns {?import('./types.js').PluginConfig}
|
|
*/
|
|
const resolvePluginConfig = (plugin) => {
|
|
if (typeof plugin === 'string') {
|
|
// resolve builtin plugin specified as string
|
|
const builtinPlugin = getPlugin(plugin);
|
|
if (builtinPlugin == null) {
|
|
throw Error(`Unknown builtin plugin "${plugin}" specified.`);
|
|
}
|
|
return {
|
|
name: plugin,
|
|
params: {},
|
|
fn: builtinPlugin.fn,
|
|
};
|
|
}
|
|
if (typeof plugin === 'object' && plugin != null) {
|
|
if (plugin.name == null) {
|
|
throw Error(`Plugin name must be specified`);
|
|
}
|
|
// use custom plugin implementation
|
|
// @ts-expect-error Checking for CustomPlugin with the presence of fn
|
|
let fn = plugin.fn;
|
|
if (fn == null) {
|
|
// resolve builtin plugin implementation
|
|
const builtinPlugin = getPlugin(plugin.name);
|
|
if (builtinPlugin == null) {
|
|
throw Error(`Unknown builtin plugin "${plugin.name}" specified.`);
|
|
}
|
|
fn = builtinPlugin.fn;
|
|
}
|
|
return {
|
|
name: plugin.name,
|
|
params: plugin.params,
|
|
fn,
|
|
};
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export * from './types.js';
|
|
|
|
/**
|
|
* The core of SVGO.
|
|
*
|
|
* @param {string} input
|
|
* @param {import('./types.js').Config=} config
|
|
* @returns {import('./types.js').Output}
|
|
*/
|
|
export const optimize = (input, config) => {
|
|
if (config == null) {
|
|
config = {};
|
|
}
|
|
if (typeof config !== 'object') {
|
|
throw Error('Config should be an object');
|
|
}
|
|
const maxPassCount = config.multipass ? 10 : 1;
|
|
let prevResultSize = Number.POSITIVE_INFINITY;
|
|
let output = '';
|
|
const info = {};
|
|
if (config.path != null) {
|
|
info.path = config.path;
|
|
}
|
|
for (let i = 0; i < maxPassCount; i += 1) {
|
|
info.multipassCount = i;
|
|
const ast = parseSvg(input, config.path);
|
|
const plugins = config.plugins || ['preset-default'];
|
|
if (!Array.isArray(plugins)) {
|
|
throw Error(
|
|
'malformed config, `plugins` property must be an array.\nSee more info here: https://github.com/svg/svgo#configuration',
|
|
);
|
|
}
|
|
const resolvedPlugins = plugins
|
|
.filter((plugin) => plugin != null)
|
|
.map(resolvePluginConfig);
|
|
|
|
if (resolvedPlugins.length < plugins.length) {
|
|
console.warn(
|
|
'Warning: plugins list includes null or undefined elements, these will be ignored.',
|
|
);
|
|
}
|
|
|
|
/** @type {import('./types.js').Config} */
|
|
const globalOverrides = {};
|
|
if (config.floatPrecision != null) {
|
|
globalOverrides.floatPrecision = config.floatPrecision;
|
|
}
|
|
invokePlugins(ast, info, resolvedPlugins, null, globalOverrides);
|
|
output = stringifySvg(ast, config.js2svg);
|
|
if (output.length < prevResultSize) {
|
|
input = output;
|
|
prevResultSize = output.length;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (config.datauri) {
|
|
output = encodeSVGDatauri(output, config.datauri);
|
|
}
|
|
return {
|
|
data: output,
|
|
};
|
|
};
|
|
|
|
export {
|
|
VERSION,
|
|
builtinPlugins,
|
|
mapNodesToParents,
|
|
querySelector,
|
|
querySelectorAll,
|
|
_collections,
|
|
};
|