Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

svgo

Package Overview
Dependencies
Maintainers
4
Versions
104
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

svgo - npm Package Compare versions

Comparing version 3.3.2 to 4.0.0-rc.0

bin/svgo.js

164

lib/builtin.js

@@ -1,57 +0,111 @@

'use strict';
import presetDefault from '../plugins/preset-default.js';
import * as addAttributesToSVGElement from '../plugins/addAttributesToSVGElement.js';
import * as addClassesToSVGElement from '../plugins/addClassesToSVGElement.js';
import * as cleanupAttrs from '../plugins/cleanupAttrs.js';
import * as cleanupEnableBackground from '../plugins/cleanupEnableBackground.js';
import * as cleanupIds from '../plugins/cleanupIds.js';
import * as cleanupListOfValues from '../plugins/cleanupListOfValues.js';
import * as cleanupNumericValues from '../plugins/cleanupNumericValues.js';
import * as collapseGroups from '../plugins/collapseGroups.js';
import * as convertColors from '../plugins/convertColors.js';
import * as convertEllipseToCircle from '../plugins/convertEllipseToCircle.js';
import * as convertOneStopGradients from '../plugins/convertOneStopGradients.js';
import * as convertPathData from '../plugins/convertPathData.js';
import * as convertShapeToPath from '../plugins/convertShapeToPath.js';
import * as convertStyleToAttrs from '../plugins/convertStyleToAttrs.js';
import * as convertTransform from '../plugins/convertTransform.js';
import * as mergeStyles from '../plugins/mergeStyles.js';
import * as inlineStyles from '../plugins/inlineStyles.js';
import * as mergePaths from '../plugins/mergePaths.js';
import * as minifyStyles from '../plugins/minifyStyles.js';
import * as moveElemsAttrsToGroup from '../plugins/moveElemsAttrsToGroup.js';
import * as moveGroupAttrsToElems from '../plugins/moveGroupAttrsToElems.js';
import * as prefixIds from '../plugins/prefixIds.js';
import * as removeAttributesBySelector from '../plugins/removeAttributesBySelector.js';
import * as removeAttrs from '../plugins/removeAttrs.js';
import * as removeComments from '../plugins/removeComments.js';
import * as removeDeprecatedAttrs from '../plugins/removeDeprecatedAttrs.js';
import * as removeDesc from '../plugins/removeDesc.js';
import * as removeDimensions from '../plugins/removeDimensions.js';
import * as removeDoctype from '../plugins/removeDoctype.js';
import * as removeEditorsNSData from '../plugins/removeEditorsNSData.js';
import * as removeElementsByAttr from '../plugins/removeElementsByAttr.js';
import * as removeEmptyAttrs from '../plugins/removeEmptyAttrs.js';
import * as removeEmptyContainers from '../plugins/removeEmptyContainers.js';
import * as removeEmptyText from '../plugins/removeEmptyText.js';
import * as removeHiddenElems from '../plugins/removeHiddenElems.js';
import * as removeMetadata from '../plugins/removeMetadata.js';
import * as removeNonInheritableGroupAttrs from '../plugins/removeNonInheritableGroupAttrs.js';
import * as removeOffCanvasPaths from '../plugins/removeOffCanvasPaths.js';
import * as removeRasterImages from '../plugins/removeRasterImages.js';
import * as removeScripts from '../plugins/removeScripts.js';
import * as removeStyleElement from '../plugins/removeStyleElement.js';
import * as removeTitle from '../plugins/removeTitle.js';
import * as removeUnknownsAndDefaults from '../plugins/removeUnknownsAndDefaults.js';
import * as removeUnusedNS from '../plugins/removeUnusedNS.js';
import * as removeUselessDefs from '../plugins/removeUselessDefs.js';
import * as removeUselessStrokeAndFill from '../plugins/removeUselessStrokeAndFill.js';
import * as removeViewBox from '../plugins/removeViewBox.js';
import * as removeXlink from '../plugins/removeXlink.js';
import * as removeXMLNS from '../plugins/removeXMLNS.js';
import * as removeXMLProcInst from '../plugins/removeXMLProcInst.js';
import * as reusePaths from '../plugins/reusePaths.js';
import * as sortAttrs from '../plugins/sortAttrs.js';
import * as sortDefsChildren from '../plugins/sortDefsChildren.js';
exports.builtin = [
require('../plugins/preset-default.js'),
require('../plugins/addAttributesToSVGElement.js'),
require('../plugins/addClassesToSVGElement.js'),
require('../plugins/cleanupAttrs.js'),
require('../plugins/cleanupEnableBackground.js'),
require('../plugins/cleanupIds.js'),
require('../plugins/cleanupListOfValues.js'),
require('../plugins/cleanupNumericValues.js'),
require('../plugins/collapseGroups.js'),
require('../plugins/convertColors.js'),
require('../plugins/convertEllipseToCircle.js'),
require('../plugins/convertOneStopGradients.js'),
require('../plugins/convertPathData.js'),
require('../plugins/convertShapeToPath.js'),
require('../plugins/convertStyleToAttrs.js'),
require('../plugins/convertTransform.js'),
require('../plugins/mergeStyles.js'),
require('../plugins/inlineStyles.js'),
require('../plugins/mergePaths.js'),
require('../plugins/minifyStyles.js'),
require('../plugins/moveElemsAttrsToGroup.js'),
require('../plugins/moveGroupAttrsToElems.js'),
require('../plugins/prefixIds.js'),
require('../plugins/removeAttributesBySelector.js'),
require('../plugins/removeAttrs.js'),
require('../plugins/removeComments.js'),
require('../plugins/removeDesc.js'),
require('../plugins/removeDimensions.js'),
require('../plugins/removeDoctype.js'),
require('../plugins/removeEditorsNSData.js'),
require('../plugins/removeElementsByAttr.js'),
require('../plugins/removeEmptyAttrs.js'),
require('../plugins/removeEmptyContainers.js'),
require('../plugins/removeEmptyText.js'),
require('../plugins/removeHiddenElems.js'),
require('../plugins/removeMetadata.js'),
require('../plugins/removeNonInheritableGroupAttrs.js'),
require('../plugins/removeOffCanvasPaths.js'),
require('../plugins/removeRasterImages.js'),
require('../plugins/removeScriptElement.js'),
require('../plugins/removeStyleElement.js'),
require('../plugins/removeTitle.js'),
require('../plugins/removeUnknownsAndDefaults.js'),
require('../plugins/removeUnusedNS.js'),
require('../plugins/removeUselessDefs.js'),
require('../plugins/removeUselessStrokeAndFill.js'),
require('../plugins/removeViewBox.js'),
require('../plugins/removeXlink.js'),
require('../plugins/removeXMLNS.js'),
require('../plugins/removeXMLProcInst.js'),
require('../plugins/reusePaths.js'),
require('../plugins/sortAttrs.js'),
require('../plugins/sortDefsChildren.js'),
export const builtin = [
presetDefault,
addAttributesToSVGElement,
addClassesToSVGElement,
cleanupAttrs,
cleanupEnableBackground,
cleanupIds,
cleanupListOfValues,
cleanupNumericValues,
collapseGroups,
convertColors,
convertEllipseToCircle,
convertOneStopGradients,
convertPathData,
convertShapeToPath,
convertStyleToAttrs,
convertTransform,
mergeStyles,
inlineStyles,
mergePaths,
minifyStyles,
moveElemsAttrsToGroup,
moveGroupAttrsToElems,
prefixIds,
removeAttributesBySelector,
removeAttrs,
removeComments,
removeDeprecatedAttrs,
removeDesc,
removeDimensions,
removeDoctype,
removeEditorsNSData,
removeElementsByAttr,
removeEmptyAttrs,
removeEmptyContainers,
removeEmptyText,
removeHiddenElems,
removeMetadata,
removeNonInheritableGroupAttrs,
removeOffCanvasPaths,
removeRasterImages,
removeScripts,
removeStyleElement,
removeTitle,
removeUnknownsAndDefaults,
removeUnusedNS,
removeUselessDefs,
removeUselessStrokeAndFill,
removeViewBox,
removeXlink,
removeXMLNS,
removeXMLProcInst,
reusePaths,
sortAttrs,
sortDefsChildren,
];

@@ -1,19 +0,17 @@

'use strict';
/**
* @typedef {import('./types').XastNode} XastNode
* @typedef {import('./types').XastInstruction} XastInstruction
* @typedef {import('./types').XastDoctype} XastDoctype
* @typedef {import('./types').XastComment} XastComment
* @typedef {import('./types').XastRoot} XastRoot
* @typedef {import('./types').XastElement} XastElement
* @typedef {import('./types').XastCdata} XastCdata
* @typedef {import('./types').XastText} XastText
* @typedef {import('./types').XastParent} XastParent
* @typedef {import('./types').XastChild} XastChild
* @typedef {import('./types.js').XastNode} XastNode
* @typedef {import('./types.js').XastInstruction} XastInstruction
* @typedef {import('./types.js').XastDoctype} XastDoctype
* @typedef {import('./types.js').XastComment} XastComment
* @typedef {import('./types.js').XastRoot} XastRoot
* @typedef {import('./types.js').XastElement} XastElement
* @typedef {import('./types.js').XastCdata} XastCdata
* @typedef {import('./types.js').XastText} XastText
* @typedef {import('./types.js').XastParent} XastParent
* @typedef {import('./types.js').XastChild} XastChild
*/
// @ts-ignore sax will be replaced with something else later
const SAX = require('@trysound/sax');
const { textElems } = require('../plugins/_collections');
import SAX from 'sax';
import { textElems } from '../plugins/_collections.js';

@@ -85,2 +83,3 @@ class SvgoParserError extends Error {

position: true,
unparsedEntities: true,
};

@@ -93,3 +92,3 @@

*/
const parseSvg = (data, from) => {
export const parseSvg = (data, from) => {
const sax = SAX.parser(config.strict, config);

@@ -121,5 +120,2 @@ /**

/**
* @type {(doctype: string) => void}
*/
sax.ondoctype = (doctype) => {

@@ -149,5 +145,2 @@ /**

/**
* @type {(data: { name: string, body: string }) => void}
*/
sax.onprocessinginstruction = (data) => {

@@ -165,5 +158,2 @@ /**

/**
* @type {(comment: string) => void}
*/
sax.oncomment = (comment) => {

@@ -180,5 +170,2 @@ /**

/**
* @type {(cdata: string) => void}
*/
sax.oncdata = (cdata) => {

@@ -195,5 +182,2 @@ /**

/**
* @type {(data: { name: string, attributes: Record<string, { value: string }>}) => void}
*/
sax.onopentag = (data) => {

@@ -217,5 +201,2 @@ /**

/**
* @type {(text: string) => void}
*/
sax.ontext = (text) => {

@@ -251,10 +232,8 @@ if (current.type === 'element') {

/**
* @type {(e: any) => void}
*/
sax.onerror = (e) => {
const reason = e.message.split('\n')[0];
const error = new SvgoParserError(
e.reason,
e.line + 1,
e.column,
reason,
sax.line + 1,
sax.column,
data,

@@ -271,2 +250,1 @@ from,

};
exports.parseSvg = parseSvg;

@@ -1,8 +0,6 @@

'use strict';
import { removeLeadingZero, toFixed } from './svgo/tools.js';
const { removeLeadingZero, toFixed } = require('./svgo/tools');
/**
* @typedef {import('./types').PathDataItem} PathDataItem
* @typedef {import('./types').PathDataCommand} PathDataCommand
* @typedef {import('./types.js').PathDataItem} PathDataItem
* @typedef {import('./types.js').PathDataCommand} PathDataCommand
*/

@@ -140,3 +138,3 @@

*/
const parsePathData = (string) => {
export const parsePathData = (string) => {
/**

@@ -244,3 +242,2 @@ * @type {PathDataItem[]}

};
exports.parsePathData = parsePathData;

@@ -291,8 +288,3 @@ /**

result += roundedStr;
} else if (
!Number.isInteger(previous) &&
rounded != 0 &&
rounded < 1 &&
rounded > -1
) {
} else if (!Number.isInteger(previous) && !isDigit(roundedStr[0])) {
// remove space before decimal with zero whole

@@ -322,3 +314,7 @@ // only when previous number is also decimal

*/
const stringifyPathData = ({ pathData, precision, disableSpaceAfterFlags }) => {
export const stringifyPathData = ({
pathData,
precision,
disableSpaceAfterFlags,
}) => {
if (pathData.length === 1) {

@@ -384,2 +380,1 @@ const { command, args } = pathData[0];

};
exports.stringifyPathData = stringifyPathData;

@@ -1,18 +0,13 @@

'use strict';
import { textElems } from '../plugins/_collections.js';
/**
* @typedef {import('./types').XastParent} XastParent
* @typedef {import('./types').XastRoot} XastRoot
* @typedef {import('./types').XastElement} XastElement
* @typedef {import('./types').XastInstruction} XastInstruction
* @typedef {import('./types').XastDoctype} XastDoctype
* @typedef {import('./types').XastText} XastText
* @typedef {import('./types').XastCdata} XastCdata
* @typedef {import('./types').XastComment} XastComment
* @typedef {import('./types').StringifyOptions} StringifyOptions
*/
const { textElems } = require('../plugins/_collections');
/**
* @typedef {import('./types.js').XastParent} XastParent
* @typedef {import('./types.js').XastRoot} XastRoot
* @typedef {import('./types.js').XastElement} XastElement
* @typedef {import('./types.js').XastInstruction} XastInstruction
* @typedef {import('./types.js').XastDoctype} XastDoctype
* @typedef {import('./types.js').XastText} XastText
* @typedef {import('./types.js').XastCdata} XastCdata
* @typedef {import('./types.js').XastComment} XastComment
* @typedef {import('./types.js').StringifyOptions} StringifyOptions
* @typedef {{

@@ -23,5 +18,2 @@ * indent: string,

* }} State
*/
/**
* @typedef {Required<StringifyOptions>} Options

@@ -81,3 +73,3 @@ */

*/
const stringifySvg = (data, userOptions = {}) => {
export const stringifySvg = (data, userOptions = {}) => {
/**

@@ -119,3 +111,2 @@ * @type {Options}

};
exports.stringifySvg = stringifySvg;

@@ -122,0 +113,0 @@ /**

@@ -1,29 +0,24 @@

'use strict';
import * as csstree from 'css-tree';
import * as csswhat from 'css-what';
import { syntax } from 'csso';
import { visit, matches } from './xast.js';
import {
attrsGroups,
inheritableAttrs,
presentationNonInheritableGroupAttrs,
} from '../plugins/_collections.js';
/**
* @typedef {import('css-tree').Rule} CsstreeRule
* @typedef {import('./types').Specificity} Specificity
* @typedef {import('./types').Stylesheet} Stylesheet
* @typedef {import('./types').StylesheetRule} StylesheetRule
* @typedef {import('./types').StylesheetDeclaration} StylesheetDeclaration
* @typedef {import('./types').ComputedStyles} ComputedStyles
* @typedef {import('./types').XastRoot} XastRoot
* @typedef {import('./types').XastElement} XastElement
* @typedef {import('./types').XastParent} XastParent
* @typedef {import('./types').XastChild} XastChild
* @typedef {import('./types.js').Specificity} Specificity
* @typedef {import('./types.js').Stylesheet} Stylesheet
* @typedef {import('./types.js').StylesheetRule} StylesheetRule
* @typedef {import('./types.js').StylesheetDeclaration} StylesheetDeclaration
* @typedef {import('./types.js').ComputedStyles} ComputedStyles
* @typedef {import('./types.js').XastRoot} XastRoot
* @typedef {import('./types.js').XastElement} XastElement
* @typedef {import('./types.js').XastParent} XastParent
* @typedef {import('./types.js').XastChild} XastChild
*/
const csstree = require('css-tree');
const csswhat = require('css-what');
const {
syntax: { specificity },
} = require('csso');
const { visit, matches } = require('./xast.js');
const {
attrsGroups,
inheritableAttrs,
presentationNonInheritableGroupAttrs,
} = require('../plugins/_collections.js');
// @ts-ignore not defined in @types/csstree
const csstreeWalkSkip = csstree.walk.skip;

@@ -63,3 +58,3 @@

rules.push({
specificity: specificity(node),
specificity: syntax.specificity(node),
dynamic: hasPseudoClasses || dynamic,

@@ -205,3 +200,3 @@ // compute specificity from original node to consider pseudo classes

*/
const compareSpecificity = (a, b) => {
export const compareSpecificity = (a, b) => {
for (let i = 0; i < 4; i += 1) {

@@ -217,3 +212,2 @@ if (a[i] < b[i]) {

};
exports.compareSpecificity = compareSpecificity;

@@ -223,3 +217,3 @@ /**

*/
const collectStylesheet = (root) => {
export const collectStylesheet = (root) => {
/** @type {StylesheetRule[]} */

@@ -260,3 +254,2 @@ const rules = [];

};
exports.collectStylesheet = collectStylesheet;

@@ -268,3 +261,3 @@ /**

*/
const computeStyle = (stylesheet, node) => {
export const computeStyle = (stylesheet, node) => {
const { parents } = stylesheet;

@@ -288,3 +281,2 @@ const computedStyles = computeOwnStyle(stylesheet, node);

};
exports.computeStyle = computeStyle;

@@ -304,3 +296,3 @@ /**

*/
const includesAttrSelector = (
export const includesAttrSelector = (
selector,

@@ -344,2 +336,1 @@ name,

};
exports.includesAttrSelector = includesAttrSelector;

@@ -1,22 +0,17 @@

'use strict';
import os from 'os';
import fs from 'fs';
import { pathToFileURL } from 'url';
import path from 'path';
import {
VERSION,
optimize as optimizeAgnostic,
builtinPlugins,
} from './svgo.js';
const os = require('os');
const fs = require('fs');
const { pathToFileURL } = require('url');
const path = require('path');
const { optimize: optimizeAgnostic } = require('./svgo.js');
const importConfig = async (configFile) => {
// dynamic import expects file url instead of path and may fail
// when windows path is provided
const imported = await import(pathToFileURL(configFile));
const config = imported.default;
const importConfig = async (configFile) => {
let config;
// at the moment dynamic import may randomly fail with segfault
// to workaround this for some users .cjs extension is loaded
// exclusively with require
if (configFile.endsWith('.cjs')) {
config = require(configFile);
} else {
// dynamic import expects file url instead of path and may fail
// when windows path is provided
const { default: imported } = await import(pathToFileURL(configFile));
config = imported;
}
if (config == null || typeof config !== 'object' || Array.isArray(config)) {

@@ -37,3 +32,5 @@ throw Error(`Invalid config file "${configFile}"`);

const loadConfig = async (configFile, cwd = process.cwd()) => {
export { VERSION, builtinPlugins };
export const loadConfig = async (configFile, cwd = process.cwd()) => {
if (configFile != null) {

@@ -47,3 +44,3 @@ if (path.isAbsolute(configFile)) {

let dir = cwd;
// eslint-disable-next-line no-constant-condition
while (true) {

@@ -69,5 +66,4 @@ const js = path.join(dir, 'svgo.config.js');

};
exports.loadConfig = loadConfig;
const optimize = (input, config) => {
export const optimize = (input, config) => {
if (config == null) {

@@ -88,2 +84,8 @@ config = {};

};
exports.optimize = optimize;
export default {
VERSION,
builtinPlugins,
loadConfig,
optimize,
};

@@ -1,10 +0,12 @@

import type { StringifyOptions, DataUri, Plugin as PluginFn } from './types';
import type { StringifyOptions, DataUri, Plugin } from './types.js';
import type {
BuiltinsWithOptionalParams,
BuiltinsWithRequiredParams,
} from '../plugins/plugins-types';
PluginsParams,
} from '../plugins/plugins-types.js';
type CustomPlugin = {
type CustomPlugin<T = any> = {
name: string;
fn: PluginFn<void>;
fn: Plugin<T>;
params?: T;
};

@@ -28,2 +30,27 @@

type BuiltinPlugin<Name, Params> = {
/** Name of the plugin, also known as the plugin ID. */
name: Name;
description?: string;
fn: Plugin<Params>;
};
/**
* 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<Name, PluginsParams[Name]> & {
/** 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<unknown, unknown>[];
};
}[keyof PluginsParams]
>;
export type Config = {

@@ -55,17 +82,6 @@ /** Can be used by plugins, for example prefixids */

/** Installed version of SVGO. */
export declare const VERSION: string;
/** The core of SVGO */
export declare function optimize(input: string, config?: Config): Output;
/**
* If you write a tool on top of svgo you might need a way to load svgo config.
*
* You can also specify relative or absolute path and customize current working directory.
*/
export declare function loadConfig(
configFile: string,
cwd?: string,
): Promise<Config>;
export declare function loadConfig(
configFile?: null,
cwd?: string,
): Promise<Config | null>;

@@ -1,9 +0,8 @@

'use strict';
import { parseSvg } from './parser.js';
import { stringifySvg } from './stringifier.js';
import { builtin } from './builtin.js';
import { invokePlugins } from './svgo/plugins.js';
import { encodeSVGDatauri } from './svgo/tools.js';
import { VERSION } from './version.js';
const { parseSvg } = require('./parser.js');
const { stringifySvg } = require('./stringifier.js');
const { builtin } = require('./builtin.js');
const { invokePlugins } = require('./svgo/plugins.js');
const { encodeSVGDatauri } = require('./svgo/tools.js');
const pluginsMap = {};

@@ -50,3 +49,5 @@ for (const plugin of builtin) {

const optimize = (input, config) => {
export { VERSION, builtin as builtinPlugins };
export const optimize = (input, config) => {
if (config == null) {

@@ -103,2 +104,7 @@ config = {};

};
exports.optimize = optimize;
export default {
VERSION,
optimize,
builtinPlugins: builtin,
};

@@ -1,11 +0,17 @@

'use strict';
import fs from 'fs';
import path from 'path';
import colors from 'picocolors';
import { fileURLToPath } from 'url';
import { encodeSVGDatauri, decodeSVGDatauri } from './tools.js';
import { loadConfig, optimize } from '../svgo-node.js';
import { builtin } from '../builtin.js';
const fs = require('fs');
const path = require('path');
const colors = require('picocolors');
const { loadConfig, optimize } = require('../svgo-node.js');
const { builtin } = require('../builtin.js');
const PKG = require('../../package.json');
const { encodeSVGDatauri, decodeSVGDatauri } = require('./tools.js');
/**
* @typedef {import('commander').Command} Command
*/
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const pkgPath = path.join(__dirname, '../../package.json');
const PKG = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
const regSVGFile = /\.svg$/i;

@@ -16,20 +22,21 @@

*
* @param {string} path
* @param {string} filePath
*/
function checkIsDir(path) {
export function checkIsDir(filePath) {
try {
return fs.lstatSync(path).isDirectory();
} catch (e) {
return false;
return fs.lstatSync(filePath).isDirectory();
} catch {
return filePath.endsWith(path.sep);
}
}
module.exports = function makeProgram(program) {
/**
* @param {Command} program
*/
export default function makeProgram(program) {
program
.name(PKG.name)
.description(PKG.description, {
INPUT: 'Alias to --input',
})
.description(PKG.description)
.version(PKG.version, '-v, --version')
.arguments('[INPUT...]')
.argument('[INPUT...]', 'Alias to --input')
.option('-i, --input <INPUT...>', 'Input files, "-" for STDIN')

@@ -49,4 +56,7 @@ .option('-s, --string <STRING>', 'Input SVG data string')

)
.option('--config <CONFIG>', 'Custom config file, only .js is supported')
.option(
'--config <CONFIG>',
'Custom config file, only .js, .mjs, and .cjs is supported',
)
.option(
'--datauri <FORMAT>',

@@ -82,3 +92,3 @@ 'Output as Data URI string (base64), URI encoded (enc) or unencoded (unenc)',

.action(action);
};
}

@@ -245,4 +255,4 @@ async function action(args, opts, command) {

if (opts.folder) {
var ouputFolder = (output && output[0]) || opts.folder;
await optimizeFolder(config, opts.folder, ouputFolder);
var outputFolder = (output && output[0]) || opts.folder;
await optimizeFolder(config, opts.folder, outputFolder);
}

@@ -531,3 +541,1 @@

}
module.exports.checkIsDir = checkIsDir;
declare let obj: any;
export = obj;
export default obj;

@@ -1,3 +0,1 @@

'use strict';
const isTag = (node) => {

@@ -120,2 +118,2 @@ return node.type === 'element';

module.exports = svgoCssSelectAdapter;
export default svgoCssSelectAdapter;

@@ -1,5 +0,3 @@

'use strict';
import { visit } from '../xast.js';
const { visit } = require('../xast.js');
/**

@@ -15,3 +13,9 @@ * Plugins engine.

*/
const invokePlugins = (ast, info, plugins, overrides, globalOverrides) => {
export const invokePlugins = (
ast,
info,
plugins,
overrides,
globalOverrides,
) => {
for (const plugin of plugins) {

@@ -30,7 +34,8 @@ const override = overrides?.[plugin.name];

};
exports.invokePlugins = invokePlugins;
const createPreset = ({ name, plugins }) => {
export const createPreset = ({ name, plugins }) => {
return {
name,
isPreset: true,
plugins,
fn: (ast, params, info) => {

@@ -63,2 +68,1 @@ const { floatPrecision, overrides } = params;

};
exports.createPreset = createPreset;

@@ -1,10 +0,8 @@

'use strict';
/**
* @typedef {import('../../lib/types').XastElement} XastElement
* @typedef {import('../types').PathDataCommand} PathDataCommand
* @typedef {import('../types').DataUri} DataUri
* @typedef {import('../types.js').DataUri} DataUri
* @typedef {import('../types.js').PathDataCommand} PathDataCommand
* @typedef {import('../../lib/types.js').XastElement} XastElement
*/
const { attrsGroups, referencesProps } = require('../../plugins/_collections');
import { attrsGroups, referencesProps } from '../../plugins/_collections.js';

@@ -20,3 +18,3 @@ const regReferencesUrl = /\burl\((["'])?#(.+?)\1\)/g;

*/
exports.encodeSVGDatauri = (str, type) => {
export const encodeSVGDatauri = (str, type) => {
var prefix = 'data:image/svg+xml';

@@ -42,3 +40,3 @@ if (!type || type === 'base64') {

*/
exports.decodeSVGDatauri = (str) => {
export const decodeSVGDatauri = (str) => {
var regexp = /data:image\/svg\+xml(;charset=[^;,]*)?(;base64)?,(.*)/;

@@ -81,3 +79,3 @@ var match = regexp.exec(str);

*/
exports.cleanupOutData = (data, params, command) => {
export const cleanupOutData = (data, params, command) => {
let str = '';

@@ -136,3 +134,3 @@ let delimiter;

*/
const removeLeadingZero = (value) => {
export const removeLeadingZero = (value) => {
const strValue = value.toString();

@@ -150,3 +148,2 @@

};
exports.removeLeadingZero = removeLeadingZero;

@@ -160,3 +157,3 @@ /**

*/
const hasScripts = (node) => {
export const hasScripts = (node) => {
if (node.name === 'script' && node.children.length !== 0) {

@@ -189,3 +186,2 @@ return true;

};
exports.hasScripts = hasScripts;

@@ -202,6 +198,5 @@ /**

*/
const includesUrlReference = (body) => {
export const includesUrlReference = (body) => {
return new RegExp(regReferencesUrl).test(body);
};
exports.includesUrlReference = includesUrlReference;

@@ -213,3 +208,3 @@ /**

*/
const findReferences = (attribute, value) => {
export const findReferences = (attribute, value) => {
const results = [];

@@ -240,3 +235,2 @@

};
exports.findReferences = findReferences;

@@ -251,6 +245,5 @@ /**

*/
const toFixed = (num, precision) => {
export const toFixed = (num, precision) => {
const pow = 10 ** precision;
return Math.round(num * pow) / pow;
};
exports.toFixed = toFixed;

@@ -112,3 +112,3 @@ export type XastDoctype = {

info: PluginInfo,
) => null | Visitor;
) => Visitor | null | void;

@@ -115,0 +115,0 @@ export type Specificity = [number, number, number];

@@ -1,13 +0,11 @@

'use strict';
import { selectAll, selectOne, is } from 'css-select';
import xastAdaptor from './svgo/css-select-adapter.js';
/**
* @typedef {import('./types').XastNode} XastNode
* @typedef {import('./types').XastChild} XastChild
* @typedef {import('./types').XastParent} XastParent
* @typedef {import('./types').Visitor} Visitor
* @typedef {import('./types.js').XastNode} XastNode
* @typedef {import('./types.js').XastChild} XastChild
* @typedef {import('./types.js').XastParent} XastParent
* @typedef {import('./types.js').Visitor} Visitor
*/
const { selectAll, selectOne, is } = require('css-select');
const xastAdaptor = require('./svgo/css-select-adapter.js');
const cssSelectOptions = {

@@ -21,6 +19,5 @@ xmlMode: true,

*/
const querySelectorAll = (node, selector) => {
export const querySelectorAll = (node, selector) => {
return selectAll(selector, node, cssSelectOptions);
};
exports.querySelectorAll = querySelectorAll;

@@ -30,6 +27,5 @@ /**

*/
const querySelector = (node, selector) => {
export const querySelector = (node, selector) => {
return selectOne(selector, node, cssSelectOptions);
};
exports.querySelector = querySelector;

@@ -39,9 +35,7 @@ /**

*/
const matches = (node, selector) => {
export const matches = (node, selector) => {
return is(node, selector, cssSelectOptions);
};
exports.matches = matches;
const visitSkip = Symbol();
exports.visitSkip = visitSkip;
export const visitSkip = Symbol();

@@ -51,3 +45,3 @@ /**

*/
const visit = (node, visitor, parentNode) => {
export const visit = (node, visitor, parentNode) => {
const callbacks = visitor[node.type];

@@ -81,3 +75,2 @@ if (callbacks && callbacks.enter) {

};
exports.visit = visit;

@@ -88,6 +81,5 @@ /**

*/
const detachNodeFromParent = (node, parentNode) => {
export const detachNodeFromParent = (node, parentNode) => {
// avoid splice to not break for loops
parentNode.children = parentNode.children.filter((child) => child !== node);
};
exports.detachNodeFromParent = detachNodeFromParent;
{
"packageManager": "yarn@2.4.3",
"packageManager": "yarn@3.8.2",
"name": "svgo",
"version": "3.3.2",
"description": "Nodejs-based tool for optimizing SVG vector graphics files",
"version": "4.0.0-rc.0",
"description": "SVGO is a Node.js library and command-line application for optimizing vector images.",
"license": "MIT",
"type": "module",
"keywords": [

@@ -53,4 +54,25 @@ "svgo",

"main": "./lib/svgo-node.js",
"bin": "./bin/svgo",
"types": "./lib/svgo.d.ts",
"bin": "./bin/svgo.js",
"types": "./lib/svgo-node.d.ts",
"exports": {
".": {
"import": "./lib/svgo-node.js",
"require": "./dist/svgo-node.cjs",
"types": "./lib/svgo-node.d.ts"
},
"./browser": {
"import": "./dist/svgo.browser.js",
"types": "./lib/svgo.d.ts"
}
},
"typesVersions": {
"*": {
".": [
"./lib/svgo-node.d.ts"
],
"browser": [
"./lib/svgo.d.ts"
]
}
},
"files": [

@@ -64,13 +86,14 @@ "bin",

"engines": {
"node": ">=14.0.0"
"node": ">=16.0.0"
},
"scripts": {
"test": "NODE_OPTIONS=--experimental-vm-modules jest --maxWorkers=4 --coverage",
"lint": "eslint --ignore-path .gitignore . && prettier --check . --ignore-path .gitignore",
"fix": "eslint --ignore-path .gitignore --fix . && prettier --write . --ignore-path .gitignore",
"build": "node scripts/sync-version.js && rollup -c",
"typecheck": "tsc",
"test-browser": "rollup -c && node ./test/browser.js",
"test-regression": "node ./test/regression-extract.js && NO_DIFF=1 node ./test/regression.js",
"prepublishOnly": "rm -rf dist && rollup -c",
"qa": "yarn lint && yarn typecheck && yarn test && yarn test-browser && yarn test-regression"
"lint": "eslint . && prettier --check .",
"fix": "eslint --fix . && prettier --write .",
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --maxWorkers=4 --coverage",
"test:bundles": "yarn build && node ./test/svgo.cjs && node ./test/browser.js",
"test:regression": "node ./test/regression-extract.js && cross-env NO_DIFF=1 node ./test/regression.js",
"qa": "yarn typecheck && yarn lint && yarn test && yarn test:bundles && yarn test:regression",
"prepublishOnly": "rimraf dist && yarn build"
},

@@ -83,4 +106,3 @@ "jest": {

"dependencies": {
"@trysound/sax": "0.2.0",
"commander": "^7.2.0",
"commander": "^11.1.0",
"css-select": "^5.1.0",

@@ -90,23 +112,31 @@ "css-tree": "^2.3.1",

"csso": "^5.0.5",
"picocolors": "^1.0.0"
"picocolors": "^1.0.0",
"sax": "^1.4.1"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^22.0.2",
"@rollup/plugin-node-resolve": "^14.1.0",
"@types/css-tree": "^2.3.4",
"@eslint/js": "^9.3.0",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4",
"@types/css-tree": "^2.3.7",
"@types/csso": "^5.0.4",
"@types/jest": "^29.5.5",
"del": "^6.0.0",
"eslint": "^8.55.0",
"jest": "^29.5.5",
"node-fetch": "^2.7.0",
"@types/jest": "^29.5.12",
"@types/node": "^20.12.11",
"@types/sax": "^1.2.7",
"cross-env": "^7.0.3",
"eslint": "^9.3.0",
"globals": "^14.0.0",
"jest": "^29.7.0",
"pixelmatch": "^5.3.0",
"playwright": "^1.40.1",
"playwright": "^1.44.0",
"pngjs": "^7.0.0",
"prettier": "^3.1.1",
"rollup": "^2.79.1",
"rollup-plugin-terser": "^7.0.2",
"tar-stream": "^3.1.6",
"typescript": "^5.3.3"
"prettier": "^3.2.5",
"rimraf": "^5.0.7",
"rollup": "^4.17.2",
"tar-stream": "^3.1.7",
"typescript": "^5.4.5"
},
"resolutions": {
"sax@^1.4.1": "patch:sax@npm%3A1.4.1#./.yarn/patches/sax-npm-1.4.1-503b1923cb.patch"
}
}

@@ -1,3 +0,1 @@

'use strict';
// https://www.w3.org/TR/SVG11/intro.html#Definitions

@@ -8,3 +6,3 @@

*/
exports.elemsGroups = {
export const elemsGroups = {
animation: new Set([

@@ -61,2 +59,3 @@ 'animate',

textContent: new Set([
'a',
'altGlyph',

@@ -112,9 +111,5 @@ 'altGlyphDef',

*/
exports.textElems = new Set([
...exports.elemsGroups.textContent,
'pre',
'title',
]);
export const textElems = new Set([...elemsGroups.textContent, 'pre', 'title']);
exports.pathElems = new Set(['glyph', 'missing-glyph', 'path']);
export const pathElems = new Set(['glyph', 'missing-glyph', 'path']);

@@ -125,3 +120,3 @@ /**

*/
exports.attrsGroups = {
export const attrsGroups = {
animationAddition: new Set(['additive', 'accumulate']),

@@ -324,3 +319,3 @@ animationAttributeTarget: new Set(['attributeType', 'attributeName']),

*/
exports.attrsGroupsDefaults = {
export const attrsGroupsDefaults = {
core: { 'xml:space': 'default' },

@@ -390,2 +385,22 @@ presentation: {

/**
* @type {Record<string, { safe?: Set<string>, unsafe?: Set<string> }>}
* @see https://www.w3.org/TR/SVG11/intro.html#Definitions
*/
export const attrsGroupsDeprecated = {
animationAttributeTarget: { unsafe: new Set(['attributeType']) },
conditionalProcessing: { unsafe: new Set(['requiredFeatures']) },
core: { unsafe: new Set(['xml:base', 'xml:lang', 'xml:space']) },
presentation: {
unsafe: new Set([
'clip',
'color-profile',
'enable-background',
'glyph-orientation-horizontal',
'glyph-orientation-vertical',
'kerning',
]),
},
};
/**
* @type {Record<string, {

@@ -395,2 +410,6 @@ * attrsGroups: Set<string>,

* defaults?: Record<string, string>,
* deprecated?: {
* safe?: Set<string>,
* unsafe?: Set<string>,
* },
* contentGroups?: Set<string>,

@@ -401,3 +420,3 @@ * content?: Set<string>,

*/
exports.elems = {
export const elems = {
a: {

@@ -591,2 +610,3 @@ attrsGroups: new Set([

},
deprecated: { unsafe: new Set(['name']) },
contentGroups: new Set(['descriptive']),

@@ -976,2 +996,3 @@ },

},
deprecated: { unsafe: new Set(['filterRes']) },
contentGroups: new Set(['descriptive', 'filterPrimitive']),

@@ -997,2 +1018,11 @@ content: new Set(['animate', 'set']),

},
deprecated: {
unsafe: new Set([
'horiz-origin-x',
'horiz-origin-y',
'vert-adv-y',
'vert-origin-x',
'vert-origin-y',
]),
},
contentGroups: new Set(['descriptive']),

@@ -1048,2 +1078,27 @@ content: new Set(['font-face', 'glyph', 'hkern', 'missing-glyph', 'vkern']),

},
deprecated: {
unsafe: new Set([
'accent-height',
'alphabetic',
'ascent',
'bbox',
'cap-height',
'descent',
'hanging',
'ideographic',
'mathematical',
'panose-1',
'slope',
'stemh',
'stemv',
'unicode-range',
'units-per-em',
'v-alphabetic',
'v-hanging',
'v-ideographic',
'v-mathematical',
'widths',
'x-height',
]),
},
contentGroups: new Set(['descriptive']),

@@ -1059,2 +1114,3 @@ content: new Set([

attrs: new Set(['string']),
deprecated: { unsafe: new Set(['string']) },
},

@@ -1064,2 +1120,3 @@ 'font-face-name': {

attrs: new Set(['name']),
deprecated: { unsafe: new Set(['name']) },
},

@@ -1157,2 +1214,14 @@ 'font-face-src': {

},
deprecated: {
unsafe: new Set([
'arabic-form',
'glyph-name',
'horiz-adv-x',
'orientation',
'unicode',
'vert-adv-y',
'vert-origin-x',
'vert-origin-y',
]),
},
contentGroups: new Set([

@@ -1197,2 +1266,10 @@ 'animation',

]),
deprecated: {
unsafe: new Set([
'horiz-adv-x',
'vert-adv-y',
'vert-origin-x',
'vert-origin-y',
]),
},
contentGroups: new Set([

@@ -1261,2 +1338,3 @@ 'animation',

attrs: new Set(['u1', 'g1', 'u2', 'g2', 'k']),
deprecated: { unsafe: new Set(['g1', 'g2', 'k', 'u1', 'u2']) },
},

@@ -1456,2 +1534,10 @@ image: {

]),
deprecated: {
unsafe: new Set([
'horiz-adv-x',
'vert-adv-y',
'vert-origin-x',
'vert-origin-y',
]),
},
contentGroups: new Set([

@@ -1737,2 +1823,11 @@ 'animation',

},
deprecated: {
safe: new Set(['version']),
unsafe: new Set([
'baseProfile',
'contentScriptType',
'contentStyleType',
'zoomAndPan',
]),
},
contentGroups: new Set([

@@ -1984,2 +2079,3 @@ 'animation',

]),
deprecated: { unsafe: new Set(['viewTarget', 'zoomAndPan']) },
contentGroups: new Set(['descriptive']),

@@ -1990,2 +2086,3 @@ },

attrs: new Set(['u1', 'g1', 'u2', 'g2', 'k']),
deprecated: { unsafe: new Set(['g1', 'g2', 'k', 'u1', 'u2']) },
},

@@ -1995,3 +2092,3 @@ };

// https://wiki.inkscape.org/wiki/index.php/Inkscape-specific_XML_attributes
exports.editorNamespaces = new Set([
export const editorNamespaces = new Set([
'http://creativecommons.org/ns#',

@@ -2024,3 +2121,3 @@ 'http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd',

*/
exports.referencesProps = new Set([
export const referencesProps = new Set([
'clip-path',

@@ -2041,3 +2138,3 @@ 'color-profile',

*/
exports.inheritableAttrs = new Set([
export const inheritableAttrs = new Set([
'clip-rule',

@@ -2090,3 +2187,3 @@ 'color-interpolation-filters',

exports.presentationNonInheritableGroupAttrs = new Set([
export const presentationNonInheritableGroupAttrs = new Set([
'clip-path',

@@ -2107,3 +2204,3 @@ 'display',

*/
exports.colorsNames = {
export const colorsNames = {
aliceblue: '#f0f8ff',

@@ -2262,3 +2359,3 @@ antiquewhite: '#faebd7',

*/
exports.colorsShortNames = {
export const colorsShortNames = {
'#f0ffff': 'azure',

@@ -2301,3 +2398,3 @@ '#f5f5dc': 'beige',

*/
exports.colorsProps = new Set([
export const colorsProps = new Set([
'color',

@@ -2312,3 +2409,3 @@ 'fill',

/** @see https://developer.mozilla.org/docs/Web/CSS/Pseudo-classes */
exports.pseudoClasses = {
export const pseudoClasses = {
displayState: new Set(['fullscreen', 'modal', 'picture-in-picture']),

@@ -2315,0 +2412,0 @@ input: new Set([

@@ -1,10 +0,8 @@

'use strict';
import { parsePathData, stringifyPathData } from '../lib/path.js';
/**
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types').PathDataItem} PathDataItem
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').PathDataItem} PathDataItem
*/
const { parsePathData, stringifyPathData } = require('../lib/path.js');
/**

@@ -20,3 +18,3 @@ * @type {[number, number]}

*/
const path2js = (path) => {
export const path2js = (path) => {
// @ts-ignore legacy

@@ -40,3 +38,2 @@ if (path.pathJS) return path.pathJS;

};
exports.path2js = path2js;

@@ -186,3 +183,3 @@ /**

*/
exports.js2path = function (path, data, params) {
export const js2path = function (path, data, params) {
// @ts-ignore legacy

@@ -232,3 +229,3 @@ path.pathJS = data;

*/
exports.intersects = function (path1, path2) {
export const intersects = function (path1, path2) {
// Collect points of every subpath.

@@ -272,3 +269,3 @@ const points1 = gatherPoints(convertRelativeToAbsolute(path1));

var iterations = 1e4; // infinite loop protection, 10 000 iterations is more than enough
// eslint-disable-next-line no-constant-condition
while (true) {

@@ -275,0 +272,0 @@ if (iterations-- == 0) {

@@ -1,5 +0,3 @@

'use strict';
import { cleanupOutData, toFixed } from '../lib/svgo/tools.js';
const { toFixed } = require('../lib/svgo/tools');
/**

@@ -9,2 +7,3 @@ * @typedef {{ name: string, data: number[] }} TransformItem

* convertToShorts: boolean,
* degPrecision?: number,
* floatPrecision: number,

@@ -42,3 +41,3 @@ * transformPrecision: number,

*/
exports.transform2js = (transformString) => {
export const transform2js = (transformString) => {
/** @type {TransformItem[]} */

@@ -74,3 +73,2 @@ const transforms = [];

};
/**

@@ -82,3 +80,3 @@ * Multiply transforms into one.

*/
exports.transformsMultiply = (transforms) => {
export const transformsMultiply = (transforms) => {
const matrixData = transforms.map((transform) => {

@@ -173,111 +171,321 @@ if (transform.name === 'matrix') {

/**
* Decompose matrix into simple transforms.
*
* @param {TransformItem} transform
* @param {TransformParams} params
* @returns {TransformItem[]}
* @see https://frederic-wang.fr/decomposition-of-2d-transform-matrices.html
* @param {TransformItem} matrix
* @returns {TransformItem[][]}
*/
exports.matrixToTransform = (transform, params) => {
const floatPrecision = params.floatPrecision;
const data = transform.data;
const transforms = [];
const getDecompositions = (matrix) => {
const decompositions = [];
const qrab = decomposeQRAB(matrix);
const qrcd = decomposeQRCD(matrix);
if (qrab) {
decompositions.push(qrab);
}
if (qrcd) {
decompositions.push(qrcd);
}
return decompositions;
};
/**
* @param {TransformItem} matrix
* @returns {TransformItem[]|undefined}
* @see {@link https://frederic-wang.fr/decomposition-of-2d-transform-matrices.html} Where applicable, variables are named in accordance with this document.
*/
const decomposeQRAB = (matrix) => {
const data = matrix.data;
const [a, b, c, d, e, f] = data;
const delta = a * d - b * c;
if (delta === 0) {
return;
}
const r = Math.hypot(a, b);
if (r === 0) {
return;
}
const decomposition = [];
const cosOfRotationAngle = a / r;
// [..., ..., ..., ..., tx, ty] → translate(tx, ty)
if (data[4] || data[5]) {
transforms.push({
if (e || f) {
decomposition.push({
name: 'translate',
data: data.slice(4, data[5] ? 6 : 5),
data: [e, f],
});
}
let sx = toFixed(Math.hypot(data[0], data[1]), params.transformPrecision);
let sy = toFixed(
(data[0] * data[3] - data[1] * data[2]) / sx,
params.transformPrecision,
);
const colsSum = data[0] * data[2] + data[1] * data[3];
const rowsSum = data[0] * data[1] + data[2] * data[3];
const scaleBefore = rowsSum !== 0 || sx === sy;
if (cosOfRotationAngle !== 1) {
const rotationAngleRads = Math.acos(cosOfRotationAngle);
decomposition.push({
name: 'rotate',
data: [mth.deg(b < 0 ? -rotationAngleRads : rotationAngleRads), 0, 0],
});
}
// [sx, 0, tan(a)·sy, sy, 0, 0] → skewX(a)·scale(sx, sy)
if (!data[1] && data[2]) {
transforms.push({
const sx = r;
const sy = delta / sx;
if (sx !== 1 || sy !== 1) {
decomposition.push({ name: 'scale', data: [sx, sy] });
}
const ac_plus_bd = a * c + b * d;
if (ac_plus_bd) {
decomposition.push({
name: 'skewX',
data: [mth.atan(data[2] / sy, floatPrecision)],
data: [mth.deg(Math.atan(ac_plus_bd / (a * a + b * b)))],
});
}
// [sx, sx·tan(a), 0, sy, 0, 0] → skewY(a)·scale(sx, sy)
} else if (data[1] && !data[2]) {
transforms.push({
return decomposition;
};
/**
* @param {TransformItem} matrix
* @returns {TransformItem[]|undefined}
* @see {@link https://frederic-wang.fr/decomposition-of-2d-transform-matrices.html} Where applicable, variables are named in accordance with this document.
*/
const decomposeQRCD = (matrix) => {
const data = matrix.data;
const [a, b, c, d, e, f] = data;
const delta = a * d - b * c;
if (delta === 0) {
return;
}
const s = Math.hypot(c, d);
if (s === 0) {
return;
}
const decomposition = [];
if (e || f) {
decomposition.push({
name: 'translate',
data: [e, f],
});
}
const rotationAngleRads = Math.PI / 2 - (d < 0 ? -1 : 1) * Math.acos(-c / s);
decomposition.push({
name: 'rotate',
data: [mth.deg(rotationAngleRads), 0, 0],
});
const sx = delta / s;
const sy = s;
if (sx !== 1 || sy !== 1) {
decomposition.push({ name: 'scale', data: [sx, sy] });
}
const ac_plus_bd = a * c + b * d;
if (ac_plus_bd) {
decomposition.push({
name: 'skewY',
data: [mth.atan(data[1] / data[0], floatPrecision)],
data: [mth.deg(Math.atan(ac_plus_bd / (c * c + d * d)))],
});
sx = data[0];
sy = data[3];
}
// [sx·cos(a), sx·sin(a), sy·-sin(a), sy·cos(a), x, y] → rotate(a[, cx, cy])·(scale or skewX) or
// [sx·cos(a), sy·sin(a), sx·-sin(a), sy·cos(a), x, y] → scale(sx, sy)·rotate(a[, cx, cy]) (if !scaleBefore)
} else if (!colsSum || (sx === 1 && sy === 1) || !scaleBefore) {
if (!scaleBefore) {
sx = Math.hypot(data[0], data[2]);
sy = Math.hypot(data[1], data[3]);
return decomposition;
};
if (toFixed(data[0], params.transformPrecision) < 0) {
sx = -sx;
}
/**
* Convert translate(tx,ty)rotate(a) to rotate(a,cx,cy).
* @param {number} tx
* @param {number} ty
* @param {number} a
* @returns {TransformItem}
*/
const mergeTranslateAndRotate = (tx, ty, a) => {
// From https://www.w3.org/TR/SVG11/coords.html#TransformAttribute:
// We have translate(tx,ty) rotate(a). This is equivalent to [cos(a) sin(a) -sin(a) cos(a) tx ty].
//
// rotate(a,cx,cy) is equivalent to translate(cx, cy) rotate(a) translate(-cx, -cy).
// Multiplying the right side gives the matrix
// [cos(a) sin(a) -sin(a) cos(a)
// -cx * cos(a) + cy * sin(a) + cx
// -cx * sin(a) - cy * cos(a) + cy
// ]
//
// We need cx and cy such that
// tx = -cx * cos(a) + cy * sin(a) + cx
// ty = -cx * sin(a) - cy * cos(a) + cy
//
// Solving these for cx and cy gives
// cy = (d * ty + e * tx)/(d^2 + e^2)
// cx = (tx - e * cy) / d
// where d = 1 - cos(a) and e = sin(a)
if (
data[3] < 0 ||
(Math.sign(data[1]) === Math.sign(data[2]) &&
toFixed(data[3], params.transformPrecision) === 0)
) {
sy = -sy;
}
const rotationAngleRads = mth.rad(a);
const d = 1 - Math.cos(rotationAngleRads);
const e = Math.sin(rotationAngleRads);
const cy = (d * ty + e * tx) / (d * d + e * e);
const cx = (tx - e * cy) / d;
return { name: 'rotate', data: [a, cx, cy] };
};
transforms.push({ name: 'scale', data: [sx, sy] });
}
const angle = Math.min(Math.max(-1, data[0] / sx), 1);
const rotate = [
mth.acos(angle, floatPrecision) *
((scaleBefore ? 1 : sy) * data[1] < 0 ? -1 : 1),
];
/**
* @param {TransformItem} t
* @returns {Boolean}
*/
const isIdentityTransform = (t) => {
switch (t.name) {
case 'rotate':
case 'skewX':
case 'skewY':
return t.data[0] === 0;
case 'scale':
return t.data[0] === 1 && t.data[1] === 1;
case 'translate':
return t.data[0] === 0 && t.data[1] === 0;
}
return false;
};
if (rotate[0]) {
transforms.push({ name: 'rotate', data: rotate });
/**
* Optimize matrix of simple transforms.
* @param {TransformItem[]} roundedTransforms
* @param {TransformItem[]} rawTransforms
* @returns {TransformItem[]}
*/
const optimize = (roundedTransforms, rawTransforms) => {
const optimizedTransforms = [];
for (let index = 0; index < roundedTransforms.length; index++) {
const roundedTransform = roundedTransforms[index];
// Don't include any identity transforms.
if (isIdentityTransform(roundedTransform)) {
continue;
}
const data = roundedTransform.data;
switch (roundedTransform.name) {
case 'rotate':
switch (data[0]) {
case 180:
case -180:
{
// If the next element is a scale, invert it, and don't add the rotate to the optimized array.
const next = roundedTransforms[index + 1];
if (next && next.name === 'scale') {
optimizedTransforms.push(
createScaleTransform(next.data.map((v) => -v)),
);
index++;
} else {
// Otherwise replace the rotate with a scale(-1).
optimizedTransforms.push({
name: 'scale',
data: [-1],
});
}
}
continue;
}
optimizedTransforms.push({
name: 'rotate',
data: data.slice(0, data[1] || data[2] ? 3 : 1),
});
break;
if (rowsSum && colsSum)
transforms.push({
name: 'skewX',
data: [mth.atan(colsSum / (sx * sx), floatPrecision)],
});
case 'scale':
optimizedTransforms.push(createScaleTransform(data));
break;
// rotate(a, cx, cy) can consume translate() within optional arguments cx, cy (rotation point)
if (rotate[0] && (data[4] || data[5])) {
transforms.shift();
const oneOverCos = 1 - data[0] / sx;
const sin = data[1] / (scaleBefore ? sx : sy);
const x = data[4] * (scaleBefore ? 1 : sy);
const y = data[5] * (scaleBefore ? 1 : sx);
const denom = (oneOverCos ** 2 + sin ** 2) * (scaleBefore ? 1 : sx * sy);
rotate.push(
(oneOverCos * x - sin * y) / denom,
(oneOverCos * y + sin * x) / denom,
);
case 'skewX':
case 'skewY':
optimizedTransforms.push({
name: roundedTransform.name,
data: [data[0]],
});
break;
case 'translate':
{
// If the next item is a rotate(a,0,0), merge the translate and rotate.
// If the rotation angle is +/-180, assume it will be optimized out, and don't do the merge.
const next = roundedTransforms[index + 1];
if (
next &&
next.name === 'rotate' &&
next.data[0] !== 180 &&
next.data[0] !== -180 &&
next.data[0] !== 0 &&
next.data[1] === 0 &&
next.data[2] === 0
) {
// Use the un-rounded data to do the merge.
const data = rawTransforms[index].data;
optimizedTransforms.push(
mergeTranslateAndRotate(
data[0],
data[1],
rawTransforms[index + 1].data[0],
),
);
// Skip over the rotate.
index++;
continue;
}
}
optimizedTransforms.push({
name: 'translate',
data: data.slice(0, data[1] ? 2 : 1),
});
break;
}
// Too many transformations, return original matrix if it isn't just a scale/translate
} else if (data[1] || data[2]) {
return [transform];
}
if ((scaleBefore && (sx != 1 || sy != 1)) || !transforms.length) {
transforms.push({
name: 'scale',
data: sx == sy ? [sx] : [sx, sy],
// If everything was optimized out, return identity transform scale(1).
return optimizedTransforms.length
? optimizedTransforms
: [{ name: 'scale', data: [1] }];
};
/**
* @param {number[]} data
* @returns {TransformItem}
*/
const createScaleTransform = (data) => {
const scaleData = data.slice(0, data[0] === data[1] ? 1 : 2);
return {
name: 'scale',
data: scaleData,
};
};
/**
* Decompose matrix into simple transforms and optimize.
* @param {TransformItem} origMatrix
* @param {TransformParams} params
* @returns {TransformItem[]}
*/
export const matrixToTransform = (origMatrix, params) => {
const decomposed = getDecompositions(origMatrix);
let shortest;
let shortestLen = Number.MAX_VALUE;
for (const decomposition of decomposed) {
// Make a copy of the decomposed matrix, and round all data. We need to keep the original decomposition,
// at full precision, to perform some optimizations.
const roundedTransforms = decomposition.map((transformItem) => {
const transformCopy = {
name: transformItem.name,
data: [...transformItem.data],
};
return roundTransform(transformCopy, params);
});
const optimized = optimize(roundedTransforms, decomposition);
const len = js2transform(optimized, params).length;
if (len < shortestLen) {
shortest = optimized;
shortestLen = len;
}
}
return transforms;
return shortest ?? [origMatrix];
};

@@ -304,3 +512,3 @@

0,
transform.data[1] || transform.data[0],
transform.data[1] ?? transform.data[0],
0,

@@ -346,3 +554,3 @@ 0,

*/
exports.transformArc = (cursor, arc, transform) => {
export const transformArc = (cursor, arc, transform) => {
const x = arc[5] - cursor[0];

@@ -418,1 +626,124 @@ const y = arc[6] - cursor[1];

};
/**
* @type {(transform: TransformItem, params: TransformParams) => TransformItem}
*/
export const roundTransform = (transform, params) => {
switch (transform.name) {
case 'translate':
transform.data = floatRound(transform.data, params);
break;
case 'rotate':
transform.data = [
...degRound(transform.data.slice(0, 1), params),
...floatRound(transform.data.slice(1), params),
];
break;
case 'skewX':
case 'skewY':
transform.data = degRound(transform.data, params);
break;
case 'scale':
transform.data = transformRound(transform.data, params);
break;
case 'matrix':
transform.data = [
...transformRound(transform.data.slice(0, 4), params),
...floatRound(transform.data.slice(4), params),
];
break;
}
return transform;
};
/**
* @type {(data: number[], params: TransformParams) => number[]}
*/
const degRound = (data, params) => {
if (
params.degPrecision != null &&
params.degPrecision >= 1 &&
params.floatPrecision < 20
) {
return smartRound(params.degPrecision, data);
} else {
return round(data);
}
};
/**
* @type {(data: number[], params: TransformParams) => number[]}
*/
const floatRound = (data, params) => {
if (params.floatPrecision >= 1 && params.floatPrecision < 20) {
return smartRound(params.floatPrecision, data);
} else {
return round(data);
}
};
/**
* @type {(data: number[], params: TransformParams) => number[]}
*/
const transformRound = (data, params) => {
if (params.transformPrecision >= 1 && params.floatPrecision < 20) {
return smartRound(params.transformPrecision, data);
} else {
return round(data);
}
};
/**
* Rounds numbers in array.
*
* @type {(data: number[]) => number[]}
*/
const round = (data) => {
return data.map(Math.round);
};
/**
* Decrease accuracy of floating-point numbers
* in transforms keeping a specified number of decimals.
* Smart rounds values like 2.349 to 2.35.
*
* @param {number} precision
* @param {number[]} data
* @returns {number[]}
*/
const smartRound = (precision, data) => {
for (
var i = data.length,
tolerance = +Math.pow(0.1, precision).toFixed(precision);
i--;
) {
if (toFixed(data[i], precision) !== data[i]) {
var rounded = +data[i].toFixed(precision - 1);
data[i] =
+Math.abs(rounded - data[i]).toFixed(precision + 1) >= tolerance
? +data[i].toFixed(precision)
: rounded;
}
}
return data;
};
/**
* Convert transforms JS representation to string.
*
* @param {TransformItem[]} transformJS
* @param {TransformParams} params
* @returns {string}
*/
export const js2transform = (transformJS, params) => {
const transformString = transformJS
.map((transform) => {
roundTransform(transform, params);
return `${transform.name}(${cleanupOutData(transform.data, params)})`;
})
.join('');
return transformString;
};

@@ -1,6 +0,4 @@

'use strict';
export const name = 'addAttributesToSVGElement';
export const description = 'adds attributes to an outer <svg> element';
exports.name = 'addAttributesToSVGElement';
exports.description = 'adds attributes to an outer <svg> element';
var ENOCLS = `Error in plugin "addAttributesToSVGElement": absent parameters.

@@ -50,5 +48,5 @@ It should have a list of "attributes" or one "attribute".

*
* @type {import('./plugins-types').Plugin<'addAttributesToSVGElement'>}
* @type {import('./plugins-types.js').Plugin<'addAttributesToSVGElement'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
if (!Array.isArray(params.attributes) && !params.attribute) {

@@ -55,0 +53,0 @@ console.error(ENOCLS);

@@ -1,6 +0,4 @@

'use strict';
export const name = 'addClassesToSVGElement';
export const description = 'adds classnames to an outer <svg> element';
exports.name = 'addClassesToSVGElement';
exports.description = 'adds classnames to an outer <svg> element';
var ENOCLS = `Error in plugin "addClassesToSVGElement": absent parameters.

@@ -52,7 +50,7 @@ It should have a list of classes in "classNames" or one "className".

*
* @type {import('./plugins-types').Plugin<'addClassesToSVGElement'>}
* @type {import('./plugins-types.js').Plugin<'addClassesToSVGElement'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params, info) => {
if (
!(Array.isArray(params.classNames) && params.classNames.some(String)) &&
!(Array.isArray(params.classNames) && params.classNames.length !== 0) &&
!params.className

@@ -75,3 +73,7 @@ ) {

if (className != null) {
classList.add(className);
const classToAdd =
typeof className === 'string'
? className
: className(node, info);
classList.add(classToAdd);
}

@@ -78,0 +80,0 @@ }

@@ -1,21 +0,17 @@

'use strict';
/**
* @typedef {import('../lib/types').PathDataItem} PathDataItem
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types.js').PathDataItem} PathDataItem
* @typedef {import('../lib/types.js').XastElement} XastElement
*/
const { collectStylesheet, computeStyle } = require('../lib/style.js');
const {
import { path2js } from './_path.js';
import {
transformsMultiply,
transform2js,
transformArc,
} = require('./_transforms.js');
const { path2js } = require('./_path.js');
const {
removeLeadingZero,
includesUrlReference,
} = require('../lib/svgo/tools.js');
const { referencesProps, attrsGroupsDefaults } = require('./_collections.js');
} from './_transforms.js';
import { referencesProps, attrsGroupsDefaults } from './_collections.js';
import { collectStylesheet, computeStyle } from '../lib/style.js';
import { removeLeadingZero, includesUrlReference } from '../lib/svgo/tools.js';
/**

@@ -31,3 +27,3 @@ * @typedef {PathDataItem[]} PathData

*
* @type {import('../lib/types').Plugin<{
* @type {import('../lib/types.js').Plugin<{
* transformPrecision: number,

@@ -37,3 +33,3 @@ * applyTransformsStroked: boolean,

*/
const applyTransforms = (root, params) => {
export const applyTransforms = (root, params) => {
const stylesheet = collectStylesheet(root);

@@ -102,5 +98,5 @@ return {

const scale = Number(
Math.sqrt(
matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1],
).toFixed(transformPrecision),
Math.hypot(matrix.data[0], matrix.data[1]).toFixed(
transformPrecision,
),
);

@@ -166,3 +162,2 @@

};
exports.applyTransforms = applyTransforms;

@@ -224,3 +219,3 @@ /**

// horizontal lineto (x)
// convert to lineto to handle two-dimentional transforms
// convert to lineto to handle two-dimensional transforms
if (command === 'H') {

@@ -236,3 +231,3 @@ command = 'L';

// vertical lineto (y)
// convert to lineto to handle two-dimentional transforms
// convert to lineto to handle two-dimensional transforms
if (command === 'V') {

@@ -239,0 +234,0 @@ command = 'L';

@@ -1,5 +0,3 @@

'use strict';
exports.name = 'cleanupAttrs';
exports.description =
export const name = 'cleanupAttrs';
export const description =
'cleanups attributes from newlines, trailing and repeating spaces';

@@ -15,6 +13,5 @@

* @author Kir Belevich
*
* @type {import('./plugins-types').Plugin<'cleanupAttrs'>}
* @type {import('./plugins-types.js').Plugin<'cleanupAttrs'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const { newlines = true, trim = true, spaces = true } = params;

@@ -21,0 +18,0 @@ return {

@@ -1,8 +0,6 @@

'use strict';
import * as csstree from 'css-tree';
import { visit } from '../lib/xast.js';
const csstree = require('css-tree');
const { visit } = require('../lib/xast.js');
exports.name = 'cleanupEnableBackground';
exports.description =
export const name = 'cleanupEnableBackground';
export const description =
'remove or cleanup enable-background attribute when possible';

@@ -22,5 +20,5 @@

* @author Kir Belevich
* @type {import('./plugins-types').Plugin<'cleanupEnableBackground'>}
* @type {import('./plugins-types.js').Plugin<'cleanupEnableBackground'>}
*/
exports.fn = (root) => {
export const fn = (root) => {
let hasFilter = false;

@@ -27,0 +25,0 @@

@@ -1,13 +0,11 @@

'use strict';
import { visitSkip } from '../lib/xast.js';
import { hasScripts, findReferences } from '../lib/svgo/tools.js';
/**
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types.js').XastElement} XastElement
*/
const { visitSkip } = require('../lib/xast.js');
const { hasScripts, findReferences } = require('../lib/svgo/tools');
export const name = 'cleanupIds';
export const description = 'removes unused IDs and minifies used';
exports.name = 'cleanupIds';
exports.description = 'removes unused IDs and minifies used';
const generateIdChars = [

@@ -124,5 +122,5 @@ 'a',

*
* @type {import('./plugins-types').Plugin<'cleanupIds'>}
* @type {import('./plugins-types.js').Plugin<'cleanupIds'>}
*/
exports.fn = (_root, params) => {
export const fn = (_root, params) => {
const {

@@ -238,6 +236,5 @@ remove = true,

// replace id in href and url()
element.attributes[name] = value.replace(
`#${encodeURI(id)}`,
`#${currentIdString}`,
);
element.attributes[name] = value
.replace(`#${encodeURI(id)}`, `#${currentIdString}`)
.replace(`#${id}`, `#${currentIdString}`);
} else {

@@ -244,0 +241,0 @@ // replace id in begin attribute

@@ -1,8 +0,6 @@

'use strict';
import { removeLeadingZero } from '../lib/svgo/tools.js';
const { removeLeadingZero } = require('../lib/svgo/tools.js');
export const name = 'cleanupListOfValues';
export const description = 'rounds list of values to the fixed precision';
exports.name = 'cleanupListOfValues';
exports.description = 'rounds list of values to the fixed precision';
const regNumericValues =

@@ -35,5 +33,5 @@ /^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/;

*
* @type {import('./plugins-types').Plugin<'cleanupListOfValues'>}
* @type {import('./plugins-types.js').Plugin<'cleanupListOfValues'>}
*/
exports.fn = (_root, params) => {
export const fn = (_root, params) => {
const {

@@ -40,0 +38,0 @@ floatPrecision = 3,

@@ -1,7 +0,5 @@

'use strict';
import { removeLeadingZero } from '../lib/svgo/tools.js';
const { removeLeadingZero } = require('../lib/svgo/tools');
exports.name = 'cleanupNumericValues';
exports.description =
export const name = 'cleanupNumericValues';
export const description =
'rounds numeric values to the fixed precision, removes default ‘px’ units';

@@ -28,5 +26,5 @@

*
* @type {import('./plugins-types').Plugin<'cleanupNumericValues'>}
* @type {import('./plugins-types.js').Plugin<'cleanupNumericValues'>}
*/
exports.fn = (_root, params) => {
export const fn = (_root, params) => {
const {

@@ -33,0 +31,0 @@ floatPrecision = 3,

@@ -1,12 +0,12 @@

'use strict';
import { computeStyle, collectStylesheet } from '../lib/style.js';
import { inheritableAttrs, elemsGroups } from './_collections.js';
/**
* @typedef {import('../lib/types').XastNode} XastNode
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastNode} XastNode
*/
const { inheritableAttrs, elemsGroups } = require('./_collections.js');
export const name = 'collapseGroups';
export const description = 'collapses useless groups';
exports.name = 'collapseGroups';
exports.description = 'collapses useless groups';
/**

@@ -52,5 +52,7 @@ * @type {(node: XastNode, name: string) => boolean}

*
* @type {import('./plugins-types').Plugin<'collapseGroups'>}
* @type {import('./plugins-types.js').Plugin<'collapseGroups'>}
*/
exports.fn = () => {
export const fn = (root) => {
const stylesheet = collectStylesheet(root);
return {

@@ -73,2 +75,5 @@ element: {

const firstChild = node.children[0];
const nodeHasFilter = !!(
node.attributes.filter || computeStyle(stylesheet, node).filter
);
// TODO untangle this mess

@@ -78,3 +83,3 @@ if (

firstChild.attributes.id == null &&
node.attributes.filter == null &&
!nodeHasFilter &&
(node.attributes.class == null ||

@@ -88,2 +93,4 @@ firstChild.attributes.class == null) &&

) {
const newChildElemAttrs = { ...firstChild.attributes };
for (const [name, value] of Object.entries(node.attributes)) {

@@ -94,17 +101,19 @@ // avoid copying to not conflict with animated attribute

}
if (firstChild.attributes[name] == null) {
firstChild.attributes[name] = value;
if (newChildElemAttrs[name] == null) {
newChildElemAttrs[name] = value;
} else if (name === 'transform') {
firstChild.attributes[name] =
value + ' ' + firstChild.attributes[name];
} else if (firstChild.attributes[name] === 'inherit') {
firstChild.attributes[name] = value;
newChildElemAttrs[name] = value + ' ' + newChildElemAttrs[name];
} else if (newChildElemAttrs[name] === 'inherit') {
newChildElemAttrs[name] = value;
} else if (
inheritableAttrs.has(name) === false &&
firstChild.attributes[name] !== value
!inheritableAttrs.has(name) &&
newChildElemAttrs[name] !== value
) {
return;
}
delete node.attributes[name];
}
node.attributes = {};
firstChild.attributes = newChildElemAttrs;
}

@@ -111,0 +120,0 @@ }

@@ -1,10 +0,10 @@

'use strict';
import { colorsNames, colorsProps, colorsShortNames } from './_collections.js';
import { includesUrlReference } from '../lib/svgo/tools.js';
const collections = require('./_collections.js');
export const name = 'convertColors';
export const description =
'converts colors: rgb() to #rrggbb and #rrggbb to #rgb';
exports.name = 'convertColors';
exports.description = 'converts colors: rgb() to #rrggbb and #rrggbb to #rgb';
const rNumber = '([+-]?(?:\\d*\\.\\d+|\\d+\\.?)%?)';
const rComma = '\\s*,\\s*';
const rComma = '(?:\\s*,\\s*|\\s+)';
const regRGB = new RegExp(

@@ -64,5 +64,5 @@ '^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$',

*
* @type {import('./plugins-types').Plugin<'convertColors'>}
* @type {import('./plugins-types.js').Plugin<'convertColors'>}
*/
exports.fn = (_root, params) => {
export const fn = (_root, params) => {
const {

@@ -72,2 +72,3 @@ currentColor = false,

rgb2hex = true,
convertCase = 'lower',
shorthex = true,

@@ -81,3 +82,3 @@ shortname = true,

for (const [name, value] of Object.entries(node.attributes)) {
if (collections.colorsProps.has(name)) {
if (colorsProps.has(name)) {
let val = value;

@@ -96,3 +97,3 @@

if (matched) {
val = 'currentColor';
val = 'currentcolor';
}

@@ -104,4 +105,4 @@ }

const colorName = val.toLowerCase();
if (collections.colorsNames[colorName] != null) {
val = collections.colorsNames[colorName];
if (colorsNames[colorName] != null) {
val = colorsNames[colorName];
}

@@ -127,5 +128,13 @@ }

if (convertCase && !includesUrlReference(val)) {
if (convertCase === 'lower') {
val = val.toLowerCase();
} else if (convertCase === 'upper') {
val = val.toUpperCase();
}
}
// convert long hex to short hex
if (shorthex) {
let match = val.match(regHEX);
let match = regHEX.exec(val);
if (match != null) {

@@ -139,4 +148,4 @@ val = '#' + match[0][1] + match[0][3] + match[0][5];

const colorName = val.toLowerCase();
if (collections.colorsShortNames[colorName] != null) {
val = collections.colorsShortNames[colorName];
if (colorsShortNames[colorName] != null) {
val = colorsShortNames[colorName];
}

@@ -143,0 +152,0 @@ }

@@ -1,6 +0,4 @@

'use strict';
export const name = 'convertEllipseToCircle';
export const description = 'converts non-eccentric <ellipse>s to <circle>s';
exports.name = 'convertEllipseToCircle';
exports.description = 'converts non-eccentric <ellipse>s to <circle>s';
/**

@@ -13,5 +11,5 @@ * Converts non-eccentric <ellipse>s to <circle>s.

*
* @type {import('./plugins-types').Plugin<'convertEllipseToCircle'>}
* @type {import('./plugins-types.js').Plugin<'convertEllipseToCircle'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -18,0 +16,0 @@ element: {

@@ -1,18 +0,16 @@

'use strict';
import { attrsGroupsDefaults, colorsProps } from './_collections.js';
import {
detachNodeFromParent,
querySelectorAll,
querySelector,
} from '../lib/xast.js';
import { computeStyle, collectStylesheet } from '../lib/style.js';
/**
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types').XastParent} XastParent
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
*/
const { attrsGroupsDefaults, colorsProps } = require('./_collections');
const {
detachNodeFromParent,
querySelectorAll,
querySelector,
} = require('../lib/xast');
const { computeStyle, collectStylesheet } = require('../lib/style');
exports.name = 'convertOneStopGradients';
exports.description =
export const name = 'convertOneStopGradients';
export const description =
'converts one-stop (single color) gradients to a plain color';

@@ -24,7 +22,7 @@

* @author Seth Falco <seth@falco.fun>
* @type {import('./plugins-types').Plugin<'convertOneStopGradients'>}
* @type {import('./plugins-types.js').Plugin<'convertOneStopGradients'>}
* @see https://developer.mozilla.org/docs/Web/SVG/Element/linearGradient
* @see https://developer.mozilla.org/docs/Web/SVG/Element/radialGradient
*/
exports.fn = (root) => {
export const fn = (root) => {
const stylesheet = collectStylesheet(root);

@@ -31,0 +29,0 @@

@@ -1,16 +0,14 @@

'use strict';
import { path2js, js2path } from './_path.js';
import { pathElems } from './_collections.js';
import { applyTransforms } from './applyTransforms.js';
import { collectStylesheet, computeStyle } from '../lib/style.js';
import { visit } from '../lib/xast.js';
import { cleanupOutData, toFixed } from '../lib/svgo/tools.js';
/**
* @typedef {import('../lib//types').PathDataItem} PathDataItem
* @typedef {import('../lib/types.js').PathDataItem} PathDataItem
*/
const { collectStylesheet, computeStyle } = require('../lib/style.js');
const { visit } = require('../lib/xast.js');
const { pathElems } = require('./_collections.js');
const { path2js, js2path } = require('./_path.js');
const { applyTransforms } = require('./applyTransforms.js');
const { cleanupOutData, toFixed } = require('../lib/svgo/tools');
exports.name = 'convertPathData';
exports.description =
export const name = 'convertPathData';
export const description =
'optimizes path data: writes in shorter form, applies transformations';

@@ -78,5 +76,5 @@

*
* @type {import('./plugins-types').Plugin<'convertPathData'>}
* @type {import('./plugins-types.js').Plugin<'convertPathData'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const {

@@ -178,6 +176,9 @@ // TODO convert to separate plugin in v3

var data = path2js(node);
let data = path2js(node);
// TODO: get rid of functions returns
if (data.length) {
const includesVertices = data.some(
(item) => item.command !== 'm' && item.command !== 'M',
);
convertToRelative(data);

@@ -195,2 +196,19 @@

const hasMarker =
node.attributes['marker-start'] != null ||
node.attributes['marker-end'] != null;
const isMarkersOnlyPath =
hasMarker &&
includesVertices &&
data.every(
(item) => item.command === 'm' || item.command === 'M',
);
if (isMarkersOnlyPath) {
data.push({
command: 'z',
args: [],
});
}
// @ts-ignore

@@ -402,3 +420,2 @@ js2path(node, data, newParams);

const qControlPoint = prevQControlPoint;
prevQControlPoint = undefined;

@@ -904,2 +921,4 @@ let command = item.command;

}
} else {
prevQControlPoint = undefined;
}

@@ -1122,3 +1141,3 @@ prev = item;

if (Math.abs(rx - ry) > error) return undefined;
const chord = Math.sqrt(data[5] ** 2 + data[6] ** 2);
const chord = Math.hypot(data[5], data[6]);
if (chord > rx * 2) return undefined;

@@ -1155,3 +1174,3 @@ return rx - Math.sqrt(rx ** 2 - 0.25 * chord ** 2);

function getDistance(point1, point2) {
return Math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2);
return Math.hypot(point1[0] - point2[0], point1[1] - point2[1]);
}

@@ -1158,0 +1177,0 @@

@@ -1,13 +0,11 @@

'use strict';
import { stringifyPathData } from '../lib/path.js';
import { detachNodeFromParent } from '../lib/xast.js';
/**
* @typedef {import('../lib/types').PathDataItem} PathDataItem
* @typedef {import('../lib/types.js').PathDataItem} PathDataItem
*/
const { stringifyPathData } = require('../lib/path.js');
const { detachNodeFromParent } = require('../lib/xast.js');
export const name = 'convertShapeToPath';
export const description = 'converts basic shapes to more compact path form';
exports.name = 'convertShapeToPath';
exports.description = 'converts basic shapes to more compact path form';
const regNumber = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g;

@@ -24,5 +22,5 @@

*
* @type {import('./plugins-types').Plugin<'convertShapeToPath'>}
* @type {import('./plugins-types.js').Plugin<'convertShapeToPath'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const { convertArcs = false, floatPrecision: precision } = params;

@@ -29,0 +27,0 @@

@@ -1,8 +0,6 @@

'use strict';
import { attrsGroups } from './_collections.js';
const { attrsGroups } = require('./_collections');
export const name = 'convertStyleToAttrs';
export const description = 'converts style to attributes';
exports.name = 'convertStyleToAttrs';
exports.description = 'converts style to attributes';
/**

@@ -68,5 +66,5 @@ * @type {(...args: string[]) => string}

*
* @type {import('./plugins-types').Plugin<'convertStyleToAttrs'>}
* @type {import('./plugins-types.js').Plugin<'convertStyleToAttrs'>}
*/
exports.fn = (_root, params) => {
export const fn = (_root, params) => {
const { keepImportant = false } = params;

@@ -73,0 +71,0 @@ return {

@@ -1,19 +0,19 @@

'use strict';
import {
js2transform,
matrixToTransform,
roundTransform,
transform2js,
transformsMultiply,
} from './_transforms.js';
/**
* @typedef {import('../lib/types').XastChild} XastChild
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types').XastParent} XastParent
* @typedef {import('../lib/types.js').XastChild} XastChild
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
*/
const { cleanupOutData, toFixed } = require('../lib/svgo/tools.js');
const {
transform2js,
transformsMultiply,
matrixToTransform,
} = require('./_transforms.js');
export const name = 'convertTransform';
export const description =
'collapses multiple transformations and optimizes it';
exports.name = 'convertTransform';
exports.description = 'collapses multiple transformations and optimizes it';
/**

@@ -29,5 +29,5 @@ * Convert matrices to the short aliases,

*
* @type {import('./plugins-types').Plugin<'convertTransform'>}
* @type {import('./plugins-types.js').Plugin<'convertTransform'>}
*/
exports.fn = (_root, params) => {
export const fn = (_root, params) => {
const {

@@ -176,38 +176,2 @@ convertToShorts = true,

/**
* @type {(data: number[], params: TransformParams) => number[]}
*/
const degRound = (data, params) => {
if (
params.degPrecision != null &&
params.degPrecision >= 1 &&
params.floatPrecision < 20
) {
return smartRound(params.degPrecision, data);
} else {
return round(data);
}
};
/**
* @type {(data: number[], params: TransformParams) => number[]}
*/
const floatRound = (data, params) => {
if (params.floatPrecision >= 1 && params.floatPrecision < 20) {
return smartRound(params.floatPrecision, data);
} else {
return round(data);
}
};
/**
* @type {(data: number[], params: TransformParams) => number[]}
*/
const transformRound = (data, params) => {
if (params.transformPrecision >= 1 && params.floatPrecision < 20) {
return smartRound(params.transformPrecision, data);
} else {
return round(data);
}
};
/**
* Returns number of digits after the point. 0.125 → 3

@@ -335,87 +299,1 @@ *

};
/**
* Convert transforms JS representation to string.
*
* @param {TransformItem[]} transformJS
* @param {TransformParams} params
* @returns {string}
*/
const js2transform = (transformJS, params) => {
const transformString = transformJS
.map((transform) => {
roundTransform(transform, params);
return `${transform.name}(${cleanupOutData(transform.data, params)})`;
})
.join('');
return transformString;
};
/**
* @type {(transform: TransformItem, params: TransformParams) => TransformItem}
*/
const roundTransform = (transform, params) => {
switch (transform.name) {
case 'translate':
transform.data = floatRound(transform.data, params);
break;
case 'rotate':
transform.data = [
...degRound(transform.data.slice(0, 1), params),
...floatRound(transform.data.slice(1), params),
];
break;
case 'skewX':
case 'skewY':
transform.data = degRound(transform.data, params);
break;
case 'scale':
transform.data = transformRound(transform.data, params);
break;
case 'matrix':
transform.data = [
...transformRound(transform.data.slice(0, 4), params),
...floatRound(transform.data.slice(4), params),
];
break;
}
return transform;
};
/**
* Rounds numbers in array.
*
* @type {(data: number[]) => number[]}
*/
const round = (data) => {
return data.map(Math.round);
};
/**
* Decrease accuracy of floating-point numbers
* in transforms keeping a specified number of decimals.
* Smart rounds values like 2.349 to 2.35.
*
* @param {number} precision
* @param {number[]} data
* @returns {number[]}
*/
const smartRound = (precision, data) => {
for (
var i = data.length,
tolerance = +Math.pow(0.1, precision).toFixed(precision);
i--;
) {
if (toFixed(data[i], precision) !== data[i]) {
var rounded = +data[i].toFixed(precision - 1);
data[i] =
+Math.abs(rounded - data[i]).toFixed(precision + 1) >= tolerance
? +data[i].toFixed(precision)
: rounded;
}
}
return data;
};

@@ -1,23 +0,19 @@

'use strict';
import * as csstree from 'css-tree';
import { syntax } from 'csso';
import { attrsGroups, pseudoClasses } from './_collections.js';
import {
visitSkip,
querySelectorAll,
detachNodeFromParent,
} from '../lib/xast.js';
import { compareSpecificity, includesAttrSelector } from '../lib/style.js';
/**
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types').XastParent} XastParent
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
*/
const csstree = require('css-tree');
const {
syntax: { specificity },
} = require('csso');
const {
visitSkip,
querySelectorAll,
detachNodeFromParent,
} = require('../lib/xast.js');
const { compareSpecificity, includesAttrSelector } = require('../lib/style');
const { attrsGroups, pseudoClasses } = require('./_collections');
export const name = 'inlineStyles';
export const description = 'inline styles (additional options)';
exports.name = 'inlineStyles';
exports.description = 'inline styles (additional options)';
/**

@@ -28,3 +24,3 @@ * Some pseudo-classes can only be calculated by clients, like :visited,

*
* The list of pseudo-classes that we can evaluate during optimization, and so
* The list of pseudo-classes that we can evaluate during optimization, and
* shouldn't be toggled conditionally through the `usePseudos` parameter.

@@ -42,6 +38,6 @@ *

*
* @type {import('./plugins-types').Plugin<'inlineStyles'>}
* @type {import('./plugins-types.js').Plugin<'inlineStyles'>}
* @author strarsis <strarsis@gmail.com>
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const {

@@ -182,4 +178,4 @@ onlyMatchedOnce = true,

.sort((a, b) => {
const aSpecificity = specificity(a.item.data);
const bSpecificity = specificity(b.item.data);
const aSpecificity = syntax.specificity(a.item.data);
const bSpecificity = syntax.specificity(b.item.data);
return compareSpecificity(aSpecificity, bSpecificity);

@@ -200,3 +196,3 @@ })

}
} catch (selectError) {
} catch {
continue;

@@ -203,0 +199,0 @@ }

@@ -1,14 +0,31 @@

'use strict';
/**
* @typedef {import('../lib/types.js').ComputedStyles} ComputedStyles
* @typedef {import('../lib/types.js').StaticStyle} StaticStyle
* @typedef {import('../lib/types.js').DynamicStyle} DynamicStyle
* @typedef {import("../lib/types.js").PathDataItem} PathDataItem
* @typedef {import('../lib/types.js').XastChild} XastChild
* @typedef {import('../lib/types.js').XastElement} XastElement
*/
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';
/**
* @typedef {import("../lib/types").PathDataItem} PathDataItem
* @typedef {import('../lib/types').XastChild} XastChild
* @typedef {import('../lib/types').XastElement} XastElement
* @param {ComputedStyles} computedStyle
* @param {string} attName
* @returns {boolean}
*/
function elementHasUrl(computedStyle, attName) {
const style = computedStyle[attName];
const { collectStylesheet, computeStyle } = require('../lib/style.js');
const { path2js, js2path, intersects } = require('./_path.js');
if (style?.type === 'static') {
return includesUrlReference(style.value);
}
exports.name = 'mergePaths';
exports.description = 'merges multiple paths in one if possible';
return false;
}

@@ -20,8 +37,8 @@ /**

*
* @type {import('./plugins-types').Plugin<'mergePaths'>}
* @type {import('./plugins-types.js').Plugin<'mergePaths'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const {
force = false,
floatPrecision,
floatPrecision = 3,
noSpaceAfterFlags = false, // a20 60 45 0 1 30 20 → a20 60 45 0130 20

@@ -88,3 +105,9 @@ } = params;

computedStyle['marker-mid'] ||
computedStyle['marker-end']
computedStyle['marker-end'] ||
computedStyle['clip-path'] ||
computedStyle['mask'] ||
computedStyle['mask-image'] ||
['fill', 'filter', 'stroke'].some((attName) =>
elementHasUrl(computedStyle, attName),
)
) {

@@ -91,0 +114,0 @@ if (prevPathData) {

@@ -1,13 +0,11 @@

'use strict';
import { visitSkip, detachNodeFromParent } from '../lib/xast.js';
/**
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types').XastChild} XastChild
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastChild} XastChild
*/
const { visitSkip, detachNodeFromParent } = require('../lib/xast.js');
export const name = 'mergeStyles';
export const description = 'merge multiple style elements into one';
exports.name = 'mergeStyles';
exports.description = 'merge multiple style elements into one';
/**

@@ -18,5 +16,5 @@ * Merge multiple style elements into one.

*
* @type {import('./plugins-types').Plugin<'mergeStyles'>}
* @type {import('./plugins-types.js').Plugin<'mergeStyles'>}
*/
exports.fn = () => {
export const fn = () => {
/**

@@ -23,0 +21,0 @@ * @type {?XastElement}

@@ -1,14 +0,12 @@

'use strict';
/**
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types').XastParent} XastParent
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
*/
const csso = require('csso');
const { detachNodeFromParent } = require('../lib/xast');
const { hasScripts } = require('../lib/svgo/tools');
import * as csso from 'csso';
import { detachNodeFromParent } from '../lib/xast.js';
import { hasScripts } from '../lib/svgo/tools.js';
exports.name = 'minifyStyles';
exports.description = 'minifies styles and removes unused styles';
export const name = 'minifyStyles';
export const description = 'minifies styles and removes unused styles';

@@ -19,5 +17,5 @@ /**

* @author strarsis <strarsis@gmail.com>
* @type {import('./plugins-types').Plugin<'minifyStyles'>}
* @type {import('./plugins-types.js').Plugin<'minifyStyles'>}
*/
exports.fn = (_root, { usage, ...params }) => {
export const fn = (_root, { usage, ...params }) => {
/** @type {Map<XastElement, XastParent>} */

@@ -24,0 +22,0 @@ const styleElements = new Map();

@@ -1,9 +0,8 @@

'use strict';
import { visit } from '../lib/xast.js';
import { inheritableAttrs, pathElems } from './_collections.js';
const { visit } = require('../lib/xast.js');
const { inheritableAttrs, pathElems } = require('./_collections.js');
export const name = 'moveElemsAttrsToGroup';
export const description =
'Move common attributes of group children to the group';
exports.name = 'moveElemsAttrsToGroup';
exports.description = 'Move common attributes of group children to the group';
/**

@@ -29,5 +28,5 @@ * Move common attributes of group children to the group

*
* @type {import('./plugins-types').Plugin<'moveElemsAttrsToGroup'>}
* @type {import('./plugins-types.js').Plugin<'moveElemsAttrsToGroup'>}
*/
exports.fn = (root) => {
export const fn = (root) => {
// find if any style element is present

@@ -91,4 +90,5 @@ let deoptimizedWithStyles = false;

// preserve transform on children when group has clip-path or mask
// preserve transform on children when group has filter or clip-path or mask
if (
node.attributes['filter'] != null ||
node.attributes['clip-path'] != null ||

@@ -95,0 +95,0 @@ node.attributes.mask != null

@@ -1,9 +0,8 @@

'use strict';
import { pathElems, referencesProps } from './_collections.js';
import { includesUrlReference } from '../lib/svgo/tools.js';
const { pathElems, referencesProps } = require('./_collections.js');
const { includesUrlReference } = require('../lib/svgo/tools.js');
export const name = 'moveGroupAttrsToElems';
export const description =
'moves some group attributes to the content elements';
exports.name = 'moveGroupAttrsToElems';
exports.description = 'moves some group attributes to the content elements';
const pathElemsWithGroupsAndText = [...pathElems, 'g', 'text'];

@@ -27,5 +26,5 @@

*
* @type {import('./plugins-types').Plugin<'moveGroupAttrsToElems'>}
* @type {import('./plugins-types.js').Plugin<'moveGroupAttrsToElems'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -32,0 +31,0 @@ element: {

@@ -5,3 +5,3 @@ import type {

XastElement,
} from '../lib/types';
} from '../lib/types.js';

@@ -33,2 +33,3 @@ type DefaultPlugins = {

rgb2hex?: boolean;
convertCase?: false | 'lower' | 'upper';
shorthex?: boolean;

@@ -148,2 +149,5 @@ shortname?: boolean;

};
removeDeprecatedAttrs: {
removeUnsafe?: boolean;
};
removeDesc: {

@@ -182,3 +186,2 @@ removeAny?: boolean;

removeNonInheritableGroupAttrs: void;
removeTitle: void;
removeUnknownsAndDefaults: {

@@ -206,3 +209,2 @@ unknownContent?: boolean;

};
removeViewBox: void;
removeXMLProcInst: void;

@@ -255,4 +257,6 @@ sortAttrs: {

removeRasterImages: void;
removeScriptElement: void;
removeScripts: void;
removeStyleElement: void;
removeTitle: void;
removeViewBox: void;
removeXlink: {

@@ -278,4 +282,6 @@ /**

addClassesToSVGElement: {
className?: string;
classNames?: string[];
className?: string | ((node: XastElement, info: PluginInfo) => string);
classNames?: Array<
string | ((node: XastElement, info: PluginInfo) => string)
>;
};

@@ -294,3 +300,4 @@ removeAttributesBySelector: any;

type PluginsParams = BuiltinsWithOptionalParams & BuiltinsWithRequiredParams;
export type PluginsParams = BuiltinsWithOptionalParams &
BuiltinsWithRequiredParams;

@@ -297,0 +304,0 @@ export type Plugin<Name extends keyof PluginsParams> = PluginDef<

@@ -1,14 +0,12 @@

'use strict';
import * as csstree from 'css-tree';
import { referencesProps } from './_collections.js';
/**
* @typedef {import('../lib/types.js').PluginInfo} PluginInfo
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types.js').XastElement} XastElement
*/
const csstree = require('css-tree');
const { referencesProps } = require('./_collections.js');
export const name = 'prefixIds';
export const description = 'prefix IDs';
exports.name = 'prefixIds';
exports.description = 'prefix IDs';
/**

@@ -121,5 +119,5 @@ * extract basename from path

* @author strarsis <strarsis@gmail.com>
* @type {import('./plugins-types').Plugin<'prefixIds'>}
* @type {import('./plugins-types.js').Plugin<'prefixIds'>}
*/
exports.fn = (_root, params, info) => {
export const fn = (_root, params, info) => {
const {

@@ -189,3 +187,2 @@ delim = '__',

child.value = csstree.generate(cssAst);
return;
}

@@ -192,0 +189,0 @@ }

@@ -1,41 +0,37 @@

'use strict';
import { createPreset } from '../lib/svgo/plugins.js';
import * as removeDoctype from './removeDoctype.js';
import * as removeXMLProcInst from './removeXMLProcInst.js';
import * as removeComments from './removeComments.js';
import * as removeDeprecatedAttrs from './removeDeprecatedAttrs.js';
import * as removeMetadata from './removeMetadata.js';
import * as removeEditorsNSData from './removeEditorsNSData.js';
import * as cleanupAttrs from './cleanupAttrs.js';
import * as mergeStyles from './mergeStyles.js';
import * as inlineStyles from './inlineStyles.js';
import * as minifyStyles from './minifyStyles.js';
import * as cleanupIds from './cleanupIds.js';
import * as removeUselessDefs from './removeUselessDefs.js';
import * as cleanupNumericValues from './cleanupNumericValues.js';
import * as convertColors from './convertColors.js';
import * as removeUnknownsAndDefaults from './removeUnknownsAndDefaults.js';
import * as removeNonInheritableGroupAttrs from './removeNonInheritableGroupAttrs.js';
import * as removeUselessStrokeAndFill from './removeUselessStrokeAndFill.js';
import * as cleanupEnableBackground from './cleanupEnableBackground.js';
import * as removeHiddenElems from './removeHiddenElems.js';
import * as removeEmptyText from './removeEmptyText.js';
import * as convertShapeToPath from './convertShapeToPath.js';
import * as convertEllipseToCircle from './convertEllipseToCircle.js';
import * as moveElemsAttrsToGroup from './moveElemsAttrsToGroup.js';
import * as moveGroupAttrsToElems from './moveGroupAttrsToElems.js';
import * as collapseGroups from './collapseGroups.js';
import * as convertPathData from './convertPathData.js';
import * as convertTransform from './convertTransform.js';
import * as removeEmptyAttrs from './removeEmptyAttrs.js';
import * as removeEmptyContainers from './removeEmptyContainers.js';
import * as mergePaths from './mergePaths.js';
import * as removeUnusedNS from './removeUnusedNS.js';
import * as sortAttrs from './sortAttrs.js';
import * as sortDefsChildren from './sortDefsChildren.js';
import * as removeDesc from './removeDesc.js';
const { createPreset } = require('../lib/svgo/plugins.js');
const removeDoctype = require('./removeDoctype.js');
const removeXMLProcInst = require('./removeXMLProcInst.js');
const removeComments = require('./removeComments.js');
const removeMetadata = require('./removeMetadata.js');
const removeEditorsNSData = require('./removeEditorsNSData.js');
const cleanupAttrs = require('./cleanupAttrs.js');
const mergeStyles = require('./mergeStyles.js');
const inlineStyles = require('./inlineStyles.js');
const minifyStyles = require('./minifyStyles.js');
const cleanupIds = require('./cleanupIds.js');
const removeUselessDefs = require('./removeUselessDefs.js');
const cleanupNumericValues = require('./cleanupNumericValues.js');
const convertColors = require('./convertColors.js');
const removeUnknownsAndDefaults = require('./removeUnknownsAndDefaults.js');
const removeNonInheritableGroupAttrs = require('./removeNonInheritableGroupAttrs.js');
const removeUselessStrokeAndFill = require('./removeUselessStrokeAndFill.js');
const removeViewBox = require('./removeViewBox.js');
const cleanupEnableBackground = require('./cleanupEnableBackground.js');
const removeHiddenElems = require('./removeHiddenElems.js');
const removeEmptyText = require('./removeEmptyText.js');
const convertShapeToPath = require('./convertShapeToPath.js');
const convertEllipseToCircle = require('./convertEllipseToCircle.js');
const moveElemsAttrsToGroup = require('./moveElemsAttrsToGroup.js');
const moveGroupAttrsToElems = require('./moveGroupAttrsToElems.js');
const collapseGroups = require('./collapseGroups.js');
const convertPathData = require('./convertPathData.js');
const convertTransform = require('./convertTransform.js');
const removeEmptyAttrs = require('./removeEmptyAttrs.js');
const removeEmptyContainers = require('./removeEmptyContainers.js');
const mergePaths = require('./mergePaths.js');
const removeUnusedNS = require('./removeUnusedNS.js');
const sortAttrs = require('./sortAttrs.js');
const sortDefsChildren = require('./sortDefsChildren.js');
const removeTitle = require('./removeTitle.js');
const removeDesc = require('./removeDesc.js');
const presetDefault = createPreset({

@@ -47,2 +43,3 @@ name: 'preset-default',

removeComments,
removeDeprecatedAttrs,
removeMetadata,

@@ -61,3 +58,2 @@ removeEditorsNSData,

removeUselessStrokeAndFill,
removeViewBox,
cleanupEnableBackground,

@@ -79,3 +75,2 @@ removeHiddenElems,

sortDefsChildren,
removeTitle,
removeDesc,

@@ -85,2 +80,2 @@ ],

module.exports = presetDefault;
export default presetDefault;

@@ -1,7 +0,5 @@

'use strict';
import { querySelectorAll } from '../lib/xast.js';
const { querySelectorAll } = require('../lib/xast.js');
exports.name = 'removeAttributesBySelector';
exports.description =
export const name = 'removeAttributesBySelector';
export const description =
'removes attributes of elements that match a css selector';

@@ -76,5 +74,5 @@

*
* @type {import('./plugins-types').Plugin<'removeAttributesBySelector'>}
* @type {import('./plugins-types.js').Plugin<'removeAttributesBySelector'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const selectors = Array.isArray(params.selectors)

@@ -81,0 +79,0 @@ ? params.selectors

@@ -1,6 +0,4 @@

'use strict';
export const name = 'removeAttrs';
export const description = 'removes specified attributes';
exports.name = 'removeAttrs';
exports.description = 'removes specified attributes';
const DEFAULT_SEPARATOR = ':';

@@ -84,5 +82,5 @@ const ENOATTRS = `Warning: The plugin "removeAttrs" requires the "attrs" parameter.

*
* @type {import('./plugins-types').Plugin<'removeAttrs'>}
* @type {import('./plugins-types.js').Plugin<'removeAttrs'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
if (typeof params.attrs == 'undefined') {

@@ -128,10 +126,7 @@ console.warn(ENOATTRS);

for (const [name, value] of Object.entries(node.attributes)) {
const isCurrentColor = value.toLowerCase() === 'currentcolor';
const isFillCurrentColor =
preserveCurrentColor &&
name == 'fill' &&
value == 'currentColor';
preserveCurrentColor && name == 'fill' && isCurrentColor;
const isStrokeCurrentColor =
preserveCurrentColor &&
name == 'stroke' &&
value == 'currentColor';
preserveCurrentColor && name == 'stroke' && isCurrentColor;
if (

@@ -138,0 +133,0 @@ !isFillCurrentColor &&

@@ -1,8 +0,6 @@

'use strict';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
export const name = 'removeComments';
export const description = 'removes comments';
exports.name = 'removeComments';
exports.description = 'removes comments';
/**

@@ -23,5 +21,5 @@ * If a comment matches one of the following patterns, it will be

*
* @type {import('./plugins-types').Plugin<'removeComments'>}
* @type {import('./plugins-types.js').Plugin<'removeComments'>}
*/
exports.fn = (_root, params) => {
export const fn = (_root, params) => {
const { preservePatterns = DEFAULT_PRESERVE_PATTERNS } = params;

@@ -28,0 +26,0 @@

@@ -1,8 +0,6 @@

'use strict';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
export const name = 'removeDesc';
export const description = 'removes <desc>';
exports.name = 'removeDesc';
exports.description = 'removes <desc>';
const standardDescs = /^(Created with|Created using)/;

@@ -12,12 +10,12 @@

* Removes <desc>.
* Removes only standard editors content or empty elements 'cause it can be used for accessibility.
* Enable parameter 'removeAny' to remove any description.
* Removes only standard editors content or empty elements because it can be
* used for accessibility. Enable parameter 'removeAny' to remove any
* description.
*
* https://developer.mozilla.org/docs/Web/SVG/Element/desc
*
* @author Daniel Wabyick
* @see https://developer.mozilla.org/docs/Web/SVG/Element/desc
*
* @type {import('./plugins-types').Plugin<'removeDesc'>}
* @type {import('./plugins-types.js').Plugin<'removeDesc'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const { removeAny = false } = params;

@@ -24,0 +22,0 @@ return {

@@ -1,7 +0,5 @@

'use strict';
export const name = 'removeDimensions';
export const description =
'removes width and height in presence of viewBox (opposite to removeViewBox)';
exports.name = 'removeDimensions';
exports.description =
'removes width and height in presence of viewBox (opposite to removeViewBox, disable it first)';
/**

@@ -17,5 +15,5 @@ * Remove width/height attributes and add the viewBox attribute if it's missing

*
* @type {import('./plugins-types').Plugin<'removeDimensions'>}
* @type {import('./plugins-types.js').Plugin<'removeDimensions'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -22,0 +20,0 @@ element: {

@@ -1,8 +0,6 @@

'use strict';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
export const name = 'removeDoctype';
export const description = 'removes doctype declaration';
exports.name = 'removeDoctype';
exports.description = 'removes doctype declaration';
/**

@@ -30,5 +28,5 @@ * Remove DOCTYPE declaration.

*
* @type {import('./plugins-types').Plugin<'removeDoctype'>}
* @type {import('./plugins-types.js').Plugin<'removeDoctype'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -35,0 +33,0 @@ doctype: {

@@ -1,9 +0,8 @@

'use strict';
import { editorNamespaces } from './_collections.js';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
const { editorNamespaces } = require('./_collections.js');
export const name = 'removeEditorsNSData';
export const description =
'removes editors namespaces, elements and attributes';
exports.name = 'removeEditorsNSData';
exports.description = 'removes editors namespaces, elements and attributes';
/**

@@ -19,5 +18,5 @@ * Remove editors namespaces, elements and attributes.

*
* @type {import('./plugins-types').Plugin<'removeEditorsNSData'>}
* @type {import('./plugins-types.js').Plugin<'removeEditorsNSData'>}
*/
exports.fn = (_root, params) => {
export const fn = (_root, params) => {
let namespaces = [...editorNamespaces];

@@ -24,0 +23,0 @@ if (Array.isArray(params.additionalNamespaces)) {

@@ -1,7 +0,5 @@

'use strict';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
exports.name = 'removeElementsByAttr';
exports.description =
export const name = 'removeElementsByAttr';
export const description =
'removes arbitrary elements by ID or className (disabled by default)';

@@ -40,5 +38,5 @@

*
* @type {import('./plugins-types').Plugin<'removeElementsByAttr'>}
* @type {import('./plugins-types.js').Plugin<'removeElementsByAttr'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const ids =

@@ -45,0 +43,0 @@ params.id == null ? [] : Array.isArray(params.id) ? params.id : [params.id];

@@ -1,8 +0,6 @@

'use strict';
import { attrsGroups } from './_collections.js';
const { attrsGroups } = require('./_collections.js');
export const name = 'removeEmptyAttrs';
export const description = 'removes empty attributes';
exports.name = 'removeEmptyAttrs';
exports.description = 'removes empty attributes';
/**

@@ -13,5 +11,5 @@ * Remove attributes with empty values.

*
* @type {import('./plugins-types').Plugin<'removeEmptyAttrs'>}
* @type {import('./plugins-types.js').Plugin<'removeEmptyAttrs'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -18,0 +16,0 @@ element: {

@@ -1,9 +0,7 @@

'use strict';
import { elemsGroups } from './_collections.js';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
const { elemsGroups } = require('./_collections.js');
export const name = 'removeEmptyContainers';
export const description = 'removes empty container elements';
exports.name = 'removeEmptyContainers';
exports.description = 'removes empty container elements';
/**

@@ -22,5 +20,5 @@ * Remove empty containers.

*
* @type {import('./plugins-types').Plugin<'removeEmptyContainers'>}
* @type {import('./plugins-types.js').Plugin<'removeEmptyContainers'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -27,0 +25,0 @@ element: {

@@ -1,8 +0,6 @@

'use strict';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
export const name = 'removeEmptyText';
export const description = 'removes empty <text> elements';
exports.name = 'removeEmptyText';
exports.description = 'removes empty <text> elements';
/**

@@ -25,5 +23,5 @@ * Remove empty Text elements.

*
* @type {import('./plugins-types').Plugin<'removeEmptyText'>}
* @type {import('./plugins-types.js').Plugin<'removeEmptyText'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const { text = true, tspan = true, tref = true } = params;

@@ -30,0 +28,0 @@ return {

@@ -1,11 +0,9 @@

'use strict';
/**
* @typedef {import('../lib/types').XastChild} XastChild
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types').XastParent} XastParent
* @typedef {import('../lib/types.js').XastChild} XastChild
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
*/
const { elemsGroups } = require('./_collections.js');
const {
import { elemsGroups } from './_collections.js';
import {
visit,

@@ -15,11 +13,11 @@ visitSkip,

detachNodeFromParent,
} = require('../lib/xast.js');
const { collectStylesheet, computeStyle } = require('../lib/style.js');
const { parsePathData } = require('../lib/path.js');
const { hasScripts, findReferences } = require('../lib/svgo/tools.js');
} from '../lib/xast.js';
import { collectStylesheet, computeStyle } from '../lib/style.js';
import { parsePathData } from '../lib/path.js';
import { hasScripts, findReferences } from '../lib/svgo/tools.js';
const nonRendering = elemsGroups.nonRendering;
exports.name = 'removeHiddenElems';
exports.description =
export const name = 'removeHiddenElems';
export const description =
'removes hidden elements (zero sized, with absent attributes)';

@@ -42,5 +40,5 @@

*
* @type {import('./plugins-types').Plugin<'removeHiddenElems'>}
* @type {import('./plugins-types.js').Plugin<'removeHiddenElems'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const {

@@ -99,2 +97,19 @@ isHidden = true,

/**
* Nodes can't be removed if they or any of their children have an id attribute that is referenced.
* @param {XastElement} node
* @returns boolean
*/
function canRemoveNonRenderingNode(node) {
if (allReferences.has(node.attributes.id)) {
return false;
}
for (const child of node.children) {
if (child.type === 'element' && !canRemoveNonRenderingNode(child)) {
return false;
}
}
return true;
}
/**
* @param {XastChild} node

@@ -121,7 +136,2 @@ * @param {XastParent} parentNode

if (nonRendering.has(node.name)) {
if (node.attributes.id == null) {
detachNodeFromParent(node, parentNode);
return visitSkip;
}
nonRenderedNodes.set(node, parentNode);

@@ -140,2 +150,6 @@ return visitSkip;

) {
if (node.name === 'path') {
nonRenderedNodes.set(node, parentNode);
return visitSkip;
}
removeElement(node, parentNode);

@@ -429,5 +443,3 @@ }

] of nonRenderedNodes.entries()) {
const id = nonRenderedNode.attributes.id;
if (!allReferences.has(id)) {
if (canRemoveNonRenderingNode(nonRenderedNode)) {
detachNodeFromParent(nonRenderedNode, nonRenderedParent);

@@ -434,0 +446,0 @@ }

@@ -1,8 +0,6 @@

'use strict';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
export const name = 'removeMetadata';
export const description = 'removes <metadata>';
exports.name = 'removeMetadata';
exports.description = 'removes <metadata>';
/**

@@ -15,5 +13,5 @@ * Remove <metadata>.

*
* @type {import('./plugins-types').Plugin<'removeMetadata'>}
* @type {import('./plugins-types.js').Plugin<'removeMetadata'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -20,0 +18,0 @@ element: {

@@ -1,11 +0,9 @@

'use strict';
const {
import {
inheritableAttrs,
attrsGroups,
presentationNonInheritableGroupAttrs,
} = require('./_collections');
} from './_collections.js';
exports.name = 'removeNonInheritableGroupAttrs';
exports.description =
export const name = 'removeNonInheritableGroupAttrs';
export const description =
'removes non-inheritable group’s presentational attributes';

@@ -18,5 +16,5 @@

*
* @type {import('./plugins-types').Plugin<'removeNonInheritableGroupAttrs'>}
* @type {import('./plugins-types.js').Plugin<'removeNonInheritableGroupAttrs'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -23,0 +21,0 @@ element: {

@@ -1,13 +0,11 @@

'use strict';
/**
* @typedef {import('../lib/types').PathDataItem} PathDataItem
* @typedef {import('../lib/types.js').PathDataItem} PathDataItem
*/
const { visitSkip, detachNodeFromParent } = require('../lib/xast.js');
const { parsePathData } = require('../lib/path.js');
const { intersects } = require('./_path.js');
import { visitSkip, detachNodeFromParent } from '../lib/xast.js';
import { parsePathData } from '../lib/path.js';
import { intersects } from './_path.js';
exports.name = 'removeOffCanvasPaths';
exports.description =
export const name = 'removeOffCanvasPaths';
export const description =
'removes elements that are drawn outside of the viewbox (disabled by default)';

@@ -20,5 +18,5 @@

*
* @type {import('./plugins-types').Plugin<'removeOffCanvasPaths'>}
* @type {import('./plugins-types.js').Plugin<'removeOffCanvasPaths'>}
*/
exports.fn = () => {
export const fn = () => {
/**

@@ -25,0 +23,0 @@ * @type {?{

@@ -1,8 +0,6 @@

'use strict';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
export const name = 'removeRasterImages';
export const description = 'removes raster images (disabled by default)';
exports.name = 'removeRasterImages';
exports.description = 'removes raster images (disabled by default)';
/**

@@ -15,5 +13,5 @@ * Remove raster images references in <image>.

*
* @type {import('./plugins-types').Plugin<'removeRasterImages'>}
* @type {import('./plugins-types.js').Plugin<'removeRasterImages'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -20,0 +18,0 @@ element: {

@@ -1,8 +0,6 @@

'use strict';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
export const name = 'removeStyleElement';
export const description = 'removes <style> element (disabled by default)';
exports.name = 'removeStyleElement';
exports.description = 'removes <style> element (disabled by default)';
/**

@@ -15,5 +13,5 @@ * Remove <style>.

*
* @type {import('./plugins-types').Plugin<'removeStyleElement'>}
* @type {import('./plugins-types.js').Plugin<'removeStyleElement'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -20,0 +18,0 @@ element: {

@@ -1,8 +0,6 @@

'use strict';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
export const name = 'removeTitle';
export const description = 'removes <title>';
exports.name = 'removeTitle';
exports.description = 'removes <title>';
/**

@@ -15,5 +13,5 @@ * Remove <title>.

*
* @type {import('./plugins-types').Plugin<'removeTitle'>}
* @type {import('./plugins-types.js').Plugin<'removeTitle'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -20,0 +18,0 @@ element: {

@@ -1,6 +0,2 @@

'use strict';
const { visitSkip, detachNodeFromParent } = require('../lib/xast.js');
const { collectStylesheet, computeStyle } = require('../lib/style.js');
const {
import {
elems,

@@ -11,6 +7,8 @@ attrsGroups,

presentationNonInheritableGroupAttrs,
} = require('./_collections');
} from './_collections.js';
import { visitSkip, detachNodeFromParent } from '../lib/xast.js';
import { collectStylesheet, computeStyle } from '../lib/style.js';
exports.name = 'removeUnknownsAndDefaults';
exports.description =
export const name = 'removeUnknownsAndDefaults';
export const description =
'removes unknown elements content and attributes, removes attrs with default values';

@@ -96,5 +94,5 @@

*
* @type {import('./plugins-types').Plugin<'removeUnknownsAndDefaults'>}
* @type {import('./plugins-types.js').Plugin<'removeUnknownsAndDefaults'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const {

@@ -101,0 +99,0 @@ unknownContent = true,

@@ -1,6 +0,4 @@

'use strict';
export const name = 'removeUnusedNS';
export const description = 'removes unused namespaces declaration';
exports.name = 'removeUnusedNS';
exports.description = 'removes unused namespaces declaration';
/**

@@ -12,5 +10,5 @@ * Remove unused namespaces declaration from svg element

*
* @type {import('./plugins-types').Plugin<'removeUnusedNS'>}
* @type {import('./plugins-types.js').Plugin<'removeUnusedNS'>}
*/
exports.fn = () => {
export const fn = () => {
/**

@@ -17,0 +15,0 @@ * @type {Set<string>}

@@ -1,13 +0,11 @@

'use strict';
import { detachNodeFromParent } from '../lib/xast.js';
import { elemsGroups } from './_collections.js';
/**
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types.js').XastElement} XastElement
*/
const { detachNodeFromParent } = require('../lib/xast.js');
const { elemsGroups } = require('./_collections.js');
export const name = 'removeUselessDefs';
export const description = 'removes elements in <defs> without id';
exports.name = 'removeUselessDefs';
exports.description = 'removes elements in <defs> without id';
/**

@@ -18,9 +16,13 @@ * Removes content of defs and properties that aren't rendered directly without ids.

*
* @type {import('./plugins-types').Plugin<'removeUselessDefs'>}
* @type {import('./plugins-types.js').Plugin<'removeUselessDefs'>}
*/
exports.fn = () => {
export const fn = () => {
return {
element: {
enter: (node, parentNode) => {
if (node.name === 'defs') {
if (
node.name === 'defs' ||
(elemsGroups.nonRendering.has(node.name) &&
node.attributes.id == null)
) {
/**

@@ -42,7 +44,2 @@ * @type {XastElement[]}

node.children = usefulNodes;
} else if (
elemsGroups.nonRendering.has(node.name) &&
node.attributes.id == null
) {
detachNodeFromParent(node, parentNode);
}

@@ -49,0 +46,0 @@ },

@@ -1,11 +0,9 @@

'use strict';
import { visit, visitSkip, detachNodeFromParent } from '../lib/xast.js';
import { collectStylesheet, computeStyle } from '../lib/style.js';
import { hasScripts } from '../lib/svgo/tools.js';
import { elemsGroups } from './_collections.js';
const { visit, visitSkip, detachNodeFromParent } = require('../lib/xast.js');
const { collectStylesheet, computeStyle } = require('../lib/style.js');
const { hasScripts } = require('../lib/svgo/tools.js');
const { elemsGroups } = require('./_collections.js');
export const name = 'removeUselessStrokeAndFill';
export const description = 'removes useless stroke and fill attributes';
exports.name = 'removeUselessStrokeAndFill';
exports.description = 'removes useless stroke and fill attributes';
/**

@@ -16,5 +14,5 @@ * Remove useless stroke and fill attrs.

*
* @type {import('./plugins-types').Plugin<'removeUselessStrokeAndFill'>}
* @type {import('./plugins-types.js').Plugin<'removeUselessStrokeAndFill'>}
*/
exports.fn = (root, params) => {
export const fn = (root, params) => {
const {

@@ -21,0 +19,0 @@ stroke: removeStroke = true,

@@ -1,6 +0,4 @@

'use strict';
export const name = 'removeViewBox';
export const description = 'removes viewBox attribute when possible';
exports.name = 'removeViewBox';
exports.description = 'removes viewBox attribute when possible';
const viewBoxElems = new Set(['pattern', 'svg', 'symbol']);

@@ -20,5 +18,5 @@

*
* @type {import('./plugins-types').Plugin<'removeViewBox'>}
* @type {import('./plugins-types.js').Plugin<'removeViewBox'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -25,0 +23,0 @@ element: {

@@ -1,11 +0,9 @@

'use strict';
import { elems } from './_collections.js';
const { elems } = require('./_collections');
/**
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types.js').XastElement} XastElement
*/
exports.name = 'removeXlink';
exports.description =
export const name = 'removeXlink';
export const description =
'remove xlink namespace and replaces attributes with the SVG 2 equivalent where applicable';

@@ -61,6 +59,6 @@

*
* @type {import('./plugins-types').Plugin<'removeXlink'>}
* @type {import('./plugins-types.js').Plugin<'removeXlink'>}
* @see https://developer.mozilla.org/docs/Web/SVG/Attribute/xlink:href
*/
exports.fn = (_, params) => {
export const fn = (_, params) => {
const { includeLegacy } = params;

@@ -77,4 +75,4 @@

* Namespace prefixes that exist in {@link xlinkPrefixes} but were overridden
* in a child element to point to another namespace, and so is not treated as
* an XLink attribute.
* in a child element to point to another namespace, and is not treated as an
* XLink attribute.
*

@@ -81,0 +79,0 @@ * @type {string[]}

@@ -1,5 +0,3 @@

'use strict';
exports.name = 'removeXMLNS';
exports.description =
export const name = 'removeXMLNS';
export const description =
'removes xmlns attribute (for inline svg, disabled by default)';

@@ -17,5 +15,5 @@

*
* @type {import('./plugins-types').Plugin<'removeXMLNS'>}
* @type {import('./plugins-types.js').Plugin<'removeXMLNS'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -22,0 +20,0 @@ element: {

@@ -1,8 +0,6 @@

'use strict';
import { detachNodeFromParent } from '../lib/xast.js';
const { detachNodeFromParent } = require('../lib/xast.js');
export const name = 'removeXMLProcInst';
export const description = 'removes XML processing instructions';
exports.name = 'removeXMLProcInst';
exports.description = 'removes XML processing instructions';
/**

@@ -16,5 +14,5 @@ * Remove XML Processing Instruction.

*
* @type {import('./plugins-types').Plugin<'removeXMLProcInst'>}
* @type {import('./plugins-types.js').Plugin<'removeXMLProcInst'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -21,0 +19,0 @@ instruction: {

@@ -1,14 +0,12 @@

'use strict';
import { collectStylesheet } from '../lib/style.js';
import { detachNodeFromParent, querySelectorAll } from '../lib/xast.js';
const { collectStylesheet } = require('../lib/style');
const { detachNodeFromParent, querySelectorAll } = require('../lib/xast');
/**
* @typedef {import('../lib/types').XastElement} XastElement
* @typedef {import('../lib/types').XastParent} XastParent
* @typedef {import('../lib/types').XastNode} XastNode
* @typedef {import('../lib/types.js').XastElement} XastElement
* @typedef {import('../lib/types.js').XastParent} XastParent
* @typedef {import('../lib/types.js').XastNode} XastNode
*/
exports.name = 'reusePaths';
exports.description =
export const name = 'reusePaths';
export const description =
'Finds <path> elements with the same d, fill, and ' +

@@ -24,5 +22,5 @@ 'stroke, and converts them to <use> elements ' +

*
* @type {import('./plugins-types').Plugin<'reusePaths'>}
* @type {import('./plugins-types.js').Plugin<'reusePaths'>}
*/
exports.fn = (root) => {
export const fn = (root) => {
const stylesheet = collectStylesheet(root);

@@ -29,0 +27,0 @@

@@ -1,6 +0,4 @@

'use strict';
export const name = 'sortAttrs';
export const description = 'Sort element attributes for better compression';
exports.name = 'sortAttrs';
exports.description = 'Sort element attributes for better compression';
/**

@@ -11,5 +9,5 @@ * Sort element attributes for better compression

*
* @type {import('./plugins-types').Plugin<'sortAttrs'>}
* @type {import('./plugins-types.js').Plugin<'sortAttrs'>}
*/
exports.fn = (_root, params) => {
export const fn = (_root, params) => {
const {

@@ -16,0 +14,0 @@ order = [

@@ -1,6 +0,4 @@

'use strict';
export const name = 'sortDefsChildren';
export const description = 'Sorts children of <defs> to improve compression';
exports.name = 'sortDefsChildren';
exports.description = 'Sorts children of <defs> to improve compression';
/**

@@ -12,5 +10,5 @@ * Sorts children of defs in order to improve compression.

*
* @type {import('./plugins-types').Plugin<'sortDefsChildren'>}
* @type {import('./plugins-types.js').Plugin<'sortDefsChildren'>}
*/
exports.fn = () => {
export const fn = () => {
return {

@@ -17,0 +15,0 @@ element: {

@@ -52,8 +52,8 @@ <div align="center">

SVGO reads the configuration from `svgo.config.js` or the `--config path/to/config.js` command-line option. Some other parameters can be configured though command-line options too.
SVGO reads the configuration from `svgo.config.mjs` or the `--config path/to/config.mjs` command-line option. Some other parameters can be configured though command-line options too.
**`svgo.config.js`**
**`svgo.config.mjs`**
```js
module.exports = {
export default {
multipass: false, // boolean

@@ -84,6 +84,6 @@ datauri: 'base64', // 'base64'|'enc'|'unenc'

**`svgo.config.js`**
**`svgo.config.mjs`**
```js
module.exports = {
export default {
plugins: [

@@ -95,3 +95,3 @@ {

// disable a default plugin
removeViewBox: false,
cleanupIds: false,

@@ -115,8 +115,8 @@ // customize the params of a default plugin

**`svgo.config.js`**
**`svgo.config.mjs`**
```js
const importedPlugin = require('./imported-plugin');
import importedPlugin from './imported-plugin';
module.exports = {
export default {
plugins: [

@@ -147,3 +147,3 @@ // plugin imported from another JavaScript file

```js
const { optimize } = require('svgo');
import { optimize } from 'svgo';

@@ -160,6 +160,6 @@ const result = optimize(svgString, {

If you write a tool on top of SVGO you may want to resolve the `svgo.config.js` file.
If you write a tool on top of SVGO you may want to resolve the `svgo.config.mjs` file.
```js
const { loadConfig } = require('svgo');
import { loadConfig } from 'svgo';

@@ -166,0 +166,0 @@ const config = await loadConfig();

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc