svelte-vitals 0.54.0 → 0.54.2

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.
@@ -1,6 +1,7 @@
1
- import { c as findUnknownRuleIds, h as readPackageVersion, i as run, l as knownRuleIds, m as readCoreVersion, p as isReporterName } from "./src-YdyHF4je.js";
1
+ import { c as findUnknownRuleIds, h as readPackageVersion, i as run, l as knownRuleIds, m as readCoreVersion, p as isReporterName } from "./src-BV_3ylhu.js";
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { dirname, resolve } from "node:path";
4
+ import { terminalSafe } from "@svelte-vitals/core/internal";
4
5
  import { spawnSync } from "node:child_process";
5
6
  import { parseArgs } from "node:util";
6
7
  import * as p from "@clack/prompts";
@@ -25,8 +26,8 @@ function realIO() {
25
26
  },
26
27
  cwd: process.cwd(),
27
28
  isTTY: Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY),
28
- log: (line) => console.log(line),
29
- errorLog: (line) => console.error(line),
29
+ log: (line) => console.log(terminalSafe(line)),
30
+ errorLog: (line) => console.error(terminalSafe(line)),
30
31
  runCommand: (command, args, cwd) => {
31
32
  const result = spawnSync(command, args, {
32
33
  cwd,
@@ -35,11 +36,11 @@ function realIO() {
35
36
  timeout: 12e4
36
37
  });
37
38
  if (result.error) {
38
- console.error(`svelte-vitals: ${command} failed to start: ${result.error.message}`);
39
+ console.error(terminalSafe(`svelte-vitals: ${command} failed to start: ${result.error.message}`));
39
40
  return 1;
40
41
  }
41
42
  if (result.signal) {
42
- console.error(`svelte-vitals: ${command} was terminated (${result.signal}) — it may have timed out.`);
43
+ console.error(terminalSafe(`svelte-vitals: ${command} was terminated (${result.signal}) — it may have timed out.`));
43
44
  return 1;
44
45
  }
45
46
  return result.status ?? 1;
@@ -85,7 +86,7 @@ function clackPrompts() {
85
86
  //#region src/cli-io.ts
86
87
  const consoleIO = {
87
88
  log: (line) => console.log(line),
88
- errorLog: (line) => console.error(line)
89
+ errorLog: (line) => console.error(terminalSafe(line))
89
90
  };
90
91
  //#endregion
91
92
  //#region src/resolve-args.ts
@@ -377,15 +378,16 @@ function guardArgs(argv, valueFlags, booleanFlags) {
377
378
  }
378
379
  }
379
380
  }
381
+ const isTokenOf = (flag, token) => token === `--${flag}` || token.startsWith(`--${flag}=`);
380
382
  const offFlags = new Set(booleanFlags.filter((flag) => {
381
383
  let lastToken;
382
- for (const t of argv) if (t === `--${flag}` || t === `--${flag}=false`) lastToken = t;
384
+ for (const t of argv) if (isTokenOf(flag, t)) lastToken = t;
383
385
  return lastToken === `--${flag}=false`;
384
386
  }));
385
387
  return {
386
388
  errors,
387
389
  argv: argv.filter((token) => {
388
- for (const flag of booleanFlags) if (token === `--${flag}=false` || offFlags.has(flag) && token === `--${flag}`) return false;
390
+ for (const flag of booleanFlags) if (offFlags.has(flag) ? isTokenOf(flag, token) : token === `--${flag}=false`) return false;
389
391
  return true;
390
392
  })
391
393
  };
package/dist/bin.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { g as realIO, i as resolveLocale, m as consoleIO, n as runAnalyzeCliGunshi } from "./analyze-BMmHtlXw.js";
2
+ import { g as realIO, i as resolveLocale, m as consoleIO, n as runAnalyzeCliGunshi } from "./analyze-Dl-VIKsc.js";
3
+ import { terminalSafe } from "@svelte-vitals/core/internal";
3
4
  //#region src/cli.ts
4
5
  /**
5
6
  * CLI dispatch: routes `docs`/`explain`/`install`/`ci` subcommands, otherwise hands off to the
@@ -16,35 +17,35 @@ async function runCli(argv, io = consoleIO, env = process.env) {
16
17
  try {
17
18
  const locale = resolveLocale(env);
18
19
  if (argv[0] === "complete") {
19
- const { runCompleteCliGunshi } = await import("./complete-Ch90r0sl.js");
20
+ const { runCompleteCliGunshi } = await import("./complete-Dr0cRw1j.js");
20
21
  return {
21
22
  code: await runCompleteCliGunshi(argv, io),
22
23
  exit: "natural"
23
24
  };
24
25
  }
25
26
  if (argv[0] === "docs") {
26
- const { runDocsCliGunshi } = await import("./docs-d-yH1BK6.js");
27
+ const { runDocsCliGunshi } = await import("./docs-DZD2UDg-.js");
27
28
  return {
28
29
  code: await runDocsCliGunshi(argv.slice(1), io, locale),
29
30
  exit: "natural"
30
31
  };
31
32
  }
32
33
  if (argv[0] === "explain") {
33
- const { runExplainCliGunshi } = await import("./explain-CibqNEff.js");
34
+ const { runExplainCliGunshi } = await import("./explain-C4eXHI7I.js");
34
35
  return {
35
36
  code: await runExplainCliGunshi(argv.slice(1), io, locale),
36
37
  exit: "natural"
37
38
  };
38
39
  }
39
40
  if (argv[0] === "install") {
40
- const { runInstallCliGunshi } = await import("./install-BrrV4ATR.js").then((n) => n.n);
41
+ const { runInstallCliGunshi } = await import("./install-D-OIDsrS.js").then((n) => n.n);
41
42
  return {
42
43
  code: await runInstallCliGunshi(argv.slice(1), io, locale),
43
44
  exit: "immediate"
44
45
  };
45
46
  }
46
47
  if (argv[0] === "ci") {
47
- const { runCiCliGunshi } = await import("./ci-BDOPcOtr.js");
48
+ const { runCiCliGunshi } = await import("./ci-DmdNtgzC.js");
48
49
  return {
49
50
  code: await runCiCliGunshi(argv.slice(1), {
50
51
  ...realIO(),
@@ -72,7 +73,7 @@ async function main() {
72
73
  else process.exitCode = code;
73
74
  }
74
75
  main().catch((err) => {
75
- console.error(`svelte-vitals: ${err instanceof Error ? err.message : String(err)}`);
76
+ console.error(terminalSafe(`svelte-vitals: ${err instanceof Error ? err.message : String(err)}`));
76
77
  process.exit(2);
77
78
  });
78
79
  //#endregion
@@ -1,4 +1,4 @@
1
- import { a as guardArgs, c as stripUnknownFlags, g as realIO, l as suggestClosest, o as splitAtTerminator, r as localizedOptionsSection, s as stripAutoVersionLine } from "./analyze-BMmHtlXw.js";
1
+ import { a as guardArgs, c as stripUnknownFlags, g as realIO, l as suggestClosest, o as splitAtTerminator, r as localizedOptionsSection, s as stripAutoVersionLine } from "./analyze-Dl-VIKsc.js";
2
2
  import { a as planWorkflowWrite, i as buildWorkflowYaml, n as ACTION_VERSION, r as WORKFLOW_PATH, t as ACTION_SHA } from "./action-pin.generated-C2XJJ3NW.js";
3
3
  import { join } from "node:path";
4
4
  import { cli } from "gunshi/bone";
@@ -1,9 +1,9 @@
1
- import { f as REPORTER_NAMES } from "./src-YdyHF4je.js";
2
- import { d as FAIL_ON_VALUES, f as TREAT_DYNAMIC_AS_VALUES, m as consoleIO, t as ROOT_ARGS, u as CATEGORIES } from "./analyze-BMmHtlXw.js";
3
- import { t as INSTALL_ARGS } from "./install-BrrV4ATR.js";
4
- import { CI_ARGS, CI_UPGRADE_ARGS } from "./ci-BDOPcOtr.js";
5
- import { DOCS_LIST_ARGS, DOCS_ROOT_ARGS, DOCS_SHOW_ARGS } from "./docs-d-yH1BK6.js";
6
- import { EXPLAIN_ARGS } from "./explain-CibqNEff.js";
1
+ import { f as REPORTER_NAMES } from "./src-BV_3ylhu.js";
2
+ import { d as FAIL_ON_VALUES, f as TREAT_DYNAMIC_AS_VALUES, m as consoleIO, t as ROOT_ARGS, u as CATEGORIES } from "./analyze-Dl-VIKsc.js";
3
+ import { t as INSTALL_ARGS } from "./install-D-OIDsrS.js";
4
+ import { CI_ARGS, CI_UPGRADE_ARGS } from "./ci-DmdNtgzC.js";
5
+ import { DOCS_LIST_ARGS, DOCS_ROOT_ARGS, DOCS_SHOW_ARGS } from "./docs-DZD2UDg-.js";
6
+ import { EXPLAIN_ARGS } from "./explain-C4eXHI7I.js";
7
7
  import { cli } from "gunshi/bone";
8
8
  import { define } from "gunshi/definition";
9
9
  import { kebabnize } from "gunshi/utils";
@@ -1,5 +1,5 @@
1
- import { l as knownRuleIds } from "./src-YdyHF4je.js";
2
- import { a as guardArgs, c as stripUnknownFlags, l as suggestClosest, m as consoleIO, o as splitAtTerminator, r as localizedOptionsSection, s as stripAutoVersionLine } from "./analyze-BMmHtlXw.js";
1
+ import { l as knownRuleIds } from "./src-BV_3ylhu.js";
2
+ import { a as guardArgs, c as stripUnknownFlags, l as suggestClosest, m as consoleIO, o as splitAtTerminator, r as localizedOptionsSection, s as stripAutoVersionLine } from "./analyze-Dl-VIKsc.js";
3
3
  import { docsUrlFor } from "@svelte-vitals/core/internal";
4
4
  import { cli } from "gunshi/bone";
5
5
  import { define } from "gunshi/definition";
@@ -1,5 +1,5 @@
1
- import { l as knownRuleIds } from "./src-YdyHF4je.js";
2
- import { a as guardArgs, c as stripUnknownFlags, l as suggestClosest, m as consoleIO, o as splitAtTerminator, r as localizedOptionsSection, s as stripAutoVersionLine } from "./analyze-BMmHtlXw.js";
1
+ import { l as knownRuleIds } from "./src-BV_3ylhu.js";
2
+ import { a as guardArgs, c as stripUnknownFlags, l as suggestClosest, m as consoleIO, o as splitAtTerminator, r as localizedOptionsSection, s as stripAutoVersionLine } from "./analyze-Dl-VIKsc.js";
3
3
  import { CATEGORIES } from "@svelte-vitals/core";
4
4
  import { allRules, explainRule } from "@svelte-vitals/core/internal";
5
5
  import { cli } from "gunshi/bone";
@@ -1,4 +1,4 @@
1
- import { t as ROOT_ARGS } from "./analyze-BMmHtlXw.js";
2
- import { t as INSTALL_ARGS } from "./install-BrrV4ATR.js";
1
+ import { t as ROOT_ARGS } from "./analyze-Dl-VIKsc.js";
2
+ import { t as INSTALL_ARGS } from "./install-D-OIDsrS.js";
3
3
  import { t as JA_ARG_DESCRIPTIONS } from "./ja-BDLP3KLG.js";
4
4
  export { INSTALL_ARGS, JA_ARG_DESCRIPTIONS, ROOT_ARGS };
package/dist/index.d.ts CHANGED
@@ -308,7 +308,7 @@ interface AnalyzeResult {
308
308
  examined: Record<string, Record<string, number>>;
309
309
  /** Routes a closed-world rule skipped, keyed by rule id — the analysis-side companion to `examined`; unfiltered by `--diff`/`--baseline`/suppressions. Absent when no analyzed route was skipped or the rule was not selected. */
310
310
  skipped?: JsonReport['skipped'];
311
- /** Ids of rules `runRules` caught throwing — already folded into `config` via `withFailedRulesOff`; exposed separately so a caller with its own base config (the vite dev dashboard) can apply the same correction without adopting this call's `config`. */
311
+ /** Ids of rules `runAnalysis` caught throwing — already folded into `config` via `withFailedRulesOff`; exposed separately so a caller with its own base config (the vite dev dashboard) can apply the same correction without adopting this call's `config`. */
312
312
  failedRuleIds: string[];
313
313
  /** Non-fatal issues surfaced during analysis: config-file problems (unknown top-level keys, invalid enum values), version-floor notices, `--rules`/overrides conflicts, closed-world skip notices (`a11y/no-missing-id-ref`), and skipped-file notices. Empty when none apply. */
314
314
  warnings: string[];
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as spinnerEnabled, b as ProjectError, c as findUnknownRuleIds, d as ruleOptionsSpec, i as run, l as knownRuleIds, n as applyScope, o as CONFIG_FILENAMES, r as defineConfig, s as loadConfigFile, t as analyzeProject, u as registryTag, y as routeMatcher } from "./src-YdyHF4je.js";
1
+ import { a as spinnerEnabled, b as ProjectError, c as findUnknownRuleIds, d as ruleOptionsSpec, i as run, l as knownRuleIds, n as applyScope, o as CONFIG_FILENAMES, r as defineConfig, s as loadConfigFile, t as analyzeProject, u as registryTag, y as routeMatcher } from "./src-BV_3ylhu.js";
2
2
  export { CONFIG_FILENAMES, ProjectError, analyzeProject, applyScope, defineConfig, findUnknownRuleIds, knownRuleIds, loadConfigFile, registryTag, routeMatcher, ruleOptionsSpec, run, spinnerEnabled };
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { _ as hasDep, g as discoverApps, h as readPackageVersion, o as CONFIG_FILENAMES, v as readPkg } from "./src-YdyHF4je.js";
3
- import { a as guardArgs, c as stripUnknownFlags, g as realIO, h as clackPrompts, m as consoleIO, o as splitAtTerminator, p as toList, r as localizedOptionsSection, s as stripAutoVersionLine } from "./analyze-BMmHtlXw.js";
2
+ import { _ as hasDep, g as discoverApps, h as readPackageVersion, o as CONFIG_FILENAMES, v as readPkg } from "./src-BV_3ylhu.js";
3
+ import { a as guardArgs, c as stripUnknownFlags, g as realIO, h as clackPrompts, m as consoleIO, o as splitAtTerminator, p as toList, r as localizedOptionsSection, s as stripAutoVersionLine } from "./analyze-Dl-VIKsc.js";
4
4
  import { a as planWorkflowWrite, i as buildWorkflowYaml, n as ACTION_VERSION, r as WORKFLOW_PATH, t as ACTION_SHA } from "./action-pin.generated-C2XJJ3NW.js";
