From f756dcf3643be70708c9976d9b4ff240acf4039d Mon Sep 17 00:00:00 2001 From: John Kenny Date: Fri, 20 Sep 2024 07:19:41 -0700 Subject: [PATCH] Add --disable command line option. --- lib/svgo.d.ts | 1 + lib/svgo.js | 2 +- lib/svgo/coa.js | 13 +++-- lib/svgo/plugins.js | 11 +++- test/coa/option.disable.test.js | 96 +++++++++++++++++++++++++++++++++ test/regression.js | 14 +++-- 6 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 test/coa/option.disable.test.js diff --git a/lib/svgo.d.ts b/lib/svgo.d.ts index f898a33..6715e0b 100644 --- a/lib/svgo.d.ts +++ b/lib/svgo.d.ts @@ -74,6 +74,7 @@ export type Config = { plugins?: PluginConfig[]; preset?: 'default' | 'next' | 'none'; enable?: string[]; + disable?: string[]; /** Options for rendering optimized SVG from AST. */ js2svg?: StringifyOptions; /** Output as Data URI string. */ diff --git a/lib/svgo.js b/lib/svgo.js index e79f3c4..927163f 100644 --- a/lib/svgo.js +++ b/lib/svgo.js @@ -161,7 +161,7 @@ export const optimize = (input, config) => { ); } /** @type {import('./svgo.js').Config} */ - const globalOverrides = {}; + const globalOverrides = { disable: config.disable }; if (config.floatPrecision != null) { globalOverrides.floatPrecision = config.floatPrecision; } diff --git a/lib/svgo/coa.js b/lib/svgo/coa.js index 2d8e726..5c42b11 100644 --- a/lib/svgo/coa.js +++ b/lib/svgo/coa.js @@ -59,13 +59,17 @@ export default function makeProgram(program) { 'Specify which set of predefined plugins to use', 'default', ) + .option( + '--config ', + 'Custom config file, only .js, .mjs, and .cjs is supported', + ) .option( '--enable ', - 'Specify one or more builtin plugins to run in addition to the presets', + 'Specify one or more builtin plugins to run in addition to those in the preset or config', ) .option( - '--config ', - 'Custom config file, only .js, .mjs, and .cjs is supported', + '--disable ', + 'Specify one or more plugins from the preset or config which should not be run ', ) .option( '--datauri ', @@ -247,6 +251,9 @@ async function action(args, opts, command) { if (opts.enable) { config.enable = opts.enable; } + if (opts.disable) { + config.disable = opts.disable; + } // --pretty if (opts.pretty) { diff --git a/lib/svgo/plugins.js b/lib/svgo/plugins.js index d79e85e..9a7733c 100644 --- a/lib/svgo/plugins.js +++ b/lib/svgo/plugins.js @@ -31,6 +31,12 @@ export const invokePlugins = ( if (override === false) { continue; } + if ( + globalOverrides.disable && + globalOverrides.disable.includes(plugin.name) + ) { + continue; + } const params = { ...plugin.params, ...globalOverrides, ...override }; const visitor = plugin.fn(ast, params, info); @@ -51,8 +57,9 @@ export const createPreset = ({ name, plugins, description }) => { isPreset: true, plugins: Object.freeze(plugins), fn: (ast, params, info) => { - const { floatPrecision, overrides } = params; - const globalOverrides = {}; + const { floatPrecision, disable, overrides } = params; + /** @type {import('../svgo.js').Config} */ + const globalOverrides = { disable: disable }; if (floatPrecision != null) { globalOverrides.floatPrecision = floatPrecision; } diff --git a/test/coa/option.disable.test.js b/test/coa/option.disable.test.js new file mode 100644 index 0000000..14326ee --- /dev/null +++ b/test/coa/option.disable.test.js @@ -0,0 +1,96 @@ +import fs from 'fs'; +import path from 'path'; +import { Command } from 'commander'; +import { fileURLToPath } from 'url'; +import svgo from '../../lib/svgo/coa.js'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +const tempFolder = 'temp'; + +/** + * @param {string[]} args + */ +function runProgram(args) { + const program = new Command(); + svgo(program); + // prevent running process.exit + program.exitOverride(() => {}); + // parser skips first two arguments + return program.parseAsync(['0', '1', ...args]); +} + +const PLUGINOPT_DIR = path.resolve(__dirname, 'testPluginOpts'); +const PLUGINOPT_FILE1 = path.resolve(PLUGINOPT_DIR, 'test1.svg'); +const PLUGINOPT_FILE1_OPT = path.resolve(tempFolder, 'test1.svg'); + +const EXPECT_NO_CHANGE = + ''; +const EXPECT_TRANS = + ''; + +describe('test --disable option', function () { + afterAll(() => { + fs.rmSync(tempFolder, { force: true, recursive: true }); + }); + + it('should not run convertShapeToPath with --preset=default and --disable=convertShapeToPath', async () => { + await runProgram([ + '-i', + PLUGINOPT_FILE1, + '-o', + PLUGINOPT_FILE1_OPT, + '--quiet', + '--disable=convertShapeToPath', + ]); + const opt = fs.readFileSync(PLUGINOPT_FILE1_OPT, { encoding: 'utf8' }); + expect(opt).toBe(EXPECT_TRANS); + }); + + it('should run multiple plugins with --preset=default and --disable minifyTransforms convertShapeToPath cleanupAttrs', async () => { + await runProgram([ + '-i', + PLUGINOPT_FILE1, + '-o', + PLUGINOPT_FILE1_OPT, + '--quiet', + '--disable', + 'minifyTransforms', + 'convertShapeToPath', + 'cleanupAttrs', + ]); + const opt = fs.readFileSync(PLUGINOPT_FILE1_OPT, { encoding: 'utf8' }); + expect(opt).toBe(EXPECT_NO_CHANGE); + }); + + it('should ignore invalid plugin names', async () => { + await runProgram([ + '-i', + PLUGINOPT_FILE1, + '-o', + PLUGINOPT_FILE1_OPT, + '--quiet', + '--disable', + 'x', + 'convertShapeToPath', + ]); + const opt = fs.readFileSync(PLUGINOPT_FILE1_OPT, { encoding: 'utf8' }); + expect(opt).toBe(EXPECT_TRANS); + }); + + it('should work when plugins are specified in custom config', async () => { + await runProgram([ + '-i', + PLUGINOPT_FILE1, + '-o', + PLUGINOPT_FILE1_OPT, + '--quiet', + '--disable', + 'minifyTransforms', + '--config', + path.resolve(PLUGINOPT_DIR, 'config1.js'), + ]); + const opt = fs.readFileSync(PLUGINOPT_FILE1_OPT, { encoding: 'utf8' }); + expect(opt).toBe(EXPECT_NO_CHANGE); + }); +}); diff --git a/test/regression.js b/test/regression.js index e842480..c8386e4 100644 --- a/test/regression.js +++ b/test/regression.js @@ -35,9 +35,11 @@ async function performTests(options) { let totalCompression = 0; /** @type {import('../lib/svgo.js').Config} */ - const config = {}; - config.preset = options.preset; - config.enable = options.enable; + const config = { + preset: options.preset, + enable: options.enable, + disable: options.disable, + }; /** * @param {string[]} list @@ -180,7 +182,11 @@ program ) .option( '--enable ', - 'Specify one or more builtin plugins to run in addition to the presets', + 'Specify one or more builtin plugins to run in addition to those in the preset or config', + ) + .option( + '--disable ', + 'Specify one or more plugins from the preset or config which should not be run ', ) .option( '--inputdir ',