schnee effeckt und fehler Korektur

This commit is contained in:
2023-08-14 17:52:24 +02:00
parent 4a843d4936
commit 79af4e9907
6813 changed files with 343821 additions and 356128 deletions

239
node_modules/svgo/lib/css-tools.js generated vendored Normal file
View File

@@ -0,0 +1,239 @@
'use strict';
var csstree = require('css-tree'),
List = csstree.List,
stable = require('stable'),
specificity = require('csso/lib/restructure/prepare/specificity');
/**
* Flatten a CSS AST to a selectors list.
*
* @param {import('css-tree').CssNode} cssAst css-tree AST to flatten
* @return {Array} selectors
*/
function flattenToSelectors(cssAst) {
var selectors = [];
csstree.walk(cssAst, {
visit: 'Rule',
enter: function (node) {
if (node.type !== 'Rule') {
return;
}
var atrule = this.atrule;
var rule = node;
node.prelude.children.each(function (selectorNode, selectorItem) {
var selector = {
item: selectorItem,
atrule: atrule,
rule: rule,
pseudos: /** @type {{item: any; list: any[]}[]} */ ([]),
};
selectorNode.children.each(function (
selectorChildNode,
selectorChildItem,
selectorChildList
) {
if (
selectorChildNode.type === 'PseudoClassSelector' ||
selectorChildNode.type === 'PseudoElementSelector'
) {
selector.pseudos.push({
item: selectorChildItem,
list: selectorChildList,
});
}
});
selectors.push(selector);
});
},
});
return selectors;
}
/**
* Filter selectors by Media Query.
*
* @param {Array} selectors to filter
* @param {Array} useMqs Array with strings of media queries that should pass (<name> <expression>)
* @return {Array} Filtered selectors that match the passed media queries
*/
function filterByMqs(selectors, useMqs) {
return selectors.filter(function (selector) {
if (selector.atrule === null) {
return ~useMqs.indexOf('');
}
var mqName = selector.atrule.name;
var mqStr = mqName;
if (
selector.atrule.expression &&
selector.atrule.expression.children.first().type === 'MediaQueryList'
) {
var mqExpr = csstree.generate(selector.atrule.expression);
mqStr = [mqName, mqExpr].join(' ');
}
return ~useMqs.indexOf(mqStr);
});
}
/**
* Filter selectors by the pseudo-elements and/or -classes they contain.
*
* @param {Array} selectors to filter
* @param {Array} usePseudos Array with strings of single or sequence of pseudo-elements and/or -classes that should pass
* @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes
*/
function filterByPseudos(selectors, usePseudos) {
return selectors.filter(function (selector) {
var pseudoSelectorsStr = csstree.generate({
type: 'Selector',
children: new List().fromArray(
selector.pseudos.map(function (pseudo) {
return pseudo.item.data;
})
),
});
return ~usePseudos.indexOf(pseudoSelectorsStr);
});
}
/**
* Remove pseudo-elements and/or -classes from the selectors for proper matching.
*
* @param {Array} selectors to clean
* @return {void}
*/
function cleanPseudos(selectors) {
selectors.forEach(function (selector) {
selector.pseudos.forEach(function (pseudo) {
pseudo.list.remove(pseudo.item);
});
});
}
/**
* Compares two selector specificities.
* extracted from https://github.com/keeganstreet/specificity/blob/master/specificity.js#L211
*
* @param {Array} aSpecificity Specificity of selector A
* @param {Array} bSpecificity Specificity of selector B
* @return {number} Score of selector specificity A compared to selector specificity B
*/
function compareSpecificity(aSpecificity, bSpecificity) {
for (var i = 0; i < 4; i += 1) {
if (aSpecificity[i] < bSpecificity[i]) {
return -1;
} else if (aSpecificity[i] > bSpecificity[i]) {
return 1;
}
}
return 0;
}
/**
* Compare two simple selectors.
*
* @param {Object} aSimpleSelectorNode Simple selector A
* @param {Object} bSimpleSelectorNode Simple selector B
* @return {number} Score of selector A compared to selector B
*/
function compareSimpleSelectorNode(aSimpleSelectorNode, bSimpleSelectorNode) {
var aSpecificity = specificity(aSimpleSelectorNode),
bSpecificity = specificity(bSimpleSelectorNode);
return compareSpecificity(aSpecificity, bSpecificity);
}
function _bySelectorSpecificity(selectorA, selectorB) {
return compareSimpleSelectorNode(selectorA.item.data, selectorB.item.data);
}
/**
* Sort selectors stably by their specificity.
*
* @param {Array} selectors to be sorted
* @return {Array} Stable sorted selectors
*/
function sortSelectors(selectors) {
return stable(selectors, _bySelectorSpecificity);
}
/**
* Convert a css-tree AST style declaration to CSSStyleDeclaration property.
*
* @param {import('css-tree').CssNode} declaration css-tree style declaration
* @return {Object} CSSStyleDeclaration property
*/
function csstreeToStyleDeclaration(declaration) {
var propertyName = declaration.property,
propertyValue = csstree.generate(declaration.value),
propertyPriority = declaration.important ? 'important' : '';
return {
name: propertyName,
value: propertyValue,
priority: propertyPriority,
};
}
/**
* Gets the CSS string of a style element
*
* @param {Object} elem style element
* @return {string} CSS string or empty array if no styles are set
*/
function getCssStr(elem) {
if (
elem.children.length > 0 &&
(elem.children[0].type === 'text' || elem.children[0].type === 'cdata')
) {
return elem.children[0].value;
}
return '';
}
/**
* Sets the CSS string of a style element
*
* @param {Object} elem style element
* @param {string} css string to be set
* @return {string} reference to field with CSS
*/
function setCssStr(elem, css) {
if (elem.children.length === 0) {
elem.children.push({
type: 'text',
value: '',
});
}
if (elem.children[0].type !== 'text' && elem.children[0].type !== 'cdata') {
return css;
}
elem.children[0].value = css;
return css;
}
module.exports.flattenToSelectors = flattenToSelectors;
module.exports.filterByMqs = filterByMqs;
module.exports.filterByPseudos = filterByPseudos;
module.exports.cleanPseudos = cleanPseudos;
module.exports.compareSpecificity = compareSpecificity;
module.exports.compareSimpleSelectorNode = compareSimpleSelectorNode;
module.exports.sortSelectors = sortSelectors;
module.exports.csstreeToStyleDeclaration = csstreeToStyleDeclaration;
module.exports.getCssStr = getCssStr;
module.exports.setCssStr = setCssStr;

259
node_modules/svgo/lib/parser.js generated vendored Normal file
View File

@@ -0,0 +1,259 @@
'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
*/
// @ts-ignore sax will be replaced with something else later
const SAX = require('@trysound/sax');
const JSAPI = require('./svgo/jsAPI.js');
const { textElems } = require('../plugins/_collections.js');
class SvgoParserError extends Error {
/**
* @param message {string}
* @param line {number}
* @param column {number}
* @param source {string}
* @param file {void | string}
*/
constructor(message, line, column, source, file) {
super(message);
this.name = 'SvgoParserError';
this.message = `${file || '<input>'}:${line}:${column}: ${message}`;
this.reason = message;
this.line = line;
this.column = column;
this.source = source;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, SvgoParserError);
}
}
toString() {
const lines = this.source.split(/\r?\n/);
const startLine = Math.max(this.line - 3, 0);
const endLine = Math.min(this.line + 2, lines.length);
const lineNumberWidth = String(endLine).length;
const startColumn = Math.max(this.column - 54, 0);
const endColumn = Math.max(this.column + 20, 80);
const code = lines
.slice(startLine, endLine)
.map((line, index) => {
const lineSlice = line.slice(startColumn, endColumn);
let ellipsisPrefix = '';
let ellipsisSuffix = '';
if (startColumn !== 0) {
ellipsisPrefix = startColumn > line.length - 1 ? ' ' : '…';
}
if (endColumn < line.length - 1) {
ellipsisSuffix = '…';
}
const number = startLine + 1 + index;
const gutter = ` ${number.toString().padStart(lineNumberWidth)} | `;
if (number === this.line) {
const gutterSpacing = gutter.replace(/[^|]/g, ' ');
const lineSpacing = (
ellipsisPrefix + line.slice(startColumn, this.column - 1)
).replace(/[^\t]/g, ' ');
const spacing = gutterSpacing + lineSpacing;
return `>${gutter}${ellipsisPrefix}${lineSlice}${ellipsisSuffix}\n ${spacing}^`;
}
return ` ${gutter}${ellipsisPrefix}${lineSlice}${ellipsisSuffix}`;
})
.join('\n');
return `${this.name}: ${this.message}\n\n${code}\n`;
}
}
const entityDeclaration = /<!ENTITY\s+(\S+)\s+(?:'([^']+)'|"([^"]+)")\s*>/g;
const config = {
strict: true,
trim: false,
normalize: false,
lowercase: true,
xmlns: true,
position: true,
};
/**
* Convert SVG (XML) string to SVG-as-JS object.
*
* @type {(data: string, from?: string) => XastRoot}
*/
const parseSvg = (data, from) => {
const sax = SAX.parser(config.strict, config);
/**
* @type {XastRoot}
*/
const root = new JSAPI({ type: 'root', children: [] });
/**
* @type {XastParent}
*/
let current = root;
/**
* @type {Array<XastParent>}
*/
const stack = [root];
/**
* @type {<T extends XastNode>(node: T) => T}
*/
const pushToContent = (node) => {
const wrapped = new JSAPI(node, current);
current.children.push(wrapped);
return wrapped;
};
/**
* @type {(doctype: string) => void}
*/
sax.ondoctype = (doctype) => {
/**
* @type {XastDoctype}
*/
const node = {
type: 'doctype',
// TODO parse doctype for name, public and system to match xast
name: 'svg',
data: {
doctype,
},
};
pushToContent(node);
const subsetStart = doctype.indexOf('[');
if (subsetStart >= 0) {
entityDeclaration.lastIndex = subsetStart;
let entityMatch = entityDeclaration.exec(data);
while (entityMatch != null) {
sax.ENTITIES[entityMatch[1]] = entityMatch[2] || entityMatch[3];
entityMatch = entityDeclaration.exec(data);
}
}
};
/**
* @type {(data: { name: string, body: string }) => void}
*/
sax.onprocessinginstruction = (data) => {
/**
* @type {XastInstruction}
*/
const node = {
type: 'instruction',
name: data.name,
value: data.body,
};
pushToContent(node);
};
/**
* @type {(comment: string) => void}
*/
sax.oncomment = (comment) => {
/**
* @type {XastComment}
*/
const node = {
type: 'comment',
value: comment.trim(),
};
pushToContent(node);
};
/**
* @type {(cdata: string) => void}
*/
sax.oncdata = (cdata) => {
/**
* @type {XastCdata}
*/
const node = {
type: 'cdata',
value: cdata,
};
pushToContent(node);
};
/**
* @type {(data: { name: string, attributes: Record<string, { value: string }>}) => void}
*/
sax.onopentag = (data) => {
/**
* @type {XastElement}
*/
let element = {
type: 'element',
name: data.name,
attributes: {},
children: [],
};
for (const [name, attr] of Object.entries(data.attributes)) {
element.attributes[name] = attr.value;
}
element = pushToContent(element);
current = element;
stack.push(element);
};
/**
* @type {(text: string) => void}
*/
sax.ontext = (text) => {
if (current.type === 'element') {
// prevent trimming of meaningful whitespace inside textual tags
if (textElems.includes(current.name)) {
/**
* @type {XastText}
*/
const node = {
type: 'text',
value: text,
};
pushToContent(node);
} else if (/\S/.test(text)) {
/**
* @type {XastText}
*/
const node = {
type: 'text',
value: text.trim(),
};
pushToContent(node);
}
}
};
sax.onclosetag = () => {
stack.pop();
current = stack[stack.length - 1];
};
/**
* @type {(e: any) => void}
*/
sax.onerror = (e) => {
const error = new SvgoParserError(
e.reason,
e.line + 1,
e.column,
data,
from
);
if (e.message.indexOf('Unexpected end') === -1) {
throw error;
}
};
sax.write(data).close();
return root;
};
exports.parseSvg = parseSvg;

347
node_modules/svgo/lib/path.js generated vendored Normal file
View File