5
5
  import { buildCursorRules, installHeader } from "./install/skill-content.js";
6
6
  import { join } from "node:path";
@@ -1,9 +1,8 @@
1
1
  import { existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
2
- import { dirname, join, resolve } from "node:path";
2
+ import { dirname, join, relative, resolve, sep } from "node:path";
3
3
  import { CATEGORIES, defineConfig, defineConfig as defineConfig$1 } from "@svelte-vitals/core";
4
- import { CHILD_NODE_KEYS, IDREF_ATTRS, LANDMARK_ROLES, ROBOTS_SOURCE_PATHS, SITEMAP_SOURCE_PATHS, SVELTE_CONFIG_FILES, VITE_CONFIG_FILES, allRules, applyInlineDirectives, applyOverrides, applyRuleSeverities, attrText, attrTextOf, attrValue, attrValueOf, collectComponentFacts, collectKitModuleFacts, collectSourceFiles, collectSuppressions, compileOverrides, computeHealth, decodeFragmentId, defaultConfig, docsUrlFor, findAttr, findMinifyDisabled, foldOccurrences, formatAgentReport, formatConsoleReport, formatFailedRuleWarning, formatGithubReport, formatHtmlReport, formatJsonReport, formatMarkdownReport, formatSarifReport, hasFailureAtOrAbove, isPenalized, isTopFragment, lineOf, noColorPalette, parseSvelte, resolveKitAliases, resolveKitPathsBase, resolveRepoLocalPath, resolveRuleOptions, runRules, scoreColor, selectRules, settingSeverity, shouldSkipRangeCheck, skippedFileWarnings, splitTokens, stripTextDirective, summarize, terminalSafe, textFromNodes, unknownDirectiveIds, validateRuleSetting, valueFromNodes, withFailedRulesOff, withReadLimit } from "@svelte-vitals/core/internal";
5
- import { access, readFile } from "node:fs/promises";
6
- import { glob } from "tinyglobby";
4
+ import { ANCESTRY_DEPENDENT_TAGS, ASIDE_DEMOTING_TAGS, CHILD_NODE_KEYS, IDREF_ATTRS, NAMING_ATTRS, ROBOTS_SOURCE_PATHS, SITEMAP_SOURCE_PATHS, SVELTE_CONFIG_FILES, VITE_CONFIG_FILES, addFactsDirectives, allRules, attrText, attrTextOf, attrValue, attrValueOf, collectComponentFacts, collectKitModuleFacts, collectSourceFiles, collectSuppressions, compileOverrides, computeHealth, decodeFragmentId, defaultConfig, docsUrlFor, findAttr, findMinifyDisabled, foldOccurrences, formatAgentReport, formatConsoleReport, formatFailedRuleWarning, formatGithubReport, formatHtmlReport, formatJsonReport, formatMarkdownReport, formatSarifReport, hasFailureAtOrAbove, isClassicScriptType, isPenalized, isTopFragment, lineOf, noColorPalette, parseSvelte, resolveKitAliases, resolveKitPathsBase, resolveLandmark, resolveRepoLocalPath, resolveRuleOptions, runAnalysis, scoreColor, selectRules, settingSeverity, shouldSkipRangeCheck, skippedFileWarnings, splitTokens, stripTextDirective, summarize, terminalSafe, textFromNodes, unknownDirectiveIds, validateRuleSetting, valueFromNodes, withReadLimit } from "@svelte-vitals/core/internal";
5
+ import { access, glob, readFile, stat } from "node:fs/promises";
7
6
  import { getAgentProfile } from "gunshi/agent";
8
7
  import { execFileSync } from "node:child_process";
9
8
  import { tmpdir } from "node:os";
@@ -35,6 +34,33 @@ function idRefSkipWarning(entries, analyzedRoutes) {
35
34
  return `${ID_REF_RULE} skipped ${entries.length} of ${analyzedRoutes} analyzed route(s) — it only checks routes it can fully resolve, so this is not a failure. Causes: ${causes.join(", ")}. Per-route detail: --reporter json → "skipped". Why, and how to widen: ${docsUrlFor(ID_REF_RULE)}`;
36
35
  }
37
36
  //#endregion
37
+ //#region src/glob.ts
38
+ /**
39
+ * `node:fs` glob constrained to the contract callers rely on: files only (fs.glob also matches
40
+ * directories), cwd-relative POSIX-separated paths on every platform (fs.glob returns platform
41
+ * separators), dotfiles excluded (fs.glob's default). A symlink's Dirent never reports isFile(),
42
+ * so symlinks are stat'd and kept when they point at a file; symlinked *directories* are not
43
+ * traversed — fs.glob never descends into them. `exclude` prunes traversal — returning true for
44
+ * a directory skips its whole subtree.
45
+ */
46
+ async function globFiles(pattern, cwd, exclude) {
47
+ const out = [];
48
+ for await (const entry of glob(pattern, {
49
+ cwd,
50
+ withFileTypes: true,
51
+ ...exclude ? { exclude } : {}
52
+ })) {
53
+ const path = join(entry.parentPath, entry.name);
54
+ if (!entry.isFile()) {
55
+ if (!entry.isSymbolicLink()) continue;
56
+ if (!(await stat(path).catch(() => null))?.isFile()) continue;
57
+ }
58
+ const rel = relative(cwd, path);
59
+ out.push(sep === "/" ? rel : rel.split(sep).join("/"));
60
+ }
61
+ return out;
62
+ }
63
+ //#endregion
38
64
  //#region src/runtime/node.ts
39
65
  /**
40
66
  * Node implementation of the core Runtime abstraction (design §8). This is the
@@ -56,10 +82,7 @@ function createNodeRuntime() {
56
82
  }
57
83
  },
58
84
  glob(pattern, cwd) {
59
- return glob(pattern, {
60
- cwd,
61
- dot: false
62
- });
85
+ return globFiles(pattern, cwd);
63
86
  },
64
87
  join(...parts) {
65
88
  return join(...parts);
@@ -570,29 +593,6 @@ function collectSvelteHeads(node, acc) {
570
593
  if (node.type === "SvelteHead") acc.push(node);
571
594
  for (const key of CHILD_NODE_KEYS) if (key in node) collectSvelteHeads(childOf(node, key), acc);
572
595
  }
573
- const JS_MIME_TYPES = /* @__PURE__ */ new Set([
574
- "application/ecmascript",
575
- "application/javascript",
576
- "application/x-ecmascript",
577
- "application/x-javascript",
578
- "text/ecmascript",
579
- "text/javascript",
580
- "text/javascript1.0",
581
- "text/javascript1.1",
582
- "text/javascript1.2",
583
- "text/javascript1.3",
584
- "text/javascript1.4",
585
- "text/javascript1.5",
586
- "text/jscript",
587
- "text/livescript",
588
- "text/x-ecmascript",
589
- "text/x-javascript"
590
- ]);
591
- function isClassicScriptType(type) {
592
- if (type === void 0) return true;
593
- const normalized = type.trim().toLowerCase();
594
- return normalized === "" || JS_MIME_TYPES.has(normalized);
595
- }
596
596
  function tagsFromHead(head) {
597
597
  const tags = [];
598
598
  const children = head.fragment.nodes;
@@ -727,27 +727,10 @@ function collectHeadings(node, source, acc) {
727
727
  });
728
728
  for (const key of CHILD_NODE_KEYS) if (key in node) collectHeadings(childOf(node, key), source, acc);
729
729
  }
