svelte-vitals 0.20.0 → 0.22.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
@@ -4,9 +4,10 @@ import {
4
4
  findUnknownRuleIds,
5
5
  isReporterName,
6
6
  knownRuleIds,
7
+ readCoreVersion,
7
8
  readPackageVersion,
8
9
  run
9
- } from "./chunk-AAM2A7D7.js";
10
+ } from "./chunk-KSJZLF5U.js";
10
11
 
11
12
  // src/bin.ts
12
13
  import mri3 from "mri";
@@ -496,6 +497,15 @@ function installCommand(pm) {
496
497
  const action = pm === "npm" ? "install" : "add";
497
498
  return { command: pm, args: [action, "-D", "@svelte-vitals/vite"] };
498
499
  }
500
+ function readInstalledViteVersion(io) {
501
+ const raw = io.readFile(join2(io.cwd, "node_modules/@svelte-vitals/vite/package.json"));
502
+ if (raw === void 0) return void 0;
503
+ try {
504
+ return JSON.parse(raw).version;
505
+ } catch {
506
+ return void 0;
507
+ }
508
+ }
499
509
 
500
510
  // src/install/index.ts
501
511
  function planForClient(client, scope, io, force) {
@@ -669,6 +679,11 @@ ${indent(r.snippet ?? "")}`);
669
679
  io.errorLog(
670
680
  `svelte-vitals: failed to install @svelte-vitals/vite (${command} ${args.join(" ")} exited ${code}). Install it manually.`
671
681
  );
682
+ } else {
683
+ const installedVersion = readInstalledViteVersion(io);
684
+ io.log(
685
+ installedVersion ? `svelte-vitals: installed @svelte-vitals/vite@${installedVersion} \u2014 compare against \`svelte-vitals --version\`'s core number if findings ever seem out of sync.` : "svelte-vitals: installed @svelte-vitals/vite (could not read the installed version from node_modules)."
686
+ );
672
687
  }
673
688
  }
674
689
  if (hadFailure) return 2;
@@ -834,9 +849,9 @@ function planWorkflowWrite(existing, force) {
834
849
  return { status: "updated" };
835
850
  }
