svelte-vitals 0.7.0 → 0.9.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
@@ -6,7 +6,7 @@ import {
6
6
  knownRuleIds,
7
7
  readPackageVersion,
8
8
  run
9
- } from "./chunk-DVIKLRTP.js";
9
+ } from "./chunk-Y56I4RGY.js";
10
10
 
11
11
  // src/bin.ts
12
12
  import mri from "mri";
@@ -85,6 +85,7 @@ Options:
85
85
  --json Alias for --reporter=json
86
86
  --fail-on <severity> Fail (exit 1) when any finding reaches this severity: critical | warning | info
87
87
  --fail-on-warning Alias for --fail-on=warning
88
+ --min-health <0-100> Fail (exit 1) when the combined Health score is below this value
88
89
  --rules <ids> Comma-separated rule ids to enable (all others disabled)
89
90
  --ignore <ids> Comma-separated rule ids to disable
90
91
  -h, --help Show this help
@@ -99,7 +100,7 @@ async function main() {
99
100
  const argv = mri(process.argv.slice(2), {
100
101
  alias: { h: "help", v: "version" },
101
102
  boolean: ["by-route", "json", "fail-on-warning"],
102
- string: ["meta-components", "treat-dynamic-as", "route", "fail-on", "reporter", "rules", "ignore"]
103
+ string: ["meta-components", "treat-dynamic-as", "route", "fail-on", "reporter", "rules", "ignore", "min-health"]
103
104
  });
104
105
  if (argv.help) {
105
106
  console.log(HELP);
@@ -113,7 +114,17 @@ async function main() {
113
114
  for (const w of warnings) console.error(w);
114
115
  for (const e of errors) console.error(e);
115
116
  if (!options) process.exit(2);
116
- const code = await run(options);
117
+ const minHealthRaw = argv["min-health"];
118
+ let minHealth;
119
+ if (minHealthRaw !== void 0) {
120
+ const n = Number(minHealthRaw);
121
+ if (!Number.isFinite(n) || n < 0 || n > 100) {
122
+ console.error(`svelte-vitals: invalid --min-health '${minHealthRaw}'; expected a number 0-100.`);
123
+ process.exit(2);
124
+ }
125
+ minHealth = n;
126
+ }
127
+ const code = await run({ ...options, minHealth });
117
128
  process.exit(code);
118
129
  }
119
130
  void main();
@@ -9,6 +9,7 @@ import {
9
9
  formatGithubReport,
10
10
  summarize,
11
11
  hasFailureAtOrAbove,
12
+ computeHealth,
12
13
  defineConfig,
13
14
  selectRules,
14
15
  applyRuleSeverities
@@ -471,105 +472,6 @@ async function collectRoutes(rt, cwd, config = defaultConfig) {
471
472
  };
472
473
  }
473
474
 
474
- // src/providers/source/a11y.ts
475
- import { compile } from "svelte/compiler";
476
- import { defaultConfig as defaultConfig2 } from "@svelte-vitals/core";
477
-
478
- // src/rules-config.ts
479
- import { allRules } from "@svelte-vitals/core";
480
- var KNOWN_IDS = new Set(allRules.map((r) => r.id));
481
- var A11Y_CODE_PREFIX = "a11y_";
482
- var A11Y_CATEGORY_KEY = "a11y_category";
483
- function findUnknownRuleIds(ids) {
484
- return [
485
- ...new Set(ids.filter((id) => !KNOWN_IDS.has(id) && !(id.startsWith(A11Y_CODE_PREFIX) && id !== A11Y_CATEGORY_KEY)))
486
- ];
487
- }
488
- function knownRuleIds() {
489
- return [...KNOWN_IDS].sort();
490
- }
491
- function buildRulesConfig(allow, ignore) {
492
- const rules = {};
493
- if (allow.length > 0) {
494
- for (const r of allRules) if (!allow.includes(r.id)) rules[r.id] = "off";
495
- if (!allow.some((id) => id.startsWith(A11Y_CODE_PREFIX))) rules[A11Y_CATEGORY_KEY] = "off";
496
- }
497
- for (const id of ignore) rules[id] = "off";
498
- return rules;
499
- }
500
-
501
- // src/providers/source/a11y.ts
502
- function firstLine(message) {
503
- return message.split("\n")[0] ?? message;
504
- }
505
- function fileA11y(source, rel) {
506
- let warnings;
507
- try {
508
- ({ warnings } = compile(source, { generate: false, filename: rel }));
509
- } catch {
510
- return { ok: false, warnings: [] };
511
- }
512
- const out = [];
513
- for (const w of warnings) {
514
- if (w.code.startsWith(A11Y_CODE_PREFIX)) {
515
- out.push({
516
- code: w.code,
517
- message: firstLine(w.message),
518
- line: w.start?.line ?? 0
519
- });
520
- }
521
- }
522
- return { ok: true, warnings: out };
523
- }
524
- async function collectA11y(rt, cwd, config = defaultConfig2) {
525
- if (config.rules[A11Y_CATEGORY_KEY] === "off") return [];
526
- const pages = await enumerateRoutePages(rt, cwd);
527
- const cache = /* @__PURE__ */ new Map();
528
- const results = [];
529
- for (const page of pages) {
530
- const files = await chainFiles(rt, cwd, page);
531
- const route = deriveRoute(page);
532
- const fails = [];
533
- let compiledAll = true;
534
- for (const { rel } of files) {
535
- let entry = cache.get(rel);
536
- if (!entry) {
537
- const source = await rt.readFile(rt.join(cwd, rel));
538
- entry = fileA11y(source, rel);
539
- cache.set(rel, entry);
540
- }
541
- if (!entry.ok) compiledAll = false;
542
- for (const w of entry.warnings) {
543
- if (config.rules[w.code] === "off") continue;
544
- fails.push({
545
- id: w.code,
546
- category: "a11y",
547
- severity: "warning",
548
- detection: { presence: "none", value: "absent" },
549
- route,
550
- location: rel,
551
- ...w.line > 0 ? { line: w.line } : {},
552
- message: w.message,
553
- docsUrl: `https://svelte.dev/e/${w.code}`
554
- });
555
- }
556
- }
557
- if (fails.length > 0) {
558
- results.push(...fails);
559
- } else if (compiledAll) {
560
- results.push({
561
- id: "a11y",
562
- category: "a11y",
563
- severity: "warning",
564
- detection: { presence: "own", value: "static" },
565
- route,
566
- message: "Accessibility"
567
- });
568
- }
569
- }
570
- return results;
571
- }
572
-
573
475
  // src/version.ts
574
476
  import { readFileSync } from "fs";
575
477
  function readPackageVersion() {
@@ -610,6 +512,24 @@ function isAutoDetectedGithub(explicit, env = process.env) {
610
512
  return !explicit && !isReporterName(env.SVELTE_VITALS_REPORTER) && !isAgentEnv(env) && isGithubActionsEnv(env);
611
513
  }
612
514
 
515
+ // src/rules-config.ts
516
+ import { allRules } from "@svelte-vitals/core";
517
+ var KNOWN_IDS = new Set(allRules.map((r) => r.id));
518
+ function findUnknownRuleIds(ids) {
519
+ return [...new Set(ids.filter((id) => !KNOWN_IDS.has(id)))];
520
+ }
521
+ function knownRuleIds() {
522
+ return [...KNOWN_IDS].sort();
523
+ }
524
+ function buildRulesConfig(allow, ignore) {
525
+ const rules = {};
526
+ if (allow.length > 0) {
527
+ for (const r of allRules) if (!allow.includes(r.id)) rules[r.id] = "off";
528
+ }
529
+ for (const id of ignore) rules[id] = "off";
530
+ return rules;
531
+ }
532
+
613
533
  // src/index.ts
614
534
  function routeMatcher(glob) {
615
535
  if (!glob) return () => true;
@@ -633,14 +553,16 @@ async function analyzeProject(opts = {}) {
633
553
  const images = collected.images.filter((i) => matches(i.route));
634
554
  const project = await collectProjectFacts(rt, cwd);
635
555
  const rules = selectRules(allRules2, config);
636
- const a11y = (await collectA11y(rt, cwd, config)).filter((r) => r.route === void 0 || matches(r.route));
637
- const ruleResults = await runRules(rules, { heads, images, project, config });
638
- const results = applyRuleSeverities([...ruleResults, ...a11y], config);
556
+ const results = applyRuleSeverities(await runRules(rules, { heads, images, project, config }), config);
639
557
  return { results, config, version: readPackageVersion() };
640
558
  }
641
559
  async function run(opts = {}) {
642
560
  const log = opts.log ?? ((line) => console.log(line));
643
561
  const errorLog = opts.errorLog ?? ((line) => console.error(line));
562
+ if (opts.minHealth != null && (!Number.isFinite(opts.minHealth) || opts.minHealth < 0 || opts.minHealth > 100)) {
563
+ errorLog(`svelte-vitals: invalid minHealth '${opts.minHealth}'; expected a number 0-100.`);
564
+ return 2;
565
+ }
644
566
  let analysis;
645
567
  try {
646
568
  analysis = await analyzeProject({
@@ -686,7 +608,9 @@ async function run(opts = {}) {
686
608
  log(formatConsoleReport(results, config, { byRoute: opts.byRoute ?? false }));
687
609
  }
688
610
  const summary = summarize(results, config);
689
- return hasFailureAtOrAbove(summary, config.failOn) ? 1 : 0;
611
+ const failBySeverity = hasFailureAtOrAbove(summary, config.failOn);
612
+ const failByHealth = opts.minHealth != null && computeHealth(results, config).health < opts.minHealth;
613
+ return failBySeverity || failByHealth ? 1 : 0;
690
614
  } catch (err) {
691
615
  errorLog(`svelte-vitals: ${err instanceof Error ? err.message : String(err)}`);
692
616
  return 2;
@@ -695,11 +619,11 @@ async function run(opts = {}) {
695
619
 
696
620
  export {
697
621
  ProjectError,
622
+ readPackageVersion,
623
+ isReporterName,
698
624
  findUnknownRuleIds,
699
625
  knownRuleIds,
700
626
  buildRulesConfig,
701
- readPackageVersion,
702
- isReporterName,
703
627
  routeMatcher,
704
628
  analyzeProject,
705
629
  run
package/dist/index.d.ts CHANGED
@@ -16,10 +16,6 @@ declare function knownRuleIds(): string[];
16
16
  * (--ignore). An allow-list disables every rule not listed; deny always wins.
17
17
  * Callers should reject unknown ids first (see findUnknownRuleIds) so a typo in
18
18
  * --rules can't silently disable every rule.
19
- *
20
- * When the allow-list is non-empty and contains no `a11y_*` entries, the
21
- * `A11Y_CATEGORY_KEY` sentinel is set to `'off'`; `collectA11y` checks this key
22
- * to suppress the entire Accessibility category.
23
19
  */
24
20
  declare function buildRulesConfig(allow: string[], ignore: string[]): Record<string, RuleSetting>;
25
21
 
@@ -37,6 +33,8 @@ interface RunOptions {
37
33
  rules?: Record<string, RuleSetting>;
38
34
  /** Override process.env for reporter auto-detection (mainly useful in tests). */
39
35
  env?: NodeJS.ProcessEnv;
36
+ /** Fail (exit 1) when the combined Health score is below this value (0–100). */
37
+ minHealth?: number;
40
38
  }
41
39
  declare function routeMatcher(glob: string | undefined): (route: string) => boolean;
42
40
  interface AnalyzeOptions {
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  knownRuleIds,
7
7
  routeMatcher,
8
8
  run
9
- } from "./chunk-DVIKLRTP.js";
9
+ } from "./chunk-Y56I4RGY.js";
10
10
  export {
11
11
  ProjectError,
12
12
  analyzeProject,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-vitals",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "A SvelteKit SEO checker — not a runtime Web Vitals reporter. Static analysis of your routes' head metadata.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -42,7 +42,7 @@
42
42
  "mri": "^1.2.0",
43
43
  "svelte": "^5.56.3",
44
44
  "tinyglobby": "^0.2.17",
45
- "@svelte-vitals/core": "0.8.0"
45
+ "@svelte-vitals/core": "0.10.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/node": "^24.7.0"