From 0c13740fddcb996768d978135308dadf0217d88c Mon Sep 17 00:00:00 2001 From: Seth Falco Date: Sun, 9 Jun 2024 12:28:37 +0100 Subject: [PATCH] feat: expose builtin plugins (#2027) --- lib/svgo-node.d.ts | 4 ++-- lib/svgo-node.js | 9 +++++++-- lib/svgo.d.ts | 26 ++++++++++++++++++++++++++ lib/svgo.js | 3 ++- lib/svgo/plugins.js | 2 ++ plugins/plugins-types.d.ts | 3 ++- test/browser.js | 5 ++++- test/svgo.cjs | 8 +++++++- test/svgo/_index.test.js | 8 +++++++- 9 files changed, 59 insertions(+), 9 deletions(-) diff --git a/lib/svgo-node.d.ts b/lib/svgo-node.d.ts index 03e37dab4..709be2a2a 100644 --- a/lib/svgo-node.d.ts +++ b/lib/svgo-node.d.ts @@ -1,6 +1,6 @@ -import { VERSION, Config, optimize } from './svgo'; +import { VERSION, Config, optimize, builtinPlugins } from './svgo'; -export { VERSION, optimize }; +export { VERSION, optimize, builtinPlugins }; /** * If you write a tool on top of svgo you might need a way to load svgo config. diff --git a/lib/svgo-node.js b/lib/svgo-node.js index dc3a6df54..406eaaa9a 100644 --- a/lib/svgo-node.js +++ b/lib/svgo-node.js @@ -2,7 +2,11 @@ import os from 'os'; import fs from 'fs'; import { pathToFileURL } from 'url'; import path from 'path'; -import { VERSION, optimize as optimizeAgnostic } from './svgo.js'; +import { + VERSION, + optimize as optimizeAgnostic, + builtinPlugins, +} from './svgo.js'; const importConfig = async (configFile) => { // dynamic import expects file url instead of path and may fail @@ -25,7 +29,7 @@ const isFile = async (file) => { } }; -export { VERSION }; +export { VERSION, builtinPlugins }; export const loadConfig = async (configFile, cwd = process.cwd()) => { if (configFile != null) { @@ -77,6 +81,7 @@ export const optimize = (input, config) => { export default { VERSION, + builtinPlugins, loadConfig, optimize, }; diff --git a/lib/svgo.d.ts b/lib/svgo.d.ts index f1151184c..f4a6401ec 100644 --- a/lib/svgo.d.ts +++ b/lib/svgo.d.ts @@ -2,6 +2,7 @@ import type { StringifyOptions, DataUri, Plugin } from './types.js'; import type { BuiltinsWithOptionalParams, BuiltinsWithRequiredParams, + PluginsParams, } from '../plugins/plugins-types.js'; type CustomPlugin = { @@ -26,6 +27,31 @@ type PluginConfig = }[keyof BuiltinsWithRequiredParams] | CustomPlugin; +type BuiltinPlugin = { + /** Name of the plugin, also known as the plugin ID. */ + name: Name; + description?: string; + fn: Plugin; +}; + +/** + * Plugins that are bundled with SVGO. This includes plugin presets, and plugins + * that are not enabled by default. + */ +export declare const builtinPlugins: Array< + { + [Name in keyof PluginsParams]: BuiltinPlugin & { + /** If the plugin is itself a preset that invokes other plugins. */ + isPreset: true | undefined; + /** + * If the plugin is a preset that invokes other plugins, this returns an + * array of the plugins in the preset in the order that they are invoked. + */ + plugins?: BuiltinPlugin[]; + }; + }[keyof PluginsParams] +>; + export type Config = { /** Can be used by plugins, for example prefixids */ path?: string; diff --git a/lib/svgo.js b/lib/svgo.js index b7a6fd8f0..ba2385288 100644 --- a/lib/svgo.js +++ b/lib/svgo.js @@ -46,7 +46,7 @@ const resolvePluginConfig = (plugin) => { return null; }; -export { VERSION }; +export { VERSION, builtin as builtinPlugins }; export const optimize = (input, config) => { if (config == null) { @@ -104,4 +104,5 @@ export const optimize = (input, config) => { export default { VERSION, optimize, + builtinPlugins: builtin, }; diff --git a/lib/svgo/plugins.js b/lib/svgo/plugins.js index ba1577864..e6702c33e 100644 --- a/lib/svgo/plugins.js +++ b/lib/svgo/plugins.js @@ -34,6 +34,8 @@ export const invokePlugins = ( export const createPreset = ({ name, plugins }) => { return { name, + isPreset: true, + plugins, fn: (ast, params, info) => { const { floatPrecision, overrides } = params; const globalOverrides = {}; diff --git a/plugins/plugins-types.d.ts b/plugins/plugins-types.d.ts index 36a576e52..bdd5de8ba 100644 --- a/plugins/plugins-types.d.ts +++ b/plugins/plugins-types.d.ts @@ -290,7 +290,8 @@ export type BuiltinsWithRequiredParams = { }; }; -type PluginsParams = BuiltinsWithOptionalParams & BuiltinsWithRequiredParams; +export type PluginsParams = BuiltinsWithOptionalParams & + BuiltinsWithRequiredParams; export type Plugin = PluginDef< PluginsParams[Name] diff --git a/test/browser.js b/test/browser.js index c35b392ac..d6e62959d 100644 --- a/test/browser.js +++ b/test/browser.js @@ -30,12 +30,13 @@ const expected = ` const content = ` `; @@ -60,10 +61,12 @@ const runTest = async () => { const actual = await page.evaluate(() => ({ version: globalThis.version, + builtinPlugins: globalThis.builtinPlugins, result: globalThis.result, })); assert.strictEqual(actual.version, version); + assert.notEqual(actual.builtinPlugins, undefined); assert.equal(actual.result, expected); await browser.close(); diff --git a/test/svgo.cjs b/test/svgo.cjs index 2c9d6fdb9..3e854307b 100644 --- a/test/svgo.cjs +++ b/test/svgo.cjs @@ -1,5 +1,10 @@ const assert = require('assert'); -const { VERSION, optimize, loadConfig } = require('../dist/svgo-node.cjs'); +const { + VERSION, + optimize, + builtinPlugins, + loadConfig, +} = require('../dist/svgo-node.cjs'); const PKG = require('../package.json'); const fixture = ` @@ -30,6 +35,7 @@ const runTest = () => { assert.strictEqual(VERSION, PKG.version); assert.equal(actual, expected); + assert.notEqual(builtinPlugins, undefined); assert.notEqual(loadConfig, undefined); }; diff --git a/test/svgo/_index.test.js b/test/svgo/_index.test.js index 5bde71787..6bdddc19b 100644 --- a/test/svgo/_index.test.js +++ b/test/svgo/_index.test.js @@ -2,7 +2,7 @@ import fs from 'node:fs/promises'; import path from 'path'; import { EOL } from 'os'; import { fileURLToPath } from 'url'; -import { VERSION, optimize } from '../../lib/svgo.js'; +import { VERSION, optimize, builtinPlugins } from '../../lib/svgo.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -25,6 +25,12 @@ describe('svgo', () => { expect(VERSION).toStrictEqual(version); }); + it('should have all exported members', async () => { + expect(VERSION).toBeDefined(); + expect(optimize).toBeDefined(); + expect(builtinPlugins).toBeDefined(); + }); + it('should create indent with 2 spaces', async () => { const [original, expected] = await parseFixture('test.svg.txt'); const result = optimize(original, {