source: frontend/node_modules/postcss-svgo/src/index.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 4.1 KB
Line 
1'use strict';
2const valueParser = require('postcss-value-parser');
3const { optimize } = require('svgo');
4const { encode, decode } = require('./lib/url');
5
6const PLUGIN = 'postcss-svgo';
7const dataURI = /data:image\/svg\+xml(;((charset=)?utf-8|base64))?,/i;
8const dataURIBase64 = /data:image\/svg\+xml;base64,/i;
9
10// the following regex will globally match:
11// \b([\w-]+) --> a word (a sequence of one or more [alphanumeric|underscore|dash] characters; followed by
12// \s*=\s* --> an equal sign character (=) between optional whitespaces; followed by
13// \\"([\S\s]+?)\\" --> any characters (including whitespaces and newlines) between literal escaped quotes (\")
14const escapedQuotes = /\b([\w-]+)\s*=\s*\\"([\S\s]+?)\\"/g;
15
16/**
17 * @param {string} input the SVG string
18 * @param {Options} opts
19 * @return {{result: string, isUriEncoded: boolean}} the minification result
20 */
21function minifySVG(input, opts) {
22 let svg = input;
23 let decodedUri, isUriEncoded;
24 try {
25 decodedUri = decode(input);
26 isUriEncoded = decodedUri !== input;
27 } catch (e) {
28 // Swallow exception if we cannot decode the value
29 isUriEncoded = false;
30 }
31
32 if (isUriEncoded) {
33 svg = /** @type {string} */ (decodedUri);
34 }
35
36 if (opts.encode !== undefined) {
37 isUriEncoded = opts.encode;
38 }
39
40 // normalize all escaped quote characters from svg attributes
41 // from <svg attr=\"value\"... /> to <svg attr="value"... />
42 // see: https://github.com/cssnano/cssnano/issues/1194
43 svg = svg.replace(escapedQuotes, '$1="$2"');
44
45 const result = optimize(svg, opts);
46 if (result.error) {
47 throw new Error(result.error);
48 }
49
50 return {
51 result: /** @type {import('svgo').OptimizedSvg}*/ (result).data,
52 isUriEncoded,
53 };
54}
55
56/**
57 * @param {import('postcss').Declaration} decl
58 * @param {Options} opts
59 * @param {import('postcss').Result} postcssResult
60 * @return {void}
61 */
62function minify(decl, opts, postcssResult) {
63 const parsed = valueParser(decl.value);
64
65 const minified = parsed.walk((node) => {
66 if (
67 node.type !== 'function' ||
68 node.value.toLowerCase() !== 'url' ||
69 !node.nodes.length
70 ) {
71 return;
72 }
73 let { value, quote } = /** @type {valueParser.StringNode} */ (
74 node.nodes[0]
75 );
76
77 let optimizedValue;
78
79 try {
80 if (dataURIBase64.test(value)) {
81 const url = new URL(value);
82 const base64String = `${url.protocol}${url.pathname}`.replace(
83 dataURI,
84 ''
85 );
86 const svg = Buffer.from(base64String, 'base64').toString('utf8');
87 const { result } = minifySVG(svg, opts);
88 const data = Buffer.from(result).toString('base64');
89 optimizedValue = 'data:image/svg+xml;base64,' + data + url.hash;
90 } else if (dataURI.test(value)) {
91 const svg = value.replace(dataURI, '');
92 const { result, isUriEncoded } = minifySVG(svg, opts);
93 let data = isUriEncoded ? encode(result) : result;
94 // Should always encode # otherwise we yield a broken SVG
95 // in Firefox (works in Chrome however). See this issue:
96 // https://github.com/cssnano/cssnano/issues/245
97 data = data.replace(/#/g, '%23');
98 optimizedValue = 'data:image/svg+xml;charset=utf-8,' + data;
99 quote = isUriEncoded ? '"' : "'";
100 } else {
101 return;
102 }
103 } catch (error) {
104 decl.warn(postcssResult, `${error}`);
105 return;
106 }
107 node.nodes[0] = Object.assign({}, node.nodes[0], {
108 value: optimizedValue,
109 quote: quote,
110 type: 'string',
111 before: '',
112 after: '',
113 });
114
115 return false;
116 });
117
118 decl.value = minified.toString();
119}
120/** @typedef {{encode?: boolean, plugins?: object[]} & import('svgo').OptimizeOptions} Options */
121/**
122 * @type {import('postcss').PluginCreator<Options>}
123 * @param {Options} opts
124 * @return {import('postcss').Plugin}
125 */
126function pluginCreator(opts = {}) {
127 return {
128 postcssPlugin: PLUGIN,
129
130 OnceExit(css, { result }) {
131 css.walkDecls((decl) => {
132 if (!dataURI.test(decl.value)) {
133 return;
134 }
135
136 minify(decl, opts, result);
137 });
138 },
139 };
140}
141
142pluginCreator.postcss = true;
143module.exports = pluginCreator;
Note: See TracBrowser for help on using the repository browser.