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

Remove hasAttr and hasAttrLocal usages (#1447)

In most cases simple check for null is enough.
This commit is contained in:
Bogdan Chadkin
2021-03-22 01:24:59 +03:00
committed by GitHub
parent 447f82ca6b
commit 316a002299
12 changed files with 122 additions and 87 deletions

View File

@ -296,7 +296,7 @@ JSAPI.prototype.computedAttr = function (name, val) {
if (val != null) {
return elem ? elem.hasAttr(name, val) : false;
} else if (elem && elem.hasAttr(name)) {
return elem.attrs[name].value;
return elem.attributes[name];
}
};

View File

@ -58,9 +58,11 @@ const applyTransforms = (elem, pathData, params) => {
let hasStrokeWidth = false;
do {
if (idElem.hasAttr('stroke-width')) hasStrokeWidth = true;
if (idElem.attributes['stroke-width']) {
hasStrokeWidth = true;
}
} while (
!idElem.hasAttr('id', id) &&
idElem.attributes.id !== id &&
!hasStrokeWidth &&
(idElem = idElem.parentNode)
);

View File

@ -1,22 +1,23 @@
'use strict';
const { inheritableAttrs, elemsGroups } = require('./_collections');
exports.type = 'perItemReverse';
exports.active = true;
exports.description = 'collapses useless groups';
var collections = require('./_collections'),
attrsInheritable = collections.inheritableAttrs,
animationElems = collections.elemsGroups.animation;
function hasAnimatedAttr(item) {
function hasAnimatedAttr(item, name) {
if (item.type === 'element') {
return (
(item.isElem(animationElems) && item.hasAttr('attributeName', this)) ||
(item.type === 'element' &&
item.children.length !== 0 &&
item.children.some(hasAnimatedAttr, this))
(elemsGroups.animation.includes(item.name) &&
item.attributes.attributeName === name) ||
(item.children.length !== 0 &&
item.children.some((child) => hasAnimatedAttr(child, name)))
);
}
return false;
}
/*
@ -51,33 +52,35 @@ exports.fn = function (item) {
) {
item.children.forEach(function (g, i) {
// non-empty groups
if (g.isElem('g') && g.children.length !== 0) {
if (g.type === 'element' && g.name === 'g' && g.children.length !== 0) {
// move group attibutes to the single child element
if (g.hasAttr() && g.children.length === 1) {
if (Object.keys(g.attributes).length !== 0 && g.children.length === 1) {
var inner = g.children[0];
if (
inner.type === 'element' &&
!inner.hasAttr('id') &&
!g.hasAttr('filter') &&
!(g.hasAttr('class') && inner.hasAttr('class')) &&
((!g.hasAttr('clip-path') && !g.hasAttr('mask')) ||
(inner.isElem('g') &&
!g.hasAttr('transform') &&
!inner.hasAttr('transform')))
inner.attributes.id == null &&
g.attributes.filter == null &&
(g.attributes.class == null || inner.attributes.class == null) &&
((g.attributes['clip-path'] == null && g.attributes.mask == null) ||
(inner.type === 'element' &&
inner.name === 'g' &&
g.attributes.transform == null &&
inner.attributes.transform == null))
) {
for (const [name, value] of Object.entries(g.attributes)) {
if (g.children.some(hasAnimatedAttr, name)) return;
if (g.children.some((item) => hasAnimatedAttr(item, name)))
return;
if (!inner.hasAttr(name)) {
if (inner.attributes[name] == null) {
inner.attributes[name] = value;
} else if (name == 'transform') {
inner.attributes[name] = value + ' ' + inner.attributes[name];
} else if (inner.hasAttr(name, 'inherit')) {
} else if (inner.attributes[name] === 'inherit') {
inner.attributes[name] = value;
} else if (
attrsInheritable.includes(name) === false &&
!inner.hasAttr(name, value)
inheritableAttrs.includes(name) === false &&
inner.attributes[name] !== value
) {
return;
}
@ -89,10 +92,8 @@ exports.fn = function (item) {
// collapse groups without attributes
if (
!g.hasAttr() &&
!g.children.some(function (item) {
return item.isElem(animationElems);
})
Object.keys(g.attributes).length === 0 &&
!g.children.some((item) => item.isElem(elemsGroups.animation))
) {
item.spliceContent(i, 1, g.children);
}

View File

@ -57,7 +57,11 @@ let arcTolerance;
* @author Kir Belevich
*/
exports.fn = function (item, params) {
if (item.isElem(pathElems) && item.hasAttr('d')) {
if (
item.type === 'element' &&
pathElems.includes(item.name) &&
item.attributes.d != null
) {
const computedStyle = computeStyle(item);
precision = params.floatPrecision;
error =

View File

@ -46,17 +46,17 @@ var cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
exports.fn = function (item, params) {
if (item.type === 'element') {
// transform
if (item.hasAttr('transform')) {
if (item.attributes.transform != null) {
convertTransform(item, 'transform', params);
}
// gradientTransform
if (item.hasAttr('gradientTransform')) {
if (item.attributes.gradientTransform != null) {
convertTransform(item, 'gradientTransform', params);
}
// patternTransform
if (item.hasAttr('patternTransform')) {
if (item.attributes.patternTransform != null) {
convertTransform(item, 'patternTransform', params);
}
}

View File

@ -1,14 +1,13 @@
'use strict';
const { inheritableAttrs, pathElems } = require('./_collections');
exports.type = 'perItemReverse';
exports.active = true;
exports.description = 'moves elements attributes to the existing group wrapper';
var inheritableAttrs = require('./_collections').inheritableAttrs,
pathElems = require('./_collections.js').pathElems;
/**
* Collapse content's intersected and inheritable
* attributes to the existing group wrapper.
@ -34,14 +33,22 @@ var inheritableAttrs = require('./_collections').inheritableAttrs,
* @author Kir Belevich
*/
exports.fn = function (item) {
if (item.isElem('g') && item.children.length > 1) {
if (
item.type === 'element' &&
item.name === 'g' &&
item.children.length > 1
) {
var intersection = {},
hasTransform = false,
hasClip = item.hasAttr('clip-path') || item.hasAttr('mask'),
hasClip =
item.attributes['clip-path'] != null || item.attributes.mask != null,
intersected = item.children.every(function (inner) {
if (inner.type === 'element' && inner.hasAttr()) {
if (
inner.type === 'element' &&
Object.keys(inner.attributes).length !== 0
) {
// don't mess with possible styles (hack until CSS parsing is implemented)
if (inner.hasAttr('class')) return false;
if (inner.attributes.class) return false;
if (!Object.keys(intersection).length) {
intersection = inner.attributes;
} else {
@ -68,7 +75,7 @@ exports.fn = function (item) {
if (name === 'transform') {
if (!hasTransform) {
if (item.hasAttr('transform')) {
if (item.attributes.transform != null) {
item.attributes.transform =
item.attributes.transform + ' ' + value;
} else {

View File

@ -1,14 +1,14 @@
'use strict';
const { pathElems, referencesProps } = require('./_collections.js');
exports.type = 'perItem';
exports.active = true;
exports.description = 'moves some group attributes to the content elements';
var collections = require('./_collections.js'),
pathElems = collections.pathElems.concat(['g', 'text']),
referencesProps = collections.referencesProps;
const pathElemsWithGroupsAndText = [...pathElems, 'g', 'text'];
/**
* Move group attrs to the content elements.
@ -41,7 +41,9 @@ exports.fn = function (item) {
referencesProps.includes(name) && value.includes('url(')
) === false &&
item.children.every(
(inner) => inner.isElem(pathElems) && !inner.hasAttr('id')
(inner) =>
pathElemsWithGroupsAndText.includes(inner.name) &&
inner.attributes.id == null
)
) {
for (const inner of item.children) {

View File

@ -1,13 +1,13 @@
'use strict';
const { elemsGroups } = require('./_collections');
exports.type = 'perItemReverse';
exports.active = true;
exports.description = 'removes empty container elements';
var container = require('./_collections').elemsGroups.container;
/**
* Remove empty containers.
*
@ -25,16 +25,19 @@ var container = require('./_collections').elemsGroups.container;
* @author Kir Belevich
*/
exports.fn = function (item) {
if (item.type === 'element') {
return (
item.isElem(container) === false ||
(item.type === 'element' && item.children.length !== 0) ||
item.isElem('svg') ||
item.children.length !== 0 ||
elemsGroups.container.includes(item.name) === false ||
item.name === 'svg' ||
// empty patterns may contain reusable configuration
(item.isElem('pattern') && Object.keys(item.attributes).length !== 0) ||
(item.name === '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')) ||
(item.name === 'g' && item.attributes.filter != null) ||
// empty <mask> hides masked element
(item.isElem('mask') && item.hasAttr('id'))
(item.name === 'mask' && item.attributes.id != null)
);
}
return true;
};

View File

@ -34,18 +34,24 @@ exports.params = {
* @author Kir Belevich
*/
exports.fn = function (item, params) {
if (item.type === 'element') {
// Remove empty text element
if (params.text && item.isElem('text') && item.children.length === 0) {
if (params.text && item.name === 'text' && item.children.length === 0) {
return false;
}
// Remove empty tspan element
if (params.tspan && item.isElem('tspan') && item.children.length === 0) {
if (params.tspan && item.name === 'tspan' && item.children.length === 0) {
return false;
}
// Remove tref with empty xlink:href attribute
if (params.tref && item.isElem('tref') && !item.hasAttrLocal('href')) {
if (
params.tref &&
item.name === 'tref' &&
item.attributes['xlink:href'] == null
) {
return false;
}
}
};

View File

@ -25,7 +25,8 @@ var _path = require('./_path.js'),
*/
exports.fn = function (item) {
if (
item.isElem('path') &&
item.type === 'element' &&
item.name === 'path' &&
item.attributes.d != null &&
typeof viewBox !== 'undefined'
) {
@ -44,7 +45,7 @@ exports.fn = function (item) {
return intersects(viewBoxJS, pathJS);
}
if (item.isElem('svg')) {
if (item.type === 'element' && item.name === 'svg') {
parseViewBox(item);
}
@ -59,8 +60,10 @@ exports.fn = function (item) {
*/
function hasTransform(item) {
return (
item.hasAttr('transform') ||
(item.parentNode && hasTransform(item.parentNode))
item.attributes.transform != null ||
(item.parentNode &&
item.parentNode.type === 'element' &&
hasTransform(item.parentNode))
);
}

View File

@ -18,8 +18,10 @@ exports.description = 'removes raster images (disabled by default)';
*/
exports.fn = function (item) {
if (
item.isElem('image') &&
item.hasAttrLocal('href', /(\.|image\/)(jpg|png|gif)/)
item.type === 'element' &&
item.name === 'image' &&
item.attributes['xlink:href'] != null &&
/(\.|image\/)(jpg|png|gif)/.test(item.attributes['xlink:href'])
) {
return false;
}

View File

@ -1,13 +1,13 @@
'use strict';
const { elemsGroups } = require('./_collections');
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes elements in <defs> without id';
var nonRendering = require('./_collections').elemsGroups.nonRendering;
/**
* Removes content of defs and properties that aren't rendered directly without ids.
*
@ -17,20 +17,25 @@ var nonRendering = require('./_collections').elemsGroups.nonRendering;
* @author Lev Solntsev
*/
exports.fn = function (item) {
if (item.isElem('defs')) {
if (item.type === 'element') {
if (item.name === 'defs') {
item.children = getUsefulItems(item, []);
if (item.children.length === 0) {
return false;
}
} else if (item.isElem(nonRendering) && !item.hasAttr('id')) {
} else if (
elemsGroups.nonRendering.includes(item.name) &&
item.attributes.id == null
) {
return false;
}
}
};
function getUsefulItems(item, usefulItems) {
for (const child of item.children) {
if (child.type === 'element') {
if (child.hasAttr('id') || child.isElem('style')) {
if (child.attributes.id != null || child.name === 'style') {
usefulItems.push(child);
child.parentNode = item;
} else {