From 97d7d00add2643e9b4af016cd34d761a1e044b21 Mon Sep 17 00:00:00 2001 From: Seth Falco Date: Sat, 7 Sep 2024 19:26:05 +0100 Subject: [PATCH] add: centralize exports to svgo (#2071) --- eslint.config.mjs | 4 +- lib/svgo-node.js | 14 +++++- lib/svgo.d.ts | 103 +++++++++++++++++++++++++++++++++++++++- lib/svgo.js | 13 ++++- lib/xast.js | 6 ++- plugins/_collections.js | 55 +++++++++++++++------ test/browser.js | 15 +++++- test/svgo.cjs | 6 +++ 8 files changed, 192 insertions(+), 24 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 61073b2bb..ef7a8ec83 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,10 +2,10 @@ import js from '@eslint/js'; import globals from 'globals'; /** - * @typedef {import('eslint').Linter.FlatConfig} FlatConfig + * @typedef {import('eslint').Linter.Config} Config */ -/** @type {FlatConfig[]} */ +/** @type {Config[]} */ export default [ { ignores: [ diff --git a/lib/svgo-node.js b/lib/svgo-node.js index 406eaaa9a..8b8b31c11 100644 --- a/lib/svgo-node.js +++ b/lib/svgo-node.js @@ -6,6 +6,9 @@ import { VERSION, optimize as optimizeAgnostic, builtinPlugins, + querySelector, + querySelectorAll, + _collections, } from './svgo.js'; const importConfig = async (configFile) => { @@ -29,7 +32,13 @@ const isFile = async (file) => { } }; -export { VERSION, builtinPlugins }; +export { + VERSION, + builtinPlugins, + querySelector, + querySelectorAll, + _collections, +}; export const loadConfig = async (configFile, cwd = process.cwd()) => { if (configFile != null) { @@ -84,4 +93,7 @@ export default { builtinPlugins, loadConfig, optimize, + querySelector, + querySelectorAll, + _collections, }; diff --git a/lib/svgo.d.ts b/lib/svgo.d.ts index f22634aa4..01f79e142 100644 --- a/lib/svgo.d.ts +++ b/lib/svgo.d.ts @@ -1,4 +1,10 @@ -import type { StringifyOptions, DataUri, Plugin } from './types.js'; +import type { + StringifyOptions, + DataUri, + Plugin, + XastChild, + XastNode, +} from './types.js'; import type { BuiltinsWithOptionalParams, BuiltinsWithRequiredParams, @@ -34,7 +40,10 @@ type BuiltinPlugin = { fn: Plugin; }; -type BuiltinPluginOrPreset = BuiltinPlugin & { +export type BuiltinPluginOrPreset = BuiltinPlugin< + Name, + Params +> & { /** If the plugin is itself a preset that invokes other plugins. */ isPreset: true | undefined; /** @@ -83,8 +92,98 @@ type Output = { data: string; }; +export declare const _collections: { + elemsGroups: Readonly>>; + /** + * Elements where adding or removing whitespace may effect rendering, metadata, + * or semantic meaning. + * + * @see https://developer.mozilla.org/docs/Web/HTML/Element/pre + */ + textElems: Readonly>; + pathElems: Readonly>; + /** + * @see https://www.w3.org/TR/SVG11/intro.html#Definitions + */ + attrsGroups: Readonly>>; + attrsGroupsDefaults: Readonly>>; + /** + * @see https://www.w3.org/TR/SVG11/intro.html#Definitions + */ + attrsGroupsDeprecated: Readonly< + Record; unsafe?: Set }> + >; + /** + * @see https://www.w3.org/TR/SVG11/eltindex.html + */ + elems: Readonly< + Record< + string, + { + attrsGroups: Set; + attrs?: Set; + defaults?: Record; + deprecated?: { + safe?: Set; + unsafe?: Set; + }; + contentGroups?: Set; + content?: Set; + } + > + >; + /** + * @see https://wiki.inkscape.org/wiki/index.php/Inkscape-specific_XML_attributes + */ + editorNamespaces: Readonly>; + /** + * @see https://www.w3.org/TR/SVG11/linking.html#processingIRI + */ + referencesProps: Readonly>; + /** + * @see https://www.w3.org/TR/SVG11/propidx.html + */ + inheritableAttrs: Readonly>; + presentationNonInheritableGroupAttrs: Readonly>; + /** + * @see https://www.w3.org/TR/SVG11/single-page.html#types-ColorKeywords + */ + colorsNames: Readonly>; + colorsShortNames: Readonly>; + /** + * @see https://www.w3.org/TR/SVG11/single-page.html#types-DataTypeColor + */ + colorsProps: Readonly>; + /** + * @see https://developer.mozilla.org/docs/Web/CSS/Pseudo-classes + */ + pseudoClasses: Readonly>>; +}; + +export type * from './types.d.ts'; + /** Installed version of SVGO. */ export declare const VERSION: string; /** The core of SVGO */ export declare function optimize(input: string, config?: Config): Output; + +/** + * @param node Element to query the children of. + * @param selector CSS selector string. + * @returns First match, or null if there was no match. + */ +export declare function querySelector( + node: XastNode, + selector: string, +): XastChild | null; + +/** + * @param node Element to query the children of. + * @param selector CSS selector string. + * @returns All matching elements. + */ +export declare function querySelectorAll( + node: XastNode, + selector: string, +): XastChild[]; diff --git a/lib/svgo.js b/lib/svgo.js index f63eed345..be023b7d9 100644 --- a/lib/svgo.js +++ b/lib/svgo.js @@ -4,6 +4,8 @@ import { builtin } from './builtin.js'; import { invokePlugins } from './svgo/plugins.js'; import { encodeSVGDatauri } from './svgo/tools.js'; import { VERSION } from './version.js'; +import { querySelector, querySelectorAll } from './xast.js'; +import _collections from '../plugins/_collections.js'; /** * @typedef {import('./svgo.js').BuiltinPluginOrPreset} BuiltinPluginOrPreset @@ -65,7 +67,13 @@ const resolvePluginConfig = (plugin) => { return null; }; -export { VERSION, builtin as builtinPlugins }; +export { + VERSION, + builtin as builtinPlugins, + querySelector, + querySelectorAll, + _collections, +}; export const optimize = (input, config) => { if (config == null) { @@ -124,4 +132,7 @@ export default { VERSION, optimize, builtinPlugins: builtin, + querySelector, + querySelectorAll, + _collections, }; diff --git a/lib/xast.js b/lib/xast.js index 342f5c321..3b47f0fc3 100644 --- a/lib/xast.js +++ b/lib/xast.js @@ -6,6 +6,8 @@ import xastAdaptor from './svgo/css-select-adapter.js'; * @typedef {import('./types.js').XastChild} XastChild * @typedef {import('./types.js').XastParent} XastParent * @typedef {import('./types.js').Visitor} Visitor + * @typedef {import('./svgo.ts').querySelector} querySelector + * @typedef {import('./svgo.ts').querySelectorAll} querySelectorAll */ const cssSelectOptions = { @@ -14,14 +16,14 @@ const cssSelectOptions = { }; /** - * @type {(node: XastNode, selector: string) => XastChild[]} + * @type {querySelectorAll} */ export const querySelectorAll = (node, selector) => { return selectAll(selector, node, cssSelectOptions); }; /** - * @type {(node: XastNode, selector: string) => ?XastChild} + * @type {querySelector} */ export const querySelector = (node, selector) => { return selectOne(selector, node, cssSelectOptions); diff --git a/plugins/_collections.js b/plugins/_collections.js index 194b39fb6..3944c645f 100644 --- a/plugins/_collections.js +++ b/plugins/_collections.js @@ -1,7 +1,12 @@ // https://www.w3.org/TR/SVG11/intro.html#Definitions +/** + * @typedef {import('../lib/svgo.ts')} svgo + */ + /** * @type {Record>} + * @see svgo#_collections */ export const elemsGroups = { animation: new Set([ @@ -101,18 +106,18 @@ export const elemsGroups = { }; /** - * Elements where adding or removing whitespace may effect rendering, metadata, - * or semantic meaning. - * - * @see https://developer.mozilla.org/docs/Web/HTML/Element/pre + * @see svgo#_collections */ export const textElems = new Set([...elemsGroups.textContent, 'pre', 'title']); +/** + * @see svgo#_collections + */ export const pathElems = new Set(['glyph', 'missing-glyph', 'path']); /** * @type {Record>} - * @see https://www.w3.org/TR/SVG11/intro.html#Definitions + * @see svgo#_collections */ export const attrsGroups = { animationAddition: new Set(['additive', 'accumulate']), @@ -311,6 +316,7 @@ export const attrsGroups = { /** * @type {Record>} + * @see svgo#_collections */ export const attrsGroupsDefaults = { core: { 'xml:space': 'default' }, @@ -378,7 +384,7 @@ export const attrsGroupsDefaults = { /** * @type {Record, unsafe?: Set }>} - * @see https://www.w3.org/TR/SVG11/intro.html#Definitions + * @see svgo#_collections */ export const attrsGroupsDeprecated = { animationAttributeTarget: { unsafe: new Set(['attributeType']) }, @@ -408,7 +414,7 @@ export const attrsGroupsDeprecated = { * contentGroups?: Set, * content?: Set, * }>} - * @see https://www.w3.org/TR/SVG11/eltindex.html + * @see svgo#_collections */ export const elems = { a: { @@ -2067,7 +2073,9 @@ export const elems = { }, }; -// https://wiki.inkscape.org/wiki/index.php/Inkscape-specific_XML_attributes +/** + * @see svgo#_collections + */ export const editorNamespaces = new Set([ 'http://creativecommons.org/ns#', 'http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd', @@ -2094,7 +2102,7 @@ export const editorNamespaces = new Set([ ]); /** - * @see https://www.w3.org/TR/SVG11/linking.html#processingIRI + * @see svgo#_collections */ export const referencesProps = new Set([ 'clip-path', @@ -2110,7 +2118,7 @@ export const referencesProps = new Set([ ]); /** - * @see https://www.w3.org/TR/SVG11/propidx.html + * @see svgo#_collections */ export const inheritableAttrs = new Set([ 'clip-rule', @@ -2172,9 +2180,8 @@ export const presentationNonInheritableGroupAttrs = new Set([ ]); /** - * https://www.w3.org/TR/SVG11/single-page.html#types-ColorKeywords - * * @type {Record} + * @see svgo#_collections */ export const colorsNames = { aliceblue: '#f0f8ff', @@ -2366,7 +2373,7 @@ export const colorsShortNames = { }; /** - * @see https://www.w3.org/TR/SVG11/single-page.html#types-DataTypeColor + * @see svgo#_collections */ export const colorsProps = new Set([ 'color', @@ -2377,7 +2384,9 @@ export const colorsProps = new Set([ 'stroke', ]); -/** @see https://developer.mozilla.org/docs/Web/CSS/Pseudo-classes */ +/** + * @see svgo#_collections + */ export const pseudoClasses = { displayState: new Set(['fullscreen', 'modal', 'picture-in-picture']), input: new Set([ @@ -2434,3 +2443,21 @@ export const pseudoClasses = { ]), functional: new Set(['is', 'not', 'where', 'has']), }; + +export default { + elemsGroups, + textElems, + pathElems, + attrsGroups, + attrsGroupsDefaults, + attrsGroupsDeprecated, + elems, + editorNamespaces, + referencesProps, + inheritableAttrs, + presentationNonInheritableGroupAttrs, + colorsNames, + colorsShortNames, + colorsProps, + pseudoClasses, +}; diff --git a/test/browser.js b/test/browser.js index d6e62959d..50560555f 100644 --- a/test/browser.js +++ b/test/browser.js @@ -30,13 +30,14 @@ const expected = ` const content = ` `; @@ -62,11 +63,21 @@ const runTest = async () => { const actual = await page.evaluate(() => ({ version: globalThis.version, builtinPlugins: globalThis.builtinPlugins, + _collections: globalThis._collections, result: globalThis.result, })); assert.strictEqual(actual.version, version); - assert.notEqual(actual.builtinPlugins, undefined); + assert.notEqual( + actual.builtinPlugins, + undefined, + 'builtinPlugins must be defined', + ); + assert.notEqual( + actual._collections, + undefined, + '_collections must be defined', + ); assert.equal(actual.result, expected); await browser.close(); diff --git a/test/svgo.cjs b/test/svgo.cjs index 3e854307b..2e3aff8cd 100644 --- a/test/svgo.cjs +++ b/test/svgo.cjs @@ -4,6 +4,9 @@ const { optimize, builtinPlugins, loadConfig, + querySelector, + querySelectorAll, + _collections, } = require('../dist/svgo-node.cjs'); const PKG = require('../package.json'); @@ -37,6 +40,9 @@ const runTest = () => { assert.equal(actual, expected); assert.notEqual(builtinPlugins, undefined); assert.notEqual(loadConfig, undefined); + assert.notEqual(querySelector, undefined); + assert.notEqual(querySelectorAll, undefined); + assert.notEqual(_collections, undefined); }; runTest();