mirror of
https://github.com/svg/svgo.git
synced 2025-07-31 07:44:22 +03:00
Refactor svg stringifier (#1593)
- rewrote prototype class with functions - covered with tsdoc - added a few TODOs for v3
This commit is contained in:
@ -1,8 +1,44 @@
|
|||||||
'use strict';
|
'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');
|
const { textElems } = require('../plugins/_collections.js');
|
||||||
|
|
||||||
var defaults = {
|
/**
|
||||||
|
* @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',
|
doctypeStart: '<!DOCTYPE',
|
||||||
doctypeEnd: '>',
|
doctypeEnd: '>',
|
||||||
procInstStart: '<?',
|
procInstStart: '<?',
|
||||||
@ -31,7 +67,10 @@ var defaults = {
|
|||||||
finalNewline: false,
|
finalNewline: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
var entities = {
|
/**
|
||||||
|
* @type {Record<string, string>}
|
||||||
|
*/
|
||||||
|
const entities = {
|
||||||
'&': '&',
|
'&': '&',
|
||||||
"'": ''',
|
"'": ''',
|
||||||
'"': '"',
|
'"': '"',
|
||||||
@ -40,278 +79,233 @@ var entities = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert SVG-as-JS object to SVG (XML) string.
|
* convert XAST to SVG string
|
||||||
*
|
*
|
||||||
* @param {Object} data input data
|
* @type {(data: XastRoot, config: StringifyOptions) => {
|
||||||
* @param {Object} config config
|
* data: string,
|
||||||
*
|
* info: {
|
||||||
* @return {Object} output data
|
* width: void | string,
|
||||||
|
* height: void | string
|
||||||
|
* }
|
||||||
|
* }}
|
||||||
*/
|
*/
|
||||||
module.exports = function (data, config) {
|
const stringifySvg = (data, userOptions = {}) => {
|
||||||
return new JS2SVG(config).convert(data);
|
/**
|
||||||
};
|
* @type {Options}
|
||||||
|
*/
|
||||||
function JS2SVG(config) {
|
const config = { ...defaults, ...userOptions };
|
||||||
if (config) {
|
const indent = config.indent;
|
||||||
this.config = Object.assign({}, defaults, config);
|
let newIndent = ' ';
|
||||||
} else {
|
if (typeof indent === 'number' && Number.isNaN(indent) === false) {
|
||||||
this.config = Object.assign({}, defaults);
|
newIndent = indent < 0 ? '\t' : ' '.repeat(indent);
|
||||||
|
} else if (typeof indent === 'string') {
|
||||||
|
newIndent = indent;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
var indent = this.config.indent;
|
* @type {State}
|
||||||
if (typeof indent == 'number' && !isNaN(indent)) {
|
*/
|
||||||
this.config.indent = indent < 0 ? '\t' : ' '.repeat(indent);
|
const state = {
|
||||||
} else if (typeof indent != 'string') {
|
// TODO remove width and height in v3
|
||||||
this.config.indent = ' ';
|
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 (this.config.eol === 'crlf') {
|
if (config.finalNewline && svg.length > 0 && svg[svg.length - 1] !== '\n') {
|
||||||
this.eol = '\r\n';
|
svg += eol;
|
||||||
} else {
|
|
||||||
this.eol = '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.config.pretty) {
|
|
||||||
this.config.doctypeEnd += this.eol;
|
|
||||||
this.config.procInstEnd += this.eol;
|
|
||||||
this.config.commentEnd += this.eol;
|
|
||||||
this.config.cdataEnd += this.eol;
|
|
||||||
this.config.tagShortEnd += this.eol;
|
|
||||||
this.config.tagOpenEnd += this.eol;
|
|
||||||
this.config.tagCloseEnd += this.eol;
|
|
||||||
this.config.textEnd += this.eol;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = '';
|
|
||||||
|
|
||||||
this.indentLevel++;
|
|
||||||
|
|
||||||
for (const item of data.children) {
|
|
||||||
if (item.type === 'element') {
|
|
||||||
svg += this.createElem(item);
|
|
||||||
}
|
|
||||||
if (item.type === 'text') {
|
|
||||||
svg += this.createText(item);
|
|
||||||
}
|
|
||||||
if (item.type === 'doctype') {
|
|
||||||
svg += this.createDoctype(item);
|
|
||||||
}
|
|
||||||
if (item.type === 'instruction') {
|
|
||||||
svg += this.createProcInst(item);
|
|
||||||
}
|
|
||||||
if (item.type === 'comment') {
|
|
||||||
svg += this.createComment(item);
|
|
||||||
}
|
|
||||||
if (item.type === 'cdata') {
|
|
||||||
svg += this.createCDATA(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.indentLevel--;
|
|
||||||
|
|
||||||
if (
|
|
||||||
this.config.finalNewline &&
|
|
||||||
this.indentLevel === 0 &&
|
|
||||||
svg.length > 0 &&
|
|
||||||
svg[svg.length - 1] !== '\n'
|
|
||||||
) {
|
|
||||||
svg += this.eol;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: svg,
|
data: svg,
|
||||||
info: {
|
info: {
|
||||||
width: this.width,
|
width: state.width,
|
||||||
height: this.height,
|
height: state.height,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
exports.stringifySvg = stringifySvg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create indent string in accordance with the current node level.
|
* @type {(node: XastParent, config: Options, state: State) => string}
|
||||||
*
|
|
||||||
* @return {String}
|
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createIndent = function () {
|
const stringifyNode = (data, config, state) => {
|
||||||
var indent = '';
|
let svg = '';
|
||||||
|
state.indentLevel += 1;
|
||||||
if (this.config.pretty && !this.textContext) {
|
for (const item of data.children) {
|
||||||
indent = this.config.indent.repeat(this.indentLevel - 1);
|
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;
|
return indent;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create doctype tag.
|
* @type {(node: XastDoctype, config: Options) => string}
|
||||||
*
|
|
||||||
* @param {String} doctype doctype body string
|
|
||||||
*
|
|
||||||
* @return {String}
|
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createDoctype = function (node) {
|
const stringifyDoctype = (node, config) => {
|
||||||
const { doctype } = node.data;
|
return config.doctypeStart + node.data.doctype + config.doctypeEnd;
|
||||||
return this.config.doctypeStart + doctype + this.config.doctypeEnd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create XML Processing Instruction tag.
|
* @type {(node: XastInstruction, config: Options) => string}
|
||||||
*
|
|
||||||
* @param {Object} instruction instruction object
|
|
||||||
*
|
|
||||||
* @return {String}
|
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createProcInst = function (node) {
|
const stringifyInstruction = (node, config) => {
|
||||||
const { name, value } = node;
|
|
||||||
return (
|
return (
|
||||||
this.config.procInstStart + name + ' ' + value + this.config.procInstEnd
|
config.procInstStart + node.name + ' ' + node.value + config.procInstEnd
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create comment tag.
|
* @type {(node: XastComment, config: Options) => string}
|
||||||
*
|
|
||||||
* @param {String} comment comment body
|
|
||||||
*
|
|
||||||
* @return {String}
|
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createComment = function (node) {
|
const stringifyComment = (node, config) => {
|
||||||
const { value } = node;
|
return config.commentStart + node.value + config.commentEnd;
|
||||||
return this.config.commentStart + value + this.config.commentEnd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create CDATA section.
|
* @type {(node: XastCdata, config: Options, state: State) => string}
|
||||||
*
|
|
||||||
* @param {String} cdata CDATA body
|
|
||||||
*
|
|
||||||
* @return {String}
|
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createCDATA = function (node) {
|
const stringifyCdata = (node, config, state) => {
|
||||||
const { value } = node;
|
|
||||||
return (
|
return (
|
||||||
this.createIndent() + this.config.cdataStart + value + this.config.cdataEnd
|
createIndent(config, state) +
|
||||||
|
config.cdataStart +
|
||||||
|
node.value +
|
||||||
|
config.cdataEnd
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create element tag.
|
* @type {(node: XastElement, config: Options, state: State) => string}
|
||||||
*
|
|
||||||
* @param {Object} data element object
|
|
||||||
*
|
|
||||||
* @return {String}
|
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createElem = function (data) {
|
const stringifyElement = (node, config, state) => {
|
||||||
// beautiful injection for obtaining SVG information :)
|
// beautiful injection for obtaining SVG information :)
|
||||||
if (
|
if (
|
||||||
data.name === 'svg' &&
|
node.name === 'svg' &&
|
||||||
data.attributes.width != null &&
|
node.attributes.width != null &&
|
||||||
data.attributes.height != null
|
node.attributes.height != null
|
||||||
) {
|
) {
|
||||||
this.width = data.attributes.width;
|
state.width = node.attributes.width;
|
||||||
this.height = data.attributes.height;
|
state.height = node.attributes.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
// empty element and short tag
|
// empty element and short tag
|
||||||
if (data.children.length === 0) {
|
if (node.children.length === 0) {
|
||||||
if (this.config.useShortTags) {
|
if (config.useShortTags) {
|
||||||
return (
|
return (
|
||||||
this.createIndent() +
|
createIndent(config, state) +
|
||||||
this.config.tagShortStart +
|
config.tagShortStart +
|
||||||
data.name +
|
node.name +
|
||||||
this.createAttrs(data) +
|
stringifyAttributes(node, config) +
|
||||||
this.config.tagShortEnd
|
config.tagShortEnd
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
this.createIndent() +
|
createIndent(config, state) +
|
||||||
this.config.tagShortStart +
|
config.tagShortStart +
|
||||||
data.name +
|
node.name +
|
||||||
this.createAttrs(data) +
|
stringifyAttributes(node, config) +
|
||||||
this.config.tagOpenEnd +
|
config.tagOpenEnd +
|
||||||
this.config.tagCloseStart +
|
config.tagCloseStart +
|
||||||
data.name +
|
node.name +
|
||||||
this.config.tagCloseEnd
|
config.tagCloseEnd
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// non-empty element
|
// non-empty element
|
||||||
} else {
|
} else {
|
||||||
var tagOpenStart = this.config.tagOpenStart,
|
let tagOpenStart = config.tagOpenStart;
|
||||||
tagOpenEnd = this.config.tagOpenEnd,
|
let tagOpenEnd = config.tagOpenEnd;
|
||||||
tagCloseStart = this.config.tagCloseStart,
|
let tagCloseStart = config.tagCloseStart;
|
||||||
tagCloseEnd = this.config.tagCloseEnd,
|
let tagCloseEnd = config.tagCloseEnd;
|
||||||
openIndent = this.createIndent(),
|
let openIndent = createIndent(config, state);
|
||||||
closeIndent = this.createIndent(),
|
let closeIndent = createIndent(config, state);
|
||||||
processedData = '',
|
|
||||||
dataEnd = '';
|
|
||||||
|
|
||||||
if (this.textContext) {
|
if (state.textContext) {
|
||||||
tagOpenStart = defaults.tagOpenStart;
|
tagOpenStart = defaults.tagOpenStart;
|
||||||
tagOpenEnd = defaults.tagOpenEnd;
|
tagOpenEnd = defaults.tagOpenEnd;
|
||||||
tagCloseStart = defaults.tagCloseStart;
|
tagCloseStart = defaults.tagCloseStart;
|
||||||
tagCloseEnd = defaults.tagCloseEnd;
|
tagCloseEnd = defaults.tagCloseEnd;
|
||||||
openIndent = '';
|
openIndent = '';
|
||||||
} else if (data.isElem(textElems)) {
|
} else if (textElems.includes(node.name)) {
|
||||||
tagOpenEnd = defaults.tagOpenEnd;
|
tagOpenEnd = defaults.tagOpenEnd;
|
||||||
tagCloseStart = defaults.tagCloseStart;
|
tagCloseStart = defaults.tagCloseStart;
|
||||||
closeIndent = '';
|
closeIndent = '';
|
||||||
this.textContext = data;
|
state.textContext = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
processedData += this.convert(data).data;
|
const children = stringifyNode(node, config, state);
|
||||||
|
|
||||||
if (this.textContext == data) {
|
if (state.textContext === node) {
|
||||||
this.textContext = null;
|
state.textContext = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
openIndent +
|
openIndent +
|
||||||
tagOpenStart +
|
tagOpenStart +
|
||||||
data.name +
|
node.name +
|
||||||
this.createAttrs(data) +
|
stringifyAttributes(node, config) +
|
||||||
tagOpenEnd +
|
tagOpenEnd +
|
||||||
processedData +
|
children +
|
||||||
dataEnd +
|
|
||||||
closeIndent +
|
closeIndent +
|
||||||
tagCloseStart +
|
tagCloseStart +
|
||||||
data.name +
|
node.name +
|
||||||
tagCloseEnd
|
tagCloseEnd
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create element attributes.
|
* @type {(node: XastElement, config: Options) => string}
|
||||||
*
|
|
||||||
* @param {Object} elem attributes object
|
|
||||||
*
|
|
||||||
* @return {String}
|
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createAttrs = function (element) {
|
const stringifyAttributes = (node, config) => {
|
||||||
let attrs = '';
|
let attrs = '';
|
||||||
for (const [name, value] of Object.entries(element.attributes)) {
|
for (const [name, value] of Object.entries(node.attributes)) {
|
||||||
|
// TODO remove attributes without values support in v3
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
const encodedValue = value
|
const encodedValue = value
|
||||||
.toString()
|
.toString()
|
||||||
.replace(this.config.regValEntities, this.config.encodeEntity);
|
.replace(config.regValEntities, config.encodeEntity);
|
||||||
attrs +=
|
attrs += ' ' + name + config.attrStart + encodedValue + config.attrEnd;
|
||||||
' ' + name + this.config.attrStart + encodedValue + this.config.attrEnd;
|
|
||||||
} else {
|
} else {
|
||||||
attrs += ' ' + name;
|
attrs += ' ' + name;
|
||||||
}
|
}
|
||||||
@ -320,18 +314,13 @@ JS2SVG.prototype.createAttrs = function (element) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create text node.
|
* @type {(node: XastText, config: Options, state: State) => string}
|
||||||
*
|
|
||||||
* @param {String} text text
|
|
||||||
*
|
|
||||||
* @return {String}
|
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createText = function (node) {
|
const stringifyText = (node, config, state) => {
|
||||||
const { value } = node;
|
|
||||||
return (
|
return (
|
||||||
this.createIndent() +
|
createIndent(config, state) +
|
||||||
this.config.textStart +
|
config.textStart +
|
||||||
value.replace(this.config.regEntities, this.config.encodeEntity) +
|
node.value.replace(config.regEntities, config.encodeEntity) +
|
||||||
(this.textContext ? '' : this.config.textEnd)
|
(state.textContext ? '' : config.textEnd)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@ const {
|
|||||||
extendDefaultPlugins,
|
extendDefaultPlugins,
|
||||||
} = require('./svgo/config.js');
|
} = require('./svgo/config.js');
|
||||||
const { parseSvg } = require('./parser.js');
|
const { parseSvg } = require('./parser.js');
|
||||||
const js2svg = require('./stringifier.js');
|
const { stringifySvg } = require('./stringifier.js');
|
||||||
const { invokePlugins } = require('./svgo/plugins.js');
|
const { invokePlugins } = require('./svgo/plugins.js');
|
||||||
const JSAPI = require('./svgo/jsAPI.js');
|
const JSAPI = require('./svgo/jsAPI.js');
|
||||||
const { encodeSVGDatauri } = require('./svgo/tools.js');
|
const { encodeSVGDatauri } = require('./svgo/tools.js');
|
||||||
@ -53,10 +53,7 @@ const optimize = (input, config) => {
|
|||||||
globalOverrides.floatPrecision = config.floatPrecision;
|
globalOverrides.floatPrecision = config.floatPrecision;
|
||||||
}
|
}
|
||||||
svgjs = invokePlugins(svgjs, info, resolvedPlugins, null, globalOverrides);
|
svgjs = invokePlugins(svgjs, info, resolvedPlugins, null, globalOverrides);
|
||||||
svgjs = js2svg(svgjs, config.js2svg);
|
svgjs = stringifySvg(svgjs, config.js2svg);
|
||||||
if (svgjs.error) {
|
|
||||||
throw Error(svgjs.error);
|
|
||||||
}
|
|
||||||
if (svgjs.data.length < prevResultSize) {
|
if (svgjs.data.length < prevResultSize) {
|
||||||
input = svgjs.data;
|
input = svgjs.data;
|
||||||
prevResultSize = svgjs.data.length;
|
prevResultSize = svgjs.data.length;
|
||||||
|
29
lib/types.ts
29
lib/types.ts
@ -51,6 +51,35 @@ export type XastParent = XastRoot | XastElement;
|
|||||||
|
|
||||||
export type XastNode = XastRoot | XastChild;
|
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> = {
|
type VisitorNode<Node> = {
|
||||||
enter?: (node: Node, parentNode: XastParent) => void | symbol;
|
enter?: (node: Node, parentNode: XastParent) => void | symbol;
|
||||||
exit?: (node: Node, parentNode: XastParent) => void;
|
exit?: (node: Node, parentNode: XastParent) => void;
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "NODE_OPTIONS=--experimental-vm-modules jest --maxWorkers=3 --coverage",
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest --maxWorkers=4 --coverage",
|
||||||
"lint": "eslint --ignore-path .gitignore . && prettier --check \"**/*.js\" --ignore-path .gitignore",
|
"lint": "eslint --ignore-path .gitignore . && prettier --check \"**/*.js\" --ignore-path .gitignore",
|
||||||
"fix": "eslint --ignore-path .gitignore --fix . && prettier --write \"**/*.js\" --ignore-path .gitignore",
|
"fix": "eslint --ignore-path .gitignore --fix . && prettier --write \"**/*.js\" --ignore-path .gitignore",
|
||||||
"typecheck": "tsc",
|
"typecheck": "tsc",
|
||||||
|
@ -10,14 +10,17 @@
|
|||||||
"resolveJsonModule": true
|
"resolveJsonModule": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
"lib/**/*.js",
|
||||||
"plugins/**/*",
|
"plugins/**/*",
|
||||||
"lib/svg-parser.js",
|
|
||||||
"lib/xast.test.js",
|
|
||||||
"lib/path.test.js",
|
|
||||||
"lib/style.test.js",
|
|
||||||
"test/cli/**/*"
|
"test/cli/**/*"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
"lib/svgo-node.js",
|
||||||
|
"lib/svgo-node.test.js",
|
||||||
|
"lib/svgo.js",
|
||||||
|
"lib/svgo.test.js",
|
||||||
|
"lib/svgo/**/*.js",
|
||||||
|
"lib/css-tools.js",
|
||||||
"plugins/_applyTransforms.js",
|
"plugins/_applyTransforms.js",
|
||||||
"plugins/convertPathData.js",
|
"plugins/convertPathData.js",
|
||||||
"plugins/convertStyleToAttrs.js",
|
"plugins/convertStyleToAttrs.js",
|
||||||
|
Reference in New Issue
Block a user