1
0
mirror of https://github.com/svg/svgo.git synced 2025-08-01 18:46:52 +03:00

Access attributes directly (#1433)

Got rid from `.attrs`, `.attr()` and `.addAttr()` usages
This commit is contained in:
Bogdan Chadkin
2021-03-18 18:53:20 +03:00
committed by GitHub
parent 07928fc77e
commit 6f2f62c5ee
23 changed files with 261 additions and 283 deletions

View File

@ -19,7 +19,7 @@ const existsOne = (test, elems) => {
};
const getAttributeValue = (elem, name) => {
return elem.hasAttr(name) ? elem.attr(name).value : undefined;
return elem.attributes[name];
};
const getChildren = (node) => {
@ -47,7 +47,7 @@ const getText = (node) => {
};
const hasAttrib = (elem, name) => {
return getAttributeValue(elem, name) !== undefined;
return elem.attributes[name] !== undefined;
};
const removeSubsets = (nodes) => {

View File

@ -203,9 +203,13 @@ JS2SVG.prototype.createCDATA = function (node) {
*/
JS2SVG.prototype.createElem = function (data) {
// beautiful injection for obtaining SVG information :)
if (data.isElem('svg') && data.hasAttr('width') && data.hasAttr('height')) {
this.width = data.attr('width').value;
this.height = data.attr('height').value;
if (
data.name === 'svg' &&
data.attributes.width != null &&
data.attributes.height != null
) {
this.width = data.attributes.width;
this.height = data.attributes.height;
}
// empty element and short tag

View File

@ -289,7 +289,7 @@ JSAPI.prototype.computedAttr = function (name, val) {
for (
var elem = this;
elem && (!elem.hasAttr(name) || !elem.attr(name).value);
elem && (!elem.hasAttr(name) || !elem.attributes[name]);
elem = elem.parentNode
);

View File

@ -38,7 +38,7 @@ const applyTransforms = (elem, pathData, params) => {
return;
}
const matrix = transformsMultiply(transform2js(elem.attr('transform').value));
const matrix = transformsMultiply(transform2js(elem.attributes.transform));
const stroke = elem.computedAttr('stroke');
const id = elem.computedAttr('id');
const transformPrecision = params.transformPrecision;
@ -77,34 +77,33 @@ const applyTransforms = (elem, pathData, params) => {
elem.computedAttr('stroke-width') || defaultStrokeWidth;
if (
!elem.hasAttr('vector-effect') ||
elem.attr('vector-effect').value !== 'non-scaling-stroke'
elem.attributes['vector-effect'] == null ||
elem.attributes['vector-effect'] !== 'non-scaling-stroke'
) {
if (elem.hasAttr('stroke-width')) {
elem.attrs['stroke-width'].value = elem.attrs['stroke-width'].value
if (elem.attributes['stroke-width'] != null) {
elem.attributes['stroke-width'] = elem.attributes['stroke-width']
.trim()
.replace(regNumericValues, (num) => removeLeadingZero(num * scale));
} else {
elem.addAttr({
name: 'stroke-width',
value: strokeWidth.replace(regNumericValues, (num) =>
elem.attributes[
'stroke-width'
] = strokeWidth.replace(regNumericValues, (num) =>
removeLeadingZero(num * scale)
),
});
);
}
if (elem.hasAttr('stroke-dashoffset')) {
elem.attrs['stroke-dashoffset'].value = elem.attrs[
if (elem.attributes['stroke-dashoffset'] != null) {
elem.attributes['stroke-dashoffset'] = elem.attributes[
'stroke-dashoffset'
].value
]
.trim()
.replace(regNumericValues, (num) => removeLeadingZero(num * scale));
}
if (elem.hasAttr('stroke-dasharray')) {
elem.attrs['stroke-dasharray'].value = elem.attrs[
if (elem.attributes['stroke-dasharray'] != null) {
elem.attributes['stroke-dasharray'] = elem.attributes[
'stroke-dasharray'
].value
]
.trim()
.replace(regNumericValues, (num) => removeLeadingZero(num * scale));
}

View File

@ -14,7 +14,7 @@ var prevCtrlPoint;
exports.path2js = function (path) {
if (path.pathJS) return path.pathJS;
const pathData = []; // JS representation of the path data
const newPathData = parsePathData(path.attr('d').value);
const newPathData = parsePathData(path.attributes.d);
for (const { command, args } of newPathData) {
if (command === 'Z' || command === 'z') {
pathData.push({ instruction: 'z' });
@ -343,7 +343,7 @@ exports.js2path = function (path, data, params) {
});
}
path.attr('d').value = stringifyPathData({
path.attributes.d = stringifyPathData({
pathData,
precision: params.floatPrecision,
disableSpaceAfterFlags: params.noSpaceAfterFlags,

View File

@ -62,18 +62,13 @@ exports.fn = function (data, params) {
if (svg.isElem('svg')) {
attributes.forEach(function (attribute) {
if (typeof attribute === 'string') {
if (!svg.hasAttr(attribute)) {
svg.addAttr({
name: attribute,
});
if (svg.attributes[attribute] == null) {
svg.attributes[attribute] = undefined;
}
} else if (typeof attribute === 'object') {
Object.keys(attribute).forEach(function (key) {
if (!svg.hasAttr(key)) {
svg.addAttr({
name: key,
value: attribute[key],
});
if (svg.attributes[key] == null) {
svg.attributes[key] = attribute[key];
}
});
}

View File

@ -208,7 +208,7 @@ exports.fn = function (data, params) {
);
} while (idPreserved(currentIDstring));
IDs.get(key).attr('id').value = currentIDstring;
IDs.get(key).attributes.id = currentIDstring;
for (const { element, name, value } of refs) {
element.attributes[name] = value.includes(idValuePrefix)

View File

@ -1,5 +1,7 @@
'use strict';
const { removeLeadingZero } = require('../lib/svgo/tools.js');
exports.type = 'perItem';
exports.active = false;
@ -13,10 +15,9 @@ exports.params = {
convertToPx: true,
};
var regNumericValues = /^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/,
regSeparator = /\s+,?\s*|,\s*/,
removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero,
absoluteLengths = {
const regNumericValues = /^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/;
const regSeparator = /\s+,?\s*|,\s*/;
const absoluteLengths = {
// relative to px
cm: 96 / 2.54,
mm: 96 / 25.4,
@ -46,49 +47,55 @@ var regNumericValues = /^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|
* @author kiyopikko
*/
exports.fn = function (item, params) {
if (item.hasAttr('points')) {
roundValues(item.attrs.points);
if (item.type !== 'element') {
return;
}
if (item.hasAttr('enable-background')) {
roundValues(item.attrs['enable-background']);
if (item.attributes.points != null) {
item.attributes.points = roundValues(item.attributes.points);
}
if (item.hasAttr('viewBox')) {
roundValues(item.attrs.viewBox);
if (item.attributes['enable-background'] != null) {
item.attributes['enable-background'] = roundValues(
item.attributes['enable-background']
);
}
if (item.hasAttr('stroke-dasharray')) {
roundValues(item.attrs['stroke-dasharray']);
if (item.attributes.viewBox != null) {
item.attributes.viewBox = roundValues(item.attributes.viewBox);
}
if (item.hasAttr('dx')) {
roundValues(item.attrs.dx);
if (item.attributes['stroke-dasharray'] != null) {
item.attributes['stroke-dasharray'] = roundValues(
item.attributes['stroke-dasharray']
);
}
if (item.hasAttr('dy')) {
roundValues(item.attrs.dy);
if (item.attributes.dx != null) {
item.attributes.dx = roundValues(item.attributes.dx);
}
if (item.hasAttr('x')) {
roundValues(item.attrs.x);
if (item.attributes.dy != null) {
item.attributes.dy = roundValues(item.attributes.dy);
}
if (item.hasAttr('y')) {
roundValues(item.attrs.y);
if (item.attributes.x != null) {
item.attributes.x = roundValues(item.attributes.x);
}
function roundValues($prop) {
if (item.attributes.y != null) {
item.attributes.y = roundValues(item.attributes.y);
}
function roundValues(lists) {
var num,
units,
match,
matchNew,
lists = $prop.value,
listsArr = lists.split(regSeparator),
roundedListArr = [],
roundedList;
roundedList = [];
listsArr.forEach(function (elem) {
for (const elem of listsArr) {
match = elem.match(regNumericValues);
matchNew = elem.match(/new/);
@ -118,17 +125,16 @@ exports.fn = function (item, params) {
units = '';
}
roundedListArr.push(num + units);
roundedList.push(num + units);
}
// if attribute value is "new"(only enable-background).
else if (matchNew) {
roundedListArr.push('new');
roundedList.push('new');
} else if (elem) {
roundedListArr.push(elem);
roundedList.push(elem);
}
}
});
roundedList = roundedListArr.join(' ');
$prop.value = roundedList;
return roundedList.join(' ');
}
};

View File

@ -39,9 +39,9 @@ exports.fn = function (item, params) {
if (item.type === 'element') {
var floatPrecision = params.floatPrecision;
if (item.hasAttr('viewBox')) {
var nums = item.attr('viewBox').value.split(/\s,?\s*|,\s*/g);
item.attr('viewBox').value = nums
if (item.attributes.viewBox != null) {
var nums = item.attributes.viewBox.split(/\s,?\s*|,\s*/g);
item.attributes.viewBox = nums
.map(function (value) {
var num = +value;
return isNaN(num) ? value : +num.toFixed(floatPrecision);

View File

@ -13,7 +13,6 @@ exports.params = {
floatPrecision: null,
};
const none = { value: 0 };
const regNumber = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g;
/**
@ -35,15 +34,15 @@ exports.fn = function (item, params) {
if (
item.isElem('rect') &&
item.hasAttr('width') &&
item.hasAttr('height') &&
!item.hasAttr('rx') &&
!item.hasAttr('ry')
item.attributes.width != null &&
item.attributes.height != null &&
item.attributes.rx == null &&
item.attributes.ry == null
) {
var x = +(item.attr('x') || none).value,
y = +(item.attr('y') || none).value,
width = +item.attr('width').value,
height = +item.attr('height').value;
const x = Number(item.attributes.x || '0');
const y = Number(item.attributes.y || '0');
const width = Number(item.attributes.width);
const height = Number(item.attributes.height);
// Values like '100%' compute to NaN, thus running after
// cleanupNumericValues when 'px' units has already been removed.
// TODO: Calculate sizes from % and non-px units if possible.
@ -55,10 +54,7 @@ exports.fn = function (item, params) {
{ command: 'H', args: [x] },
{ command: 'z', args: [] },
];
item.addAttr({
name: 'd',
value: stringifyPathData({ pathData, precision }),
});
item.attributes.d = stringifyPathData({ pathData, precision });
item.renameElem('path');
delete item.attributes.x;
delete item.attributes.y;
@ -67,19 +63,16 @@ exports.fn = function (item, params) {
}
if (item.isElem('line')) {
var x1 = +(item.attr('x1') || none).value,
y1 = +(item.attr('y1') || none).value,
x2 = +(item.attr('x2') || none).value,
y2 = +(item.attr('y2') || none).value;
const x1 = Number(item.attributes.x1 || '0');
const y1 = Number(item.attributes.y1 || '0');
const x2 = Number(item.attributes.x2 || '0');
const y2 = Number(item.attributes.y2 || '0');
if (isNaN(x1 - y1 + x2 - y2)) return;
const pathData = [
{ command: 'M', args: [x1, y1] },
{ command: 'L', args: [x2, y2] },
];
item.addAttr({
name: 'd',
value: stringifyPathData({ pathData, precision }),
});
item.attributes.d = stringifyPathData({ pathData, precision });
item.renameElem('path');
delete item.attributes.x1;
delete item.attributes.y1;
@ -89,9 +82,9 @@ exports.fn = function (item, params) {
if (
(item.isElem('polyline') || item.isElem('polygon')) &&
item.hasAttr('points')
item.attributes.points != null
) {
var coords = (item.attr('points').value.match(regNumber) || []).map(Number);
const coords = (item.attributes.points.match(regNumber) || []).map(Number);
if (coords.length < 4) return false;
const pathData = [];
for (let i = 0; i < coords.length; i += 2) {
@ -103,18 +96,15 @@ exports.fn = function (item, params) {
if (item.isElem('polygon')) {
pathData.push({ command: 'z', args: [] });
}
item.addAttr({
name: 'd',
value: stringifyPathData({ pathData, precision }),
});
item.attributes.d = stringifyPathData({ pathData, precision });
item.renameElem('path');
delete item.attributes.points;
}
if (item.isElem('circle') && convertArcs) {
var cx = +(item.attr('cx') || none).value;
var cy = +(item.attr('cy') || none).value;
var r = +(item.attr('r') || none).value;
const cx = Number(item.attributes.cx || '0');
const cy = Number(item.attributes.cy || '0');
const r = Number(item.attributes.r || '0');
if (isNaN(cx - cy + r)) {
return;
}
@ -124,10 +114,7 @@ exports.fn = function (item, params) {
{ command: 'A', args: [r, r, 0, 1, 0, cx, cy - r] },
{ command: 'z', args: [] },
];
item.addAttr({
name: 'd',
value: stringifyPathData({ pathData, precision }),
});
item.attributes.d = stringifyPathData({ pathData, precision });
item.renameElem('path');
delete item.attributes.cx;
delete item.attributes.cy;
@ -135,10 +122,10 @@ exports.fn = function (item, params) {
}
if (item.isElem('ellipse') && convertArcs) {
var ecx = +(item.attr('cx') || none).value;
var ecy = +(item.attr('cy') || none).value;
var rx = +(item.attr('rx') || none).value;
var ry = +(item.attr('ry') || none).value;
const ecx = Number(item.attributes.cx || '0');
const ecy = Number(item.attributes.cy || '0');
const rx = Number(item.attributes.rx || '0');
const ry = Number(item.attributes.ry || '0');
if (isNaN(ecx - ecy + rx - ry)) {
return;
}
@ -148,10 +135,7 @@ exports.fn = function (item, params) {
{ command: 'A', args: [rx, ry, 0, 1, 0, ecx, ecy - ry] },
{ command: 'z', args: [] },
];
item.addAttr({
name: 'd',
value: stringifyPathData({ pathData, precision }),
});
item.attributes.d = stringifyPathData({ pathData, precision });
item.renameElem('path');
delete item.attributes.cx;
delete item.attributes.cy;

View File

@ -67,20 +67,22 @@ var stylingProps = require('./_collections').attrsGroups.presentation,
* @author Kir Belevich
*/
exports.fn = function (item, params) {
if (item.type === 'element' && item.hasAttr('style')) {
if (item.type === 'element' && item.attributes.style != null) {
// ['opacity: 1', 'color: #000']
var styleValue = item.attr('style').value,
styles = [],
attrs = {};
let styles = [];
const newAttributes = {};
// Strip CSS comments preserving escape sequences and strings.
styleValue = styleValue.replace(regStripComments, function (match) {
const styleValue = item.attributes.style.replace(
regStripComments,
(match) => {
return match[0] == '/'
? ''
: match[0] == '\\' && /[-g-z]/i.test(match[1])
? match[1]
: match;
});
}
);
regDeclarationBlock.lastIndex = 0;
// eslint-disable-next-line no-cond-assign
@ -100,11 +102,8 @@ exports.fn = function (item, params) {
val = val.slice(1, -1);
}
if (stylingProps.indexOf(prop) > -1) {
attrs[prop] = {
name: prop,
value: val,
};
if (stylingProps.includes(prop)) {
newAttributes[prop] = val;
return false;
}
@ -113,13 +112,11 @@ exports.fn = function (item, params) {
return true;
});
Object.assign(item.attrs, attrs);
Object.assign(item.attributes, newAttributes);
if (styles.length) {
item.attr('style').value = styles
.map(function (declaration) {
return declaration.join(':');
})
item.attributes.style = styles
.map((declaration) => declaration.join(':'))
.join(';');
} else {
delete item.attributes.style;

View File

@ -70,7 +70,7 @@ exports.fn = function (item, params) {
* @param {Object} params plugin params
*/
function convertTransform(item, attrName, params) {
var data = transform2js(item.attr(attrName).value);
let data = transform2js(item.attributes[attrName]);
params = definePrecision(data, params);
if (params.collapseIntoOne && data.length > 1) {

View File

@ -55,9 +55,9 @@ exports.fn = function (document, opts) {
for (var styleEl of styleEls) {
// values other than the empty string or text/css are not used
if (
styleEl.hasAttr('type') &&
styleEl.attr('type').value !== '' &&
styleEl.attr('type').value !== 'text/css'
styleEl.attributes.type != null &&
styleEl.attributes.type !== '' &&
styleEl.attributes.type !== 'text/css'
) {
continue;
}

View File

@ -28,18 +28,18 @@ exports.params = {
exports.fn = function (item, params) {
if (item.type !== 'element' || item.children.length === 0) return;
var prevContentItem = null,
prevContentItemKeys = null;
let prevContentItem = null;
let prevContentItemKeys = null;
item.children = item.children.filter(function (contentItem) {
if (
prevContentItem &&
prevContentItem.isElem('path') &&
prevContentItem.children.length === 0 &&
prevContentItem.hasAttr('d') &&
prevContentItem.attributes.d != null &&
contentItem.isElem('path') &&
contentItem.children.length === 0 &&
contentItem.hasAttr('d')
contentItem.attributes.d != null
) {
const computedStyle = computeStyle(contentItem);
// keep path to not break markers
@ -51,21 +51,21 @@ exports.fn = function (item, params) {
return true;
}
if (!prevContentItemKeys) {
prevContentItemKeys = Object.keys(prevContentItem.attrs);
prevContentItemKeys = Object.keys(prevContentItem.attributes);
}
var contentItemAttrs = Object.keys(contentItem.attrs),
equalData =
const contentItemAttrs = Object.keys(contentItem.attributes);
const equalData =
prevContentItemKeys.length == contentItemAttrs.length &&
contentItemAttrs.every(function (key) {
return (
key == 'd' ||
(prevContentItem.hasAttr(key) &&
prevContentItem.attr(key).value == contentItem.attr(key).value)
(prevContentItem.attributes[key] != null &&
prevContentItem.attributes[key] == contentItem.attributes[key])
);
}),
prevPathJS = path2js(prevContentItem),
curPathJS = path2js(contentItem);
});
const prevPathJS = path2js(prevContentItem);
const curPathJS = path2js(contentItem);
if (equalData && (params.force || !intersects(prevPathJS, curPathJS))) {
js2path(prevContentItem, prevPathJS.concat(curPathJS), params);

View File

@ -56,9 +56,9 @@ exports.fn = function (ast, options) {
}
} else {
// style attribute
var elemStyle = elem.attr('style').value;
var elemStyle = elem.attributes.style;
elem.attr('style').value = csso.minifyBlock(
elem.attributes.style = csso.minifyBlock(
elemStyle,
minifyOptionsForAttribute
).css;
@ -84,7 +84,7 @@ function findStyleElems(ast) {
if (item.isElem('style') && item.children.length !== 0) {
styles.push(item);
} else if (item.type === 'element' && item.hasAttr('style')) {
} else if (item.type === 'element' && item.attributes.style != null) {
styles.push(item);
}
}
@ -109,41 +109,33 @@ function shouldFilter(options, name) {
function collectUsageData(ast, options) {
function walk(items, usageData) {
for (var i = 0; i < items.children.length; i++) {
var item = items.children[i];
for (const item of items.children) {
// go deeper
if (item.children) {
if (item.type === 'root' || item.type === 'element') {
walk(item, usageData);
}
if (item.isElem('script')) {
if (item.type === 'element') {
if (item.name === 'script') {
safe = false;
}
if (item.type === 'element') {
usageData.tags[item.name] = true;
if (item.hasAttr('id')) {
usageData.ids[item.attr('id').value] = true;
if (item.attributes.id != null) {
usageData.ids[item.attributes.id] = true;
}
if (item.hasAttr('class')) {
item
.attr('class')
.value.replace(/^\s+|\s+$/g, '')
if (item.attributes.class != null) {
item.attributes.class
.replace(/^\s+|\s+$/g, '')
.split(/\s+/)
.forEach(function (className) {
usageData.classes[className] = true;
});
}
if (
item.attrs &&
Object.keys(item.attrs).some(function (name) {
return /^on/i.test(name);
})
) {
if (Object.keys(item.attributes).some((name) => /^on/i.test(name))) {
safe = false;
}
}

View File

@ -69,15 +69,16 @@ exports.fn = function (item) {
if (name === 'transform') {
if (!hasTransform) {
if (item.hasAttr('transform')) {
item.attr('transform').value += ' ' + value;
item.attributes.transform =
item.attributes.transform + ' ' + value;
} else {
item.addAttr({ name, value });
item.attributes.transform = value;
}
hasTransform = true;
}
} else {
item.addAttr({ name, value });
item.attributes[name] = value;
}
}
}

View File

@ -51,11 +51,6 @@ var matchUrl = function (val) {
return urlMatches[1];
};
// Checks if attribute is empty
var attrNotEmpty = function (attr) {
return attr && attr.value && attr.value.length > 0;
};
// prefixes an #ID
var prefixId = function (val) {
var idName = matchId(val);
@ -65,74 +60,88 @@ var prefixId = function (val) {
return '#' + addPrefix(idName);
};
// attr.value helper methods
// prefixes a class attribute value
var addPrefixToClassAttr = function (attr) {
if (!attrNotEmpty(attr)) {
const addPrefixToClassAttr = (element, name) => {
if (
element.attributes[name] == null ||
element.attributes[name].length === 0
) {
return;
}
attr.value = attr.value.split(/\s+/).map(addPrefix).join(' ');
element.attributes[name] = element.attributes[name]
.split(/\s+/)
.map(addPrefix)
.join(' ');
};
// prefixes an ID attribute value
var addPrefixToIdAttr = function (attr) {
if (!attrNotEmpty(attr)) {
const addPrefixToIdAttr = (element, name) => {
if (
element.attributes[name] == null ||
element.attributes[name].length === 0
) {
return;
}
attr.value = addPrefix(attr.value);
element.attributes[name] = addPrefix(element.attributes[name]);
};
// prefixes a href attribute value
var addPrefixToHrefAttr = function (attr) {
if (!attrNotEmpty(attr)) {
const addPrefixToHrefAttr = (element, name) => {
if (
element.attributes[name] == null ||
element.attributes[name].length === 0
) {
return;
}
var idPrefixed = prefixId(attr.value);
const idPrefixed = prefixId(element.attributes[name]);
if (!idPrefixed) {
return;
}
attr.value = idPrefixed;
element.attributes[name] = idPrefixed;
};
// prefixes an URL attribute value
var addPrefixToUrlAttr = function (attr) {
if (!attrNotEmpty(attr)) {
const addPrefixToUrlAttr = (element, name) => {
if (
element.attributes[name] == null ||
element.attributes[name].length === 0
) {
return;
}
// url(...) in value
var urlVal = matchUrl(attr.value);
const urlVal = matchUrl(element.attributes[name]);
if (!urlVal) {
return;
}
var idPrefixed = prefixId(urlVal);
const idPrefixed = prefixId(urlVal);
if (!idPrefixed) {
return;
}
attr.value = 'url(' + idPrefixed + ')';
element.attributes[name] = 'url(' + idPrefixed + ')';
};
// prefixes begin/end attribute value
var addPrefixToBeginEndAttr = function (attr) {
if (!attrNotEmpty(attr)) {
const addPrefixToBeginEndAttr = (element, name) => {
if (
element.attributes[name] == null ||
element.attributes[name].length === 0
) {
return;
}
var parts = attr.value.split('; ').map(function (val) {
const parts = element.attributes[name].split('; ').map((val) => {
val = val.trim();
if (val.endsWith('.end') || val.endsWith('.start')) {
var idPostfix = val.split('.'),
id = idPostfix[0],
postfix = idPostfix[1];
const [id, postfix] = val.split('.');
var idPrefixed = prefixId(`#${id}`);
let idPrefixed = prefixId(`#${id}`);
if (!idPrefixed) {
return val;
@ -145,7 +154,7 @@ var addPrefixToBeginEndAttr = function (attr) {
}
});
attr.value = parts.join('; ');
element.attributes[name] = parts.join('; ');
};
const getBasename = (path) => {
@ -169,7 +178,7 @@ const getBasename = (path) => {
exports.fn = function (node, opts, extra) {
// skip subsequent passes when multipass is used
if (extra.multipassCount && extra.multipassCount > 0) {
return node;
return;
}
// prefix, from file name or option
@ -200,7 +209,7 @@ exports.fn = function (node, opts, extra) {
if (node.type === 'element' && node.name === 'style') {
if (node.children.length === 0) {
// skip empty <style/>s
return node;
return;
}
var cssStr = '';
@ -219,7 +228,7 @@ exports.fn = function (node, opts, extra) {
'Warning: Parse error of styles of <style/> element, skipped. Error details: ' +
parseError
);
return node;
return;
}
var idPrefixed = '';
@ -250,42 +259,40 @@ exports.fn = function (node, opts, extra) {
// update <style>s
node.children[0].value = csstree.generate(cssAst);
return node;
return;
}
// element attributes
if (!node.attrs) {
return node;
if (node.type !== 'element') {
return;
}
// Nodes
if (opts.prefixIds) {
// ID
addPrefixToIdAttr(node.attrs.id);
addPrefixToIdAttr(node, 'id');
}
if (opts.prefixClassNames) {
// Class
addPrefixToClassAttr(node.attrs.class);
addPrefixToClassAttr(node, 'class');
}
// References
// href
addPrefixToHrefAttr(node.attrs.href);
addPrefixToHrefAttr(node, 'href');
// (xlink:)href (deprecated, must be still supported)
addPrefixToHrefAttr(node.attrs['xlink:href']);
addPrefixToHrefAttr(node, 'xlink:href');
// (referenceable) properties
for (var referencesProp of referencesProps) {
addPrefixToUrlAttr(node.attrs[referencesProp]);
addPrefixToUrlAttr(node, referencesProp);
}
addPrefixToBeginEndAttr(node.attrs.begin);
addPrefixToBeginEndAttr(node.attrs.end);
return node;
addPrefixToBeginEndAttr(node, 'begin');
addPrefixToBeginEndAttr(node, 'end');
};

View File

@ -65,15 +65,13 @@ exports.fn = function (item, params) {
}
// remove element if it's `id` matches configured `id` params
const elemId = item.attr('id');
if (elemId && params.id.length !== 0) {
return params.id.includes(elemId.value) === false;
if (item.attributes.id != null && params.id.length !== 0) {
return params.id.includes(item.attributes.id) === false;
}
// remove element if it's `class` contains any of the configured `class` params
const elemClass = item.attr('class');
if (elemClass && params.class.length !== 0) {
const classList = elemClass.value.split(' ');
if (item.attributes.class && params.class.length !== 0) {
const classList = item.attributes.class.split(' ');
return params.class.some((item) => classList.includes(item)) === false;
}
};

View File

@ -30,7 +30,7 @@ exports.fn = function (item) {
(item.type === 'element' && item.children.length !== 0) ||
item.isElem('svg') ||
// empty patterns may contain reusable configuration
(item.isElem('pattern') && Object.keys(item.attrs).length !== 0) ||
(item.isElem('pattern') && Object.keys(item.attributes).length !== 0) ||
// The 'g' may not have content, but the filter may cause a rectangle
// to be created and filled with pattern.
(item.isElem('g') && item.hasAttr('filter')) ||

View File

@ -103,7 +103,7 @@ exports.fn = function (item, params) {
params.circleR0 &&
item.isElem('circle') &&
item.children.length === 0 &&
item.hasAttr('r', '0')
item.attributes.r === '0'
) {
return false;
}
@ -118,7 +118,7 @@ exports.fn = function (item, params) {
params.ellipseRX0 &&
item.isElem('ellipse') &&
item.children.length === 0 &&
item.hasAttr('rx', '0')
item.attributes.rx === '0'
) {
return false;
}
@ -133,7 +133,7 @@ exports.fn = function (item, params) {
params.ellipseRY0 &&
item.isElem('ellipse') &&
item.children.length === 0 &&
item.hasAttr('ry', '0')
item.attributes.ry === '0'
) {
return false;
}
@ -148,7 +148,7 @@ exports.fn = function (item, params) {
params.rectWidth0 &&
item.isElem('rect') &&
item.children.length === 0 &&
item.hasAttr('width', '0')
item.attributes.width === '0'
) {
return false;
}
@ -164,7 +164,7 @@ exports.fn = function (item, params) {
params.rectWidth0 &&
item.isElem('rect') &&
item.children.length === 0 &&
item.hasAttr('height', '0')
item.attributes.height === '0'
) {
return false;
}
@ -178,7 +178,7 @@ exports.fn = function (item, params) {
if (
params.patternWidth0 &&
item.isElem('pattern') &&
item.hasAttr('width', '0')
item.attributes.width === '0'
) {
return false;
}
@ -192,7 +192,7 @@ exports.fn = function (item, params) {
if (
params.patternHeight0 &&
item.isElem('pattern') &&
item.hasAttr('height', '0')
item.attributes.height === '0'
) {
return false;
}
@ -206,7 +206,7 @@ exports.fn = function (item, params) {
if (
params.imageWidth0 &&
item.isElem('image') &&
item.hasAttr('width', '0')
item.attributes.width === '0'
) {
return false;
}
@ -220,7 +220,7 @@ exports.fn = function (item, params) {
if (
params.imageHeight0 &&
item.isElem('image') &&
item.hasAttr('height', '0')
item.attributes.height === '0'
) {
return false;
}
@ -231,10 +231,10 @@ exports.fn = function (item, params) {
//
// <path d=""/>
if (params.pathEmptyD && item.isElem('path')) {
if (item.hasAttr('d') === false) {
if (item.attributes.d == null) {
return false;
}
const pathData = parsePathData(item.attr('d').value);
const pathData = parsePathData(item.attributes.d);
if (pathData.length === 0) {
return false;
}
@ -257,7 +257,7 @@ exports.fn = function (item, params) {
if (
params.polylineEmptyPoints &&
item.isElem('polyline') &&
!item.hasAttr('points')
item.attributes.points == null
) {
return false;
}
@ -270,7 +270,7 @@ exports.fn = function (item, params) {
if (
params.polygonEmptyPoints &&
item.isElem('polygon') &&
!item.hasAttr('points')
item.attributes.points == null
) {
return false;
}

View File

@ -26,12 +26,12 @@ var _path = require('./_path.js'),
exports.fn = function (item) {
if (
item.isElem('path') &&
item.hasAttr('d') &&
item.attributes.d != null &&
typeof viewBox !== 'undefined'
) {
// Consider that any item with a transform attribute or a M instruction
// within the viewBox is visible
if (hasTransform(item) || pathMovesWithinViewBox(item.attr('d').value)) {
if (hasTransform(item) || pathMovesWithinViewBox(item.attributes.d)) {
return true;
}
@ -71,12 +71,11 @@ function hasTransform(item) {
*/
function parseViewBox(svg) {
var viewBoxData = '';
if (svg.hasAttr('viewBox')) {
if (svg.attributes.viewBox != null) {
// Remove commas and plus signs, normalize and trim whitespace
viewBoxData = svg.attr('viewBox').value;
} else if (svg.hasAttr('height') && svg.hasAttr('width')) {
viewBoxData =
'0 0 ' + svg.attr('width').value + ' ' + svg.attr('height').value;
viewBoxData = svg.attributes.viewBox;
} else if (svg.attributes.height != null && svg.attributes.width != null) {
viewBoxData = `0 0 ${svg.attributes.width} ${svg.attributes.height}`;
}
// Remove commas and plus signs, normalize and trim whitespace
@ -104,12 +103,11 @@ function parseViewBox(svg) {
var path = new JSAPI({
type: 'element',
name: 'path',
attributes: {
d: 'M' + m[1] + ' ' + m[2] + 'h' + m[3] + 'v' + m[4] + 'H' + m[1] + 'z',
},
content: [],
});
path.addAttr({
name: 'd',
value: 'M' + m[1] + ' ' + m[2] + 'h' + m[3] + 'v' + m[4] + 'H' + m[1] + 'z',
});
viewBoxJS = path2js(path);
}

View File

@ -83,9 +83,8 @@ exports.fn = function (item, params) {
if (
params.removeNone &&
(!stroke ||
(item.hasAttr('stroke') && item.attr('stroke').value == 'none')) &&
(!fill || (item.hasAttr('fill') && item.attr('fill').value == 'none'))
(!stroke || item.attributes.stroke == 'none') &&
(!fill || item.attributes.fill == 'none')
) {
return false;
}

View File

@ -22,12 +22,16 @@ exports.fn = function (data) {
let count = 0;
const defs = [];
traverse(data, (item) => {
if (!item.isElem('path') || !item.hasAttr('d')) {
if (
item.type !== 'element' ||
item.name !== 'path' ||
item.attributes.d == null
) {
return;
}
const d = item.attr('d').value;
const fill = (item.hasAttr('fill') && item.attr('fill').value) || '';
const stroke = (item.hasAttr('stroke') && item.attr('stroke').value) || '';
const d = item.attributes.d;
const fill = item.attributes.fill || '';
const stroke = item.attributes.stroke || '';
const key = d + ';s:' + stroke + ';f:' + fill;
const hasSeen = seen.get(key);
if (!hasSeen) {
@ -36,23 +40,20 @@ exports.fn = function (data) {
}
if (!hasSeen.reused) {
hasSeen.reused = true;
if (!hasSeen.elem.hasAttr('id')) {
hasSeen.elem.addAttr({
name: 'id',
value: 'reuse-' + count++,
});
if (hasSeen.elem.attributes.id == null) {
hasSeen.elem.attributes.id = 'reuse-' + count++;
}
defs.push(hasSeen.elem);
}
convertToUse(item, hasSeen.elem.attr('id').value);
convertToUse(item, hasSeen.elem.attributes.id);
});
if (defs.length > 0) {
const defsTag = new JSAPI(
{
type: 'element',
name: 'defs',
attributes: {},
children: [],
attrs: {},
},
data
);
@ -71,7 +72,7 @@ exports.fn = function (data) {
delete defClone.attributes.transform;
defsTag.spliceContent(0, 0, defClone);
// Convert the original def to a use so the first usage isn't duplicated.
def = convertToUse(def, defClone.attr('id').value);
def = convertToUse(def, defClone.attributes.id);
delete def.attributes.id;
}
}
@ -84,10 +85,7 @@ function convertToUse(item, href) {
delete item.attributes.d;
delete item.attributes.stroke;
delete item.attributes.fill;
item.addAttr({
name: 'xlink:href',
value: '#' + href,
});
item.attributes['xlink:href'] = '#' + href;
delete item.pathJS;
return item;
}