836
851
  function buildWorkflowYaml(opts) {
837
- const v = opts.version;
852
+ const { actionSha, actionVersion } = opts;
838
853
  return [
839
- `# Generated by \`svelte-vitals ci install\` (svelte-vitals ${v}).`,
854
+ "# Generated by `svelte-vitals ci install`.",
840
855
  "# Re-run with --force to regenerate.",
841
856
  "name: svelte-vitals",
842
857
  "",
@@ -854,60 +869,27 @@ function buildWorkflowYaml(opts) {
854
869
  " - uses: actions/checkout@v4",
855
870
  " with:",
856
871
  " fetch-depth: 0",
857
- " - uses: actions/setup-node@v4",
872
+ ` - uses: oekazuma/svelte-vitals/packages/action@${actionSha} # @svelte-vitals/action@${actionVersion}`,
858
873
  " with:",
859
- " node-version: 24",
860
- " - name: Scan (inline annotations + gate)",
861
- " id: scan",
862
- " continue-on-error: true",
863
- " run: >",
864
- ` npx -y svelte-vitals@${v} .`,
865
- " --diff origin/${{ github.base_ref }}",
866
- " --baseline origin/${{ github.base_ref }}",
867
- " --reporter github",
868
- " - name: Markdown summary",
869
- " run: >",
870
- ` npx -y svelte-vitals@${v} .`,
871
- " --diff origin/${{ github.base_ref }}",
872
- " --baseline origin/${{ github.base_ref }}",
873
- " --reporter md > svelte-vitals-report.md || true",
874
- " - name: Job summary",
875
- ' run: cat svelte-vitals-report.md >> "$GITHUB_STEP_SUMMARY"',
876
- " - name: PR comment (sticky)",
877
- " if: github.event.pull_request.head.repo.full_name == github.repository",
878
- " continue-on-error: true",
879
- " uses: actions/github-script@v7",
880
- " with:",
881
- " script: |",
882
- " const fs = require('fs');",
883
- " const marker = '<!-- svelte-vitals-report -->';",
884
- " const body = marker + '\\n' + fs.readFileSync('svelte-vitals-report.md', 'utf8');",
885
- " const { data: comments } = await github.rest.issues.listComments({",
886
- " ...context.repo, issue_number: context.issue.number, per_page: 100",
887
- " });",
888
- " const mine = comments.find(c => c.body && c.body.startsWith(marker));",
889
- " if (mine) {",
890
- " await github.rest.issues.updateComment({ ...context.repo, comment_id: mine.id, body });",
891
- " } else {",
892
- " await github.rest.issues.createComment({ ...context.repo, issue_number: context.issue.number, body });",
893
- " }",
894
- " - name: Gate",
895
- " if: steps.scan.outcome == 'failure'",
896
- " run: |",
897
- ' echo "svelte-vitals found blocking issues (see annotations above)."',
898
- " exit 1",
874
+ " diff: origin/${{ github.base_ref }}",
875
+ " baseline: origin/${{ github.base_ref }}",
899
876
  ""
900
877
  ].join("\n");
901
878
  }
902
879
 
880
+ // src/ci/action-pin.generated.ts
881
+ var ACTION_SHA = "86e84073bddea99530d2d6831378a68836443ee4";
882
+ var ACTION_VERSION = "0.2.0";
883
+
903
884
  // src/ci/cli.ts
904
885
  var CI_HELP = `svelte-vitals ci \u2014 scaffold CI integration
905
886
 
906
887
  Usage:
907
888
  svelte-vitals ci install [options]
908
889
 
909
- Adds a GitHub Actions workflow (${WORKFLOW_PATH}) that scans pull requests, posts inline
910
- annotations + a job summary, and maintains a sticky PR comment with the findings.
890
+ Adds a GitHub Actions workflow (${WORKFLOW_PATH}) that calls the \`@svelte-vitals/action\`
891
+ GitHub Action on pull requests: inline annotations, a job summary, and a sticky PR
892
+ comment with the findings.
911
893
 
912
894
  Options:
913
895
  --force Overwrite an existing workflow file
@@ -943,9 +925,8 @@ async function runCiCli(args, io = realIO()) {
943
925
  if (plan.status === "exists") {
944
926
  io.log(`= already installed (${WORKFLOW_PATH}) \u2014 use --force to regenerate.`);
945
927
  } else {
946
- const version = readPackageVersion();
947
928
  try {
948
- io.writeFile(path, buildWorkflowYaml({ version }));
929
+ io.writeFile(path, buildWorkflowYaml({ actionSha: ACTION_SHA, actionVersion: ACTION_VERSION }));
949
930
  io.log(`\u2713 ${plan.status} ${WORKFLOW_PATH}`);
950
931
  } catch (err) {
951
932
  io.errorLog(
@@ -1038,7 +1019,7 @@ async function main() {
1038
1019
  process.exit(0);
1039
1020
  }
1040
1021
  if (argv.version) {
1041
- console.log(VERSION);
1022
+ console.log(`${VERSION} (core ${readCoreVersion()})`);
1042
1023
  process.exit(0);
1043
1024
  }
1044
1025
  const { options, warnings, errors } = resolveArgs(argv);
@@ -678,6 +678,15 @@ function readPackageVersion() {
678
678
  return "0.0.0";
679
679
  }
680
680
  }
681
+ function readCoreVersion() {
682
+ try {
683
+ const entry = import.meta.resolve("@svelte-vitals/core");
684
+ const pkg = JSON.parse(readFileSync(new URL("../package.json", entry), "utf8"));
685
+ return pkg.version ?? "0.0.0";
686
+ } catch {
687
+ return "0.0.0";
688
+ }
689
+ }
681
690
 
682
691
  // src/reporter-resolve.ts
683
692
  var AGENT_ENV_VARS = ["CLAUDECODE", "SVELTE_VITALS_AGENT"];
@@ -985,6 +994,38 @@ async function analyzeProject(opts = {}) {
985
994
  );
986
995
  return { results, config, version: readPackageVersion(), warnings };
987
996
  }
997
+ async function applyScope(results, opts) {
998
+ const errorLog = opts.errorLog ?? ((line) => console.error(line));
999
+ let scoped = results;
1000
+ if (opts.staged || opts.diffBase !== void 0) {
1001
+ const changed = opts.staged ? getChangedFiles(opts.cwd, { staged: true }) : getChangedFiles(opts.cwd, { base: opts.diffBase });
1002
+ if (changed === void 0) {
1003
+ errorLog(
1004
+ "svelte-vitals: could not determine changed files (not a git repo, git unavailable, or bad ref); analyzing all."
1005
+ );
1006
+ } else {
1007
+ scoped = filterToChangedFiles(scoped, changed);
1008
+ }
1009
+ }
1010
+ if (opts.baseline !== void 0) {
1011
+ const checkout = checkoutBaseline(opts.cwd, opts.baseline);
1012
+ if (checkout === void 0) {
1013
+ errorLog(
1014
+ `svelte-vitals: could not analyze baseline '${opts.baseline}' (not a git repo, git unavailable, or bad ref); reporting all findings.`
1015
+ );
1016
+ } else {
1017
+ try {
1018
+ const base = await analyzeProject({ ...opts.analyzeOpts, cwd: checkout.analyzeCwd });
1019
+ scoped = filterToNewFindings(scoped, base.results);
1020
+ } catch {
1021
+ errorLog(`svelte-vitals: baseline analysis of '${opts.baseline}' failed; reporting all findings.`);
1022
+ } finally {
1023
+ checkout.cleanup();
1024
+ }
1025
+ }
1026
+ }
1027
+ return scoped;
1028
+ }
988
1029
  async function run(opts = {}) {
989
1030
  const log = opts.log ?? ((line) => console.log(line));
990
1031
  const errorLog = opts.errorLog ?? ((line) => console.error(line));
@@ -1077,43 +1118,22 @@ async function run(opts = {}) {
1077
1118
  for (const w of analysis.warnings) errorLog(`svelte-vitals: ${w}`);
1078
1119
  try {
1079
1120
  const { config, version } = analysis;
1080
- let results = analysis.results;
1081
- if (opts.staged || opts.diffBase !== void 0) {
1082
- const changed = opts.staged ? getChangedFiles(cwd, { staged: true }) : getChangedFiles(cwd, { base: opts.diffBase });
1083
- if (changed === void 0) {
1084
- errorLog(
1085
- "svelte-vitals: could not determine changed files (not a git repo, git unavailable, or bad ref); analyzing all."
1086
- );
1087
- } else {
1088
- results = filterToChangedFiles(results, changed);
1089
- }
1090
- }
1091
- if (opts.baseline !== void 0) {
1092
- const checkout = checkoutBaseline(cwd, opts.baseline);
1093
- if (checkout === void 0) {
1094
- errorLog(
1095
- `svelte-vitals: could not analyze baseline '${opts.baseline}' (not a git repo, git unavailable, or bad ref); reporting all findings.`
1096
- );
1097
- } else {
1098
- try {
1099
- const base = await analyzeProject({
1100
- cwd: checkout.analyzeCwd,
1101
- metaComponents: opts.metaComponents,
1102
- treatDynamicAs: opts.treatDynamicAs,
1103
- route: opts.route,
1104
- failOn: opts.failOn,
1105
- rules: opts.rules,
1106
- weights: opts.weights,
1107
- categories: opts.categories
1108
- });
1109
- results = filterToNewFindings(results, base.results);
1110
- } catch {
1111
- errorLog(`svelte-vitals: baseline analysis of '${opts.baseline}' failed; reporting all findings.`);
1112
- } finally {
1113
- checkout.cleanup();
1114
- }
1121
+ const results = await applyScope(analysis.results, {
1122
+ cwd,
1123
+ staged: opts.staged,
1124
+ diffBase: opts.diffBase,
1125
+ baseline: opts.baseline,
1126
+ errorLog,
1127
+ analyzeOpts: {
1128
+ metaComponents: opts.metaComponents,
1129
+ treatDynamicAs: opts.treatDynamicAs,
1130
+ route: opts.route,
1131
+ failOn: opts.failOn,
1132
+ rules: opts.rules,
1133
+ weights: opts.weights,
1134
+ categories: opts.categories
1115
1135
  }
1116
- }
1136
+ });
1117
1137
  if (opts.score) {
1118
1138
  log(String(computeHealth(results, config).health));
1119
1139
  } else {
@@ -1137,7 +1157,7 @@ async function run(opts = {}) {
1137
1157
  const output = formatGithubReport(results, config);
1138
1158
  if (output) log(output);
1139
1159
  } else if (reporter === "html") {
1140
- const html = formatHtmlReport(results, config, { version });
1160
+ const html = formatHtmlReport(results, config, { version, coreVersion: readCoreVersion() });
1141
1161
  if (opts.outFile === "-") {
1142
1162
  log(html);
1143
1163
  } else {
@@ -1174,6 +1194,7 @@ async function run(opts = {}) {
1174
1194
  export {
1175
1195
  ProjectError,
1176
1196
  readPackageVersion,
1197
+ readCoreVersion,
1177
1198
  isReporterName,
1178
1199
  findUnknownRuleIds,
1179
1200
  knownRuleIds,
@@ -1182,6 +1203,7 @@ export {
1182
1203
  spinnerEnabled,
1183
1204
  routeMatcher,
1184
1205
  analyzeProject,
1206
+ applyScope,
1185
1207
  run,
1186
1208
  defineConfig2 as defineConfig
1187
1209
  };
package/dist/index.d.ts CHANGED
@@ -137,10 +137,25 @@ interface AnalyzeResult {
137
137
  * 2026-07-05-config-file-design.md §3).
138
138
  */
139
139
  declare function analyzeProject(opts?: AnalyzeOptions): Promise<AnalyzeResult>;
140
+ interface ApplyScopeOptions {
141
+ cwd: string;
142
+ staged?: boolean;
143
+ diffBase?: string;
144
+ baseline?: string;
145
+ errorLog?: (line: string) => void;
146
+ analyzeOpts?: AnalyzeOptions;
147
+ }
148
+ /**
149
+ * Narrow `results` to what a PR gate cares about: `--staged`/`--diff` restrict to
150
+ * changed files, `--baseline` drops findings that already existed at that ref. Shared
151
+ * by `run()` and `@svelte-vitals/action` (issue #154) so the git-diff/baseline
152
+ * orchestration lives in exactly one place.
153
+ */
154
+ declare function applyScope(results: Result[], opts: ApplyScopeOptions): Promise<Result[]>;
140
155
  /**
141
156
  * Run static-mode analysis once and return the process exit code (design §6):
142
157
  * 0 = no failing findings, 1 = critical finding present, 2 = execution error.
143
158
  */
144
159
  declare function run(opts?: RunOptions): Promise<number>;
145
160
 
146
- export { type AnalyzeOptions, type AnalyzeResult, type LoadedConfigFile, ProjectError, type RunOptions, analyzeProject, buildRulesConfig, findUnknownRuleIds, knownRuleIds, loadConfigFile, routeMatcher, run, spinnerEnabled };
161
+ export { type AnalyzeOptions, type AnalyzeResult, type ApplyScopeOptions, type LoadedConfigFile, ProjectError, type RunOptions, analyzeProject, applyScope, buildRulesConfig, findUnknownRuleIds, knownRuleIds, loadConfigFile, routeMatcher, run, spinnerEnabled };
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  ProjectError,
3
3
  analyzeProject,
4
+ applyScope,
4
5
  buildRulesConfig,
5
6
  defineConfig,
6
7
  findUnknownRuleIds,
@@ -9,10 +10,11 @@ import {
9
10
  routeMatcher,
10
11
  run,
11
12
  spinnerEnabled
12
- } from "./chunk-AAM2A7D7.js";
13
+ } from "./chunk-KSJZLF5U.js";
13
14
  export {
14
15
  ProjectError,
15
16
  analyzeProject,
17
+ applyScope,
16
18
  buildRulesConfig,
17
19
  defineConfig,
18
20
  findUnknownRuleIds,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-vitals",
3
- "version": "0.20.0",
3
+ "version": "0.22.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",
@@ -45,14 +45,14 @@
45
45
  "smol-toml": "^1.7.0",
46
46
  "svelte": "^5.56.4",
47
47
  "tinyglobby": "^0.2.17",
48
- "@svelte-vitals/core": "0.21.0"
48
+ "@svelte-vitals/core": "0.22.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/node": "^24.13.2"
52
52
  },
53
53
  "scripts": {
54
- "build": "tsup",
55
- "typecheck": "tsc --noEmit",
56
- "test": "vitest run"
54
+ "build": "node scripts/gen-action-pin.mjs && tsup",
55
+ "typecheck": "node scripts/gen-action-pin.mjs && tsc --noEmit",
56
+ "test": "node scripts/gen-action-pin.mjs && vitest run"
57
57
  }
58
58
  }