@svelte-vitals/core 0.36.1 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +22 -6
- package/dist/index.js +74 -55
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -956,6 +956,14 @@ interface RuleContext {
|
|
|
956
956
|
sourceFiles?: string[];
|
|
957
957
|
project: Project;
|
|
958
958
|
config: Config;
|
|
959
|
+
/**
|
|
960
|
+
* Report per-declaration counts of places this rule examined. The engine supplies it and keys the
|
|
961
|
+
* result by rule id; a rule that does not call it gets no entry, which is distinct from an entry of
|
|
962
|
+
* zeros. Absent in contexts a caller builds directly. Silent last-write-wins: calling it more than
|
|
963
|
+
* once keeps only the most recent map, with no merge and no error — call it once, with the complete
|
|
964
|
+
* counts, at the end of `check()`.
|
|
965
|
+
*/
|
|
966
|
+
recordExamined?: (counts: Record<string, number>) => void;
|
|
959
967
|
}
|
|
960
968
|
interface Rule {
|
|
961
969
|
id: string;
|
|
@@ -995,7 +1003,10 @@ declare function isPenalized(detection: Detection, treatDynamicAs: TreatDynamicA
|
|
|
995
1003
|
* Rules are independent, so they run concurrently; results are flattened in
|
|
996
1004
|
* rule order for stable output.
|
|
997
1005
|
*/
|
|
998
|
-
declare function runRules(rules: Rule[], ctx: RuleContext): Promise<
|
|
1006
|
+
declare function runRules(rules: Rule[], ctx: RuleContext): Promise<{
|
|
1007
|
+
results: Result[];
|
|
1008
|
+
examined: Record<string, Record<string, number>>;
|
|
1009
|
+
}>;
|
|
999
1010
|
|
|
1000
1011
|
/**
|
|
1001
1012
|
* seo/title-presence — every route should resolve a non-empty <title> (design §11).
|
|
@@ -1554,15 +1565,22 @@ interface JsonReport {
|
|
|
1554
1565
|
* and floors that sum once, so adding this map's already-floored entries and re-dividing can disagree.
|
|
1555
1566
|
*/
|
|
1556
1567
|
inventories: Record<string, number>;
|
|
1568
|
+
/**
|
|
1569
|
+
* Per-rule, per-declaration counts of places examined. Unlike `rules`, this describes the analysis
|
|
1570
|
+
* rather than the report: `--diff`, `--baseline` and suppressions do not narrow it. Three states: a
|
|
1571
|
+
* rule that reports no counts has no entry; a rule that counts but whose configuration declares
|
|
1572
|
+
* nothing has an empty entry; a declaration that judged nothing has an entry of `0`.
|
|
1573
|
+
*/
|
|
1574
|
+
examined?: Record<string, Record<string, number>>;
|
|
1557
1575
|
}
|
|
1558
1576
|
/** Build the structured JSON report object (design §7). The shape the `json` reporter emits (issue #24). */
|
|
1559
1577
|
declare function buildJsonReport(results: Result[], config: Config, meta: {
|
|
1560
1578
|
version: string;
|
|
1561
|
-
}, ruleIds?: readonly string[]): JsonReport;
|
|
1579
|
+
}, ruleIds?: readonly string[], examined?: Record<string, Record<string, number>>): JsonReport;
|
|
1562
1580
|
/** Render results as the documented JSON report string (design §7). */
|
|
1563
1581
|
declare function formatJsonReport(results: Result[], config: Config, meta: {
|
|
1564
1582
|
version: string;
|
|
1565
|
-
}, ruleIds?: readonly string[]): string;
|
|
1583
|
+
}, ruleIds?: readonly string[], examined?: Record<string, Record<string, number>>): string;
|
|
1566
1584
|
|
|
1567
1585
|
/** Render failing findings as an agent-actionable Markdown remediation document (issue #18). */
|
|
1568
1586
|
declare function formatAgentReport(results: Result[], config: Config): string;
|
|
@@ -1625,13 +1643,11 @@ declare const APP_SCRIPT: string;
|
|
|
1625
1643
|
declare function renderAppShell(snapshot: AppSnapshot): string;
|
|
1626
1644
|
/**
|
|
1627
1645
|
* Static (non-live) document over a prebuilt JsonReport — kept as the public name the
|
|
1628
|
-
* html reporter has always exported.
|
|
1646
|
+
* html reporter has always exported.
|
|
1629
1647
|
*/
|
|
1630
1648
|
declare function buildHtmlDocument(report: JsonReport, meta: {
|
|
1631
1649
|
version: string;
|
|
1632
1650
|
coreVersion?: string;
|
|
1633
|
-
}, opts?: {
|
|
1634
|
-
routeBadges?: Record<string, RouteBadge>;
|
|
1635
1651
|
}): string;
|
|
1636
1652
|
/** Render results as the self-contained HTML report (the CLI's `--reporter html`). */
|
|
1637
1653
|
declare function formatHtmlReport(results: Result[], config: Config, meta: {
|
package/dist/index.js
CHANGED
|
@@ -167,17 +167,9 @@ function collectEachBlocks(node, source, acc) {
|
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
var WALK_IGNORED_KEYS = /* @__PURE__ */ new Set(["type", "start", "end", "loc", "range"]);
|
|
170
|
+
var NO_BOUNDARIES = /* @__PURE__ */ new Set();
|
|
170
171
|
function walkEstree(node, visit) {
|
|
171
|
-
|
|
172
|
-
for (const child of node) walkEstree(child, visit);
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
if (!node || typeof node !== "object" || typeof node.type !== "string") return;
|
|
176
|
-
visit(node);
|
|
177
|
-
for (const key of Object.keys(node)) {
|
|
178
|
-
if (WALK_IGNORED_KEYS.has(key)) continue;
|
|
179
|
-
walkEstree(node[key], visit);
|
|
180
|
-
}
|
|
172
|
+
walkEvalScope(node, (n) => void visit(n), /* @__PURE__ */ new Set(), NO_BOUNDARIES);
|
|
181
173
|
}
|
|
182
174
|
function isEffectCall(node) {
|
|
183
175
|
const c = node?.callee;
|
|
@@ -280,18 +272,7 @@ function scopeIntroducedNames(node) {
|
|
|
280
272
|
return introduced;
|
|
281
273
|
}
|
|
282
274
|
function walkScoped(node, visit, shadowed = /* @__PURE__ */ new Set()) {
|
|
283
|
-
|
|
284
|
-
for (const child of node) walkScoped(child, visit, shadowed);
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
if (!node || typeof node !== "object" || typeof node.type !== "string") return;
|
|
288
|
-
const introduced = scopeIntroducedNames(node);
|
|
289
|
-
const scope = introduced.size > 0 ? /* @__PURE__ */ new Set([...shadowed, ...introduced]) : shadowed;
|
|
290
|
-
visit(node, scope);
|
|
291
|
-
for (const key of Object.keys(node)) {
|
|
292
|
-
if (WALK_IGNORED_KEYS.has(key)) continue;
|
|
293
|
-
walkScoped(node[key], visit, scope);
|
|
294
|
-
}
|
|
275
|
+
walkEvalScope(node, (n, scope) => void visit(n, scope), shadowed, NO_BOUNDARIES);
|
|
295
276
|
}
|
|
296
277
|
function collectStateWrites(root, stateNames, acc, kinds) {
|
|
297
278
|
const record = (name, kind) => {
|
|
@@ -769,7 +750,7 @@ function collectPropNames(program, includeBindable) {
|
|
|
769
750
|
let seen = 0;
|
|
770
751
|
let ambiguous = false;
|
|
771
752
|
walkEstree(program, (n) => {
|
|
772
|
-
if (n.type !== "VariableDeclarator" || !n.init || !isPropsCall(n.init)) return;
|
|
753
|
+
if (n.type !== "VariableDeclarator" || !n.init || !isPropsCall(unwrapTs(n.init))) return;
|
|
773
754
|
seen++;
|
|
774
755
|
if (n.id?.type === "Identifier") {
|
|
775
756
|
names.add(n.id.name);
|
|
@@ -842,7 +823,7 @@ function countProps(program) {
|
|
|
842
823
|
let seen = 0;
|
|
843
824
|
let uncountable = false;
|
|
844
825
|
walkEstree(program, (n) => {
|
|
845
|
-
if (n.type !== "VariableDeclarator" || !n.init || !isPropsCall(n.init)) return;
|
|
826
|
+
if (n.type !== "VariableDeclarator" || !n.init || !isPropsCall(unwrapTs(n.init))) return;
|
|
846
827
|
seen++;
|
|
847
828
|
const props = n.id?.type === "ObjectPattern" ? n.id.properties : void 0;
|
|
848
829
|
if (!Array.isArray(props) || props.some((p) => p?.type === "RestElement")) {
|
|
@@ -958,19 +939,19 @@ var EVAL_SCOPE_BOUNDARIES = /* @__PURE__ */ new Set([
|
|
|
958
939
|
"ClassDeclaration",
|
|
959
940
|
"ClassExpression"
|
|
960
941
|
]);
|
|
961
|
-
function walkEvalScope(node, visit, shadowed = /* @__PURE__ */ new Set()) {
|
|
942
|
+
function walkEvalScope(node, visit, shadowed = /* @__PURE__ */ new Set(), boundaries = EVAL_SCOPE_BOUNDARIES) {
|
|
962
943
|
if (Array.isArray(node)) {
|
|
963
|
-
for (const child of node) walkEvalScope(child, visit, shadowed);
|
|
944
|
+
for (const child of node) walkEvalScope(child, visit, shadowed, boundaries);
|
|
964
945
|
return;
|
|
965
946
|
}
|
|
966
947
|
if (!node || typeof node !== "object" || typeof node.type !== "string") return;
|
|
967
948
|
const introduced = scopeIntroducedNames(node);
|
|
968
949
|
const scope = introduced.size > 0 ? /* @__PURE__ */ new Set([...shadowed, ...introduced]) : shadowed;
|
|
969
950
|
if (visit(node, scope)) return;
|
|
970
|
-
if (
|
|
951
|
+
if (boundaries.has(node.type)) return;
|
|
971
952
|
for (const key of Object.keys(node)) {
|
|
972
953
|
if (WALK_IGNORED_KEYS.has(key)) continue;
|
|
973
|
-
walkEvalScope(node[key], visit, scope);
|
|
954
|
+
walkEvalScope(node[key], visit, scope, boundaries);
|
|
974
955
|
}
|
|
975
956
|
}
|
|
976
957
|
function collectEvalScopeCalls(root, source, matcher, skipSubtree, initialShadowed) {
|
|
@@ -1261,13 +1242,13 @@ function collectModuleStateDecls(program, source) {
|
|
|
1261
1242
|
const decl = unwrapExport(stmt);
|
|
1262
1243
|
if (decl?.type === "VariableDeclaration") {
|
|
1263
1244
|
for (const d of decl.declarations ?? []) {
|
|
1264
|
-
if (d?.id?.type === "Identifier" && d.init && isStateDeclaration(d.init)) {
|
|
1245
|
+
if (d?.id?.type === "Identifier" && d.init && isStateDeclaration(unwrapTs(d.init))) {
|
|
1265
1246
|
out.push({ name: d.id.name, line: lineOf(source, d.start) });
|
|
1266
1247
|
}
|
|
1267
1248
|
}
|
|
1268
1249
|
} else if (decl?.type === "ClassDeclaration" && decl.id?.type === "Identifier") {
|
|
1269
1250
|
const hasStateField = (decl.body?.body ?? []).some(
|
|
1270
|
-
(m) => m?.type === "PropertyDefinition" && m.value && isStateDeclaration(m.value)
|
|
1251
|
+
(m) => m?.type === "PropertyDefinition" && m.value && isStateDeclaration(unwrapTs(m.value))
|
|
1271
1252
|
);
|
|
1272
1253
|
if (hasStateField) statefulClasses.add(decl.id.name);
|
|
1273
1254
|
}
|
|
@@ -1303,6 +1284,17 @@ function parseModuleFacts(source, filename) {
|
|
|
1303
1284
|
for (const l of raw) basePathLinks.push({ ...l, line: shift(l.line) });
|
|
1304
1285
|
basePathLinks.sort((a, b) => a.line - b.line);
|
|
1305
1286
|
}
|
|
1287
|
+
const importSpans = [];
|
|
1288
|
+
const namespaceImports = [];
|
|
1289
|
+
if (program) {
|
|
1290
|
+
const rawImportSpans = [];
|
|
1291
|
+
collectImportSources(program, wrapped, rawImportSpans);
|
|
1292
|
+
for (const s of rawImportSpans) importSpans.push({ ...s, line: shift(s.line) });
|
|
1293
|
+
const rawNamespaceImports = [];
|
|
1294
|
+
collectNamespaceImports(program, wrapped, rawNamespaceImports);
|
|
1295
|
+
for (const n of rawNamespaceImports) namespaceImports.push({ ...n, line: shift(n.line) });
|
|
1296
|
+
}
|
|
1297
|
+
const imports = importSpans.map((s) => s.source);
|
|
1306
1298
|
return {
|
|
1307
1299
|
eachBlocks: [],
|
|
1308
1300
|
effects: [],
|
|
@@ -1310,9 +1302,9 @@ function parseModuleFacts(source, filename) {
|
|
|
1310
1302
|
javascriptUrls: [],
|
|
1311
1303
|
loc: 0,
|
|
1312
1304
|
propCount: 0,
|
|
1313
|
-
imports
|
|
1314
|
-
importSpans
|
|
1315
|
-
namespaceImports
|
|
1305
|
+
imports,
|
|
1306
|
+
importSpans,
|
|
1307
|
+
namespaceImports,
|
|
1316
1308
|
constableStates: [],
|
|
1317
1309
|
mutatedProps: [],
|
|
1318
1310
|
stalePropDerivations: [],
|
|
@@ -1409,11 +1401,12 @@ function parseComponentFacts(source, filename) {
|
|
|
1409
1401
|
const stateDecls = [];
|
|
1410
1402
|
walkEstree(program, (n) => {
|
|
1411
1403
|
if (n.type !== "VariableDeclarator" || !n.init) return;
|
|
1412
|
-
|
|
1404
|
+
const init = unwrapTs(n.init);
|
|
1405
|
+
if (isStateDeclaration(init) && n.id?.type === "Identifier") {
|
|
1413
1406
|
stateNames.add(n.id.name);
|
|
1414
1407
|
stateDecls.push({ name: n.id.name, line: lineOf(source, n.start) });
|
|
1415
1408
|
}
|
|
1416
|
-
if (isStateDeclaration(
|
|
1409
|
+
if (isStateDeclaration(init) || isDerivedDeclaration(init) || isPropsCall(init))
|
|
1417
1410
|
addBoundNames(n.id, reactiveNames);
|
|
1418
1411
|
});
|
|
1419
1412
|
walkEstree(program, (n) => {
|
|
@@ -1440,8 +1433,10 @@ function parseComponentFacts(source, filename) {
|
|
|
1440
1433
|
for (const stmt of program.body ?? []) {
|
|
1441
1434
|
if (stmt?.type !== "VariableDeclaration") continue;
|
|
1442
1435
|
for (const d of stmt.declarations ?? []) {
|
|
1443
|
-
if (d?.id?.type !== "Identifier" || !d.init
|
|
1444
|
-
const
|
|
1436
|
+
if (d?.id?.type !== "Identifier" || !d.init) continue;
|
|
1437
|
+
const init = unwrapTs(d.init);
|
|
1438
|
+
if (!isPlainStateCall(init)) continue;
|
|
1439
|
+
const arg = unwrapTs(init.arguments?.[0]);
|
|
1445
1440
|
if (arg?.type === "ObjectExpression" || arg?.type === "ArrayExpression") {
|
|
1446
1441
|
rawableCandidates.push({ name: d.id.name, line: lineOf(source, d.start) });
|
|
1447
1442
|
}
|
|
@@ -1475,8 +1470,10 @@ function parseComponentFacts(source, filename) {
|
|
|
1475
1470
|
for (const stmt of program.body ?? []) {
|
|
1476
1471
|
if (stmt?.type !== "VariableDeclaration") continue;
|
|
1477
1472
|
for (const d of stmt.declarations ?? []) {
|
|
1478
|
-
if (d?.id?.type !== "Identifier" || !d.init
|
|
1479
|
-
const
|
|
1473
|
+
if (d?.id?.type !== "Identifier" || !d.init) continue;
|
|
1474
|
+
const init = unwrapTs(d.init);
|
|
1475
|
+
if (!isPlainStateCall(init)) continue;
|
|
1476
|
+
const arg = unwrapTs(init.arguments?.[0]);
|
|
1480
1477
|
if (arg?.type === "NewExpression" && arg.callee?.type === "Identifier" && BUILTIN_STATE_TYPES.has(arg.callee.name)) {
|
|
1481
1478
|
builtinCandidates.set(d.id.name, { type: arg.callee.name, line: lineOf(source, d.start) });
|
|
1482
1479
|
}
|
|
@@ -2444,8 +2441,11 @@ function isPenalized(detection, treatDynamicAs) {
|
|
|
2444
2441
|
|
|
2445
2442
|
// src/engine.ts
|
|
2446
2443
|
async function runRules(rules, ctx) {
|
|
2447
|
-
const
|
|
2448
|
-
|
|
2444
|
+
const examined = {};
|
|
2445
|
+
const perRule = await Promise.all(
|
|
2446
|
+
rules.map((rule) => rule.check({ ...ctx, recordExamined: (counts) => void (examined[rule.id] = counts) }))
|
|
2447
|
+
);
|
|
2448
|
+
return { results: perRule.flat(), examined };
|
|
2449
2449
|
}
|
|
2450
2450
|
|
|
2451
2451
|
// src/rules/seo/title-presence.ts
|
|
@@ -3511,7 +3511,6 @@ var PLACEHOLDER_RES = [
|
|
|
3511
3511
|
/yourcompany/i,
|
|
3512
3512
|
/your name here/i
|
|
3513
3513
|
];
|
|
3514
|
-
var PLACEHOLDERS = PLACEHOLDER_RES.map((r) => r.source);
|
|
3515
3514
|
function hasPlaceholder(s) {
|
|
3516
3515
|
return PLACEHOLDER_RES.some((re) => re.test(s));
|
|
3517
3516
|
}
|
|
@@ -3743,14 +3742,12 @@ var seoJsonLdRequiredProps = jsonldRule({
|
|
|
3743
3742
|
});
|
|
3744
3743
|
|
|
3745
3744
|
// src/rules/seo/text-metrics.ts
|
|
3746
|
-
var segmenter =
|
|
3745
|
+
var segmenter = new Intl.Segmenter();
|
|
3747
3746
|
function collapseWhitespace(s) {
|
|
3748
3747
|
return s.trim().replace(/\s+/g, " ");
|
|
3749
3748
|
}
|
|
3750
3749
|
function visibleLength(s) {
|
|
3751
|
-
|
|
3752
|
-
if (!segmenter) return [...collapsed].length;
|
|
3753
|
-
return [...segmenter.segment(collapsed)].length;
|
|
3750
|
+
return [...segmenter.segment(collapseWhitespace(s))].length;
|
|
3754
3751
|
}
|
|
3755
3752
|
|
|
3756
3753
|
// src/rules/seo/length-rule.ts
|
|
@@ -5479,6 +5476,8 @@ var architectureReservedNamePlacement = {
|
|
|
5479
5476
|
}
|
|
5480
5477
|
}
|
|
5481
5478
|
const usedAlternatives = /* @__PURE__ */ new Set();
|
|
5479
|
+
const examinedCounts = {};
|
|
5480
|
+
for (const key of globalAlternatives.keys()) examinedCounts[key] = 0;
|
|
5482
5481
|
const allDirs = [...dirs].sort();
|
|
5483
5482
|
for (const dir of allDirs) {
|
|
5484
5483
|
const o = resolveRuleOptions(ID7, OPTIONS6, ctx.config, { route: dir, file: dir }, compiledOverrides);
|
|
@@ -5503,6 +5502,17 @@ var architectureReservedNamePlacement = {
|
|
|
5503
5502
|
if (isExcluded(dir, ancestorDirs2(dir), excluded)) {
|
|
5504
5503
|
continue;
|
|
5505
5504
|
}
|
|
5505
|
+
const judged = /* @__PURE__ */ new Set();
|
|
5506
|
+
const resolvedValues = [
|
|
5507
|
+
["placements", placements[name]],
|
|
5508
|
+
["capitalisedUnitPlacements", capUnits[name]],
|
|
5509
|
+
["anyCaseUnitPlacements", anyUnits[name]]
|
|
5510
|
+
];
|
|
5511
|
+
for (const [map, value] of resolvedValues) {
|
|
5512
|
+
if (value === void 0) continue;
|
|
5513
|
+
for (const glob of globsOf(value)) judged.add(label(map, name, glob));
|
|
5514
|
+
}
|
|
5515
|
+
for (const key of judged) if (globalAlternatives.has(key)) examinedCounts[key] = (examinedCounts[key] ?? 0) + 1;
|
|
5506
5516
|
const record = (map, value, qualifies) => {
|
|
5507
5517
|
if (value === void 0) return false;
|
|
5508
5518
|
const { matched } = matchKeys(parent, compile(globsOf(value), true));
|
|
@@ -5571,6 +5581,7 @@ var architectureReservedNamePlacement = {
|
|
|
5571
5581
|
docsUrl: docsUrl11
|
|
5572
5582
|
});
|
|
5573
5583
|
}
|
|
5584
|
+
ctx.recordExamined?.(examinedCounts);
|
|
5574
5585
|
return out;
|
|
5575
5586
|
}
|
|
5576
5587
|
};
|
|
@@ -6258,7 +6269,7 @@ function ruleEvidence(results, config, ruleIds) {
|
|
|
6258
6269
|
}
|
|
6259
6270
|
return out;
|
|
6260
6271
|
}
|
|
6261
|
-
function buildJsonReport(results, config, meta, ruleIds) {
|
|
6272
|
+
function buildJsonReport(results, config, meta, ruleIds, examined) {
|
|
6262
6273
|
const { health, categories: byCat, weights } = computeHealth(results, config);
|
|
6263
6274
|
const summary = summarize(results, config);
|
|
6264
6275
|
const rules = ruleEvidence(results, config, ruleIds);
|
|
@@ -6288,10 +6299,21 @@ function buildJsonReport(results, config, meta, ruleIds) {
|
|
|
6288
6299
|
const inventories = Object.fromEntries(
|
|
6289
6300
|
[...buildInventory(config)].map(([pair, weight]) => [pair, Math.max(weight, INVENTORY_FLOOR)])
|
|
6290
6301
|
);
|
|
6291
|
-
return {
|
|
6302
|
+
return {
|
|
6303
|
+
version: meta.version,
|
|
6304
|
+
score: health,
|
|
6305
|
+
weights,
|
|
6306
|
+
categories,
|
|
6307
|
+
summary,
|
|
6308
|
+
rules,
|
|
6309
|
+
routes,
|
|
6310
|
+
siteIssues,
|
|
6311
|
+
inventories,
|
|
6312
|
+
...examined && Object.keys(examined).length > 0 ? { examined } : {}
|
|
6313
|
+
};
|
|
6292
6314
|
}
|
|
6293
|
-
function formatJsonReport(results, config, meta, ruleIds) {
|
|
6294
|
-
return JSON.stringify(buildJsonReport(results, config, meta, ruleIds), null, 2);
|
|
6315
|
+
function formatJsonReport(results, config, meta, ruleIds, examined) {
|
|
6316
|
+
return JSON.stringify(buildJsonReport(results, config, meta, ruleIds, examined), null, 2);
|
|
6295
6317
|
}
|
|
6296
6318
|
|
|
6297
6319
|
// src/reporter/agent.ts
|
|
@@ -7174,13 +7196,10 @@ function renderAppShell(snapshot) {
|
|
|
7174
7196
|
const title = snapshot.live ? "svelte-vitals dashboard" : "svelte-vitals report";
|
|
7175
7197
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${title}</title><style>${APP_STYLE}</style></head><body><div class="dv-app" id="dv-app"><header class="dv-topbar" id="dv-topbar"></header><nav class="dv-sidebar" id="dv-sidebar"></nav><main class="dv-detail" id="dv-detail"></main></div><script type="application/json" id="svelte-vitals-data">${embedJson(safe)}</script><script>${APP_SCRIPT}</script></body></html>`;
|
|
7176
7198
|
}
|
|
7177
|
-
function buildHtmlDocument(report, meta
|
|
7178
|
-
const badges = Object.fromEntries(
|
|
7179
|
-
Object.entries(opts?.routeBadges ?? {}).filter(([, b]) => b === "measured" || b === "static")
|
|
7180
|
-
);
|
|
7199
|
+
function buildHtmlDocument(report, meta) {
|
|
7181
7200
|
return renderAppShell({
|
|
7182
7201
|
report,
|
|
7183
|
-
badges,
|
|
7202
|
+
badges: {},
|
|
7184
7203
|
analyzing: false,
|
|
7185
7204
|
sequence: 0,
|
|
7186
7205
|
live: false,
|