diff --git a/lib/svgo.js b/lib/svgo.js index e57fb2e1e..45aed9c45 100644 --- a/lib/svgo.js +++ b/lib/svgo.js @@ -4,11 +4,22 @@ import { builtin } from './builtin.js'; import { invokePlugins } from './svgo/plugins.js'; import { encodeSVGDatauri } from './svgo/tools.js'; +/** + * @template T {any} + * @typedef {import('./types.js').PluginConfig} PluginConfig + * @typedef {import('./types.js').PresetConfig} PresetConfig + */ + const pluginsMap = {}; for (const plugin of builtin) { pluginsMap[plugin.name] = plugin; } +/** + * @template T {any} + * @param {string | PresetConfig| PluginConfig} plugin plugin name or plugin config + * @returns {PresetConfig| PluginConfig | null} plugin config or null if plugin was not found + */ const resolvePluginConfig = (plugin) => { if (typeof plugin === 'string') { // resolve builtin plugin specified as string @@ -77,10 +88,33 @@ export const optimize = (input, config) => { 'Warning: plugins list includes null or undefined elements, these will be ignored.', ); } + + const disablePlugins = config.disable; + if (disablePlugins != null && !Array.isArray(disablePlugins)) { + throw Error('malformed config, `disable` property must be an array.'); + } + + const enablePlugins = config.enable; + if (enablePlugins != null && !Array.isArray(enablePlugins)) { + throw Error('malformed config, `enable` property must be an array.'); + } + const globalOverrides = {}; if (config.floatPrecision != null) { globalOverrides.floatPrecision = config.floatPrecision; } + const overrides = {}; + if (disablePlugins != null) { + for (const plugin of disablePlugins) { + overrides[plugin] = false; + } + } + if (enablePlugins != null) { + for (const plugin of enablePlugins) { + overrides[plugin] = true; + } + } + globalOverrides.overrides = overrides; invokePlugins(ast, info, resolvedPlugins, null, globalOverrides); output = stringifySvg(ast, config.js2svg); if (output.length < prevResultSize) { diff --git a/lib/svgo/coa.js b/lib/svgo/coa.js index 62404fc34..faf6d4496 100644 --- a/lib/svgo/coa.js +++ b/lib/svgo/coa.js @@ -76,6 +76,11 @@ export default function makeProgram(program) { 'Only output error messages, not regular status messages', ) .option('--show-plugins', 'Show available plugins and exit') + .option('--disable ', 'Disable selected plugins') + .option( + '--enable ', + 'Enable selected plugins. Takes precedence over `disable`', + ) // used by picocolors internally .option('--no-color', 'Output plain text without color') .action(action); @@ -272,6 +277,14 @@ async function action(args, opts, command) { return processSVGData(config, null, data, output[0]); } + + if (opts.disable) { + config.disable = opts.disable; + } + + if (opts.enable) { + config.enable = opts.enable; + } } /** diff --git a/lib/types.d.ts b/lib/types.d.ts index 9c6a194e7..4eba513fe 100644 --- a/lib/types.d.ts +++ b/lib/types.d.ts @@ -111,6 +111,17 @@ export type Plugin = ( info: PluginInfo, ) => Visitor | null | void; +export type PluginConfig = { + name: string; + params: any; + fn: Plugin | null; +}; + +export type PresetConfig = { + name: string; + plugins: PluginConfig[]; +}; + export type Specificity = [number, number, number]; export type StylesheetDeclaration = {