summaryrefslogtreecommitdiff
path: root/node_modules/postcss-svgo/src
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/postcss-svgo/src')
-rw-r--r--node_modules/postcss-svgo/src/globals.d.ts1
-rw-r--r--node_modules/postcss-svgo/src/index.js140
-rw-r--r--node_modules/postcss-svgo/src/lib/url.js18
3 files changed, 159 insertions, 0 deletions
diff --git a/node_modules/postcss-svgo/src/globals.d.ts b/node_modules/postcss-svgo/src/globals.d.ts
new file mode 100644
index 00000000..731c4638
--- /dev/null
+++ b/node_modules/postcss-svgo/src/globals.d.ts
@@ -0,0 +1 @@
+declare var URL: typeof import('url').URL;
diff --git a/node_modules/postcss-svgo/src/index.js b/node_modules/postcss-svgo/src/index.js
new file mode 100644
index 00000000..a40850c8
--- /dev/null
+++ b/node_modules/postcss-svgo/src/index.js
@@ -0,0 +1,140 @@
+'use strict';
+const valueParser = require('postcss-value-parser');
+const { optimize } = require('svgo');
+const { encode, decode } = require('./lib/url');
+
+const PLUGIN = 'postcss-svgo';
+const dataURI = /data:image\/svg\+xml(;((charset=)?utf-8|base64))?,/i;
+const dataURIBase64 = /data:image\/svg\+xml;base64,/i;
+
+// the following regex will globally match:
+// \b([\w-]+) --> a word (a sequence of one or more [alphanumeric|underscore|dash] characters; followed by
+// \s*=\s* --> an equal sign character (=) between optional whitespaces; followed by
+// \\"([\S\s]+?)\\" --> any characters (including whitespaces and newlines) between literal escaped quotes (\")
+const escapedQuotes = /\b([\w-]+)\s*=\s*\\"([\S\s]+?)\\"/g;
+
+/**
+ * @param {string} input the SVG string
+ * @param {Options} opts
+ * @return {{result: string, isUriEncoded: boolean}} the minification result
+ */
+function minifySVG(input, opts) {
+ let svg = input;
+ let decodedUri, isUriEncoded;
+ try {
+ decodedUri = decode(input);
+ isUriEncoded = decodedUri !== input;
+ } catch (e) {
+ // Swallow exception if we cannot decode the value
+ isUriEncoded = false;
+ }
+
+ if (isUriEncoded) {
+ svg = /** @type {string} */ (decodedUri);
+ }
+
+ if (opts.encode !== undefined) {
+ isUriEncoded = opts.encode;
+ }
+
+ // normalize all escaped quote characters from svg attributes
+ // from <svg attr=\"value\"... /> to <svg attr="value"... />
+ // see: https://github.com/cssnano/cssnano/issues/1194
+ svg = svg.replace(escapedQuotes, '$1="$2"');
+
+ const result = optimize(svg, opts);
+
+ return {
+ result: /** @type {import('svgo').Output}*/ (result).data,
+ isUriEncoded,
+ };
+}
+
+/**
+ * @param {import('postcss').Declaration} decl
+ * @param {Options} opts
+ * @param {import('postcss').Result} postcssResult
+ * @return {void}
+ */
+function minify(decl, opts, postcssResult) {
+ const parsed = valueParser(decl.value);
+
+ const minified = parsed.walk((node) => {
+ if (
+ node.type !== 'function' ||
+ node.value.toLowerCase() !== 'url' ||
+ !node.nodes.length
+ ) {
+ return;
+ }
+ let { value, quote } = /** @type {valueParser.StringNode} */ (
+ node.nodes[0]
+ );
+
+ let optimizedValue;
+
+ try {
+ if (dataURIBase64.test(value)) {
+ const url = new URL(value);
+ const base64String = `${url.protocol}${url.pathname}`.replace(
+ dataURI,
+ ''
+ );
+ const svg = Buffer.from(base64String, 'base64').toString('utf8');
+ const { result } = minifySVG(svg, opts);
+ const data = Buffer.from(result).toString('base64');
+ optimizedValue = 'data:image/svg+xml;base64,' + data + url.hash;
+ } else if (dataURI.test(value)) {
+ const svg = value.replace(dataURI, '');
+ const { result, isUriEncoded } = minifySVG(svg, opts);
+ let data = isUriEncoded ? encode(result) : result;
+ // Should always encode # otherwise we yield a broken SVG
+ // in Firefox (works in Chrome however). See this issue:
+ // https://github.com/cssnano/cssnano/issues/245
+ data = data.replace(/#/g, '%23');
+ optimizedValue = 'data:image/svg+xml;charset=utf-8,' + data;
+ quote = isUriEncoded ? '"' : "'";
+ } else {
+ return;
+ }
+ } catch (error) {
+ decl.warn(postcssResult, `${error}`);
+ return;
+ }
+ node.nodes[0] = Object.assign({}, node.nodes[0], {
+ value: optimizedValue,
+ quote: quote,
+ type: 'string',
+ before: '',
+ after: '',
+ });
+
+ return false;
+ });
+
+ decl.value = minified.toString();
+}
+/** @typedef {{encode?: boolean, plugins?: object[]} & import('svgo').Config} Options */
+/**
+ * @type {import('postcss').PluginCreator<Options>}
+ * @param {Options} opts
+ * @return {import('postcss').Plugin}
+ */
+function pluginCreator(opts = {}) {
+ return {
+ postcssPlugin: PLUGIN,
+
+ OnceExit(css, { result }) {
+ css.walkDecls((decl) => {
+ if (!dataURI.test(decl.value)) {
+ return;
+ }
+
+ minify(decl, opts, result);
+ });
+ },
+ };
+}
+
+pluginCreator.postcss = true;
+module.exports = pluginCreator;
diff --git a/node_modules/postcss-svgo/src/lib/url.js b/node_modules/postcss-svgo/src/lib/url.js
new file mode 100644
index 00000000..1db6a397
--- /dev/null
+++ b/node_modules/postcss-svgo/src/lib/url.js
@@ -0,0 +1,18 @@
+'use strict';
+/**
+ * @param {string} data
+ * @return {string}
+ */
+function encode(data) {
+ return data
+ .replace(/"/g, "'")
+ .replace(/%/g, '%25')
+ .replace(/</g, '%3C')
+ .replace(/>/g, '%3E')
+ .replace(/&/g, '%26')
+ .replace(/#/g, '%23')
+ .replace(/\s+/g, ' ');
+}
+
+const decode = decodeURIComponent;
+module.exports = { encode, decode };