@@ -0,0 +1,347 @@
'use strict';
/**
* @typedef {import('./types').PathDataItem} PathDataItem
* @typedef {import('./types').PathDataCommand} PathDataCommand
*/
// Based on https://www.w3.org/TR/SVG11/paths.html#PathDataBNF
const argsCountPerCommand = {
M: 2,
m: 2,
Z: 0,
z: 0,
L: 2,
l: 2,
H: 1,
h: 1,
V: 1,
v: 1,
C: 6,
c: 6,
S: 4,
s: 4,
Q: 4,
q: 4,
T: 2,
t: 2,
A: 7,
a: 7,
};
/**
* @type {(c: string) => c is PathDataCommand}
*/
const isCommand = (c) => {
return c in argsCountPerCommand;
};
/**
* @type {(c: string) => boolean}
*/
const isWsp = (c) => {
const codePoint = c.codePointAt(0);
return (
codePoint === 0x20 ||
codePoint === 0x9 ||
codePoint === 0xd ||
codePoint === 0xa
);
};
/**
* @type {(c: string) => boolean}
*/
const isDigit = (c) => {
const codePoint = c.codePointAt(0);
if (codePoint == null) {
return false;
}
return 48 <= codePoint && codePoint <= 57;
};
/**
* @typedef {'none' | 'sign' | 'whole' | 'decimal_point' | 'decimal' | 'e' | 'exponent_sign' | 'exponent'} ReadNumberState
*/
/**
* @type {(string: string, cursor: number) => [number, number | null]}
*/
const readNumber = (string, cursor) => {
let i = cursor;
let value = '';
let state = /** @type {ReadNumberState} */ ('none');
for (; i < string.length; i += 1) {
const c = string[i];
if (c === '+' || c === '-') {
if (state === 'none') {
state = 'sign';
value += c;
continue;
}
if (state === 'e') {
state = 'exponent_sign';
value += c;
continue;
}
}
if (isDigit(c)) {
if (state === 'none' || state === 'sign' || state === 'whole') {
state = 'whole';
value += c;
continue;
}
if (state === 'decimal_point' || state === 'decimal') {
state = 'decimal';
value += c;
continue;
}
if (state === 'e' || state === 'exponent_sign' || state === 'exponent') {
state = 'exponent';
value += c;
continue;
}
}
if (c === '.') {
if (state === 'none' || state === 'sign' || state === 'whole') {
state = 'decimal_point';
value += c;
continue;
}
}
if (c === 'E' || c == 'e') {
if (
state === 'whole' ||
state === 'decimal_point' ||
state === 'decimal'
) {
state = 'e';
value += c;
continue;
}
}
break;
}
const number = Number.parseFloat(value);
if (Number.isNaN(number)) {
return [cursor, null];
} else {
// step back to delegate iteration to parent loop
return [i - 1, number];
}
};
/**
* @type {(string: string) => Array<PathDataItem>}
*/
const parsePathData = (string) => {
/**
* @type {Array<PathDataItem>}
*/
const pathData = [];
/**
* @type {null | PathDataCommand}
*/
let command = null;
let args = /** @type {number[]} */ ([]);
let argsCount = 0;
let canHaveComma = false;
let hadComma = false;
for (let i = 0; i < string.length; i += 1) {
const c = string.charAt(i);
if (isWsp(c)) {
continue;
}
// allow comma only between arguments
if (canHaveComma && c === ',') {
if (hadComma) {
break;
}
hadComma = true;
continue;
}
if (isCommand(c)) {
if (hadComma) {
return pathData;
}
if (command == null) {
// moveto should be leading command
if (c !== 'M' && c !== 'm') {
return pathData;
}
} else {
// stop if previous command arguments are not flushed
if (args.length !== 0) {
return pathData;
}
}
command = c;
args = [];
argsCount = argsCountPerCommand[command];
canHaveComma = false;
// flush command without arguments
if (argsCount === 0) {
pathData.push({ command, args });
}
continue;
}
// avoid parsing arguments if no command detected
if (command == null) {
return pathData;
}
// read next argument
let newCursor = i;
let number = null;
if (command === 'A' || command === 'a') {
const position = args.length;
if (position === 0 || position === 1) {
// allow only positive number without sign as first two arguments
if (c !== '+' && c !== '-') {
[newCursor, number] = readNumber(string, i);
}
}
if (position === 2 || position === 5 || position === 6) {
[newCursor, number] = readNumber(string, i);
}
if (position === 3 || position === 4) {
// read flags
if (c === '0') {
number = 0;
}
if (c === '1') {
number = 1;
}
}
} else {
[newCursor, number] = readNumber(string, i);
}
if (number == null) {
return pathData;
}
args.push(number);
canHaveComma = true;
hadComma = false;
i = newCursor;
// flush arguments when necessary count is reached
if (args.length === argsCount) {
pathData.push({ command, args });
// subsequent moveto coordinates are threated as implicit lineto commands
if (command === 'M') {
command = 'L';
}
if (command === 'm') {
command = 'l';
}
args = [];
}
}
return pathData;
};
exports.parsePathData = parsePathData;
/**
* @type {(number: number, precision?: number) => string}
*/
const stringifyNumber = (number, precision) => {
if (precision != null) {
const ratio = 10 ** precision;
number = Math.round(number * ratio) / ratio;
}
// remove zero whole from decimal number
return number.toString().replace(/^0\./, '.').replace(/^-0\./, '-.');
};
/**
* Elliptical arc large-arc and sweep flags are rendered with spaces
* because many non-browser environments are not able to parse such paths
*
* @type {(
* command: string,
* args: number[],
* precision?: number,
* disableSpaceAfterFlags?: boolean
* ) => string}
*/
const stringifyArgs = (command, args, precision, disableSpaceAfterFlags) => {
let result = '';
let prev = '';
for (let i = 0; i < args.length; i += 1) {
const number = args[i];
const numberString = stringifyNumber(number, precision);
if (
disableSpaceAfterFlags &&
(command === 'A' || command === 'a') &&
// consider combined arcs
(i % 7 === 4 || i % 7 === 5)
) {
result += numberString;
} else if (i === 0 || numberString.startsWith('-')) {
// avoid space before first and negative numbers
result += numberString;
} else if (prev.includes('.') && numberString.startsWith('.')) {
// remove space before decimal with zero whole
// only when previous number is also decimal
result += numberString;
} else {
result += ` ${numberString}`;
}
prev = numberString;
}
return result;
};
/**
* @typedef {{
* pathData: Array<PathDataItem>;
* precision?: number;
* disableSpaceAfterFlags?: boolean;
* }} StringifyPathDataOptions
*/
/**
* @type {(options: StringifyPathDataOptions) => string}
*/
const stringifyPathData = ({ pathData, precision, disableSpaceAfterFlags }) => {
// combine sequence of the same commands
let combined = [];
for (let i = 0; i < pathData.length; i += 1) {
const { command, args } = pathData[i];
if (i === 0) {
combined.push({ command, args });
} else {
/**
* @type {PathDataItem}
*/
const last = combined[combined.length - 1];
// match leading moveto with following lineto
if (i === 1) {
if (command === 'L') {
last.command = 'M';
}
if (command === 'l') {
last.command = 'm';
}
}
if (
(last.command === command &&
last.command !== 'M' &&
last.command !== 'm') ||
// combine matching moveto and lineto sequences
(last.command === 'M' && command === 'L') ||
(last.command === 'm' && command === 'l')
) {
last.args = [...last.args, ...args];
} else {
combined.push({ command, args });
}
}
}
let result = '';
for (const { command, args } of combined) {
result +=
command + stringifyArgs(command, args, precision, disableSpaceAfterFlags);
}
return result;
};
exports.stringifyPathData = stringifyPathData;

326
node_modules/svgo/lib/stringifier.js generated vendored Normal file
View File

