summaryrefslogtreecommitdiff
path: root/node_modules/svgo/plugins/removeHiddenElems.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/svgo/plugins/removeHiddenElems.js')
-rw-r--r--node_modules/svgo/plugins/removeHiddenElems.js440
1 files changed, 0 insertions, 440 deletions
diff --git a/node_modules/svgo/plugins/removeHiddenElems.js b/node_modules/svgo/plugins/removeHiddenElems.js
deleted file mode 100644
index 75720a06..00000000
--- a/node_modules/svgo/plugins/removeHiddenElems.js
+++ /dev/null
@@ -1,440 +0,0 @@
-'use strict';
-
-/**
- * @typedef {import('../lib/types').XastChild} XastChild
- * @typedef {import('../lib/types').XastElement} XastElement
- * @typedef {import('../lib/types').XastParent} XastParent
- */
-
-const { elemsGroups } = require('./_collections.js');
-const {
- visit,
- visitSkip,
- querySelector,
- detachNodeFromParent,
-} = require('../lib/xast.js');
-const { collectStylesheet, computeStyle } = require('../lib/style.js');
-const { parsePathData } = require('../lib/path.js');
-const { hasScripts, findReferences } = require('../lib/svgo/tools.js');
-
-const nonRendering = elemsGroups.nonRendering;
-
-exports.name = 'removeHiddenElems';
-exports.description =
- 'removes hidden elements (zero sized, with absent attributes)';
-
-/**
- * Remove hidden elements with disabled rendering:
- * - display="none"
- * - opacity="0"
- * - circle with zero radius
- * - ellipse with zero x-axis or y-axis radius
- * - rectangle with zero width or height
- * - pattern with zero width or height
- * - image with zero width or height
- * - path with empty data
- * - polyline with empty points
- * - polygon with empty points
- *
- * @author Kir Belevich
- *
- * @type {import('./plugins-types').Plugin<'removeHiddenElems'>}
- */
-exports.fn = (root, params) => {
- const {
- isHidden = true,
- displayNone = true,
- opacity0 = true,
- circleR0 = true,
- ellipseRX0 = true,
- ellipseRY0 = true,
- rectWidth0 = true,
- rectHeight0 = true,
- patternWidth0 = true,
- patternHeight0 = true,
- imageWidth0 = true,
- imageHeight0 = true,
- pathEmptyD = true,
- polylineEmptyPoints = true,
- polygonEmptyPoints = true,
- } = params;
- const stylesheet = collectStylesheet(root);
-
- /**
- * Skip non-rendered nodes initially, and only detach if they have no ID, or
- * their ID is not referenced by another node.
- *
- * @type {Map<XastElement, XastParent>}
- */
- const nonRenderedNodes = new Map();
-
- /**
- * IDs for removed hidden definitions.
- *
- * @type {Set<string>}
- */
- const removedDefIds = new Set();
-
- /**
- * @type {Map<XastElement, XastParent>}
- */
- const allDefs = new Map();
-
- /** @type {Set<string>} */
- const allReferences = new Set();
-
- /**
- * @type {Map<string, Array<{ node: XastElement, parentNode: XastParent }>>}
- */
- const referencesById = new Map();
-
- /**
- * If styles are present, we can't be sure if a definition is unused or not
- */
- let deoptimized = false;
-
- /**
- * @param {XastChild} node
- * @param {XastParent} parentNode
- */
- function removeElement(node, parentNode) {
- if (
- node.type === 'element' &&
- node.attributes.id != null &&
- parentNode.type === 'element' &&
- parentNode.name === 'defs'
- ) {
- removedDefIds.add(node.attributes.id);
- }
-
- detachNodeFromParent(node, parentNode);
- }
-
- visit(root, {
- element: {
- enter: (node, parentNode) => {
- // transparent non-rendering elements still apply where referenced
- if (nonRendering.has(node.name)) {
- if (node.attributes.id == null) {
- detachNodeFromParent(node, parentNode);
- return visitSkip;
- }
-
- nonRenderedNodes.set(node, parentNode);
- return visitSkip;
- }
- const computedStyle = computeStyle(stylesheet, node);
- // opacity="0"
- //
- // https://www.w3.org/TR/SVG11/masking.html#ObjectAndGroupOpacityProperties
- if (
- opacity0 &&
- computedStyle.opacity &&
- computedStyle.opacity.type === 'static' &&
- computedStyle.opacity.value === '0'
- ) {
- removeElement(node, parentNode);
- }
- },
- },
- });
-
- return {
- element: {
- enter: (node, parentNode) => {
- if (
- (node.name === 'style' && node.children.length !== 0) ||
- hasScripts(node)
- ) {
- deoptimized = true;
- return;
- }
-
- if (node.name === 'defs') {
- allDefs.set(node, parentNode);
- }
-
- if (node.name === 'use') {
- for (const attr of Object.keys(node.attributes)) {
- if (attr !== 'href' && !attr.endsWith(':href')) continue;
- const value = node.attributes[attr];
- const id = value.slice(1);
-
- let refs = referencesById.get(id);
- if (!refs) {
- refs = [];
- referencesById.set(id, refs);
- }
- refs.push({ node, parentNode });
- }
- }
-
- // Removes hidden elements
- // https://www.w3schools.com/cssref/pr_class_visibility.asp
- const computedStyle = computeStyle(stylesheet, node);
- if (
- isHidden &&
- computedStyle.visibility &&
- computedStyle.visibility.type === 'static' &&
- computedStyle.visibility.value === 'hidden' &&
- // keep if any descendant enables visibility
- querySelector(node, '[visibility=visible]') == null
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // display="none"
- //
- // https://www.w3.org/TR/SVG11/painting.html#DisplayProperty
- // "A value of display: none indicates that the given element
- // and its children shall not be rendered directly"
- if (
- displayNone &&
- computedStyle.display &&
- computedStyle.display.type === 'static' &&
- computedStyle.display.value === 'none' &&
- // markers with display: none still rendered
- node.name !== 'marker'
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // Circles with zero radius
- //
- // https://www.w3.org/TR/SVG11/shapes.html#CircleElementRAttribute
- // "A value of zero disables rendering of the element"
- //
- // <circle r="0">
- if (
- circleR0 &&
- node.name === 'circle' &&
- node.children.length === 0 &&
- node.attributes.r === '0'
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // Ellipse with zero x-axis radius
- //
- // https://www.w3.org/TR/SVG11/shapes.html#EllipseElementRXAttribute
- // "A value of zero disables rendering of the element"
- //
- // <ellipse rx="0">
- if (
- ellipseRX0 &&
- node.name === 'ellipse' &&
- node.children.length === 0 &&
- node.attributes.rx === '0'
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // Ellipse with zero y-axis radius
- //
- // https://www.w3.org/TR/SVG11/shapes.html#EllipseElementRYAttribute
- // "A value of zero disables rendering of the element"
- //
- // <ellipse ry="0">
- if (
- ellipseRY0 &&
- node.name === 'ellipse' &&
- node.children.length === 0 &&
- node.attributes.ry === '0'
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // Rectangle with zero width
- //
- // https://www.w3.org/TR/SVG11/shapes.html#RectElementWidthAttribute
- // "A value of zero disables rendering of the element"
- //
- // <rect width="0">
- if (
- rectWidth0 &&
- node.name === 'rect' &&
- node.children.length === 0 &&
- node.attributes.width === '0'
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // Rectangle with zero height
- //
- // https://www.w3.org/TR/SVG11/shapes.html#RectElementHeightAttribute
- // "A value of zero disables rendering of the element"
- //
- // <rect height="0">
- if (
- rectHeight0 &&
- rectWidth0 &&
- node.name === 'rect' &&
- node.children.length === 0 &&
- node.attributes.height === '0'
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // Pattern with zero width
- //
- // https://www.w3.org/TR/SVG11/pservers.html#PatternElementWidthAttribute
- // "A value of zero disables rendering of the element (i.e., no paint is applied)"
- //
- // <pattern width="0">
- if (
- patternWidth0 &&
- node.name === 'pattern' &&
- node.attributes.width === '0'
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // Pattern with zero height
- //
- // https://www.w3.org/TR/SVG11/pservers.html#PatternElementHeightAttribute
- // "A value of zero disables rendering of the element (i.e., no paint is applied)"
- //
- // <pattern height="0">
- if (
- patternHeight0 &&
- node.name === 'pattern' &&
- node.attributes.height === '0'
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // Image with zero width
- //
- // https://www.w3.org/TR/SVG11/struct.html#ImageElementWidthAttribute
- // "A value of zero disables rendering of the element"
- //
- // <image width="0">
- if (
- imageWidth0 &&
- node.name === 'image' &&
- node.attributes.width === '0'
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // Image with zero height
- //
- // https://www.w3.org/TR/SVG11/struct.html#ImageElementHeightAttribute
- // "A value of zero disables rendering of the element"
- //
- // <image height="0">
- if (
- imageHeight0 &&
- node.name === 'image' &&
- node.attributes.height === '0'
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // Path with empty data
- //
- // https://www.w3.org/TR/SVG11/paths.html#DAttribute
- //
- // <path d=""/>
- if (pathEmptyD && node.name === 'path') {
- if (node.attributes.d == null) {
- removeElement(node, parentNode);
- return;
- }
- const pathData = parsePathData(node.attributes.d);
- if (pathData.length === 0) {
- removeElement(node, parentNode);
- return;
- }
- // keep single point paths for markers
- if (
- pathData.length === 1 &&
- computedStyle['marker-start'] == null &&
- computedStyle['marker-end'] == null
- ) {
- removeElement(node, parentNode);
- return;
- }
- }
-
- // Polyline with empty points
- //
- // https://www.w3.org/TR/SVG11/shapes.html#PolylineElementPointsAttribute
- //
- // <polyline points="">
- if (
- polylineEmptyPoints &&
- node.name === 'polyline' &&
- node.attributes.points == null
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- // Polygon with empty points
- //
- // https://www.w3.org/TR/SVG11/shapes.html#PolygonElementPointsAttribute
- //
- // <polygon points="">
- if (
- polygonEmptyPoints &&
- node.name === 'polygon' &&
- node.attributes.points == null
- ) {
- removeElement(node, parentNode);
- return;
- }
-
- for (const [name, value] of Object.entries(node.attributes)) {
- const ids = findReferences(name, value);
-
- for (const id of ids) {
- allReferences.add(id);
- }
- }
- },
- },
- root: {
- exit: () => {
- for (const id of removedDefIds) {
- const refs = referencesById.get(id);
- if (refs) {
- for (const { node, parentNode } of refs) {
- detachNodeFromParent(node, parentNode);
- }
- }
- }
-
- if (!deoptimized) {
- for (const [
- nonRenderedNode,
- nonRenderedParent,
- ] of nonRenderedNodes.entries()) {
- const id = nonRenderedNode.attributes.id;
-
- if (!allReferences.has(id)) {
- detachNodeFromParent(nonRenderedNode, nonRenderedParent);
- }
- }
- }
-
- for (const [node, parentNode] of allDefs.entries()) {
- if (node.children.length === 0) {
- detachNodeFromParent(node, parentNode);
- }
- }
- },
- },
- };
-};