1
0
mirror of https://github.com/svg/svgo.git synced 2025-07-29 20:21:14 +03:00

chore: migrate plugin types to plugin (#2111)

This commit is contained in:
Seth Falco
2025-04-30 02:16:53 +01:00
committed by GitHub
parent 0ff7f24092
commit 4573d0178e
60 changed files with 399 additions and 387 deletions

View File

@ -55,7 +55,7 @@ You should read our [Plugin Architecture](https://svgo.dev/docs/plugins-api/) do
SVGO plugins can optionally have parameters. These can be consumed by the plugin to tailor the behavior.
As types are managed through TypeScript definition files and JSDocs, you must define the parameter types in [`plugins/plugin-types.d.ts`](https://github.com/svg/svgo/blob/main/plugins/plugins-types.d.ts) for built-in plugins. Then you'll have code completion and type checking as you'd expect while editing the plugin if your code editor supports that.
Parameters must have types declared in a [`@typedef`](https://jsdoc.app/tags-typedef) at the top of the file. For new plugins, you must also append the appropriate type in [`plugins/plugin-types.d.ts`](https://github.com/svg/svgo/blob/main/plugins/plugins-types.d.ts). This way built-in plugins will have code completion and type checking as you'd expect while editing the plugin.
## Documentation

View File

@ -20,7 +20,7 @@ export class SvgoParserError extends Error {
* @param {number} line
* @param {number} column
* @param {string} source
* @param {string|undefined} file
* @param {string | undefined} file
*/
constructor(message, line, column, source, file = undefined) {
super(message);

View File

@ -284,7 +284,7 @@ export const computeStyle = (stylesheet, node) => {
* if a `.class` or `#id` is included by passing `name=class` or `name=id`
* respectively.
*
* @param {csstree.ListItem<csstree.CssNode>|string} selector
* @param {csstree.ListItem<csstree.CssNode> | string} selector
* @param {string} name
* @param {?string} value
* @param {boolean} traversed

View File

@ -35,7 +35,7 @@ function getPlugin(name) {
}
/**
* @param {string|PluginConfig} plugin
* @param {string | PluginConfig} plugin
* @returns {?PluginConfig}
*/
const resolvePluginConfig = (plugin) => {

4
lib/types.d.ts vendored
View File

@ -105,9 +105,9 @@ export type PluginInfo = {
multipassCount: number;
};
export type Plugin<Params> = (
export type Plugin<P = null> = (
root: XastRoot,
params: Params,
params: P,
info: PluginInfo,
) => Visitor | null | void;

View File

@ -183,7 +183,7 @@ const getDecompositions = (matrix) => {
/**
* @param {TransformItem} matrix
* @returns {TransformItem[]|undefined}
* @returns {TransformItem[] | undefined}
* @see {@link https://frederic-wang.fr/2013/12/01/decomposition-of-2d-transform-matrices/} Where applicable, variables are named in accordance with this document.
*/
const decomposeQRAB = (matrix) => {
@ -238,7 +238,7 @@ const decomposeQRAB = (matrix) => {
/**
* @param {TransformItem} matrix
* @returns {TransformItem[]|undefined}
* @returns {TransformItem[] | undefined}
* @see {@link https://frederic-wang.fr/2013/12/01/decomposition-of-2d-transform-matrices/} Where applicable, variables are named in accordance with this document.
*/
const decomposeQRCD = (matrix) => {

View File

@ -1,3 +1,9 @@
/**
* @typedef AddAttributesToSVGElementParams
* @property {string | Record<string, null | string>=} attribute
* @property {Array<string | Record<string, null | string>>=} attributes
*/
export const name = 'addAttributesToSVGElement';
export const description = 'adds attributes to an outer <svg> element';
@ -45,7 +51,7 @@ plugins: [
*
* @author April Arcus
*
* @type {import('./plugins-types.js').Plugin<'addAttributesToSVGElement'>}
* @type {import('../lib/types.js').Plugin<AddAttributesToSVGElementParams>}
*/
export const fn = (root, params) => {
if (!Array.isArray(params.attributes) && !params.attribute) {

View File

@ -1,3 +1,12 @@
/**
* @typedef {import('../lib/types.js').PluginInfo} PluginInfo
* @typedef {import('../lib/types.js').XastElement} XastElement
*
* @typedef AddClassesToSVGElementParams
* @property {string | ((node: XastElement, info: PluginInfo) => string)=} className
* @property {Array<string | ((node: XastElement, info: PluginInfo) => string)>=} classNames
*/
export const name = 'addClassesToSVGElement';
export const description = 'adds classnames to an outer <svg> element';
@ -47,7 +56,7 @@ plugins: [
*
* @author April Arcus
*
* @type {import('./plugins-types.js').Plugin<'addClassesToSVGElement'>}
* @type {import('../lib/types.js').Plugin<AddClassesToSVGElementParams>}
*/
export const fn = (root, params, info) => {
if (

View File

@ -1,3 +1,10 @@
/**
* @typedef CleanupAttrsParams
* @property {boolean=} newlines
* @property {boolean=} trim
* @property {boolean=} spaces
*/
export const name = 'cleanupAttrs';
export const description =
'cleanups attributes from newlines, trailing and repeating spaces';
@ -10,7 +17,7 @@ const regSpaces = /\s{2,}/g;
* Cleanup attributes values from newlines, trailing and repeating spaces.
*
* @author Kir Belevich
* @type {import('./plugins-types.js').Plugin<'cleanupAttrs'>}
* @type {import('../lib/types.js').Plugin<CleanupAttrsParams>}
*/
export const fn = (root, params) => {
const { newlines = true, trim = true, spaces = true } = params;

View File

@ -17,7 +17,7 @@ const regEnableBackground =
* ⬇
* <svg width="100" height="50">
* @author Kir Belevich
* @type {import('./plugins-types.js').Plugin<'cleanupEnableBackground'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = (root) => {
let hasFilter = false;

View File

@ -3,6 +3,13 @@ import { hasScripts, findReferences } from '../lib/svgo/tools.js';
/**
* @typedef {import('../lib/types.js').XastElement} XastElement
*
* @typedef CleanupIdsParams
* @property {boolean=} remove
* @property {boolean=} minify
* @property {string[]=} preserve
* @property {string[]=} preservePrefixes
* @property {boolean=} force
*/
export const name = 'cleanupIds';
@ -119,7 +126,7 @@ const getIdString = (arr) => {
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'cleanupIds'>}
* @type {import('../lib/types.js').Plugin<CleanupIdsParams>}
*/
export const fn = (_root, params) => {
const {

View File

@ -1,5 +1,13 @@
import { removeLeadingZero } from '../lib/svgo/tools.js';
/**
* @typedef CleanupListOfValuesParams
* @property {number=} floatPrecision
* @property {boolean=} leadingZero
* @property {boolean=} defaultPx
* @property {boolean=} convertToPx
*/
export const name = 'cleanupListOfValues';
export const description = 'rounds list of values to the fixed precision';
@ -30,7 +38,7 @@ const absoluteLengths = {
*
* @author kiyopikko
*
* @type {import('./plugins-types.js').Plugin<'cleanupListOfValues'>}
* @type {import('../lib/types.js').Plugin<CleanupListOfValuesParams>}
*/
export const fn = (_root, params) => {
const {
@ -57,7 +65,7 @@ export const fn = (_root, params) => {
/** @type {any} */
let matchedUnit = match[3] || '';
/**
* @type{'' | keyof typeof absoluteLengths}
* @type {'' | keyof typeof absoluteLengths}
*/
let units = matchedUnit;

View File

@ -1,5 +1,13 @@
import { removeLeadingZero } from '../lib/svgo/tools.js';
/**
* @typedef CleanupNumericValuesParams
* @property {number=} floatPrecision
* @property {boolean=} leadingZero
* @property {boolean=} defaultPx
* @property {boolean=} convertToPx
*/
export const name = 'cleanupNumericValues';
export const description =
'rounds numeric values to the fixed precision, removes default px units';
@ -23,7 +31,7 @@ const absoluteLengths = {
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'cleanupNumericValues'>}
* @type {import('../lib/types.js').Plugin<CleanupNumericValuesParams>}
*/
export const fn = (_root, params) => {
const {

View File

@ -49,7 +49,7 @@ const hasAnimatedAttr = (node, name) => {
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'collapseGroups'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = (root) => {
const stylesheet = collectStylesheet(root);

View File

@ -1,6 +1,16 @@
import { colorsNames, colorsProps, colorsShortNames } from './_collections.js';
import { includesUrlReference } from '../lib/svgo/tools.js';
/**
* @typedef ConvertColorsParams
* @property {boolean | string | RegExp=} currentColor
* @property {boolean=} names2hex
* @property {boolean=} rgb2hex
* @property {false | 'lower' | 'upper'=} convertCase
* @property {boolean=} shorthex
* @property {boolean=} shortname
*/
export const name = 'convertColors';
export const description =
'converts colors: rgb() to #rrggbb and #rrggbb to #rgb';
@ -61,7 +71,7 @@ const convertRgbToHex = ([r, g, b]) => {
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'convertColors'>}
* @type {import('../lib/types.js').Plugin<ConvertColorsParams>}
*/
export const fn = (_root, params) => {
const {

View File

@ -8,7 +8,7 @@ export const description = 'converts non-eccentric <ellipse>s to <circle>s';
*
* @author Taylor Hunt
*
* @type {import('./plugins-types.js').Plugin<'convertEllipseToCircle'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = () => {
return {

View File

@ -19,7 +19,7 @@ export const description =
* Converts one-stop (single color) gradients to a plain color.
*
* @author Seth Falco <seth@falco.fun>
* @type {import('./plugins-types.js').Plugin<'convertOneStopGradients'>}
* @type {import('../lib/types.js').Plugin}
* @see https://developer.mozilla.org/docs/Web/SVG/Element/linearGradient
* @see https://developer.mozilla.org/docs/Web/SVG/Element/radialGradient
*/

View File

@ -7,6 +7,38 @@ import { cleanupOutData, toFixed } from '../lib/svgo/tools.js';
/**
* @typedef {import('../lib/types.js').PathDataItem} PathDataItem
*
* @typedef {[number, number]} Point
*
* @typedef Circle
* @property {Point} center
* @property {number} radius
*
* @typedef MakeArcs
* @property {number} threshold
* @property {number} tolerance
*
* @typedef ConvertPathDataParams
* @property {boolean=} applyTransforms
* @property {boolean=} applyTransformsStroked
* @property {MakeArcs=} makeArcs
* @property {boolean=} straightCurves
* @property {boolean=} convertToQ
* @property {boolean=} lineShorthands
* @property {boolean=} convertToZ
* @property {boolean=} curveSmoothShorthands
* @property {number | false=} floatPrecision
* @property {number=} transformPrecision
* @property {boolean=} smartArcRounding
* @property {boolean=} removeUseless
* @property {boolean=} collapseRepeated
* @property {boolean=} utilizeAbsolute
* @property {boolean=} leadingZero
* @property {boolean=} negativeExtraSpace
* @property {boolean=} noSpaceAfterFlags
* @property {boolean=} forceAbsolutePath
*
* @typedef {Required<ConvertPathDataParams>} InternalParams
*/
export const name = 'convertPathData';
@ -24,43 +56,6 @@ let arcThreshold;
/** @type {number} */
let arcTolerance;
/**
* @typedef {{
* applyTransforms: boolean,
* applyTransformsStroked: boolean,
* makeArcs: {
* threshold: number,
* tolerance: number,
* },
* straightCurves: boolean,
* convertToQ: boolean,
* lineShorthands: boolean,
* convertToZ: boolean,
* curveSmoothShorthands: boolean,
* floatPrecision: number | false,
* transformPrecision: number,
* smartArcRounding: boolean,
* removeUseless: boolean,
* collapseRepeated: boolean,
* utilizeAbsolute: boolean,
* leadingZero: boolean,
* negativeExtraSpace: boolean,
* noSpaceAfterFlags: boolean,
* forceAbsolutePath: boolean,
* }} InternalParams
*/
/**
* @typedef {[number, number]} Point
*/
/**
* @typedef {{
* center: Point,
* radius: number
* }} Circle
*/
/**
* Convert absolute Path to relative,
* collapse repeated instructions,
@ -73,7 +68,7 @@ let arcTolerance;
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'convertPathData'>}
* @type {import('../lib/types.js').Plugin<ConvertPathDataParams>}
*/
export const fn = (root, params) => {
const {

View File

@ -3,6 +3,10 @@ import { detachNodeFromParent } from '../lib/xast.js';
/**
* @typedef {import('../lib/types.js').PathDataItem} PathDataItem
*
* @typedef ConvertShapeToPathParams
* @property {boolean=} convertArcs
* @property {number=} floatPrecision
*/
export const name = 'convertShapeToPath';
@ -19,7 +23,7 @@ const regNumber = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g;
*
* @author Lev Solntsev
*
* @type {import('./plugins-types.js').Plugin<'convertShapeToPath'>}
* @type {import('../lib/types.js').Plugin<ConvertShapeToPathParams>}
*/
export const fn = (root, params) => {
const { convertArcs = false, floatPrecision: precision } = params;

View File

@ -1,5 +1,10 @@
import { attrsGroups } from './_collections.js';
/**
* @typedef ConvertStyleToAttrsParams
* @property {boolean=} keepImportant
*/
export const name = 'convertStyleToAttrs';
export const description = 'converts style to attributes';
@ -70,7 +75,7 @@ const regStripComments = new RegExp(
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'convertStyleToAttrs'>}
* @type {import('../lib/types.js').Plugin<ConvertStyleToAttrsParams>}
*/
export const fn = (_root, params) => {
const { keepImportant = false } = params;

View File

@ -10,6 +10,20 @@ import {
* @typedef {import('../lib/types.js').XastChild} XastChild
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
*
* @typedef ConvertTransformParams
* @property {boolean=} convertToShorts
* @property {number=} degPrecision
* @property {number=} floatPrecision
* @property {number=} transformPrecision
* @property {boolean=} matrixToTransform
* @property {boolean=} shortTranslate
* @property {boolean=} shortScale
* @property {boolean=} shortRotate
* @property {boolean=} removeUseless
* @property {boolean=} collapseIntoOne
* @property {boolean=} leadingZero
* @property {boolean=} negativeExtraSpace
*/
export const name = 'convertTransform';
@ -26,7 +40,7 @@ export const description =
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'convertTransform'>}
* @type {import('../lib/types.js').Plugin<ConvertTransformParams>}
*/
export const fn = (_root, params) => {
const {

View File

@ -11,6 +11,17 @@ import { compareSpecificity, includesAttrSelector } from '../lib/style.js';
/**
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
*
* @typedef InlineStylesParams
* @property {boolean=} onlyMatchedOnce Inlines selectors that match once only.
* @property {boolean=} removeMatchedSelectors
* Clean up matched selectors. Unused selects are left as-is.
* @property {string[]=} useMqs
* Media queries to use. An empty string indicates all selectors outside of
* media queries.
* @property {string[]=} usePseudos
* Pseudo-classes and elements to use. An empty string indicates all
* non-pseudo-classes and elements.
*/
export const name = 'inlineStyles';
@ -34,7 +45,7 @@ const preservedPseudos = [
/**
* Merges styles from style nodes into inline styles.
*
* @type {import('./plugins-types.js').Plugin<'inlineStyles'>}
* @type {import('../lib/types.js').Plugin<InlineStylesParams>}
* @author strarsis <strarsis@gmail.com>
*/
export const fn = (root, params) => {

View File

@ -1,3 +1,7 @@
import { collectStylesheet, computeStyle } from '../lib/style.js';
import { path2js, js2path, intersects } from './_path.js';
import { includesUrlReference } from '../lib/svgo/tools.js';
/**
* @typedef {import('../lib/types.js').ComputedStyles} ComputedStyles
* @typedef {import('../lib/types.js').StaticStyle} StaticStyle
@ -5,12 +9,13 @@
* @typedef {import("../lib/types.js").PathDataItem} PathDataItem
* @typedef {import('../lib/types.js').XastChild} XastChild
* @typedef {import('../lib/types.js').XastElement} XastElement
*
* @typedef MergePathsParams
* @property {boolean=} force
* @property {number=} floatPrecision
* @property {boolean=} noSpaceAfterFlags
*/
import { collectStylesheet, computeStyle } from '../lib/style.js';
import { path2js, js2path, intersects } from './_path.js';
import { includesUrlReference } from '../lib/svgo/tools.js';
export const name = 'mergePaths';
export const description = 'merges multiple paths in one if possible';
@ -34,7 +39,7 @@ function elementHasUrl(computedStyle, attName) {
*
* @author Kir Belevich, Lev Solntsev
*
* @type {import('./plugins-types.js').Plugin<'mergePaths'>}
* @type {import('../lib/types.js').Plugin<MergePathsParams>}
*/
export const fn = (root, params) => {
const {

View File

@ -13,7 +13,7 @@ export const description = 'merge multiple style elements into one';
*
* @author strarsis <strarsis@gmail.com>
*
* @type {import('./plugins-types.js').Plugin<'mergeStyles'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = () => {
/**

View File

@ -1,12 +1,31 @@
/**
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
*/
import * as csso from 'csso';
import { detachNodeFromParent } from '../lib/xast.js';
import { hasScripts } from '../lib/svgo/tools.js';
/**
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
*
* @typedef Usage
* @property {boolean=} force
* @property {boolean=} ids
* @property {boolean=} classes
* @property {boolean=} tags
*
* @typedef MinifyStylesParams
* @property {boolean=} restructure Disable or enable a structure optimizations.
* @property {boolean=} forceMediaMerge
* Enables merging of `@media` rules with the same media query split by other
* rules. Unsafe in general, but should work fine in most cases. Use it on
* your own risk.
* @property {'exclamation' | 'first-exclamation' | boolean=} comments
* Specify what comments to leave:
* - `'exclamation'` or `true` — leave all exclamation comments
* - `'first-exclamation'` — remove every comment except first one
* - `false` — remove all comments
* @property {boolean | Usage=} usage Advanced optimizations.
*/
export const name = 'minifyStyles';
export const description = 'minifies styles and removes unused styles';
@ -14,7 +33,7 @@ export const description = 'minifies styles and removes unused styles';
* Minifies styles (<style> element + style attribute) using CSSO.
*
* @author strarsis <strarsis@gmail.com>
* @type {import('./plugins-types.js').Plugin<'minifyStyles'>}
* @type {import('../lib/types.js').Plugin<MinifyStylesParams>}
*/
export const fn = (_root, { usage, ...params }) => {
/** @type {Map<XastElement, XastParent>} */

View File

@ -25,7 +25,7 @@ export const description =
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'moveElemsAttrsToGroup'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = (root) => {
// find if any style element is present

View File

@ -23,7 +23,7 @@ const pathElemsWithGroupsAndText = [...pathElems, 'g', 'text'];
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'moveGroupAttrsToElems'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = () => {
return {

View File

@ -1,213 +1,66 @@
import type {
Plugin as PluginDef,
PluginInfo,
XastElement,
} from '../lib/types.js';
import type { AddAttributesToSVGElementParams } from './addAttributesToSVGElement.js';
import type { AddClassesToSVGElementParams } from './addClassesToSVGElement.js';
import type { CleanupAttrsParams } from './cleanupAttrs.js';
import type { CleanupIdsParams } from './cleanupIds.js';
import type { CleanupListOfValuesParams } from './cleanupListOfValues.js';
import type { CleanupNumericValuesParams } from './cleanupNumericValues.js';
import type { ConvertColorsParams } from './convertColors.js';
import type { ConvertPathDataParams } from './convertPathData.js';
import type { ConvertShapeToPathParams } from './convertShapeToPath.js';
import type { ConvertStyleToAttrsParams } from './convertStyleToAttrs.js';
import type { ConvertTransformParams } from './convertTransform.js';
import type { InlineStylesParams } from './inlineStyles.js';
import type { MergePathsParams } from './mergePaths.js';
import type { MinifyStylesParams } from './minifyStyles.js';
import type { PrefixIdsParams } from './prefixIds.js';
import type { RemoveAttrsParams } from './removeAttrs.js';
import type { RemoveCommentsParams } from './removeComments.js';
import type { RemoveDeprecatedAttrsParams } from './removeDeprecatedAttrs.js';
import type { RemoveDescParams } from './removeDesc.js';
import type { RemoveEditorsNSDataParams } from './removeEditorsNSData.js';
import type { RemoveElementsByAttrParams } from './removeElementsByAttr.js';
import type { RemoveEmptyTextParams } from './removeEmptyText.js';
import type { RemoveHiddenElemsParams } from './removeHiddenElems.js';
import type { RemoveUnknownsAndDefaultsParams } from './removeUnknownsAndDefaults.js';
import type { RemoveUselessStrokeAndFillParams } from './removeUselessStrokeAndFill.js';
import type { RemoveXlinkParams } from './removeXlink.js';
import type { SortAttrsParams } from './sortAttrs.js';
type DefaultPlugins = {
cleanupAttrs: {
newlines?: boolean;
trim?: boolean;
spaces?: boolean;
};
cleanupEnableBackground: void;
cleanupIds: {
remove?: boolean;
minify?: boolean;
preserve?: string[];
preservePrefixes?: string[];
force?: boolean;
};
cleanupNumericValues: {
floatPrecision?: number;
leadingZero?: boolean;
defaultPx?: boolean;
convertToPx?: boolean;
};
collapseGroups: void;
convertColors: {
currentColor?: boolean | string | RegExp;
names2hex?: boolean;
rgb2hex?: boolean;
convertCase?: false | 'lower' | 'upper';
shorthex?: boolean;
shortname?: boolean;
};
convertEllipseToCircle: void;
convertPathData: {
applyTransforms?: boolean;
applyTransformsStroked?: boolean;
makeArcs?: {
threshold: number;
tolerance: number;
};
straightCurves?: boolean;
convertToQ?: boolean;
lineShorthands?: boolean;
convertToZ?: boolean;
curveSmoothShorthands?: boolean;
floatPrecision?: number | false;
transformPrecision?: number;
smartArcRounding?: boolean;
removeUseless?: boolean;
collapseRepeated?: boolean;
utilizeAbsolute?: boolean;
leadingZero?: boolean;
negativeExtraSpace?: boolean;
noSpaceAfterFlags?: boolean;
forceAbsolutePath?: boolean;
};
convertShapeToPath: {
convertArcs?: boolean;
floatPrecision?: number;
};
convertTransform: {
convertToShorts?: boolean;
degPrecision?: number;
floatPrecision?: number;
transformPrecision?: number;
matrixToTransform?: boolean;
shortTranslate?: boolean;
shortScale?: boolean;
shortRotate?: boolean;
removeUseless?: boolean;
collapseIntoOne?: boolean;
leadingZero?: boolean;
negativeExtraSpace?: boolean;
};
mergeStyles: void;
inlineStyles: {
/**
* Inlines selectors that match once only.
*
* @default true
*/
onlyMatchedOnce?: boolean;
/**
* Clean up matched selectors. Unused selects are left as-is.
*
* @default true
*/
removeMatchedSelectors?: boolean;
/**
* Media queries to use. An empty string indicates all selectors outside of
* media queries.
*/
useMqs?: string[];
/**
* Pseudo-classes and elements to use. An empty string indicates all
* non-pseudo-classes and elements.
*/
usePseudos?: string[];
};
mergePaths: {
force?: boolean;
floatPrecision?: number;
noSpaceAfterFlags?: boolean;
};
minifyStyles: {
/**
* Disable or enable a structure optimizations.
* @default true
*/
restructure?: boolean;
/**
* Enables merging of @media rules with the same media query split by other rules.
* Unsafe in general, but should work fine in most cases. Use it on your own risk.
* @default false
*/
forceMediaMerge?: boolean;
/**
* Specify what comments to leave:
* - 'exclamation' or true leave all exclamation comments
* - 'first-exclamation' remove every comment except first one
* - false remove all comments
* @default true
*/
comments?: string | boolean;
/**
* Advanced optimizations
*/
usage?:
| boolean
| {
force?: boolean;
ids?: boolean;
classes?: boolean;
tags?: boolean;
};
};
moveElemsAttrsToGroup: void;
moveGroupAttrsToElems: void;
removeComments: {
preservePatterns: Array<RegExp | string> | false;
};
removeDeprecatedAttrs: {
removeUnsafe?: boolean;
};
removeDesc: {
removeAny?: boolean;
};
removeDoctype: void;
removeEditorsNSData: {
additionalNamespaces?: string[];
};
removeEmptyAttrs: void;
removeEmptyContainers: void;
removeEmptyText: {
text?: boolean;
tspan?: boolean;
tref?: boolean;
};
removeHiddenElems: {
isHidden?: boolean;
displayNone?: boolean;
opacity0?: boolean;
circleR0?: boolean;
ellipseRX0?: boolean;
ellipseRY0?: boolean;
rectWidth0?: boolean;
rectHeight0?: boolean;
patternWidth0?: boolean;
patternHeight0?: boolean;
imageWidth0?: boolean;
imageHeight0?: boolean;
pathEmptyD?: boolean;
polylineEmptyPoints?: boolean;
polygonEmptyPoints?: boolean;
};
removeMetadata: void;
removeNonInheritableGroupAttrs: void;
removeUnknownsAndDefaults: {
unknownContent?: boolean;
unknownAttrs?: boolean;
defaultAttrs?: boolean;
/**
* If to remove XML declarations that are assigned their default value. XML
* declarations are the properties in the `<?xml … ?>` block at the top of
* the document.
*/
defaultMarkupDeclarations?: boolean;
uselessOverrides?: boolean;
keepDataAttrs?: boolean;
keepAriaAttrs?: boolean;
keepRoleAttr?: boolean;
};
removeUnusedNS: void;
removeUselessDefs: void;
removeUselessStrokeAndFill: {
stroke?: boolean;
fill?: boolean;
removeNone?: boolean;
};
removeXMLProcInst: void;
sortAttrs: {
order?: string[];
xmlnsOrder?: 'front' | 'alphabetical';
};
sortDefsChildren: void;
cleanupAttrs: CleanupAttrsParams;
cleanupEnableBackground: null;
cleanupIds: CleanupIdsParams;
cleanupNumericValues: CleanupNumericValuesParams;
collapseGroups: null;
convertColors: ConvertColorsParams;
convertEllipseToCircle: null;
convertPathData: ConvertPathDataParams;
convertShapeToPath: ConvertShapeToPathParams;
convertTransform: ConvertTransformParams;
mergeStyles: null;
inlineStyles: InlineStylesParams;
mergePaths: MergePathsParams;
minifyStyles: MinifyStylesParams;
moveElemsAttrsToGroup: null;
moveGroupAttrsToElems: null;
removeComments: RemoveCommentsParams;
removeDeprecatedAttrs: RemoveDeprecatedAttrsParams;
removeDesc: RemoveDescParams;
removeDoctype: null;
removeEditorsNSData: RemoveEditorsNSDataParams;
removeEmptyAttrs: null;
removeEmptyContainers: null;
removeEmptyText: RemoveEmptyTextParams;
removeHiddenElems: RemoveHiddenElemsParams;
removeMetadata: null;
removeNonInheritableGroupAttrs: null;
removeUnknownsAndDefaults: RemoveUnknownsAndDefaultsParams;
removeUnusedNS: null;
removeUselessDefs: null;
removeUselessStrokeAndFill: RemoveUselessStrokeAndFillParams;
removeXMLProcInst: null;
sortAttrs: SortAttrsParams;
sortDefsChildren: null;
};
type PresetDefaultOverrides = {
@ -227,72 +80,29 @@ export type BuiltinsWithOptionalParams = DefaultPlugins & {
*/
overrides?: PresetDefaultOverrides;
};
cleanupListOfValues: {
floatPrecision?: number;
leadingZero?: boolean;
defaultPx?: boolean;
convertToPx?: boolean;
};
convertOneStopGradients: void;
convertStyleToAttrs: {
keepImportant?: boolean;
};
prefixIds: {
prefix?:
| boolean
| string
| ((node: XastElement, info: PluginInfo) => string);
delim?: string;
prefixIds?: boolean;
prefixClassNames?: boolean;
};
removeDimensions: void;
removeOffCanvasPaths: void;
removeRasterImages: void;
removeScripts: void;
removeStyleElement: void;
removeTitle: void;
removeViewBox: void;
removeXlink: {
/**
* By default this plugin ignores legacy elements that were deprecated or
* removed in SVG 2. Set to true to force performing operations on those
* too.
*
* @default false
*/
includeLegacy: boolean;
};
removeXMLNS: void;
reusePaths: void;
cleanupListOfValues: CleanupListOfValuesParams;
convertOneStopGradients: null;
convertStyleToAttrs: ConvertStyleToAttrsParams;
prefixIds: PrefixIdsParams;
removeDimensions: null;
removeOffCanvasPaths: null;
removeRasterImages: null;
removeScripts: null;
removeStyleElement: null;
removeTitle: null;
removeViewBox: null;
removeXlink: RemoveXlinkParams;
removeXMLNS: null;
reusePaths: null;
};
export type BuiltinsWithRequiredParams = {
addAttributesToSVGElement: {
attribute?: string | Record<string, null | string>;
attributes?: Array<string | Record<string, null | string>>;
};
addClassesToSVGElement: {
className?: string | ((node: XastElement, info: PluginInfo) => string);
classNames?: Array<
string | ((node: XastElement, info: PluginInfo) => string)
>;
};
addAttributesToSVGElement: AddAttributesToSVGElementParams;
addClassesToSVGElement: AddClassesToSVGElementParams;
removeAttributesBySelector: any;
removeAttrs: {
elemSeparator?: string;
preserveCurrentColor?: boolean;
attrs: string | string[];
};
removeElementsByAttr: {
id?: string | string[];
class?: string | string[];
};
removeAttrs: RemoveAttrsParams;
removeElementsByAttr: RemoveElementsByAttrParams;
};
export type PluginsParams = BuiltinsWithOptionalParams &
BuiltinsWithRequiredParams;
export type Plugin<Name extends keyof PluginsParams> = PluginDef<
PluginsParams[Name]
>;

View File

@ -4,6 +4,12 @@ import { referencesProps } from './_collections.js';
/**
* @typedef {import('../lib/types.js').PluginInfo} PluginInfo
* @typedef {import('../lib/types.js').XastElement} XastElement
*
* @typedef PrefixIdsParams
* @property {boolean | string | ((node: XastElement, info: PluginInfo) => string)=} prefix
* @property {string=} delim
* @property {boolean=} prefixIds
* @property {boolean=} prefixClassNames
*/
export const name = 'prefixIds';
@ -79,7 +85,7 @@ const prefixReference = (prefixGenerator, reference) => {
* @param {string} body An arbitrary string.
* @param {XastElement} node XML node that the identifier belongs to.
* @param {PluginInfo} info
* @param {((node: XastElement, info: PluginInfo) => string)|string|boolean|undefined} prefixGenerator Some way of obtaining a prefix.
* @param {((node: XastElement, info: PluginInfo) => string) | string | boolean | undefined} prefixGenerator Some way of obtaining a prefix.
* @param {string} delim Content to insert between the prefix and original value.
* @param {Map<string, string>} history Map of previously generated prefixes to IDs.
* @returns {string} A generated prefix.
@ -116,7 +122,7 @@ const generatePrefix = (body, node, info, prefixGenerator, delim, history) => {
* Prefixes identifiers
*
* @author strarsis <strarsis@gmail.com>
* @type {import('./plugins-types.js').Plugin<'prefixIds'>}
* @type {import('../lib/types.js').Plugin<PrefixIdsParams>}
*/
export const fn = (_root, params, info) => {
const {

View File

@ -71,7 +71,7 @@ export const description =
*
* @author Bradley Mease
*
* @type {import('./plugins-types.js').Plugin<'removeAttributesBySelector'>}
* @type {import('../lib/types.js').Plugin<any>}
*/
export const fn = (root, params) => {
const selectors = Array.isArray(params.selectors)

View File

@ -1,3 +1,10 @@
/**
* @typedef RemoveAttrsParams
* @property {string=} elemSeparator
* @property {boolean=} preserveCurrentColor
* @property {string | string[]} attrs
*/
export const name = 'removeAttrs';
export const description = 'removes specified attributes';
@ -79,7 +86,7 @@ plugins: [
*
* @author Benny Schudel
*
* @type {import('./plugins-types.js').Plugin<'removeAttrs'>}
* @type {import('../lib/types.js').Plugin<RemoveAttrsParams>}
*/
export const fn = (root, params) => {
if (typeof params.attrs == 'undefined') {

View File

@ -1,5 +1,10 @@
import { detachNodeFromParent } from '../lib/xast.js';
/**
* @typedef RemoveCommentsParams
* @property {Array<RegExp | string> | false=} preservePatterns
*/
export const name = 'removeComments';
export const description = 'removes comments';
@ -18,7 +23,7 @@ const DEFAULT_PRESERVE_PATTERNS = [/^!/];
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeComments'>}
* @type {import('../lib/types.js').Plugin<RemoveCommentsParams>}
*/
export const fn = (_root, params) => {
const { preservePatterns = DEFAULT_PRESERVE_PATTERNS } = params;

View File

@ -2,14 +2,17 @@ import * as csswhat from 'css-what';
import { attrsGroupsDeprecated, elems } from './_collections.js';
import { collectStylesheet } from '../lib/style.js';
export const name = 'removeDeprecatedAttrs';
export const description = 'removes deprecated attributes';
/**
* @typedef {{ safe?: Set<string>; unsafe?: Set<string> }} DeprecatedAttrs
* @typedef {import('../lib/types.js').XastElement} XastElement
*
* @typedef RemoveDeprecatedAttrsParams
* @property {boolean=} removeUnsafe
*/
export const name = 'removeDeprecatedAttrs';
export const description = 'removes deprecated attributes';
/**
* @param {import('../lib/types.js').Stylesheet} stylesheet
* @returns {Set<string>}
@ -71,7 +74,7 @@ function processAttributes(
/**
* Remove deprecated attributes.
*
* @type {import('./plugins-types.js').Plugin<'removeDeprecatedAttrs'>}
* @type {import('../lib/types.js').Plugin<RemoveDeprecatedAttrsParams>}
*/
export function fn(root, params) {
const stylesheet = collectStylesheet(root);

View File

@ -1,5 +1,10 @@
import { detachNodeFromParent } from '../lib/xast.js';
/**
* @typedef RemoveDescParams
* @property {boolean=} removeAny
*/
export const name = 'removeDesc';
export const description = 'removes <desc>';
@ -14,7 +19,7 @@ const standardDescs = /^(Created with|Created using)/;
* @author Daniel Wabyick
* @see https://developer.mozilla.org/docs/Web/SVG/Element/desc
*
* @type {import('./plugins-types.js').Plugin<'removeDesc'>}
* @type {import('../lib/types.js').Plugin<RemoveDescParams>}
*/
export const fn = (root, params) => {
const { removeAny = false } = params;

View File

@ -12,7 +12,7 @@ export const description =
*
* @author Benny Schudel
*
* @type {import('./plugins-types.js').Plugin<'removeDimensions'>}
* @type {import('../lib/types.js').Plugin<'removeDimensions'>}
*/
export const fn = () => {
return {

View File

@ -25,7 +25,7 @@ export const description = 'removes doctype declaration';
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeDoctype'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = () => {
return {

View File

@ -1,6 +1,11 @@
import { editorNamespaces } from './_collections.js';
import { detachNodeFromParent } from '../lib/xast.js';
/**
* @typedef RemoveEditorsNSDataParams
* @property {string[]=} additionalNamespaces
*/
export const name = 'removeEditorsNSData';
export const description =
'removes editors namespaces, elements and attributes';
@ -15,7 +20,7 @@ export const description =
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeEditorsNSData'>}
* @type {import('../lib/types.js').Plugin<RemoveEditorsNSDataParams>}
*/
export const fn = (_root, params) => {
let namespaces = [...editorNamespaces];

View File

@ -1,5 +1,11 @@
import { detachNodeFromParent } from '../lib/xast.js';
/**
* @typedef RemoveElementsByAttrParams
* @property {string | string[]=} id
* @property {string | string[]=} class
*/
export const name = 'removeElementsByAttr';
export const description =
'removes arbitrary elements by ID or className (disabled by default)';
@ -35,7 +41,7 @@ export const description =
*
* @author Eli Dupuis (@elidupuis)
*
* @type {import('./plugins-types.js').Plugin<'removeElementsByAttr'>}
* @type {import('../lib/types.js').Plugin<RemoveElementsByAttrParams>}
*/
export const fn = (root, params) => {
const ids =

View File

@ -8,7 +8,7 @@ export const description = 'removes empty attributes';
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeEmptyAttrs'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = () => {
return {

View File

@ -18,7 +18,7 @@ export const description = 'removes empty container elements';
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeEmptyContainers'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = (root) => {
const stylesheet = collectStylesheet(root);

View File

@ -1,5 +1,12 @@
import { detachNodeFromParent } from '../lib/xast.js';
/**
* @typedef RemoveEmptyTextParams
* @property {boolean=} text
* @property {boolean=} tspan
* @property {boolean=} tref
*/
export const name = 'removeEmptyText';
export const description = 'removes empty <text> elements';
@ -20,7 +27,7 @@ export const description = 'removes empty <text> elements';
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeEmptyText'>}
* @type {import('../lib/types.js').Plugin<RemoveEmptyTextParams>}
*/
export const fn = (root, params) => {
const { text = true, tspan = true, tref = true } = params;

View File

@ -1,9 +1,3 @@
/**
* @typedef {import('../lib/types.js').XastChild} XastChild
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
*/
import { elemsGroups } from './_collections.js';
import {
visit,
@ -15,6 +9,29 @@ import { collectStylesheet, computeStyle } from '../lib/style.js';
import { parsePathData } from '../lib/path.js';
import { hasScripts, findReferences } from '../lib/svgo/tools.js';
/**
* @typedef {import('../lib/types.js').XastChild} XastChild
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
*
* @typedef RemoveHiddenElemsParams
* @property {boolean=} isHidden
* @property {boolean=} displayNone
* @property {boolean=} opacity0
* @property {boolean=} circleR0
* @property {boolean=} ellipseRX0
* @property {boolean=} ellipseRY0
* @property {boolean=} rectWidth0
* @property {boolean=} rectHeight0
* @property {boolean=} patternWidth0
* @property {boolean=} patternHeight0
* @property {boolean=} imageWidth0
* @property {boolean=} imageHeight0
* @property {boolean=} pathEmptyD
* @property {boolean=} polylineEmptyPoints
* @property {boolean=} polygonEmptyPoints
*/
const nonRendering = elemsGroups.nonRendering;
export const name = 'removeHiddenElems';
@ -36,7 +53,7 @@ export const description =
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeHiddenElems'>}
* @type {import('../lib/types.js').Plugin<RemoveHiddenElemsParams>}
*/
export const fn = (root, params) => {
const {

View File

@ -10,7 +10,7 @@ export const description = 'removes <metadata>';
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeMetadata'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = () => {
return {

View File

@ -13,7 +13,7 @@ export const description =
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeNonInheritableGroupAttrs'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = () => {
return {

View File

@ -15,7 +15,7 @@ export const description =
*
* @author JoshyPHP
*
* @type {import('./plugins-types.js').Plugin<'removeOffCanvasPaths'>}
* @type {import('../lib/types.js').Plugin<'removeOffCanvasPaths'>}
*/
export const fn = () => {
/**

View File

@ -10,7 +10,7 @@ export const description = 'removes raster images (disabled by default)';
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeRasterImages'>}
* @type {import('../lib/types.js').Plugin<'removeRasterImages'>}
*/
export const fn = () => {
return {

View File

@ -19,7 +19,7 @@ const eventAttrs = [
* https://www.w3.org/TR/SVG11/script.html
*
* @author Patrick Klingemann
* @type {import('./plugins-types.js').Plugin<'removeScripts'>}
* @type {import('../lib/types.js').Plugin<'removeScripts'>}
*/
export const fn = () => {
return {

View File

@ -10,7 +10,7 @@ export const description = 'removes <style> element (disabled by default)';
*
* @author Betsy Dupuis
*
* @type {import('./plugins-types.js').Plugin<'removeStyleElement'>}
* @type {import('../lib/types.js').Plugin<'removeStyleElement'>}
*/
export const fn = () => {
return {

View File

@ -10,7 +10,7 @@ export const description = 'removes <title>';
*
* @author Igor Kalashnikov
*
* @type {import('./plugins-types.js').Plugin<'removeTitle'>}
* @type {import('../lib/types.js').Plugin<'removeTitle'>}
*/
export const fn = () => {
return {

View File

@ -8,6 +8,21 @@ import {
import { visitSkip, detachNodeFromParent } from '../lib/xast.js';
import { collectStylesheet, computeStyle } from '../lib/style.js';
/**
* @typedef RemoveUnknownsAndDefaultsParams
* @property {boolean=} unknownContent
* @property {boolean=} unknownAttrs
* @property {boolean=} defaultAttrs
* @property {boolean=} defaultMarkupDeclarations
* If to remove XML declarations that are assigned their default value. XML
* declarations are the properties in the `<?xml … ?>` block at the top of the
* document.
* @property {boolean=} uselessOverrides
* @property {boolean=} keepDataAttrs
* @property {boolean=} keepAriaAttrs
* @property {boolean=} keepRoleAttr
*/
export const name = 'removeUnknownsAndDefaults';
export const description =
'removes unknown elements content and attributes, removes attrs with default values';
@ -90,7 +105,7 @@ for (const [name, config] of Object.entries(elems)) {
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeUnknownsAndDefaults'>}
* @type {import('../lib/types.js').Plugin<RemoveUnknownsAndDefaultsParams>}
*/
export const fn = (root, params) => {
const {

View File

@ -7,7 +7,7 @@ export const description = 'removes unused namespaces declaration';
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeUnusedNS'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = () => {
/**

View File

@ -13,7 +13,7 @@ export const description = 'removes elements in <defs> without id';
*
* @author Lev Solntsev
*
* @type {import('./plugins-types.js').Plugin<'removeUselessDefs'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = () => {
return {

View File

@ -3,6 +3,13 @@ import { collectStylesheet, computeStyle } from '../lib/style.js';
import { hasScripts } from '../lib/svgo/tools.js';
import { elemsGroups } from './_collections.js';
/**
* @typedef RemoveUselessStrokeAndFillParams
* @property {boolean=} stroke
* @property {boolean=} fill
* @property {boolean=} removeNone
*/
export const name = 'removeUselessStrokeAndFill';
export const description = 'removes useless stroke and fill attributes';
@ -11,7 +18,7 @@ export const description = 'removes useless stroke and fill attributes';
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeUselessStrokeAndFill'>}
* @type {import('../lib/types.js').Plugin<RemoveUselessStrokeAndFillParams>}
*/
export const fn = (root, params) => {
const {

View File

@ -15,7 +15,7 @@ const viewBoxElems = new Set(['pattern', 'svg', 'symbol']);
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeViewBox'>}
* @type {import('../lib/types.js').Plugin<'removeViewBox'>}
*/
export const fn = () => {
return {

View File

@ -12,7 +12,7 @@ export const description =
*
* @author Ricardo Tomasi
*
* @type {import('./plugins-types.js').Plugin<'removeXMLNS'>}
* @type {import('../lib/types.js').Plugin<'removeXMLNS'>}
*/
export const fn = () => {
return {

View File

@ -11,7 +11,7 @@ export const description = 'removes XML processing instructions';
*
* @author Kir Belevich
*
* @type {import('./plugins-types.js').Plugin<'removeXMLProcInst'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = () => {
return {

View File

@ -2,6 +2,11 @@ import { elems } from './_collections.js';
/**
* @typedef {import('../lib/types.js').XastElement} XastElement
*
* @typedef RemoveXlinkParams
* @property {boolean=} includeLegacy
* By default this plugin ignores legacy elements that were deprecated or
* removed in SVG 2. Set to true to force performing operations on those too.
*/
export const name = 'removeXlink';
@ -56,7 +61,7 @@ const findPrefixedAttrs = (node, prefixes, attr) => {
*
* XLink namespace is deprecated in SVG 2.
*
* @type {import('./plugins-types.js').Plugin<'removeXlink'>}
* @type {import('../lib/types.js').Plugin<RemoveXlinkParams>}
* @see https://developer.mozilla.org/docs/Web/SVG/Attribute/xlink:href
*/
export const fn = (_, params) => {

View File

@ -19,7 +19,7 @@ export const description =
*
* @author Jacob Howcroft
*
* @type {import('./plugins-types.js').Plugin<'reusePaths'>}
* @type {import('../lib/types.js').Plugin<'reusePaths'>}
*/
export const fn = (root) => {
const stylesheet = collectStylesheet(root);

View File

@ -1,3 +1,9 @@
/**
* @typedef SortAttrsParams
* @property {string[]=} order
* @property {'front' | 'alphabetical'=} xmlnsOrder
*/
export const name = 'sortAttrs';
export const description = 'Sort element attributes for better compression';
@ -6,7 +12,7 @@ export const description = 'Sort element attributes for better compression';
*
* @author Nikolay Frantsev
*
* @type {import('./plugins-types.js').Plugin<'sortAttrs'>}
* @type {import('../lib/types.js').Plugin<SortAttrsParams>}
*/
export const fn = (_root, params) => {
const {

View File

@ -7,7 +7,7 @@ export const description = 'Sorts children of <defs> to improve compression';
*
* @author David Leston
*
* @type {import('./plugins-types.js').Plugin<'sortDefsChildren'>}
* @type {import('../lib/types.js').Plugin}
*/
export const fn = () => {
return {