summaryrefslogtreecommitdiff
path: root/node_modules/svgo/plugins/removeXlink.js
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2023-12-21 22:46:53 +0800
committerlittleblack111 <littleblack11111@gmail.com>2023-12-21 22:46:53 +0800
commitf06956efd2dc4bf77244a9fcce2b883a00b925af (patch)
tree0123cb73ce67f1f4b17e1d6cbabff076ee44e31b /node_modules/svgo/plugins/removeXlink.js
parent8d980c13970c15b6d2312b6fc4ac51698dd0d220 (diff)
updated node modules
Diffstat (limited to 'node_modules/svgo/plugins/removeXlink.js')
-rw-r--r--node_modules/svgo/plugins/removeXlink.js226
1 files changed, 226 insertions, 0 deletions
diff --git a/node_modules/svgo/plugins/removeXlink.js b/node_modules/svgo/plugins/removeXlink.js
new file mode 100644
index 00000000..d341b673
--- /dev/null
+++ b/node_modules/svgo/plugins/removeXlink.js
@@ -0,0 +1,226 @@
+'use strict';
+
+const { elems } = require('./_collections');
+
+/**
+ * @typedef {import('../lib/types').XastElement} XastElement
+ */
+
+exports.name = 'removeXlink';
+exports.description =
+ 'remove xlink namespace and replaces attributes with the SVG 2 equivalent where applicable';
+
+/** URI indicating the Xlink namespace. */
+const XLINK_NAMESPACE = 'http://www.w3.org/1999/xlink';
+
+/**
+ * Map of `xlink:show` values to the SVG 2 `target` attribute values.
+ *
+ * @type {Record<string, string>}
+ * @see https://developer.mozilla.org/docs/Web/SVG/Attribute/xlink:show#usage_notes
+ */
+const SHOW_TO_TARGET = {
+ new: '_blank',
+ replace: '_self',
+};
+
+/**
+ * Elements that use xlink:href, but were deprecated in SVG 2 and therefore
+ * don't support the SVG 2 href attribute.
+ *
+ * @type {string[]}
+ * @see https://developer.mozilla.org/docs/Web/SVG/Attribute/xlink:href
+ * @see https://developer.mozilla.org/docs/Web/SVG/Attribute/href
+ */
+const LEGACY_ELEMENTS = [
+ 'cursor',
+ 'filter',
+ 'font-face-uri',
+ 'glyphRef',
+ 'tref',
+];
+
+/**
+ * @param {XastElement} node
+ * @param {string[]} prefixes
+ * @param {string} attr
+ * @returns {string[]}
+ */
+const findPrefixedAttrs = (node, prefixes, attr) => {
+ return prefixes
+ .map((prefix) => `${prefix}:${attr}`)
+ .filter((attr) => node.attributes[attr] != null);
+};
+
+/**
+ * Removes XLink namespace prefixes and converts references to XLink attributes
+ * to the native SVG equivalent.
+ *
+ * The XLink namespace is deprecated in SVG 2.
+ *
+ * @type {import('./plugins-types').Plugin<'removeXlink'>}
+ * @see https://developer.mozilla.org/docs/Web/SVG/Attribute/xlink:href
+ */
+exports.fn = (_, params) => {
+ const { includeLegacy } = params;
+
+ /**
+ * XLink namespace prefixes that are currently in the stack.
+ *
+ * @type {string[]}
+ */
+ const xlinkPrefixes = [];
+
+ /**
+ * Namespace prefixes that exist in {@link xlinkPrefixes} but were overridden
+ * in a child element to point to another namespace, and so is not treated as
+ * an XLink attribute.
+ *
+ * @type {string[]}
+ */
+ const overriddenPrefixes = [];
+
+ /**
+ * Namespace prefixes that were used in one of the {@link LEGACY_ELEMENTS}.
+ *
+ * @type {string[]}
+ */
+ const usedInLegacyElement = [];
+
+ return {
+ element: {
+ enter: (node) => {
+ for (const [key, value] of Object.entries(node.attributes)) {
+ if (key.startsWith('xmlns:')) {
+ const prefix = key.split(':', 2)[1];
+
+ if (value === XLINK_NAMESPACE) {
+ xlinkPrefixes.push(prefix);
+ continue;
+ }
+
+ if (xlinkPrefixes.includes(prefix)) {
+ overriddenPrefixes.push(prefix);
+ }
+ }
+ }
+
+ if (
+ overriddenPrefixes.some((prefix) => xlinkPrefixes.includes(prefix))
+ ) {
+ return;
+ }
+
+ const showAttrs = findPrefixedAttrs(node, xlinkPrefixes, 'show');
+ let showHandled = node.attributes.target != null;
+ for (let i = showAttrs.length - 1; i >= 0; i--) {
+ const attr = showAttrs[i];
+ const value = node.attributes[attr];
+ const mapping = SHOW_TO_TARGET[value];
+
+ if (showHandled || mapping == null) {
+ delete node.attributes[attr];
+ continue;
+ }
+
+ if (mapping !== elems[node.name]?.defaults?.target) {
+ node.attributes.target = mapping;
+ }
+
+ delete node.attributes[attr];
+ showHandled = true;
+ }
+
+ const titleAttrs = findPrefixedAttrs(node, xlinkPrefixes, 'title');
+ for (let i = titleAttrs.length - 1; i >= 0; i--) {
+ const attr = titleAttrs[i];
+ const value = node.attributes[attr];
+ const hasTitle = node.children.filter(
+ (child) => child.type === 'element' && child.name === 'title'
+ );
+
+ if (hasTitle.length > 0) {
+ delete node.attributes[attr];
+ continue;
+ }
+
+ /** @type {XastElement} */
+ const titleTag = {
+ type: 'element',
+ name: 'title',
+ attributes: {},
+ children: [
+ {
+ type: 'text',
+ value,
+ },
+ ],
+ };
+
+ Object.defineProperty(titleTag, 'parentNode', {
+ writable: true,
+ value: node,
+ });
+
+ node.children.unshift(titleTag);
+ delete node.attributes[attr];
+ }
+
+ const hrefAttrs = findPrefixedAttrs(node, xlinkPrefixes, 'href');
+
+ if (
+ hrefAttrs.length > 0 &&
+ LEGACY_ELEMENTS.includes(node.name) &&
+ !includeLegacy
+ ) {
+ hrefAttrs
+ .map((attr) => attr.split(':', 1)[0])
+ .forEach((prefix) => usedInLegacyElement.push(prefix));
+ return;
+ }
+
+ for (let i = hrefAttrs.length - 1; i >= 0; i--) {
+ const attr = hrefAttrs[i];
+ const value = node.attributes[attr];
+
+ if (node.attributes.href != null) {
+ delete node.attributes[attr];
+ continue;
+ }
+
+ node.attributes.href = value;
+ delete node.attributes[attr];
+ }
+ },
+ exit: (node) => {
+ for (const [key, value] of Object.entries(node.attributes)) {
+ const [prefix, attr] = key.split(':', 2);
+
+ if (
+ xlinkPrefixes.includes(prefix) &&
+ !overriddenPrefixes.includes(prefix) &&
+ !usedInLegacyElement.includes(prefix) &&
+ !includeLegacy
+ ) {
+ delete node.attributes[key];
+ continue;
+ }
+
+ if (key.startsWith('xmlns:') && !usedInLegacyElement.includes(attr)) {
+ if (value === XLINK_NAMESPACE) {
+ const index = xlinkPrefixes.indexOf(attr);
+ xlinkPrefixes.splice(index, 1);
+ delete node.attributes[key];
+ continue;
+ }
+
+ if (overriddenPrefixes.includes(prefix)) {
+ const index = overriddenPrefixes.indexOf(attr);
+ overriddenPrefixes.splice(index, 1);
+ }
+ }
+ }
+ },
+ },
+ };
+};