Comparing version 3.3.2 to 4.0.0-rc.0
@@ -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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
82
25134
3
Yes
1348828
21
1
8
+ Addedsax@^1.4.1
+ Addedcommander@11.1.0(transitive)
+ Addedsax@1.4.1(transitive)
- Removed@trysound/sax@0.2.0
- Removed@trysound/sax@0.2.0(transitive)
- Removedcommander@7.2.0(transitive)
Updatedcommander@^11.1.0