Skip to content

Commit

Permalink
Add --enable command line option.
Browse files Browse the repository at this point in the history
  • Loading branch information
johnkenny54 committed Sep 17, 2024
1 parent 28ee1f1 commit c604107
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 27 deletions.
1 change: 1 addition & 0 deletions lib/svgo.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export type Config = {
*/
plugins?: PluginConfig[];
preset?: 'default' | 'none';
enable?: string[];
/** Options for rendering optimized SVG from AST. */
js2svg?: StringifyOptions;
/** Output as Data URI string. */
Expand Down
32 changes: 25 additions & 7 deletions lib/svgo.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,34 @@ export const optimize = (input, config) => {
* @returns {import('svgo-ll').PluginConfig[]}
*/
function getPlugins(config) {
if (config.plugins) {
return config.plugins;
/**
* @returns {import('svgo-ll').PluginConfig[]}
*/
function getPreset() {
if (config.plugins) {
return config.plugins;
}
if (config.preset) {
if (builtinPresets.has(config.preset)) {
return [`preset-${config.preset}`];
}
console.warn(`invalid preset "${config.preset}"; using preset-default`);
}
return ['preset-default'];
}
if (config.preset) {
if (builtinPresets.has(config.preset)) {
return [`preset-${config.preset}`];

const presets = getPreset();
if (config.enable) {
for (const builtinName of config.enable) {
const builtin = pluginsMap.get(builtinName);
if (builtin) {
presets.push(builtin);
} else {
console.warn(`plugin "${builtinName}" not found`);
}
}
console.warn(`invalid preset "${config.preset}"; using preset-default`);
}
return ['preset-default'];
return presets;
}

if (!config) {
Expand Down
10 changes: 9 additions & 1 deletion lib/svgo/coa.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,13 @@ export default function makeProgram(program) {
)
.option(
'--preset <default | none>',
'Specify which set of predefined plugins to use.',
'Specify which set of predefined plugins to use',
'default',
)
.option(
'--enable <plugin...>',
'Specify one or more builtin plugins to run in addition to the presets',
)
.option(
'--config <CONFIG>',
'Custom config file, only .js, .mjs, and .cjs is supported',
Expand Down Expand Up @@ -240,6 +244,10 @@ async function action(args, opts, command) {
}
}

if (opts.enable) {
config.enable = opts.enable;
}

// --pretty
if (opts.pretty) {
config.js2svg = config.js2svg || {};
Expand Down
132 changes: 113 additions & 19 deletions test/coa/_index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,34 +180,45 @@ describe('coa', function () {
});
});

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_TRANS =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect x="10" y="20" width="10" height="20" transform="translate(10 20)"/></svg>';
const EXPECT_TRANS_PATH =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path transform="translate(10 20)" d="M10 20h10v20H10z"/></svg>';
const EXPECT_TRANS_PATH_SORTED =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M10 20h10v20H10z" transform="translate(10 20)"/></svg>';

describe('test preset option', function () {
afterAll(() => {
fs.rmSync(tempFolder, { force: true, recursive: true });
});

const dirName = path.resolve(__dirname, 'testPreset');
const svg1 = path.resolve(dirName, 'test1.svg');
const svg1Opt = path.resolve(tempFolder, 'test1.svg');

it('should use default preset when option not specified', async () => {
await runProgram(['-i', svg1, '-o', svg1Opt, '--quiet']);
const opt = fs.readFileSync(svg1Opt, { encoding: 'utf8' });
expect(opt).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path transform="translate(10 20)" d="M10 20h10v20H10z"/></svg>',
);
await runProgram([
'-i',
PLUGINOPT_FILE1,
'-o',
PLUGINOPT_FILE1_OPT,
'--quiet',
]);
const opt = fs.readFileSync(PLUGINOPT_FILE1_OPT, { encoding: 'utf8' });
expect(opt).toBe(EXPECT_TRANS_PATH);
});

it('should only remove whitespace when "none" specified', async () => {
await runProgram([
'-i',
svg1,
PLUGINOPT_FILE1,
'-o',
svg1Opt,
PLUGINOPT_FILE1_OPT,
'--quiet',
'--preset',
'none',
]);
const opt = fs.readFileSync(svg1Opt, { encoding: 'utf8' });
const opt = fs.readFileSync(PLUGINOPT_FILE1_OPT, { encoding: 'utf8' });
expect(opt).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect x="10" y="20" width="10" height="20" transform="matrix(1 0 0 1 10 20) "/></svg>',
);
Expand All @@ -216,18 +227,101 @@ describe('test preset option', function () {
it('should only minify transform when "none" specified, but custom config is used', async () => {
await runProgram([
'-i',
svg1,
PLUGINOPT_FILE1,
'-o',
svg1Opt,
PLUGINOPT_FILE1_OPT,
'--quiet',
'--preset',
'none',
'--config',
path.resolve(dirName, 'config1.js'),
path.resolve(PLUGINOPT_DIR, 'config1.js'),
]);
const opt = fs.readFileSync(svg1Opt, { encoding: 'utf8' });
expect(opt).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect x="10" y="20" width="10" height="20" transform="translate(10 20)"/></svg>',
);
const opt = fs.readFileSync(PLUGINOPT_FILE1_OPT, { encoding: 'utf8' });
expect(opt).toBe(EXPECT_TRANS);
});
});

describe('test --enable option', function () {
afterAll(() => {
fs.rmSync(tempFolder, { force: true, recursive: true });
});

it('should only run one plugin with --preset=none and --enable=minifyTransforms', async () => {
await runProgram([
'-i',
PLUGINOPT_FILE1,
'-o',
PLUGINOPT_FILE1_OPT,
'--quiet',
'--preset=none',
'--enable=minifyTransforms',
]);
const opt = fs.readFileSync(PLUGINOPT_FILE1_OPT, { encoding: 'utf8' });
expect(opt).toBe(EXPECT_TRANS);
});

it('should run two plugins with --preset=none and --enable minifyTransforms convertShapeToPath minifyPathData', async () => {
await runProgram([
'-i',
PLUGINOPT_FILE1,
'-o',
PLUGINOPT_FILE1_OPT,
'--quiet',
'--preset=none',
'--enable',
'minifyTransforms',
'convertShapeToPath',
'minifyPathData',
]);
const opt = fs.readFileSync(PLUGINOPT_FILE1_OPT, { encoding: 'utf8' });
expect(opt).toBe(EXPECT_TRANS_PATH);
});

it('should ignore invalid plugin names', async () => {
await runProgram([
'-i',
PLUGINOPT_FILE1,
'-o',
PLUGINOPT_FILE1_OPT,
'--quiet',
'--preset=none',
'--enable',
'x',
'minifyTransforms',
]);
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',
'--preset=none',
'--enable',
'convertShapeToPath',
'minifyPathData',
'--config',
path.resolve(PLUGINOPT_DIR, 'config1.js'),
]);
const opt = fs.readFileSync(PLUGINOPT_FILE1_OPT, { encoding: 'utf8' });
expect(opt).toBe(EXPECT_TRANS_PATH);
});

it('should work with preset-default', async () => {
await runProgram([
'-i',
PLUGINOPT_FILE1,
'-o',
PLUGINOPT_FILE1_OPT,
'--quiet',
'--enable',
'sortAttrs',
]);
const opt = fs.readFileSync(PLUGINOPT_FILE1_OPT, { encoding: 'utf8' });
expect(opt).toBe(EXPECT_TRANS_PATH_SORTED);
});
});
File renamed without changes.
File renamed without changes

0 comments on commit c604107

Please sign in to comment.