Skip to content

Commit 5e44a1f

Browse files
committedApr 7, 2022
get it mostly humming
1 parent 7a89010 commit 5e44a1f

13 files changed

+517
-23
lines changed
 

‎.eslintrc.js

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ module.exports = {
3333
'./blueprints/*/index.js',
3434
'./config/**/*.js',
3535
'./tests/dummy/config/**/*.js',
36+
'./lib/**/*.js',
3637
],
3738
parserOptions: {
3839
sourceType: 'script',

‎addon/components/s-v-g-icon.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
>
99
{{yield}}
1010
{{! if an icon needs a11y support, this allows title/desc to be added}}
11-
<use xlink:href="assets/component-icons/{{@name}}.svg" />
11+
<use href="assets/images/component-icon-sprite.svg#{{@name}}" xlink:href="assets/images/component-icon-sprite.svg#{{@name}}" />
1212
</svg>

‎index.js

+45-19
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,22 @@
22

33
const Funnel = require('broccoli-funnel');
44
const merge = require('broccoli-merge-trees');
5+
const SVGOptimizer = require('./lib/svgo-optimizer');
56
const path = require('path');
7+
const SpriteConfigGenerator = require('./lib/sprite-config-generator');
8+
const SpriteAssembler = require('./lib/sprite-assembler');
9+
const dasherize = require('./lib/utils/dasherize');
610

7-
function dasherize(str) {
8-
return str.replace(/[A-Z]/g, function (char, index) {
9-
return (index !== 0 ? '-' : '') + char.toLowerCase();
10-
});
11-
}
12-
13-
function templatePrecompiler(env, usedIcons) {
11+
function templatePrecompiler(env) {
1412
const b = env.syntax.builders;
1513
return {
1614
name: 'svg-component-rewrite',
1715
visitor: {
1816
ElementNode(node) {
1917
if (node.tag.startsWith('Icon::')) {
20-
const tag = node.tag;
2118
const parts = node.tag.split('::');
2219
parts.shift();
2320
const fullName = parts.map(dasherize).join('/');
24-
usedIcons.set(fullName, tag);
2521
node.tag = 'SVGIcon';
2622
const attr = b.attr('@name', b.text(fullName));
2723
node.attributes.push(attr);
@@ -64,25 +60,55 @@ module.exports = {
6460
},
6561
}
6662
);
63+
const treeForTemplates = new Funnel(this.pathForMainFilesRoot(), {
64+
include: ['**/*.hbs'],
65+
exclude: ['components/icon/**/*.hbs'],
66+
getDestinationPath(relativePath) {
67+
return relativePath.replace('.hbs', '.svg');
68+
},
69+
});
70+
const configTree = new SpriteConfigGenerator(treeForTemplates);
71+
72+
const TrulyRemoveComments = {
73+
name: 'Remove Comments Starting With !',
74+
type: 'visitor',
75+
fn: () => {
76+
return {
77+
comment: {
78+
enter: (node, parentNode) => {
79+
if (node.value.charAt(0) === '!') {
80+
parentNode.children = parentNode.children.filter(
81+
(child) => child !== node
82+
);
83+
}
84+
},
85+
},
86+
};
87+
},
88+
};
89+
90+
const compiled = new SVGOptimizer(treeForIcons, {
91+
persist: false,
92+
svgoConfig: {
93+
multipass: true,
94+
plugins: ['preset-default', TrulyRemoveComments],
95+
},
96+
});
97+
const spriteTree = new SpriteAssembler([configTree, compiled]);
6798
return tree
68-
? merge([tree, treeForIcons], { overwrite: true })
69-
: treeForIcons;
99+
? merge([tree, spriteTree, compiled], { overwrite: true })
100+
: merge([spriteTree, compiled], { overwrite: true });
70101
},
71102

72103
setupPreprocessorRegistry(type, registry) {
73-
const usedIcons = new Map();
74-
// TODO make this something in the file system
75-
this.usedIcons = usedIcons;
76-
77104
if (type === 'parent') {
78105
registry.add('htmlbars-ast-plugin', {
79106
name: 'svg-component-rewrite',
80107
ext: 'hbs',
81-
plugin: (env) => {
82-
// TODO write config to file so that this can be safely parallelized
83-
return templatePrecompiler(env, usedIcons);
108+
plugin: templatePrecompiler,
109+
cacheKey: () => {
110+
return `${Date.now()}`; // use this to deactivate when deving
84111
},
85-
// cacheKey: () => {},
86112
baseDir() {
87113
return __dirname;
88114
},

‎lib/sprite-assembler.js

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
const Plugin = require('./utils/basic-plugin');
2+
const path = require('path');
3+
const fs = require('fs');
4+
const formatAttrs = require('./utils/format-attrs');
5+
const consoleUI = require('./utils/console-ui');
6+
const cheerio = require('cheerio');
7+
8+
function processSVG(svgContent, symbolName, filePath) {
9+
let $svg = cheerio.load(svgContent, { xmlMode: true })('svg');
10+
let [svgAttrs, svgHTML] = [$svg.attr(), $svg.html()];
11+
12+
if (!svgHTML || !svgAttrs) {
13+
consoleUI.warn(`invalid SVG found ${filePath}`);
14+
return '';
15+
}
16+
17+
let symbolAttrs = {
18+
id: symbolName,
19+
viewBox: svgAttrs.viewBox,
20+
};
21+
let symbolContent = `<symbol ${formatAttrs(symbolAttrs)}></symbol>`;
22+
let $symbolWrapper = cheerio.load(symbolContent, { xmlMode: true });
23+
let $symbol = $symbolWrapper('symbol');
24+
25+
$symbol.html(svgHTML);
26+
return $symbolWrapper.html();
27+
}
28+
29+
/**
30+
* Roughly how it works:
31+
* - find all elements that are referenced by `#id`, e.g. `fill="url(#gradient)"`
32+
* - now we have referenced elements (targets), e.g. `<linearGradient ... id="gradient">...`
33+
* - change target's id to make it unique
34+
* - change all references to target inside symbol to have new id
35+
* - remove target from the symbol
36+
* - add target to the sprite's defs
37+
* - add updated symbol to the sprite
38+
*/
39+
function extractDefs(svgContent) {
40+
let $svg = cheerio.load(svgContent, { xmlMode: true });
41+
let $newSvg = cheerio.load(
42+
`<svg ${formatAttrs($svg('svg').attr())}><defs /></svg>`,
43+
{ xmlMode: true }
44+
);
45+
let $defs = $newSvg('defs');
46+
47+
$svg('symbol').each((_, element) => {
48+
const $symbol = $svg(element);
49+
const extractedRefIds = $svg('[id]', $symbol)
50+
.filter((_, elementWithId) =>
51+
$symbol.html().includes(`#${$svg(elementWithId).attr('id')}`)
52+
)
53+
.map((_, referencedEl) => {
54+
const $referencedEl = $svg(referencedEl);
55+
const refId = $referencedEl.attr('id');
56+
$referencedEl.attr('id', `${$symbol.attr('id')}-${refId}`);
57+
$referencedEl.remove();
58+
$defs.append($referencedEl);
59+
return refId;
60+
});
61+
$svg('defs', $symbol).remove();
62+
let symbolHtml = `<symbol ${formatAttrs(
63+
$symbol.attr()
64+
)}>${$symbol.html()}</symbol>`;
65+
extractedRefIds.each((_, refId) => {
66+
symbolHtml = symbolHtml.replace(
67+
`#${refId}`,
68+
`#${$symbol.attr('id')}-${refId}`
69+
);
70+
});
71+
$defs.after(symbolHtml);
72+
});
73+
74+
return $defs.children().length ? $newSvg.html() : svgContent;
75+
}
76+
77+
module.exports = class SpriteGenerator extends Plugin {
78+
constructor(inputNodes, options = {}) {
79+
super(inputNodes, {
80+
name: 'SpriteAssembler',
81+
annotation: 'compiles svg icon sprite from stats',
82+
});
83+
this.symbols = new Map();
84+
this.fileMap = new Map();
85+
this.usageMeta = null;
86+
87+
let config = Object.assign({}, { persist: true, svgAttrs: {} }, options);
88+
Object.assign(
89+
config.svgAttrs,
90+
{
91+
style: 'position: absolute; width: 0; height: 0;',
92+
width: '0',
93+
height: '0',
94+
version: '1.1',
95+
xmlns: 'http://www.w3.org/2000/svg',
96+
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
97+
},
98+
options.svgAttrs
99+
);
100+
101+
this.config = config;
102+
}
103+
104+
processFile(filePath, meta) {
105+
if (filePath.endsWith('.svg')) {
106+
let symbolName = filePath.replace(meta.inputPath, ''); // to-do definitely not this
107+
symbolName = symbolName.replace('.svg', '');
108+
symbolName = symbolName.replace('/assets/component-icons/', '');
109+
this.fileMap.set(symbolName, filePath);
110+
} else if (filePath.endsWith('svg-icon-usage-meta.json')) {
111+
this.usageMeta = JSON.parse(
112+
fs.readFileSync(filePath, { encoding: 'utf-8' })
113+
);
114+
// ignore indexing by default
115+
} else if (!filePath.endsWith('.DS_Store')) {
116+
consoleUI.warn(
117+
`Unexpected file ${filePath} in sprite-assembler tree for @html-next/svg-icon-optimizer`
118+
);
119+
}
120+
}
121+
122+
emit() {
123+
if (!this.usageMeta) {
124+
throw new Error(
125+
`unable to build sprite-assembler tree for @html-next/svg-icon-optimizer, expected usage meta file but found none.`
126+
);
127+
}
128+
const contents = [`<svg ${formatAttrs(this.config.svgAttrs)}>`];
129+
Object.keys(this.usageMeta).forEach((symbolName) => {
130+
const filePath = this.fileMap.get(symbolName);
131+
const file = fs.readFileSync(filePath, { encoding: 'utf-8' });
132+
contents.push(processSVG(file, symbolName, filePath));
133+
});
134+
contents.push('</svg>');
135+
const spriteFile = contents.join('');
136+
137+
fs.mkdirSync(path.join(this.outputPath, 'assets/images'), {
138+
recursive: true,
139+
});
140+
fs.writeFileSync(
141+
path.join(this.outputPath, 'assets/images/component-icon-sprite.svg'),
142+
extractDefs(spriteFile),
143+
{ encoding: 'utf-8' }
144+
);
145+
}
146+
};

‎lib/sprite-config-generator.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const Plugin = require('./utils/basic-plugin');
2+
const path = require('path');
3+
const fs = require('fs');
4+
const recast = require('ember-template-recast');
5+
const dasherize = require('./utils/dasherize');
6+
7+
function processFile(filePath, usedMap) {
8+
const file = fs.readFileSync(filePath, { encoding: 'utf-8' });
9+
const ast = recast.parse(file);
10+
recast.traverse(ast, {
11+
ElementNode(node) {
12+
if (node.tag.startsWith('Icon::')) {
13+
const tag = node.tag;
14+
const parts = node.tag.split('::');
15+
parts.shift();
16+
const fullName = parts.map(dasherize).join('/');
17+
usedMap.set(fullName, tag);
18+
}
19+
},
20+
});
21+
}
22+
23+
module.exports = class SpriteConfigGenerator extends Plugin {
24+
constructor(inputNodes) {
25+
super(inputNodes, {
26+
name: 'SpriteConfigGenerator',
27+
annotation: 'compiles svg icon usage stats from template',
28+
});
29+
this.used = new Map();
30+
}
31+
32+
processFile(filePath) {
33+
processFile(filePath, this.used);
34+
}
35+
36+
emit() {
37+
fs.writeFileSync(
38+
path.join(this.outputPath, 'svg-icon-usage-meta.json'),
39+
JSON.stringify(Object.fromEntries(this.used), null, 2),
40+
{ encoding: 'utf-8' }
41+
);
42+
}
43+
};

‎lib/svgo-optimizer.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use strict';
2+
3+
const PersistentFilter = require('broccoli-persistent-filter');
4+
const stringify = require('safe-stable-stringify');
5+
const { optimize } = require('svgo');
6+
7+
class SVGOFilter extends PersistentFilter {
8+
constructor(inputNode, options) {
9+
options = options || {};
10+
11+
super(inputNode, {
12+
name: 'SVGOFilter',
13+
extensions: ['svg'],
14+
// async: true,
15+
targetExtension: 'svg',
16+
persist: typeof options.persist === 'undefined' ? true : options.persist,
17+
annotation: options.annotation,
18+
});
19+
20+
this.options = options;
21+
this.optionsHash = stringify(options);
22+
}
23+
24+
processString(svg, relativePath) {
25+
const options = Object.assign({}, this.options.svgoConfig, {
26+
path: relativePath,
27+
});
28+
const result = svg ? optimize(svg, options).data : '';
29+
30+
return result;
31+
}
32+
33+
cacheKeyProcessString(string, relativePath) {
34+
return super.cacheKeyProcessString(string + this.optionsHash, relativePath);
35+
}
36+
37+
baseDir() {
38+
return __dirname;
39+
}
40+
}
41+
42+
module.exports = SVGOFilter;

‎lib/utils/basic-plugin.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const Plugin = require('broccoli-plugin');
2+
const walkTree = require('./walk-tree');
3+
4+
module.exports = class BasePlugin extends Plugin {
5+
constructor(inputNodes, options = {}) {
6+
super(Array.isArray(inputNodes) ? inputNodes : [inputNodes], options);
7+
8+
this.options = options;
9+
}
10+
11+
processFile() {}
12+
emit() {}
13+
14+
build() {
15+
this.inputPaths.forEach((inputPath) => {
16+
walkTree(
17+
inputPath,
18+
{ inputPath, fullPath: inputPath },
19+
(filePath, meta) => {
20+
this.processFile(filePath, meta);
21+
}
22+
);
23+
});
24+
this.emit();
25+
}
26+
};

‎lib/utils/console-ui.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
const UI = require('console-ui');
4+
5+
const ui = new UI({
6+
inputStream: process.stdin,
7+
outputStream: process.stderr,
8+
errorStream: process.stderr,
9+
});
10+
11+
const prefix = '[ember-svg-jar]';
12+
13+
module.exports = {
14+
log: (message) => {
15+
ui.write('\n');
16+
ui.writeLine(JSON.stringify(message, null, 2));
17+
},
18+
19+
warn: (message) => {
20+
ui.write('\n');
21+
ui.writeWarnLine(`${prefix} ${message}`);
22+
},
23+
24+
error: (message) => {
25+
throw new Error(`${prefix} ${message}`);
26+
},
27+
};

‎lib/utils/dasherize.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = function dasherize(str) {
2+
return str.replace(/[A-Z]/g, function (char, index) {
3+
return (index !== 0 ? '-' : '') + char.toLowerCase();
4+
});
5+
};

‎lib/utils/format-attrs.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = function formatAttrs(attrs = {}) {
2+
return Object.keys(attrs)
3+
.filter((key) => attrs[key] !== undefined)
4+
.map((key) => `${key}="${String(attrs[key]).replace(/"/g, '\\"')}"`)
5+
.join(' ');
6+
};

‎lib/utils/walk-tree.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const path = require('path');
2+
const fs = require('fs');
3+
4+
module.exports = function walkTree(dirPath, meta, callback) {
5+
const dir = fs.readdirSync(dirPath);
6+
dir.forEach((entry) => {
7+
const f = path.join(dirPath, entry);
8+
const stat = fs.statSync(f);
9+
10+
if (stat && stat.isDirectory()) {
11+
const newMeta = Object.assign({}, meta);
12+
newMeta.fullPath = f;
13+
walkTree(f, newMeta, callback);
14+
} else {
15+
callback(f, meta);
16+
}
17+
});
18+
};

‎package.json

+8-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,14 @@
3131
"ember-cli-babel": "^7.26.11",
3232
"ember-cli-htmlbars": "^6.0.1",
3333
"broccoli-funnel": "^3.0.8",
34-
"broccoli-merge-trees": "^4.2.0"
34+
"broccoli-merge-trees": "^4.2.0",
35+
"broccoli-persistent-filter": "^3.1.2",
36+
"safe-stable-stringify": "^2.3.1",
37+
"svgo": "^2.8.0",
38+
"broccoli-plugin": "^4.0.7",
39+
"ember-template-recast": "^6.1.3",
40+
"console-ui": "^3.1.2",
41+
"cheerio": "^1.0.0-rc.10"
3542
},
3643
"devDependencies": {
3744
"@ember/optional-features": "^2.0.0",

‎yarn.lock

+149-2
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,11 @@
12811281
dependencies:
12821282
defer-to-connect "^1.0.1"
12831283

1284+
"@trysound/sax@0.2.0":
1285+
version "0.2.0"
1286+
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
1287+
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
1288+
12841289
"@types/body-parser@*":
12851290
version "1.19.2"
12861291
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0"
@@ -2481,6 +2486,11 @@ body@^5.1.0:
24812486
raw-body "~1.1.0"
24822487
safe-json-parse "~1.0.1"
24832488

2489+
boolbase@^1.0.0:
2490+
version "1.0.0"
2491+
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
2492+
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
2493+
24842494
bower-config@^1.4.3:
24852495
version "1.4.3"
24862496
resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.3.tgz#3454fecdc5f08e7aa9cc6d556e492be0669689ae"
@@ -3265,6 +3275,30 @@ charm@^1.0.0:
32653275
dependencies:
32663276
inherits "^2.0.1"
32673277

3278+
cheerio-select@^1.5.0:
3279+
version "1.6.0"
3280+
resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.6.0.tgz#489f36604112c722afa147dedd0d4609c09e1696"
3281+
integrity sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==
3282+
dependencies:
3283+
css-select "^4.3.0"
3284+
css-what "^6.0.1"
3285+
domelementtype "^2.2.0"
3286+
domhandler "^4.3.1"
3287+
domutils "^2.8.0"
3288+
3289+
cheerio@^1.0.0-rc.10:
3290+
version "1.0.0-rc.10"
3291+
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.10.tgz#2ba3dcdfcc26e7956fc1f440e61d51c643379f3e"
3292+
integrity sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==
3293+
dependencies:
3294+
cheerio-select "^1.5.0"
3295+
dom-serializer "^1.3.2"
3296+
domhandler "^4.2.0"
3297+
htmlparser2 "^6.1.0"
3298+
parse5 "^6.0.1"
3299+
parse5-htmlparser2-tree-adapter "^6.0.1"
3300+
tslib "^2.2.0"
3301+
32683302
chokidar@^2.1.8:
32693303
version "2.1.8"
32703304
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
@@ -3489,7 +3523,7 @@ commander@2.8.x:
34893523
dependencies:
34903524
graceful-readlink ">= 1.0.0"
34913525

3492-
commander@7.2.0:
3526+
commander@7.2.0, commander@^7.2.0:
34933527
version "7.2.0"
34943528
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
34953529
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
@@ -3792,6 +3826,25 @@ css-loader@^5.2.0:
37923826
schema-utils "^3.0.0"
37933827
semver "^7.3.5"
37943828

3829+
css-select@^4.1.3, css-select@^4.3.0:
3830+
version "4.3.0"
3831+
resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
3832+
integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
3833+
dependencies:
3834+
boolbase "^1.0.0"
3835+
css-what "^6.0.1"
3836+
domhandler "^4.3.1"
3837+
domutils "^2.8.0"
3838+
nth-check "^2.0.1"
3839+
3840+
css-tree@^1.1.2, css-tree@^1.1.3:
3841+
version "1.1.3"
3842+
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
3843+
integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
3844+
dependencies:
3845+
mdn-data "2.0.14"
3846+
source-map "^0.6.1"
3847+
37953848
css-tree@^2.0.4:
37963849
version "2.1.0"
37973850
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.1.0.tgz#170e27ccf94e7c5facb183765c25898be843d1d2"
@@ -3800,11 +3853,23 @@ css-tree@^2.0.4:
38003853
mdn-data "2.0.27"
38013854
source-map-js "^1.0.1"
38023855

3856+
css-what@^6.0.1:
3857+
version "6.1.0"
3858+
resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
3859+
integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
3860+
38033861
cssesc@^3.0.0:
38043862
version "3.0.0"
38053863
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
38063864
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
38073865

3866+
csso@^4.2.0:
3867+
version "4.2.0"
3868+
resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
3869+
integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
3870+
dependencies:
3871+
css-tree "^1.1.2"
3872+
38083873
cyclist@^1.0.1:
38093874
version "1.0.1"
38103875
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
@@ -3982,11 +4047,41 @@ doctrine@^3.0.0:
39824047
dependencies:
39834048
esutils "^2.0.2"
39844049

4050+
dom-serializer@^1.0.1, dom-serializer@^1.3.2:
4051+
version "1.3.2"
4052+
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91"
4053+
integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==
4054+
dependencies:
4055+
domelementtype "^2.0.1"
4056+
domhandler "^4.2.0"
4057+
entities "^2.0.0"
4058+
39854059
domain-browser@^1.1.1:
39864060
version "1.2.0"
39874061
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
39884062
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
39894063

4064+
domelementtype@^2.0.1, domelementtype@^2.2.0:
4065+
version "2.2.0"
4066+
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
4067+
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
4068+
4069+
domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1:
4070+
version "4.3.1"
4071+
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
4072+
integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
4073+
dependencies:
4074+
domelementtype "^2.2.0"
4075+
4076+
domutils@^2.5.2, domutils@^2.8.0:
4077+
version "2.8.0"
4078+
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
4079+
integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
4080+
dependencies:
4081+
dom-serializer "^1.0.1"
4082+
domelementtype "^2.2.0"
4083+
domhandler "^4.2.0"
4084+
39904085
dot-case@^3.0.4:
39914086
version "3.0.4"
39924087
resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
@@ -6136,6 +6231,16 @@ hosted-git-info@^4.0.1:
61366231
dependencies:
61376232
lru-cache "^6.0.0"
61386233

6234+
htmlparser2@^6.1.0:
6235+
version "6.1.0"
6236+
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
6237+
integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
6238+
dependencies:
6239+
domelementtype "^2.0.1"
6240+
domhandler "^4.0.0"
6241+
domutils "^2.5.2"
6242+
entities "^2.0.0"
6243+
61396244
http-cache-semantics@^4.0.0:
61406245
version "4.1.0"
61416246
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
@@ -7317,6 +7422,11 @@ md5.js@^1.3.4:
73177422
inherits "^2.0.1"
73187423
safe-buffer "^5.1.2"
73197424

7425+
mdn-data@2.0.14:
7426+
version "2.0.14"
7427+
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
7428+
integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
7429+
73207430
mdn-data@2.0.27:
73217431
version "2.0.27"
73227432
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.27.tgz#1710baa7b0db8176d3b3d565ccb7915fc69525ab"
@@ -7808,6 +7918,13 @@ npmlog@^4.0.0:
78087918
gauge "~2.7.3"
78097919
set-blocking "~2.0.0"
78107920

7921+
nth-check@^2.0.1:
7922+
version "2.0.1"
7923+
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2"
7924+
integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==
7925+
dependencies:
7926+
boolbase "^1.0.0"
7927+
78117928
number-is-nan@^1.0.0:
78127929
version "1.0.1"
78137930
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
@@ -8114,6 +8231,13 @@ parse-static-imports@^1.1.0:
81148231
resolved "https://registry.yarnpkg.com/parse-static-imports/-/parse-static-imports-1.1.0.tgz#ae2f18f18da1a993080ae406a5219455c0bbad5d"
81158232
integrity sha512-HlxrZcISCblEV0lzXmAHheH/8qEkKgmqkdxyHTPbSqsTUV8GzqmN1L+SSti+VbNPfbBO3bYLPHDiUs2avbAdbA==
81168233

8234+
parse5-htmlparser2-tree-adapter@^6.0.1:
8235+
version "6.0.1"
8236+
resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
8237+
integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==
8238+
dependencies:
8239+
parse5 "^6.0.1"
8240+
81178241
parse5@^6.0.1:
81188242
version "6.0.1"
81198243
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
@@ -9016,6 +9140,11 @@ safe-regex@^1.1.0:
90169140
dependencies:
90179141
ret "~0.1.10"
90189142

9143+
safe-stable-stringify@^2.3.1:
9144+
version "2.3.1"
9145+
resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz#ab67cbe1fe7d40603ca641c5e765cb942d04fc73"
9146+
integrity sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==
9147+
90199148
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0:
90209149
version "2.1.2"
90219150
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
@@ -9506,6 +9635,11 @@ ssri@^6.0.1:
95069635
dependencies:
95079636
figgy-pudding "^3.5.1"
95089637

9638+
stable@^0.1.8:
9639+
version "0.1.8"
9640+
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
9641+
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
9642+
95099643
stagehand@^1.0.0:
95109644
version "1.0.0"
95119645
resolved "https://registry.yarnpkg.com/stagehand/-/stagehand-1.0.0.tgz#79515e2ad3a02c63f8720c7df9b6077ae14276d9"
@@ -9756,6 +9890,19 @@ supports-preserve-symlinks-flag@^1.0.0:
97569890
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
97579891
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
97589892

9893+
svgo@^2.8.0:
9894+
version "2.8.0"
9895+
resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
9896+
integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
9897+
dependencies:
9898+
"@trysound/sax" "0.2.0"
9899+
commander "^7.2.0"
9900+
css-select "^4.1.3"
9901+
css-tree "^1.1.3"
9902+
csso "^4.2.0"
9903+
picocolors "^1.0.0"
9904+
stable "^0.1.8"
9905+
97599906
symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0, symlink-or-copy@^1.3.1:
97609907
version "1.3.1"
97619908
resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.3.1.tgz#9506dd64d8e98fa21dcbf4018d1eab23e77f71fe"
@@ -10086,7 +10233,7 @@ tslib@^1.9.0:
1008610233
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
1008710234
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
1008810235

10089-
tslib@^2.0.3, tslib@^2.3.1:
10236+
tslib@^2.0.3, tslib@^2.2.0, tslib@^2.3.1:
1009010237
version "2.3.1"
1009110238
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
1009210239
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==

0 commit comments

Comments
 (0)
Please sign in to comment.