730
- const LANDMARK_TAGS = /* @__PURE__ */ new Map([
731
- ["main", "main"],
732
- ["header", "banner"],
733
- ["footer", "contentinfo"]
734
- ]);
735
- /**
736
- * HTML-AAM: an `<aside>` scoped to `body` or `main` is a `complementary` landmark; scoped to
737
- * sectioning content it is one only when it has an accessible name. `main` is deliberately absent
738
- * — it is a scope in which an `aside` *is* a landmark, unlike the sectioning set that decides
739
- * `<header>`/`<footer>`.
740
- */
741
- const ASIDE_DEMOTING_TAGS = /* @__PURE__ */ new Set([
742
- "article",
743
- "aside",
744
- "nav",
745
- "section"
746
- ]);
747
730
  /** An `aria-label`/`aria-labelledby` carrying a name: a non-blank literal, or an expression whose
748
731
  * rendered value is unknowable. An empty or whitespace-only literal names nothing. */
749
732
  function hasAccessibleName(attrs) {
750
- return ["aria-label", "aria-labelledby"].some((name) => {
733
+ return NAMING_ATTRS.some((name) => {
751
734
  const attr = findAttr(attrs, name);
752
735
  if (!attr) return false;
753
736
  if (attrValueOf(attr) === "dynamic") return true;
@@ -900,11 +883,16 @@ function collectA11y(fragment, source) {
900
883
  const line = lineOf(source, node.start);
901
884
  const attrs = node.attributes;
902
885
  const roleAttr = findAttr(attrs, "role");
903
- const role = roleAttr ? splitTokens(attrTextOf(roleAttr))[0] : void 0;
904
- let landmark = roleAttr ? role && LANDMARK_ROLES.has(role) ? role : void 0 : LANDMARK_TAGS.get(node.name);
905
- if (!roleAttr && node.name === "aside") landmark = ctx.asideDemoting === 0 || hasAccessibleName(attrs) ? "complementary" : void 0;
886
+ const tag = (node.type === "SvelteElement" ? node.tag.type === "Literal" && typeof node.tag.value === "string" ? node.tag.value : void 0 : node.name)?.toLowerCase();
887
+ const landmark = resolveLandmark({
888
+ tag,
889
+ roleTokens: roleAttr ? splitTokens(attrTextOf(roleAttr)) : void 0,
890
+ named: tag === "aside" && hasAccessibleName(attrs),
891
+ insideSectioning: false,
892
+ insideAsideDemoting: ctx.asideDemoting > 0
893
+ });
906
894
  if (landmark) {
907
- const headerFooter = !roleAttr && (node.name === "header" || node.name === "footer");
895
+ const headerFooter = !roleAttr && tag !== void 0 && ANCESTRY_DEPENDENT_TAGS.has(tag);
908
896
  emit(ctx, {
909
897
  kind: "landmark",
910
898
  key: landmark,
@@ -942,12 +930,11 @@ function collectA11y(fragment, source) {
942
930
  attr: attr.name
943
931
  });
944
932
  }
945
- const literalTag = node.type === "SvelteElement" ? node.tag.type === "Literal" && typeof node.tag.value === "string" ? node.tag.value : void 0 : node.name;
946
- if (literalTag === "template") return;
933
+ if (tag === "template") return;
947
934
  walk(node.fragment, {
948
935
  ...ctx,
949
936
  elementDepth: ctx.elementDepth + 1,
950
- asideDemoting: ctx.asideDemoting + (literalTag && ASIDE_DEMOTING_TAGS.has(literalTag) ? 1 : 0),
937
+ asideDemoting: ctx.asideDemoting + (tag !== void 0 && ASIDE_DEMOTING_TAGS.has(tag) ? 1 : 0),
951
938
  landmarks: landmark ? [...ctx.landmarks, landmark] : ctx.landmarks
952
939
  });
953
940
  };
@@ -1133,8 +1120,8 @@ async function resolveFileTags(rt, cwd, fileRel, parsed, config, depth, visited,
1133
1120
  //#endregion
1134
1121
  //#region src/providers/source/routes.ts
1135
1122
  const ROUTES_DIR = "src/routes";
1136
- const MAX_DEPTH = 5;
1137
- /** glob/tinyglobby returns POSIX-separated paths on every platform, so we split on '/'. */
1123
+ const MAX_DEPTH$1 = 5;
1124
+ /** Runtime.glob returns POSIX-separated paths on every platform, so we split on '/'. */
1138
1125
  function isGroupSegment(segment) {
1139
1126
  return /^\(.+\)$/.test(segment);
1140
1127
  }
@@ -1364,7 +1351,7 @@ async function resolveRoute(rt, cwd, pageRel, config, layouts, cache, aliases, a
1364
1351
  let slotLandmark;
1365
1352
  for (const { rel, isPage } of files) {
1366
1353
  const parsed = await readAndParse(rt, cwd, rel, cache);
1367
- const contributed = await composeA11y(a11yCtx, rel, parsed, MAX_DEPTH, /* @__PURE__ */ new Set([rel]), true);
1354
+ const contributed = await composeA11y(a11yCtx, rel, parsed, MAX_DEPTH$1, /* @__PURE__ */ new Set([rel]), true);
1368
1355
  for (const node of contributed) {
1369
1356
  if (!node.chain || node.kind !== "landmark" || !countsAsLandmark(node) || node.repeatable) continue;
1370
1357
  const within = node.inLandmark ?? slotLandmark;
@@ -1385,7 +1372,7 @@ async function resolveRoute(rt, cwd, pageRel, config, layouts, cache, aliases, a
1385
1372
  ...heading,
1386
1373
  file: rel
1387
1374
  });
1388
- const resolved = await resolveFileTags(rt, cwd, rel, parsed, config, MAX_DEPTH, /* @__PURE__ */ new Set([rel]), cache, aliases);
1375
+ const resolved = await resolveFileTags(rt, cwd, rel, parsed, config, MAX_DEPTH$1, /* @__PURE__ */ new Set([rel]), cache, aliases);
1389
1376
  for (const tag of resolved.tags) {
1390
1377
  const stamped = {
1391
1378
  ...tag,
@@ -1535,10 +1522,11 @@ async function collectAll(rt, cwd, config, opts = {}) {
1535
1522
  const suppressions = await parsed.then((parsedFile) => parsedFile.suppressions, () => void 0);
1536
1523
  if (suppressions) directives.set(file, suppressions);
1537
1524
  }
1538
- for (const c of components) directives.set(c.file, c.suppressions ?? []);
1539
- for (const m of kitModules) directives.set(m.file, m.suppressions ?? []);
1540
- const viteConfig = project.viteMinifyDisabled;
1541
- if (viteConfig?.file) directives.set(viteConfig.file, viteConfig.suppressions ?? []);
1525
+ addFactsDirectives(directives, {
1526
+ components,
1527
+ kitModules,
1528
+ viteMinifyDisabled: project.viteMinifyDisabled
1529
+ });
1542
1530
  const routes = collected.heads.map((h) => h.route);
1543
1531
  const emptySelections = [];
1544
1532
  if (opts.route !== void 0 && routes.length > 0 && !routes.some(matches)) emptySelections.push(`--route '${opts.route}' matched none of the ${routes.length} route(s) found — routes are URL paths, e.g. --route '/blog/**'; list them with --reporter json → routes.`);
@@ -1596,16 +1584,18 @@ function hasDep(pkg, name) {
1596
1584
  }
1597
1585
  //#endregion
1598
1586
  //#region src/discover-apps.ts
1599
- const GLOB_OPTS = {
1600
- dot: false,
1601
- deep: 4,
1602
- ignore: [
1603
- "**/node_modules/**",
1604
- "**/.svelte-kit/**",
1605
- "**/build/**",
1606
- "**/dist/**",
1607
- "**/.git/**"
1608
- ]
1587
+ const IGNORED_DIRS = /* @__PURE__ */ new Set([
1588
+ "node_modules",
1589
+ ".svelte-kit",
1590
+ "build",
1591
+ "dist",
1592
+ ".git"
1593
+ ]);
1594
+ const MAX_DEPTH = 4;
1595
+ const pruneFor = (cwd) => (entry) => {
1596
+ if (!entry.isDirectory()) return false;
1597
+ if (IGNORED_DIRS.has(entry.name)) return true;
1598
+ return relative(cwd, join(entry.parentPath, entry.name)).split(sep).length >= MAX_DEPTH;
1609
1599
  };
1610
1600
  /** True if `pkgJsonPath` declares `@sveltejs/kit` as a dependency. Missing or malformed package.json — not a candidate. */
1611
1601
  async function hasKitDependency(pkgJsonPath) {
@@ -1625,13 +1615,8 @@ async function hasKitDependency(pkgJsonPath) {
1625
1615
  * huge repo stays fast.
1626
1616
  */
1627
1617
  async function discoverApps(cwd) {
1628
- const [configs, pkgJsons] = await Promise.all([glob("**/svelte.config.{js,ts}", {
1629
- cwd,
1630
- ...GLOB_OPTS
1631
- }), glob("**/package.json", {
1632
- cwd,
1633
- ...GLOB_OPTS
1634
- })]);
1618
+ const prune = pruneFor(cwd);
1619
+ const [configs, pkgJsons] = await Promise.all([globFiles("**/svelte.config.{js,ts}", cwd, prune), globFiles("**/package.json", cwd, prune)]);
1635
1620
  const configDirs = configs.map(dirname);
1636
1621
  const kitDepDirs = [];
1637
1622
  for (const pkgJson of pkgJsons) {
@@ -2828,7 +2813,7 @@ function overridesOffWarnings(allowRules, overrides) {
2828
2813
  return warnings;
2829
2814
  }
2830
2815
  /**
2831
- * Warn about rules `runRules` caught throwing (dev tooling must never throw): the run completes
2816
+ * Warn about rules `runAnalysis` caught throwing (dev tooling must never throw): the run completes
2832
2817
  * without them, so any findings they would have produced are simply missing rather than reported
2833
2818
  * as clean. Message capped to its first line so a multi-line stack trace can't flood the terminal.
2834
2819
  */
@@ -2885,7 +2870,7 @@ async function analyzeProject(opts = {}) {
2885
2870
  const starved = rules.filter((r) => opts.allowRules.includes(r.id) && r.scope === "component").map((r) => r.id);
2886
2871
  if (starved.length > 0) warnings.push(`--rules ${starved.map((id) => `'${id}'`).join(", ")} examined nothing: --route analyzes routes only, and that rule reads component/config files — run without --route to check it.`);
2887
2872
  }
2888
- const { results: rawResults, examined, failedRules } = await runRules(rules, {
2873
+ const { results, examined, failedRules, failedRuleIds, scoringConfig } = await runAnalysis(rules, {
2889
2874
  heads,
2890
2875
  images,
2891
2876
  headings,
@@ -2895,12 +2880,10 @@ async function analyzeProject(opts = {}) {
2895
2880
  config,
2896
2881
  kitModules,
2897
2882
  sourceFiles
2898
- });
2899
- const results = applyInlineDirectives(applyOverrides(applyRuleSeverities(rawResults, config), config), directives, rules, config);
2900
- const failedRuleIds = failedRules.map((f) => f.id);
2883
+ }, directives);
2901
2884
  return {
2902
2885
  results,
2903
- config: withFailedRulesOff(config, failedRuleIds),
2886
+ config: scoringConfig,
2904
2887
  version: readPackageVersion(),
2905
2888
  ruleIds: rules.map((r) => r.id),
2906
2889
  examined,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-vitals",
3
- "version": "0.54.0",
3
+ "version": "0.54.2",
4
4
  "description": "A deterministic SvelteKit code-health scanner (SEO, performance, correctness, security, architecture, accessibility).",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -43,15 +43,14 @@
43
43
  "dist"
44
44
  ],
45
45
  "dependencies": {
46
- "@svelte-vitals/core": "0.50.0",
46
+ "@svelte-vitals/core": "0.51.0",
47
47
  "@clack/prompts": "^1.7.0",
48
48
  "@gunshi/plugin-completion": "0.37.1",
49
49
  "@gunshi/plugin-i18n": "0.37.1",
50
50
  "@gunshi/plugin-suggestion": "0.37.1",
51
51
  "gunshi": "0.37.1",
52
52
  "magicast": "^0.5.4",
53
- "svelte": "^5.56.10",
54
- "tinyglobby": "^0.2.17"
53
+ "svelte": "^5.57.0"
55
54
  },
56
55
  "devDependencies": {
57
56
  "@gunshi/docs": "0.37.1",