@svelte-vitals/core 0.31.0 → 0.31.1
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 +13 -6
- package/dist/index.js +15 -12
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -946,9 +946,9 @@ interface Rule {
|
|
|
946
946
|
severity: Severity;
|
|
947
947
|
/** 'route' = evaluated per route, 'project' = site-wide (design §10, §12). */
|
|
948
948
|
scope: Scope;
|
|
949
|
-
/** Why this rule matters — one or two sentences, surfaced by
|
|
949
|
+
/** Why this rule matters — one or two sentences, surfaced by `svelte-vitals explain` (issue #24). */
|
|
950
950
|
rationale: string;
|
|
951
|
-
/** Canonical remediation template, shared by findings and
|
|
951
|
+
/** Canonical remediation template, shared by findings and `svelte-vitals explain` (issue #24). */
|
|
952
952
|
fix?: Fix;
|
|
953
953
|
/** Configurable options for this rule; absent means the rule takes none. */
|
|
954
954
|
options?: RuleOptionsSpec;
|
|
@@ -1290,7 +1290,7 @@ declare const performanceStateRaw: Rule;
|
|
|
1290
1290
|
|
|
1291
1291
|
declare const allRules: Rule[];
|
|
1292
1292
|
|
|
1293
|
-
/** One configurable option of a rule, flattened for
|
|
1293
|
+
/** One configurable option of a rule, flattened for `svelte-vitals explain`'s output. */
|
|
1294
1294
|
interface RuleOptionInfo {
|
|
1295
1295
|
name: string;
|
|
1296
1296
|
/** `integer` replaces the default; `string-list`/`string-map` are ADDED to it. */
|
|
@@ -1314,7 +1314,7 @@ interface RuleInfo {
|
|
|
1314
1314
|
*/
|
|
1315
1315
|
options?: RuleOptionInfo[];
|
|
1316
1316
|
}
|
|
1317
|
-
/** Look up a rule's static metadata
|
|
1317
|
+
/** Look up a rule's static metadata, as `svelte-vitals explain` renders it (issue #24). Rule ids are matched exactly (case-sensitive, e.g. "seo/ssr-disabled"). */
|
|
1318
1318
|
declare function explainRule(id: string): RuleInfo | undefined;
|
|
1319
1319
|
|
|
1320
1320
|
interface HeadTagRuleOptions {
|
|
@@ -1326,7 +1326,7 @@ interface HeadTagRuleOptions {
|
|
|
1326
1326
|
/** Short human label, e.g. 'description'. */
|
|
1327
1327
|
label: string;
|
|
1328
1328
|
recommendation: string;
|
|
1329
|
-
/** Why this rule matters — surfaced by
|
|
1329
|
+
/** Why this rule matters — surfaced by `svelte-vitals explain` (issue #24). */
|
|
1330
1330
|
rationale: string;
|
|
1331
1331
|
/** Agent-actionable remediation attached to every finding (issue #18). */
|
|
1332
1332
|
fix?: Fix;
|
|
@@ -1432,7 +1432,14 @@ interface ScoreModel {
|
|
|
1432
1432
|
criticalCap: number | null;
|
|
1433
1433
|
}
|
|
1434
1434
|
interface ScoreResult {
|
|
1435
|
+
/** The score as displayed: `Math.floor(rawScore)`, so 100 means the deduction was exactly zero. */
|
|
1435
1436
|
score: number;
|
|
1437
|
+
/**
|
|
1438
|
+
* The same score before flooring, after `sitePenalty` and the cap, clamped to `[0, 100]`. Exposed so
|
|
1439
|
+
* `computeHealth` can average unrounded values and floor once — averaging the displayed scores would
|
|
1440
|
+
* compose two roundings and move Health by up to two points.
|
|
1441
|
+
*/
|
|
1442
|
+
rawScore: number;
|
|
1436
1443
|
scoreModel: ScoreModel;
|
|
1437
1444
|
}
|
|
1438
1445
|
interface ScoreOptions {
|
|
@@ -1482,7 +1489,7 @@ interface JsonReport {
|
|
|
1482
1489
|
}>;
|
|
1483
1490
|
siteIssues: JsonIssue[];
|
|
1484
1491
|
}
|
|
1485
|
-
/** Build the structured JSON report object (design §7).
|
|
1492
|
+
/** Build the structured JSON report object (design §7). The shape the `json` reporter emits (issue #24). */
|
|
1486
1493
|
declare function buildJsonReport(results: Result[], config: Config, meta: {
|
|
1487
1494
|
version: string;
|
|
1488
1495
|
}): JsonReport;
|
package/dist/index.js
CHANGED
|
@@ -4938,7 +4938,7 @@ var architectureUnitEntryFile = {
|
|
|
4938
4938
|
category: "architecture",
|
|
4939
4939
|
severity: "info",
|
|
4940
4940
|
detection: { presence: "own", value: "static" },
|
|
4941
|
-
|
|
4941
|
+
location: expected,
|
|
4942
4942
|
message: "Unit entry file",
|
|
4943
4943
|
recommendation: recommendation8,
|
|
4944
4944
|
docsUrl: docsUrl8
|
|
@@ -5641,7 +5641,8 @@ function computeScore(results, config, options = {}) {
|
|
|
5641
5641
|
routeScores.set(route, routeScores.get(route) - deduction);
|
|
5642
5642
|
}
|
|
5643
5643
|
const scores = [...routeScores.values()].map(clamp);
|
|
5644
|
-
const
|
|
5644
|
+
const rawRouteAverage = scores.length ? scores.reduce((a, b) => a + b, 0) / scores.length : 100;
|
|
5645
|
+
const routeAverage = Math.floor(rawRouteAverage);
|
|
5645
5646
|
const projectRuleMax = /* @__PURE__ */ new Map();
|
|
5646
5647
|
for (const r of projectResults) {
|
|
5647
5648
|
if (!isPenalized(r.detection, config.treatDynamicAs)) continue;
|
|
@@ -5653,11 +5654,11 @@ function computeScore(results, config, options = {}) {
|
|
|
5653
5654
|
let sitePenalty = 0;
|
|
5654
5655
|
for (const deduction of projectRuleMax.values()) sitePenalty += deduction;
|
|
5655
5656
|
const applyCap = options.applyCriticalCap ?? true;
|
|
5656
|
-
const
|
|
5657
|
-
const capBinds = applyCap && anyCritical &&
|
|
5657
|
+
const rawUncapped = rawRouteAverage - sitePenalty;
|
|
5658
|
+
const capBinds = applyCap && anyCritical && rawUncapped > CRITICAL_CAP;
|
|
5658
5659
|
const criticalCap = capBinds ? CRITICAL_CAP : null;
|
|
5659
|
-
const
|
|
5660
|
-
return { score:
|
|
5660
|
+
const rawScore = clamp(capBinds ? CRITICAL_CAP : rawUncapped);
|
|
5661
|
+
return { score: Math.floor(rawScore), rawScore, scoreModel: { routeAverage, sitePenalty, criticalCap } };
|
|
5661
5662
|
}
|
|
5662
5663
|
function scoresByCategory(results, config) {
|
|
5663
5664
|
const byCat = /* @__PURE__ */ new Map();
|
|
@@ -5674,7 +5675,7 @@ function scoresByCategory(results, config) {
|
|
|
5674
5675
|
function computeHealth(results, config) {
|
|
5675
5676
|
const categories = scoresByCategory(results, config);
|
|
5676
5677
|
const weights = {};
|
|
5677
|
-
let
|
|
5678
|
+
let weightedDeficit = 0;
|
|
5678
5679
|
let total = 0;
|
|
5679
5680
|
for (const cat of Object.keys(categories)) {
|
|
5680
5681
|
const w = config.weights?.[cat] ?? 1;
|
|
@@ -5682,14 +5683,15 @@ function computeHealth(results, config) {
|
|
|
5682
5683
|
throw new RangeError(`invalid weight for '${cat}'; expected a finite number >= 0.`);
|
|
5683
5684
|
}
|
|
5684
5685
|
weights[cat] = w;
|
|
5685
|
-
|
|
5686
|
+
weightedDeficit += (100 - categories[cat].rawScore) * w;
|
|
5686
5687
|
total += w;
|
|
5687
5688
|
}
|
|
5688
5689
|
if (Object.keys(weights).length === 0) return { health: 100, categories, weights };
|
|
5689
5690
|
if (total === 0) {
|
|
5690
5691
|
throw new RangeError("Health weights sum to 0; at least one present category must have a positive weight.");
|
|
5691
5692
|
}
|
|
5692
|
-
const
|
|
5693
|
+
const averageDeficit = weightedDeficit / total;
|
|
5694
|
+
const health = averageDeficit === 0 ? 100 : Math.min(99, Math.floor(100 - averageDeficit));
|
|
5693
5695
|
return { health, categories, weights };
|
|
5694
5696
|
}
|
|
5695
5697
|
|
|
@@ -5763,7 +5765,7 @@ function byRouteTree(p, results, config, verbose) {
|
|
|
5763
5765
|
}
|
|
5764
5766
|
if (!verbose && scored.length > MAX_ROUTES_BY_ROUTE) {
|
|
5765
5767
|
const remaining = scored.slice(MAX_ROUTES_BY_ROUTE);
|
|
5766
|
-
const avgScore = Math.
|
|
5768
|
+
const avgScore = Math.floor(remaining.reduce((sum, r) => sum + r.score, 0) / remaining.length);
|
|
5767
5769
|
lines.push(
|
|
5768
5770
|
p.dim(
|
|
5769
5771
|
`\u2026and ${remaining.length} more route${remaining.length > 1 ? "s" : ""} (avg score ${avgScore}) \u2014 run with --verbose to see all`
|
|
@@ -5833,8 +5835,9 @@ function formatConsoleReport(results, config, options = {}) {
|
|
|
5833
5835
|
if (options.verbose) {
|
|
5834
5836
|
for (const r of passed) {
|
|
5835
5837
|
const marker = classify(r, config) === "dynamic" ? p.cyan(" \u21AF dynamic") : "";
|
|
5836
|
-
const
|
|
5837
|
-
|
|
5838
|
+
const where = r.location ?? r.route;
|
|
5839
|
+
const suffix = where ? ` ${where}` : "";
|
|
5840
|
+
lines.push(`${p.green("\u2713")} ${r.id} ${r.message}${marker}${suffix}`);
|
|
5838
5841
|
}
|
|
5839
5842
|
}
|
|
5840
5843
|
lines.push("");
|