@@ -0,0 +1,326 @@
'use strict';
/**
* @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.js');
/**
* @typedef {{
* width: void | string,
* height: void | string,
* indent: string,
* textContext: null | XastElement,
* indentLevel: number,
* }} State
*/
/**
* @typedef {Required<StringifyOptions>} Options
*/
/**
* @type {(char: string) => string}
*/
const encodeEntity = (char) => {
return entities[char];
};
/**
* @type {Options}
*/
const defaults = {
doctypeStart: '<!DOCTYPE',
doctypeEnd: '>',
procInstStart: '<?',
procInstEnd: '?>',
tagOpenStart: '<',
tagOpenEnd: '>',
tagCloseStart: '</',
tagCloseEnd: '>',
tagShortStart: '<',
tagShortEnd: '/>',
attrStart: '="',
attrEnd: '"',
commentStart: '<!--',
commentEnd: '-->',
cdataStart: '<![CDATA[',
cdataEnd: ']]>',
textStart: '',
textEnd: '',
indent: 4,
regEntities: /[&'"<>]/g,
regValEntities: /[&"<>]/g,
encodeEntity: encodeEntity,
pretty: false,
useShortTags: true,
eol: 'lf',
finalNewline: false,
};
/**
* @type {Record<string, string>}
*/
const entities = {
'&': '&amp;',
"'": '&apos;',
'"': '&quot;',
'>': '&gt;',
'<': '&lt;',
};
/**
* convert XAST to SVG string
*
* @type {(data: XastRoot, config: StringifyOptions) => {
* data: string,
* info: {
* width: void | string,
* height: void | string
* }
* }}
*/
const stringifySvg = (data, userOptions = {}) => {
/**
* @type {Options}
*/
const config = { ...defaults, ...userOptions };
const indent = config.indent;
let newIndent = ' ';
if (typeof indent === 'number' && Number.isNaN(indent) === false) {
newIndent = indent < 0 ? '\t' : ' '.repeat(indent);
} else if (typeof indent === 'string') {
newIndent = indent;
}
/**
* @type {State}
*/
const state = {
// TODO remove width and height in v3
width: undefined,
height: undefined,
indent: newIndent,
textContext: null,
indentLevel: 0,
};
const eol = config.eol === 'crlf' ? '\r\n' : '\n';
if (config.pretty) {
config.doctypeEnd += eol;
config.procInstEnd += eol;
config.commentEnd += eol;
config.cdataEnd += eol;
config.tagShortEnd += eol;
config.tagOpenEnd += eol;
config.tagCloseEnd += eol;
config.textEnd += eol;
}
let svg = stringifyNode(data, config, state);
if (config.finalNewline && svg.length > 0 && svg[svg.length - 1] !== '\n') {
svg += eol;
}
return {
data: svg,
info: {
width: state.width,
height: state.height,
},
};
};
exports.stringifySvg = stringifySvg;
/**
* @type {(node: XastParent, config: Options, state: State) => string}
*/
const stringifyNode = (data, config, state) => {
let svg = '';
state.indentLevel += 1;
for (const item of data.children) {
if (item.type === 'element') {
svg += stringifyElement(item, config, state);
}
if (item.type === 'text') {
svg += stringifyText(item, config, state);
}
if (item.type === 'doctype') {
svg += stringifyDoctype(item, config);
}
if (item.type === 'instruction') {
svg += stringifyInstruction(item, config);
}
if (item.type === 'comment') {
svg += stringifyComment(item, config);
}
if (item.type === 'cdata') {
svg += stringifyCdata(item, config, state);
}
}
state.indentLevel -= 1;
return svg;
};
/**
* create indent string in accordance with the current node level.
*
* @type {(config: Options, state: State) => string}
*/
const createIndent = (config, state) => {
let indent = '';
if (config.pretty && state.textContext == null) {
indent = state.indent.repeat(state.indentLevel - 1);
}
return indent;
};
/**
* @type {(node: XastDoctype, config: Options) => string}
*/
const stringifyDoctype = (node, config) => {
return config.doctypeStart + node.data.doctype + config.doctypeEnd;
};
/**
* @type {(node: XastInstruction, config: Options) => string}
*/
const stringifyInstruction = (node, config) => {
return (
config.procInstStart + node.name + ' ' + node.value + config.procInstEnd
);
};
/**
* @type {(node: XastComment, config: Options) => string}
*/
const stringifyComment = (node, config) => {
return config.commentStart + node.value + config.commentEnd;
};
/**
* @type {(node: XastCdata, config: Options, state: State) => string}
*/
const stringifyCdata = (node, config, state) => {
return (
createIndent(config, state) +
config.cdataStart +
node.value +
config.cdataEnd
);
};
/**
* @type {(node: XastElement, config: Options, state: State) => string}
*/
const stringifyElement = (node, config, state) => {
// beautiful injection for obtaining SVG information :)
if (
node.name === 'svg' &&
node.attributes.width != null &&
node.attributes.height != null
) {
state.width = node.attributes.width;
state.height = node.attributes.height;
}
// empty element and short tag
if (node.children.length === 0) {
if (config.useShortTags) {
return (
createIndent(config, state) +
config.tagShortStart +
node.name +
stringifyAttributes(node, config) +
config.tagShortEnd
);
} else {
return (
createIndent(config, state) +
config.tagShortStart +
node.name +
stringifyAttributes(node, config) +
config.tagOpenEnd +
config.tagCloseStart +
node.name +
config.tagCloseEnd
);
}
// non-empty element
} else {
let tagOpenStart = config.tagOpenStart;
let tagOpenEnd = config.tagOpenEnd;
let tagCloseStart = config.tagCloseStart;
let tagCloseEnd = config.tagCloseEnd;
let openIndent = createIndent(config, state);
let closeIndent = createIndent(config, state);
if (state.textContext) {
tagOpenStart = defaults.tagOpenStart;
tagOpenEnd = defaults.tagOpenEnd;
tagCloseStart = defaults.tagCloseStart;
tagCloseEnd = defaults.tagCloseEnd;
openIndent = '';
} else if (textElems.includes(node.name)) {
tagOpenEnd = defaults.tagOpenEnd;
tagCloseStart = defaults.tagCloseStart;
closeIndent = '';
state.textContext = node;
}
const children = stringifyNode(node, config, state);
if (state.textContext === node) {
state.textContext = null;
}
return (
openIndent +
tagOpenStart +
node.name +
stringifyAttributes(node, config) +
tagOpenEnd +
children +
closeIndent +
tagCloseStart +
node.name +
tagCloseEnd
);
}
};
/**
* @type {(node: XastElement, config: Options) => string}
*/
const stringifyAttributes = (node, config) => {
let attrs = '';
for (const [name, value] of Object.entries(node.attributes)) {
// TODO remove attributes without values support in v3
if (value !== undefined) {
const encodedValue = value
.toString()
.replace(config.regValEntities, config.encodeEntity);
attrs += ' ' + name + config.attrStart + encodedValue + config.attrEnd;
} else {
attrs += ' ' + name;
}
}
return attrs;
};
/**
* @type {(node: XastText, config: Options, state: State) => string}
*/
const stringifyText = (node, config, state) => {
return (
createIndent(config, state) +
config.textStart +
node.value.replace(config.regEntities, config.encodeEntity) +
(state.textContext ? '' : config.textEnd)
);
};

283
node_modules/svgo/lib/style.js generated vendored Normal file
View File

@@ -0,0 +1,283 @@
'use strict';
/**
* @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
*/
const stable = require('stable');
const csstree = require('css-tree');
// @ts-ignore not defined in @types/csso
const specificity = require('csso/lib/restructure/prepare/specificity');
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;
/**
* @type {(ruleNode: CsstreeRule, dynamic: boolean) => StylesheetRule}
*/
const parseRule = (ruleNode, dynamic) => {
let selectors;
let selectorsSpecificity;
/**
* @type {Array<StylesheetDeclaration>}
*/
const declarations = [];
csstree.walk(ruleNode, (cssNode) => {
if (cssNode.type === 'SelectorList') {
// compute specificity from original node to consider pseudo classes
selectorsSpecificity = specificity(cssNode);
const newSelectorsNode = csstree.clone(cssNode);
csstree.walk(newSelectorsNode, (pseudoClassNode, item, list) => {
if (pseudoClassNode.type === 'PseudoClassSelector') {
dynamic = true;
list.remove(item);
}
});
selectors = csstree.generate(newSelectorsNode);
return csstreeWalkSkip;
}
if (cssNode.type === 'Declaration') {
declarations.push({
name: cssNode.property,
value: csstree.generate(cssNode.value),
important: cssNode.important === true,
});
return csstreeWalkSkip;
}
});
if (selectors == null || selectorsSpecificity == null) {
throw Error('assert');
}
return {
dynamic,
selectors,
specificity: selectorsSpecificity,
declarations,
};
};
/**
* @type {(css: string, dynamic: boolean) => Array<StylesheetRule>}
*/
const parseStylesheet = (css, dynamic) => {
/**
* @type {Array<StylesheetRule>}
*/
const rules = [];
const ast = csstree.parse(css, {
parseValue: false,
parseAtrulePrelude: false,
});
csstree.walk(ast, (cssNode) => {
if (cssNode.type === 'Rule') {
rules.push(parseRule(cssNode, dynamic || false));
return csstreeWalkSkip;
}
if (cssNode.type === 'Atrule') {
if (cssNode.name === 'keyframes') {
return csstreeWalkSkip;
}
csstree.walk(cssNode, (ruleNode) => {
if (ruleNode.type === 'Rule') {
rules.push(parseRule(ruleNode, dynamic || true));
return csstreeWalkSkip;
}
});
return csstreeWalkSkip;
}
});
return rules;
};
/**
* @type {(css: string) => Array<StylesheetDeclaration>}
*/
const parseStyleDeclarations = (css) => {
/**
* @type {Array<StylesheetDeclaration>}
*/
const declarations = [];
const ast = csstree.parse(css, {
context: 'declarationList',
parseValue: false,
});
csstree.walk(ast, (cssNode) => {
if (cssNode.type === 'Declaration') {
declarations.push({
name: cssNode.property,
value: csstree.generate(cssNode.value),
important: cssNode.important === true,
});
}
});
return declarations;
};
/**
* @type {(stylesheet: Stylesheet, node: XastElement) => ComputedStyles}
*/
const computeOwnStyle = (stylesheet, node) => {
/**
* @type {ComputedStyles}
*/
const computedStyle = {};
const importantStyles = new Map();
// collect attributes
for (const [name, value] of Object.entries(node.attributes)) {
if (attrsGroups.presentation.includes(name)) {
computedStyle[name] = { type: 'static', inherited: false, value };
importantStyles.set(name, false);
}
}
// collect matching rules
for (const { selectors, declarations, dynamic } of stylesheet.rules) {
if (matches(node, selectors)) {
for (const { name, value, important } of declarations) {
const computed = computedStyle[name];
if (computed && computed.type === 'dynamic') {
continue;
}
if (dynamic) {
computedStyle[name] = { type: 'dynamic', inherited: false };
continue;
}
if (
computed == null ||
important === true ||
importantStyles.get(name) === false
) {
computedStyle[name] = { type: 'static', inherited: false, value };
importantStyles.set(name, important);
}
}
}
}
// collect inline styles
const styleDeclarations =
node.attributes.style == null
? []
: parseStyleDeclarations(node.attributes.style);
for (const { name, value, important } of styleDeclarations) {
const computed = computedStyle[name];
if (computed && computed.type === 'dynamic') {
continue;
}
if (
computed == null ||
important === true ||
importantStyles.get(name) === false
) {
computedStyle[name] = { type: 'static', inherited: false, value };
importantStyles.set(name, important);
}
}
return computedStyle;
};
/**
* Compares two selector specificities.
* extracted from https://github.com/keeganstreet/specificity/blob/master/specificity.js#L211
*
* @type {(a: Specificity, b: Specificity) => number}
*/
const compareSpecificity = (a, b) => {
for (var i = 0; i < 4; i += 1) {
if (a[i] < b[i]) {
return -1;
} else if (a[i] > b[i]) {
return 1;
}
}
return 0;
};
/**
* @type {(root: XastRoot) => Stylesheet}
*/
const collectStylesheet = (root) => {
/**
* @type {Array<StylesheetRule>}
*/
const rules = [];
/**
* @type {Map<XastElement, XastParent>}
*/
const parents = new Map();
visit(root, {
element: {
enter: (node, parentNode) => {
// store parents
parents.set(node, parentNode);
// find and parse all styles
if (node.name === 'style') {
const dynamic =
node.attributes.media != null && node.attributes.media !== 'all';
if (
node.attributes.type == null ||
node.attributes.type === '' ||
node.attributes.type === 'text/css'
) {
const children = node.children;
for (const child of children) {
if (child.type === 'text' || child.type === 'cdata') {
rules.push(...parseStylesheet(child.value, dynamic));
}
}
}
}
},
},
});
// sort by selectors specificity
stable.inplace(rules, (a, b) =>
compareSpecificity(a.specificity, b.specificity)
);
return { rules, parents };
};
exports.collectStylesheet = collectStylesheet;
/**
* @type {(stylesheet: Stylesheet, node: XastElement) => ComputedStyles}
*/
const computeStyle = (stylesheet, node) => {
const { parents } = stylesheet;
// collect inherited styles
const computedStyles = computeOwnStyle(stylesheet, node);
let parent = parents.get(node);
while (parent != null && parent.type !== 'root') {
const inheritedStyles = computeOwnStyle(stylesheet, parent);
for (const [name, computed] of Object.entries(inheritedStyles)) {
if (
computedStyles[name] == null &&
// ignore not inheritable styles
inheritableAttrs.includes(name) === true &&
presentationNonInheritableGroupAttrs.includes(name) === false
) {
computedStyles[name] = { ...computed, inherited: true };
}
}
parent = parents.get(parent);
}
return computedStyles;
};
exports.computeStyle = computeStyle;

106
node_modules/svgo/lib/svgo-node.js generated vendored Normal file
View File

@@ -0,0 +1,106 @@
'use strict';
const os = require('os');
const fs = require('fs');
const { pathToFileURL } = require('url');
const path = require('path');
const {
extendDefaultPlugins,
optimize: optimizeAgnostic,
createContentItem,
} = require('./svgo.js');
exports.extendDefaultPlugins = extendDefaultPlugins;
exports.createContentItem = createContentItem;
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 {
try {
// 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;
} catch (importError) {
// TODO remove require in v3
try {
config = require(configFile);
} catch (requireError) {
// throw original error if es module is detected
if (requireError.code === 'ERR_REQUIRE_ESM') {
throw importError;
} else {
throw requireError;
}
}
}
}
if (config == null || typeof config !== 'object' || Array.isArray(config)) {
throw Error(`Invalid config file "${configFile}"`);
}
return config;
};
const isFile = async (file) => {
try {
const stats = await fs.promises.stat(file);
return stats.isFile();
} catch {
return false;
}
};
const loadConfig = async (configFile, cwd = process.cwd()) => {
if (configFile != null) {
if (path.isAbsolute(configFile)) {
return await importConfig(configFile);
} else {
return await importConfig(path.join(cwd, configFile));
}
}
let dir = cwd;
// eslint-disable-next-line no-constant-condition
while (true) {
const js = path.join(dir, 'svgo.config.js');
if (await isFile(js)) {
return await importConfig(js);
}
const mjs = path.join(dir, 'svgo.config.mjs');
if (await isFile(mjs)) {
return await importConfig(mjs);
}
const cjs = path.join(dir, 'svgo.config.cjs');
if (await isFile(cjs)) {
return await importConfig(cjs);
}
const parent = path.dirname(dir);
if (dir === parent) {
return null;
}
dir = parent;
}
};
exports.loadConfig = loadConfig;
const optimize = (input, config) => {
if (config == null) {
config = {};
}
if (typeof config !== 'object') {
throw Error('Config should be an object');
}
return optimizeAgnostic(input, {
...config,
js2svg: {
// platform specific default for end of line
eol: os.EOL === '\r\n' ? 'crlf' : 'lf',
...config.js2svg,
},
});
};
exports.optimize = optimize;

139
node_modules/svgo/lib/svgo.js generated vendored
View File

@@ -1,80 +1,83 @@
'use strict';
/**
* SVGO is a Nodejs-based tool for optimizing SVG vector graphics files.
*
* @see https://github.com/svg/svgo
*
* @author Kir Belevich <kir@soulshine.in> (https://github.com/deepsweet)
* @copyright © 2012 Kir Belevich
* @license MIT https://raw.githubusercontent.com/svg/svgo/master/LICENSE
*/
const {
defaultPlugins,
resolvePluginConfig,
extendDefaultPlugins,
} = require('./svgo/config.js');
const { parseSvg } = require('./parser.js');
const { stringifySvg } = require('./stringifier.js');
const { invokePlugins } = require('./svgo/plugins.js');
const JSAPI = require('./svgo/jsAPI.js');
const { encodeSVGDatauri } = require('./svgo/tools.js');
var CONFIG = require('./svgo/config.js'),
SVG2JS = require('./svgo/svg2js.js'),
PLUGINS = require('./svgo/plugins.js'),
JSAPI = require('./svgo/jsAPI.js'),
JS2SVG = require('./svgo/js2svg.js');
var SVGO = module.exports = function(config) {
this.config = CONFIG(config);
exports.extendDefaultPlugins = extendDefaultPlugins;
const optimize = (input, config) => {
if (config == null) {
config = {};
}
if (typeof config !== 'object') {
throw Error('Config should be an object');
}
const maxPassCount = config.multipass ? 10 : 1;
let prevResultSize = Number.POSITIVE_INFINITY;
let svgjs = null;
const info = {};
if (config.path != null) {
info.path = config.path;
}
for (let i = 0; i < maxPassCount; i += 1) {
info.multipassCount = i;
// TODO throw this error in v3
try {
svgjs = parseSvg(input, config.path);
} catch (error) {
return { error: error.toString(), modernError: error };
}
if (svgjs.error != null) {
if (config.path != null) {
svgjs.path = config.path;
}
return svgjs;
}
const plugins = config.plugins || defaultPlugins;
if (Array.isArray(plugins) === false) {
throw Error(
"Invalid plugins list. Provided 'plugins' in config should be an array."
);
}
const resolvedPlugins = plugins.map(resolvePluginConfig);
const globalOverrides = {};
if (config.floatPrecision != null) {
globalOverrides.floatPrecision = config.floatPrecision;
}
svgjs = invokePlugins(svgjs, info, resolvedPlugins, null, globalOverrides);
svgjs = stringifySvg(svgjs, config.js2svg);
if (svgjs.data.length < prevResultSize) {
input = svgjs.data;
prevResultSize = svgjs.data.length;
} else {
if (config.datauri) {
svgjs.data = encodeSVGDatauri(svgjs.data, config.datauri);
}
if (config.path != null) {
svgjs.path = config.path;
}
return svgjs;
}
}
return svgjs;
};
SVGO.prototype.optimize = function(svgstr, callback) {
if (this.config.error) return callback(this.config);
var _this = this,
config = this.config,
maxPassCount = config.multipass ? 10 : 1,
counter = 0,
prevResultSize = Number.POSITIVE_INFINITY,
optimizeOnceCallback = function(svgjs) {
if (svgjs.error) {
callback(svgjs);
return;
}
if (++counter < maxPassCount && svgjs.data.length < prevResultSize) {
prevResultSize = svgjs.data.length;
_this._optimizeOnce(svgjs.data, optimizeOnceCallback);
} else {
callback(svgjs);
}
};
_this._optimizeOnce(svgstr, optimizeOnceCallback);
};
SVGO.prototype._optimizeOnce = function(svgstr, callback) {
var config = this.config;
SVG2JS(svgstr, function(svgjs) {
if (svgjs.error) {
callback(svgjs);
return;
}
svgjs = PLUGINS(svgjs, config.plugins);
callback(JS2SVG(svgjs, config.js2svg));
});
};
exports.optimize = optimize;
/**
* The factory that creates a content item with the helper methods.
*
* @param {Object} data which passed to jsAPI constructor
* @param {Object} data which is passed to jsAPI constructor
* @returns {JSAPI} content item
*/
SVGO.prototype.createContentItem = function(data) {
return new JSAPI(data);
const createContentItem = (data) => {
return new JSAPI(data);
};
exports.createContentItem = createContentItem;

1042
node_modules/svgo/lib/svgo/coa.js generated vendored

File diff suppressed because it is too large Load Diff

328
node_modules/svgo/lib/svgo/config.js generated vendored
View File

@@ -1,212 +1,138 @@
'use strict';
var FS = require('fs');
var yaml = require('js-yaml');
const pluginsMap = require('../../plugins/plugins.js');
var EXTEND = require('whet.extend');
const pluginsOrder = [
'removeDoctype',
'removeXMLProcInst',
'removeComments',
'removeMetadata',
'removeXMLNS',
'removeEditorsNSData',
'cleanupAttrs',
'mergeStyles',
'inlineStyles',
'minifyStyles',
'convertStyleToAttrs',
'cleanupIDs',
'prefixIds',
'removeRasterImages',
'removeUselessDefs',
'cleanupNumericValues',
'cleanupListOfValues',
'convertColors',
'removeUnknownsAndDefaults',
'removeNonInheritableGroupAttrs',
'removeUselessStrokeAndFill',
'removeViewBox',
'cleanupEnableBackground',
'removeHiddenElems',
'removeEmptyText',
'convertShapeToPath',
'convertEllipseToCircle',
'moveElemsAttrsToGroup',
'moveGroupAttrsToElems',
'collapseGroups',
'convertPathData',
'convertTransform',
'removeEmptyAttrs',
'removeEmptyContainers',
'mergePaths',
'removeUnusedNS',
'sortAttrs',
'sortDefsChildren',
'removeTitle',
'removeDesc',
'removeDimensions',
'removeAttrs',
'removeAttributesBySelector',
'removeElementsByAttr',
'addClassesToSVGElement',
'removeStyleElement',
'removeScriptElement',
'addAttributesToSVGElement',
'removeOffCanvasPaths',
'reusePaths',
];
const defaultPlugins = pluginsOrder.filter((name) => pluginsMap[name].active);
exports.defaultPlugins = defaultPlugins;
/**
* Read and/or extend/replace default config file,
* prepare and optimize plugins array.
*
* @param {Object} [config] input config
* @return {Object} output config
*/
module.exports = function(config) {
var defaults;
config = typeof config == 'object' && config || {};
if (config.plugins && !Array.isArray(config.plugins)) {
return { error: 'Error: Invalid plugins list. Provided \'plugins\' in config should be an array.' };
}
if (config.full) {
defaults = config;
if (Array.isArray(defaults.plugins)) {
defaults.plugins = preparePluginsArray(defaults.plugins);
}
const extendDefaultPlugins = (plugins) => {
console.warn(
'\n"extendDefaultPlugins" utility is deprecated.\n' +
'Use "preset-default" plugin with overrides instead.\n' +
'For example:\n' +
`{\n` +
` name: 'preset-default',\n` +
` params: {\n` +
` overrides: {\n` +
` // customize plugin options\n` +
` convertShapeToPath: {\n` +
` convertArcs: true\n` +
` },\n` +
` // disable plugins\n` +
` convertPathData: false\n` +
` }\n` +
` }\n` +
`}\n`
);
const extendedPlugins = pluginsOrder.map((name) => ({
name,
active: pluginsMap[name].active,
}));
for (const plugin of plugins) {
const resolvedPlugin = resolvePluginConfig(plugin);
const index = pluginsOrder.indexOf(resolvedPlugin.name);
if (index === -1) {
extendedPlugins.push(plugin);
} else {
defaults = EXTEND({}, yaml.safeLoad(FS.readFileSync(__dirname + '/../../.svgo.yml', 'utf8')));
defaults.plugins = preparePluginsArray(defaults.plugins);
defaults = extendConfig(defaults, config);
extendedPlugins[index] = plugin;
}
if ('floatPrecision' in config && Array.isArray(defaults.plugins)) {
defaults.plugins.forEach(function(plugin) {
if (plugin.params && ('floatPrecision' in plugin.params)) {
// Don't touch default plugin params
plugin.params = EXTEND({}, plugin.params, { floatPrecision: config.floatPrecision });
}
});
}
if (Array.isArray(defaults.plugins)) {
defaults.plugins = optimizePluginsArray(defaults.plugins);
}
return defaults;
}
return extendedPlugins;
};
exports.extendDefaultPlugins = extendDefaultPlugins;
/**
* Require() all plugins in array.
*
* @param {Array} plugins input plugins array
* @return {Array} input plugins array of arrays
*/
function preparePluginsArray(plugins) {
var plugin,
key;
return plugins.map(function(item) {
// {}
if (typeof item === 'object') {
key = Object.keys(item)[0];
// custom
if (typeof item[key] === 'object' && item[key].fn && typeof item[key].fn === 'function') {
plugin = setupCustomPlugin(key, item[key]);
} else {
plugin = EXTEND({}, require('../../plugins/' + key));
// name: {}
if (typeof item[key] === 'object') {
plugin.params = EXTEND({}, plugin.params || {}, item[key]);
plugin.active = true;
// name: false
} else if (item[key] === false) {
plugin.active = false;
// name: true
} else if (item[key] === true) {
plugin.active = true;
}
plugin.name = key;
}
// name
} else {
plugin = EXTEND({}, require('../../plugins/' + item));
plugin.name = item;
}
return plugin;
});
}
/**
* Extend plugins with the custom config object.
*
* @param {Array} plugins input plugins
* @param {Object} config config
* @return {Array} output plugins
*/
function extendConfig(defaults, config) {
var key;
// plugins
if (config.plugins) {
config.plugins.forEach(function(item) {
// {}
if (typeof item === 'object') {
key = Object.keys(item)[0];
// custom
if (typeof item[key] === 'object' && item[key].fn && typeof item[key].fn === 'function') {
defaults.plugins.push(setupCustomPlugin(key, item[key]));
} else {
defaults.plugins.forEach(function(plugin) {
if (plugin.name === key) {
// name: {}
if (typeof item[key] === 'object') {
plugin.params = EXTEND({}, plugin.params || {}, item[key]);
plugin.active = true;
// name: false
} else if (item[key] === false) {
plugin.active = false;
// name: true
} else if (item[key] === true) {
plugin.active = true;
}
}
});
}
}
});
const resolvePluginConfig = (plugin) => {
let configParams = {};
if (typeof plugin === 'string') {
// resolve builtin plugin specified as string
const pluginConfig = pluginsMap[plugin];
if (pluginConfig == null) {
throw Error(`Unknown builtin plugin "${plugin}" specified.`);
}
defaults.multipass = config.multipass;
// svg2js
if (config.svg2js) {
defaults.svg2js = config.svg2js;
return {
...pluginConfig,
name: plugin,
active: true,
params: { ...pluginConfig.params, ...configParams },
};
}
if (typeof plugin === 'object' && plugin != null) {
if (plugin.name == null) {
throw Error(`Plugin name should be specified`);
}
// js2svg
if (config.js2svg) {
defaults.js2svg = config.js2svg;
if (plugin.fn) {
// resolve custom plugin with implementation
return {
active: true,
...plugin,
params: { ...configParams, ...plugin.params },
};
} else {
// resolve builtin plugin specified as object without implementation
const pluginConfig = pluginsMap[plugin.name];
if (pluginConfig == null) {
throw Error(`Unknown builtin plugin "${plugin.name}" specified.`);
}
return {
...pluginConfig,
active: true,
...plugin,
params: { ...pluginConfig.params, ...configParams, ...plugin.params },
};
}
return defaults;
}
/**
* Setup and enable a custom plugin
*
* @param {String} plugin name
* @param {Object} custom plugin
* @return {Array} enabled plugin
*/
function setupCustomPlugin(name, plugin) {
plugin.active = true;
plugin.params = EXTEND({}, plugin.params || {});
plugin.name = name;
return plugin;
}
/**
* Try to group sequential elements of plugins array.
*
* @param {Object} plugins input plugins
* @return {Array} output plugins
*/
function optimizePluginsArray(plugins) {
var prev;
return plugins.reduce(function(plugins, item) {
if (prev && item.type == prev[0].type) {
prev.push(item);
} else {
plugins.push(prev = [item]);
}
return plugins;
}, []);
}
}
return null;
};
exports.resolvePluginConfig = resolvePluginConfig;

72
node_modules/svgo/lib/svgo/css-class-list.js generated vendored Normal file
View File

@@ -0,0 +1,72 @@
'use strict';
var CSSClassList = function (node) {
this.parentNode = node;
this.classNames = new Set();
const value = node.attributes.class;
if (value != null) {
this.addClassValueHandler();
this.setClassValue(value);
}
};
// attr.class.value
CSSClassList.prototype.addClassValueHandler = function () {
Object.defineProperty(this.parentNode.attributes, 'class', {
get: this.getClassValue.bind(this),
set: this.setClassValue.bind(this),
enumerable: true,
configurable: true,
});
};
CSSClassList.prototype.getClassValue = function () {
var arrClassNames = Array.from(this.classNames);
return arrClassNames.join(' ');
};
CSSClassList.prototype.setClassValue = function (newValue) {
if (typeof newValue === 'undefined') {
this.classNames.clear();
return;
}
var arrClassNames = newValue.split(' ');
this.classNames = new Set(arrClassNames);
};
CSSClassList.prototype.add = function (/* variadic */) {
this.addClassValueHandler();
Object.values(arguments).forEach(this._addSingle.bind(this));
};
CSSClassList.prototype._addSingle = function (className) {
this.classNames.add(className);
};
CSSClassList.prototype.remove = function (/* variadic */) {
this.addClassValueHandler();
Object.values(arguments).forEach(this._removeSingle.bind(this));
};
CSSClassList.prototype._removeSingle = function (className) {
this.classNames.delete(className);
};
CSSClassList.prototype.item = function (index) {
var arrClassNames = Array.from(this.classNames);
return arrClassNames[index];
};
CSSClassList.prototype.toggle = function (className, force) {
if (this.contains(className) || force === false) {
this.classNames.delete(className);
}
this.classNames.add(className);
};
CSSClassList.prototype.contains = function (className) {
return this.classNames.has(className);
};
module.exports = CSSClassList;

2
node_modules/svgo/lib/svgo/css-select-adapter.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare let obj: any;
export = obj;

120
node_modules/svgo/lib/svgo/css-select-adapter.js generated vendored Normal file
View File

@@ -0,0 +1,120 @@
'use strict';
const isTag = (node) => {
return node.type === 'element';
};
const existsOne = (test, elems) => {
return elems.some((elem) => {
if (isTag(elem)) {
return test(elem) || existsOne(test, getChildren(elem));
} else {
return false;
}
});
};
const getAttributeValue = (elem, name) => {
return elem.attributes[name];
};
const getChildren = (node) => {
return node.children || [];
};
const getName = (elemAst) => {
return elemAst.name;
};
const getParent = (node) => {
return node.parentNode || null;
};
const getSiblings = (elem) => {
var parent = getParent(elem);
return parent ? getChildren(parent) : [];
};
const getText = (node) => {
if (node.children[0].type === 'text' && node.children[0].type === 'cdata') {
return node.children[0].value;
}
return '';
};
const hasAttrib = (elem, name) => {
return elem.attributes[name] !== undefined;
};
const removeSubsets = (nodes) => {
let idx = nodes.length;
let node;
let ancestor;
let replace;
// Check if each node (or one of its ancestors) is already contained in the
// array.
while (--idx > -1) {
node = ancestor = nodes[idx];
// Temporarily remove the node under consideration
nodes[idx] = null;
replace = true;
while (ancestor) {
if (nodes.includes(ancestor)) {
replace = false;
nodes.splice(idx, 1);
break;
}
ancestor = getParent(ancestor);
}
// If the node has been found to be unique, re-insert it.
if (replace) {
nodes[idx] = node;
}
}
return nodes;
};
const findAll = (test, elems) => {
const result = [];
for (const elem of elems) {
if (isTag(elem)) {
if (test(elem)) {
result.push(elem);
}
result.push(...findAll(test, getChildren(elem)));
}
}
return result;
};
const findOne = (test, elems) => {
for (const elem of elems) {
if (isTag(elem)) {
if (test(elem)) {
return elem;
}
const result = findOne(test, getChildren(elem));
if (result) {
return result;
}
}
}
return null;
};
const svgoCssSelectAdapter = {
isTag,
existsOne,
getAttributeValue,
getChildren,
getName,
getParent,
getSiblings,
getText,
hasAttrib,
removeSubsets,
findAll,
findOne,
};
module.exports = svgoCssSelectAdapter;

232
node_modules/svgo/lib/svgo/css-style-declaration.js generated vendored Normal file
View File

@@ -0,0 +1,232 @@
'use strict';
var csstree = require('css-tree'),
csstools = require('../css-tools');
var CSSStyleDeclaration = function (node) {
this.parentNode = node;
this.properties = new Map();
this.hasSynced = false;
this.styleValue = null;
this.parseError = false;
const value = node.attributes.style;
if (value != null) {
this.addStyleValueHandler();
this.setStyleValue(value);
}
};
// attr.style.value
CSSStyleDeclaration.prototype.addStyleValueHandler = function () {
Object.defineProperty(this.parentNode.attributes, 'style', {
get: this.getStyleValue.bind(this),
set: this.setStyleValue.bind(this),
enumerable: true,
configurable: true,
});
};
CSSStyleDeclaration.prototype.getStyleValue = function () {
return this.getCssText();
};
CSSStyleDeclaration.prototype.setStyleValue = function (newValue) {
this.properties.clear(); // reset all existing properties
this.styleValue = newValue;
this.hasSynced = false; // raw css changed
};
CSSStyleDeclaration.prototype._loadCssText = function () {
if (this.hasSynced) {
return;
}
this.hasSynced = true; // must be set here to prevent loop in setProperty(...)
if (!this.styleValue || this.styleValue.length === 0) {
return;
}
var inlineCssStr = this.styleValue;
var declarations = {};
try {
declarations = csstree.parse(inlineCssStr, {
context: 'declarationList',
parseValue: false,
});
} catch (parseError) {
this.parseError = parseError;
return;
}
this.parseError = false;
var self = this;
declarations.children.each(function (declaration) {
try {
var styleDeclaration = csstools.csstreeToStyleDeclaration(declaration);
self.setProperty(
styleDeclaration.name,
styleDeclaration.value,
styleDeclaration.priority
);
} catch (styleError) {
if (styleError.message !== 'Unknown node type: undefined') {
self.parseError = styleError;
}
}
});
};
// only reads from properties
/**
* Get the textual representation of the declaration block (equivalent to .cssText attribute).
*
* @return {string} Textual representation of the declaration block (empty string for no properties)
*/
CSSStyleDeclaration.prototype.getCssText = function () {
var properties = this.getProperties();
if (this.parseError) {
// in case of a parse error, pass through original styles
return this.styleValue;
}
var cssText = [];
properties.forEach(function (property, propertyName) {
var strImportant = property.priority === 'important' ? '!important' : '';
cssText.push(
propertyName.trim() + ':' + property.value.trim() + strImportant
);
});
return cssText.join(';');
};
CSSStyleDeclaration.prototype._handleParseError = function () {
if (this.parseError) {
console.warn(
"Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr('style').value. Error details: " +
this.parseError
);
}
};
CSSStyleDeclaration.prototype._getProperty = function (propertyName) {
if (typeof propertyName === 'undefined') {
throw Error('1 argument required, but only 0 present.');
}
var properties = this.getProperties();
this._handleParseError();
var property = properties.get(propertyName.trim());
return property;
};
/**
* Return the optional priority, "important".
*
* @param {string} propertyName representing the property name to be checked.
* @return {string} priority that represents the priority (e.g. "important") if one exists. If none exists, returns the empty string.
*/
CSSStyleDeclaration.prototype.getPropertyPriority = function (propertyName) {
var property = this._getProperty(propertyName);
return property ? property.priority : '';
};
/**
* Return the property value given a property name.
*
* @param {string} propertyName representing the property name to be checked.
* @return {string} value containing the value of the property. If not set, returns the empty string.
*/
CSSStyleDeclaration.prototype.getPropertyValue = function (propertyName) {
var property = this._getProperty(propertyName);
return property ? property.value : null;
};
/**
* Return a property name.
*
* @param {number} index of the node to be fetched. The index is zero-based.
* @return {string} propertyName that is the name of the CSS property at the specified index.
*/
CSSStyleDeclaration.prototype.item = function (index) {
if (typeof index === 'undefined') {
throw Error('1 argument required, but only 0 present.');
}
var properties = this.getProperties();
this._handleParseError();
return Array.from(properties.keys())[index];
};
/**
* Return all properties of the node.
*
* @return {Map} properties that is a Map with propertyName as key and property (propertyValue + propertyPriority) as value.
*/
CSSStyleDeclaration.prototype.getProperties = function () {
this._loadCssText();
return this.properties;
};
// writes to properties
/**
* Remove a property from the CSS declaration block.
*
* @param {string} propertyName representing the property name to be removed.
* @return {string} oldValue equal to the value of the CSS property before it was removed.
*/
CSSStyleDeclaration.prototype.removeProperty = function (propertyName) {
if (typeof propertyName === 'undefined') {
throw Error('1 argument required, but only 0 present.');
}
this.addStyleValueHandler();
var properties = this.getProperties();
this._handleParseError();
var oldValue = this.getPropertyValue(propertyName);
properties.delete(propertyName.trim());
return oldValue;
};
/**
* Modify an existing CSS property or creates a new CSS property in the declaration block.
*
* @param {string} propertyName representing the CSS property name to be modified.
* @param {string} value containing the new property value. If not specified, treated as the empty string. value must not contain "!important" -- that should be set using the priority parameter.
* @param {string} priority allowing the "important" CSS priority to be set. If not specified, treated as the empty string.
* @return {{value: string, priority: string}}
*/
CSSStyleDeclaration.prototype.setProperty = function (
propertyName,
value,
priority
) {
if (typeof propertyName === 'undefined') {
throw Error('propertyName argument required, but only not present.');
}
this.addStyleValueHandler();
var properties = this.getProperties();
this._handleParseError();
var property = {
value: value.trim(),
priority: priority.trim(),
};
properties.set(propertyName.trim(), property);
return property;
};
module.exports = CSSStyleDeclaration;

344
node_modules/svgo/lib/svgo/js2svg.js generated vendored
View File

@@ -1,344 +0,0 @@
'use strict';
var EXTEND = require('whet.extend'),
textElem = require('../../plugins/_collections.js').elemsGroups.textContent.concat('title');
var defaults = {
doctypeStart: '<!DOCTYPE',
doctypeEnd: '>',
procInstStart: '<?',
procInstEnd: '?>',
tagOpenStart: '<',
tagOpenEnd: '>',
tagCloseStart: '</',
tagCloseEnd: '>',
tagShortStart: '<',
tagShortEnd: '/>',
attrStart: '="',
attrEnd: '"',
commentStart: '<!--',
commentEnd: '-->',
cdataStart: '<![CDATA[',
cdataEnd: ']]>',
textStart: '',
textEnd: '',
indent: 4,
regEntities: /[&'"<>]/g,
regValEntities: /[&"<>]/g,
encodeEntity: encodeEntity,
pretty: false,
useShortTags: true
};
var entities = {
'&': '&amp;',
'\'': '&apos;',
'"': '&quot;',
'>': '&gt;',
'<': '&lt;',
};
/**
* Convert SVG-as-JS object to SVG (XML) string.
*
* @param {Object} data input data
* @param {Object} config config
*
* @return {Object} output data
*/
module.exports = function(data, config) {
return new JS2SVG(config).convert(data);
};
function JS2SVG(config) {
if (config) {
this.config = EXTEND(true, {}, defaults, config);
} else {
this.config = defaults;
}
var indent = this.config.indent;
if (typeof indent == 'number' && !isNaN(indent)) {
this.config.indent = '';
for (var i = indent; i-- > 0;) this.config.indent += ' ';
} else if (typeof indent != 'string') {
this.config.indent = ' ';
}
if (this.config.pretty) {
this.config.doctypeEnd += '\n';
this.config.procInstEnd += '\n';
this.config.commentEnd += '\n';
this.config.cdataEnd += '\n';
this.config.tagShortEnd += '\n';
this.config.tagOpenEnd += '\n';
this.config.tagCloseEnd += '\n';
this.config.textEnd += '\n';
}
this.indentLevel = 0;
this.textContext = null;
}
function encodeEntity(char) {
return entities[char];
}
/**
* Start conversion.
*
* @param {Object} data input data
*
* @return {String}
*/
JS2SVG.prototype.convert = function(data) {
var svg = '';
if (data.content) {
this.indentLevel++;
data.content.forEach(function(item) {
if (item.elem) {
svg += this.createElem(item);
} else if (item.text) {
svg += this.createText(item.text);
} else if (item.doctype) {
svg += this.createDoctype(item.doctype);
} else if (item.processinginstruction) {
svg += this.createProcInst(item.processinginstruction);
} else if (item.comment) {
svg += this.createComment(item.comment);
} else if (item.cdata) {
svg += this.createCDATA(item.cdata);
}
}, this);
}
this.indentLevel--;
return {
data: svg,
info: {
width: this.width,
height: this.height
}
};
};
/**
* Create indent string in accordance with the current node level.
*
* @return {String}
*/
JS2SVG.prototype.createIndent = function() {
var indent = '';
if (this.config.pretty && !this.textContext) {
for (var i = 1; i < this.indentLevel; i++) {
indent += this.config.indent;
}
}
return indent;
};
/**
* Create doctype tag.
*
* @param {String} doctype doctype body string
*
* @return {String}
*/
JS2SVG.prototype.createDoctype = function(doctype) {
return this.config.doctypeStart +
doctype +
this.config.doctypeEnd;
};
/**
* Create XML Processing Instruction tag.
*
* @param {Object} instruction instruction object
*
* @return {String}
*/
JS2SVG.prototype.createProcInst = function(instruction) {
return this.config.procInstStart +
instruction.name +
' ' +
instruction.body +
this.config.procInstEnd;
};
/**
* Create comment tag.
*
* @param {String} comment comment body
*
* @return {String}
*/
JS2SVG.prototype.createComment = function(comment) {
return this.config.commentStart +
comment +
this.config.commentEnd;
};
/**
* Create CDATA section.
*
* @param {String} cdata CDATA body
*
* @return {String}
*/
JS2SVG.prototype.createCDATA = function(cdata) {
return this.createIndent() +
this.config.cdataStart +
cdata +
this.config.cdataEnd;
};
/**
* Create element tag.
*
* @param {Object} data element object
*
* @return {String}
*/
JS2SVG.prototype.createElem = function(data) {
// beautiful injection for obtaining SVG information :)
if (
data.isElem('svg') &&
data.hasAttr('width') &&
data.hasAttr('height')
) {
this.width = data.attr('width').value;
this.height = data.attr('height').value;
}
// empty element and short tag
if (data.isEmpty()) {
if (this.config.useShortTags) {
return this.createIndent() +
this.config.tagShortStart +
data.elem +
this.createAttrs(data) +
this.config.tagShortEnd;
} else {
return this.createIndent() +
this.config.tagShortStart +
data.elem +
this.createAttrs(data) +
this.config.tagOpenEnd +
this.config.tagCloseStart +
data.elem +
this.config.tagCloseEnd;
}
// non-empty element
} else {
var tagOpenStart = this.config.tagOpenStart,
tagOpenEnd = this.config.tagOpenEnd,
tagCloseStart = this.config.tagCloseStart,
tagCloseEnd = this.config.tagCloseEnd,
openIndent = this.createIndent(),
textIndent = '',
processedData = '',
dataEnd = '';
if (this.textContext) {
tagOpenStart = defaults.tagOpenStart;
tagOpenEnd = defaults.tagOpenEnd;
tagCloseStart = defaults.tagCloseStart;
tagCloseEnd = defaults.tagCloseEnd;
openIndent = '';
} else if (data.isElem(textElem)) {
if (this.config.pretty) {
textIndent += openIndent + this.config.indent;
}
this.textContext = data;
}
processedData += this.convert(data).data;
if (this.textContext == data) {
this.textContext = null;
if (this.config.pretty) dataEnd = '\n';
}
return openIndent +
tagOpenStart +
data.elem +
this.createAttrs(data) +
tagOpenEnd +
textIndent +
processedData +
dataEnd +
this.createIndent() +
tagCloseStart +
data.elem +
tagCloseEnd;
}
};
/**
* Create element attributes.
*
* @param {Object} elem attributes object
*
* @return {String}
*/
JS2SVG.prototype.createAttrs = function(elem) {
var attrs = '';
elem.eachAttr(function(attr) {
attrs += ' ' +
attr.name +
this.config.attrStart +
String(attr.value).replace(this.config.regValEntities, this.config.encodeEntity) +
this.config.attrEnd;
}, this);
return attrs;
};
/**
* Create text node.
*
* @param {String} text text
*
* @return {String}
*/
JS2SVG.prototype.createText = function(text) {
return this.createIndent() +
this.config.textStart +
text.replace(this.config.regEntities, this.config.encodeEntity) +
(this.textContext ? '' : this.config.textEnd);
};

2
node_modules/svgo/lib/svgo/jsAPI.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare let obj: any;
export = obj;

470
node_modules/svgo/lib/svgo/jsAPI.js generated vendored
View File

@@ -1,50 +1,126 @@
'use strict';
var EXTEND = require('whet.extend');
const { selectAll, selectOne, is } = require('css-select');
const svgoCssSelectAdapter = require('./css-select-adapter');
const CSSClassList = require('./css-class-list');
const CSSStyleDeclaration = require('./css-style-declaration');
var JSAPI = module.exports = function(data, parentNode) {
EXTEND(this, data);
if (parentNode) {
Object.defineProperty(this, 'parentNode', {
writable: true,
value: parentNode
});
}
/**
* @type {(name: string) => { prefix: string, local: string }}
*/
const parseName = (name) => {
if (name == null) {
return {
prefix: '',
local: '',
};
}
if (name === 'xmlns') {
return {
prefix: 'xmlns',
local: '',
};
}
const chunks = name.split(':');
if (chunks.length === 1) {
return {
prefix: '',
local: chunks[0],
};
}
return {
prefix: chunks[0],
local: chunks[1],
};
};
var cssSelectOpts = {
xmlMode: true,
adapter: svgoCssSelectAdapter,
};
const attrsHandler = {
get: (attributes, name) => {
// eslint-disable-next-line no-prototype-builtins
if (attributes.hasOwnProperty(name)) {
return {
name,
get value() {
return attributes[name];
},
set value(value) {
attributes[name] = value;
},
};
}
},
set: (attributes, name, attr) => {
attributes[name] = attr.value;
return true;
},
};
var JSAPI = function (data, parentNode) {
Object.assign(this, data);
if (this.type === 'element') {
if (this.attributes == null) {
this.attributes = {};
}
if (this.children == null) {
this.children = [];
}
Object.defineProperty(this, 'class', {
writable: true,
configurable: true,
value: new CSSClassList(this),
});
Object.defineProperty(this, 'style', {
writable: true,
configurable: true,
value: new CSSStyleDeclaration(this),
});
Object.defineProperty(this, 'parentNode', {
writable: true,
value: parentNode,
});
// temporary attrs polyfill
// TODO remove after migration
const element = this;
Object.defineProperty(this, 'attrs', {
configurable: true,
get() {
return new Proxy(element.attributes, attrsHandler);
},
set(value) {
const newAttributes = {};
for (const attr of Object.values(value)) {
newAttributes[attr.name] = attr.value;
}
element.attributes = newAttributes;
},
});
}
};
module.exports = JSAPI;
/**
* Perform a deep clone of this node.
*
* @return {Object} element
*/
JSAPI.prototype.clone = function() {
var node = this;
var nodeData = {};
Object.keys(node).forEach(function(key) {
if (key !== 'content') {
nodeData[key] = node[key];
}
JSAPI.prototype.clone = function () {
const { children, ...nodeData } = this;
// Deep-clone node data.
const clonedNode = new JSAPI(JSON.parse(JSON.stringify(nodeData)), null);
if (children) {
clonedNode.children = children.map((child) => {
const clonedChild = child.clone();
clonedChild.parentNode = clonedNode;
return clonedChild;
});
// Deep-clone node data
// This is still faster than using EXTEND(true…)
nodeData = JSON.parse(JSON.stringify(nodeData));
// parentNode gets set to a proper object by the parent clone,
// but it needs to be true/false now to do the right thing
// in the constructor.
var clonedNode = new JSAPI(nodeData, !!node.parentNode);
if (node.content) {
clonedNode.content = node.content.map(function(childNode) {
var clonedChild = childNode.clone();
clonedChild.parentNode = clonedNode;
return clonedChild;
});
}
return clonedNode;
}
return clonedNode;
};
/**
@@ -54,14 +130,17 @@ JSAPI.prototype.clone = function() {
* @param {String|Array} [param] element name or names arrays
* @return {Boolean}
*/
JSAPI.prototype.isElem = function(param) {
if (!param) return !!this.elem;
if (Array.isArray(param)) return !!this.elem && (param.indexOf(this.elem) > -1);
return !!this.elem && this.elem === param;
JSAPI.prototype.isElem = function (param) {
if (this.type !== 'element') {
return false;
}
if (param == null) {
return true;
}
if (Array.isArray(param)) {
return param.includes(this.name);
}
return this.name === param;
};
/**
@@ -70,13 +149,10 @@ JSAPI.prototype.isElem = function(param) {
* @param {String} name new element name
* @return {Object} element
*/
JSAPI.prototype.renameElem = function(name) {
if (name && typeof name === 'string')
this.elem = this.local = name;
return this;
JSAPI.prototype.renameElem = function (name) {
if (name && typeof name === 'string') this.name = name;
return this;
};
/**
@@ -84,32 +160,46 @@ JSAPI.prototype.renameElem = function(name) {
*
* @return {Boolean}
*/
JSAPI.prototype.isEmpty = function() {
return !this.content || !this.content.length;
JSAPI.prototype.isEmpty = function () {
return !this.children || !this.children.length;
};
/**
* Changes content by removing elements and/or adding new elements.
* Find the closest ancestor of the current element.
* @param elemName
*
* @param {Number} start Index at which to start changing the content.
* @return {?Object}
*/
JSAPI.prototype.closestElem = function (elemName) {
var elem = this;
while ((elem = elem.parentNode) && !elem.isElem(elemName));
return elem;
};
/**
* Changes children by removing elements and/or adding new elements.
*
* @param {Number} start Index at which to start changing the children.
* @param {Number} n Number of elements to remove.
* @param {Array|Object} [insertion] Elements to add to the content.
* @param {Array|Object} [insertion] Elements to add to the children.
* @return {Array} Removed elements.
*/
JSAPI.prototype.spliceContent = function(start, n, insertion) {
JSAPI.prototype.spliceContent = function (start, n, insertion) {
if (arguments.length < 2) return [];
if (arguments.length < 2) return [];
if (!Array.isArray(insertion))
insertion = Array.apply(null, arguments).slice(2);
insertion.forEach(function(inner) { inner.parentNode = this }, this);
return this.content.splice.apply(this.content, [start, n].concat(insertion));
if (!Array.isArray(insertion))
insertion = Array.apply(null, arguments).slice(2);
insertion.forEach(function (inner) {
inner.parentNode = this;
}, this);
return this.children.splice.apply(
this.children,
[start, n].concat(insertion)
);
};
/**
@@ -120,16 +210,24 @@ JSAPI.prototype.renameElem = function(name) {
* @param {String} [val] attribute value (will be toString()'ed)
* @return {Boolean}
*/
JSAPI.prototype.hasAttr = function(name, val) {
if (!this.attrs || !Object.keys(this.attrs).length) return false;
if (!arguments.length) return !!this.attrs;
if (val !== undefined) return !!this.attrs[name] && this.attrs[name].value === val.toString();
return !!this.attrs[name];
JSAPI.prototype.hasAttr = function (name, val) {
if (this.type !== 'element') {
return false;
}
if (Object.keys(this.attributes).length === 0) {
return false;
}
if (name == null) {
return true;
}
// eslint-disable-next-line no-prototype-builtins
if (this.attributes.hasOwnProperty(name) === false) {
return false;
}
if (val !== undefined) {
return this.attributes[name] === val.toString();
}
return true;
};
/**
@@ -140,39 +238,48 @@ JSAPI.prototype.renameElem = function(name) {
* @param {Number|String|RegExp|Function} [val] attribute value (will be toString()'ed or executed, otherwise ignored)
* @return {Boolean}
*/
JSAPI.prototype.hasAttrLocal = function(localName, val) {
JSAPI.prototype.hasAttrLocal = function (localName, val) {
if (!this.attrs || !Object.keys(this.attrs).length) return false;
if (!this.attrs || !Object.keys(this.attrs).length) return false;
if (!arguments.length) return !!this.attrs;
if (!arguments.length) return !!this.attrs;
var callback;
var callback;
switch (val != null && val.constructor && val.constructor.name) {
case 'Number': // same as String
case 'String':
callback = stringValueTest;
break;
case 'RegExp':
callback = regexpValueTest;
break;
case 'Function':
callback = funcValueTest;
break;
default:
callback = nameTest;
}
return this.someAttr(callback);
switch (val != null && val.constructor && val.constructor.name) {
case 'Number': // same as String
case 'String': callback = stringValueTest; break;
case 'RegExp': callback = regexpValueTest; break;
case 'Function': callback = funcValueTest; break;
default: callback = nameTest;
}
return this.someAttr(callback);
function nameTest(attr) {
const { local } = parseName(attr.name);
return local === localName;
}
function nameTest(attr) {
return attr.local === localName;
}
function stringValueTest(attr) {
const { local } = parseName(attr.name);
return local === localName && val == attr.value;
}
function stringValueTest(attr) {
return attr.local === localName && val == attr.value;
}
function regexpValueTest(attr) {
return attr.local === localName && val.test(attr.value);
}
function funcValueTest(attr) {
return attr.local === localName && val(attr.value);
}
function regexpValueTest(attr) {
const { local } = parseName(attr.name);
return local === localName && val.test(attr.value);
}
function funcValueTest(attr) {
const { local } = parseName(attr.name);
return local === localName && val(attr.value);
}
};
/**
@@ -183,14 +290,10 @@ JSAPI.prototype.renameElem = function(name) {
* @param {String} [val] attribute value (will be toString()'ed)
* @return {Object|Undefined}
*/
JSAPI.prototype.attr = function(name, val) {
if (!this.hasAttr() || !arguments.length) return undefined;
if (val !== undefined) return this.hasAttr(name, val) ? this.attrs[name] : undefined;
JSAPI.prototype.attr = function (name, val) {
if (this.hasAttr(name, val)) {
return this.attrs[name];
}
};
/**
@@ -199,18 +302,20 @@ JSAPI.prototype.renameElem = function(name) {
* @param {String} name attribute name
* @return {Object|Undefined}
*/
JSAPI.prototype.computedAttr = function(name, val) {
/* jshint eqnull: true */
if (!arguments.length) return;
JSAPI.prototype.computedAttr = function (name, val) {
if (!arguments.length) return;
for (var elem = this; elem && (!elem.hasAttr(name) || !elem.attr(name).value); elem = elem.parentNode);
if (val != null) {
return elem ? elem.hasAttr(name, val) : false;
} else if (elem && elem.hasAttr(name)) {
return elem.attrs[name].value;
}
for (
var elem = this;
elem && (!elem.hasAttr(name) || !elem.attributes[name]);
elem = elem.parentNode
);
if (val != null) {
return elem ? elem.hasAttr(name, val) : false;
} else if (elem && elem.hasAttr(name)) {
return elem.attributes[name];
}
};
/**
@@ -220,22 +325,24 @@ JSAPI.prototype.renameElem = function(name) {
* @param {String} [val] attribute value
* @return {Boolean}
*/
JSAPI.prototype.removeAttr = function(name, val, recursive) {
if (!arguments.length) return false;
if (Array.isArray(name)) name.forEach(this.removeAttr, this);
if (!this.hasAttr(name)) return false;
if (!recursive && val && this.attrs[name].value !== val) return false;
delete this.attrs[name];
if (!Object.keys(this.attrs).length) delete this.attrs;
return true;
JSAPI.prototype.removeAttr = function (name, val) {
if (this.type !== 'element') {
return false;
}
if (arguments.length === 0) {
return false;
}
if (Array.isArray(name)) {
for (const nameItem of name) {
this.removeAttr(nameItem, val);
}
return false;
}
if (this.hasAttr(name, val) === false) {
return false;
}
delete this.attributes[name];
return true;
};
/**
@@ -244,20 +351,24 @@ JSAPI.prototype.renameElem = function(name) {
* @param {Object} [attr={}] attribute object
* @return {Object|Boolean} created attribute or false if no attr was passed in
*/
JSAPI.prototype.addAttr = function(attr) {
attr = attr || {};
JSAPI.prototype.addAttr = function (attr) {
attr = attr || {};
if (attr.name === undefined ||
attr.value === undefined ||
attr.prefix === undefined ||
attr.local === undefined
) return false;
if (attr.name === undefined) return false;
this.attrs = this.attrs || {};
this.attrs[attr.name] = attr;
this.attributes[attr.name] = attr.value;
return this.attrs[attr.name];
if (attr.name === 'class') {
// newly added class attribute
this.class.addClassValueHandler();
}
if (attr.name === 'style') {
// newly added style attribute
this.style.addStyleValueHandler();
}
return this.attrs[attr.name];
};
/**
@@ -267,16 +378,17 @@ JSAPI.prototype.renameElem = function(name) {
* @param {Object} [context] callback context
* @return {Boolean} false if there are no any attributes
*/
JSAPI.prototype.eachAttr = function(callback, context) {
if (!this.hasAttr()) return false;
for (var name in this.attrs) {
callback.call(context, this.attrs[name]);
}
return true;
JSAPI.prototype.eachAttr = function (callback, context) {
if (this.type !== 'element') {
return false;
}
if (callback == null) {
return false;
}
for (const attr of Object.values(this.attrs)) {
callback.call(context, attr);
}
return true;
};
/**
@@ -286,14 +398,46 @@ JSAPI.prototype.renameElem = function(name) {
* @param {Object} [context] callback context
* @return {Boolean} false if there are no any attributes
*/
JSAPI.prototype.someAttr = function(callback, context) {
if (!this.hasAttr()) return false;
for (var name in this.attrs) {
if (callback.call(context, this.attrs[name])) return true;
}
JSAPI.prototype.someAttr = function (callback, context) {
if (this.type !== 'element') {
return false;
}
for (const attr of Object.values(this.attrs)) {
if (callback.call(context, attr)) return true;
}
return false;
};
/**
* Evaluate a string of CSS selectors against the element and returns matched elements.
*
* @param {String} selectors CSS selector(s) string
* @return {Array} null if no elements matched
*/
JSAPI.prototype.querySelectorAll = function (selectors) {
var matchedEls = selectAll(selectors, this, cssSelectOpts);
return matchedEls.length > 0 ? matchedEls : null;
};
/**
* Evaluate a string of CSS selectors against the element and returns only the first matched element.
*
* @param {String} selectors CSS selector(s) string
* @return {Array} null if no element matched
*/
JSAPI.prototype.querySelector = function (selectors) {
return selectOne(selectors, this, cssSelectOpts);
};
/**
* Test if a selector matches a given element.
*
* @param {String} selector CSS selector string
* @return {Boolean} true if element would be selected by selector string, false if it does not
*/
JSAPI.prototype.matches = function (selector) {
return is(this, selector, cssSelectOpts);
};

165
node_modules/svgo/lib/svgo/plugins.js generated vendored
View File

@@ -1,98 +1,109 @@
'use strict';
const { visit } = require('../xast.js');
/**
* Plugins engine.
*
* @module plugins
*
* @param {Object} data input data
* @param {Object} plugins plugins object from config
* @return {Object} output data
* @param {Object} ast input ast
* @param {Object} info extra information
* @param {Array} plugins plugins object from config
* @return {Object} output ast
*/
module.exports = function(data, plugins) {
const invokePlugins = (ast, info, plugins, overrides, globalOverrides) => {
for (const plugin of plugins) {
const override = overrides == null ? null : overrides[plugin.name];
if (override === false) {
continue;
}
const params = { ...plugin.params, ...globalOverrides, ...override };
plugins.forEach(function(group) {
switch(group[0].type) {
case 'perItem':
data = perItem(data, group);
break;
case 'perItemReverse':
data = perItem(data, group, true);
break;
case 'full':
data = full(data, group);
break;
if (plugin.type === 'perItem') {
ast = perItem(ast, info, plugin, params);
}
if (plugin.type === 'perItemReverse') {
ast = perItem(ast, info, plugin, params, true);
}
if (plugin.type === 'full') {
if (plugin.active) {
ast = plugin.fn(ast, params, info);
}
}
if (plugin.type === 'visitor') {
if (plugin.active) {
const visitor = plugin.fn(ast, params, info);
if (visitor != null) {
visit(ast, visitor);
}
});
return data;
}
}
}
return ast;
};
exports.invokePlugins = invokePlugins;
/**
* Direct or reverse per-item loop.
*
* @param {Object} data input data
* @param {Object} info extra information
* @param {Array} plugins plugins list to process
* @param {Boolean} [reverse] reverse pass?
* @param {boolean} [reverse] reverse pass?
* @return {Object} output data
*/
function perItem(data, plugins, reverse) {
function monkeys(items) {
items.content = items.content.filter(function(item) {
// reverse pass
if (reverse && item.content) {
monkeys(item);
}
// main filter
var filter = true;
for (var i = 0; filter && i < plugins.length; i++) {
var plugin = plugins[i];
if (plugin.active && plugin.fn(item, plugin.params) === false) {
filter = false;
}
}
// direct pass
if (!reverse && item.content) {
monkeys(item);
}
return filter;
});
return items;
}
return monkeys(data);
}
/**
* "Full" plugins.
*
* @param {Object} data input data
* @param {Array} plugins plugins list to process
* @return {Object} output data
*/
function full(data, plugins) {
plugins.forEach(function(plugin) {
if (plugin.active) {
data = plugin.fn(data, plugin.params);
}
function perItem(data, info, plugin, params, reverse) {
function monkeys(items) {
items.children = items.children.filter(function (item) {
// reverse pass
if (reverse && item.children) {
monkeys(item);
}
// main filter
let kept = true;
if (plugin.active) {
kept = plugin.fn(item, params, info) !== false;
}
// direct pass
if (!reverse && item.children) {
monkeys(item);
}
return kept;
});
return data;
return items;
}
return monkeys(data);
}
const createPreset = ({ name, plugins }) => {
return {
name,
type: 'full',
fn: (ast, params, info) => {
const { floatPrecision, overrides } = params;
const globalOverrides = {};
if (floatPrecision != null) {
globalOverrides.floatPrecision = floatPrecision;
}
if (overrides) {
for (const [pluginName, override] of Object.entries(overrides)) {
if (override === true) {
console.warn(
`You are trying to enable ${pluginName} which is not part of preset.\n` +
`Try to put it before or after preset, for example\n\n` +
`plugins: [\n` +
` {\n` +
` name: 'preset-default',\n` +
` },\n` +
` 'cleanupListOfValues'\n` +
`]\n`
);
}
}
}
return invokePlugins(ast, info, plugins, overrides, globalOverrides);
},
};
};
exports.createPreset = createPreset;

187
node_modules/svgo/lib/svgo/svg2js.js generated vendored
View File

@@ -1,187 +0,0 @@
'use strict';
var SAX = require('sax'),
JSAPI = require('./jsAPI.js'),
entityDeclaration = /<!ENTITY\s+(\S+)\s+(?:'([^\']+)'|"([^\"]+)")\s*>/g;
var config = {
strict: true,
trim: false,
normalize: true,
lowercase: true,
xmlns: true,
position: true
};
/**
* Convert SVG (XML) string to SVG-as-JS object.
*
* @param {String} data input data
* @param {Function} callback
*/
module.exports = function(data, callback) {
var sax = SAX.parser(config.strict, config),
root = new JSAPI({ elem: '#document' }),
current = root,
stack = [root],
textContext = null,
parsingError = false;
function pushToContent(content) {
content = new JSAPI(content, current);
(current.content = current.content || []).push(content);
return content;
}
sax.ondoctype = function(doctype) {
pushToContent({
doctype: doctype
});
var subsetStart = doctype.indexOf('['),
entityMatch;
if (subsetStart >= 0) {
entityDeclaration.lastIndex = subsetStart;
while ((entityMatch = entityDeclaration.exec(data)) != null) {
sax.ENTITIES[entityMatch[1]] = entityMatch[2] || entityMatch[3];
}
}
};
sax.onprocessinginstruction = function(data) {
pushToContent({
processinginstruction: data
});
};
sax.oncomment = function(comment) {
pushToContent({
comment: comment.trim()
});
};
sax.oncdata = function(cdata) {
pushToContent({
cdata: cdata
});
};
sax.onopentag = function(data) {
var elem = {
elem: data.name,
prefix: data.prefix,
local: data.local
};
if (Object.keys(data.attributes).length) {
elem.attrs = {};
for (var name in data.attributes) {
elem.attrs[name] = {
name: name,
value: data.attributes[name].value,
prefix: data.attributes[name].prefix,
local: data.attributes[name].local
};
}
}
elem = pushToContent(elem);
current = elem;
// Save info about <text> tag to prevent trimming of meaningful whitespace
if (data.name == 'text' && !data.prefix) {
textContext = current;
}
stack.push(elem);
};
sax.ontext = function(text) {
if (/\S/.test(text) || textContext) {
if (!textContext)
text = text.trim();
pushToContent({
text: text
});
}
};
sax.onclosetag = function() {
var last = stack.pop();
// Trim text inside <text> tag.
if (last == textContext) {
trim(textContext);
textContext = null;
}
current = stack[stack.length - 1];
};
sax.onerror = function(e) {
e.message = 'Error in parsing SVG: ' + e.message;
if (e.message.indexOf('Unexpected end') < 0) {
throw e;
}
};
sax.onend = function() {
if (!this.error) {
callback(root);
} else {
callback({ error: this.error.message });
}
};
try {
sax.write(data);
} catch (e) {
callback({ error: e.message });
parsingError = true;
}
if (!parsingError) sax.close();
function trim(elem) {
if (!elem.content) return elem;
var start = elem.content[0],
end = elem.content[elem.content.length - 1];
while (start && start.content && !start.text) start = start.content[0];
if (start && start.text) start.text = start.text.replace(/^\s+/, '');
while (end && end.content && !end.text) end = end.content[end.content.length - 1];
if (end && end.text) end.text = end.text.replace(/\s+$/, '');
return elem;
}
};

203
node_modules/svgo/lib/svgo/tools.js generated vendored
View File

@@ -1,123 +1,116 @@
'use strict';
/**
* @typedef {import('../types').PathDataCommand} PathDataCommand
*/
/**
* Encode plain SVG data string into Data URI string.
*
* @param {String} str input string
* @param {String} type Data URI type
* @return {String} output string
* @type {(str: string, type?: 'base64' | 'enc' | 'unenc') => string}
*/
exports.encodeSVGDatauri = function(str, type) {
var prefix = 'data:image/svg+xml';
exports.encodeSVGDatauri = (str, type) => {
var prefix = 'data:image/svg+xml';
if (!type || type === 'base64') {
// base64
if (!type || type === 'base64') {
prefix += ';base64,';
str = prefix + new Buffer(str).toString('base64');
prefix += ';base64,';
str = prefix + Buffer.from(str).toString('base64');
} else if (type === 'enc') {
// URI encoded
} else if (type === 'enc') {
str = prefix + ',' + encodeURIComponent(str);
str = prefix + ',' + encodeURIComponent(str);
} else if (type === 'unenc') {
// unencoded
} else if (type === 'unenc') {
str = prefix + ',' + str;
}
return str;
str = prefix + ',' + str;
}
return str;
};
/**
* Decode SVG Data URI string into plain SVG string.
*
* @param {string} str input string
* @return {String} output string
* @type {(str: string) => string}
*/
exports.decodeSVGDatauri = function(str) {
var regexp = /data:image\/svg\+xml(;charset=[^;,]*)?(;base64)?,(.*)/;
var match = regexp.exec(str);
exports.decodeSVGDatauri = (str) => {
var regexp = /data:image\/svg\+xml(;charset=[^;,]*)?(;base64)?,(.*)/;
var match = regexp.exec(str);
// plain string
if (!match) return str;
// plain string
if (!match) return str;
var data = match[3];
var data = match[3];
if (match[2]) {
// base64
if (match[2]) {
str = new Buffer(data, 'base64').toString('utf8');
str = Buffer.from(data, 'base64').toString('utf8');
} else if (data.charAt(0) === '%') {
// URI encoded
} else if (data.charAt(0) === '%') {
str = decodeURIComponent(data);
str = decodeURIComponent(data);
} else if (data.charAt(0) === '<') {
// unencoded
} else if (data.charAt(0) === '<') {
str = data;
}
return str;
};
str = data;
/**
* @typedef {{
* noSpaceAfterFlags?: boolean,
* leadingZero?: boolean,
* negativeExtraSpace?: boolean
* }} CleanupOutDataParams
*/
/**
* Convert a row of numbers to an optimized string view.
*
* @example
* [0, -1, .5, .5] → "0-1 .5.5"
*
* @type {(data: Array<number>, params: CleanupOutDataParams, command?: PathDataCommand) => string}
*/
exports.cleanupOutData = (data, params, command) => {
let str = '';
let delimiter;
/**
* @type {number}
*/
let prev;
data.forEach((item, i) => {
// space delimiter by default
delimiter = ' ';
// no extra space in front of first number
if (i == 0) delimiter = '';
// no extra space after 'arcto' command flags(large-arc and sweep flags)
// a20 60 45 0 1 30 20 → a20 60 45 0130 20
if (params.noSpaceAfterFlags && (command == 'A' || command == 'a')) {
var pos = i % 7;
if (pos == 4 || pos == 5) delimiter = '';
}
return str;
};
exports.intersectArrays = function(a, b) {
return a.filter(function(n) {
return b.indexOf(n) > -1;
});
};
exports.cleanupOutData = function(data, params) {
var str = '',
delimiter,
prev;
data.forEach(function(item, i) {
// space delimiter by default
delimiter = ' ';
// no extra space in front of first number
if (i === 0) {
delimiter = '';
}
// remove floating-point numbers leading zeros
// 0.5 → .5
// -0.5 → -.5
if (params.leadingZero) {
item = removeLeadingZero(item);
}
// no extra space in front of negative number or
// in front of a floating number if a previous number is floating too
if (
params.negativeExtraSpace &&
(item < 0 ||
(/^\./.test(item) && prev % 1 !== 0)
)
) {
delimiter = '';
}
// save prev item value
prev = item;
str += delimiter + item;
});
return str;
// remove floating-point numbers leading zeros
// 0.5 → .5
// -0.5 → -.5
const itemStr = params.leadingZero
? removeLeadingZero(item)
: item.toString();
// no extra space in front of negative number or
// in front of a floating number if a previous number is floating too
if (
params.negativeExtraSpace &&
delimiter != '' &&
(item < 0 || (itemStr.charAt(0) === '.' && prev % 1 !== 0))
) {
delimiter = '';
}
// save prev item value
prev = item;
str += delimiter + itemStr;
});
return str;
};
/**
@@ -129,18 +122,16 @@ exports.cleanupOutData = function(data, params) {
* @example
* -0.5 → -.5
*
* @param {Float} num input number
*
* @return {String} output number as string
* @type {(num: number) => string}
*/
var removeLeadingZero = exports.removeLeadingZero = function(num) {
if (num > 0 && num < 1) {
num = ('' + num).slice(1);
} else if (num < 0 && num > -1) {
num = '-' + ('' + num).slice(2);
}
return num;
const removeLeadingZero = (num) => {
var strNum = num.toString();
if (0 < num && num < 1 && strNum.charAt(0) === '0') {
strNum = strNum.slice(1);
} else if (-1 < num && num < 0 && strNum.charAt(1) === '0') {
strNum = strNum.charAt(0) + strNum.slice(2);
}
return strNum;
};
exports.removeLeadingZero = removeLeadingZero;

172
node_modules/svgo/lib/types.ts generated vendored Normal file
View File

@@ -0,0 +1,172 @@
export type XastDoctype = {
type: 'doctype';
name: string;
data: {
doctype: string;
};
};
export type XastInstruction = {
type: 'instruction';
name: string;
value: string;
};
export type XastComment = {
type: 'comment';
value: string;
};
export type XastCdata = {
type: 'cdata';
value: string;
};
export type XastText = {
type: 'text';
value: string;
};
export type XastElement = {
type: 'element';
name: string;
attributes: Record<string, string>;
children: Array<XastChild>;
};
export type XastChild =
| XastDoctype
| XastInstruction
| XastComment
| XastCdata
| XastText
| XastElement;
export type XastRoot = {
type: 'root';
children: Array<XastChild>;
};
export type XastParent = XastRoot | XastElement;
export type XastNode = XastRoot | XastChild;
export type StringifyOptions = {
doctypeStart?: string;
doctypeEnd?: string;
procInstStart?: string;
procInstEnd?: string;
tagOpenStart?: string;
tagOpenEnd?: string;
tagCloseStart?: string;
tagCloseEnd?: string;
tagShortStart?: string;
tagShortEnd?: string;
attrStart?: string;
attrEnd?: string;
commentStart?: string;
commentEnd?: string;
cdataStart?: string;
cdataEnd?: string;
textStart?: string;
textEnd?: string;
indent?: number | string;
regEntities?: RegExp;
regValEntities?: RegExp;
encodeEntity?: (char: string) => string;
pretty?: boolean;
useShortTags?: boolean;
eol?: 'lf' | 'crlf';
finalNewline?: boolean;
};
type VisitorNode<Node> = {
enter?: (node: Node, parentNode: XastParent) => void | symbol;
exit?: (node: Node, parentNode: XastParent) => void;
};
type VisitorRoot = {
enter?: (node: XastRoot, parentNode: null) => void;
exit?: (node: XastRoot, parentNode: null) => void;
};
export type Visitor = {
doctype?: VisitorNode<XastDoctype>;
instruction?: VisitorNode<XastInstruction>;
comment?: VisitorNode<XastComment>;
cdata?: VisitorNode<XastCdata>;
text?: VisitorNode<XastText>;
element?: VisitorNode<XastElement>;
root?: VisitorRoot;
};
export type PluginInfo = {
path?: string;
multipassCount: number;
};
export type Plugin<Params> = (
root: XastRoot,
params: Params,
info: PluginInfo
) => null | Visitor;
export type Specificity = [number, number, number, number];
export type StylesheetDeclaration = {
name: string;
value: string;
important: boolean;
};
export type StylesheetRule = {
dynamic: boolean;
selectors: string;
specificity: Specificity;
declarations: Array<StylesheetDeclaration>;
};
export type Stylesheet = {
rules: Array<StylesheetRule>;
parents: Map<XastElement, XastParent>;
};
type StaticStyle = {
type: 'static';
inherited: boolean;
value: string;
};
type DynamicStyle = {
type: 'dynamic';
inherited: boolean;
};
export type ComputedStyles = Record<string, StaticStyle | DynamicStyle>;
export type PathDataCommand =
| 'M'
| 'm'
| 'Z'
| 'z'
| 'L'
| 'l'
| 'H'
| 'h'
| 'V'
| 'v'
| 'C'
| 'c'
| 'S'
| 's'
| 'Q'
| 'q'
| 'T'
| 't'
| 'A'
| 'a';
export type PathDataItem = {
command: PathDataCommand;
args: Array<number>;
};

102
node_modules/svgo/lib/xast.js generated vendored Normal file
View File

@@ -0,0 +1,102 @@
'use strict';
/**
* @typedef {import('./types').XastNode} XastNode
* @typedef {import('./types').XastChild} XastChild
* @typedef {import('./types').XastParent} XastParent
* @typedef {import('./types').Visitor} Visitor
*/
const { selectAll, selectOne, is } = require('css-select');
const xastAdaptor = require('./svgo/css-select-adapter.js');
const cssSelectOptions = {
xmlMode: true,
adapter: xastAdaptor,
};
/**
* @type {(node: XastNode, selector: string) => Array<XastChild>}
*/
const querySelectorAll = (node, selector) => {
return selectAll(selector, node, cssSelectOptions);
};
exports.querySelectorAll = querySelectorAll;
/**
* @type {(node: XastNode, selector: string) => null | XastChild}
*/
const querySelector = (node, selector) => {
return selectOne(selector, node, cssSelectOptions);
};
exports.querySelector = querySelector;
/**
* @type {(node: XastChild, selector: string) => boolean}
*/
const matches = (node, selector) => {
return is(node, selector, cssSelectOptions);
};
exports.matches = matches;
/**
* @type {(node: XastChild, name: string) => null | XastChild}
*/
const closestByName = (node, name) => {
let currentNode = node;
while (currentNode) {
if (currentNode.type === 'element' && currentNode.name === name) {
return currentNode;
}
// @ts-ignore parentNode is hidden from public usage
currentNode = currentNode.parentNode;
}
return null;
};
exports.closestByName = closestByName;
const visitSkip = Symbol();
exports.visitSkip = visitSkip;
/**
* @type {(node: XastNode, visitor: Visitor, parentNode?: any) => void}
*/
const visit = (node, visitor, parentNode) => {
const callbacks = visitor[node.type];
if (callbacks && callbacks.enter) {
// @ts-ignore hard to infer
const symbol = callbacks.enter(node, parentNode);
if (symbol === visitSkip) {
return;
}
}
// visit root children
if (node.type === 'root') {
// copy children array to not loose cursor when children is spliced
for (const child of node.children) {
visit(child, visitor, node);
}
}
// visit element children if still attached to parent
if (node.type === 'element') {
if (parentNode.children.includes(node)) {
for (const child of node.children) {
visit(child, visitor, node);
}
}
}
if (callbacks && callbacks.exit) {
// @ts-ignore hard to infer
callbacks.exit(node, parentNode);
}
};
exports.visit = visit;
/**
* @type {(node: XastChild, parentNode: XastParent) => void}
*/
const detachNodeFromParent = (node, parentNode) => {
// avoid splice to not break for loops
parentNode.children = parentNode.children.filter((child) => child !== node);
};
exports.detachNodeFromParent = detachNodeFromParent;