Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --enable command line option. #2

Merged
merged 1 commit into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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