@svelte-vitals/core 0.46.0 → 0.47.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.
@@ -34,21 +34,21 @@ function isPenalized(detection, treatDynamicAs) {
34
34
  }
35
35
 
36
36
  // src/summary.ts
37
- function classify(result4, config) {
38
- if (isPenalized(result4.detection, config.treatDynamicAs)) return "fail";
39
- if (result4.detection.value === "dynamic") return "dynamic";
37
+ function classify(result5, config) {
38
+ if (isPenalized(result5.detection, config.treatDynamicAs)) return "fail";
39
+ if (result5.detection.value === "dynamic") return "dynamic";
40
40
  return "pass";
41
41
  }
42
- function effectiveSeverity(result4, config) {
43
- if (result4.detection.value === "dynamic" && config.treatDynamicAs === "warn") return "warning";
44
- return result4.severity;
42
+ function effectiveSeverity(result5, config) {
43
+ if (result5.detection.value === "dynamic" && config.treatDynamicAs === "warn") return "warning";
44
+ return result5.severity;
45
45
  }
46
46
  function summarize(results, config) {
47
47
  const summary = { critical: 0, warning: 0, info: 0, passed: 0, dynamic: 0 };
48
- for (const result4 of results) {
49
- const cls = classify(result4, config);
48
+ for (const result5 of results) {
49
+ const cls = classify(result5, config);
50
50
  if (cls === "fail") {
51
- summary[effectiveSeverity(result4, config)] += 1;
51
+ summary[effectiveSeverity(result5, config)] += 1;
52
52
  } else {
53
53
  summary.passed += 1;
54
54
  if (cls === "dynamic") summary.dynamic += 1;
@@ -620,8 +620,15 @@ function settingSeverity(setting) {
620
620
  function settingOptions(setting) {
621
621
  return setting !== void 0 && typeof setting !== "string" ? setting.options : void 0;
622
622
  }
623
+ function configuredSeverity(rule, config) {
624
+ const setting = config.rules[rule.id];
625
+ if (setting === void 0) return rule.defaultOff ? void 0 : rule.severity;
626
+ const severity = settingSeverity(setting);
627
+ if (severity === "off") return void 0;
628
+ return severity ?? rule.severity;
629
+ }
623
630
  function selectRules(rules, config) {
624
- return rules.filter((rule) => settingSeverity(config.rules[rule.id]) !== "off");
631
+ return rules.filter((rule) => configuredSeverity(rule, config) !== void 0);
625
632
  }
626
633
  function withFailedRulesOff(config, failedRuleIds) {
627
634
  if (failedRuleIds.length === 0) return config;
@@ -637,9 +644,9 @@ function formatFailedRuleWarning(f) {
637
644
  return `rule ${f.id} failed and was skipped: ${f.message.split("\n")[0]}`;
638
645
  }
639
646
  function applyRuleSeverities(results, config) {
640
- return results.map((result4) => {
641
- const severity = settingSeverity(config.rules[result4.id]);
642
- return severity !== void 0 && severity !== "off" ? { ...result4, severity } : result4;
647
+ return results.map((result5) => {
648
+ const severity = settingSeverity(config.rules[result5.id]);
649
+ return severity !== void 0 && severity !== "off" ? { ...result5, severity } : result5;
643
650
  });
644
651
  }
645
652
  function routeGlobToRegExp(pattern) {
@@ -666,15 +673,15 @@ function applyOverrides(results, config) {
666
673
  const compiled = compileOverrides(config);
667
674
  if (compiled.length === 0) return results;
668
675
  const out = [];
669
- for (const result4 of results) {
676
+ for (const result5 of results) {
670
677
  let severity;
671
678
  for (const o of compiled) {
672
- if (!overrideMatches(o, { route: result4.route, file: result4.location })) continue;
673
- const sev = settingSeverity(o.rules[result4.id]) ?? settingSeverity(o.rules[result4.category ?? "seo"]);
679
+ if (!overrideMatches(o, { route: result5.route, file: result5.location })) continue;
680
+ const sev = settingSeverity(o.rules[result5.id]) ?? settingSeverity(o.rules[result5.category ?? "seo"]);
674
681
  if (sev !== void 0) severity = sev;
675
682
  }
676
- if (severity === void 0) out.push(result4);
677
- else if (severity !== "off") out.push({ ...result4, severity });
683
+ if (severity === void 0) out.push(result5);
684
+ else if (severity !== "off") out.push({ ...result5, severity });
678
685
  }
679
686
  return out;
680
687
  }
@@ -1516,7 +1523,7 @@ function lengthRule(opts) {
1516
1523
  const o = resolveRuleOptions(opts.id, spec, ctx.config, { route: head.route, file: location }, compiled);
1517
1524
  const min = intOption(o, "min", opts.min);
1518
1525
  const max = intOption(o, "max", opts.max);
1519
- const recommendation13 = typeof opts.recommendation === "function" ? opts.recommendation(o) : opts.recommendation;
1526
+ const recommendation14 = typeof opts.recommendation === "function" ? opts.recommendation(o) : opts.recommendation;
1520
1527
  const len = visibleLength(tag.text);
1521
1528
  let problem;
1522
1529
  if (len < min) problem = `${opts.noun} is too short (${len} chars; aim for ${min}\u2013${max})`;
@@ -1530,7 +1537,7 @@ function lengthRule(opts) {
1530
1537
  route: head.route,
1531
1538
  location,
1532
1539
  message: problem,
1533
- recommendation: recommendation13,
1540
+ recommendation: recommendation14,
1534
1541
  docsUrl: docsUrl12
1535
1542
  } : {
1536
1543
  id: opts.id,
@@ -1544,7 +1551,7 @@ function lengthRule(opts) {
1544
1551
  // it to also apply `severity: 'off'`.
1545
1552
  location,
1546
1553
  message: opts.label,
1547
- recommendation: recommendation13,
1554
+ recommendation: recommendation14,
1548
1555
  docsUrl: docsUrl12
1549
1556
  }
1550
1557
  );
@@ -1900,7 +1907,7 @@ function fileRule(spec) {
1900
1907
  for (const f of spec.facts(ctx) ?? []) {
1901
1908
  const o = resolveRuleOptions(spec.id, spec.options, ctx.config, { route: f.file, file: f.file }, compiled);
1902
1909
  if (!spec.applies(f, o, ctx)) continue;
1903
- const recommendation13 = typeof spec.recommendation === "function" ? spec.recommendation(o) : spec.recommendation;
1910
+ const recommendation14 = typeof spec.recommendation === "function" ? spec.recommendation(o) : spec.recommendation;
1904
1911
  const bad = spec.bad(f, o, ctx).filter((b) => !(b.line > 0 && isSuppressed(f.suppressions, spec.id, b.line)));
1905
1912
  if (bad.length === 0) {
1906
1913
  out.push({
@@ -1911,7 +1918,7 @@ function fileRule(spec) {
1911
1918
  route: f.file,
1912
1919
  location: f.file,
1913
1920
  message: spec.label,
1914
- recommendation: recommendation13,
1921
+ recommendation: recommendation14,
1915
1922
  docsUrl: docsUrl12
1916
1923
  });
1917
1924
  continue;
@@ -1926,7 +1933,7 @@ function fileRule(spec) {
1926
1933
  location: f.file,
1927
1934
  ...b.line > 0 ? { line: b.line } : {},
1928
1935
  message: b.message,
1929
- recommendation: recommendation13,
1936
+ recommendation: recommendation14,
1930
1937
  docsUrl: docsUrl12,
1931
1938
  ...spec.fix ? { fix: { ...spec.fix } } : {}
1932
1939
  });
@@ -6155,9 +6162,9 @@ var routeEntryImportsCache = /* @__PURE__ */ new WeakMap();
6155
6162
  function cachedRouteEntryImports(c, ctx) {
6156
6163
  const cached = routeEntryImportsCache.get(c);
6157
6164
  if (cached !== void 0 && cached.aliases === ctx.project.kitAliases) return cached.result;
6158
- const result4 = routeEntryImports(c, ctx);
6159
- routeEntryImportsCache.set(c, { aliases: ctx.project.kitAliases, result: result4 });
6160
- return result4;
6165
+ const result5 = routeEntryImports(c, ctx);
6166
+ routeEntryImportsCache.set(c, { aliases: ctx.project.kitAliases, result: result5 });
6167
+ return result5;
6161
6168
  }
6162
6169
  var architectureRouteComponentImport = componentRule({
6163
6170
  id: ID8,
@@ -7123,23 +7130,23 @@ var a11yPermittedContents = componentRule({
7123
7130
  });
7124
7131
 
7125
7132
  // src/rules/a11y/route-rule.ts
7126
- function resultFactory(id, recommendation13) {
7133
+ function resultFactory(id, recommendation14, severity) {
7127
7134
  const docsUrl12 = docsUrlFor(id);
7128
7135
  return (route, detection, occ, message) => ({
7129
7136
  id,
7130
7137
  category: "a11y",
7131
- severity: "warning",
7138
+ severity,
7132
7139
  detection,
7133
7140
  route,
7134
7141
  location: occ.file,
7135
7142
  ...occ.line > 0 ? { line: occ.line } : {},
7136
7143
  message,
7137
- recommendation: recommendation13,
7144
+ recommendation: recommendation14,
7138
7145
  docsUrl: docsUrl12
7139
7146
  });
7140
7147
  }
7141
7148
  function surplusRule(spec) {
7142
- const result4 = resultFactory(spec.id, spec.recommendation);
7149
+ const result5 = resultFactory(spec.id, spec.recommendation, "warning");
7143
7150
  return {
7144
7151
  id: spec.id,
7145
7152
  title: spec.title,
@@ -7157,10 +7164,10 @@ function surplusRule(spec) {
7157
7164
  first ??= reps[0];
7158
7165
  for (let i = 1; i < reps.length; i++) {
7159
7166
  surplus = true;
7160
- out.push(result4(route.route, PENALIZED, reps[i], spec.message(key, i, reps.length)));
7167
+ out.push(result5(route.route, PENALIZED, reps[i], spec.message(key, i, reps.length, reps[0])));
7161
7168
  }
7162
7169
  }
7163
- if (first && !surplus) out.push(result4(route.route, PASS, { file: first.file, line: 0 }, spec.passMessage));
7170
+ if (first && !surplus) out.push(result5(route.route, PASS, { file: first.file, line: 0 }, spec.passMessage));
7164
7171
  }
7165
7172
  return out;
7166
7173
  }
@@ -7171,7 +7178,7 @@ function surplusRule(spec) {
7171
7178
  var ID10 = "a11y/required-element";
7172
7179
  var OPTIONS7 = { elements: ELEMENTS_OPTION };
7173
7180
  var recommendation10 = "Add the element to the route \u2014 usually in the layout the route composes \u2014 or narrow the declaration with an `overrides` entry for the routes it does not apply to.";
7174
- var result = resultFactory(ID10, recommendation10);
7181
+ var result = resultFactory(ID10, recommendation10, "warning");
7175
7182
  var a11yRequiredElement = {
7176
7183
  id: ID10,
7177
7184
  title: "Required element",
@@ -7268,7 +7275,7 @@ var a11yDuplicateLandmark = surplusRule({
7268
7275
 
7269
7276
  // src/rules/a11y/top-level-landmark.ts
7270
7277
  var recommendation11 = "A banner, main, complementary, or contentinfo landmark should not be nested inside another landmark.";
7271
- var result2 = resultFactory("a11y/top-level-landmark", recommendation11);
7278
+ var result2 = resultFactory("a11y/top-level-landmark", recommendation11, "warning");
7272
7279
  var KINDS2 = ["main", "banner", "complementary", "contentinfo"];
7273
7280
  var a11yTopLevelLandmark = {
7274
7281
  id: "a11y/top-level-landmark",
@@ -7301,13 +7308,13 @@ var a11yIdDuplication = surplusRule({
7301
7308
  // Entries ordered by each id's first representative (file, then line): content-derived and
7302
7309
  // stable — a Record's own-key enumeration would pull integer-like ids ("1") to the front.
7303
7310
  map: (route) => Object.entries(route.ids).sort(([, a], [, b]) => a[0].file.localeCompare(b[0].file) || a[0].line - b[0].line),
7304
- message: (id) => `Duplicate id "${id}"`,
7311
+ message: (id, _i, _n, first) => first.file === "src/app.html" ? `Duplicate id "${id}" \u2014 also defined by the src/app.html shell (line ${first.line})` : `Duplicate id "${id}"`,
7305
7312
  passMessage: "No duplicate ids"
7306
7313
  });
7307
7314
 
7308
7315
  // src/rules/a11y/no-missing-id-ref.ts
7309
7316
  var recommendation12 = "An id reference should point to an id that exists somewhere in the composed route.";
7310
- var result3 = resultFactory("a11y/no-missing-id-ref", recommendation12);
7317
+ var result3 = resultFactory("a11y/no-missing-id-ref", recommendation12, "warning");
7311
7318
  var a11yNoMissingIdRef = {
7312
7319
  id: "a11y/no-missing-id-ref",
7313
7320
  title: "No missing id ref",
@@ -7342,6 +7349,61 @@ var a11yNoMissingIdRef = {
7342
7349
  }
7343
7350
  };
7344
7351
 
7352
+ // src/rules/a11y/unverified-id-ref.ts
7353
+ var recommendation13 = "The reference could not be verified against the composed route. Confirm the id exists in the rendered page, or resolve the causes so a11y/no-missing-id-ref can verify it.";
7354
+ var result4 = resultFactory("a11y/unverified-id-ref", recommendation13, "info");
7355
+ var CAUSE_LABEL = {
7356
+ component: "unresolved component",
7357
+ spread: "spread",
7358
+ html: "{@html}",
7359
+ "dynamic-id": "dynamic id"
7360
+ };
7361
+ function causeList(causes) {
7362
+ const shown = causes.slice(0, 3).map((c) => {
7363
+ const name = c.kind === "component" && c.detail ? `${CAUSE_LABEL.component} <${c.detail}>` : CAUSE_LABEL[c.kind];
7364
+ return `${name} at ${c.file}:${c.line}`;
7365
+ });
7366
+ const rest = causes.length - shown.length;
7367
+ return shown.join(", ") + (rest > 0 ? `, +${rest} more` : "");
7368
+ }
7369
+ var passLabel = "All id references match literal ids (composition not fully resolved)";
7370
+ var a11yUnverifiedIdRef = {
7371
+ id: "a11y/unverified-id-ref",
7372
+ title: "Unverified id reference",
7373
+ category: "a11y",
7374
+ severity: "info",
7375
+ scope: "route",
7376
+ defaultOff: true,
7377
+ passLabel,
7378
+ rationale: "Opt-in: on routes a11y/no-missing-id-ref must skip (composition not fully resolved), an id reference that matches no literal id anywhere analyzed is reported as unverifiable \u2014 a real dangling reference and an id hidden inside an unresolved component look the same, so findings need manual confirmation.",
7379
+ async check(ctx) {
7380
+ const out = [];
7381
+ for (const route of ctx.a11y ?? []) {
7382
+ if (route.fullyResolved || route.idRefs.length === 0) continue;
7383
+ const candidates = new Set(route.idCandidates);
7384
+ const causes = causeList(route.unresolvedCauses ?? []);
7385
+ let hasUnverified = false;
7386
+ for (const ref of route.idRefs) {
7387
+ if (candidates.has(ref.id)) continue;
7388
+ hasUnverified = true;
7389
+ out.push(
7390
+ result4(
7391
+ route.route,
7392
+ PENALIZED,
7393
+ ref,
7394
+ `${ref.attr}="${ref.attr === "href" ? "#" : ""}${ref.id}" references an id not found in any analyzed source \u2014 the route is not fully resolved (${causes}); verify the id exists at runtime`
7395
+ )
7396
+ );
7397
+ }
7398
+ if (!hasUnverified) {
7399
+ const first = route.idRefs[0];
7400
+ out.push(result4(route.route, PASS, { file: first.file, line: 0 }, passLabel));
7401
+ }
7402
+ }
7403
+ return out;
7404
+ }
7405
+ };
7406
+
7345
7407
  // src/rules/index.ts
7346
7408
  var allRules = [
7347
7409
  seoTitlePresence,
@@ -7438,7 +7500,8 @@ var allRules = [
7438
7500
  a11yDuplicateLandmark,
7439
7501
  a11yTopLevelLandmark,
7440
7502
  a11yIdDuplication,
7441
- a11yNoMissingIdRef
7503
+ a11yNoMissingIdRef,
7504
+ a11yUnverifiedIdRef
7442
7505
  ];
7443
7506
  function optionInfos(spec) {
7444
7507
  return Object.entries(spec).map(([name, s]) => ({
@@ -7473,8 +7536,8 @@ function severityToSarifLevel(sev) {
7473
7536
  function severityToGithubLevel(sev) {
7474
7537
  return sev === "critical" ? "error" : sev === "warning" ? "warning" : "notice";
7475
7538
  }
7476
- function messageText(result4) {
7477
- return result4.recommendation ? `${result4.message} ${result4.recommendation}` : result4.message;
7539
+ function messageText(result5) {
7540
+ return result5.recommendation ? `${result5.message} ${result5.recommendation}` : result5.message;
7478
7541
  }
7479
7542
  var RULE_META = new Map(
7480
7543
  allRules.map((r) => [r.id, { title: r.title, severity: r.severity, docsUrl: docsUrlFor(r.id) }])
@@ -7513,9 +7576,7 @@ function pairKey(category, scope) {
7513
7576
  return `${category}::${scope}`;
7514
7577
  }
7515
7578
  function severityOf(rule, config) {
7516
- const setting = settingSeverity(config.rules[rule.id]);
7517
- if (setting === "off") return void 0;
7518
- return setting ?? rule.severity;
7579
+ return configuredSeverity(rule, config);
7519
7580
  }
7520
7581
  function buildInventory(config, rules = selectRules(allRules, config)) {
7521
7582
  const out = /* @__PURE__ */ new Map();
@@ -7632,17 +7693,17 @@ function computeHealth(results, config) {
7632
7693
  }
7633
7694
 
7634
7695
  // src/reporter/json.ts
7635
- function issueOf(result4) {
7696
+ function issueOf(result5) {
7636
7697
  return {
7637
- id: result4.id,
7638
- category: result4.category ?? "seo",
7639
- title: result4.message,
7640
- detection: result4.detection,
7641
- location: result4.location,
7642
- ...result4.line !== void 0 ? { line: result4.line } : {},
7643
- recommendation: result4.recommendation,
7644
- ...result4.docsUrl ? { docsUrl: result4.docsUrl } : {},
7645
- ...result4.fix ? { fix: result4.fix } : {}
7698
+ id: result5.id,
7699
+ category: result5.category ?? "seo",
7700
+ title: result5.message,
7701
+ detection: result5.detection,
7702
+ location: result5.location,
7703
+ ...result5.line !== void 0 ? { line: result5.line } : {},
7704
+ recommendation: result5.recommendation,
7705
+ ...result5.docsUrl ? { docsUrl: result5.docsUrl } : {},
7706
+ ...result5.fix ? { fix: result5.fix } : {}
7646
7707
  };
7647
7708
  }
7648
7709
  function ruleEvidence(results, config, ruleIds) {
@@ -7655,7 +7716,7 @@ function ruleEvidence(results, config, ruleIds) {
7655
7716
  }
7656
7717
  return out;
7657
7718
  }
7658
- function buildJsonReport(results, config, meta, ruleIds, examined) {
7719
+ function buildJsonReport(results, config, meta, ruleIds, examined, skipped) {
7659
7720
  const { health, categories: byCat, weights } = computeHealth(results, config);
7660
7721
  const summary = summarize(results, config);
7661
7722
  const rules = ruleEvidence(results, config, ruleIds);
@@ -7695,11 +7756,12 @@ function buildJsonReport(results, config, meta, ruleIds, examined) {
7695
7756
  routes,
7696
7757
  siteIssues,
7697
7758
  inventories,
7698
- ...examined && Object.keys(examined).length > 0 ? { examined } : {}
7759
+ ...examined && Object.keys(examined).length > 0 ? { examined } : {},
7760
+ ...skipped && Object.keys(skipped).length > 0 ? { skipped } : {}
7699
7761
  };
7700
7762
  }
7701
- function formatJsonReport(results, config, meta, ruleIds, examined) {
7702
- return JSON.stringify(buildJsonReport(results, config, meta, ruleIds, examined), null, 2);
7763
+ function formatJsonReport(results, config, meta, ruleIds, examined, skipped) {
7764
+ return JSON.stringify(buildJsonReport(results, config, meta, ruleIds, examined, skipped), null, 2);
7703
7765
  }
7704
7766
 
7705
7767
  // src/reporter/sanitize.ts
@@ -7951,6 +8013,7 @@ export {
7951
8013
  a11yTopLevelLandmark,
7952
8014
  a11yIdDuplication,
7953
8015
  a11yNoMissingIdRef,
8016
+ a11yUnverifiedIdRef,
7954
8017
  allRules,
7955
8018
  explainRule,
7956
8019
  SEVERITY_RANK,
@@ -393,12 +393,11 @@ interface Project {
393
393
  * silent then, like `viteMinifyDisabled`'s absent convention.
394
394
  */
395
395
  appHtmlDoctype?: boolean;
396
- /**
397
- * Literal `id` attributes in `src/app.html`, from the same read as `htmlLang`. The shell is part
398
- * of every rendered document, so its ids satisfy a route's id references (a11y/no-missing-id-ref);
399
- * absent when the file wasn't read.
400
- */
401
- appHtmlIds?: string[];
396
+ /** Literal ids in src/app.html with the line each first appears on — shell content present on every rendered route. Absent when the file wasn't read. */
397
+ appHtmlIds?: {
398
+ id: string;
399
+ line: number;
400
+ }[];
402
401
  /** Distinct lowercased tag names inside `app.html`'s `<body>` (a11y/required-element's presence set; static mode). */
403
402
  appHtmlBodyTags?: string[];
404
403
  }
@@ -700,6 +699,14 @@ interface A11yOccurrenceInfo {
700
699
  file: string;
701
700
  line: number;
702
701
  }
702
+ /** One reason a route's closed world failed to hold, with the first offending location. */
703
+ interface A11ySkipCause {
704
+ kind: 'component' | 'spread' | 'html' | 'dynamic-id';
705
+ file: string;
706
+ line: number;
707
+ /** for kind 'component': the unresolvable component's name as written */
708
+ detail?: string;
709
+ }
703
710
  /**
704
711
  * Route-scoped a11y facts, the mode-independent boundary for the landmark/id rules
705
712
  * (mirrors headings.ts). Source mode composes the layout chain plus its resolved
@@ -729,6 +736,8 @@ interface ResolvedA11y {
729
736
  idCandidates: string[];
730
737
  /** closed world holds: every component resolved, no depth truncation, no {@html}/spread, no dynamic id */
731
738
  fullyResolved: boolean;
739
+ /** Why `fullyResolved` is false — deduped by (kind, file, detail), first occurrence's line kept. Present exactly when `fullyResolved` is false. */
740
+ unresolvedCauses?: A11ySkipCause[];
732
741
  /**
733
742
  * Distinct tag names in the route's body subtree — layout chain, page, every resolved component,
734
743
  * and `app.html`'s `<body>` (static), or the prerendered `<body>` (rendered); optimistic across
@@ -876,7 +885,7 @@ interface KitModuleFacts {
876
885
  declare function settingSeverity(setting: RuleSetting | undefined): Severity | 'off' | undefined;
877
886
  /** The options a setting carries, or undefined for the string forms. */
878
887
  declare function settingOptions(setting: RuleSetting | undefined): RuleOptions | undefined;
879
- /** Drop rules disabled via config (design §6). */
888
+ /** Drop rules disabled via config (design §6), including a `defaultOff` rule with no entry. */
880
889
  declare function selectRules(rules: Rule[], config: Config): Rule[];
881
890
  /**
882
891
  * `config` with `failedRuleIds` (from `runRules`' `failedRules`) forced `'off'`: a rule that threw
@@ -1121,6 +1130,8 @@ interface Rule {
1121
1130
  * only in `--verbose`'s passed listing.
1122
1131
  */
1123
1132
  passLabel?: string;
1133
+ /** Off unless config.rules names the rule explicitly — the opt-in class (design 2026-08-21). */
1134
+ defaultOff?: true;
1124
1135
  /**
1125
1136
  * The rule compares routes against each other (`seo/duplicate-title`), so it cannot be judged
1126
1137
  * from one route's rendered HTML — the dev dashboard's live layer leaves it to the static pass.
@@ -1242,14 +1253,31 @@ interface JsonReport {
1242
1253
  * nothing has an empty entry; a declaration that judged nothing has an entry of `0`.
1243
1254
  */
1244
1255
  examined?: Record<string, Record<string, number>>;
1256
+ /**
1257
+ * Routes a closed-world rule skipped, keyed by rule id. Like `examined`, this describes the
1258
+ * analysis rather than the report: `--diff`, `--baseline` and suppressions do not narrow it.
1259
+ * `refs` is the route's literal id-reference count — a skipped route with `refs: 0` would
1260
+ * produce nothing even if unlocked. Only source-mode analysis populates it; absent when no
1261
+ * analyzed route was skipped.
1262
+ */
1263
+ skipped?: Record<string, Array<{
1264
+ route: string;
1265
+ refs: number;
1266
+ causes: Array<{
1267
+ kind: string;
1268
+ file: string;
1269
+ line: number;
1270
+ detail?: string;
1271
+ }>;
1272
+ }>>;
1245
1273
  }
1246
1274
  /** Build the structured JSON report object (design §7). The shape the `json` reporter emits (issue #24). */
1247
1275
  declare function buildJsonReport(results: Result[], config: Config, meta: {
1248
1276
  version: string;
1249
- }, ruleIds?: readonly string[], examined?: Record<string, Record<string, number>>): JsonReport;
1277
+ }, ruleIds?: readonly string[], examined?: Record<string, Record<string, number>>, skipped?: JsonReport['skipped']): JsonReport;
1250
1278
  /** Render results as the documented JSON report string (design §7). */
1251
1279
  declare function formatJsonReport(results: Result[], config: Config, meta: {
1252
1280
  version: string;
1253
- }, ruleIds?: readonly string[], examined?: Record<string, Record<string, number>>): string;
1281
+ }, ruleIds?: readonly string[], examined?: Record<string, Record<string, number>>, skipped?: JsonReport['skipped']): string;
1254
1282
 
1255
- export { formatFailedRuleWarning as $, type A11yOccurrenceInfo as A, type BranchStep as B, type ComponentFacts as C, applyRuleSeverities as D, type EachBlockFact as E, type Fix as F, buildJsonReport as G, type HeadTag as H, type ImageInfo as I, type JsonReport as J, type KitAlias as K, LANDMARK_ROLES as L, classify as M, compileOverrides as N, type OrphanEffectFact as O, type Project as P, computeHealth as Q, type Result as R, type SuppressionDirective as S, computeScore as T, decodeFragmentId as U, type Value as V, defaultConfig as W, defaultProject as X, docsUrlFor as Y, effectiveSeverity as Z, foldOccurrences as _, type Rule as a, formatGithubReport as a0, formatJsonReport as a1, formatMarkdownReport as a2, hasFailureAtOrAbove as a3, intOption as a4, isMentionedAnywhere as a5, isPenalized as a6, isTopFragment as a7, listOption as a8, mapOption as a9, defineConfig as aA, overrideMatches as aa, resolveRuleOptions as ab, scoresByCategory as ac, selectRules as ad, settingOptions as ae, settingSeverity as af, shouldSkipRangeCheck as ag, skippedFileWarnings as ah, splitTokens as ai, stripTextDirective as aj, summarize as ak, validateRuleOptions as al, validateRuleSetting as am, withFailedRulesOff as an, withReadLimit as ao, CATEGORIES as ap, type Detection as aq, type Presence as ar, type RuleEvidence as as, type RuleOptions as at, type RuleOverride as au, type RuleSetting as av, type RuleSettingObject as aw, type ScoreModel as ax, type Summary as ay, type TreatDynamicAs as az, type Config as b, type Runtime as c, type KitModuleFacts as d, type RuleContext as e, type Category as f, type Severity as g, type RuleOptionSpec as h, type ResolvedHead as i, type Classification as j, type CompiledOverride as k, type EffectFact as l, type HeadProvider as m, type HeadingInfo as n, type HealthResult as o, IDREF_ATTRS as p, READ_CONCURRENCY as q, type ResolvedA11y as r, type ResolvedHeadings as s, type ResolvedImages as t, type RuleOptionsSpec as u, type Scope as v, type ScoreOptions as w, type ScoreResult as x, type SourceSpan as y, applyOverrides as z };
1283
+ export { foldOccurrences as $, type A11yOccurrenceInfo as A, type BranchStep as B, type ComponentFacts as C, applyOverrides as D, type EachBlockFact as E, type Fix as F, applyRuleSeverities as G, type HeadTag as H, type ImageInfo as I, type JsonReport as J, type KitAlias as K, LANDMARK_ROLES as L, buildJsonReport as M, classify as N, type OrphanEffectFact as O, type Project as P, compileOverrides as Q, type Result as R, type SuppressionDirective as S, computeHealth as T, computeScore as U, type Value as V, decodeFragmentId as W, defaultConfig as X, defaultProject as Y, docsUrlFor as Z, effectiveSeverity as _, type Rule as a, formatFailedRuleWarning as a0, formatGithubReport as a1, formatJsonReport as a2, formatMarkdownReport as a3, hasFailureAtOrAbove as a4, intOption as a5, isMentionedAnywhere as a6, isPenalized as a7, isTopFragment as a8, listOption as a9, type TreatDynamicAs as aA, defineConfig as aB, mapOption as aa, overrideMatches as ab, resolveRuleOptions as ac, scoresByCategory as ad, selectRules as ae, settingOptions as af, settingSeverity as ag, shouldSkipRangeCheck as ah, skippedFileWarnings as ai, splitTokens as aj, stripTextDirective as ak, summarize as al, validateRuleOptions as am, validateRuleSetting as an, withFailedRulesOff as ao, withReadLimit as ap, CATEGORIES as aq, type Detection as ar, type Presence as as, type RuleEvidence as at, type RuleOptions as au, type RuleOverride as av, type RuleSetting as aw, type RuleSettingObject as ax, type ScoreModel as ay, type Summary as az, type Config as b, type Runtime as c, type KitModuleFacts as d, type RuleContext as e, type Category as f, type Severity as g, type RuleOptionSpec as h, type ResolvedHead as i, type A11ySkipCause as j, type Classification as k, type CompiledOverride as l, type EffectFact as m, type HeadProvider as n, type HeadingInfo as o, type HealthResult as p, IDREF_ATTRS as q, READ_CONCURRENCY as r, type ResolvedA11y as s, type ResolvedHeadings as t, type ResolvedImages as u, type RuleOptionsSpec as v, type Scope as w, type ScoreOptions as x, type ScoreResult as y, type SourceSpan as z };
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { ap as CATEGORIES, f as Category, b as Config, aq as Detection, F as Fix, J as JsonReport, ar as Presence, R as Result, as as RuleEvidence, at as RuleOptions, au as RuleOverride, av as RuleSetting, aw as RuleSettingObject, ax as ScoreModel, g as Severity, ay as Summary, az as TreatDynamicAs, V as Value, aA as defineConfig, a0 as formatGithubReport, a2 as formatMarkdownReport, a3 as hasFailureAtOrAbove, ak as summarize } from './index-Cx3Mi_d4.js';
1
+ export { aq as CATEGORIES, f as Category, b as Config, ar as Detection, F as Fix, J as JsonReport, as as Presence, R as Result, at as RuleEvidence, au as RuleOptions, av as RuleOverride, aw as RuleSetting, ax as RuleSettingObject, ay as ScoreModel, g as Severity, az as Summary, aA as TreatDynamicAs, V as Value, aB as defineConfig, a1 as formatGithubReport, a3 as formatMarkdownReport, a4 as hasFailureAtOrAbove, al as summarize } from './index-Qrw_f9HP.js';
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  formatMarkdownReport,
6
6
  hasFailureAtOrAbove,
7
7
  summarize
8
- } from "./chunk-M7RA6QQW.js";
8
+ } from "./chunk-25TAKBFU.js";
9
9
  export {
10
10
  CATEGORIES,
11
11
  defineConfig,
@@ -1,5 +1,5 @@
1
- import { S as SuppressionDirective, C as ComponentFacts, R as Result, a as Rule, b as Config, c as Runtime, K as KitAlias, d as KitModuleFacts, V as Value, e as RuleContext, f as Category, g as Severity, F as Fix, h as RuleOptionSpec, H as HeadTag, i as ResolvedHead, I as ImageInfo, J as JsonReport } from './index-Cx3Mi_d4.js';
2
- export { A as A11yOccurrenceInfo, B as BranchStep, j as Classification, k as CompiledOverride, E as EachBlockFact, l as EffectFact, m as HeadProvider, n as HeadingInfo, o as HealthResult, p as IDREF_ATTRS, L as LANDMARK_ROLES, O as OrphanEffectFact, P as Project, q as READ_CONCURRENCY, r as ResolvedA11y, s as ResolvedHeadings, t as ResolvedImages, u as RuleOptionsSpec, v as Scope, w as ScoreOptions, x as ScoreResult, y as SourceSpan, z as applyOverrides, D as applyRuleSeverities, G as buildJsonReport, M as classify, N as compileOverrides, Q as computeHealth, T as computeScore, U as decodeFragmentId, W as defaultConfig, X as defaultProject, Y as docsUrlFor, Z as effectiveSeverity, _ as foldOccurrences, $ as formatFailedRuleWarning, a0 as formatGithubReport, a1 as formatJsonReport, a2 as formatMarkdownReport, a3 as hasFailureAtOrAbove, a4 as intOption, a5 as isMentionedAnywhere, a6 as isPenalized, a7 as isTopFragment, a8 as listOption, a9 as mapOption, aa as overrideMatches, ab as resolveRuleOptions, ac as scoresByCategory, ad as selectRules, ae as settingOptions, af as settingSeverity, ag as shouldSkipRangeCheck, ah as skippedFileWarnings, ai as splitTokens, aj as stripTextDirective, ak as summarize, al as validateRuleOptions, am as validateRuleSetting, an as withFailedRulesOff, ao as withReadLimit } from './index-Cx3Mi_d4.js';
1
+ import { S as SuppressionDirective, C as ComponentFacts, R as Result, a as Rule, b as Config, c as Runtime, K as KitAlias, d as KitModuleFacts, V as Value, e as RuleContext, f as Category, g as Severity, F as Fix, h as RuleOptionSpec, H as HeadTag, i as ResolvedHead, I as ImageInfo, J as JsonReport } from './index-Qrw_f9HP.js';
2
+ export { A as A11yOccurrenceInfo, j as A11ySkipCause, B as BranchStep, k as Classification, l as CompiledOverride, E as EachBlockFact, m as EffectFact, n as HeadProvider, o as HeadingInfo, p as HealthResult, q as IDREF_ATTRS, L as LANDMARK_ROLES, O as OrphanEffectFact, P as Project, r as READ_CONCURRENCY, s as ResolvedA11y, t as ResolvedHeadings, u as ResolvedImages, v as RuleOptionsSpec, w as Scope, x as ScoreOptions, y as ScoreResult, z as SourceSpan, D as applyOverrides, G as applyRuleSeverities, M as buildJsonReport, N as classify, Q as compileOverrides, T as computeHealth, U as computeScore, W as decodeFragmentId, X as defaultConfig, Y as defaultProject, Z as docsUrlFor, _ as effectiveSeverity, $ as foldOccurrences, a0 as formatFailedRuleWarning, a1 as formatGithubReport, a2 as formatJsonReport, a3 as formatMarkdownReport, a4 as hasFailureAtOrAbove, a5 as intOption, a6 as isMentionedAnywhere, a7 as isPenalized, a8 as isTopFragment, a9 as listOption, aa as mapOption, ab as overrideMatches, ac as resolveRuleOptions, ad as scoresByCategory, ae as selectRules, af as settingOptions, ag as settingSeverity, ah as shouldSkipRangeCheck, ai as skippedFileWarnings, aj as splitTokens, ak as stripTextDirective, al as summarize, am as validateRuleOptions, an as validateRuleSetting, ao as withFailedRulesOff, ap as withReadLimit } from './index-Qrw_f9HP.js';
3
3
  import { AST } from 'svelte/compiler';
4
4
 
5
5
  /**
@@ -722,6 +722,8 @@ declare const a11yIdDuplication: Rule;
722
722
  */
723
723
  declare const a11yNoMissingIdRef: Rule;
724
724
 
725
+ declare const a11yUnverifiedIdRef: Rule;
726
+
725
727
  declare const allRules: Rule[];
726
728
 
727
729
  /** One configurable option of a rule, flattened for `svelte-vitals explain`'s output. */
@@ -931,4 +933,4 @@ declare function formatHtmlReport(results: Result[], config: Config, meta: {
931
933
  coreVersion?: string;
932
934
  }): string;
933
935
 
934
- export { APP_SCRIPT, APP_STYLE, type AppSnapshot, BAND_COLOR, CHILD_NODE_KEYS, ComponentFacts, type ConsoleReportOptions, type DirectiveIndex, type FailedRule, HeadTag, ImageInfo, KitAlias, KitModuleFacts, type Palette, ROBOTS_SOURCE_PATHS, type RawKitAliases, ResolvedHead, type RouteBadge, Rule, RuleContext, type RuleInfo, type RuleOptionInfo, RuleOptionSpec, Runtime, SITEMAP_SOURCE_PATHS, SVELTE_CONFIG_FILES, SuppressionDirective, VITE_CONFIG_FILES, type ViteKitConfigResult, a11yAccessibleName, a11yDeprecatedAria, a11yDeprecatedAttr, a11yDeprecatedElement, a11yDisallowedAriaProps, a11yDisallowedElement, a11yDoctype, a11yDuplicateLandmark, a11yIdDuplication, a11yInteractiveNesting, a11yInvalidAriaValue, a11yInvalidRole, a11yLabelHasControl, a11yNoMissingIdRef, a11yPermittedContents, a11yPlaceholderLabelOption, a11yRequireDatetime, a11yRequiredAriaProps, a11yRequiredElement, a11yTopLevelLandmark, a11yUnknownAriaAttribute, a11yUseList, allRules, applyInlineDirectives, architectureComponentSize, architectureDirectoryNaming, architectureDocLinkTarget, architecturePrivateScopeImport, architecturePropCount, architectureReservedDirectoryNames, architectureReservedNamePlacement, architectureRouteComponentImport, architectureUnitEntryFile, attrText, attrTextOf, attrValue, attrValueOf, buildHtmlDocument, collectComponentFacts, collectKitModuleFacts, collectSourceFiles, collectSuppressions, correctnessBasePathNavigation, correctnessCheckableBindValue, correctnessEachIndexKey, correctnessEachKey, correctnessEffectAsDerived, correctnessEffectAsOnMount, correctnessInstanceBrowserGlobal, correctnessNonreactiveBuiltinState, correctnessOrphanEffect, correctnessOrphanLifecycle, correctnessPropMutation, correctnessServerBrowserGlobal, correctnessStalePropDerivation, correctnessUnmutatedState, emptyComponentFacts, emptyKitModuleFacts, escapeHtml, explainRule, findAttr, findKitAliasesInSvelteConfig, findKitPathsBaseInSvelteConfig, findKitPathsBaseInViteConfig, findMinifyDisabled, formatAgentReport, formatConsoleReport, formatHtmlReport, formatSarifReport, headTagRule, imageRule, lineOf, linkRule, noColorPalette, parseComponentFacts, parseKitModuleFacts, parseSvelte, performanceFontPreloadCrossorigin, performanceHeavyImport, performanceImageDimensions, performanceImageLoadingHint, performanceLcpImage, performanceLoadWaterfall, performanceMinifyDisabled, performanceNamespaceImport, performancePreconnect, performancePreloadMissingAs, performanceRenderBlockingScript, performanceResponsiveImage, performanceSequentialAwaits, performanceStateRaw, renderAppShell, resolveKitAliases, resolveKitPathsBase, resolveRepoLocalPath, resolveRunesModuleSpecifier, runRules, safeHref, scoreBand, scoreColor, securityHandlerStateWrite, securityJavascriptUrl, securityRawHtml, securityServerModuleState, securitySharedStateImport, seoCanonicalUrl, seoCharset, seoDescriptionLength, seoDescriptionPresence, seoDuplicateDescription, seoDuplicateTitle, seoHeadingLevelSkip, seoHreflang, seoHtmlLang, seoImageAlt, seoIndexability, seoJsonLd, seoJsonLdDateFormat, seoJsonLdDeprecatedType, seoJsonLdPlaceholder, seoJsonLdRelativeUrl, seoJsonLdRequiredProps, seoJsonLdValidity, seoOgDescription, seoOgImage, seoOgTitle, seoOgUrl, seoRobotsTxt, seoSingleH1, seoSitemapInRobots, seoSitemapXml, seoSsrDisabled, seoTitleLength, seoTitlePresence, seoTwitterCard, seoViewport, terminalSafe, textFromNodes, unknownDirectiveIds, valueFromNodes };
936
+ export { APP_SCRIPT, APP_STYLE, type AppSnapshot, BAND_COLOR, CHILD_NODE_KEYS, ComponentFacts, type ConsoleReportOptions, type DirectiveIndex, type FailedRule, HeadTag, ImageInfo, KitAlias, KitModuleFacts, type Palette, ROBOTS_SOURCE_PATHS, type RawKitAliases, ResolvedHead, type RouteBadge, Rule, RuleContext, type RuleInfo, type RuleOptionInfo, RuleOptionSpec, Runtime, SITEMAP_SOURCE_PATHS, SVELTE_CONFIG_FILES, SuppressionDirective, VITE_CONFIG_FILES, type ViteKitConfigResult, a11yAccessibleName, a11yDeprecatedAria, a11yDeprecatedAttr, a11yDeprecatedElement, a11yDisallowedAriaProps, a11yDisallowedElement, a11yDoctype, a11yDuplicateLandmark, a11yIdDuplication, a11yInteractiveNesting, a11yInvalidAriaValue, a11yInvalidRole, a11yLabelHasControl, a11yNoMissingIdRef, a11yPermittedContents, a11yPlaceholderLabelOption, a11yRequireDatetime, a11yRequiredAriaProps, a11yRequiredElement, a11yTopLevelLandmark, a11yUnknownAriaAttribute, a11yUnverifiedIdRef, a11yUseList, allRules, applyInlineDirectives, architectureComponentSize, architectureDirectoryNaming, architectureDocLinkTarget, architecturePrivateScopeImport, architecturePropCount, architectureReservedDirectoryNames, architectureReservedNamePlacement, architectureRouteComponentImport, architectureUnitEntryFile, attrText, attrTextOf, attrValue, attrValueOf, buildHtmlDocument, collectComponentFacts, collectKitModuleFacts, collectSourceFiles, collectSuppressions, correctnessBasePathNavigation, correctnessCheckableBindValue, correctnessEachIndexKey, correctnessEachKey, correctnessEffectAsDerived, correctnessEffectAsOnMount, correctnessInstanceBrowserGlobal, correctnessNonreactiveBuiltinState, correctnessOrphanEffect, correctnessOrphanLifecycle, correctnessPropMutation, correctnessServerBrowserGlobal, correctnessStalePropDerivation, correctnessUnmutatedState, emptyComponentFacts, emptyKitModuleFacts, escapeHtml, explainRule, findAttr, findKitAliasesInSvelteConfig, findKitPathsBaseInSvelteConfig, findKitPathsBaseInViteConfig, findMinifyDisabled, formatAgentReport, formatConsoleReport, formatHtmlReport, formatSarifReport, headTagRule, imageRule, lineOf, linkRule, noColorPalette, parseComponentFacts, parseKitModuleFacts, parseSvelte, performanceFontPreloadCrossorigin, performanceHeavyImport, performanceImageDimensions, performanceImageLoadingHint, performanceLcpImage, performanceLoadWaterfall, performanceMinifyDisabled, performanceNamespaceImport, performancePreconnect, performancePreloadMissingAs, performanceRenderBlockingScript, performanceResponsiveImage, performanceSequentialAwaits, performanceStateRaw, renderAppShell, resolveKitAliases, resolveKitPathsBase, resolveRepoLocalPath, resolveRunesModuleSpecifier, runRules, safeHref, scoreBand, scoreColor, securityHandlerStateWrite, securityJavascriptUrl, securityRawHtml, securityServerModuleState, securitySharedStateImport, seoCanonicalUrl, seoCharset, seoDescriptionLength, seoDescriptionPresence, seoDuplicateDescription, seoDuplicateTitle, seoHeadingLevelSkip, seoHreflang, seoHtmlLang, seoImageAlt, seoIndexability, seoJsonLd, seoJsonLdDateFormat, seoJsonLdDeprecatedType, seoJsonLdPlaceholder, seoJsonLdRelativeUrl, seoJsonLdRequiredProps, seoJsonLdValidity, seoOgDescription, seoOgImage, seoOgTitle, seoOgUrl, seoRobotsTxt, seoSingleH1, seoSitemapInRobots, seoSitemapXml, seoSsrDisabled, seoTitleLength, seoTitlePresence, seoTwitterCard, seoViewport, terminalSafe, textFromNodes, unknownDirectiveIds, valueFromNodes };
package/dist/internal.js CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  a11yRequiredElement,
25
25
  a11yTopLevelLandmark,
26
26
  a11yUnknownAriaAttribute,
27
+ a11yUnverifiedIdRef,
27
28
  a11yUseList,
28
29
  allRules,
29
30
  applyOverrides,
@@ -164,7 +165,7 @@ import {
164
165
  validateRuleSetting,
165
166
  valueFromNodes,
166
167
  withFailedRulesOff
167
- } from "./chunk-M7RA6QQW.js";
168
+ } from "./chunk-25TAKBFU.js";
168
169
 
169
170
  // src/inline-directives.ts
170
171
  function directiveFor(index, r) {
@@ -1640,6 +1641,7 @@ export {
1640
1641
  a11yRequiredElement,
1641
1642
  a11yTopLevelLandmark,
1642
1643
  a11yUnknownAriaAttribute,
1644
+ a11yUnverifiedIdRef,
1643
1645
  a11yUseList,
1644
1646
  allRules,
1645
1647
  applyInlineDirectives,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svelte-vitals/core",
3
- "version": "0.46.0",
3
+ "version": "0.47.0",
4
4
  "description": "Shared, runtime-agnostic core for svelte-vitals (types, rule engine, scorer, reporter).",
5
5
  "type": "module",
6
6
  "license": "MIT",