diff --git a/lib/svgo.js b/lib/svgo.js index e57fb2e1e..e164294c4 100644 --- a/lib/svgo.js +++ b/lib/svgo.js @@ -4,11 +4,21 @@ 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 + */ + const pluginsMap = {}; for (const plugin of builtin) { pluginsMap[plugin.name] = plugin; } +/** + * @template T {any} + * @param {string | PluginConfig} plugin plugin name or plugin config + * @returns {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,11 +87,53 @@ 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 resolvedPluginsWithDisable = disablePlugins + ? resolvedPlugins.filter( + (plugin) => !disablePlugins.includes(plugin.name), + ) + : resolvedPlugins; + + const enablePlugins = config.enable; + if (enablePlugins != null && !Array.isArray(enablePlugins)) { + throw Error('malformed config, `enable` property must be an array.'); + } + + const resolvedEnablePlugins = enablePlugins + ? enablePlugins + .filter((plugin) => plugin != null) + .map(resolvePluginConfig) + : null; + + if ( + resolvedEnablePlugins && + resolvedEnablePlugins.length < enablePlugins.length + ) { + console.warn( + 'Warning: enable plugins list includes null or undefined elements, these will be ignored.', + ); + } + + const resolvedPluginsWithDisableEnable = resolvedEnablePlugins + ? resolvedPluginsWithDisable.concat(resolvedEnablePlugins) + : resolvedPluginsWithDisable; + const globalOverrides = {}; if (config.floatPrecision != null) { globalOverrides.floatPrecision = config.floatPrecision; } - invokePlugins(ast, info, resolvedPlugins, null, globalOverrides); + invokePlugins( + ast, + info, + resolvedPluginsWithDisableEnable, + null, + globalOverrides, + ); output = stringifySvg(ast, config.js2svg); if (output.length < prevResultSize) { input = output; diff --git a/lib/svgo/coa.js b/lib/svgo/coa.js index 62404fc34..0da2a8464 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); diff --git a/lib/types.d.ts b/lib/types.d.ts index 9c6a194e7..e93c5cd15 100644 --- a/lib/types.d.ts +++ b/lib/types.d.ts @@ -111,6 +111,12 @@ export type Plugin = ( info: PluginInfo, ) => Visitor | null | void; +export type PluginConfig = { + name: string; + params: any; + fn: Plugin | null; +}; + export type Specificity = [number, number, number]; export type StylesheetDeclaration = {