svelte-vitals 0.52.0 → 0.53.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
|
@@ -16,14 +16,14 @@ async function runCli(argv, io = consoleIO, env = process.env) {
|
|
|
16
16
|
try {
|
|
17
17
|
const locale = resolveLocale(env);
|
|
18
18
|
if (argv[0] === "complete") {
|
|
19
|
-
const { runCompleteCliGunshi } = await import("./complete-
|
|
19
|
+
const { runCompleteCliGunshi } = await import("./complete-BbHBOkTw.js");
|
|
20
20
|
return {
|
|
21
21
|
code: await runCompleteCliGunshi(argv, io),
|
|
22
22
|
exit: "natural"
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
if (argv[0] === "docs") {
|
|
26
|
-
const { runDocsCliGunshi } = await import("./docs-
|
|
26
|
+
const { runDocsCliGunshi } = await import("./docs-B-poFe5N.js");
|
|
27
27
|
return {
|
|
28
28
|
code: await runDocsCliGunshi(argv.slice(1), io, locale),
|
|
29
29
|
exit: "natural"
|
|
@@ -2,7 +2,7 @@ import { f as REPORTER_NAMES } from "./src-hgEeAWHb.js";
|
|
|
2
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-njXPaqmd.js";
|
|
3
3
|
import { t as INSTALL_ARGS } from "./install-CzogylBI.js";
|
|
4
4
|
import { CI_ARGS, CI_UPGRADE_ARGS } from "./ci-BWM2gYNJ.js";
|
|
5
|
-
import { DOCS_LIST_ARGS, DOCS_ROOT_ARGS, DOCS_SHOW_ARGS } from "./docs-
|
|
5
|
+
import { DOCS_LIST_ARGS, DOCS_ROOT_ARGS, DOCS_SHOW_ARGS } from "./docs-B-poFe5N.js";
|
|
6
6
|
import { EXPLAIN_ARGS } from "./explain-B0DWOujg.js";
|
|
7
7
|
import { cli } from "gunshi/bone";
|
|
8
8
|
import { define } from "gunshi/definition";
|
|
@@ -16,7 +16,7 @@ const EMBEDDED_DOCS = [
|
|
|
16
16
|
name: "config",
|
|
17
17
|
title: "The config file",
|
|
18
18
|
description: "Where svelte-vitals.config lives, every top-level option, how to disable or re-grade a rule, and how to scope rules to routes or files.",
|
|
19
|
-
body: "# The config file\n\n## Where it lives\n\nIn the **analyzed directory only** — no upward search. First match wins:\n\n1. `svelte-vitals.config.js`\n2. `svelte-vitals.config.ts`\n\nNo file means built-in defaults. `svelte-vitals install --client config-file` scaffolds one with\nevery option commented out.\n\n`--config <path>` analyzes under the config file at that path instead of the one in the analyzed\ndirectory — no discovery, no merge. A relative path resolves against the directory you run the\ncommand from, never the analyzed directory: from a repo root,\n`svelte-vitals apps/web --config shared/sv.config.js` reads `./shared/sv.config.js`. It accepts\n`.js` and `.ts` only, and a missing or unreadable file exits `2`. Useful for trying a config out\nbefore committing it, and for sharing one config across the apps in a monorepo. CLI only: the Vite\nplugin resolves its own config from the `cwd` passed to `svelteVitals({ ... })` (else the Vite\nconfig root) — share with it by importing the shared file in `vite.config.ts` and spreading it\ninto the plugin's options.\n\n```js\n// svelte-vitals.config.js\nexport default {\n treatDynamicAs: 'warn',\n metaComponents: ['Seo'],\n rules: { 'seo/json-ld': 'off' },\n failOn: 'warning',\n weights: { seo: 2 }\n};\n```\n\nA `.ts` config can `import { defineConfig } from 'svelte-vitals'` for type-checking, but that is a\n**runtime** import: it needs svelte-vitals as a declared dependency. A plain `export default {}`\nin `.js` behaves identically and needs no dependency. Both are ESM — the project must be\n`\"type\": \"module\"` (SvelteKit's default).\n\n## Options\n\n| Option | Type | Default |\n| ---------------- | -------------------------------------------------------------- | ------------------ |\n| `treatDynamicAs` | `'pass' \\| 'warn' \\| 'fail'` | `'pass'` |\n| `metaComponents` | `string[]` | `[]` |\n| `rules` | `Record<ruleId, 'off' \\| Severity \\| { severity?, options? }>` | `{}` |\n| `failOn` | `'critical' \\| 'warning' \\| 'info'` | `'critical'` |\n| `weights` | `Partial<Record<Category, number>>` | every category `1` |\n| `overrides` | `RuleOverride[]` | (none) |\n\n`Severity` is `'critical' | 'warning' | 'info'`. `Category` is `'seo' | 'performance' |\n'correctness' | 'security' | 'architecture' | 'a11y'`. A weight of `0` drops a category from the Health\naverage; setting every category to `0` is an error (exit `2`).\n\n`metaComponents` names head-metadata components the analyzer cannot resolve (e.g. from an npm\npackage without an adapter). Components the analyzer can resolve in your own repo are followed\nautomatically — declaring one of those is a no-op; the declaration only kicks in when\nresolution fails.\n\n## Turning a rule off or down\n\n```js\nexport default {\n rules: {\n 'seo/json-ld': 'off', // remove its findings entirely\n 'architecture/prop-count': 'info' // keep it, stop it failing the build\n }\n};\n```\n\nMany rules take options, so check whether the finding is a **threshold disagreement** rather than\na defect first. `svelte-vitals explain <rule-id>` prints each option's name, default, bounds, and\nmerge semantics (`integer` replaces, `string-list` appends, `string-map` is spread over).\n\n```js\nexport default {\n rules: {\n 'architecture/prop-count': { options: { max: 12 } }\n }\n};\n```\n\n## Scoping to routes or files (`overrides`)\n\n`rules` applies everywhere; `overrides` applies only where it matches — typically routes that\nare deliberately not public.\n\n```js\nexport default {\n overrides: [\n { files: 'src/routes/(app)/**', rules: { seo: 'off' } },\n { route: '/admin/**', rules: { 'seo/title-presence': 'info' } }\n ]\n};\n```\n\nEach entry needs `rules` (keys are rule ids **or** category names) plus at least one of:\n\n-
|
|
19
|
+
body: "# The config file\n\n## Where it lives\n\nIn the **analyzed directory only** — no upward search. First match wins:\n\n1. `svelte-vitals.config.js`\n2. `svelte-vitals.config.ts`\n\nNo file means built-in defaults. `svelte-vitals install --client config-file` scaffolds one with\nevery option commented out.\n\n`--config <path>` analyzes under the config file at that path instead of the one in the analyzed\ndirectory — no discovery, no merge. A relative path resolves against the directory you run the\ncommand from, never the analyzed directory: from a repo root,\n`svelte-vitals apps/web --config shared/sv.config.js` reads `./shared/sv.config.js`. It accepts\n`.js` and `.ts` only, and a missing or unreadable file exits `2`. Useful for trying a config out\nbefore committing it, and for sharing one config across the apps in a monorepo. CLI only: the Vite\nplugin resolves its own config from the `cwd` passed to `svelteVitals({ ... })` (else the Vite\nconfig root) — share with it by importing the shared file in `vite.config.ts` and spreading it\ninto the plugin's options.\n\n```js\n// svelte-vitals.config.js\nexport default {\n treatDynamicAs: 'warn',\n metaComponents: ['Seo'],\n rules: { 'seo/json-ld': 'off' },\n failOn: 'warning',\n weights: { seo: 2 }\n};\n```\n\nA `.ts` config can `import { defineConfig } from 'svelte-vitals'` for type-checking, but that is a\n**runtime** import: it needs svelte-vitals as a declared dependency. A plain `export default {}`\nin `.js` behaves identically and needs no dependency. Both are ESM — the project must be\n`\"type\": \"module\"` (SvelteKit's default).\n\n## Options\n\n| Option | Type | Default |\n| ---------------- | -------------------------------------------------------------- | ------------------ |\n| `treatDynamicAs` | `'pass' \\| 'warn' \\| 'fail'` | `'pass'` |\n| `metaComponents` | `string[]` | `[]` |\n| `rules` | `Record<ruleId, 'off' \\| Severity \\| { severity?, options? }>` | `{}` |\n| `failOn` | `'critical' \\| 'warning' \\| 'info'` | `'critical'` |\n| `weights` | `Partial<Record<Category, number>>` | every category `1` |\n| `overrides` | `RuleOverride[]` | (none) |\n\n`Severity` is `'critical' | 'warning' | 'info'`. `Category` is `'seo' | 'performance' |\n'correctness' | 'security' | 'architecture' | 'a11y'`. A weight of `0` drops a category from the Health\naverage; setting every category to `0` is an error (exit `2`).\n\n`metaComponents` names head-metadata components the analyzer cannot resolve (e.g. from an npm\npackage without an adapter). Components the analyzer can resolve in your own repo are followed\nautomatically — declaring one of those is a no-op; the declaration only kicks in when\nresolution fails.\n\n## Turning a rule off or down\n\n```js\nexport default {\n rules: {\n 'seo/json-ld': 'off', // remove its findings entirely\n 'architecture/prop-count': 'info' // keep it, stop it failing the build\n }\n};\n```\n\nMany rules take options, so check whether the finding is a **threshold disagreement** rather than\na defect first. `svelte-vitals explain <rule-id>` prints each option's name, default, bounds, and\nmerge semantics (`integer` replaces, `string-list` appends, `string-map` is spread over).\n\n```js\nexport default {\n rules: {\n 'architecture/prop-count': { options: { max: 12 } }\n }\n};\n```\n\n## Scoping to routes or files (`overrides`)\n\n`rules` applies everywhere; `overrides` applies only where it matches — typically routes that\nare deliberately not public.\n\n```js\nexport default {\n overrides: [\n { files: 'src/routes/(app)/**', rules: { seo: 'off' } },\n { route: '/admin/**', rules: { 'seo/title-presence': 'info' } }\n ]\n};\n```\n\nEach entry needs `rules` (keys are rule ids **or** category names) plus at least one of:\n\n- `route` — glob(s) against the route id as reported (`/blog/[slug]`). SvelteKit `(group)`\n segments are **not** in the route id, so use `files` to target a group.\n- `files` — glob(s) against the source path.\n\nGlobs are deliberately small: `*` within a segment, `**` across segments, a trailing `/**` also\nmatches the bare prefix. Everything else — including `(`, `)`, `[`, `]` — is literal. Later entries win.\n\n## Precedence\n\nPer field: **CLI flag > config file > built-in default**. One exception — `--rules` and `--ignore`\nare selection, not configuration: `--rules` narrows the run to the ids it names and overrides a\nconfig-file `off` for them, but keeps their declared severity and options; `--ignore` adds `off`\nentries for the ids it names, layered on top of whatever `rules` resolved to, and beats `--rules`\nwhen both name the same rule.\n\n`overrides` has no CLI flag; route policy belongs in a committed file.\n\n## Validation\n\nAn unknown rule id or category, a negative weight, a malformed `overrides` entry, or an invalid\nrule setting is a **hard error (exit `2`)** — a typo must not silently un-gate CI. An unrecognized\n`treatDynamicAs`/`failOn` value, or an unknown top-level key, only warns.\n\n## Related\n\n- `svelte-vitals explain --list` — every rule id\n- `svelte-vitals docs show scoping` — accepting an existing backlog instead of disabling rules"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
name: "monorepo",
|
|
@@ -28,13 +28,13 @@ const EMBEDDED_DOCS = [
|
|
|
28
28
|
name: "output",
|
|
29
29
|
title: "Reading the output",
|
|
30
30
|
description: "Which reporter to use, how one is auto-selected, what goes to stdout vs stderr, and what each exit code means.",
|
|
31
|
-
body: "# Reading the output\n\n## Pick a reporter\n\n`--reporter <fmt>`: `console` (default) · `json` · `agent` · `sarif` · `github` · `html` · `md`.\n\n-
|
|
31
|
+
body: "# Reading the output\n\n## Pick a reporter\n\n`--reporter <fmt>`: `console` (default) · `json` · `agent` · `sarif` · `github` · `html` · `md`.\n\n- `agent` — Markdown remediation: each failing finding with its location, a concrete fix\n (with snippet), and an acceptance check. Use this when something will act on the findings.\n- `json` — the full structured report (scores per route and site-wide; every finding with\n `fix`, `recommendation`, `docsUrl`). Use it to filter or count.\n- `console` — for a human. Grouped and capped; `--verbose` for everything.\n- `md` — a compact summary table for a PR comment or job summary (capped at 50 rows).\n- `sarif` — SARIF v2.1, for GitHub Code Scanning and other SAST tooling.\n- `github` — `::error` / `::warning` workflow annotations.\n- `html` — a self-contained report file; `--out-file <path>`, or `--out-file -` for stdout.\n\n## Auto-selection\n\nFirst match wins:\n\n1. an explicit `--reporter <fmt>`\n2. `SVELTE_VITALS_REPORTER=<fmt>`\n3. a recognized AI-agent harness (Claude Code, Cursor, Codex, and others — detection is\n delegated to gunshi's agent profile and evolves with it) or `SVELTE_VITALS_AGENT=1` set → `agent`\n4. `GITHUB_ACTIONS=true` → `github`\n5. otherwise → `console`\n\nInside an agent harness you get `agent` without asking; a one-line override hint goes to stderr.\n\n## stdout vs stderr\n\nThe report goes to **stdout**; every diagnostic — hints, suppression counts, app-detection\nnotices, warnings, errors — to **stderr**. Piping stdout never mixes the two.\n\n`--reporter html` is the exception: it writes a file and prints the path to stderr, unless you\npass `--out-file -`.\n\n## Exit codes\n\n| Code | Meaning |\n| ---- | -------------------------------------------------------------------------- |\n| `0` | no failing findings |\n| `1` | a critical finding is present, or `--fail-on` / `--min-health` was reached |\n| `2` | execution error — not a SvelteKit project, bad flag, unreadable config |\n\n`2` is never a clean result — the run did not happen. `--fail-on <critical|warning|info>` lowers\nthe bar for `1`; `--min-health <0-100>` adds a score gate.\n\n## Related\n\n- `svelte-vitals docs show scoping` — report only what a change introduced\n- `svelte-vitals explain <rule-id>` — one rule's rationale, fix and options"
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
name: "scoping",
|
|
35
35
|
title: "Scoping findings to a change",
|
|
36
36
|
description: "Use --diff, --staged, --baseline and the suppressions file so only what a change introduced is reported, instead of a legacy backlog.",
|
|
37
|
-
body: "# Scoping findings to a change\n\nAn existing project usually has a backlog nobody is about to fix. Scope the report rather than\ndisabling rules.\n\n## Scope by file\n\n-
|
|
37
|
+
body: "# Scoping findings to a change\n\nAn existing project usually has a backlog nobody is about to fix. Scope the report rather than\ndisabling rules.\n\n## Scope by file\n\n- `--diff [ref]` — only findings in files changed versus `ref` (default `HEAD`).\n- `--staged` — only findings in staged files. The pre-commit gate.\n\n```bash\nsvelte-vitals . --diff --reporter agent # after editing: what did I just break?\nsvelte-vitals . --staged # before committing\n```\n\nBoth work when the project is not at the git repo root.\n\n## Scope by finding (`--baseline <ref>`)\n\nReports only findings **not already present** at `ref`. Scopes by finding identity rather than by\nfile, so a pre-existing problem in a file you touched does not fail the gate. No default ref.\n\n```bash\nsvelte-vitals --diff origin/main --baseline origin/main --fail-on warning # PR gate\n```\n\nIt checks `ref` out into a temporary worktree and subtracts those findings. On failure (no git,\nbad ref) it warns and reports everything rather than failing the run.\n\n## Accept a backlog once (`svelte-vitals-suppressions.json`)\n\n`--baseline` handles the transient case. For a persistent ramp, record today's findings once:\n\n```bash\nsvelte-vitals --update-suppressions\ngit add svelte-vitals-suppressions.json\n```\n\nThis analyzes the whole project (`--diff`/`--staged`/`--baseline` are ignored), writes every\npenalized finding, and exits `0` without a report.\n\nThe file then applies automatically on every run, after `--diff`/`--staged` and `--baseline`.\nFixing an accepted finding leaves a **stale** entry, reported on stderr but never failing the run.\n`--no-suppressions` ignores the file for one run.\n\nAn entry covers whatever its rule reports at that route and location, not just the message\nrecorded when written — a different finding from the same rule at the same spot still matches\nand stays suppressed (and not stale).\n\nA malformed suppressions file is a hard error (exit `2`), not a silent skip.\n\n## Suppress one occurrence inline\n\nFor a single finding that is correct by design, put a `svelte-vitals-disable-next-line` comment on\nthe line directly above it:\n\n```html\n<!-- svelte-vitals-disable-next-line security/raw-html -->\n<div>{@html sanitized}</div>\n```\n\nInside `<script>`, use `// svelte-vitals-disable-next-line <rule-id>`. Omit the id to suppress every\nrule on the next line, or list several comma-separated.\n\nOnly findings the report anchors to a **line** can be reached this way — not the `<head>` metadata\nrules, which report what a route never set. A directive in a component silences that finding on\nevery route composing it; for one route, use the suppressions file or `overrides`.\n\n## Which one\n\n| Situation | Use |\n| -------------------------------------- | ---------------------------------------- |\n| Checking an edit you just made | `--diff` |\n| One occurrence that is right as-is | `svelte-vitals-disable-next-line` |\n| Pre-commit hook | `--staged` |\n| PR gate against a base branch | `--diff <base> --baseline <base>` |\n| Adopting on a legacy project, for good | `--update-suppressions`, commit the file |\n\nMatching ignores line numbers in both `--baseline` and the suppressions file, so a second\nviolation of the same rule lower in the same file does not surface as new.\n\n## Related\n\n- `svelte-vitals docs show ci` — the generated PR gate already does the `--diff`/`--baseline` pairing\n- `svelte-vitals docs show config` — turning a rule off for good, when that is genuinely right"
|
|
38
38
|
}
|
|
39
39
|
];
|
|
40
40
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-vitals",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0",
|
|
4
4
|
"description": "A deterministic SvelteKit code-health scanner (SEO, performance, correctness, security, architecture, accessibility).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"magicast": "^0.5.4",
|
|
52
52
|
"svelte": "^5.56.10",
|
|
53
53
|
"tinyglobby": "^0.2.17",
|
|
54
|
-
"@svelte-vitals/core": "0.
|
|
54
|
+
"@svelte-vitals/core": "0.49.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@gunshi/docs": "0.37.1",
|