svelte-vitals 0.48.0 → 0.49.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/bin.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runAnalyzeCliGunshi
4
- } from "./chunk-4LSRQXJ6.js";
4
+ } from "./chunk-4FOGEXGH.js";
5
5
  import "./chunk-DZVXCUHG.js";
6
6
  import {
7
7
  realIO
8
8
  } from "./chunk-RSSMIHIM.js";
9
- import "./chunk-LJPABOWU.js";
9
+ import "./chunk-5YVVJMZM.js";
10
10
  import "./chunk-WGFXFKBB.js";
11
11
  import {
12
12
  consoleIO
@@ -21,7 +21,7 @@ async function runCli(argv, io = consoleIO, env = process.env) {
21
21
  try {
22
22
  const locale = resolveLocale(env);
23
23
  if (argv[0] === "complete") {
24
- const { runCompleteCliGunshi } = await import("./complete-IOAMJRBY.js");
24
+ const { runCompleteCliGunshi } = await import("./complete-ZQZGCJ5W.js");
25
25
  return { code: await runCompleteCliGunshi(argv, io), exit: "natural" };
26
26
  }
27
27
  if (argv[0] === "docs") {
@@ -29,7 +29,7 @@ async function runCli(argv, io = consoleIO, env = process.env) {
29
29
  return { code: await runDocsCliGunshi(argv.slice(1), io, locale), exit: "natural" };
30
30
  }
31
31
  if (argv[0] === "explain") {
32
- const { runExplainCliGunshi } = await import("./explain-WOKUZJVY.js");
32
+ const { runExplainCliGunshi } = await import("./explain-PRCEATL4.js");
33
33
  return { code: await runExplainCliGunshi(argv.slice(1), io, locale), exit: "natural" };
34
34
  }
35
35
  if (argv[0] === "install") {
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-RSSMIHIM.js";
9
9
  import {
10
10
  run
11
- } from "./chunk-LJPABOWU.js";
11
+ } from "./chunk-5YVVJMZM.js";
12
12
  import {
13
13
  readCoreVersion,
14
14
  readPackageVersion
@@ -34,6 +34,8 @@ import {
34
34
  selectRules,
35
35
  applyRuleSeverities,
36
36
  applyOverrides,
37
+ applyInlineDirectives,
38
+ unknownDirectiveIds,
37
39
  settingSeverity,
38
40
  withFailedRulesOff,
39
41
  formatFailedRuleWarning,
@@ -75,6 +77,7 @@ import {
75
77
  SITEMAP_SOURCE_PATHS,
76
78
  SVELTE_CONFIG_FILES,
77
79
  VITE_CONFIG_FILES,
80
+ collectSuppressions,
78
81
  findMinifyDisabled,
79
82
  resolveKitAliases,
80
83
  resolveKitPathsBase
@@ -152,6 +155,18 @@ function detectHtmlLang(html) {
152
155
  const value = match[1] ?? match[2] ?? match[3] ?? "";
153
156
  return { presence: "own", value: value.trim().length > 0 ? "static" : "absent" };
154
157
  }
158
+ function detectAppHtmlBodyTags(html) {
159
+ let markup = html.replace(/<!--[\s\S]*?-->/g, "").replace(/<script[\s\S]*?<\/script\s*>/gi, "").replace(/<style[\s\S]*?<\/style\s*>/gi, "");
160
+ const innermost = /<template\b[^>]*>(?:(?!<template\b)[\s\S])*?<\/template\s*>/gi;
161
+ for (let prev = ""; prev !== markup; ) {
162
+ prev = markup;
163
+ markup = markup.replace(innermost, "\0");
164
+ }
165
+ markup = markup.replaceAll("\0", "<template></template>");
166
+ const body = /<body\b[^>]*>([\s\S]*?)(?:<\/body\s*>|$)/i.exec(markup)?.[1];
167
+ if (body === void 0) return [];
168
+ return [...new Set([...body.matchAll(/<([a-zA-Z][a-zA-Z0-9-]*)\b/g)].map((m) => m[1].toLowerCase()))];
169
+ }
155
170
  function detectAppHtmlIds(html) {
156
171
  const markup = html.replace(/<!--[\s\S]*?-->/g, "").replace(/<script[\s\S]*?<\/script\s*>/gi, "").replace(/<style[\s\S]*?<\/style\s*>/gi, "");
157
172
  const found = markup.matchAll(/(?<![\w-])id\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>{][^\s"'>]*))/gi);
@@ -172,7 +187,8 @@ async function detectAppHtmlFacts(rt, cwd) {
172
187
  // [\s\S]*? is ambiguous across iterations and backtracks exponentially on a comment run
173
188
  // with no doctype (measured: ~45 leading comments hang the process).
174
189
  appHtmlDoctype: /^\s*<!doctype\s+html/i.test(content.replace(/<!--[\s\S]*?-->/g, "")),
175
- appHtmlIds: detectAppHtmlIds(content)
190
+ appHtmlIds: detectAppHtmlIds(content),
191
+ appHtmlBodyTags: detectAppHtmlBodyTags(content)
176
192
  };
177
193
  }
178
194
  async function robotsRefsSitemap(rt, cwd) {
@@ -189,8 +205,9 @@ async function detectViteMinifyDisabled(rt, cwd) {
189
205
  const file = VITE_CONFIG_FILES[exists.indexOf(true)];
190
206
  if (!file) return void 0;
191
207
  try {
192
- const hit = findMinifyDisabled(await rt.readFile(rt.join(cwd, file)));
193
- return hit ? { file, line: hit.line } : void 0;
208
+ const source = await rt.readFile(rt.join(cwd, file));
209
+ const hit = findMinifyDisabled(source);
210
+ return hit ? { file, line: hit.line, suppressions: collectSuppressions(source) } : void 0;
194
211
  } catch {
195
212
  return void 0;
196
213
  }
@@ -243,7 +260,12 @@ import "@svelte-vitals/core";
243
260
  import {
244
261
  collectComponentFacts,
245
262
  collectKitModuleFacts,
246
- collectSourceFiles
263
+ collectSourceFiles,
264
+ compileOverrides,
265
+ ROBOTS_SOURCE_PATHS as ROBOTS_SOURCE_PATHS2,
266
+ SITEMAP_SOURCE_PATHS as SITEMAP_SOURCE_PATHS2,
267
+ SVELTE_CONFIG_FILES as SVELTE_CONFIG_FILES2,
268
+ VITE_CONFIG_FILES as VITE_CONFIG_FILES2
247
269
  } from "@svelte-vitals/core/internal";
248
270
 
249
271
  // src/providers/source/routes.ts
@@ -387,6 +409,7 @@ function findAdapter(info) {
387
409
 
388
410
  // src/providers/source/parse.ts
389
411
  import {
412
+ collectSuppressions as collectSuppressions2,
390
413
  stripTextDirective,
391
414
  parseSvelte,
392
415
  CHILD_NODE_KEYS,
@@ -605,6 +628,8 @@ function collectA11y(fragment, source) {
605
628
  let groups = 0;
606
629
  let slotInLandmark;
607
630
  let unknowableContent = false;
631
+ const elementTags = /* @__PURE__ */ new Set();
632
+ let elementsUnknowable = false;
608
633
  const emit = (ctx, node) => {
609
634
  const inLandmark = ctx.landmarks.at(-1);
610
635
  nodes.push({ ...node, repeatable: ctx.repeatable, path: ctx.path, ...inLandmark ? { inLandmark } : {} });
@@ -627,6 +652,7 @@ function collectA11y(fragment, source) {
627
652
  // head content never renders into the body
628
653
  case "HtmlTag":
629
654
  unknowableContent = true;
655
+ elementsUnknowable = true;
630
656
  return;
631
657
  case "IfBlock":
632
658
  walkIfChain(node, ctx, groups++, 0);
@@ -649,6 +675,8 @@ function collectA11y(fragment, source) {
649
675
  // attributes are real — dropping them would make no-missing-id-ref report phantom misses.
650
676
  case "RegularElement":
651
677
  case "SvelteElement":
678
+ if (node.type === "SvelteElement") elementsUnknowable = true;
679
+ else elementTags.add(node.name.toLowerCase());
652
680
  walkElement(node, ctx);
653
681
  return;
654
682
  case "Component":
@@ -728,7 +756,13 @@ function collectA11y(fragment, source) {
728
756
  });
729
757
  };
730
758
  walk(fragment, { path: [], repeatable: false, landmarks: [], elementDepth: 0, asideDemoting: 0 });
731
- return { nodes, ...slotInLandmark ? { slotInLandmark } : {}, unknowableContent };
759
+ return {
760
+ nodes,
761
+ ...slotInLandmark ? { slotInLandmark } : {},
762
+ unknowableContent,
763
+ elementTags: [...elementTags],
764
+ elementsUnknowable
765
+ };
732
766
  }
733
767
  function isChildrenRender(node) {
734
768
  const call = node.expression.type === "ChainExpression" ? node.expression.expression : node.expression;
@@ -750,7 +784,8 @@ function parseFile(source, filename) {
750
784
  imports: collectImports(ast),
751
785
  images,
752
786
  headings,
753
- a11y: collectA11y(ast.fragment, source)
787
+ a11y: collectA11y(ast.fragment, source),
788
+ suppressions: collectSuppressions2(source)
754
789
  };
755
790
  }
756
791
 
@@ -921,6 +956,8 @@ function offsetPath(path, base) {
921
956
  async function composeA11y(ctx, fileRel, parsed, depth, visited, chain) {
922
957
  const { rt, cwd, state } = ctx;
923
958
  if (parsed.a11y.unknowableContent) state.fullyResolved = false;
959
+ for (const t of parsed.a11y.elementTags) state.elementTags.add(t);
960
+ if (parsed.a11y.elementsUnknowable) state.elementsClosed = false;
924
961
  const base = state.nextGroup;
925
962
  state.nextGroup += groupSpan(parsed.a11y.nodes);
926
963
  const composed = [];
@@ -934,6 +971,7 @@ async function composeA11y(ctx, fileRel, parsed, depth, visited, chain) {
934
971
  const childRel = info ? resolveComponentPath(info.source, fileRel, ctx.aliases) : void 0;
935
972
  if (!childRel || depth <= 0 || visited.has(childRel) || !await rt.exists(rt.join(cwd, childRel))) {
936
973
  state.fullyResolved = false;
974
+ state.elementsClosed = false;
937
975
  continue;
938
976
  }
939
977
  const childParsed = await readAndParse(rt, cwd, childRel, ctx.cache);
@@ -963,7 +1001,7 @@ function representatives(nodes, chainOrder) {
963
1001
  [...folded].map(([key, list]) => [key, list.sort(order).map(({ file, line }) => ({ file, line }))])
964
1002
  );
965
1003
  }
966
- async function resolveRoute(rt, cwd, pageRel, config, layouts, cache, aliases, appHtmlIds) {
1004
+ async function resolveRoute(rt, cwd, pageRel, config, layouts, cache, aliases, appHtmlIds, appHtmlBodyTags) {
967
1005
  const files = chainFiles(pageRel, layouts);
968
1006
  const chainOrder = new Map(files.map((f, i) => [f.rel, i]));
969
1007
  const composed = /* @__PURE__ */ new Map();
@@ -973,7 +1011,14 @@ async function resolveRoute(rt, cwd, pageRel, config, layouts, cache, aliases, a
973
1011
  const images = [];
974
1012
  const headings = [];
975
1013
  const componentHeadings = [];
976
- const a11yCtx = { rt, cwd, config, cache, aliases, state: { nextGroup: 0, fullyResolved: true } };
1014
+ const a11yCtx = {
1015
+ rt,
1016
+ cwd,
1017
+ config,
1018
+ cache,
1019
+ aliases,
1020
+ state: { nextGroup: 0, fullyResolved: true, elementTags: new Set(appHtmlBodyTags ?? []), elementsClosed: true }
1021
+ };
977
1022
  const a11yNodes = [];
978
1023
  const nestedLandmarks = [];
979
1024
  let slotLandmark;
@@ -1033,14 +1078,17 @@ async function resolveRoute(rt, cwd, pageRel, config, layouts, cache, aliases, a
1033
1078
  // never a missing reference (HTML's "top of the document" fragment).
1034
1079
  idRefs: a11yNodes.filter((n) => n.kind === "idref" && !(n.attr === "href" && isTopFragment(n.key))).map((n) => ({ id: n.key, attr: n.attr ?? "", file: n.file, line: n.line })),
1035
1080
  idCandidates: [.../* @__PURE__ */ new Set([...literalIds.map((n) => n.key), ...appHtmlIds ?? []])],
1036
- fullyResolved: a11yCtx.state.fullyResolved
1081
+ fullyResolved: a11yCtx.state.fullyResolved,
1082
+ elementTags: [...a11yCtx.state.elementTags],
1083
+ elementsClosed: a11yCtx.state.elementsClosed,
1084
+ file: pageRel
1037
1085
  }
1038
1086
  };
1039
1087
  }
1040
- async function collectRoutes(rt, cwd, config = defaultConfig, cache = /* @__PURE__ */ new Map(), aliases, appHtmlIds) {
1088
+ async function collectRoutes(rt, cwd, config = defaultConfig, cache = /* @__PURE__ */ new Map(), aliases, appHtmlIds, appHtmlBodyTags) {
1041
1089
  const [pages, layouts] = await Promise.all([enumerateRoutePages(rt, cwd), collectLayouts(rt, cwd)]);
1042
1090
  const facts = await Promise.all(
1043
- pages.map((page) => resolveRoute(rt, cwd, page, config, layouts, cache, aliases, appHtmlIds))
1091
+ pages.map((page) => resolveRoute(rt, cwd, page, config, layouts, cache, aliases, appHtmlIds, appHtmlBodyTags))
1044
1092
  );
1045
1093
  return {
1046
1094
  heads: facts.map((f) => f.head),
@@ -1059,11 +1107,15 @@ function routeMatcher(glob) {
1059
1107
  }
1060
1108
 
1061
1109
  // src/collect-all.ts
1110
+ function globList(globs) {
1111
+ return globs === void 0 ? [] : Array.isArray(globs) ? globs : [globs];
1112
+ }
1062
1113
  async function collectAll(rt, cwd, config, opts = {}) {
1063
1114
  const matches = routeMatcher(opts.route);
1115
+ const parseCache = opts.parseCache ?? /* @__PURE__ */ new Map();
1064
1116
  const project = await collectProjectFacts(rt, cwd);
1065
1117
  const [collected, components, kitModules, sourceFiles] = await Promise.all([
1066
- collectRoutes(rt, cwd, config, opts.parseCache, project.kitAliases, project.appHtmlIds),
1118
+ collectRoutes(rt, cwd, config, parseCache, project.kitAliases, project.appHtmlIds, project.appHtmlBodyTags),
1067
1119
  // Component (Correctness) facts are file-scoped with no route attribution yet, so a
1068
1120
  // route-filtered run skips them rather than reporting unrelated components (#68 review);
1069
1121
  // kitModules is skipped for the same reason.
@@ -1079,7 +1131,45 @@ async function collectAll(rt, cwd, config, opts = {}) {
1079
1131
  const images = collected.images.filter((i) => matches(i.route));
1080
1132
  const headings = collected.headings.filter((h) => matches(h.route));
1081
1133
  const a11y = collected.a11y.filter((a) => matches(a.route));
1082
- return { heads, images, headings, a11y, project, components, kitModules, sourceFiles };
1134
+ const directives = /* @__PURE__ */ new Map();
1135
+ for (const [file, parsed] of parseCache) {
1136
+ const suppressions = await parsed.then(
1137
+ (parsedFile) => parsedFile.suppressions,
1138
+ () => void 0
1139
+ );
1140
+ if (suppressions) directives.set(file, suppressions);
1141
+ }
1142
+ for (const c of components) directives.set(c.file, c.suppressions ?? []);
1143
+ for (const m of kitModules) directives.set(m.file, m.suppressions ?? []);
1144
+ const viteConfig = project.viteMinifyDisabled;
1145
+ if (viteConfig?.file) directives.set(viteConfig.file, viteConfig.suppressions ?? []);
1146
+ const routes = collected.heads.map((h) => h.route);
1147
+ const emptySelections = [];
1148
+ if (opts.route !== void 0 && routes.length > 0 && !routes.some(matches))
1149
+ emptySelections.push(`--route '${opts.route}' matched none of the ${routes.length} route(s) found.`);
1150
+ if (opts.route === void 0 && routes.length > 0) {
1151
+ const attributable = [
1152
+ ...directives.keys(),
1153
+ ...ROBOTS_SOURCE_PATHS2,
1154
+ ...SITEMAP_SOURCE_PATHS2,
1155
+ ...VITE_CONFIG_FILES2,
1156
+ ...SVELTE_CONFIG_FILES2
1157
+ ];
1158
+ const entries = config.overrides ?? [];
1159
+ const compiled = compileOverrides(config);
1160
+ entries.forEach((entry, i) => {
1161
+ globList(entry.route).forEach((glob) => {
1162
+ if (!routes.some(routeMatcher(glob)))
1163
+ emptySelections.push(`overrides entry for route '${glob}' matched no route.`);
1164
+ });
1165
+ globList(entry.files).forEach((glob, j) => {
1166
+ const pattern = compiled[i]?.files[j];
1167
+ if (pattern && !attributable.some((f) => pattern.test(f)))
1168
+ emptySelections.push(`overrides entry for files '${glob}' matched no file.`);
1169
+ });
1170
+ });
1171
+ }
1172
+ return { heads, images, headings, a11y, project, components, kitModules, sourceFiles, directives, emptySelections };
1083
1173
  }
1084
1174
 
1085
1175
  // src/changed-files.ts
@@ -1580,17 +1670,21 @@ async function analyzeProject(opts = {}) {
1580
1670
  ...await checkVersionFloor(rt, cwd),
1581
1671
  ...overridesOffWarnings(opts.allowRules, config.overrides)
1582
1672
  ];
1583
- const { heads, images, headings, a11y, project, components, kitModules, sourceFiles } = await collectAll(
1584
- rt,
1585
- cwd,
1586
- config,
1587
- {
1588
- route: opts.route,
1589
- parseCache: opts.parseCache
1590
- }
1591
- );
1673
+ const { heads, images, headings, a11y, project, components, kitModules, sourceFiles, directives, emptySelections } = await collectAll(rt, cwd, config, {
1674
+ route: opts.route,
1675
+ parseCache: opts.parseCache
1676
+ });
1677
+ warnings.push(...emptySelections);
1678
+ if (opts.route === void 0) warnings.push(...unknownDirectiveIds(directives, allRules2));
1592
1679
  const selected = selectRules(allRules2, config);
1593
1680
  const rules = opts.categories ? selected.filter((r) => opts.categories.includes(r.category)) : selected;
1681
+ if (opts.route !== void 0 && opts.allowRules?.length) {
1682
+ const starved = rules.filter((r) => opts.allowRules.includes(r.id) && r.scope !== "route").map((r) => r.id);
1683
+ if (starved.length > 0)
1684
+ warnings.push(
1685
+ `--rules ${starved.map((id) => `'${id}'`).join(", ")} examined nothing: --route collects route facts only.`
1686
+ );
1687
+ }
1594
1688
  const {
1595
1689
  results: rawResults,
1596
1690
  examined,
@@ -1606,7 +1700,12 @@ async function analyzeProject(opts = {}) {
1606
1700
  kitModules,
1607
1701
  sourceFiles
1608
1702
  });
1609
- const results = applyOverrides(applyRuleSeverities(rawResults, config), config);
1703
+ const results = applyInlineDirectives(
1704
+ applyOverrides(applyRuleSeverities(rawResults, config), config),
1705
+ directives,
1706
+ rules,
1707
+ config
1708
+ );
1610
1709
  const failedRuleIds = failedRules.map((f) => f.id);
1611
1710
  const scoringConfig = withFailedRulesOff(config, failedRuleIds);
1612
1711
  return {
@@ -26,7 +26,11 @@ function describeOptions(id, options) {
26
26
  "string-map": "merged over the default entries \u2014 a new key is added, a built-in key has its value overridden"
27
27
  };
28
28
  const lines = options.map((o) => {
29
- const bounds = [o.min !== void 0 ? `>= ${o.min}` : "", o.max !== void 0 ? `<= ${o.max}` : ""].filter(Boolean).join(", ");
29
+ const bounds = [
30
+ o.min !== void 0 ? `>= ${o.min}` : "",
31
+ o.max !== void 0 ? `<= ${o.max}` : "",
32
+ o.pattern ? `each entry ${o.pattern}` : ""
33
+ ].filter(Boolean).join(", ");
30
34
  return `- ${o.name} (${o.kind}, default ${JSON.stringify(o.default)}${bounds ? `, ${bounds}` : ""}) \u2014 ${MERGE[o.kind]}`;
31
35
  });
32
36
  return `set in svelte-vitals.config.* as \`rules: { '${id}': { options: { \u2026 } } }\`, or per path in \`overrides\`:
@@ -8,14 +8,14 @@ import {
8
8
  import "./chunk-CTMKTFST.js";
9
9
  import {
10
10
  ROOT_ARGS
11
- } from "./chunk-4LSRQXJ6.js";
11
+ } from "./chunk-4FOGEXGH.js";
12
12
  import {
13
13
  CATEGORIES,
14
14
  FAIL_ON_VALUES,
15
15
  TREAT_DYNAMIC_AS_VALUES
16
16
  } from "./chunk-DZVXCUHG.js";
17
17
  import "./chunk-RSSMIHIM.js";
18
- import "./chunk-LJPABOWU.js";
18
+ import "./chunk-5YVVJMZM.js";
19
19
  import {
20
20
  REPORTER_NAMES
21
21
  } from "./chunk-WGFXFKBB.js";
@@ -27,7 +27,7 @@ import {
27
27
  } from "./chunk-72ZLERW3.js";
28
28
  import {
29
29
  EXPLAIN_ARGS
30
- } from "./chunk-ZAHTKEJ5.js";
30
+ } from "./chunk-K363W33X.js";
31
31
  import {
32
32
  consoleIO
33
33
  } from "./chunk-SLUMRYUD.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  EXPLAIN_ARGS,
3
3
  runExplainCliGunshi
4
- } from "./chunk-ZAHTKEJ5.js";
4
+ } from "./chunk-K363W33X.js";
5
5
  import "./chunk-SLUMRYUD.js";
6
6
  import "./chunk-NMVBVKLX.js";
7
7
  import "./chunk-AI24FJ5Q.js";
@@ -4,10 +4,10 @@ import {
4
4
  import "./chunk-CTMKTFST.js";
5
5
  import {
6
6
  ROOT_ARGS
7
- } from "./chunk-4LSRQXJ6.js";
7
+ } from "./chunk-4FOGEXGH.js";
8
8
  import "./chunk-DZVXCUHG.js";
9
9
  import "./chunk-RSSMIHIM.js";
10
- import "./chunk-LJPABOWU.js";
10
+ import "./chunk-5YVVJMZM.js";
11
11
  import "./chunk-WGFXFKBB.js";
12
12
  import "./chunk-MLIODPHZ.js";
13
13
  import {
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Config, Severity, RuleSetting, Category, Result } from '@svelte-vitals/core';
2
2
  export { defineConfig } from '@svelte-vitals/core';
3
3
  import { AST } from 'svelte/compiler';
4
- import { HeadTag, BranchStep, RuleOptionsSpec } from '@svelte-vitals/core/internal';
4
+ import { HeadTag, BranchStep, SuppressionDirective, RuleOptionsSpec } from '@svelte-vitals/core/internal';
5
5
 
6
6
  /** A resolved import binding: which module, and which export ('default' for default imports). */
7
7
  interface ImportInfo {
@@ -58,6 +58,10 @@ interface ParsedA11y {
58
58
  slotInLandmark?: string;
59
59
  /** file contains {@html} or a spread attribute — poisons the closed world for no-missing-id-ref */
60
60
  unknowableContent: boolean;
61
+ /** Distinct lowercased tag names of the body's `RegularElement`s (a11y/required-element's presence set). */
62
+ elementTags: string[];
63
+ /** file contains `{@html}` or a `<svelte:element>` — either can render an element the walk cannot see */
64
+ elementsUnknowable: boolean;
61
65
  }
62
66
  interface ParsedFile {
63
67
  headTags: ParsedTag[];
@@ -66,6 +70,10 @@ interface ParsedFile {
66
70
  images: ParsedImage[];
67
71
  headings: ParsedHeading[];
68
72
  a11y: ParsedA11y;
73
+ /** Inline `svelte-vitals-disable-next-line` directives in this file, for the central
74
+ * suppression pass. Collected here because a route-scoped finding can be located in any file
75
+ * the composition reads, including ones no component-fact collection visited (`--route`). */
76
+ suppressions: SuppressionDirective[];
69
77
  }
70
78
 
71
79
  /**
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  routeMatcher,
7
7
  run,
8
8
  spinnerEnabled
9
- } from "./chunk-LJPABOWU.js";
9
+ } from "./chunk-5YVVJMZM.js";
10
10
  import {
11
11
  CONFIG_FILENAMES,
12
12
  loadConfigFile
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-vitals",
3
- "version": "0.48.0",
3
+ "version": "0.49.0",
4
4
  "description": "A deterministic SvelteKit code-health scanner (SEO, performance, correctness, security, architecture, accessibility).",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -52,7 +52,7 @@
52
52
  "magicast": "^0.5.4",
53
53
  "svelte": "^5.56.9",
54
54
  "tinyglobby": "^0.2.17",
55
- "@svelte-vitals/core": "0.44.0"
55
+ "@svelte-vitals/core": "0.46.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@gunshi/docs": "0.37.1",