├── .gitignore
├── .vscode
└── settings.json
├── README.md
├── exo-2-latin-400.woff2
├── index.html
├── package.json
├── rename.sh
├── rollup.config.js
├── script
├── gauge.js
├── main.js
├── math.js
├── metrics.js
└── util.js
├── style.css
├── vercel.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | dist
4 |
5 | calc.js*
6 |
7 | stats.html
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "prettier.printWidth": 130
3 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Lighthouse Scoring Calculator
2 | -------------------
3 |
4 | [googlechrome.github.io/lighthouse/scorecalc/](https://googlechrome.github.io/lighthouse/scorecalc/)
5 |
6 |
7 | 
8 |
--------------------------------------------------------------------------------
/exo-2-latin-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulirish/lh-scorecalc/05fc1c5a4e779e4801163dfc15bbcaa523db436a/exo-2-latin-400.woff2
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Lighthouse Scoring calculator
5 |
6 |
7 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
50 |
51 | Lighthouse Scoring Calculator
52 |
53 |
54 |
55 |
56 |
57 |
66 |
67 |
68 |
69 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lh-scorecalc",
3 | "version": "1.0.0",
4 | "description": "wassup ===========",
5 | "main": "math.js",
6 | "scripts": {
7 | "watch": "find . script -depth 1 -type f | entr yarn build",
8 | "build": "rollup -c",
9 | "clean": "rm -rf dist",
10 | "deploy:ghpages": "yarn gh-pages --dist dist --repo git@github.com:GoogleChrome/lighthouse.git --dest scorecalc --add --message scorecalc-update",
11 | "deploy:copy": "mkdir -p dist && cp -r index.html *.css calc.* dist",
12 | "deploy": "yarn clean && yarn build && yarn deploy:copy && yarn deploy:ghpages",
13 | "test": "echo \"Error: no test specified\" && exit 1"
14 | },
15 | "keywords": [],
16 | "author": "",
17 | "license": "ISC",
18 | "devDependencies": {
19 | "gh-pages": "^5.0.0",
20 | "rollup": "^2.45.2",
21 | "rollup-plugin-commonjs": "^10.1.0",
22 | "rollup-plugin-node-resolve": "^5.2.0",
23 | "rollup-plugin-visualizer": "^5.4.1"
24 | },
25 | "dependencies": {
26 | "@rollup/plugin-buble": "^0.21.3",
27 | "preact": "^10.4.1"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/rename.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | git filter-branch --env-filter '
4 |
5 | OLD_EMAIL="none"
6 | CORRECT_NAME="Paul Irish"
7 | CORRECT_EMAIL="commits@paul.irish"
8 |
9 | if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
10 | then
11 | export GIT_COMMITTER_NAME="$CORRECT_NAME"
12 | export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
13 | fi
14 | if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
15 | then
16 | export GIT_AUTHOR_NAME="$CORRECT_NAME"
17 | export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
18 | fi
19 | ' a5b7254bc3cdc7dc50b49b3d86c153614d183a82...91f7df52bf211c99b164e8b2f56221f074a85fa9
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | // rollup.config.js
2 | import resolve from 'rollup-plugin-node-resolve';
3 | import commonjs from 'rollup-plugin-commonjs';
4 | import buble from '@rollup/plugin-buble';
5 | import { visualizer } from 'rollup-plugin-visualizer';
6 |
7 |
8 | export default {
9 | input: 'script/main.js',
10 | output: {
11 | file: 'calc.js',
12 | format: 'es',
13 | sourcemap: true,
14 | },
15 | plugins: [
16 | resolve(),
17 | buble({
18 | jsx: 'h',
19 | objectAssign: 'Object.assign',
20 | target: { chrome: 71, safari: 11.1, firefox: 64 }, // roughly disable ES feature transpilation
21 | }),
22 | commonjs(),
23 | visualizer(), // build and view stats.html
24 | ]
25 | };
--------------------------------------------------------------------------------
/script/gauge.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* Most of the impressive code here authored by Ana Tudor, Nov 2019 */
4 |
5 | import {calculateRating} from './util.js';
6 |
7 | const delay = delay => new Promise(resolve => setTimeout(resolve, delay));
8 |
9 | export function updateGauge(wrapper, category) {
10 | _setPerfGaugeExplodey(wrapper, category);
11 | }
12 |
13 | function _determineTrig(sizeSVG, percent, strokeWidth) {
14 | strokeWidth = strokeWidth || sizeSVG / 32;
15 |
16 | const radiusInner = sizeSVG / strokeWidth;
17 | const strokeGap = 0.5 * strokeWidth;
18 | const radiusOuter = radiusInner + strokeGap + strokeWidth;
19 |
20 | const circumferenceInner = 2 * Math.PI * radiusInner;
21 | // arc length we need to subtract
22 | // for very small strokeWidth:radius ratios this is ≈ strokeWidth
23 | // angle = acute angle of isosceles △ with 2 edges equal to radius & 3rd equal to strokeWidth
24 | // angle formula given by law of cosines
25 | const endDiffInner = Math.acos(1 - 0.5 * Math.pow((0.5 * strokeWidth) / radiusInner, 2)) * radiusInner;
26 |
27 | const circumferenceOuter = 2 * Math.PI * radiusOuter;
28 | const endDiffOuter = Math.acos(1 - 0.5 * Math.pow((0.5 * strokeWidth) / radiusOuter, 2)) * radiusOuter;
29 |
30 | return {
31 | radiusInner,
32 | radiusOuter,
33 | circumferenceInner,
34 | circumferenceOuter,
35 | getArcLength: _ => Math.max(0, +(percent * circumferenceInner - 2 * endDiffInner).toFixed(4)),
36 | // isButt case is for metricArcHoverTarget
37 | getMetricArcLength: (weightingPct, isButt) => {
38 | // TODO: this math isn't perfect butt it's very close.
39 | const linecapFactor = isButt ? 0 : 2 * endDiffOuter;
40 | return Math.max(0, +(weightingPct * circumferenceOuter - strokeGap - linecapFactor).toFixed(4));
41 | },
42 | endDiffInner,
43 | endDiffOuter,
44 | strokeWidth,
45 | strokeGap,
46 | };
47 | }
48 |
49 | /**
50 | * @param {HTMLAnchorElement} wrapper
51 | * @param {LH.ReportResult.Category} category
52 | */
53 | function _setPerfGaugeExplodey(wrapper, category) {
54 | const sizeSVG = 128;
55 | const offsetSVG = -0.5 * sizeSVG;
56 |
57 | const percent = Number(category.score);
58 | const {
59 | radiusInner,
60 | radiusOuter,
61 | circumferenceInner,
62 | circumferenceOuter,
63 | getArcLength,
64 | getMetricArcLength,
65 | endDiffInner,
66 | endDiffOuter,
67 | strokeWidth,
68 | strokeGap,
69 | } = _determineTrig(sizeSVG, percent);
70 |
71 | const SVG = wrapper.querySelector('.lh-gauge');
72 | const NS_URI = 'http://www.w3.org/2000/svg';
73 |
74 | SVG.setAttribute('viewBox', [offsetSVG, offsetSVG, sizeSVG, sizeSVG].join(' '));
75 | SVG.style.setProperty('--stroke-width', `${strokeWidth}px`);
76 | SVG.style.setProperty('--circle-meas', 2 * Math.PI.toFixed(4));
77 |
78 | const groupOuter = wrapper.querySelector('.lh-gauge__outer');
79 | const groupInner = wrapper.querySelector('.lh-gauge__inner');
80 | const cover = groupOuter.querySelector('.cover');
81 | const gaugeArc = groupInner.querySelector('.lh-gauge__arc');
82 | const gaugePerc = groupInner.querySelector('.lh-gauge__percentage');
83 |
84 | groupOuter.style.setProperty('--scale-initial', radiusInner / radiusOuter);
85 | groupOuter.style.setProperty('--radius', `${radiusOuter}px`);
86 | cover.style.setProperty('--radius', `${0.5 * (radiusInner + radiusOuter)}px`);
87 | cover.setAttribute('stroke-width', strokeGap);
88 | SVG.style.setProperty('--radius', `${radiusInner}px`);
89 |
90 | gaugeArc.setAttribute('stroke-dasharray', `${getArcLength()} ${(circumferenceInner - getArcLength()).toFixed(4)}`);
91 | gaugeArc.setAttribute('stroke-dashoffset', 0.25 * circumferenceInner - endDiffInner);
92 |
93 | gaugePerc.textContent = Math.round(percent * 100);
94 |
95 | const radiusTextOuter = radiusOuter + strokeWidth;
96 | const radiusTextInner = radiusOuter - strokeWidth;
97 |
98 | const metrics = category.auditRefs.filter(r => r.group === 'metrics' && r.weight);
99 | const totalWeight = metrics.reduce((sum, each) => (sum += each.weight), 0);
100 | let offsetAdder = 0.25 * circumferenceOuter - endDiffOuter - 0.5 * strokeGap;
101 | let angleAdder = -0.5 * Math.PI;
102 |
103 | // Extra hack on top of the HACK for element reuse below. Delete any metric elems that aren't needed anymore (happens when the same gauge goes from v5 to v6)
104 | groupOuter.querySelectorAll('.metric').forEach(metricElem => {
105 | const classNamesToRetain = metrics.map(metric => `metric--${metric.id}`);
106 | const match = classNamesToRetain.find(selector => metricElem.classList.contains(selector));
107 | if (!match) metricElem.remove();
108 | });
109 |
110 | metrics.forEach((metric, i) => {
111 | // TODO(porting to real LHR..): in scorecalc we dont use the real audit ID just the acronym.
112 | const alias = metric.id;
113 |
114 | // Hack
115 | const needsDomPopulation = !groupOuter.querySelector(`.metric--${alias}`);
116 |
117 | // HACK:This isn't ideal but it was quick. Create element during initialization or reuse existing during updates
118 | const metricGroup = groupOuter.querySelector(`.metric--${alias}`) || document.createElementNS(NS_URI, 'g');
119 | const metricArcMax = groupOuter.querySelector(`.metric--${alias} .lh-gauge--faded`) || document.createElementNS(NS_URI, 'circle');
120 | const metricArc = groupOuter.querySelector(`.metric--${alias} .lh-gauge--miniarc`) || document.createElementNS(NS_URI, 'circle');
121 | const metricArcHoverTarget = groupOuter.querySelector(`.metric--${alias} .lh-gauge-hover`) || document.createElementNS(NS_URI, 'circle');
122 | const metricLabel = groupOuter.querySelector(`.metric--${alias} .metric__label`) || document.createElementNS(NS_URI, 'text');
123 | const metricValue = groupOuter.querySelector(`.metric--${alias} .metric__value`) || document.createElementNS(NS_URI, 'text');
124 |
125 | metricGroup.classList.add('metric', `metric--${alias}`);
126 | metricArcMax.classList.add('lh-gauge__arc', 'lh-gauge__arc--metric', 'lh-gauge--faded');
127 | metricArc.classList.add('lh-gauge__arc', 'lh-gauge__arc--metric', 'lh-gauge--miniarc');
128 | metricArcHoverTarget.classList.add('lh-gauge__arc', 'lh-gauge__arc--metric', 'lh-gauge--faded', 'lh-gauge-hover');
129 |
130 | const weightingPct = metric.weight / totalWeight;
131 | const metricLengthMax = getMetricArcLength(weightingPct);
132 | const metricPercent = metric.result.score * weightingPct;
133 | const metricLength = getMetricArcLength(metricPercent);
134 | const metricOffset = weightingPct * circumferenceOuter;
135 | const metricHoverLength = getMetricArcLength(weightingPct, true);
136 |
137 | metricGroup.style.setProperty('--metric-color', `var(--palette-${i})`);
138 | metricGroup.style.setProperty('--metric-offset', `${offsetAdder}`);
139 | metricGroup.style.setProperty('--i', i);
140 |
141 | metricArcMax.setAttribute('stroke-dasharray', `${metricLengthMax} ${circumferenceOuter - metricLengthMax}`);
142 | metricArc.style.setProperty('--metric-array', `${metricLength} ${circumferenceOuter - metricLength}`);
143 | metricArcHoverTarget.setAttribute('stroke-dasharray', `${metricHoverLength} ${circumferenceOuter - metricHoverLength - endDiffOuter}`);
144 |
145 | metricLabel.classList.add('metric__label');
146 | metricValue.classList.add('metric__value');
147 | metricLabel.textContent = alias;
148 | metricValue.textContent = `+${Math.round(metricPercent * 100)}`;
149 |
150 | const midAngle = angleAdder + weightingPct * Math.PI;
151 | const cos = Math.cos(midAngle);
152 | const sin = Math.sin(midAngle);
153 |
154 | // only set non-default alignments
155 | switch (true) {
156 | case cos > 0:
157 | metricValue.setAttribute('text-anchor', 'end');
158 | break;
159 | case cos < 0:
160 | metricLabel.setAttribute('text-anchor', 'end');
161 | break;
162 | case cos === 0:
163 | metricLabel.setAttribute('text-anchor', 'middle');
164 | metricValue.setAttribute('text-anchor', 'middle');
165 | break;
166 | }
167 |
168 | switch (true) {
169 | case sin > 0:
170 | metricLabel.setAttribute('dominant-baseline', 'hanging');
171 | break;
172 | case sin < 0:
173 | metricValue.setAttribute('dominant-baseline', 'hanging');
174 | break;
175 | case sin === 0:
176 | metricLabel.setAttribute('dominant-baseline', 'middle');
177 | metricValue.setAttribute('dominant-baseline', 'middle');
178 | break;
179 | }
180 |
181 | metricLabel.setAttribute('x', (radiusTextOuter * cos).toFixed(2));
182 | metricLabel.setAttribute('y', (radiusTextOuter * sin).toFixed(2));
183 | metricValue.setAttribute('x', (radiusTextInner * cos).toFixed(2));
184 | metricValue.setAttribute('y', (radiusTextInner * sin).toFixed(2));
185 |
186 | if (needsDomPopulation) {
187 | metricGroup.appendChild(metricArcMax);
188 | metricGroup.appendChild(metricArc);
189 | metricGroup.appendChild(metricArcHoverTarget);
190 | metricGroup.appendChild(metricLabel);
191 | metricGroup.appendChild(metricValue);
192 | groupOuter.appendChild(metricGroup);
193 | }
194 |
195 | offsetAdder -= metricOffset;
196 | angleAdder += weightingPct * 2 * Math.PI;
197 | });
198 |
199 | // Hack. Not ideal.
200 | if (SVG.dataset.listenersSetup) return;
201 | SVG.dataset.listenersSetup = true;
202 |
203 | // peekGauge(SVG);
204 |
205 | /*
206 | wrapper.state-expanded: gauge is exploded
207 | wrapper.state-highlight: gauge is exploded and one of the metrics is being highlighted
208 | metric.metric-highlight: highlight this particular metric
209 | */
210 | SVG.addEventListener('mouseover', e => {
211 | // if hovering on the SVG and its expanded, get rid of everything
212 | if (e.target === SVG && wrapper.classList.contains('state--expanded')) {
213 | // paul: not sure why we want to remove this.. seems like we want to keep it expanded...
214 | SVG.classList.remove('state--expanded');
215 |
216 | if (SVG.classList.contains('state--highlight')) {
217 | SVG.classList.remove('state--highlight');
218 | SVG.querySelector('.metric--highlight').classList.remove('metric--highlight');
219 | }
220 | return;
221 | }
222 |
223 | const parent = e.target.parentNode;
224 |
225 | // if hovering on a metric, highlight that one.
226 | // TODO: The hover target is a little small. ideally it's thicker.
227 | if (parent && parent.classList && parent.classList.contains('metric')) {
228 | // match the bg color of the gauge during a metric highlight
229 | wrapper.style.setProperty('--color-highlight', `var(--palette-${parent.style.getPropertyValue('--i')})`);
230 |
231 | if (!SVG.classList.contains('state--highlight')) {
232 | SVG.classList.add('state--highlight');
233 | parent.classList.add('metric--highlight');
234 | } else {
235 | const highlighted = SVG.querySelector('.metric--highlight');
236 |
237 | if (highlighted && parent !== highlighted) {
238 | highlighted.classList.remove('metric--highlight');
239 | parent.classList.add('metric--highlight');
240 | }
241 | }
242 | }
243 | });
244 |
245 | // clear on mouselave even if mousemove didn't catch it.
246 | SVG.addEventListener('mouseleave', e => {
247 | SVG.classList.remove('state--highlight');
248 | const mh = SVG.querySelector('.metric--highlight');
249 | mh && mh.classList.remove('metric--highlight');
250 | });
251 |
252 | // On the first run, tease with a little peek reveal
253 | async function peekGauge(SVG) {
254 | // Delay just a tad to let the user aclimatize beforehand.
255 | await delay(1000);
256 |
257 | // To visually get the outer ring to peek on the edge, we need the inner ring on top. This is SVG's equivalent to `innerElem.zIndex = 100`
258 | const inner = SVG.querySelector('.lh-gauge__inner');
259 | let id = `uniq-${Math.random()}`;
260 | inner.setAttribute('id', id);
261 | const useElem = document.createElementNS(NS_URI, 'use');
262 | useElem.setAttribute('href', `#${id}`);
263 | // for paint order this must come _after_ the outer.
264 | SVG.appendChild(useElem);
265 |
266 | const peekDurationSec = 2.5;
267 | SVG.style.setProperty('--peek-dur', `${peekDurationSec}s`);
268 | SVG.classList.add('state--peek', 'state--expanded');
269 |
270 | // Fancy double cleanup
271 | const cleanup = _ => SVG.classList.remove('state--peek', 'state--expanded') || useElem.remove();
272 | const tId = setTimeout(_ => {
273 | SVG.removeEventListener('mouseenter', handleEarlyInteraction);
274 | cleanup();
275 | }, peekDurationSec * 1000 * 1.5); // lil extra time just cuz
276 | function handleEarlyInteraction() {
277 | clearTimeout(tId);
278 | cleanup();
279 | }
280 | SVG.addEventListener('mouseenter', handleEarlyInteraction, {once: true});
281 | }
282 | }
283 |
--------------------------------------------------------------------------------
/script/main.js:
--------------------------------------------------------------------------------
1 | import { h, render, createRef, Component } from 'preact';
2 | import { QUANTILE_AT_VALUE, VALUE_AT_QUANTILE } from './math.js';
3 | import { $, NBSP, numberFormatter, calculateRating, arithmeticMean } from './util.js';
4 | import { metrics, scoringGuides } from './metrics.js';
5 | import { updateGauge } from './gauge.js';
6 |
7 | const params = new URLSearchParams(location.hash.substr(1));
8 |
9 | function determineMinMax(metricScoring) {
10 | const valueAtScore100 = VALUE_AT_QUANTILE(metricScoring, 0.995);
11 | const valueAtScore5 = VALUE_AT_QUANTILE(metricScoring, 0.05);
12 |
13 | let min = Math.floor(valueAtScore100 / 1000) * 1000;
14 | let max = Math.ceil(valueAtScore5 / 1000) * 1000;
15 | let step = 10;
16 |
17 | // Special handling for CLS
18 | if (metricScoring.units === 'unitless') {
19 | min = 0;
20 | max = Math.ceil(valueAtScore5 * 100) / 100;
21 | step = 0.01;
22 | }
23 |
24 | return {
25 | min,
26 | max,
27 | step,
28 | };
29 | }
30 |
31 | /**
32 | * @param {string} version
33 | */
34 | function getMajorVersion(version) {
35 | return version.split('.')[0];
36 | }
37 |
38 | class Metric extends Component {
39 | onValueChange(e) {
40 | const {id} = this.props;
41 |
42 | this.props.app.setState({
43 | metricValues: {
44 | ...this.props.app.state.metricValues,
45 | [id]: e.target.valueAsNumber,
46 | },
47 | });
48 | }
49 |
50 | onScoreChange(e) {
51 | const {id, metricScoring} = this.props;
52 |
53 | const score = e.target.valueAsNumber;
54 | let computedValue = VALUE_AT_QUANTILE(metricScoring, score / 100);
55 |
56 | // Clamp because we can end up with Infinity
57 | const { min, max } = determineMinMax(metricScoring);
58 | computedValue = Math.max(Math.min(computedValue, max), min);
59 |
60 | if (metricScoring.units !== 'unitless') {
61 | computedValue = Math.round(computedValue);
62 | }
63 |
64 | this.props.app.setState({
65 | metricValues: {
66 | ...this.props.app.state.metricValues,
67 | [id]: computedValue,
68 | },
69 | });
70 | }
71 |
72 | render({ id, value, score, weightMax, metricScoring }) {
73 | const { min, max, step } = determineMinMax(metricScoring, id);
74 | const weight = metricScoring.weight;
75 | const valueFormatted = metricScoring.units === 'unitless' ?
76 | value.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}) :
77 | // TODO: Use https://github.com/tc39/proposal-unified-intl-numberformat#i-units when Safari/FF support it
78 | `${numberFormatter.format(value)}${NBSP}ms`;
79 | const weightFormatted = (weight * 100).toLocaleString(undefined, {maximumFractionDigits: 1});
80 |
81 | return
82 |
83 |
84 | |
85 | {`${id} (${metricScoring.name})`} |
86 |
87 | this.onValueChange(e)} />
88 |
89 | |
90 | |
91 |
92 |
93 | this.onScoreChange(e)} />
94 |
95 | |
96 |
97 |
98 | {weightFormatted}%
99 | |
100 |
101 | }
102 | }
103 |
104 | class Gauge extends Component {
105 | constructor(props) {
106 | super(props);
107 | this.ref = createRef();
108 | }
109 |
110 | refreshGauge() {
111 | updateGauge(this.ref.current, {
112 | title: 'Performance',
113 | auditRefs: this.props.auditRefs,
114 | id: 'performance',
115 | score: this.props.score,
116 | });
117 | }
118 |
119 | componentDidMount() {
120 | this.refreshGauge();
121 | }
122 |
123 | componentDidUpdate() {
124 | this.refreshGauge();
125 | }
126 |
127 | render({ score }) {
128 | return (
129 |
130 |
131 |
142 |
143 |
144 | );
145 | }
146 | }
147 |
148 | class ScoringGuide extends Component {
149 | render({ app, name, values, scoring }) {
150 | // Make sure weights total to 1
151 | const weights = Object.values(scoring).map(metricScoring => metricScoring.weight);
152 | const weightSum = weights.reduce((agg, val) => (agg += val));
153 | const weightMax = Math.max(...Object.values(weights));
154 | console.assert(weightSum > 0.999 && weightSum < 1.0001); // lol rounding is hard.
155 |
156 | const metricsData = Object.keys(scoring).map(id => {
157 | const metricScoring = scoring[id];
158 | return {
159 | id,
160 | metricScoring,
161 | value: values[id],
162 | score: Math.round(QUANTILE_AT_VALUE(metricScoring, values[id]) * 100),
163 | };
164 | });
165 |
166 | const auditRefs = metricsData.map(metric => {
167 | return {
168 | id: metric.id,
169 | weight: metric.metricScoring.weight,
170 | group: 'metrics',
171 | result: {
172 | score: metric.score / 100,
173 | },
174 | };
175 | });
176 |
177 | const score = arithmeticMean(auditRefs);
178 |
179 | let title = {name}
;
180 | if (name === 'v10') {
181 | title = ;
182 | } else if (name === 'v8') {
183 | title = ;
184 | } else if (name === 'v6') {
185 | title = ;
186 | }
187 |
188 | return
212 | }
213 | }
214 |
215 | const debounce = (callback, time = 250, interval) =>
216 | ((...args) => {
217 | clearTimeout(interval);
218 | interval = setTimeout(() => callback(...args), time);
219 | });
220 |
221 | class App extends Component {
222 | constructor(props) {
223 | super(props);
224 | this.state = getInitialState();
225 | this.onDeviceChange = this.onDeviceChange.bind(this);
226 | this.onVersionsChange = this.onVersionsChange.bind(this);
227 | // debounce to avoid flooding with new URLs
228 | this.debouncedUpdatePermalink = debounce(this.updatePermalink);
229 | }
230 |
231 | updatePermalink(state) {
232 | const {versions, device, metricValues} = state;
233 | const url = new URL(location.href);
234 | const auditIdValuePairs = Object.entries(metricValues).map(([id, value]) => {
235 | return [id, value];
236 | });
237 | const params = new URLSearchParams(auditIdValuePairs);
238 | params.set('device', device);
239 | for (const version of versions) params.append('version', version);
240 | url.hash = params.toString();
241 | history.replaceState(state, '', url.toString());
242 | }
243 |
244 | componentDidUpdate() {
245 | this.debouncedUpdatePermalink(this.state);
246 | }
247 |
248 | onDeviceChange(e) {
249 | this.setState({device: e.target.value});
250 | }
251 |
252 | onVersionsChange(e) {
253 | this.setState({versions: e.target.value.split(',')});
254 | }
255 |
256 | normalizeVersions(versions) {
257 | return versions.map(version => {
258 | version = parseInt(version, 10);
259 | if (version < 5) {
260 | throw new Error(`Unsupported Lighthouse version (${version})`);
261 | }
262 |
263 | switch (version) {
264 | default:
265 | case 12:
266 | case 11:
267 | case 10:
268 | return 10;
269 | case 9:
270 | case 8:
271 | return 8;
272 | case 7:
273 | case 6:
274 | return 6;
275 | }
276 | });
277 | }
278 |
279 | render() {
280 | const {versions, device, metricValues} = this.state;
281 |
282 | const normalizedVersions = this.normalizeVersions(versions);
283 |
284 | const scoringGuideEls = normalizedVersions.map(version => {
285 | const key = `v${version}`;
286 | console.assert(scoringGuides[key], `scoringGuide for ${key} doesnt exist`)
287 | return ;
288 | });
289 | return
290 |
291 |
297 |
306 |
307 | {scoringGuideEls}
308 |
309 | }
310 | }
311 |
312 | function getInitialState() {
313 | const availableScoringGuides = Object.keys(scoringGuides).map(k => parseInt(k.replace('v',''), 10)).sort((a, b) => b - a);
314 |
315 | const versions = params.has('version') ?
316 | params.getAll('version').map(getMajorVersion) :
317 | [`${availableScoringGuides.at(0) || 8}`]; // version (or versions) to show by default
318 |
319 | // Default to mobile if it's not matching our known emulatedFormFactors. https://github.com/GoogleChrome/lighthouse/blob/master/types/externs.d.ts#:~:text=emulatedFormFactor
320 | let device = params.get('device');
321 | if (device && device !== 'mobile' && device !== 'desktop') {
322 | console.warn(`Invalid emulatedFormFactors value: ${device}. Fallback to mobile scoring.`);
323 | device = 'mobile';
324 | } else if (!device) {
325 | // Device not expressed in the params
326 | device = 'mobile';
327 | }
328 |
329 | const metricValues = {};
330 | // If no metric values come in w/ params, initalize with mobile medians (score of 50)
331 | const metricScorings = {...scoringGuides.v5.mobile, ...scoringGuides.v8.mobile}; // v5 is neccessary for FCI
332 | for (const id in metricScorings) {
333 | metricValues[id] = metricScorings[id].median;
334 | }
335 |
336 | // Populate metricValues from query string.
337 | for (const [id, metric] of Object.entries(metrics)) {
338 | const value = params.get(id) || params.get(metric.auditId);
339 | if (!value) continue;
340 | metricValues[id] = Number(value);
341 | }
342 |
343 | return {
344 | versions,
345 | device,
346 | metricValues,
347 | };;
348 | }
349 |
350 | function main() {
351 | render(, $('#container'));
352 | }
353 |
354 | // just one call to main because i'm basic like that
355 | main();
356 |
--------------------------------------------------------------------------------
/script/math.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Approximates the Gauss error function, the probability that a random variable
3 | * from the standard normal distribution lies within [-x, x]. Moved from
4 | * traceviewer.b.math.erf, based on Abramowitz and Stegun, formula 7.1.26.
5 | * @param {number} x
6 | * @return {number}
7 | */
8 | function internalErf_(x) {
9 | // erf(-x) = -erf(x);
10 | var sign = x < 0 ? -1 : 1;
11 | x = Math.abs(x);
12 |
13 | var a1 = 0.254829592;
14 | var a2 = -0.284496736;
15 | var a3 = 1.421413741;
16 | var a4 = -1.453152027;
17 | var a5 = 1.061405429;
18 | var p = 0.3275911;
19 | var t = 1 / (1 + p * x);
20 | var y = t * (a1 + t * (a2 + t * (a3 + t * (a4 + t * a5))));
21 | return sign * (1 - y * Math.exp(-x * x));
22 | }
23 |
24 | /**
25 | * Creates a log-normal distribution and finds the complementary
26 | * quantile (1-percentile) of that distribution at value. All
27 | * arguments should be in the same units (e.g. milliseconds).
28 | *
29 | * @param {{median: number, podr?: number, p10?: number}} curve
30 | * @param {number} value
31 | * @return The complement of the quantile at value.
32 | * @customfunction
33 | */
34 | export function QUANTILE_AT_VALUE({median, podr, p10}, value) {
35 | if (!podr) {
36 | podr = derivePodrFromP10(median, p10);
37 | }
38 |
39 | var location = Math.log(median);
40 |
41 | // The "podr" value specified the location of the smaller of the positive
42 | // roots of the third derivative of the log-normal CDF. Calculate the shape
43 | // parameter in terms of that value and the median.
44 | // See https://www.desmos.com/calculator/2t1ugwykrl
45 | var logRatio = Math.log(podr / median);
46 | var shape = Math.sqrt(1 - 3 * logRatio - Math.sqrt((logRatio - 3) * (logRatio - 3) - 8)) / 2;
47 |
48 | var standardizedX = (Math.log(value) - location) / (Math.SQRT2 * shape);
49 | return (1 - internalErf_(standardizedX)) / 2;
50 | }
51 |
52 | /**
53 | * Approximates the inverse error function. Based on Winitzki, "A handy
54 | * approximation for the error function and its inverse"
55 | * @param {number} x
56 | * @return {number}
57 | */
58 | function internalErfInv_(x) {
59 | // erfinv(-x) = -erfinv(x);
60 | var sign = x < 0 ? -1 : 1;
61 | var a = 0.147;
62 |
63 | var log1x = Math.log(1 - x*x);
64 | var p1 = 2 / (Math.PI * a) + log1x / 2;
65 | var sqrtP1Log = Math.sqrt(p1 * p1 - (log1x / a));
66 | return sign * Math.sqrt(sqrtP1Log - p1);
67 | }
68 |
69 | /**
70 | * Calculates the value at the given quantile. Median, podr, and
71 | * expected value should all be in the same units (e.g. milliseconds).
72 | * quantile should be within [0,1].
73 | *
74 | * @param {{median: number, podr?: number, p10?: number}} curve
75 | * @return The value at this quantile.
76 | * @customfunction
77 | */
78 | export function VALUE_AT_QUANTILE({median, podr, p10}, quantile) {
79 | if (!podr) {
80 | podr = derivePodrFromP10(median, p10);
81 | }
82 |
83 | var location = Math.log(median);
84 | var logRatio = Math.log(podr / median);
85 | var shape = Math.sqrt(1 - 3 * logRatio - Math.sqrt((logRatio - 3) * (logRatio - 3) - 8)) / 2;
86 |
87 | return Math.exp(location + shape * Math.SQRT2 * internalErfInv_(1 - 2 * quantile));
88 | }
89 |
90 | // https://www.desmos.com/calculator/oqlvmezbze
91 | function derivePodrFromP10(median, p10) {
92 | const u = Math.log(median);
93 | const shape = Math.abs(Math.log(p10) - u) / (Math.SQRT2 * 0.9061938024368232);
94 | const inner1 = -3 * shape - Math.sqrt(4 + shape * shape);
95 | const podr = Math.exp(u + shape/2 * inner1)
96 | return podr;
97 | }
98 |
--------------------------------------------------------------------------------
/script/metrics.js:
--------------------------------------------------------------------------------
1 | export const metrics = {
2 | FCP: {auditId: 'first-contentful-paint', name: 'First Contentful Paint'},
3 | SI: {auditId: 'speed-index', name: 'Speed Index'},
4 | LCP: {auditId: 'largest-contentful-paint', name: 'Largest Contentful Paint'},
5 | TTI: {auditId: 'interactive', name: 'Time to Interactive'},
6 | TBT: {auditId: 'total-blocking-time', name: 'Total Blocking Time'},
7 | CLS: {auditId: 'cumulative-layout-shift', name: 'Cumulative Layout Shift', units: 'unitless'},
8 | FMP: {auditId: 'first-meaningful-paint', name: 'First Meaningful Paint'},
9 | FCI: {auditId: 'first-cpu-idle', name: 'First CPU Idle'},
10 | };
11 |
12 | export const curves = {
13 | v10: {
14 | mobile: {
15 | FCP: {weight: 0.10, median: 3000, p10: 1800},
16 | SI: {weight: 0.10, median: 5800, p10: 3387},
17 | LCP: {weight: 0.25, median: 4000, p10: 2500},
18 | TBT: {weight: 0.30, median: 600, p10: 200},
19 | CLS: {weight: 0.25, median: 0.25, p10: 0.1},
20 | },
21 | desktop: {
22 | FCP: {weight: 0.10, median: 1600, p10: 934},
23 | SI: {weight: 0.10, median: 2300, p10: 1311},
24 | LCP: {weight: 0.25, median: 2400, p10: 1200},
25 | TBT: {weight: 0.30, median: 350, p10: 150},
26 | CLS: {weight: 0.25, median: 0.25, p10: 0.1},
27 | },
28 | },
29 | v8: {
30 | mobile: {
31 | FCP: {weight: 0.10, median: 3000, p10: 1800},
32 | SI: {weight: 0.10, median: 5800, p10: 3387},
33 | LCP: {weight: 0.25, median: 4000, p10: 2500},
34 | TTI: {weight: 0.10, median: 7300, p10: 3785},
35 | TBT: {weight: 0.30, median: 600, p10: 200},
36 | CLS: {weight: 0.15, median: 0.25, p10: 0.1},
37 | },
38 | desktop: {
39 | FCP: {weight: 0.10, median: 1600, p10: 934},
40 | SI: {weight: 0.10, median: 2300, p10: 1311},
41 | LCP: {weight: 0.25, median: 2400, p10: 1200},
42 | TTI: {weight: 0.10, median: 4500, p10: 2468},
43 | TBT: {weight: 0.30, median: 350, p10: 150},
44 | CLS: {weight: 0.15, median: 0.25, p10: 0.1},
45 | },
46 | },
47 | v6: {
48 | mobile: {
49 | FCP: {weight: 0.15, median: 4000, p10: 2336},
50 | SI: {weight: 0.15, median: 5800, p10: 3387},
51 | LCP: {weight: 0.25, median: 4000, p10: 2500},
52 | TTI: {weight: 0.15, median: 7300, p10: 3785},
53 | TBT: {weight: 0.25, median: 600, p10: 287},
54 | CLS: {weight: 0.05, median: 0.25, p10: 0.1},
55 | },
56 | desktop: {
57 | FCP: {weight: 0.15, median: 1600, p10: 934},
58 | SI: {weight: 0.15, median: 2300, p10: 1311},
59 | LCP: {weight: 0.25, median: 2400, p10: 1200},
60 | TTI: {weight: 0.15, median: 4500, p10: 2468},
61 | TBT: {weight: 0.25, median: 350, p10: 150},
62 | CLS: {weight: 0.05, median: 0.25, p10: 0.1},
63 | },
64 | },
65 | v5: {
66 | FCP: {weight: 0.2, median: 4000, podr: 2000},
67 | SI: {weight: 0.26666, median: 5800, podr: 2900},
68 | FMP: {weight: 0.066666, median: 4000, podr: 2000},
69 | TTI: {weight: 0.33333, median: 7300, podr: 2900},
70 | FCI: {weight: 0.133333, median: 6500, podr: 2900},
71 | },
72 | };
73 |
74 | /**
75 | * @param {Record} curves
76 | */
77 | function makeScoringGuide(curves) {
78 | const scoringGuide = {};
79 | for (const [key, curve] of Object.entries(curves)) {
80 | scoringGuide[key] = {...metrics[key], ...curve};
81 | }
82 | return scoringGuide;
83 | }
84 |
85 | export const scoringGuides = {
86 | // v9 => v8 and v7 => v6 is handled in normalizeVersions()
87 | v10: {
88 | mobile: makeScoringGuide(curves.v10.mobile),
89 | desktop: makeScoringGuide(curves.v10.desktop),
90 | },
91 | v8: {
92 | mobile: makeScoringGuide(curves.v8.mobile),
93 | desktop: makeScoringGuide(curves.v8.desktop),
94 | },
95 | v6: {
96 | mobile: makeScoringGuide(curves.v6.mobile),
97 | desktop: makeScoringGuide(curves.v6.desktop),
98 | },
99 | v5: {
100 | mobile: makeScoringGuide(curves.v5),
101 | desktop: makeScoringGuide(curves.v5),
102 | },
103 | };
104 |
--------------------------------------------------------------------------------
/script/util.js:
--------------------------------------------------------------------------------
1 |
2 | // blingjs
3 | export const $ = document.querySelector.bind(document);
4 | export const $$ = document.querySelectorAll.bind(document);
5 |
6 | Element.prototype.$ = Element.prototype.querySelector;
7 | Element.prototype.$$ = Element.prototype.querySelectorAll;
8 |
9 | export const NBSP = '\xa0';
10 | export const numberFormatter = new Intl.NumberFormat();
11 |
12 | // thx Lighthouse's util.js
13 | export function arithmeticMean(items) {
14 | items = items.filter(item => item.weight > 0);
15 | const results = items.reduce(
16 | (result, item) => {
17 | const score = item.result.score;
18 | const weight = item.weight;
19 | return {
20 | weight: result.weight + weight,
21 | sum: result.sum + score * weight,
22 | };
23 | },
24 | {weight: 0, sum: 0}
25 | );
26 | return results.sum / results.weight || 0;
27 | }
28 |
29 | export function calculateRating(score) {
30 | const RATINGS = {
31 | PASS: {label: 'pass', minScore: 0.9},
32 | AVERAGE: {label: 'average', minScore: 0.5},
33 | FAIL: {label: 'fail'},
34 | };
35 |
36 | let rating = RATINGS.FAIL.label;
37 | if (score >= RATINGS.PASS.minScore) {
38 | rating = RATINGS.PASS.label;
39 | } else if (score >= RATINGS.AVERAGE.minScore) {
40 | rating = RATINGS.AVERAGE.label;
41 | }
42 | return rating;
43 | }
44 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | html,
6 | body {
7 | background-color: hsla(225, 68%, 25%, 1);
8 | height: 100%;
9 | padding: 0;
10 |
11 | /* lighthouse css */
12 | font-family: var(--report-font-family);
13 | font-size: var(--report-font-size);
14 | margin: 0;
15 | line-height: var(--report-line-height);
16 | background: var(--report-background-color);
17 | scroll-behavior: smooth;
18 | color: var(--report-text-color);
19 |
20 | }
21 |
22 | [hidden] {
23 | display: none !important;
24 | }
25 |
26 | body {
27 | padding: 20px 0;
28 | }
29 |
30 | table {
31 | table-layout: fixed;
32 |
33 | /* this is some amazing shit. https://kennethormandy.com/journal/flipping-on-tabular-numbers/ */
34 | -webkit-font-feature-settings: "tnum";
35 | font-feature-settings: "tnum";
36 | font-variant-numeric: tabular-nums;
37 |
38 | margin: 0 auto;
39 | }
40 |
41 | th, .controls {
42 | font-weight: normal;
43 | color: var(--color-gray-600);
44 | word-break: normal;
45 | border-bottom: 1px solid var(--color-gray-200);
46 | }
47 |
48 | tr:first-child td {
49 | border-top: 8px solid transparent;
50 | }
51 |
52 | td {
53 | vertical-align: top;
54 | }
55 |
56 | /* icon */
57 | tbody td:nth-child(1) {
58 | width: 16px;
59 | }
60 |
61 | /* metric value */
62 | tbody td:nth-child(3) {
63 | text-align: right;
64 | }
65 |
66 | input.metric-value, tbody td:nth-child(3) {
67 | max-width: 210px;
68 | width: 18vw;
69 | }
70 |
71 | tbody td:nth-child(4) {
72 | width: 30px;
73 | }
74 |
75 | /* metric score */
76 | tbody td:nth-child(5) {
77 | text-align: right;
78 | font-size: 11px;
79 | }
80 | /* weighting */
81 | tbody td:nth-child(6) {
82 | width: 40px;
83 | text-align: right;
84 | }
85 |
86 |
87 | input.metric-score {
88 | opacity: 0.85;
89 | }
90 | output {
91 | display: block;
92 | line-height: 16px;
93 | margin-bottom: 8px;
94 | }
95 |
96 |
97 |
98 | section {
99 | display: flex;
100 | justify-content: center;
101 | align-items: center;
102 | }
103 |
104 | h1 {
105 | font-size: var(--gauge-label-font-size-big);
106 | line-height: var(--gauge-label-line-height-big);
107 | font-weight: normal;
108 | text-align: center;
109 | }
110 |
111 | h1 svg {
112 | height: var(--gauge-label-font-size-big);
113 | vertical-align: text-top;
114 | }
115 |
116 | h2 i {
117 | font-size: 60%;
118 | }
119 |
120 | footer {
121 | font-size: 80%;
122 | display: block !important;
123 | }
124 |
125 | @media screen and (max-width: 1040px) {
126 | footer {
127 | padding: 0 20px;
128 | }
129 | }
130 |
131 | .wrapper {
132 | max-width: 1020px;
133 | margin: 60px auto;
134 | min-width: 380px;
135 |
136 | display: flex;
137 | align-items: center;
138 | }
139 |
140 | .controls {
141 | margin: 30px auto;
142 | justify-content: center;
143 | border: 0;
144 | }
145 | select {
146 | color: var(--color-gray-600);
147 | }
148 |
149 | label {
150 | margin: 0 10px;
151 | }
152 |
153 | /* the SVG pretty big so we'll subtract some of its whitespace */
154 | .perfscore {
155 | margin-left: -20px;
156 | }
157 | /* keep the table on top tho. */
158 | table {
159 | position: relative;
160 | z-index: 10;
161 | }
162 |
163 | @media screen and (max-width: 890px) {
164 | .wrapper {
165 | flex-direction: column;
166 | }
167 | .perfscore {
168 | margin-left: 0;
169 | margin-top: -20px;
170 | }
171 | tbody td:nth-child(4) {
172 | width: 3px
173 | }
174 | }
175 |
176 | h2 {
177 | font-weight: 200;
178 | font-size: 21px;
179 | margin: 0;
180 | text-align: center;
181 | width: 70px;
182 | }
183 |
184 | form {
185 | overflow: hidden;
186 | }
187 |
188 |
189 |
190 |
191 | .weight-text {
192 | color: var(--color-gray-500);
193 | }
194 |
195 |
196 |
197 |
198 | /* Lighthouse styles */
199 |
200 | /* no idea which of these variables i dont need.. */
201 |
202 | :root {
203 |
204 | --palette-0: #1de9b6;
205 | --palette-1: #7c4dff;
206 | --palette-2: #ffb200;
207 | --palette-3: #00affe;
208 | --palette-4: #ff4181;
209 | --palette-5: #a1a1a1;
210 |
211 |
212 | /* Palette using Material Design Colors
213 | * https://www.materialui.co/colors */
214 | --color-amber-50: #FFF8E1;
215 | --color-blue-200: #90CAF9;
216 | --color-blue-900: #0D47A1;
217 | --color-blue-A700: #2962FF;
218 | --color-cyan-500: #00BCD4;
219 | --color-gray-100: #F5F5F5;
220 | --color-gray-200: #E0E0E0;
221 | --color-gray-400: #BDBDBD;
222 | --color-gray-50: #FAFAFA;
223 | --color-gray-500: #9E9E9E;
224 | --color-gray-600: #757575;
225 | --color-gray-700: #616161;
226 | --color-gray-800: #424242;
227 | --color-gray-900: #212121;
228 | --color-gray: #000000;
229 | --color-green-700: #018642;
230 | --color-green: #0CCE6B;
231 | --color-orange-700: #D04900;
232 | --color-orange: #FFA400;
233 | --color-red-700: #EB0F00;
234 | --color-red: #FF4E42;
235 | --color-teal-600: #00897B;
236 | --color-white: #FFFFFF;
237 |
238 | /* Context-specific colors */
239 | --color-average-secondary: var(--color-orange-700);
240 | --color-average: var(--color-orange);
241 | --color-fail-secondary: var(--color-red-700);
242 | --color-fail: var(--color-red);
243 | --color-informative: var(--color-blue-900);
244 | --color-pass-secondary: var(--color-green-700);
245 | --color-pass: var(--color-green);
246 | --color-hover: var(--color-gray-50);
247 |
248 | /* Component variables */
249 | --audit-description-padding-left: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right));
250 | --audit-explanation-line-height: 16px;
251 | --audit-group-margin-bottom: 40px;
252 | --audit-group-padding-vertical: 8px;
253 | --audit-margin-horizontal: 5px;
254 | --audit-padding-vertical: 8px;
255 | --category-header-font-size: 20px;
256 | --category-padding: 40px;
257 | --chevron-line-stroke: var(--color-gray-600);
258 | --chevron-size: 12px;
259 | --default-padding: 12px;
260 | --env-item-background-color: var(--color-gray-100);
261 | --env-item-font-size: 28px;
262 | --env-item-line-height: 36px;
263 | --env-item-padding: 10px 0px;
264 | --env-name-min-width: 220px;
265 | --footer-padding-vertical: 16px;
266 | --gauge-circle-size-big: 112px;
267 | --gauge-circle-size: 120px;
268 | --gauge-label-font-size-big: 28px;
269 | --gauge-label-font-size: 20px;
270 | --gauge-label-line-height-big: 36px;
271 | --gauge-label-line-height: 26px;
272 | --gauge-percentage-font-size-big: 38px;
273 | --gauge-percentage-font-size: 28px;
274 | --gauge-wrapper-width: 148px;
275 | --header-line-height: 24px;
276 | --highlighter-background-color: var(--report-text-color);
277 | --icon-square-size: calc(var(--score-icon-size) * 0.88);
278 | --image-preview-size: 48px;
279 | --metric-toggle-lines-fill: #7F7F7F;
280 | --metrics-toggle-background-color: var(--color-gray-200);
281 | --plugin-badge-background-color: var(--color-white);
282 | --plugin-badge-size-big: calc(var(--gauge-circle-size-big) / 2.7);
283 | --plugin-badge-size: calc(var(--gauge-circle-size) / 2.7);
284 | --plugin-icon-size: 65%;
285 | --pwa-icon-margin: 0 6px 0 -2px;
286 | --pwa-icon-size: var(--topbar-logo-size);
287 | --report-background-color: #fff;
288 | --report-border-color-secondary: #ebebeb;
289 | --report-font-family-monospace: 'Roboto Mono', 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;
290 | --report-font-family: Roboto, Helvetica, Arial, sans-serif;
291 | --report-font-size: 16px;
292 | --report-line-height: 24px;
293 | --report-min-width: 400px;
294 | --report-text-color-secondary: var(--color-gray-800);
295 | --report-text-color: var(--color-gray-900);
296 | --report-width: calc(60 * var(--report-font-size));
297 | --score-container-padding: 8px;
298 | --score-icon-background-size: 24px;
299 | --score-icon-margin-left: 4px;
300 | --score-icon-margin-right: 12px;
301 | --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);
302 | --score-icon-size: 12px;
303 | --scores-container-padding: 20px 0 20px 0;
304 | --scorescale-height: 6px;
305 | --scorescale-width: 18px;
306 | --section-padding-vertical: 12px;
307 | --snippet-background-color: var(--color-gray-50);
308 | --snippet-color: var(--color-gray-800);
309 | --sparkline-height: 5px;
310 | --stackpack-padding-horizontal: 10px;
311 | --sticky-header-background-color: var(--report-background-color);
312 | --table-higlight-background-color: hsla(0, 0%, 75%, 0.1);
313 | --tools-icon-color: var(--color-gray-600);
314 | --tools-icon-size: var(--score-icon-background-size);
315 | --topbar-background-color: var(--color-gray-100);
316 | --topbar-height: 32px;
317 | --topbar-logo-size: 24px;
318 | --topbar-padding: 0 8px;
319 | --toplevel-warning-padding: 22px;
320 |
321 | }
322 |
323 |
324 | /* score icon */
325 |
326 | .lh-metric__score-icon {
327 | width: var(--score-icon-size);
328 | height: var(--score-icon-size);
329 | display: inline-block;
330 | }
331 |
332 | .lh-metric--pass .lh-metric__display-text {
333 | color: var(--color-pass-secondary);
334 | }
335 | .lh-metric--pass .lh-metric__score-icon {
336 | border-radius: 100%;
337 | background: var(--color-pass);
338 | }
339 |
340 | .lh-metric--average .lh-metric__display-text {
341 | color: var(--color-average-secondary);
342 | }
343 | .lh-metric--average .lh-metric__score-icon {
344 | background: var(--color-average);
345 | width: var(--icon-square-size);
346 | height: var(--icon-square-size);
347 | }
348 |
349 | .lh-metric--fail .lh-metric__display-text {
350 | color: var(--color-fail-secondary);
351 | }
352 | .lh-metric--fail .lh-metric__score-icon,
353 | .lh-metric--error .lh-metric__score-icon {
354 | border-left: calc(var(--score-icon-size) / 2) solid transparent;
355 | border-right: calc(var(--score-icon-size) / 2) solid transparent;
356 | border-bottom: var(--score-icon-size) solid var(--color-fail);
357 | }
358 |
359 |
360 | /* the gauge! */
361 |
362 |
363 | circle {
364 | stroke: currentcolor;
365 | r: var(--radius);
366 | }
367 |
368 | text {
369 | font-size: calc(var(--radius) * 0.2);
370 | }
371 |
372 |
373 | .lh-gauge {
374 | margin: 0 auto;
375 | width: 225px;
376 | stroke-width: var(--stroke-width);
377 | stroke-linecap: round;
378 | }
379 | .lh-gauge--faded {
380 | opacity: 0.1;
381 | }
382 | .lh-gauge__wrapper {
383 | font-family: var(--report-font-family-monospace);
384 | text-align: center;
385 | text-decoration: none;
386 | transition: .3s;
387 | cursor:default;
388 | }
389 | .lh-gauge__wrapper--pass {
390 | color: var(--color-pass);
391 | }
392 | .lh-gauge__wrapper--average {
393 | color: var(--color-average);
394 | }
395 | .lh-gauge__wrapper--fail {
396 | color: var(--color-fail);
397 | }
398 | .state--expanded {
399 | /* color: var(--color-gray-600); */
400 | transition: color .3s;
401 | }
402 | .state--highlight {
403 | color: var(--color-highlight);
404 | }
405 | .lh-gauge__svg-wrapper {
406 | display: flex;
407 | flex-direction: column-reverse;
408 | }
409 |
410 | .lh-gauge__cutout {
411 | opacity: .999;
412 | transition: opacity .3s;
413 | }
414 | .state--highlight .lh-gauge__cutout {
415 | opacity: 0;
416 | }
417 |
418 | .lh-gauge__inner {
419 | color: inherit;
420 | }
421 | .lh-gauge__base {
422 | fill: currentcolor;
423 | }
424 |
425 |
426 | .lh-gauge__arc {
427 | fill: none;
428 | transition: opacity .3s;
429 | }
430 | .lh-gauge__arc--metric {
431 | color: var(--metric-color);
432 | stroke-dashoffset: var(--metric-offset);
433 | }
434 | .lh-gauge-hover {
435 | color: currentcolor;
436 | opacity: 0.001;
437 | stroke-linecap: butt;
438 | stroke-width: 24;
439 | /* hack. move the hover target out of the center. ideally i tweak the r instead but that rquires considerably more math. */
440 | transform: scale(1.15);
441 | /* I'll remove it when someone goes 'eh' */
442 | cursor: help;
443 | }
444 | .lh-gauge__arc--metric.lh-gauge--miniarc {
445 | opacity: 0;
446 | stroke-dasharray: 0 calc(var(--circle-meas) * var(--radius));
447 | transition: 0s .005s;
448 | }
449 | .state--expanded .lh-gauge__arc--metric.lh-gauge--miniarc {
450 | opacity: .999;
451 | stroke-dasharray: var(--metric-array);
452 | transition: 0.3s; /* calc(.005s + var(--i)*.05s); entrace animation */
453 | }
454 |
455 | .state--expanded .lh-gauge__base {
456 | fill: var(--color-gray-600);
457 | stroke: var(--color-gray-600);
458 | }
459 |
460 | .state--expanded .lh-gauge__inner .lh-gauge__arc {
461 | opacity: 0;
462 | }
463 |
464 |
465 | .lh-gauge__percentage {
466 | text-anchor: middle;
467 | dominant-baseline: middle;
468 | fill: currentcolor;
469 | opacity: .999;
470 | font-size: calc(var(--radius) * 0.625);
471 | transition: opacity .3s ease-in;
472 | }
473 | .state--highlight .lh-gauge__percentage {
474 | opacity: 0;
475 | }
476 |
477 | .cover {
478 | fill: none;
479 | opacity: .001;
480 | pointer-events: none;
481 | }
482 | .state--expanded .cover {
483 | pointer-events: auto;
484 | }
485 |
486 | .metric {
487 | transform: scale(var(--scale-initial));
488 | opacity: 0;
489 | transition: transform .1s .2s ease-out, opacity .3s ease-out;
490 | pointer-events: none;
491 | }
492 | .metric text {
493 | pointer-events: none;
494 | }
495 | .metric__value {
496 | fill: currentcolor;
497 | opacity: 0;
498 | transition: opacity 0.2s;
499 | }
500 | .state--expanded .metric {
501 | transform: scale(1);
502 | opacity: .999;
503 | transition: transform .3s ease-out, opacity .3s ease-in, stroke-width .1s ease-out;
504 | transition-delay: calc(var(--i)*.05s);
505 | pointer-events: auto;
506 | }
507 | .state--highlight .metric {
508 | opacity: .3;
509 | }
510 | .state--highlight .metric--highlight {
511 | opacity: .999;
512 | stroke-width: calc(1.5*var(--stroke-width));
513 | }
514 | .state--highlight .metric--highlight .metric__value {
515 | opacity: 0.999;
516 | }
517 |
518 |
519 | /*
520 | the initial first load peek
521 | */
522 | .lh-gauge__bg { /* needed for the use zindex stacking w/ transparency */
523 | fill: var(--report-background-color);
524 | stroke: var(--report-background-color);
525 | }
526 | .state--peek .metric {
527 | transition-delay: 0ms;
528 | animation: peek var(--peek-dur) cubic-bezier(0.46, 0.03, 0.52, 0.96);
529 | animation-fill-mode: forwards;
530 | }
531 | .state--peek .lh-gauge__inner .lh-gauge__arc {
532 | opacity: 1;
533 | }
534 | .state--peek .lh-gauge__arc.lh-gauge--faded:not(.lh-gauge-hover) {
535 | opacity: 0.3; /* just a tad stronger cuz its fighting with a big solid arg */
536 | }
537 | /* do i need to set expanded and override this? */
538 | .state--peek .lh-gauge__arc--metric.lh-gauge--miniarc {
539 | transition: opacity 0.3s;
540 | }
541 | .state--peek {
542 | color: unset;
543 | }
544 | .state--peek .metric__label {
545 | display: none;
546 | }
547 |
548 |
549 | @keyframes peek {
550 | /* biggest it should go is 0.92. smallest is 0.8 */
551 | 0% { transform: scale(0.8); opacity: 0.8; }
552 | 50% { transform: scale(0.92); opacity: 1; }
553 | 100% { transform: scale(0.8); opacity: 0.8; }
554 | }
--------------------------------------------------------------------------------
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 2,
3 | "github": {
4 | "silent": true
5 | }
6 | }
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@rollup/plugin-buble@^0.21.3":
6 | version "0.21.3"
7 | resolved "https://registry.yarnpkg.com/@rollup/plugin-buble/-/plugin-buble-0.21.3.tgz#1649a915b1d051a4f430d40e7734a7f67a69b33e"
8 | integrity sha512-Iv8cCuFPnMdqV4pcyU+OrfjOfagPArRQ1PyQjx5KgHk3dARedI+8PNTLSMpJts0lQJr8yF2pAU4GxpxCBJ9HYw==
9 | dependencies:
10 | "@rollup/pluginutils" "^3.0.8"
11 | "@types/buble" "^0.19.2"
12 | buble "^0.20.0"
13 |
14 | "@rollup/pluginutils@^3.0.8":
15 | version "3.0.10"
16 | resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.0.10.tgz#a659b9025920378494cd8f8c59fbf9b3a50d5f12"
17 | integrity sha512-d44M7t+PjmMrASHbhgpSbVgtL6EFyX7J4mYxwQ/c5eoaE6N2VgCgEcWVzNnwycIloti+/MpwFr8qfw+nRw00sw==
18 | dependencies:
19 | "@types/estree" "0.0.39"
20 | estree-walker "^1.0.1"
21 | picomatch "^2.2.2"
22 |
23 | "@types/buble@^0.19.2":
24 | version "0.19.2"
25 | resolved "https://registry.yarnpkg.com/@types/buble/-/buble-0.19.2.tgz#a4289d20b175b3c206aaad80caabdabe3ecdfdd1"
26 | integrity sha512-uUD8zIfXMKThmFkahTXDGI3CthFH1kMg2dOm3KLi4GlC5cbARA64bEcUMbbWdWdE73eoc/iBB9PiTMqH0dNS2Q==
27 | dependencies:
28 | magic-string "^0.25.0"
29 |
30 | "@types/estree@0.0.39":
31 | version "0.0.39"
32 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
33 | integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
34 |
35 | "@types/node@*":
36 | version "12.12.3"
37 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.3.tgz#ebfe83507ac506bc3486314a8aa395be66af8d23"
38 | integrity sha512-opgSsy+cEF9N8MgaVPnWVtdJ3o4mV2aMHvDq7thkQUFt0EuOHJon4rQpJfhjmNHB+ikl0Cd6WhWIErOyQ+f7tw==
39 |
40 | "@types/resolve@0.0.8":
41 | version "0.0.8"
42 | resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194"
43 | integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==
44 | dependencies:
45 | "@types/node" "*"
46 |
47 | acorn-dynamic-import@^4.0.0:
48 | version "4.0.0"
49 | resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948"
50 | integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==
51 |
52 | acorn-jsx@^5.2.0:
53 | version "5.2.0"
54 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe"
55 | integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==
56 |
57 | acorn@^6.4.1:
58 | version "6.4.1"
59 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
60 | integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
61 |
62 | ansi-regex@^5.0.0:
63 | version "5.0.1"
64 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
65 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
66 |
67 | ansi-styles@^3.2.1:
68 | version "3.2.1"
69 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
70 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
71 | dependencies:
72 | color-convert "^1.9.0"
73 |
74 | ansi-styles@^4.0.0:
75 | version "4.3.0"
76 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
77 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
78 | dependencies:
79 | color-convert "^2.0.1"
80 |
81 | array-union@^1.0.1:
82 | version "1.0.2"
83 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
84 | integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
85 | dependencies:
86 | array-uniq "^1.0.1"
87 |
88 | array-uniq@^1.0.1:
89 | version "1.0.3"
90 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
91 | integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
92 |
93 | async@^3.2.4:
94 | version "3.2.4"
95 | resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c"
96 | integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
97 |
98 | balanced-match@^1.0.0:
99 | version "1.0.0"
100 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
101 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
102 |
103 | brace-expansion@^1.1.7:
104 | version "1.1.11"
105 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
106 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
107 | dependencies:
108 | balanced-match "^1.0.0"
109 | concat-map "0.0.1"
110 |
111 | buble@^0.20.0:
112 | version "0.20.0"
113 | resolved "https://registry.yarnpkg.com/buble/-/buble-0.20.0.tgz#a143979a8d968b7f76b57f38f2e7ce7cfe938d1f"
114 | integrity sha512-/1gnaMQE8xvd5qsNBl+iTuyjJ9XxeaVxAMF86dQ4EyxFJOZtsgOS8Ra+7WHgZTam5IFDtt4BguN0sH0tVTKrOw==
115 | dependencies:
116 | acorn "^6.4.1"
117 | acorn-dynamic-import "^4.0.0"
118 | acorn-jsx "^5.2.0"
119 | chalk "^2.4.2"
120 | magic-string "^0.25.7"
121 | minimist "^1.2.5"
122 | regexpu-core "4.5.4"
123 |
124 | builtin-modules@^3.1.0:
125 | version "3.1.0"
126 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484"
127 | integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==
128 |
129 | chalk@^2.4.2:
130 | version "2.4.2"
131 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
132 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
133 | dependencies:
134 | ansi-styles "^3.2.1"
135 | escape-string-regexp "^1.0.5"
136 | supports-color "^5.3.0"
137 |
138 | cliui@^7.0.2:
139 | version "7.0.4"
140 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
141 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
142 | dependencies:
143 | string-width "^4.2.0"
144 | strip-ansi "^6.0.0"
145 | wrap-ansi "^7.0.0"
146 |
147 | color-convert@^1.9.0:
148 | version "1.9.3"
149 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
150 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
151 | dependencies:
152 | color-name "1.1.3"
153 |
154 | color-convert@^2.0.1:
155 | version "2.0.1"
156 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
157 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
158 | dependencies:
159 | color-name "~1.1.4"
160 |
161 | color-name@1.1.3:
162 | version "1.1.3"
163 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
164 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
165 |
166 | color-name@~1.1.4:
167 | version "1.1.4"
168 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
169 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
170 |
171 | commander@^2.18.0:
172 | version "2.20.3"
173 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
174 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
175 |
176 | commondir@^1.0.1:
177 | version "1.0.1"
178 | resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
179 | integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==
180 |
181 | concat-map@0.0.1:
182 | version "0.0.1"
183 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
184 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
185 |
186 | email-addresses@^5.0.0:
187 | version "5.0.0"
188 | resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-5.0.0.tgz#7ae9e7f58eef7d5e3e2c2c2d3ea49b78dc854fa6"
189 | integrity sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==
190 |
191 | emoji-regex@^8.0.0:
192 | version "8.0.0"
193 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
194 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
195 |
196 | escalade@^3.1.1:
197 | version "3.1.1"
198 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
199 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
200 |
201 | escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
202 | version "1.0.5"
203 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
204 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
205 |
206 | estree-walker@^0.6.1:
207 | version "0.6.1"
208 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
209 | integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
210 |
211 | estree-walker@^1.0.1:
212 | version "1.0.1"
213 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
214 | integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
215 |
216 | filename-reserved-regex@^2.0.0:
217 | version "2.0.0"
218 | resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229"
219 | integrity sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==
220 |
221 | filenamify@^4.3.0:
222 | version "4.3.0"
223 | resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-4.3.0.tgz#62391cb58f02b09971c9d4f9d63b3cf9aba03106"
224 | integrity sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==
225 | dependencies:
226 | filename-reserved-regex "^2.0.0"
227 | strip-outer "^1.0.1"
228 | trim-repeated "^1.0.0"
229 |
230 | find-cache-dir@^3.3.1:
231 | version "3.3.2"
232 | resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b"
233 | integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==
234 | dependencies:
235 | commondir "^1.0.1"
236 | make-dir "^3.0.2"
237 | pkg-dir "^4.1.0"
238 |
239 | find-up@^4.0.0:
240 | version "4.1.0"
241 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
242 | integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
243 | dependencies:
244 | locate-path "^5.0.0"
245 | path-exists "^4.0.0"
246 |
247 | fs-extra@^8.1.0:
248 | version "8.1.0"
249 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
250 | integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
251 | dependencies:
252 | graceful-fs "^4.2.0"
253 | jsonfile "^4.0.0"
254 | universalify "^0.1.0"
255 |
256 | fs.realpath@^1.0.0:
257 | version "1.0.0"
258 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
259 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
260 |
261 | fsevents@~2.3.1:
262 | version "2.3.2"
263 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
264 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
265 |
266 | get-caller-file@^2.0.5:
267 | version "2.0.5"
268 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
269 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
270 |
271 | gh-pages@^5.0.0:
272 | version "5.0.0"
273 | resolved "https://registry.yarnpkg.com/gh-pages/-/gh-pages-5.0.0.tgz#e0893272a0e33f0453e53a3c017c33b91ddd6394"
274 | integrity sha512-Nqp1SjkPIB94Xw/3yYNTUL+G2dxlhjvv1zeN/4kMC1jfViTEqhtVz/Ba1zSXHuvXCN9ADNS1dN4r5/J/nZWEQQ==
275 | dependencies:
276 | async "^3.2.4"
277 | commander "^2.18.0"
278 | email-addresses "^5.0.0"
279 | filenamify "^4.3.0"
280 | find-cache-dir "^3.3.1"
281 | fs-extra "^8.1.0"
282 | globby "^6.1.0"
283 |
284 | glob@^7.0.3:
285 | version "7.1.6"
286 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
287 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
288 | dependencies:
289 | fs.realpath "^1.0.0"
290 | inflight "^1.0.4"
291 | inherits "2"
292 | minimatch "^3.0.4"
293 | once "^1.3.0"
294 | path-is-absolute "^1.0.0"
295 |
296 | globby@^6.1.0:
297 | version "6.1.0"
298 | resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
299 | integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=
300 | dependencies:
301 | array-union "^1.0.1"
302 | glob "^7.0.3"
303 | object-assign "^4.0.1"
304 | pify "^2.0.0"
305 | pinkie-promise "^2.0.0"
306 |
307 | graceful-fs@^4.1.6, graceful-fs@^4.2.0:
308 | version "4.2.3"
309 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
310 | integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
311 |
312 | has-flag@^3.0.0:
313 | version "3.0.0"
314 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
315 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
316 |
317 | inflight@^1.0.4:
318 | version "1.0.6"
319 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
320 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
321 | dependencies:
322 | once "^1.3.0"
323 | wrappy "1"
324 |
325 | inherits@2:
326 | version "2.0.4"
327 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
328 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
329 |
330 | is-docker@^2.0.0:
331 | version "2.2.1"
332 | resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
333 | integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
334 |
335 | is-fullwidth-code-point@^3.0.0:
336 | version "3.0.0"
337 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
338 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
339 |
340 | is-module@^1.0.0:
341 | version "1.0.0"
342 | resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
343 | integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=
344 |
345 | is-reference@^1.1.2:
346 | version "1.1.4"
347 | resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.1.4.tgz#3f95849886ddb70256a3e6d062b1a68c13c51427"
348 | integrity sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==
349 | dependencies:
350 | "@types/estree" "0.0.39"
351 |
352 | is-wsl@^2.1.1:
353 | version "2.2.0"
354 | resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
355 | integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
356 | dependencies:
357 | is-docker "^2.0.0"
358 |
359 | jsesc@~0.5.0:
360 | version "0.5.0"
361 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
362 | integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
363 |
364 | jsonfile@^4.0.0:
365 | version "4.0.0"
366 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
367 | integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
368 | optionalDependencies:
369 | graceful-fs "^4.1.6"
370 |
371 | locate-path@^5.0.0:
372 | version "5.0.0"
373 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
374 | integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
375 | dependencies:
376 | p-locate "^4.1.0"
377 |
378 | magic-string@^0.25.0, magic-string@^0.25.7:
379 | version "0.25.7"
380 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
381 | integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
382 | dependencies:
383 | sourcemap-codec "^1.4.4"
384 |
385 | magic-string@^0.25.2:
386 | version "0.25.4"
387 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.4.tgz#325b8a0a79fc423db109b77fd5a19183b7ba5143"
388 | integrity sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw==
389 | dependencies:
390 | sourcemap-codec "^1.4.4"
391 |
392 | make-dir@^3.0.2:
393 | version "3.1.0"
394 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
395 | integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
396 | dependencies:
397 | semver "^6.0.0"
398 |
399 | minimatch@^3.0.4:
400 | version "3.0.4"
401 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
402 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
403 | dependencies:
404 | brace-expansion "^1.1.7"
405 |
406 | minimist@^1.2.5:
407 | version "1.2.5"
408 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
409 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
410 |
411 | nanoid@^3.1.22:
412 | version "3.1.22"
413 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.22.tgz#b35f8fb7d151990a8aebd5aa5015c03cf726f844"
414 | integrity sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==
415 |
416 | object-assign@^4.0.1:
417 | version "4.1.1"
418 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
419 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
420 |
421 | once@^1.3.0:
422 | version "1.4.0"
423 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
424 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
425 | dependencies:
426 | wrappy "1"
427 |
428 | open@^7.4.2:
429 | version "7.4.2"
430 | resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321"
431 | integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==
432 | dependencies:
433 | is-docker "^2.0.0"
434 | is-wsl "^2.1.1"
435 |
436 | p-limit@^2.2.0:
437 | version "2.3.0"
438 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
439 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
440 | dependencies:
441 | p-try "^2.0.0"
442 |
443 | p-locate@^4.1.0:
444 | version "4.1.0"
445 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
446 | integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
447 | dependencies:
448 | p-limit "^2.2.0"
449 |
450 | p-try@^2.0.0:
451 | version "2.2.0"
452 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
453 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
454 |
455 | path-exists@^4.0.0:
456 | version "4.0.0"
457 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
458 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
459 |
460 | path-is-absolute@^1.0.0:
461 | version "1.0.1"
462 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
463 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
464 |
465 | path-parse@^1.0.6:
466 | version "1.0.7"
467 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
468 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
469 |
470 | picomatch@^2.2.2:
471 | version "2.2.2"
472 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
473 | integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
474 |
475 | pify@^2.0.0:
476 | version "2.3.0"
477 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
478 | integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
479 |
480 | pinkie-promise@^2.0.0:
481 | version "2.0.1"
482 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
483 | integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
484 | dependencies:
485 | pinkie "^2.0.0"
486 |
487 | pinkie@^2.0.0:
488 | version "2.0.4"
489 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
490 | integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
491 |
492 | pkg-dir@^4.1.0:
493 | version "4.2.0"
494 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
495 | integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
496 | dependencies:
497 | find-up "^4.0.0"
498 |
499 | preact@^10.4.1:
500 | version "10.4.1"
501 | resolved "https://registry.yarnpkg.com/preact/-/preact-10.4.1.tgz#9b3ba020547673a231c6cf16f0fbaef0e8863431"
502 | integrity sha512-WKrRpCSwL2t3tpOOGhf2WfTpcmbpxaWtDbdJdKdjd0aEiTkvOmS4NBkG6kzlaAHI9AkQ3iVqbFWM3Ei7mZ4o1Q==
503 |
504 | regenerate-unicode-properties@^8.0.2:
505 | version "8.2.0"
506 | resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
507 | integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==
508 | dependencies:
509 | regenerate "^1.4.0"
510 |
511 | regenerate@^1.4.0:
512 | version "1.4.0"
513 | resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
514 | integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
515 |
516 | regexpu-core@4.5.4:
517 | version "4.5.4"
518 | resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae"
519 | integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==
520 | dependencies:
521 | regenerate "^1.4.0"
522 | regenerate-unicode-properties "^8.0.2"
523 | regjsgen "^0.5.0"
524 | regjsparser "^0.6.0"
525 | unicode-match-property-ecmascript "^1.0.4"
526 | unicode-match-property-value-ecmascript "^1.1.0"
527 |
528 | regjsgen@^0.5.0:
529 | version "0.5.1"
530 | resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c"
531 | integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==
532 |
533 | regjsparser@^0.6.0:
534 | version "0.6.4"
535 | resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272"
536 | integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==
537 | dependencies:
538 | jsesc "~0.5.0"
539 |
540 | require-directory@^2.1.1:
541 | version "2.1.1"
542 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
543 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
544 |
545 | resolve@^1.11.0, resolve@^1.11.1:
546 | version "1.12.0"
547 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6"
548 | integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==
549 | dependencies:
550 | path-parse "^1.0.6"
551 |
552 | rollup-plugin-commonjs@^10.1.0:
553 | version "10.1.0"
554 | resolved "https://registry.yarnpkg.com/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz#417af3b54503878e084d127adf4d1caf8beb86fb"
555 | integrity sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==
556 | dependencies:
557 | estree-walker "^0.6.1"
558 | is-reference "^1.1.2"
559 | magic-string "^0.25.2"
560 | resolve "^1.11.0"
561 | rollup-pluginutils "^2.8.1"
562 |
563 | rollup-plugin-node-resolve@^5.2.0:
564 | version "5.2.0"
565 | resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz#730f93d10ed202473b1fb54a5997a7db8c6d8523"
566 | integrity sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==
567 | dependencies:
568 | "@types/resolve" "0.0.8"
569 | builtin-modules "^3.1.0"
570 | is-module "^1.0.0"
571 | resolve "^1.11.1"
572 | rollup-pluginutils "^2.8.1"
573 |
574 | rollup-plugin-visualizer@^5.4.1:
575 | version "5.4.1"
576 | resolved "https://registry.yarnpkg.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.4.1.tgz#ec25c88d1ebab6d523e938c0084ca14cfe63b02e"
577 | integrity sha512-mwrUIfOamkCw3dCtLvgnn/H0rvNSDA1RAe0sO9uHBpmdf86j/xOX/2yeCrVh2Ia/gCGLG846JB00MW0chq8CHQ==
578 | dependencies:
579 | nanoid "^3.1.22"
580 | open "^7.4.2"
581 | source-map "^0.7.3"
582 | yargs "^16.2.0"
583 |
584 | rollup-pluginutils@^2.8.1:
585 | version "2.8.2"
586 | resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e"
587 | integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==
588 | dependencies:
589 | estree-walker "^0.6.1"
590 |
591 | rollup@^2.45.2:
592 | version "2.45.2"
593 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.45.2.tgz#8fb85917c9f35605720e92328f3ccbfba6f78b48"
594 | integrity sha512-kRRU7wXzFHUzBIv0GfoFFIN3m9oteY4uAsKllIpQDId5cfnkWF2J130l+27dzDju0E6MScKiV0ZM5Bw8m4blYQ==
595 | optionalDependencies:
596 | fsevents "~2.3.1"
597 |
598 | semver@^6.0.0:
599 | version "6.3.0"
600 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
601 | integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
602 |
603 | source-map@^0.7.3:
604 | version "0.7.3"
605 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
606 | integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
607 |
608 | sourcemap-codec@^1.4.4:
609 | version "1.4.6"
610 | resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz#e30a74f0402bad09807640d39e971090a08ce1e9"
611 | integrity sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==
612 |
613 | string-width@^4.1.0, string-width@^4.2.0:
614 | version "4.2.2"
615 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
616 | integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
617 | dependencies:
618 | emoji-regex "^8.0.0"
619 | is-fullwidth-code-point "^3.0.0"
620 | strip-ansi "^6.0.0"
621 |
622 | strip-ansi@^6.0.0:
623 | version "6.0.0"
624 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
625 | integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
626 | dependencies:
627 | ansi-regex "^5.0.0"
628 |
629 | strip-outer@^1.0.1:
630 | version "1.0.1"
631 | resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631"
632 | integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==
633 | dependencies:
634 | escape-string-regexp "^1.0.2"
635 |
636 | supports-color@^5.3.0:
637 | version "5.5.0"
638 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
639 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
640 | dependencies:
641 | has-flag "^3.0.0"
642 |
643 | trim-repeated@^1.0.0:
644 | version "1.0.0"
645 | resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21"
646 | integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE=
647 | dependencies:
648 | escape-string-regexp "^1.0.2"
649 |
650 | unicode-canonical-property-names-ecmascript@^1.0.4:
651 | version "1.0.4"
652 | resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
653 | integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==
654 |
655 | unicode-match-property-ecmascript@^1.0.4:
656 | version "1.0.4"
657 | resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c"
658 | integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==
659 | dependencies:
660 | unicode-canonical-property-names-ecmascript "^1.0.4"
661 | unicode-property-aliases-ecmascript "^1.0.4"
662 |
663 | unicode-match-property-value-ecmascript@^1.1.0:
664 | version "1.2.0"
665 | resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531"
666 | integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==
667 |
668 | unicode-property-aliases-ecmascript@^1.0.4:
669 | version "1.1.0"
670 | resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4"
671 | integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==
672 |
673 | universalify@^0.1.0:
674 | version "0.1.2"
675 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
676 | integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
677 |
678 | wrap-ansi@^7.0.0:
679 | version "7.0.0"
680 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
681 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
682 | dependencies:
683 | ansi-styles "^4.0.0"
684 | string-width "^4.1.0"
685 | strip-ansi "^6.0.0"
686 |
687 | wrappy@1:
688 | version "1.0.2"
689 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
690 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
691 |
692 | y18n@^5.0.5:
693 | version "5.0.8"
694 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
695 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
696 |
697 | yargs-parser@^20.2.2:
698 | version "20.2.7"
699 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a"
700 | integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==
701 |
702 | yargs@^16.2.0:
703 | version "16.2.0"
704 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
705 | integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
706 | dependencies:
707 | cliui "^7.0.2"
708 | escalade "^3.1.1"
709 | get-caller-file "^2.0.5"
710 | require-directory "^2.1.1"
711 | string-width "^4.2.0"
712 | y18n "^5.0.5"
713 | yargs-parser "^20.2.2"
714 |
--------------------------------------------------------------------------------