UNPKG

@spiriit/vite-plugin-svg-spritemap

Version:

Generates symbol-based SVG spritemap from all .svg files in a directory

2,460 lines (2,458 loc) 110 kB
import path, { basename, dirname, parse, posix, relative, resolve } from "node:path"; import hash_sum from "hash-sum"; import { promises } from "node:fs"; import { DOMImplementation, DOMParser, XMLSerializer } from "@xmldom/xmldom"; import { glob } from "tinyglobby"; import svgToMiniDataURI from "mini-svg-data-uri"; import picomatch from "picomatch"; //#region src/helpers/options.ts function createOptions(options = {}) { const logs = { warn: [] }; let prefix = "sprite-"; if (options.prefix === false) prefix = ""; else if (typeof options.prefix === "string") prefix = options.prefix; let styles = false; const stylesLang = [ "css", "scss", "less", "styl" ]; if (typeof options.styles === "string") { let lang = options.styles.split(".").pop(); if (typeof lang === "undefined" || !stylesLang.includes(lang)) { lang = "css"; logs.warn.push("Invalid styles lang, fallback to css"); } styles = { filename: options.styles, lang, include: true, names: { prefix: "sprites-prefix", sprites: "sprites", mixin: "sprite" }, sizes: { unit: "px", base: 1 } }; } else if (typeof options.styles === "object" && typeof options.styles.filename === "string") { const stylesNames = { prefix: options.styles.names?.prefix || "sprites-prefix", sprites: options.styles.names?.sprites || "sprites", mixin: options.styles.names?.mixin || "sprite" }; const stylesSizes = { unit: options.styles.sizes?.unit || "px", base: options.styles.sizes?.base || 1 }; let lang = options.styles.filename.split(".").pop(); if (typeof lang === "undefined" || !stylesLang.includes(lang)) { lang = "css"; logs.warn.push("Invalid styles lang, fallback to css"); } styles = { filename: options.styles.filename, lang, include: typeof options.styles.include === "undefined" ? true : options.styles.include, names: stylesNames, sizes: stylesSizes, callback: options.styles.callback }; } let output = { filename: "[name].[hash][extname]", name: "spritemap.svg", use: true, view: true }; if (options.output === false) output = false; else if (typeof options.output === "string") output.filename = options.output; else if (typeof options.output === "object") output = { filename: options.output.filename || output.filename, name: options.output.name || output.name, use: typeof options.output.use !== "undefined" ? options.output.use : output.use, view: typeof options.output.view !== "undefined" ? options.output.view : output.view }; const injectSvgOnDev = options.injectSvgOnDev || options.injectSVGOnDev || false; let idify = (name) => name; if (typeof options.idify === "function") idify = options.idify; const route = { url: "/__spritemap", name: "spritemap" }; if (typeof options.route === "string") { route.url = options.route; route.name = route.url.startsWith("/") ? options.route.slice(1) : options.route; } else if (typeof options.route === "object" && options.route.url) { route.url = options.route.url || route.url; route.name = options.route.name || (route.url.startsWith("/") ? options.route.url.slice(1) : options.route.url); } if (!route.url.startsWith("/")) { logs.warn.push(`Route option ${route.url} should start with a leading slash, automatically added.`); route.url = `/${route.url}`; } const gutter = options.gutter || 0; const types = typeof options.types === "string" ? options.types : false; return { options: { svgo: options.svgo, oxvg: options.oxvg, output, prefix, styles, types, injectSvgOnDev, idify, route, gutter }, logs }; } //#endregion //#region src/helpers/filename.ts const hashPattern = /\[hash\]/g; const extPattern = /\[ext\]/g; const extnamePattern = /\[extname\]/g; const namePattern = /\[name\]/g; function getFileName(fileName, name, content, ext) { const hash = hash_sum(content); fileName = fileName.replace(hashPattern, hash); fileName = fileName.replace(extPattern, ext); fileName = fileName.replace(extnamePattern, `.${ext}`); fileName = fileName.replace(namePattern, name); return fileName; } //#endregion //#region src/plugins/build.ts function BuildPlugin(shared) { let fileRef; let fileName; let config; const pluginExternal = new RegExp(shared.options.route.url); const spritemapFilter = new RegExp(shared.options.route.url, "g"); return { name: "vite-plugin-svg-spritemap:build", apply: "build", config(config) { const configExternal = config.build?.rollupOptions?.external; let finalExternal = pluginExternal; if (Array.isArray(configExternal)) { configExternal.push(pluginExternal); finalExternal = configExternal; } else if (typeof configExternal === "string" || typeof configExternal === "object") finalExternal = [configExternal, pluginExternal]; else if (typeof configExternal === "function") finalExternal = (source, importer, isResolved) => { if (pluginExternal.test(source)) return true; return configExternal(source, importer, isResolved); }; return { build: { rollupOptions: { external: finalExternal } } }; }, configResolved(_config) { config = _config; }, async buildStart() { /* v8 ignore if -- @preserve */ if (!shared.svgManager) return; await shared.svgManager.updateAll(); if (typeof shared.options.output === "object") { fileName = getFileName(shared.options.output.filename, "spritemap", shared.svgManager.spritemap, "svg"); const filePath = posix.join(config.build.assetsDir, fileName); fileRef = this.emitFile({ type: "asset", needsCodeReference: false, name: shared.options.output.name, source: shared.svgManager.spritemap, fileName: filePath, originalFileName: shared.options.output.name }); } }, transform: { filter: { code: spritemapFilter }, handler(code) { if (!spritemapFilter.test(code) || typeof shared.options.output !== "object") return; const base = config.base.startsWith(".") ? config.base.substring(1) : config.base; return { code: code.replace(spritemapFilter, posix.join(base, this.getFileName(fileRef))), map: null }; } } }; } //#endregion //#region node_modules/.pnpm/kolorist@1.8.0/node_modules/kolorist/dist/esm/index.mjs let enabled = true; const globalVar = typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {}; /** * Detect how much colors the current terminal supports */ let supportLevel = 0; if (globalVar.process && globalVar.process.env && globalVar.process.stdout) { const { FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM, COLORTERM } = globalVar.process.env; if (NODE_DISABLE_COLORS || NO_COLOR || FORCE_COLOR === "0") enabled = false; else if (FORCE_COLOR === "1" || FORCE_COLOR === "2" || FORCE_COLOR === "3") enabled = true; else if (TERM === "dumb") enabled = false; else if ("CI" in globalVar.process.env && [ "TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE", "DRONE" ].some((vendor) => vendor in globalVar.process.env)) enabled = true; else enabled = process.stdout.isTTY; if (enabled) if (process.platform === "win32") supportLevel = 3; else if (COLORTERM && (COLORTERM === "truecolor" || COLORTERM === "24bit")) supportLevel = 3; else if (TERM && (TERM.endsWith("-256color") || TERM.endsWith("256"))) supportLevel = 2; else supportLevel = 1; } let options = { enabled, supportLevel }; function kolorist(start, end, level = 1) { const open = `\x1b[${start}m`; const close = `\x1b[${end}m`; const regex = new RegExp(`\\x1b\\[${end}m`, "g"); return (str) => { return options.enabled && options.supportLevel >= level ? open + ("" + str).replace(regex, open) + close : "" + str; }; } kolorist(0, 0); const bold = kolorist(1, 22); kolorist(2, 22); kolorist(3, 23); kolorist(4, 24); kolorist(7, 27); kolorist(8, 28); kolorist(9, 29); kolorist(30, 39); kolorist(31, 39); kolorist(32, 39); kolorist(33, 39); const blue = kolorist(34, 39); kolorist(35, 39); kolorist(36, 39); kolorist(97, 39); kolorist(90, 39); kolorist(37, 39); kolorist(91, 39); kolorist(92, 39); kolorist(93, 39); kolorist(94, 39); kolorist(95, 39); kolorist(96, 39); kolorist(40, 49); kolorist(41, 49); kolorist(42, 49); kolorist(43, 49); kolorist(44, 49); kolorist(45, 49); kolorist(46, 49); kolorist(107, 49); kolorist(100, 49); kolorist(101, 49); kolorist(102, 49); kolorist(103, 49); kolorist(104, 49); kolorist(105, 49); kolorist(106, 49); kolorist(47, 49); //#endregion //#region src/helpers/log.ts function logMessage(message) { return `${bold(blue("[vite-plugin-svg-spritemap]"))} ${message}`; } /** * Logs a message to the console with a standardized prefix. * @param obj - The log object containing level, message, and logger. * @param obj.level - The log level ('info', 'warn', 'error'). * @param obj.message - The message to log. * @param obj.logger - The Vite logger instance. */ function log(obj) { obj.logger[obj.level](logMessage(obj.message)); } //#endregion //#region src/helpers/oxvg.ts /** * Get OXVG Options */ function getOptions$1(oxvgOptions) { let svgo = {}; if (typeof oxvgOptions === "object") svgo = oxvgOptions; else if (oxvgOptions === false) svgo = void 0; return svgo; } /** * Get SVGO Optimize function */ async function getOptimize$1(logger) { try { const { optimise } = await import("@oxvg/napi"); return optimise; } catch (error) { if (error.code !== "ERR_MODULE_NOT_FOUND") log({ level: "error", message: `Error when loading OXVG: ${error.message}`, logger }); return false; } } //#endregion //#region src/helpers/svgo.ts /** * Get SVGO Options */ function getOptions(svgoOptions, prefix) { let svgo = { plugins: [{ name: "preset-default", params: { overrides: { removeEmptyAttrs: false, moveGroupAttrsToElems: false, collapseGroups: false, cleanupIds: { preservePrefixes: [prefix] } } } }] }; if (typeof svgoOptions === "object") svgo = svgoOptions; else if (svgoOptions === false) svgo = void 0; return svgo; } /** * Get SVGO Optimize function */ async function getOptimize() { try { const { optimize } = await import("svgo"); return optimize; } catch { return false; } } //#endregion //#region src/core/styles.ts var Styles = class { constructor(svgs, options, routeUrl) { this._svgs = /* @__PURE__ */ new Map(); this._options = options; this._routeUrl = routeUrl; svgs.forEach((svg, filePath) => { const svgDataUri = svgToMiniDataURI(svg.source); this._svgs.set(filePath, { id: svg.id, width: svg.width, height: svg.height, viewbox: svg.viewBox, svgDataUri }); }); } createSpriteMap(generator) { let spriteMap = ""; let index = 1; this._svgs.forEach((svg) => { spriteMap += `${generator(svg, index === this._svgs.size)}\n`; index++; }); return spriteMap; } formatSize(value) { if (!this._options.styles) return `${value}px`; const { unit, base } = this._options.styles.sizes; return `${value / base}${unit}`; } async insert(insert) { if (!this._options.styles || this._options.styles.include === false) return ""; let template = ""; if (this._options.styles.lang !== "css" && (this._options.styles.include === true || this._options.styles.include.includes("mixin"))) { const templateFileName = `template.${this._options.styles.lang}`; const currentDir = import.meta.dirname; const templatePath = path.join(currentDir, "./styles", templateFileName); template = await promises.readFile(templatePath, "utf8"); } const findAndReplaceObject = { mixin: this._options.styles.names.mixin, route: this._routeUrl, prefix: this._options.styles.names.prefix, sprites: this._options.styles.names.sprites }; for (const [key, value] of Object.entries(findAndReplaceObject)) template = template.replace(`__${key}__`, value); return `${"/* Generated by vite-plugin-svg-spritemap */\n\n" + insert}\n${template}`; } _generate_scss() { if (!this._options.styles || this._options.styles.include === false || Array.isArray(this._options.styles.include) && !this._options.styles.include.includes("variables")) return ""; let insert = `$${this._options.styles.names.prefix}: '${this._options.prefix}';\n`; insert += `$${this._options.styles.names.sprites}: (\n`; insert += this.createSpriteMap((svg, isLast) => { let sprite = ""; sprite = `\t'${svg.id}': (`; sprite += `\n\t\turi: "${svg.svgDataUri}",`; sprite += `\n\t\twidth: ${this.formatSize(svg.width)},`; sprite += `\n\t\theight: ${this.formatSize(svg.height)}`; sprite += `\n\t${!isLast ? ")," : ")"}`; return sprite; }); insert += ");\n"; return insert; } _generate_styl() { if (!this._options.styles || this._options.styles.include === false || Array.isArray(this._options.styles.include) && !this._options.styles.include.includes("variables")) return ""; let insert = `$${this._options.styles.names.prefix} = '${this._options.prefix}'\n`; insert += `$${this._options.styles.names.sprites} = {\n`; insert += this.createSpriteMap((svg, isLast) => { let sprite = ""; sprite = `\t'${svg.id}': {`; sprite += `\n\t\turi: "${svg.svgDataUri}",`; sprite += `\n\t\twidth: ${this.formatSize(svg.width)},`; sprite += `\n\t\theight: ${this.formatSize(svg.height)}`; sprite += `\n\t${!isLast ? "}," : "}"}`; return sprite; }); insert += "}\n"; return insert; } _generate_less() { if (!this._options.styles || this._options.styles.include === false || Array.isArray(this._options.styles.include) && !this._options.styles.include.includes("variables")) return ""; let insert = `@${this._options.styles.names.prefix}: '${this._options.prefix}';\n`; insert += `@${this._options.styles.names.sprites}: {\n`; insert += this.createSpriteMap((svg) => { let sprite = ""; sprite = `\t@${svg.id}: {`; sprite += `\n\t\turi: "${svg.svgDataUri}";`; sprite += `\n\t\twidth: ${this.formatSize(svg.width)};`; sprite += `\n\t\theight: ${this.formatSize(svg.height)};`; sprite += "\n };"; return sprite; }); insert += "}\n"; return insert; } _generate_css() { let insert = ""; if (!this._options.styles || this._options.styles.include === false) return insert; if (this._options.styles.include === true || this._options.styles.include.includes("bg")) insert = this.createSpriteMap((svg) => { const selector = `.${this._options.prefix + svg.id}`; let sprite = ""; sprite = `${selector} {`; sprite += `\n\tbackground: url("${svg.svgDataUri}") center no-repeat;`; sprite += "\n}"; return sprite; }); if (this._options.styles.include === true || this._options.styles.include.includes("mask")) insert += this.createSpriteMap((svg) => { const selector = `.${this._options.prefix + svg.id}-mask`; let sprite = ""; sprite = `${selector} {`; sprite += `\n\tmask: url("${svg.svgDataUri}") center no-repeat;`; sprite += "\n}"; return sprite; }); if (this._options.styles.include === true || this._options.styles.include.includes("bg-frag")) { if (this._options.output && this._options.output.view) insert += this.createSpriteMap((svg) => { const selector = `.${this._options.prefix + svg.id}-frag`; let sprite = ""; sprite = `${selector} {`; sprite += `\n\tbackground: url('${this._routeUrl}#${this._options.prefix + svg.id}-view') center no-repeat;`; sprite += "\n}"; return sprite; }); } return insert; } async generate() { if (!this._options.styles) return ""; let insert; switch (this._options.styles.lang) { case "scss": insert = this._generate_scss(); break; case "styl": insert = this._generate_styl(); break; case "less": insert = this._generate_less(); break; default: insert = this._generate_css(); } if (this._options.styles.callback) insert = this._options.styles.callback({ content: insert, options: this._options, createSpritemap: this.createSpriteMap.bind(this) }); return await this.insert(insert); } }; //#endregion //#region src/core/types.ts var Types = class { constructor(svgs, options) { this._svgs = svgs; this._options = options; } /** * Generate TypeScript type definition string * @returns TypeScript type definition content */ generate() { if (!this._options.types) return ""; const iconIds = Array.from(this._svgs.values()).map((svg) => svg.id).sort(); if (iconIds.length === 0) return `// Generated by vite-plugin-svg-spritemap export type Icons = never; export type Prefix = '${this._options.prefix}'; export type IconsPrefixed = never;`; return `// Generated by vite-plugin-svg-spritemap export type Icons = ${iconIds.map((id) => `'${id}'`).join(" | ")}; export type Prefix = '${this._options.prefix}'; export type IconsPrefixed = \`\${Prefix}\${Icons}\`; `; } }; //#endregion //#region src/helpers/calculateY.ts function calculateY(heights = [], gutter = 0) { return heights.reduce((a, b) => a + b, 0) + heights.length * gutter; } //#endregion //#region node_modules/.pnpm/svg-element-attributes@2.1.0/node_modules/svg-element-attributes/index.js /** * Map of SVG elements to allowed attributes. * * @type {Record<string, Array<string>>} */ const svgElementAttributes = { "*": [ "about", "class", "content", "datatype", "id", "lang", "property", "rel", "resource", "rev", "style", "tabindex", "typeof" ], a: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "download", "enable-background", "externalResourcesRequired", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "focusHighlight", "focusable", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "href", "hreflang", "image-rendering", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "nav-down", "nav-down-left", "nav-down-right", "nav-left", "nav-next", "nav-prev", "nav-right", "nav-up", "nav-up-left", "nav-up-right", "opacity", "overflow", "ping", "pointer-events", "referrerpolicy", "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemLanguage", "target", "text-anchor", "text-decoration", "text-rendering", "transform", "type", "unicode-bidi", "visibility", "word-spacing", "writing-mode" ], altGlyph: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "dx", "dy", "enable-background", "externalResourcesRequired", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "format", "glyph-orientation-horizontal", "glyph-orientation-vertical", "glyphRef", "image-rendering", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "requiredExtensions", "requiredFeatures", "rotate", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemLanguage", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "word-spacing", "writing-mode", "x", "y" ], altGlyphDef: [], altGlyphItem: [], animate: [ "accumulate", "additive", "alignment-baseline", "attributeName", "attributeType", "baseline-shift", "begin", "by", "calcMode", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "dur", "enable-background", "end", "externalResourcesRequired", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "from", "glyph-orientation-horizontal", "glyph-orientation-vertical", "href", "image-rendering", "kerning", "keySplines", "keyTimes", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "max", "min", "opacity", "overflow", "pointer-events", "repeatCount", "repeatDur", "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "restart", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemLanguage", "text-anchor", "text-decoration", "text-rendering", "to", "unicode-bidi", "values", "visibility", "word-spacing", "writing-mode" ], animateColor: [ "accumulate", "additive", "alignment-baseline", "attributeName", "attributeType", "baseline-shift", "begin", "by", "calcMode", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "dur", "enable-background", "end", "externalResourcesRequired", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "from", "glyph-orientation-horizontal", "glyph-orientation-vertical", "image-rendering", "kerning", "keySplines", "keyTimes", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "max", "min", "opacity", "overflow", "pointer-events", "repeatCount", "repeatDur", "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "restart", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemLanguage", "text-anchor", "text-decoration", "text-rendering", "to", "unicode-bidi", "values", "visibility", "word-spacing", "writing-mode" ], animateMotion: [ "accumulate", "additive", "begin", "by", "calcMode", "dur", "end", "externalResourcesRequired", "fill", "from", "href", "keyPoints", "keySplines", "keyTimes", "max", "min", "origin", "path", "repeatCount", "repeatDur", "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "restart", "rotate", "systemLanguage", "to", "values" ], animateTransform: [ "accumulate", "additive", "attributeName", "attributeType", "begin", "by", "calcMode", "dur", "end", "externalResourcesRequired", "fill", "from", "href", "keySplines", "keyTimes", "max", "min", "repeatCount", "repeatDur", "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "restart", "systemLanguage", "to", "type", "values" ], animation: [ "begin", "dur", "end", "externalResourcesRequired", "fill", "focusHighlight", "focusable", "height", "initialVisibility", "max", "min", "nav-down", "nav-down-left", "nav-down-right", "nav-left", "nav-next", "nav-prev", "nav-right", "nav-up", "nav-up-left", "nav-up-right", "preserveAspectRatio", "repeatCount", "repeatDur", "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "restart", "syncBehavior", "syncMaster", "syncTolerance", "systemLanguage", "transform", "width", "x", "y" ], audio: [ "begin", "dur", "end", "externalResourcesRequired", "fill", "max", "min", "repeatCount", "repeatDur", "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "restart", "syncBehavior", "syncMaster", "syncTolerance", "systemLanguage", "type" ], canvas: [ "preserveAspectRatio", "requiredExtensions", "systemLanguage" ], circle: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "cx", "cy", "direction", "display", "dominant-baseline", "enable-background", "externalResourcesRequired", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "focusHighlight", "focusable", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "image-rendering", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "nav-down", "nav-down-left", "nav-down-right", "nav-left", "nav-next", "nav-prev", "nav-right", "nav-up", "nav-up-left", "nav-up-right", "opacity", "overflow", "pathLength", "pointer-events", "r", "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemLanguage", "text-anchor", "text-decoration", "text-rendering", "transform", "unicode-bidi", "visibility", "word-spacing", "writing-mode" ], clipPath: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "clipPathUnits", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "externalResourcesRequired", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "image-rendering", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "requiredExtensions", "requiredFeatures", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemLanguage", "text-anchor", "text-decoration", "text-rendering", "transform", "unicode-bidi", "visibility", "word-spacing", "writing-mode" ], "color-profile": [ "local", "name", "rendering-intent" ], cursor: [ "externalResourcesRequired", "requiredExtensions", "requiredFeatures", "systemLanguage", "x", "y" ], defs: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "externalResourcesRequired", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "image-rendering", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "requiredExtensions", "requiredFeatures", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemLanguage", "text-anchor", "text-decoration", "text-rendering", "transform", "unicode-bidi", "visibility", "word-spacing", "writing-mode" ], desc: [ "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "systemLanguage" ], discard: [ "begin", "href", "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "systemLanguage" ], ellipse: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "cx", "cy", "direction", "display", "dominant-baseline", "enable-background", "externalResourcesRequired", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "focusHighlight", "focusable", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "image-rendering", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "nav-down", "nav-down-left", "nav-down-right", "nav-left", "nav-next", "nav-prev", "nav-right", "nav-up", "nav-up-left", "nav-up-right", "opacity", "overflow", "pathLength", "pointer-events", "requiredExtensions", "requiredFeatures", "requiredFonts", "requiredFormats", "rx", "ry", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemLanguage", "text-anchor", "text-decoration", "text-rendering", "transform", "unicode-bidi", "visibility", "word-spacing", "writing-mode" ], feBlend: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "in2", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "mode", "opacity", "overflow", "pointer-events", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feColorMatrix: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "type", "unicode-bidi", "values", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feComponentTransfer: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feComposite: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "in2", "k1", "k2", "k3", "k4", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "operator", "overflow", "pointer-events", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feConvolveMatrix: [ "alignment-baseline", "baseline-shift", "bias", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "divisor", "dominant-baseline", "edgeMode", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "kernelMatrix", "kernelUnitLength", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "order", "overflow", "pointer-events", "preserveAlpha", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "targetX", "targetY", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feDiffuseLighting: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "diffuseConstant", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "kernelUnitLength", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "surfaceScale", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feDisplacementMap: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "in2", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "result", "scale", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "xChannelSelector", "y", "yChannelSelector" ], feDistantLight: ["azimuth", "elevation"], feDropShadow: [ "dx", "dy", "height", "in", "result", "stdDeviation", "width", "x", "y" ], feFlood: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feFuncA: [ "amplitude", "exponent", "intercept", "offset", "slope", "tableValues", "type" ], feFuncB: [ "amplitude", "exponent", "intercept", "offset", "slope", "tableValues", "type" ], feFuncG: [ "amplitude", "exponent", "intercept", "offset", "slope", "tableValues", "type" ], feFuncR: [ "amplitude", "exponent", "intercept", "offset", "slope", "tableValues", "type" ], feGaussianBlur: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "edgeMode", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "result", "shape-rendering", "stdDeviation", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feImage: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "crossorigin", "cursor", "direction", "display", "dominant-baseline", "enable-background", "externalResourcesRequired", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "href", "image-rendering", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "preserveAspectRatio", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feMerge: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feMergeNode: ["in"], feMorphology: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "operator", "overflow", "pointer-events", "radius", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feOffset: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "dx", "dy", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], fePointLight: [ "x", "y", "z" ], feSpecularLighting: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "kernelUnitLength", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "result", "shape-rendering", "specularConstant", "specularExponent", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "surfaceScale", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feSpotLight: [ "limitingConeAngle", "pointsAtX", "pointsAtY", "pointsAtZ", "specularExponent", "x", "y", "z" ], feTile: [ "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "height", "image-rendering", "in", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "result", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "unicode-bidi", "visibility", "width", "word-spacing", "writing-mode", "x", "y" ], feTurbulence: [ "alignment-baseline", "baseFrequency", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity",