svelte-vitals 0.3.0 → 0.5.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 +8 -23
- package/dist/{chunk-LYX2RVRM.js → chunk-RI6LBHFR.js} +69 -13
- package/dist/index.d.ts +40 -3
- package/dist/index.js +11 -1
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -1,32 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
buildRulesConfig,
|
|
4
|
+
findUnknownRuleIds,
|
|
3
5
|
isReporterName,
|
|
6
|
+
knownRuleIds,
|
|
4
7
|
readPackageVersion,
|
|
5
8
|
run
|
|
6
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-RI6LBHFR.js";
|
|
7
10
|
|
|
8
11
|
// src/bin.ts
|
|
9
12
|
import mri from "mri";
|
|
10
|
-
|
|
11
|
-
// src/rules-config.ts
|
|
12
|
-
import { allRules } from "@svelte-vitals/core";
|
|
13
|
-
var KNOWN_IDS = new Set(allRules.map((r) => r.id));
|
|
14
|
-
function findUnknownRuleIds(ids) {
|
|
15
|
-
return [...new Set(ids.filter((id) => !KNOWN_IDS.has(id)))];
|
|
16
|
-
}
|
|
17
|
-
function knownRuleIds() {
|
|
18
|
-
return [...KNOWN_IDS].sort();
|
|
19
|
-
}
|
|
20
|
-
function buildRulesConfig(allow, ignore) {
|
|
21
|
-
const rules = {};
|
|
22
|
-
if (allow.length > 0) {
|
|
23
|
-
for (const r of allRules) if (!allow.includes(r.id)) rules[r.id] = "off";
|
|
24
|
-
}
|
|
25
|
-
for (const id of ignore) rules[id] = "off";
|
|
26
|
-
return rules;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// src/bin.ts
|
|
30
13
|
var HELP = `svelte-vitals \u2014 a SvelteKit SEO checker (static mode)
|
|
31
14
|
|
|
32
15
|
Usage:
|
|
@@ -37,7 +20,7 @@ Options:
|
|
|
37
20
|
--treat-dynamic-as <mode> pass | warn | fail (default: pass)
|
|
38
21
|
--route <glob> Only analyze routes matching this glob
|
|
39
22
|
--by-route Show per-route score breakdown in console output
|
|
40
|
-
--reporter <fmt> console | json | agent (auto: agent under AI-agent envs)
|
|
23
|
+
--reporter <fmt> console | json | agent | sarif | github (auto: agent under AI-agent envs, github under GitHub Actions)
|
|
41
24
|
--json Alias for --reporter=json
|
|
42
25
|
--fail-on <severity> Fail (exit 1) when any finding reaches this severity: critical | warning | info
|
|
43
26
|
--fail-on-warning Alias for --fail-on=warning
|
|
@@ -84,7 +67,9 @@ async function main() {
|
|
|
84
67
|
reporter = "json";
|
|
85
68
|
} else if (typeof argv.reporter === "string") {
|
|
86
69
|
if (!isReporterName(argv.reporter)) {
|
|
87
|
-
console.error(
|
|
70
|
+
console.error(
|
|
71
|
+
`svelte-vitals: unknown reporter '${argv.reporter}'. Valid values: console, json, agent, sarif, github.`
|
|
72
|
+
);
|
|
88
73
|
process.exit(2);
|
|
89
74
|
}
|
|
90
75
|
reporter = argv.reporter;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import {
|
|
3
|
-
allRules,
|
|
3
|
+
allRules as allRules2,
|
|
4
4
|
runRules,
|
|
5
5
|
formatConsoleReport,
|
|
6
6
|
formatJsonReport,
|
|
7
7
|
formatAgentReport,
|
|
8
|
+
formatSarifReport,
|
|
9
|
+
formatGithubReport,
|
|
8
10
|
summarize,
|
|
9
11
|
hasFailureAtOrAbove,
|
|
10
12
|
defineConfig,
|
|
@@ -449,7 +451,7 @@ function readPackageVersion() {
|
|
|
449
451
|
// src/reporter-resolve.ts
|
|
450
452
|
var AGENT_ENV_VARS = ["CLAUDECODE", "SVELTE_VITALS_AGENT"];
|
|
451
453
|
function isReporterName(value) {
|
|
452
|
-
return value === "console" || value === "json" || value === "agent";
|
|
454
|
+
return value === "console" || value === "json" || value === "agent" || value === "sarif" || value === "github";
|
|
453
455
|
}
|
|
454
456
|
function isAgentEnv(env = process.env) {
|
|
455
457
|
return AGENT_ENV_VARS.some((key) => {
|
|
@@ -457,16 +459,41 @@ function isAgentEnv(env = process.env) {
|
|
|
457
459
|
return v !== void 0 && v !== "";
|
|
458
460
|
});
|
|
459
461
|
}
|
|
462
|
+
function isGithubActionsEnv(env = process.env) {
|
|
463
|
+
return env.GITHUB_ACTIONS === "true";
|
|
464
|
+
}
|
|
460
465
|
function resolveReporter(explicit, env = process.env) {
|
|
461
466
|
if (explicit) return explicit;
|
|
462
467
|
const fromEnv = env.SVELTE_VITALS_REPORTER;
|
|
463
468
|
if (isReporterName(fromEnv)) return fromEnv;
|
|
464
469
|
if (isAgentEnv(env)) return "agent";
|
|
470
|
+
if (isGithubActionsEnv(env)) return "github";
|
|
465
471
|
return "console";
|
|
466
472
|
}
|
|
467
473
|
function isAutoDetectedAgent(explicit, env = process.env) {
|
|
468
474
|
return !explicit && !isReporterName(env.SVELTE_VITALS_REPORTER) && isAgentEnv(env);
|
|
469
475
|
}
|
|
476
|
+
function isAutoDetectedGithub(explicit, env = process.env) {
|
|
477
|
+
return !explicit && !isReporterName(env.SVELTE_VITALS_REPORTER) && !isAgentEnv(env) && isGithubActionsEnv(env);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// src/rules-config.ts
|
|
481
|
+
import { allRules } from "@svelte-vitals/core";
|
|
482
|
+
var KNOWN_IDS = new Set(allRules.map((r) => r.id));
|
|
483
|
+
function findUnknownRuleIds(ids) {
|
|
484
|
+
return [...new Set(ids.filter((id) => !KNOWN_IDS.has(id)))];
|
|
485
|
+
}
|
|
486
|
+
function knownRuleIds() {
|
|
487
|
+
return [...KNOWN_IDS].sort();
|
|
488
|
+
}
|
|
489
|
+
function buildRulesConfig(allow, ignore) {
|
|
490
|
+
const rules = {};
|
|
491
|
+
if (allow.length > 0) {
|
|
492
|
+
for (const r of allRules) if (!allow.includes(r.id)) rules[r.id] = "off";
|
|
493
|
+
}
|
|
494
|
+
for (const id of ignore) rules[id] = "off";
|
|
495
|
+
return rules;
|
|
496
|
+
}
|
|
470
497
|
|
|
471
498
|
// src/index.ts
|
|
472
499
|
function routeMatcher(glob) {
|
|
@@ -475,10 +502,8 @@ function routeMatcher(glob) {
|
|
|
475
502
|
const re = new RegExp(`^${body}$`);
|
|
476
503
|
return (route) => re.test(route.replace(/^\//, ""));
|
|
477
504
|
}
|
|
478
|
-
async function
|
|
505
|
+
async function analyzeProject(opts = {}) {
|
|
479
506
|
const cwd = opts.cwd ?? process.cwd();
|
|
480
|
-
const log = opts.log ?? ((line) => console.log(line));
|
|
481
|
-
const errorLog = opts.errorLog ?? ((line) => console.error(line));
|
|
482
507
|
const rt = createNodeRuntime();
|
|
483
508
|
const config = defineConfig({
|
|
484
509
|
treatDynamicAs: opts.treatDynamicAs ?? "pass",
|
|
@@ -486,21 +511,37 @@ async function run(opts = {}) {
|
|
|
486
511
|
rules: opts.rules ?? {},
|
|
487
512
|
failOn: opts.failOn ?? "critical"
|
|
488
513
|
});
|
|
514
|
+
await detectProject(rt, cwd);
|
|
515
|
+
const matches = routeMatcher(opts.route);
|
|
516
|
+
const heads = (await sourceHeadProvider.collect(rt, cwd, config)).filter((h) => matches(h.route));
|
|
517
|
+
const project = await collectProjectFacts(rt, cwd);
|
|
518
|
+
const rules = selectRules(allRules2, config);
|
|
519
|
+
const results = applyRuleSeverities(await runRules(rules, { heads, project, config }), config);
|
|
520
|
+
return { results, config, version: readPackageVersion() };
|
|
521
|
+
}
|
|
522
|
+
async function run(opts = {}) {
|
|
523
|
+
const log = opts.log ?? ((line) => console.log(line));
|
|
524
|
+
const errorLog = opts.errorLog ?? ((line) => console.error(line));
|
|
525
|
+
let analysis;
|
|
489
526
|
try {
|
|
490
|
-
await
|
|
527
|
+
analysis = await analyzeProject({
|
|
528
|
+
cwd: opts.cwd ?? process.cwd(),
|
|
529
|
+
metaComponents: opts.metaComponents,
|
|
530
|
+
treatDynamicAs: opts.treatDynamicAs,
|
|
531
|
+
route: opts.route,
|
|
532
|
+
failOn: opts.failOn,
|
|
533
|
+
rules: opts.rules
|
|
534
|
+
});
|
|
491
535
|
} catch (err) {
|
|
492
536
|
if (err instanceof ProjectError) {
|
|
493
537
|
errorLog(err.message);
|
|
494
538
|
return 2;
|
|
495
539
|
}
|
|
496
|
-
|
|
540
|
+
errorLog(`svelte-vitals: ${err instanceof Error ? err.message : String(err)}`);
|
|
541
|
+
return 2;
|
|
497
542
|
}
|
|
498
543
|
try {
|
|
499
|
-
const
|
|
500
|
-
const heads = (await sourceHeadProvider.collect(rt, cwd, config)).filter((h) => matches(h.route));
|
|
501
|
-
const project = await collectProjectFacts(rt, cwd);
|
|
502
|
-
const rules = selectRules(allRules, config);
|
|
503
|
-
const results = applyRuleSeverities(await runRules(rules, { heads, project, config }), config);
|
|
544
|
+
const { results, config, version } = analysis;
|
|
504
545
|
const env = opts.env ?? process.env;
|
|
505
546
|
const reporter = resolveReporter(opts.reporter, env);
|
|
506
547
|
if (reporter === "agent" && isAutoDetectedAgent(opts.reporter, env)) {
|
|
@@ -508,10 +549,20 @@ async function run(opts = {}) {
|
|
|
508
549
|
"svelte-vitals: agent reporter auto-selected (AI-agent env detected); override with --reporter console|json."
|
|
509
550
|
);
|
|
510
551
|
}
|
|
552
|
+
if (reporter === "github" && isAutoDetectedGithub(opts.reporter, env)) {
|
|
553
|
+
errorLog(
|
|
554
|
+
"svelte-vitals: github reporter auto-selected (GitHub Actions detected); override with --reporter console|json|sarif."
|
|
555
|
+
);
|
|
556
|
+
}
|
|
511
557
|
if (reporter === "json") {
|
|
512
|
-
log(formatJsonReport(results, config, { version
|
|
558
|
+
log(formatJsonReport(results, config, { version }));
|
|
513
559
|
} else if (reporter === "agent") {
|
|
514
560
|
log(formatAgentReport(results, config));
|
|
561
|
+
} else if (reporter === "sarif") {
|
|
562
|
+
log(formatSarifReport(results, config, { version }));
|
|
563
|
+
} else if (reporter === "github") {
|
|
564
|
+
const output = formatGithubReport(results, config);
|
|
565
|
+
if (output) log(output);
|
|
515
566
|
} else {
|
|
516
567
|
log(formatConsoleReport(results, config, { byRoute: opts.byRoute ?? false }));
|
|
517
568
|
}
|
|
@@ -524,8 +575,13 @@ async function run(opts = {}) {
|
|
|
524
575
|
}
|
|
525
576
|
|
|
526
577
|
export {
|
|
578
|
+
ProjectError,
|
|
527
579
|
readPackageVersion,
|
|
528
580
|
isReporterName,
|
|
581
|
+
findUnknownRuleIds,
|
|
582
|
+
knownRuleIds,
|
|
583
|
+
buildRulesConfig,
|
|
529
584
|
routeMatcher,
|
|
585
|
+
analyzeProject,
|
|
530
586
|
run
|
|
531
587
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
|
-
import { Severity,
|
|
1
|
+
import { RuleSetting, Severity, Result, Config } from '@svelte-vitals/core';
|
|
2
2
|
|
|
3
|
-
type ReporterName = 'console' | 'json' | 'agent';
|
|
3
|
+
type ReporterName = 'console' | 'json' | 'agent' | 'sarif' | 'github';
|
|
4
|
+
|
|
5
|
+
/** Thrown when the target directory is not a SvelteKit project (CLI maps to exit 2). */
|
|
6
|
+
declare class ProjectError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Rule ids passed to --rules/--ignore that aren't part of the built-in registry. */
|
|
11
|
+
declare function findUnknownRuleIds(ids: string[]): string[];
|
|
12
|
+
/** All built-in rule ids, sorted — for help and error messages. */
|
|
13
|
+
declare function knownRuleIds(): string[];
|
|
14
|
+
/**
|
|
15
|
+
* Build the per-rule config map from an allow-list (--rules) and a deny-list
|
|
16
|
+
* (--ignore). An allow-list disables every rule not listed; deny always wins.
|
|
17
|
+
* Callers should reject unknown ids first (see findUnknownRuleIds) so a typo in
|
|
18
|
+
* --rules can't silently disable every rule.
|
|
19
|
+
*/
|
|
20
|
+
declare function buildRulesConfig(allow: string[], ignore: string[]): Record<string, RuleSetting>;
|
|
4
21
|
|
|
5
22
|
interface RunOptions {
|
|
6
23
|
cwd?: string;
|
|
@@ -18,10 +35,30 @@ interface RunOptions {
|
|
|
18
35
|
env?: NodeJS.ProcessEnv;
|
|
19
36
|
}
|
|
20
37
|
declare function routeMatcher(glob: string | undefined): (route: string) => boolean;
|
|
38
|
+
interface AnalyzeOptions {
|
|
39
|
+
cwd?: string;
|
|
40
|
+
metaComponents?: string[];
|
|
41
|
+
treatDynamicAs?: 'pass' | 'warn' | 'fail';
|
|
42
|
+
/** Restrict analysis to routes whose path matches this glob (matched against the route path without leading slash). */
|
|
43
|
+
route?: string;
|
|
44
|
+
failOn?: Severity;
|
|
45
|
+
rules?: Record<string, RuleSetting>;
|
|
46
|
+
}
|
|
47
|
+
interface AnalyzeResult {
|
|
48
|
+
results: Result[];
|
|
49
|
+
config: Config;
|
|
50
|
+
version: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Run static-mode analysis and return the structured findings + resolved config.
|
|
54
|
+
* Throws ProjectError when `cwd` is not a SvelteKit project. Shared by the CLI's
|
|
55
|
+
* run() and by @svelte-vitals/mcp (issue #24).
|
|
56
|
+
*/
|
|
57
|
+
declare function analyzeProject(opts?: AnalyzeOptions): Promise<AnalyzeResult>;
|
|
21
58
|
/**
|
|
22
59
|
* Run static-mode analysis once and return the process exit code (design §6):
|
|
23
60
|
* 0 = no failing findings, 1 = critical finding present, 2 = execution error.
|
|
24
61
|
*/
|
|
25
62
|
declare function run(opts?: RunOptions): Promise<number>;
|
|
26
63
|
|
|
27
|
-
export { type RunOptions, routeMatcher, run };
|
|
64
|
+
export { type AnalyzeOptions, type AnalyzeResult, ProjectError, type RunOptions, analyzeProject, buildRulesConfig, findUnknownRuleIds, knownRuleIds, routeMatcher, run };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ProjectError,
|
|
3
|
+
analyzeProject,
|
|
4
|
+
buildRulesConfig,
|
|
5
|
+
findUnknownRuleIds,
|
|
6
|
+
knownRuleIds,
|
|
2
7
|
routeMatcher,
|
|
3
8
|
run
|
|
4
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-RI6LBHFR.js";
|
|
5
10
|
export {
|
|
11
|
+
ProjectError,
|
|
12
|
+
analyzeProject,
|
|
13
|
+
buildRulesConfig,
|
|
14
|
+
findUnknownRuleIds,
|
|
15
|
+
knownRuleIds,
|
|
6
16
|
routeMatcher,
|
|
7
17
|
run
|
|
8
18
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-vitals",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"mri": "^1.2.0",
|
|
39
39
|
"svelte": "^5.56.3",
|
|
40
40
|
"tinyglobby": "^0.2.17",
|
|
41
|
-
"@svelte-vitals/core": "0.
|
|
41
|
+
"@svelte-vitals/core": "0.6.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^24.7.0"
|