mirror of
https://github.com/svg/svgo.git
synced 2025-08-07 15:22:54 +03:00
@@ -5,7 +5,6 @@ var csstree = require('css-tree'),
|
|||||||
stable = require('stable'),
|
stable = require('stable'),
|
||||||
specificity = require('csso/lib/restructure/prepare/specificity');
|
specificity = require('csso/lib/restructure/prepare/specificity');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flatten a CSS AST to a selectors list.
|
* Flatten a CSS AST to a selectors list.
|
||||||
*
|
*
|
||||||
@@ -15,7 +14,9 @@ var csstree = require('css-tree'),
|
|||||||
function flattenToSelectors(cssAst) {
|
function flattenToSelectors(cssAst) {
|
||||||
var selectors = [];
|
var selectors = [];
|
||||||
|
|
||||||
csstree.walk(cssAst, {visit: 'Rule', enter: function(node) {
|
csstree.walk(cssAst, {
|
||||||
|
visit: 'Rule',
|
||||||
|
enter: function (node) {
|
||||||
if (node.type !== 'Rule') {
|
if (node.type !== 'Rule') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -28,22 +29,29 @@ function flattenToSelectors(cssAst) {
|
|||||||
item: selectorItem,
|
item: selectorItem,
|
||||||
atrule: atrule,
|
atrule: atrule,
|
||||||
rule: rule,
|
rule: rule,
|
||||||
pseudos: []
|
pseudos: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
selectorNode.children.each(function(selectorChildNode, selectorChildItem, selectorChildList) {
|
selectorNode.children.each(function (
|
||||||
if (selectorChildNode.type === 'PseudoClassSelector' ||
|
selectorChildNode,
|
||||||
selectorChildNode.type === 'PseudoElementSelector') {
|
selectorChildItem,
|
||||||
|
selectorChildList
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
selectorChildNode.type === 'PseudoClassSelector' ||
|
||||||
|
selectorChildNode.type === 'PseudoElementSelector'
|
||||||
|
) {
|
||||||
selector.pseudos.push({
|
selector.pseudos.push({
|
||||||
item: selectorChildItem,
|
item: selectorChildItem,
|
||||||
list: selectorChildList
|
list: selectorChildList,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
selectors.push(selector);
|
selectors.push(selector);
|
||||||
});
|
});
|
||||||
}});
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return selectors;
|
return selectors;
|
||||||
}
|
}
|
||||||
@@ -63,8 +71,10 @@ function filterByMqs(selectors, useMqs) {
|
|||||||
|
|
||||||
var mqName = selector.atrule.name;
|
var mqName = selector.atrule.name;
|
||||||
var mqStr = mqName;
|
var mqStr = mqName;
|
||||||
if (selector.atrule.expression &&
|
if (
|
||||||
selector.atrule.expression.children.first().type === 'MediaQueryList') {
|
selector.atrule.expression &&
|
||||||
|
selector.atrule.expression.children.first().type === 'MediaQueryList'
|
||||||
|
) {
|
||||||
var mqExpr = csstree.generate(selector.atrule.expression);
|
var mqExpr = csstree.generate(selector.atrule.expression);
|
||||||
mqStr = [mqName, mqExpr].join(' ');
|
mqStr = [mqName, mqExpr].join(' ');
|
||||||
}
|
}
|
||||||
@@ -84,9 +94,11 @@ function filterByPseudos(selectors, usePseudos) {
|
|||||||
return selectors.filter(function (selector) {
|
return selectors.filter(function (selector) {
|
||||||
var pseudoSelectorsStr = csstree.generate({
|
var pseudoSelectorsStr = csstree.generate({
|
||||||
type: 'Selector',
|
type: 'Selector',
|
||||||
children: new List().fromArray(selector.pseudos.map(function(pseudo) {
|
children: new List().fromArray(
|
||||||
|
selector.pseudos.map(function (pseudo) {
|
||||||
return pseudo.item.data;
|
return pseudo.item.data;
|
||||||
}))
|
})
|
||||||
|
),
|
||||||
});
|
});
|
||||||
return ~usePseudos.indexOf(pseudoSelectorsStr);
|
return ~usePseudos.indexOf(pseudoSelectorsStr);
|
||||||
});
|
});
|
||||||
@@ -106,7 +118,6 @@ function cleanPseudos(selectors) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares two selector specificities.
|
* Compares two selector specificities.
|
||||||
* extracted from https://github.com/keeganstreet/specificity/blob/master/specificity.js#L211
|
* extracted from https://github.com/keeganstreet/specificity/blob/master/specificity.js#L211
|
||||||
@@ -127,7 +138,6 @@ function compareSpecificity(aSpecificity, bSpecificity) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare two simple selectors.
|
* Compare two simple selectors.
|
||||||
*
|
*
|
||||||
@@ -145,7 +155,6 @@ function _bySelectorSpecificity(selectorA, selectorB) {
|
|||||||
return compareSimpleSelectorNode(selectorA.item.data, selectorB.item.data);
|
return compareSimpleSelectorNode(selectorA.item.data, selectorB.item.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort selectors stably by their specificity.
|
* Sort selectors stably by their specificity.
|
||||||
*
|
*
|
||||||
@@ -156,7 +165,6 @@ function sortSelectors(selectors) {
|
|||||||
return stable(selectors, _bySelectorSpecificity);
|
return stable(selectors, _bySelectorSpecificity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a css-tree AST style declaration to CSSStyleDeclaration property.
|
* Convert a css-tree AST style declaration to CSSStyleDeclaration property.
|
||||||
*
|
*
|
||||||
@@ -166,15 +174,14 @@ function sortSelectors(selectors) {
|
|||||||
function csstreeToStyleDeclaration(declaration) {
|
function csstreeToStyleDeclaration(declaration) {
|
||||||
var propertyName = declaration.property,
|
var propertyName = declaration.property,
|
||||||
propertyValue = csstree.generate(declaration.value),
|
propertyValue = csstree.generate(declaration.value),
|
||||||
propertyPriority = (declaration.important ? 'important' : '');
|
propertyPriority = declaration.important ? 'important' : '';
|
||||||
return {
|
return {
|
||||||
name: propertyName,
|
name: propertyName,
|
||||||
value: propertyValue,
|
value: propertyValue,
|
||||||
priority: propertyPriority
|
priority: propertyPriority,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the CSS string of a style element
|
* Gets the CSS string of a style element
|
||||||
*
|
*
|
||||||
@@ -204,7 +211,6 @@ function setCssStr(elem, css) {
|
|||||||
return elem.content[0].text;
|
return elem.content[0].text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports.flattenToSelectors = flattenToSelectors;
|
module.exports.flattenToSelectors = flattenToSelectors;
|
||||||
|
|
||||||
module.exports.filterByMqs = filterByMqs;
|
module.exports.filterByMqs = filterByMqs;
|
||||||
|
@@ -8,7 +8,7 @@ const {
|
|||||||
createContentItem,
|
createContentItem,
|
||||||
} = require('./svgo.js');
|
} = require('./svgo.js');
|
||||||
|
|
||||||
const importConfig = async configFile => {
|
const importConfig = async (configFile) => {
|
||||||
const config = require(configFile);
|
const config = require(configFile);
|
||||||
if (config == null || typeof config !== 'object' || Array.isArray(config)) {
|
if (config == null || typeof config !== 'object' || Array.isArray(config)) {
|
||||||
throw Error(`Invalid config file "${configFile}"`);
|
throw Error(`Invalid config file "${configFile}"`);
|
||||||
@@ -23,7 +23,7 @@ const isFile = async (file) => {
|
|||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const loadConfig = async (configFile, cwd = process.cwd()) => {
|
const loadConfig = async (configFile, cwd = process.cwd()) => {
|
||||||
if (configFile != null) {
|
if (configFile != null) {
|
||||||
@@ -36,7 +36,7 @@ const loadConfig = async (configFile, cwd = process.cwd()) => {
|
|||||||
let dir = cwd;
|
let dir = cwd;
|
||||||
// eslint-disable-next-line no-constant-condition
|
// eslint-disable-next-line no-constant-condition
|
||||||
while (true) {
|
while (true) {
|
||||||
const file = path.join(dir, "svgo.config.js");
|
const file = path.join(dir, 'svgo.config.js');
|
||||||
if (await isFile(file)) {
|
if (await isFile(file)) {
|
||||||
return await importConfig(file);
|
return await importConfig(file);
|
||||||
}
|
}
|
||||||
|
16
lib/svgo.js
16
lib/svgo.js
@@ -13,7 +13,7 @@
|
|||||||
const {
|
const {
|
||||||
defaultPlugins,
|
defaultPlugins,
|
||||||
resolvePluginConfig,
|
resolvePluginConfig,
|
||||||
extendDefaultPlugins
|
extendDefaultPlugins,
|
||||||
} = require('./svgo/config.js');
|
} = require('./svgo/config.js');
|
||||||
const svg2js = require('./svgo/svg2js.js');
|
const svg2js = require('./svgo/svg2js.js');
|
||||||
const js2svg = require('./svgo/js2svg.js');
|
const js2svg = require('./svgo/js2svg.js');
|
||||||
@@ -28,12 +28,12 @@ const optimize = (input, config) => {
|
|||||||
config = {};
|
config = {};
|
||||||
}
|
}
|
||||||
if (typeof config !== 'object') {
|
if (typeof config !== 'object') {
|
||||||
throw Error('Config should be an object')
|
throw Error('Config should be an object');
|
||||||
}
|
}
|
||||||
const maxPassCount = config.multipass ? 10 : 1;
|
const maxPassCount = config.multipass ? 10 : 1;
|
||||||
let prevResultSize = Number.POSITIVE_INFINITY;
|
let prevResultSize = Number.POSITIVE_INFINITY;
|
||||||
let svgjs = null;
|
let svgjs = null;
|
||||||
const info = {}
|
const info = {};
|
||||||
if (config.path != null) {
|
if (config.path != null) {
|
||||||
info.path = config.path;
|
info.path = config.path;
|
||||||
}
|
}
|
||||||
@@ -48,9 +48,13 @@ const optimize = (input, config) => {
|
|||||||
}
|
}
|
||||||
const plugins = config.plugins || defaultPlugins;
|
const plugins = config.plugins || defaultPlugins;
|
||||||
if (Array.isArray(plugins) === false) {
|
if (Array.isArray(plugins) === false) {
|
||||||
throw Error('Invalid plugins list. Provided \'plugins\' in config should be an array.');
|
throw Error(
|
||||||
|
"Invalid plugins list. Provided 'plugins' in config should be an array."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const resolvedPlugins = plugins.map(plugin => resolvePluginConfig(plugin, config))
|
const resolvedPlugins = plugins.map((plugin) =>
|
||||||
|
resolvePluginConfig(plugin, config)
|
||||||
|
);
|
||||||
svgjs = invokePlugins(svgjs, info, resolvedPlugins);
|
svgjs = invokePlugins(svgjs, info, resolvedPlugins);
|
||||||
svgjs = js2svg(svgjs, config.js2svg);
|
svgjs = js2svg(svgjs, config.js2svg);
|
||||||
if (svgjs.error) {
|
if (svgjs.error) {
|
||||||
@@ -58,7 +62,7 @@ const optimize = (input, config) => {
|
|||||||
}
|
}
|
||||||
if (svgjs.data.length < prevResultSize) {
|
if (svgjs.data.length < prevResultSize) {
|
||||||
input = svgjs.data;
|
input = svgjs.data;
|
||||||
prevResultSize = svgjs.data.length
|
prevResultSize = svgjs.data.length;
|
||||||
} else {
|
} else {
|
||||||
if (config.datauri) {
|
if (config.datauri) {
|
||||||
svgjs.data = encodeSVGDatauri(svgjs.data, config.datauri);
|
svgjs.data = encodeSVGDatauri(svgjs.data, config.datauri);
|
||||||
|
181
lib/svgo/coa.js
181
lib/svgo/coa.js
@@ -25,52 +25,83 @@ module.exports = function makeProgram(program) {
|
|||||||
program
|
program
|
||||||
.name(PKG.name)
|
.name(PKG.name)
|
||||||
.description(PKG.description, {
|
.description(PKG.description, {
|
||||||
INPUT: 'Alias to --input'
|
INPUT: 'Alias to --input',
|
||||||
})
|
})
|
||||||
.version(PKG.version, '-v, --version')
|
.version(PKG.version, '-v, --version')
|
||||||
.arguments('[INPUT...]')
|
.arguments('[INPUT...]')
|
||||||
.option('-i, --input <INPUT...>', 'Input files, "-" for STDIN')
|
.option('-i, --input <INPUT...>', 'Input files, "-" for STDIN')
|
||||||
.option('-s, --string <STRING>', 'Input SVG data string')
|
.option('-s, --string <STRING>', 'Input SVG data string')
|
||||||
.option('-f, --folder <FOLDER>', 'Input folder, optimize and rewrite all *.svg files')
|
.option(
|
||||||
.option('-o, --output <OUTPUT...>', 'Output file or folder (by default the same as the input), "-" for STDOUT')
|
'-f, --folder <FOLDER>',
|
||||||
.option('-p, --precision <INTEGER>', 'Set number of digits in the fractional part, overrides plugins params')
|
'Input folder, optimize and rewrite all *.svg files'
|
||||||
|
)
|
||||||
|
.option(
|
||||||
|
'-o, --output <OUTPUT...>',
|
||||||
|
'Output file or folder (by default the same as the input), "-" for STDOUT'
|
||||||
|
)
|
||||||
|
.option(
|
||||||
|
'-p, --precision <INTEGER>',
|
||||||
|
'Set number of digits in the fractional part, overrides plugins params'
|
||||||
|
)
|
||||||
.option('--config <CONFIG>', 'Custom config file, only .js is supported')
|
.option('--config <CONFIG>', 'Custom config file, only .js is supported')
|
||||||
.option('--datauri <FORMAT>', 'Output as Data URI string (base64), URI encoded (enc) or unencoded (unenc)')
|
.option(
|
||||||
.option('--multipass', 'Pass over SVGs multiple times to ensure all optimizations are applied')
|
'--datauri <FORMAT>',
|
||||||
|
'Output as Data URI string (base64), URI encoded (enc) or unencoded (unenc)'
|
||||||
|
)
|
||||||
|
.option(
|
||||||
|
'--multipass',
|
||||||
|
'Pass over SVGs multiple times to ensure all optimizations are applied'
|
||||||
|
)
|
||||||
.option('--pretty', 'Make SVG pretty printed')
|
.option('--pretty', 'Make SVG pretty printed')
|
||||||
.option('--indent <INTEGER>', 'Indent number when pretty printing SVGs')
|
.option('--indent <INTEGER>', 'Indent number when pretty printing SVGs')
|
||||||
.option('-r, --recursive', 'Use with \'-f\'. Optimizes *.svg files in folders recursively.')
|
.option(
|
||||||
.option('-q, --quiet', 'Only output error messages, not regular status messages')
|
'-r, --recursive',
|
||||||
|
"Use with '-f'. Optimizes *.svg files in folders recursively."
|
||||||
|
)
|
||||||
|
.option(
|
||||||
|
'-q, --quiet',
|
||||||
|
'Only output error messages, not regular status messages'
|
||||||
|
)
|
||||||
.option('--show-plugins', 'Show available plugins and exit')
|
.option('--show-plugins', 'Show available plugins and exit')
|
||||||
.action(action);
|
.action(action);
|
||||||
}
|
};
|
||||||
|
|
||||||
async function action(args, opts, command) {
|
async function action(args, opts, command) {
|
||||||
var input = opts.input || args;
|
var input = opts.input || args;
|
||||||
var output = opts.output;
|
var output = opts.output;
|
||||||
var config = {}
|
var config = {};
|
||||||
|
|
||||||
if (opts.precision != null) {
|
if (opts.precision != null) {
|
||||||
const number = Number.parseInt(opts.precision, 0);
|
const number = Number.parseInt(opts.precision, 0);
|
||||||
if (Number.isNaN(number)) {
|
if (Number.isNaN(number)) {
|
||||||
console.error("error: option '-p, --precision' argument must be an integer number");
|
console.error(
|
||||||
process.exit(1)
|
"error: option '-p, --precision' argument must be an integer number"
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
} else {
|
} else {
|
||||||
opts.precision = number;
|
opts.precision = number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.datauri != null) {
|
if (opts.datauri != null) {
|
||||||
if (opts.datauri !== 'base64' && opts.datauri !== 'enc' && opts.datauri !== 'unenc') {
|
if (
|
||||||
console.error("error: option '--datauri' must have one of the following values: 'base64', 'enc' or 'unenc'")
|
opts.datauri !== 'base64' &&
|
||||||
process.exit(1)
|
opts.datauri !== 'enc' &&
|
||||||
|
opts.datauri !== 'unenc'
|
||||||
|
) {
|
||||||
|
console.error(
|
||||||
|
"error: option '--datauri' must have one of the following values: 'base64', 'enc' or 'unenc'"
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.indent != null) {
|
if (opts.indent != null) {
|
||||||
const number = Number.parseInt(opts.indent, 0);
|
const number = Number.parseInt(opts.indent, 0);
|
||||||
if (Number.isNaN(number)) {
|
if (Number.isNaN(number)) {
|
||||||
console.error("error: option '--indent' argument must be an integer number");
|
console.error(
|
||||||
|
"error: option '--indent' argument must be an integer number"
|
||||||
|
);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
} else {
|
} else {
|
||||||
opts.indent = number;
|
opts.indent = number;
|
||||||
@@ -94,10 +125,18 @@ async function action(args, opts, command) {
|
|||||||
return command.help();
|
return command.help();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof process == 'object' && process.versions && process.versions.node && PKG && PKG.engines.node) {
|
if (
|
||||||
|
typeof process == 'object' &&
|
||||||
|
process.versions &&
|
||||||
|
process.versions.node &&
|
||||||
|
PKG &&
|
||||||
|
PKG.engines.node
|
||||||
|
) {
|
||||||
var nodeVersion = String(PKG.engines.node).match(/\d*(\.\d+)*/)[0];
|
var nodeVersion = String(PKG.engines.node).match(/\d*(\.\d+)*/)[0];
|
||||||
if (parseFloat(process.versions.node) < parseFloat(nodeVersion)) {
|
if (parseFloat(process.versions.node) < parseFloat(nodeVersion)) {
|
||||||
throw Error(`${PKG.name} requires Node.js version ${nodeVersion} or higher.`);
|
throw Error(
|
||||||
|
`${PKG.name} requires Node.js version ${nodeVersion} or higher.`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +182,9 @@ async function action(args, opts, command) {
|
|||||||
if (output.length == 1 && checkIsDir(output[0])) {
|
if (output.length == 1 && checkIsDir(output[0])) {
|
||||||
var dir = output[0];
|
var dir = output[0];
|
||||||
for (var i = 0; i < input.length; i++) {
|
for (var i = 0; i < input.length; i++) {
|
||||||
output[i] = checkIsDir(input[i]) ? input[i] : PATH.resolve(dir, PATH.basename(input[i]));
|
output[i] = checkIsDir(input[i])
|
||||||
|
? input[i]
|
||||||
|
: PATH.resolve(dir, PATH.basename(input[i]));
|
||||||
}
|
}
|
||||||
} else if (output.length < input.length) {
|
} else if (output.length < input.length) {
|
||||||
output = output.concat(input.slice(output.length));
|
output = output.concat(input.slice(output.length));
|
||||||
@@ -161,7 +202,7 @@ async function action(args, opts, command) {
|
|||||||
|
|
||||||
// --folder
|
// --folder
|
||||||
if (opts.folder) {
|
if (opts.folder) {
|
||||||
var ouputFolder = output && output[0] || opts.folder;
|
var ouputFolder = (output && output[0]) || opts.folder;
|
||||||
await optimizeFolder(config, opts.folder, ouputFolder);
|
await optimizeFolder(config, opts.folder, ouputFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,8 +215,13 @@ async function action(args, opts, command) {
|
|||||||
file = output[0];
|
file = output[0];
|
||||||
|
|
||||||
process.stdin
|
process.stdin
|
||||||
.on('data', chunk => data += chunk)
|
.on('data', (chunk) => (data += chunk))
|
||||||
.once('end', () => processSVGData(config, {input: 'string'}, data, file).then(resolve, reject));
|
.once('end', () =>
|
||||||
|
processSVGData(config, { input: 'string' }, data, file).then(
|
||||||
|
resolve,
|
||||||
|
reject
|
||||||
|
)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
// file
|
// file
|
||||||
} else {
|
} else {
|
||||||
@@ -203,7 +249,9 @@ function optimizeFolder(config, dir, output) {
|
|||||||
if (!config.quiet) {
|
if (!config.quiet) {
|
||||||
console.log(`Processing directory '${dir}':\n`);
|
console.log(`Processing directory '${dir}':\n`);
|
||||||
}
|
}
|
||||||
return FS.promises.readdir(dir).then(files => processDirectory(config, dir, files, output));
|
return FS.promises
|
||||||
|
.readdir(dir)
|
||||||
|
.then((files) => processDirectory(config, dir, files, output));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -218,9 +266,19 @@ function processDirectory(config, dir, files, output) {
|
|||||||
// take only *.svg files, recursively if necessary
|
// take only *.svg files, recursively if necessary
|
||||||
var svgFilesDescriptions = getFilesDescriptions(config, dir, files, output);
|
var svgFilesDescriptions = getFilesDescriptions(config, dir, files, output);
|
||||||
|
|
||||||
return svgFilesDescriptions.length ?
|
return svgFilesDescriptions.length
|
||||||
Promise.all(svgFilesDescriptions.map(fileDescription => optimizeFile(config, fileDescription.inputPath, fileDescription.outputPath))) :
|
? Promise.all(
|
||||||
Promise.reject(new Error(`No SVG files have been found in '${dir}' directory.`));
|
svgFilesDescriptions.map((fileDescription) =>
|
||||||
|
optimizeFile(
|
||||||
|
config,
|
||||||
|
fileDescription.inputPath,
|
||||||
|
fileDescription.outputPath
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: Promise.reject(
|
||||||
|
new Error(`No SVG files have been found in '${dir}' directory.`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -233,26 +291,31 @@ function processDirectory(config, dir, files, output) {
|
|||||||
*/
|
*/
|
||||||
function getFilesDescriptions(config, dir, files, output) {
|
function getFilesDescriptions(config, dir, files, output) {
|
||||||
const filesInThisFolder = files
|
const filesInThisFolder = files
|
||||||
.filter(name => regSVGFile.test(name))
|
.filter((name) => regSVGFile.test(name))
|
||||||
.map(name => ({
|
.map((name) => ({
|
||||||
inputPath: PATH.resolve(dir, name),
|
inputPath: PATH.resolve(dir, name),
|
||||||
outputPath: PATH.resolve(output, name),
|
outputPath: PATH.resolve(output, name),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return config.recursive ?
|
return config.recursive
|
||||||
[].concat(
|
? [].concat(
|
||||||
filesInThisFolder,
|
filesInThisFolder,
|
||||||
files
|
files
|
||||||
.filter(name => checkIsDir(PATH.resolve(dir, name)))
|
.filter((name) => checkIsDir(PATH.resolve(dir, name)))
|
||||||
.map(subFolderName => {
|
.map((subFolderName) => {
|
||||||
const subFolderPath = PATH.resolve(dir, subFolderName);
|
const subFolderPath = PATH.resolve(dir, subFolderName);
|
||||||
const subFolderFiles = FS.readdirSync(subFolderPath);
|
const subFolderFiles = FS.readdirSync(subFolderPath);
|
||||||
const subFolderOutput = PATH.resolve(output, subFolderName);
|
const subFolderOutput = PATH.resolve(output, subFolderName);
|
||||||
return getFilesDescriptions(config, subFolderPath, subFolderFiles, subFolderOutput);
|
return getFilesDescriptions(
|
||||||
|
config,
|
||||||
|
subFolderPath,
|
||||||
|
subFolderFiles,
|
||||||
|
subFolderOutput
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.reduce((a, b) => [].concat(a, b), [])
|
.reduce((a, b) => [].concat(a, b), [])
|
||||||
) :
|
)
|
||||||
filesInThisFolder;
|
: filesInThisFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -264,8 +327,9 @@ function getFilesDescriptions(config, dir, files, output) {
|
|||||||
*/
|
*/
|
||||||
function optimizeFile(config, file, output) {
|
function optimizeFile(config, file, output) {
|
||||||
return FS.promises.readFile(file, 'utf8').then(
|
return FS.promises.readFile(file, 'utf8').then(
|
||||||
data => processSVGData(config, {input: 'file', path: file}, data, output, file),
|
(data) =>
|
||||||
error => checkOptimizeFileError(config, file, output, error)
|
processSVGData(config, { input: 'file', path: file }, data, output, file),
|
||||||
|
(error) => checkOptimizeFileError(config, file, output, error)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,9 +349,9 @@ function processSVGData(config, info, data, output, input) {
|
|||||||
if (result.error) {
|
if (result.error) {
|
||||||
let message = result.error;
|
let message = result.error;
|
||||||
if (result.path != null) {
|
if (result.path != null) {
|
||||||
message += `\nFile: ${result.path}`
|
message += `\nFile: ${result.path}`;
|
||||||
}
|
}
|
||||||
throw Error(message)
|
throw Error(message);
|
||||||
}
|
}
|
||||||
if (config.datauri) {
|
if (config.datauri) {
|
||||||
result.data = encodeSVGDatauri(result.data, config.datauri);
|
result.data = encodeSVGDatauri(result.data, config.datauri);
|
||||||
@@ -295,7 +359,8 @@ function processSVGData(config, info, data, output, input) {
|
|||||||
var resultFileSize = Buffer.byteLength(result.data, 'utf8'),
|
var resultFileSize = Buffer.byteLength(result.data, 'utf8'),
|
||||||
processingTime = Date.now() - startTime;
|
processingTime = Date.now() - startTime;
|
||||||
|
|
||||||
return writeOutput(input, output, result.data).then(function() {
|
return writeOutput(input, output, result.data).then(
|
||||||
|
function () {
|
||||||
if (!config.quiet && output != '-') {
|
if (!config.quiet && output != '-') {
|
||||||
if (input) {
|
if (input) {
|
||||||
console.log(`\n${PATH.basename(input)}:`);
|
console.log(`\n${PATH.basename(input)}:`);
|
||||||
@@ -304,7 +369,15 @@ function processSVGData(config, info, data, output, input) {
|
|||||||
printProfitInfo(prevFileSize, resultFileSize);
|
printProfitInfo(prevFileSize, resultFileSize);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error => Promise.reject(new Error(error.code === 'ENOTDIR' ? `Error: output '${output}' is not a directory.` : error)));
|
(error) =>
|
||||||
|
Promise.reject(
|
||||||
|
new Error(
|
||||||
|
error.code === 'ENOTDIR'
|
||||||
|
? `Error: output '${output}' is not a directory.`
|
||||||
|
: error
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -322,10 +395,11 @@ function writeOutput(input, output, data) {
|
|||||||
|
|
||||||
FS.mkdirSync(PATH.dirname(output), { recursive: true });
|
FS.mkdirSync(PATH.dirname(output), { recursive: true });
|
||||||
|
|
||||||
return FS.promises.writeFile(output, data, 'utf8').catch(error => checkWriteFileError(input, output, data, error));
|
return FS.promises
|
||||||
|
.writeFile(output, data, 'utf8')
|
||||||
|
.catch((error) => checkWriteFileError(input, output, data, error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a time taken by optimization.
|
* Write a time taken by optimization.
|
||||||
* @param {number} time time in milliseconds.
|
* @param {number} time time in milliseconds.
|
||||||
@@ -340,13 +414,16 @@ function printTimeInfo(time) {
|
|||||||
* @param {number} outBytes size after optimization.
|
* @param {number} outBytes size after optimization.
|
||||||
*/
|
*/
|
||||||
function printProfitInfo(inBytes, outBytes) {
|
function printProfitInfo(inBytes, outBytes) {
|
||||||
var profitPercents = 100 - outBytes * 100 / inBytes;
|
var profitPercents = 100 - (outBytes * 100) / inBytes;
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
(Math.round((inBytes / 1024) * 1000) / 1000) + ' KiB' +
|
Math.round((inBytes / 1024) * 1000) / 1000 +
|
||||||
|
' KiB' +
|
||||||
(profitPercents < 0 ? ' + ' : ' - ') +
|
(profitPercents < 0 ? ' + ' : ' - ') +
|
||||||
chalk.green(Math.abs((Math.round(profitPercents * 10) / 10)) + '%') + ' = ' +
|
chalk.green(Math.abs(Math.round(profitPercents * 10) / 10) + '%') +
|
||||||
(Math.round((outBytes / 1024) * 1000) / 1000) + ' KiB'
|
' = ' +
|
||||||
|
Math.round((outBytes / 1024) * 1000) / 1000 +
|
||||||
|
' KiB'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +439,9 @@ function checkOptimizeFileError(config, input, output, error) {
|
|||||||
if (error.code == 'EISDIR') {
|
if (error.code == 'EISDIR') {
|
||||||
return optimizeFolder(config, input, output);
|
return optimizeFolder(config, input, output);
|
||||||
} else if (error.code == 'ENOENT') {
|
} else if (error.code == 'ENOENT') {
|
||||||
return Promise.reject(new Error(`Error: no such file or directory '${error.path}'.`));
|
return Promise.reject(
|
||||||
|
new Error(`Error: no such file or directory '${error.path}'.`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
@@ -377,7 +456,11 @@ function checkOptimizeFileError(config, input, output, error) {
|
|||||||
*/
|
*/
|
||||||
function checkWriteFileError(input, output, data, error) {
|
function checkWriteFileError(input, output, data, error) {
|
||||||
if (error.code == 'EISDIR' && input) {
|
if (error.code == 'EISDIR' && input) {
|
||||||
return FS.promises.writeFile(PATH.resolve(output, PATH.basename(input)), data, 'utf8');
|
return FS.promises.writeFile(
|
||||||
|
PATH.resolve(output, PATH.basename(input)),
|
||||||
|
data,
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
@@ -53,11 +53,14 @@ const pluginsOrder = [
|
|||||||
'removeOffCanvasPaths',
|
'removeOffCanvasPaths',
|
||||||
'reusePaths',
|
'reusePaths',
|
||||||
];
|
];
|
||||||
const defaultPlugins = pluginsOrder.filter(name => pluginsMap[name].active);
|
const defaultPlugins = pluginsOrder.filter((name) => pluginsMap[name].active);
|
||||||
exports.defaultPlugins = defaultPlugins;
|
exports.defaultPlugins = defaultPlugins;
|
||||||
|
|
||||||
const extendDefaultPlugins = (plugins) => {
|
const extendDefaultPlugins = (plugins) => {
|
||||||
const extendedPlugins = pluginsOrder.map(name => ({ name, ...pluginsMap[name] }));
|
const extendedPlugins = pluginsOrder.map((name) => ({
|
||||||
|
name,
|
||||||
|
...pluginsMap[name],
|
||||||
|
}));
|
||||||
for (const plugin of plugins) {
|
for (const plugin of plugins) {
|
||||||
const resolvedPlugin = resolvePluginConfig(plugin, {});
|
const resolvedPlugin = resolvePluginConfig(plugin, {});
|
||||||
const index = pluginsOrder.indexOf(resolvedPlugin.name);
|
const index = pluginsOrder.indexOf(resolvedPlugin.name);
|
||||||
@@ -68,7 +71,7 @@ const extendDefaultPlugins = (plugins) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return extendedPlugins;
|
return extendedPlugins;
|
||||||
}
|
};
|
||||||
exports.extendDefaultPlugins = extendDefaultPlugins;
|
exports.extendDefaultPlugins = extendDefaultPlugins;
|
||||||
|
|
||||||
const resolvePluginConfig = (plugin, config) => {
|
const resolvePluginConfig = (plugin, config) => {
|
||||||
@@ -86,7 +89,7 @@ const resolvePluginConfig = (plugin, config) => {
|
|||||||
...pluginConfig,
|
...pluginConfig,
|
||||||
name: plugin,
|
name: plugin,
|
||||||
active: true,
|
active: true,
|
||||||
params: { ...pluginConfig.params, ...configParams }
|
params: { ...pluginConfig.params, ...configParams },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (typeof plugin === 'object' && plugin != null) {
|
if (typeof plugin === 'object' && plugin != null) {
|
||||||
@@ -98,7 +101,7 @@ const resolvePluginConfig = (plugin, config) => {
|
|||||||
return {
|
return {
|
||||||
active: true,
|
active: true,
|
||||||
...plugin,
|
...plugin,
|
||||||
params: { configParams, ...plugin.params }
|
params: { configParams, ...plugin.params },
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// resolve builtin plugin specified as object without implementation
|
// resolve builtin plugin specified as object without implementation
|
||||||
@@ -110,7 +113,7 @@ const resolvePluginConfig = (plugin, config) => {
|
|||||||
...pluginConfig,
|
...pluginConfig,
|
||||||
active: true,
|
active: true,
|
||||||
...plugin,
|
...plugin,
|
||||||
params: { ...pluginConfig.params, ...configParams, ...plugin.params }
|
params: { ...pluginConfig.params, ...configParams, ...plugin.params },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,24 +31,23 @@ CSSClassList.prototype.clone = function(parentNode) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
CSSClassList.prototype.hasClass = function () {
|
CSSClassList.prototype.hasClass = function () {
|
||||||
this.classAttr = { // empty class attr
|
this.classAttr = {
|
||||||
'name': 'class',
|
// empty class attr
|
||||||
'value': null
|
name: 'class',
|
||||||
|
value: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.addClassHandler();
|
this.addClassHandler();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// attr.class
|
// attr.class
|
||||||
|
|
||||||
CSSClassList.prototype.addClassHandler = function () {
|
CSSClassList.prototype.addClassHandler = function () {
|
||||||
|
|
||||||
Object.defineProperty(this.parentNode.attrs, 'class', {
|
Object.defineProperty(this.parentNode.attrs, 'class', {
|
||||||
get: this.getClassAttr.bind(this),
|
get: this.getClassAttr.bind(this),
|
||||||
set: this.setClassAttr.bind(this),
|
set: this.setClassAttr.bind(this),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true
|
configurable: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addClassValueHandler();
|
this.addClassValueHandler();
|
||||||
@@ -57,12 +56,11 @@ CSSClassList.prototype.addClassHandler = function() {
|
|||||||
// attr.class.value
|
// attr.class.value
|
||||||
|
|
||||||
CSSClassList.prototype.addClassValueHandler = function () {
|
CSSClassList.prototype.addClassValueHandler = function () {
|
||||||
|
|
||||||
Object.defineProperty(this.classAttr, 'value', {
|
Object.defineProperty(this.classAttr, 'value', {
|
||||||
get: this.getClassValue.bind(this),
|
get: this.getClassValue.bind(this),
|
||||||
set: this.setClassValue.bind(this),
|
set: this.setClassValue.bind(this),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true
|
configurable: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,7 +89,6 @@ CSSClassList.prototype.setClassValue = function(newValue) {
|
|||||||
this.classNames = new Set(arrClassNames);
|
this.classNames = new Set(arrClassNames);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
CSSClassList.prototype.add = function (/* variadic */) {
|
CSSClassList.prototype.add = function (/* variadic */) {
|
||||||
this.hasClass();
|
this.hasClass();
|
||||||
Object.values(arguments).forEach(this._addSingle.bind(this));
|
Object.values(arguments).forEach(this._addSingle.bind(this));
|
||||||
@@ -101,7 +98,6 @@ CSSClassList.prototype._addSingle = function(className) {
|
|||||||
this.classNames.add(className);
|
this.classNames.add(className);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
CSSClassList.prototype.remove = function (/* variadic */) {
|
CSSClassList.prototype.remove = function (/* variadic */) {
|
||||||
this.hasClass();
|
this.hasClass();
|
||||||
Object.values(arguments).forEach(this._removeSingle.bind(this));
|
Object.values(arguments).forEach(this._removeSingle.bind(this));
|
||||||
@@ -111,7 +107,6 @@ CSSClassList.prototype._removeSingle = function(className) {
|
|||||||
this.classNames.delete(className);
|
this.classNames.delete(className);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
CSSClassList.prototype.item = function (index) {
|
CSSClassList.prototype.item = function (index) {
|
||||||
var arrClassNames = Array.from(this.classNames);
|
var arrClassNames = Array.from(this.classNames);
|
||||||
return arrClassNames[index];
|
return arrClassNames[index];
|
||||||
@@ -128,5 +123,4 @@ CSSClassList.prototype.contains = function(className) {
|
|||||||
return this.classNames.has(className);
|
return this.classNames.has(className);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = CSSClassList;
|
module.exports = CSSClassList;
|
||||||
|
@@ -6,7 +6,6 @@ var baseCssAdapter = require('css-select-base-adapter');
|
|||||||
* DOMUtils API for SVGO AST (used by css-select)
|
* DOMUtils API for SVGO AST (used by css-select)
|
||||||
*/
|
*/
|
||||||
var svgoCssSelectAdapterMin = {
|
var svgoCssSelectAdapterMin = {
|
||||||
|
|
||||||
// is the node a tag?
|
// is the node a tag?
|
||||||
// isTag: ( node:Node ) => isTag:Boolean
|
// isTag: ( node:Node ) => isTag:Boolean
|
||||||
isTag: function (node) {
|
isTag: function (node) {
|
||||||
@@ -44,7 +43,7 @@ var svgoCssSelectAdapterMin = {
|
|||||||
// returns null when attribute doesn't exist
|
// returns null when attribute doesn't exist
|
||||||
getAttributeValue: function (elem, name) {
|
getAttributeValue: function (elem, name) {
|
||||||
return elem.hasAttr(name) ? elem.attr(name).value : null;
|
return elem.hasAttr(name) ? elem.attr(name).value : null;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// use base adapter for default implementation
|
// use base adapter for default implementation
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
var csstree = require('css-tree'),
|
var csstree = require('css-tree'),
|
||||||
csstools = require('../css-tools');
|
csstools = require('../css-tools');
|
||||||
|
|
||||||
|
|
||||||
var CSSStyleDeclaration = function (node) {
|
var CSSStyleDeclaration = function (node) {
|
||||||
this.parentNode = node;
|
this.parentNode = node;
|
||||||
|
|
||||||
@@ -43,23 +42,20 @@ CSSStyleDeclaration.prototype.hasStyle = function() {
|
|||||||
this.addStyleHandler();
|
this.addStyleHandler();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// attr.style
|
// attr.style
|
||||||
|
|
||||||
CSSStyleDeclaration.prototype.addStyleHandler = function () {
|
CSSStyleDeclaration.prototype.addStyleHandler = function () {
|
||||||
|
this.styleAttr = {
|
||||||
this.styleAttr = { // empty style attr
|
// empty style attr
|
||||||
'name': 'style',
|
name: 'style',
|
||||||
'value': null
|
value: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.defineProperty(this.parentNode.attrs, 'style', {
|
Object.defineProperty(this.parentNode.attrs, 'style', {
|
||||||
get: this.getStyleAttr.bind(this),
|
get: this.getStyleAttr.bind(this),
|
||||||
set: this.setStyleAttr.bind(this),
|
set: this.setStyleAttr.bind(this),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true
|
configurable: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addStyleValueHandler();
|
this.addStyleValueHandler();
|
||||||
@@ -68,12 +64,11 @@ CSSStyleDeclaration.prototype.addStyleHandler = function() {
|
|||||||
// attr.style.value
|
// attr.style.value
|
||||||
|
|
||||||
CSSStyleDeclaration.prototype.addStyleValueHandler = function () {
|
CSSStyleDeclaration.prototype.addStyleValueHandler = function () {
|
||||||
|
|
||||||
Object.defineProperty(this.styleAttr, 'value', {
|
Object.defineProperty(this.styleAttr, 'value', {
|
||||||
get: this.getStyleValue.bind(this),
|
get: this.getStyleValue.bind(this),
|
||||||
set: this.setStyleValue.bind(this),
|
set: this.setStyleValue.bind(this),
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true
|
configurable: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,9 +94,6 @@ CSSStyleDeclaration.prototype.setStyleValue = function(newValue) {
|
|||||||
this.hasSynced = false; // raw css changed
|
this.hasSynced = false; // raw css changed
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CSSStyleDeclaration.prototype._loadCssText = function () {
|
CSSStyleDeclaration.prototype._loadCssText = function () {
|
||||||
if (this.hasSynced) {
|
if (this.hasSynced) {
|
||||||
return;
|
return;
|
||||||
@@ -117,7 +109,7 @@ CSSStyleDeclaration.prototype._loadCssText = function() {
|
|||||||
try {
|
try {
|
||||||
declarations = csstree.parse(inlineCssStr, {
|
declarations = csstree.parse(inlineCssStr, {
|
||||||
context: 'declarationList',
|
context: 'declarationList',
|
||||||
parseValue: false
|
parseValue: false,
|
||||||
});
|
});
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
this.parseError = parseError;
|
this.parseError = parseError;
|
||||||
@@ -129,7 +121,11 @@ CSSStyleDeclaration.prototype._loadCssText = function() {
|
|||||||
declarations.children.each(function (declaration) {
|
declarations.children.each(function (declaration) {
|
||||||
try {
|
try {
|
||||||
var styleDeclaration = csstools.csstreeToStyleDeclaration(declaration);
|
var styleDeclaration = csstools.csstreeToStyleDeclaration(declaration);
|
||||||
self.setProperty(styleDeclaration.name, styleDeclaration.value, styleDeclaration.priority);
|
self.setProperty(
|
||||||
|
styleDeclaration.name,
|
||||||
|
styleDeclaration.value,
|
||||||
|
styleDeclaration.priority
|
||||||
|
);
|
||||||
} catch (styleError) {
|
} catch (styleError) {
|
||||||
if (styleError.message !== 'Unknown node type: undefined') {
|
if (styleError.message !== 'Unknown node type: undefined') {
|
||||||
self.parseError = styleError;
|
self.parseError = styleError;
|
||||||
@@ -138,7 +134,6 @@ CSSStyleDeclaration.prototype._loadCssText = function() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// only reads from properties
|
// only reads from properties
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -157,18 +152,22 @@ CSSStyleDeclaration.prototype.getCssText = function() {
|
|||||||
var cssText = [];
|
var cssText = [];
|
||||||
properties.forEach(function (property, propertyName) {
|
properties.forEach(function (property, propertyName) {
|
||||||
var strImportant = property.priority === 'important' ? '!important' : '';
|
var strImportant = property.priority === 'important' ? '!important' : '';
|
||||||
cssText.push(propertyName.trim() + ':' + property.value.trim() + strImportant);
|
cssText.push(
|
||||||
|
propertyName.trim() + ':' + property.value.trim() + strImportant
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return cssText.join(';');
|
return cssText.join(';');
|
||||||
};
|
};
|
||||||
|
|
||||||
CSSStyleDeclaration.prototype._handleParseError = function () {
|
CSSStyleDeclaration.prototype._handleParseError = function () {
|
||||||
if (this.parseError) {
|
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);
|
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) {
|
CSSStyleDeclaration.prototype._getProperty = function (propertyName) {
|
||||||
if (typeof propertyName === 'undefined') {
|
if (typeof propertyName === 'undefined') {
|
||||||
throw Error('1 argument required, but only 0 present.');
|
throw Error('1 argument required, but only 0 present.');
|
||||||
@@ -230,7 +229,6 @@ CSSStyleDeclaration.prototype.getProperties = function() {
|
|||||||
return this.properties;
|
return this.properties;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// writes to properties
|
// writes to properties
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -262,7 +260,11 @@ CSSStyleDeclaration.prototype.removeProperty = function(propertyName) {
|
|||||||
* @param {String} [priority] allowing the "important" CSS priority to be set. If not specified, treated as the empty string.
|
* @param {String} [priority] allowing the "important" CSS priority to be set. If not specified, treated as the empty string.
|
||||||
* @return {undefined}
|
* @return {undefined}
|
||||||
*/
|
*/
|
||||||
CSSStyleDeclaration.prototype.setProperty = function(propertyName, value, priority) {
|
CSSStyleDeclaration.prototype.setProperty = function (
|
||||||
|
propertyName,
|
||||||
|
value,
|
||||||
|
priority
|
||||||
|
) {
|
||||||
if (typeof propertyName === 'undefined') {
|
if (typeof propertyName === 'undefined') {
|
||||||
throw Error('propertyName argument required, but only not present.');
|
throw Error('propertyName argument required, but only not present.');
|
||||||
}
|
}
|
||||||
@@ -274,12 +276,11 @@ CSSStyleDeclaration.prototype.setProperty = function(propertyName, value, priori
|
|||||||
|
|
||||||
var property = {
|
var property = {
|
||||||
value: value.trim(),
|
value: value.trim(),
|
||||||
priority: priority.trim()
|
priority: priority.trim(),
|
||||||
};
|
};
|
||||||
properties.set(propertyName.trim(), property);
|
properties.set(propertyName.trim(), property);
|
||||||
|
|
||||||
return property;
|
return property;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = CSSStyleDeclaration;
|
module.exports = CSSStyleDeclaration;
|
||||||
|
@@ -27,12 +27,12 @@ var defaults = {
|
|||||||
regValEntities: /[&"<>]/g,
|
regValEntities: /[&"<>]/g,
|
||||||
encodeEntity: encodeEntity,
|
encodeEntity: encodeEntity,
|
||||||
pretty: false,
|
pretty: false,
|
||||||
useShortTags: true
|
useShortTags: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var entities = {
|
var entities = {
|
||||||
'&': '&',
|
'&': '&',
|
||||||
'\'': ''',
|
"'": ''',
|
||||||
'"': '"',
|
'"': '"',
|
||||||
'>': '>',
|
'>': '>',
|
||||||
'<': '<',
|
'<': '<',
|
||||||
@@ -47,13 +47,10 @@ var entities = {
|
|||||||
* @return {Object} output data
|
* @return {Object} output data
|
||||||
*/
|
*/
|
||||||
module.exports = function (data, config) {
|
module.exports = function (data, config) {
|
||||||
|
|
||||||
return new JS2SVG(config).convert(data);
|
return new JS2SVG(config).convert(data);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function JS2SVG(config) {
|
function JS2SVG(config) {
|
||||||
|
|
||||||
if (config) {
|
if (config) {
|
||||||
this.config = Object.assign({}, defaults, config);
|
this.config = Object.assign({}, defaults, config);
|
||||||
} else {
|
} else {
|
||||||
@@ -62,7 +59,7 @@ function JS2SVG(config) {
|
|||||||
|
|
||||||
var indent = this.config.indent;
|
var indent = this.config.indent;
|
||||||
if (typeof indent == 'number' && !isNaN(indent)) {
|
if (typeof indent == 'number' && !isNaN(indent)) {
|
||||||
this.config.indent = (indent < 0) ? '\t' : ' '.repeat(indent);
|
this.config.indent = indent < 0 ? '\t' : ' '.repeat(indent);
|
||||||
} else if (typeof indent != 'string') {
|
} else if (typeof indent != 'string') {
|
||||||
this.config.indent = ' ';
|
this.config.indent = ' ';
|
||||||
}
|
}
|
||||||
@@ -80,7 +77,6 @@ function JS2SVG(config) {
|
|||||||
|
|
||||||
this.indentLevel = 0;
|
this.indentLevel = 0;
|
||||||
this.textContext = null;
|
this.textContext = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function encodeEntity(char) {
|
function encodeEntity(char) {
|
||||||
@@ -95,15 +91,12 @@ function encodeEntity(char) {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.convert = function (data) {
|
JS2SVG.prototype.convert = function (data) {
|
||||||
|
|
||||||
var svg = '';
|
var svg = '';
|
||||||
|
|
||||||
if (data.content) {
|
if (data.content) {
|
||||||
|
|
||||||
this.indentLevel++;
|
this.indentLevel++;
|
||||||
|
|
||||||
data.content.forEach(function (item) {
|
data.content.forEach(function (item) {
|
||||||
|
|
||||||
if (item.elem) {
|
if (item.elem) {
|
||||||
svg += this.createElem(item);
|
svg += this.createElem(item);
|
||||||
} else if (item.text) {
|
} else if (item.text) {
|
||||||
@@ -117,9 +110,7 @@ JS2SVG.prototype.convert = function(data) {
|
|||||||
} else if (item.cdata) {
|
} else if (item.cdata) {
|
||||||
svg += this.createCDATA(item.cdata);
|
svg += this.createCDATA(item.cdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.indentLevel--;
|
this.indentLevel--;
|
||||||
@@ -128,10 +119,9 @@ JS2SVG.prototype.convert = function(data) {
|
|||||||
data: svg,
|
data: svg,
|
||||||
info: {
|
info: {
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height
|
height: this.height,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,7 +130,6 @@ JS2SVG.prototype.convert = function(data) {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createIndent = function () {
|
JS2SVG.prototype.createIndent = function () {
|
||||||
|
|
||||||
var indent = '';
|
var indent = '';
|
||||||
|
|
||||||
if (this.config.pretty && !this.textContext) {
|
if (this.config.pretty && !this.textContext) {
|
||||||
@@ -148,7 +137,6 @@ JS2SVG.prototype.createIndent = function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return indent;
|
return indent;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -159,11 +147,7 @@ JS2SVG.prototype.createIndent = function() {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createDoctype = function (doctype) {
|
JS2SVG.prototype.createDoctype = function (doctype) {
|
||||||
|
return this.config.doctypeStart + doctype + this.config.doctypeEnd;
|
||||||
return this.config.doctypeStart +
|
|
||||||
doctype +
|
|
||||||
this.config.doctypeEnd;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,13 +158,13 @@ JS2SVG.prototype.createDoctype = function(doctype) {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createProcInst = function (instruction) {
|
JS2SVG.prototype.createProcInst = function (instruction) {
|
||||||
|
return (
|
||||||
return this.config.procInstStart +
|
this.config.procInstStart +
|
||||||
instruction.name +
|
instruction.name +
|
||||||
' ' +
|
' ' +
|
||||||
instruction.body +
|
instruction.body +
|
||||||
this.config.procInstEnd;
|
this.config.procInstEnd
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -191,11 +175,7 @@ JS2SVG.prototype.createProcInst = function(instruction) {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createComment = function (comment) {
|
JS2SVG.prototype.createComment = function (comment) {
|
||||||
|
return this.config.commentStart + comment + this.config.commentEnd;
|
||||||
return this.config.commentStart +
|
|
||||||
comment +
|
|
||||||
this.config.commentEnd;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -206,12 +186,9 @@ JS2SVG.prototype.createComment = function(comment) {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createCDATA = function (cdata) {
|
JS2SVG.prototype.createCDATA = function (cdata) {
|
||||||
|
return (
|
||||||
return this.createIndent() +
|
this.createIndent() + this.config.cdataStart + cdata + this.config.cdataEnd
|
||||||
this.config.cdataStart +
|
);
|
||||||
cdata +
|
|
||||||
this.config.cdataEnd;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -222,13 +199,8 @@ JS2SVG.prototype.createCDATA = function(cdata) {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createElem = function (data) {
|
JS2SVG.prototype.createElem = function (data) {
|
||||||
|
|
||||||
// beautiful injection for obtaining SVG information :)
|
// beautiful injection for obtaining SVG information :)
|
||||||
if (
|
if (data.isElem('svg') && data.hasAttr('width') && data.hasAttr('height')) {
|
||||||
data.isElem('svg') &&
|
|
||||||
data.hasAttr('width') &&
|
|
||||||
data.hasAttr('height')
|
|
||||||
) {
|
|
||||||
this.width = data.attr('width').value;
|
this.width = data.attr('width').value;
|
||||||
this.height = data.attr('height').value;
|
this.height = data.attr('height').value;
|
||||||
}
|
}
|
||||||
@@ -236,20 +208,24 @@ JS2SVG.prototype.createElem = function(data) {
|
|||||||
// empty element and short tag
|
// empty element and short tag
|
||||||
if (data.isEmpty()) {
|
if (data.isEmpty()) {
|
||||||
if (this.config.useShortTags) {
|
if (this.config.useShortTags) {
|
||||||
return this.createIndent() +
|
return (
|
||||||
|
this.createIndent() +
|
||||||
this.config.tagShortStart +
|
this.config.tagShortStart +
|
||||||
data.elem +
|
data.elem +
|
||||||
this.createAttrs(data) +
|
this.createAttrs(data) +
|
||||||
this.config.tagShortEnd;
|
this.config.tagShortEnd
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return this.createIndent() +
|
return (
|
||||||
|
this.createIndent() +
|
||||||
this.config.tagShortStart +
|
this.config.tagShortStart +
|
||||||
data.elem +
|
data.elem +
|
||||||
this.createAttrs(data) +
|
this.createAttrs(data) +
|
||||||
this.config.tagOpenEnd +
|
this.config.tagOpenEnd +
|
||||||
this.config.tagCloseStart +
|
this.config.tagCloseStart +
|
||||||
data.elem +
|
data.elem +
|
||||||
this.config.tagCloseEnd;
|
this.config.tagCloseEnd
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// non-empty element
|
// non-empty element
|
||||||
} else {
|
} else {
|
||||||
@@ -281,7 +257,8 @@ JS2SVG.prototype.createElem = function(data) {
|
|||||||
this.textContext = null;
|
this.textContext = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return openIndent +
|
return (
|
||||||
|
openIndent +
|
||||||
tagOpenStart +
|
tagOpenStart +
|
||||||
data.elem +
|
data.elem +
|
||||||
this.createAttrs(data) +
|
this.createAttrs(data) +
|
||||||
@@ -291,10 +268,9 @@ JS2SVG.prototype.createElem = function(data) {
|
|||||||
closeIndent +
|
closeIndent +
|
||||||
tagCloseStart +
|
tagCloseStart +
|
||||||
data.elem +
|
data.elem +
|
||||||
tagCloseEnd;
|
tagCloseEnd
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -305,28 +281,25 @@ JS2SVG.prototype.createElem = function(data) {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createAttrs = function (elem) {
|
JS2SVG.prototype.createAttrs = function (elem) {
|
||||||
|
|
||||||
var attrs = '';
|
var attrs = '';
|
||||||
|
|
||||||
elem.eachAttr(function (attr) {
|
elem.eachAttr(function (attr) {
|
||||||
|
|
||||||
if (attr.value !== undefined) {
|
if (attr.value !== undefined) {
|
||||||
attrs += ' ' +
|
attrs +=
|
||||||
|
' ' +
|
||||||
attr.name +
|
attr.name +
|
||||||
this.config.attrStart +
|
this.config.attrStart +
|
||||||
String(attr.value).replace(this.config.regValEntities, this.config.encodeEntity) +
|
String(attr.value).replace(
|
||||||
|
this.config.regValEntities,
|
||||||
|
this.config.encodeEntity
|
||||||
|
) +
|
||||||
this.config.attrEnd;
|
this.config.attrEnd;
|
||||||
|
} else {
|
||||||
|
attrs += ' ' + attr.name;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
attrs += ' ' +
|
|
||||||
attr.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
return attrs;
|
return attrs;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -337,10 +310,10 @@ JS2SVG.prototype.createAttrs = function(elem) {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
JS2SVG.prototype.createText = function (text) {
|
JS2SVG.prototype.createText = function (text) {
|
||||||
|
return (
|
||||||
return this.createIndent() +
|
this.createIndent() +
|
||||||
this.config.textStart +
|
this.config.textStart +
|
||||||
text.replace(this.config.regEntities, this.config.encodeEntity) +
|
text.replace(this.config.regEntities, this.config.encodeEntity) +
|
||||||
(this.textContext ? '' : this.config.textEnd);
|
(this.textContext ? '' : this.config.textEnd)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@@ -5,18 +5,19 @@ const svgoCssSelectAdapter = require('./css-select-adapter');
|
|||||||
|
|
||||||
var cssSelectOpts = {
|
var cssSelectOpts = {
|
||||||
xmlMode: true,
|
xmlMode: true,
|
||||||
adapter: svgoCssSelectAdapter
|
adapter: svgoCssSelectAdapter,
|
||||||
};
|
};
|
||||||
|
|
||||||
var JSAPI = module.exports = function(data, parentNode) {
|
var JSAPI = function (data, parentNode) {
|
||||||
Object.assign(this, data);
|
Object.assign(this, data);
|
||||||
if (parentNode) {
|
if (parentNode) {
|
||||||
Object.defineProperty(this, 'parentNode', {
|
Object.defineProperty(this, 'parentNode', {
|
||||||
writable: true,
|
writable: true,
|
||||||
value: parentNode
|
value: parentNode,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
module.exports = JSAPI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a deep clone of this node.
|
* Perform a deep clone of this node.
|
||||||
@@ -66,13 +67,11 @@ JSAPI.prototype.clone = function() {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
JSAPI.prototype.isElem = function (param) {
|
JSAPI.prototype.isElem = function (param) {
|
||||||
|
|
||||||
if (!param) return !!this.elem;
|
if (!param) return !!this.elem;
|
||||||
|
|
||||||
if (Array.isArray(param)) return !!this.elem && (param.indexOf(this.elem) > -1);
|
if (Array.isArray(param)) return !!this.elem && param.indexOf(this.elem) > -1;
|
||||||
|
|
||||||
return !!this.elem && this.elem === param;
|
return !!this.elem && this.elem === param;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,12 +81,9 @@ JSAPI.prototype.isElem = function(param) {
|
|||||||
* @return {Object} element
|
* @return {Object} element
|
||||||
*/
|
*/
|
||||||
JSAPI.prototype.renameElem = function (name) {
|
JSAPI.prototype.renameElem = function (name) {
|
||||||
|
if (name && typeof name === 'string') this.elem = this.local = name;
|
||||||
if (name && typeof name === 'string')
|
|
||||||
this.elem = this.local = name;
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,9 +92,7 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
JSAPI.prototype.isEmpty = function () {
|
JSAPI.prototype.isEmpty = function () {
|
||||||
|
|
||||||
return !this.content || !this.content.length;
|
return !this.content || !this.content.length;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,17 +118,16 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
* @return {Array} Removed elements.
|
* @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))
|
if (!Array.isArray(insertion))
|
||||||
insertion = Array.apply(null, arguments).slice(2);
|
insertion = Array.apply(null, arguments).slice(2);
|
||||||
|
|
||||||
insertion.forEach(function(inner) { inner.parentNode = this }, this);
|
insertion.forEach(function (inner) {
|
||||||
|
inner.parentNode = this;
|
||||||
|
}, this);
|
||||||
|
|
||||||
return this.content.splice.apply(this.content, [start, n].concat(insertion));
|
return this.content.splice.apply(this.content, [start, n].concat(insertion));
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,15 +139,14 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
JSAPI.prototype.hasAttr = function (name, val) {
|
JSAPI.prototype.hasAttr = function (name, 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;
|
||||||
|
|
||||||
if (val !== undefined) return !!this.attrs[name] && this.attrs[name].value === val.toString();
|
if (val !== undefined)
|
||||||
|
return !!this.attrs[name] && this.attrs[name].value === val.toString();
|
||||||
|
|
||||||
return !!this.attrs[name];
|
return !!this.attrs[name];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -166,7 +158,6 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
* @return {Boolean}
|
* @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;
|
||||||
@@ -175,10 +166,17 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
|
|
||||||
switch (val != null && val.constructor && val.constructor.name) {
|
switch (val != null && val.constructor && val.constructor.name) {
|
||||||
case 'Number': // same as String
|
case 'Number': // same as String
|
||||||
case 'String': callback = stringValueTest; break;
|
case 'String':
|
||||||
case 'RegExp': callback = regexpValueTest; break;
|
callback = stringValueTest;
|
||||||
case 'Function': callback = funcValueTest; break;
|
break;
|
||||||
default: callback = nameTest;
|
case 'RegExp':
|
||||||
|
callback = regexpValueTest;
|
||||||
|
break;
|
||||||
|
case 'Function':
|
||||||
|
callback = funcValueTest;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
callback = nameTest;
|
||||||
}
|
}
|
||||||
return this.someAttr(callback);
|
return this.someAttr(callback);
|
||||||
|
|
||||||
@@ -197,7 +195,6 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
function funcValueTest(attr) {
|
function funcValueTest(attr) {
|
||||||
return attr.local === localName && val(attr.value);
|
return attr.local === localName && val(attr.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -209,13 +206,12 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
* @return {Object|Undefined}
|
* @return {Object|Undefined}
|
||||||
*/
|
*/
|
||||||
JSAPI.prototype.attr = function (name, val) {
|
JSAPI.prototype.attr = function (name, val) {
|
||||||
|
|
||||||
if (!this.hasAttr() || !arguments.length) return undefined;
|
if (!this.hasAttr() || !arguments.length) return undefined;
|
||||||
|
|
||||||
if (val !== undefined) return this.hasAttr(name, val) ? this.attrs[name] : undefined;
|
if (val !== undefined)
|
||||||
|
return this.hasAttr(name, val) ? this.attrs[name] : undefined;
|
||||||
|
|
||||||
return this.attrs[name];
|
return this.attrs[name];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -227,14 +223,17 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
JSAPI.prototype.computedAttr = function (name, val) {
|
JSAPI.prototype.computedAttr = function (name, val) {
|
||||||
if (!arguments.length) return;
|
if (!arguments.length) return;
|
||||||
|
|
||||||
for (var elem = this; elem && (!elem.hasAttr(name) || !elem.attr(name).value); elem = elem.parentNode);
|
for (
|
||||||
|
var elem = this;
|
||||||
|
elem && (!elem.hasAttr(name) || !elem.attr(name).value);
|
||||||
|
elem = elem.parentNode
|
||||||
|
);
|
||||||
|
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
return elem ? elem.hasAttr(name, val) : false;
|
return elem ? elem.hasAttr(name, val) : false;
|
||||||
} else if (elem && elem.hasAttr(name)) {
|
} else if (elem && elem.hasAttr(name)) {
|
||||||
return elem.attrs[name].value;
|
return elem.attrs[name].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -245,7 +244,6 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
JSAPI.prototype.removeAttr = function (name, val, recursive) {
|
JSAPI.prototype.removeAttr = function (name, val, recursive) {
|
||||||
|
|
||||||
if (!arguments.length) return false;
|
if (!arguments.length) return false;
|
||||||
|
|
||||||
if (Array.isArray(name)) {
|
if (Array.isArray(name)) {
|
||||||
@@ -262,7 +260,6 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
if (!Object.keys(this.attrs).length) delete this.attrs;
|
if (!Object.keys(this.attrs).length) delete this.attrs;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -274,24 +271,27 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
JSAPI.prototype.addAttr = function (attr) {
|
JSAPI.prototype.addAttr = function (attr) {
|
||||||
attr = attr || {};
|
attr = attr || {};
|
||||||
|
|
||||||
if (attr.name === undefined ||
|
if (
|
||||||
|
attr.name === undefined ||
|
||||||
attr.prefix === undefined ||
|
attr.prefix === undefined ||
|
||||||
attr.local === undefined
|
attr.local === undefined
|
||||||
) return false;
|
)
|
||||||
|
return false;
|
||||||
|
|
||||||
this.attrs = this.attrs || {};
|
this.attrs = this.attrs || {};
|
||||||
this.attrs[attr.name] = attr;
|
this.attrs[attr.name] = attr;
|
||||||
|
|
||||||
if(attr.name === 'class') { // newly added class attribute
|
if (attr.name === 'class') {
|
||||||
|
// newly added class attribute
|
||||||
this.class.hasClass();
|
this.class.hasClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(attr.name === 'style') { // newly added style attribute
|
if (attr.name === 'style') {
|
||||||
|
// newly added style attribute
|
||||||
this.style.hasStyle();
|
this.style.hasStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.attrs[attr.name];
|
return this.attrs[attr.name];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -302,7 +302,6 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
* @return {Boolean} false if there are no any attributes
|
* @return {Boolean} false if there are no any attributes
|
||||||
*/
|
*/
|
||||||
JSAPI.prototype.eachAttr = function (callback, context) {
|
JSAPI.prototype.eachAttr = function (callback, context) {
|
||||||
|
|
||||||
if (!this.hasAttr()) return false;
|
if (!this.hasAttr()) return false;
|
||||||
|
|
||||||
for (const attr of Object.values(this.attrs)) {
|
for (const attr of Object.values(this.attrs)) {
|
||||||
@@ -310,7 +309,6 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -321,7 +319,6 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
* @return {Boolean} false if there are no any attributes
|
* @return {Boolean} false if there are no any attributes
|
||||||
*/
|
*/
|
||||||
JSAPI.prototype.someAttr = function (callback, context) {
|
JSAPI.prototype.someAttr = function (callback, context) {
|
||||||
|
|
||||||
if (!this.hasAttr()) return false;
|
if (!this.hasAttr()) return false;
|
||||||
|
|
||||||
for (const attr of Object.values(this.attrs)) {
|
for (const attr of Object.values(this.attrs)) {
|
||||||
@@ -329,7 +326,6 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -339,11 +335,9 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
* @return {Array} null if no elements matched
|
* @return {Array} null if no elements matched
|
||||||
*/
|
*/
|
||||||
JSAPI.prototype.querySelectorAll = function (selectors) {
|
JSAPI.prototype.querySelectorAll = function (selectors) {
|
||||||
|
|
||||||
var matchedEls = selectAll(selectors, this, cssSelectOpts);
|
var matchedEls = selectAll(selectors, this, cssSelectOpts);
|
||||||
|
|
||||||
return matchedEls.length > 0 ? matchedEls : null;
|
return matchedEls.length > 0 ? matchedEls : null;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -353,9 +347,7 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
* @return {Array} null if no element matched
|
* @return {Array} null if no element matched
|
||||||
*/
|
*/
|
||||||
JSAPI.prototype.querySelector = function (selectors) {
|
JSAPI.prototype.querySelector = function (selectors) {
|
||||||
|
|
||||||
return selectOne(selectors, this, cssSelectOpts);
|
return selectOne(selectors, this, cssSelectOpts);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -365,7 +357,5 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
* @return {Boolean} true if element would be selected by selector string, false if it does not
|
* @return {Boolean} true if element would be selected by selector string, false if it does not
|
||||||
*/
|
*/
|
||||||
JSAPI.prototype.matches = function (selector) {
|
JSAPI.prototype.matches = function (selector) {
|
||||||
|
|
||||||
return is(this, selector, cssSelectOpts);
|
return is(this, selector, cssSelectOpts);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -49,11 +49,8 @@ module.exports = function(data, info, plugins) {
|
|||||||
* @return {Object} output data
|
* @return {Object} output data
|
||||||
*/
|
*/
|
||||||
function perItem(data, info, plugins, reverse) {
|
function perItem(data, info, plugins, reverse) {
|
||||||
|
|
||||||
function monkeys(items) {
|
function monkeys(items) {
|
||||||
|
|
||||||
items.content = items.content.filter(function (item) {
|
items.content = items.content.filter(function (item) {
|
||||||
|
|
||||||
// reverse pass
|
// reverse pass
|
||||||
if (reverse && item.content) {
|
if (reverse && item.content) {
|
||||||
monkeys(item);
|
monkeys(item);
|
||||||
@@ -76,15 +73,12 @@ function perItem(data, info, plugins, reverse) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return monkeys(data);
|
return monkeys(data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,7 +90,6 @@ function perItem(data, info, plugins, reverse) {
|
|||||||
* @return {Object} output data
|
* @return {Object} output data
|
||||||
*/
|
*/
|
||||||
function full(data, info, plugins) {
|
function full(data, info, plugins) {
|
||||||
|
|
||||||
plugins.forEach(function (plugin) {
|
plugins.forEach(function (plugin) {
|
||||||
if (plugin.active) {
|
if (plugin.active) {
|
||||||
data = plugin.fn(data, plugin.params, info);
|
data = plugin.fn(data, plugin.params, info);
|
||||||
@@ -104,5 +97,4 @@ function full(data, info, plugins) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,7 @@ var config = {
|
|||||||
normalize: false,
|
normalize: false,
|
||||||
lowercase: true,
|
lowercase: true,
|
||||||
xmlns: true,
|
xmlns: true,
|
||||||
position: true
|
position: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,26 +22,22 @@ var config = {
|
|||||||
* @param {String} data input data
|
* @param {String} data input data
|
||||||
*/
|
*/
|
||||||
module.exports = function (data) {
|
module.exports = function (data) {
|
||||||
|
|
||||||
var sax = SAX.parser(config.strict, config),
|
var sax = SAX.parser(config.strict, config),
|
||||||
root = new JSAPI({ elem: '#document', content: [] }),
|
root = new JSAPI({ elem: '#document', content: [] }),
|
||||||
current = root,
|
current = root,
|
||||||
stack = [root];
|
stack = [root];
|
||||||
|
|
||||||
function pushToContent(content) {
|
function pushToContent(content) {
|
||||||
|
|
||||||
content = new JSAPI(content, current);
|
content = new JSAPI(content, current);
|
||||||
|
|
||||||
(current.content = current.content || []).push(content);
|
(current.content = current.content || []).push(content);
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sax.ondoctype = function (doctype) {
|
sax.ondoctype = function (doctype) {
|
||||||
|
|
||||||
pushToContent({
|
pushToContent({
|
||||||
doctype: doctype
|
doctype: doctype,
|
||||||
});
|
});
|
||||||
|
|
||||||
var subsetStart = doctype.indexOf('['),
|
var subsetStart = doctype.indexOf('['),
|
||||||
@@ -57,36 +53,29 @@ module.exports = function(data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
sax.onprocessinginstruction = function (data) {
|
sax.onprocessinginstruction = function (data) {
|
||||||
|
|
||||||
pushToContent({
|
pushToContent({
|
||||||
processinginstruction: data
|
processinginstruction: data,
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
sax.oncomment = function (comment) {
|
sax.oncomment = function (comment) {
|
||||||
|
|
||||||
pushToContent({
|
pushToContent({
|
||||||
comment: comment.trim()
|
comment: comment.trim(),
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
sax.oncdata = function (cdata) {
|
sax.oncdata = function (cdata) {
|
||||||
|
|
||||||
pushToContent({
|
pushToContent({
|
||||||
cdata: cdata
|
cdata: cdata,
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
sax.onopentag = function (data) {
|
sax.onopentag = function (data) {
|
||||||
|
|
||||||
var elem = {
|
var elem = {
|
||||||
elem: data.name,
|
elem: data.name,
|
||||||
prefix: data.prefix,
|
prefix: data.prefix,
|
||||||
local: data.local,
|
local: data.local,
|
||||||
attrs: {}
|
attrs: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
elem.class = new CSSClassList(elem);
|
elem.class = new CSSClassList(elem);
|
||||||
@@ -94,12 +83,13 @@ module.exports = function(data) {
|
|||||||
|
|
||||||
if (Object.keys(data.attributes).length) {
|
if (Object.keys(data.attributes).length) {
|
||||||
for (const [name, attr] of Object.entries(data.attributes)) {
|
for (const [name, attr] of Object.entries(data.attributes)) {
|
||||||
|
if (name === 'class') {
|
||||||
if (name === 'class') { // has class attribute
|
// has class attribute
|
||||||
elem.class.hasClass();
|
elem.class.hasClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name === 'style') { // has style attribute
|
if (name === 'style') {
|
||||||
|
// has style attribute
|
||||||
elem.style.hasStyle();
|
elem.style.hasStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +97,7 @@ module.exports = function(data) {
|
|||||||
name: name,
|
name: name,
|
||||||
value: attr.value,
|
value: attr.value,
|
||||||
prefix: attr.prefix,
|
prefix: attr.prefix,
|
||||||
local: attr.local
|
local: attr.local,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,7 +106,6 @@ module.exports = function(data) {
|
|||||||
current = elem;
|
current = elem;
|
||||||
|
|
||||||
stack.push(elem);
|
stack.push(elem);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
sax.ontext = function (text) {
|
sax.ontext = function (text) {
|
||||||
@@ -134,12 +123,10 @@ module.exports = function(data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
sax.onerror = function (e) {
|
sax.onerror = function (e) {
|
||||||
|
|
||||||
e.message = 'Error in parsing SVG: ' + e.message;
|
e.message = 'Error in parsing SVG: ' + e.message;
|
||||||
if (e.message.indexOf('Unexpected end') < 0) {
|
if (e.message.indexOf('Unexpected end') < 0) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -148,5 +135,4 @@ module.exports = function(data) {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
return { error: e.message };
|
return { error: e.message };
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -99,9 +99,7 @@ exports.cleanupOutData = function(data, params, command) {
|
|||||||
if (
|
if (
|
||||||
params.negativeExtraSpace &&
|
params.negativeExtraSpace &&
|
||||||
delimiter != '' &&
|
delimiter != '' &&
|
||||||
(item < 0 ||
|
(item < 0 || (String(item).charCodeAt(0) == 46 && prev % 1 !== 0))
|
||||||
(String(item).charCodeAt(0) == 46 && prev % 1 !== 0)
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
delimiter = '';
|
delimiter = '';
|
||||||
}
|
}
|
||||||
@@ -125,7 +123,7 @@ exports.cleanupOutData = function(data, params, command) {
|
|||||||
*
|
*
|
||||||
* @return {String} output number as string
|
* @return {String} output number as string
|
||||||
*/
|
*/
|
||||||
var removeLeadingZero = exports.removeLeadingZero = function(num) {
|
var removeLeadingZero = function (num) {
|
||||||
var strNum = num.toString();
|
var strNum = num.toString();
|
||||||
|
|
||||||
if (0 < num && num < 1 && strNum.charCodeAt(0) == 48) {
|
if (0 < num && num < 1 && strNum.charCodeAt(0) == 48) {
|
||||||
@@ -135,3 +133,4 @@ var removeLeadingZero = exports.removeLeadingZero = function(num) {
|
|||||||
}
|
}
|
||||||
return strNum;
|
return strNum;
|
||||||
};
|
};
|
||||||
|
exports.removeLeadingZero = removeLeadingZero;
|
||||||
|
Reference in New Issue
Block a user