From 773eca4c8defc07627f3c52c4b619c8656ff2787 Mon Sep 17 00:00:00 2001 From: Wojciech Maj Date: Mon, 8 Apr 2024 15:39:18 +0200 Subject: [PATCH] feat: add support for `--disable` and `--enable` flags back Closes #1356 Closes #1622 In https://github.com/svg/svgo/issues/1622#issuecomment-971440346 we read: > I consider adding it back at some point but it should be able to work with presets somehow. This is still need to be figured out. I believe that adding it at the very last possible moment, AFTER initial list is resolved, will make it work with presets, and preserve the original behavior if the options aren't used at all. I've also increased JSDoc coverage here, mainly for my own sanity when working with these arrays of plugins. Hope you don't mind that scope creep :) --- lib/svgo.js | 34 ++++++++++++++++++++++++++++++++++ lib/svgo/coa.js | 13 +++++++++++++ lib/types.d.ts | 11 +++++++++++ 3 files changed, 58 insertions(+) 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 = {