svelte-vitals 0.28.0 → 0.30.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 +16 -8
- package/dist/{chunk-O5VMXV2Q.js → chunk-QBXO46PU.js} +92 -12
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
readCoreVersion,
|
|
10
10
|
readPackageVersion,
|
|
11
11
|
run
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-QBXO46PU.js";
|
|
13
13
|
|
|
14
14
|
// src/bin.ts
|
|
15
15
|
import mri3 from "mri";
|
|
@@ -998,8 +998,8 @@ function readInstalledViteVersion(io) {
|
|
|
998
998
|
}
|
|
999
999
|
|
|
1000
1000
|
// src/ci/action-pin.generated.ts
|
|
1001
|
-
var ACTION_SHA = "
|
|
1002
|
-
var ACTION_VERSION = "0.3.
|
|
1001
|
+
var ACTION_SHA = "81d49a11b71a16ea1294212d43520a0137b4bd5e";
|
|
1002
|
+
var ACTION_VERSION = "0.3.5";
|
|
1003
1003
|
|
|
1004
1004
|
// src/install/index.ts
|
|
1005
1005
|
function detectPackageManagerNear(io, appDir) {
|
|
@@ -1195,9 +1195,15 @@ async function runInstall(flags, io, prompts, version = "0.0.0") {
|
|
|
1195
1195
|
io.errorLog("svelte-vitals: no valid clients or targets selected.");
|
|
1196
1196
|
return 2;
|
|
1197
1197
|
}
|
|
1198
|
-
const
|
|
1198
|
+
const isSvelteKitApp = (dir) => {
|
|
1199
1199
|
try {
|
|
1200
|
-
|
|
1200
|
+
if (io.readFile(join4(dir, "svelte.config.js")) !== void 0 || io.readFile(join4(dir, "svelte.config.ts")) !== void 0) {
|
|
1201
|
+
return true;
|
|
1202
|
+
}
|
|
1203
|
+
const pkgRaw = io.readFile(join4(dir, "package.json"));
|
|
1204
|
+
if (pkgRaw === void 0) return false;
|
|
1205
|
+
const pkg = JSON.parse(pkgRaw);
|
|
1206
|
+
return Boolean(pkg.dependencies?.["@sveltejs/kit"] ?? pkg.devDependencies?.["@sveltejs/kit"]);
|
|
1201
1207
|
} catch {
|
|
1202
1208
|
return false;
|
|
1203
1209
|
}
|
|
@@ -1207,12 +1213,14 @@ async function runInstall(flags, io, prompts, version = "0.0.0") {
|
|
|
1207
1213
|
if (needsApp) {
|
|
1208
1214
|
if (flags.app) {
|
|
1209
1215
|
const candidate = join4(io.cwd, flags.app);
|
|
1210
|
-
if (!
|
|
1211
|
-
io.errorLog(
|
|
1216
|
+
if (!isSvelteKitApp(candidate)) {
|
|
1217
|
+
io.errorLog(
|
|
1218
|
+
`svelte-vitals: --app '${flags.app}' is not a SvelteKit app (no svelte.config.{js,ts} or @sveltejs/kit dependency there).`
|
|
1219
|
+
);
|
|
1212
1220
|
return 2;
|
|
1213
1221
|
}
|
|
1214
1222
|
appDir = candidate;
|
|
1215
|
-
} else if (!
|
|
1223
|
+
} else if (!isSvelteKitApp(io.cwd)) {
|
|
1216
1224
|
const apps = await (io.discoverApps ?? discoverApps)(io.cwd);
|
|
1217
1225
|
if (apps.length === 1) {
|
|
1218
1226
|
io.errorLog(`svelte-vitals: detected SvelteKit app at ${apps[0]}; targeting it for the Vite/config targets.`);
|
|
@@ -16,7 +16,9 @@ import {
|
|
|
16
16
|
computeHealth,
|
|
17
17
|
defineConfig,
|
|
18
18
|
selectRules,
|
|
19
|
-
applyRuleSeverities
|
|
19
|
+
applyRuleSeverities,
|
|
20
|
+
applyOverrides,
|
|
21
|
+
collectKitModuleFacts
|
|
20
22
|
} from "@svelte-vitals/core";
|
|
21
23
|
|
|
22
24
|
// src/runtime/node.ts
|
|
@@ -652,16 +654,36 @@ import { collectComponentFacts } from "@svelte-vitals/core";
|
|
|
652
654
|
|
|
653
655
|
// src/discover-apps.ts
|
|
654
656
|
import { existsSync } from "fs";
|
|
657
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
655
658
|
import { join as join2, dirname } from "path";
|
|
656
659
|
import { glob } from "tinyglobby";
|
|
660
|
+
var GLOB_OPTS = {
|
|
661
|
+
dot: false,
|
|
662
|
+
deep: 4,
|
|
663
|
+
ignore: ["**/node_modules/**", "**/.svelte-kit/**", "**/build/**", "**/dist/**", "**/.git/**"]
|
|
664
|
+
};
|
|
665
|
+
async function hasKitDependency(pkgJsonPath) {
|
|
666
|
+
try {
|
|
667
|
+
const pkg = JSON.parse(await readFile2(pkgJsonPath, "utf8"));
|
|
668
|
+
return Boolean(pkg.dependencies?.["@sveltejs/kit"] ?? pkg.devDependencies?.["@sveltejs/kit"]);
|
|
669
|
+
} catch {
|
|
670
|
+
return false;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
657
673
|
async function discoverApps(cwd) {
|
|
658
|
-
const configs = await
|
|
659
|
-
cwd,
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
const
|
|
674
|
+
const [configs, pkgJsons] = await Promise.all([
|
|
675
|
+
glob("**/svelte.config.{js,ts}", { cwd, ...GLOB_OPTS }),
|
|
676
|
+
glob("**/package.json", { cwd, ...GLOB_OPTS })
|
|
677
|
+
]);
|
|
678
|
+
const configDirs = configs.map(dirname);
|
|
679
|
+
const kitDepDirs = [];
|
|
680
|
+
for (const pkgJson of pkgJsons) {
|
|
681
|
+
const dir = dirname(pkgJson);
|
|
682
|
+
if (dir !== "." && await hasKitDependency(join2(cwd, pkgJson))) {
|
|
683
|
+
kitDepDirs.push(dir);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
const dirs = [.../* @__PURE__ */ new Set([...configDirs, ...kitDepDirs])].filter(
|
|
665
687
|
(d) => d !== "." && existsSync(join2(cwd, d, "src", "routes"))
|
|
666
688
|
);
|
|
667
689
|
return dirs.sort();
|
|
@@ -1111,7 +1133,8 @@ var CONFIG_FILENAMES = ["svelte-vitals.config.mjs", "svelte-vitals.config.js", "
|
|
|
1111
1133
|
var CATEGORIES = ["seo", "performance", "correctness", "security", "architecture"];
|
|
1112
1134
|
var TREAT_DYNAMIC_AS_VALUES = ["pass", "warn", "fail"];
|
|
1113
1135
|
var FAIL_ON_VALUES = ["critical", "warning", "info"];
|
|
1114
|
-
var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["treatDynamicAs", "metaComponents", "rules", "failOn", "weights"]);
|
|
1136
|
+
var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["treatDynamicAs", "metaComponents", "rules", "failOn", "weights", "overrides"]);
|
|
1137
|
+
var RULE_SETTING_VALUES = ["off", "critical", "warning", "info"];
|
|
1115
1138
|
function isPlainObject2(value) {
|
|
1116
1139
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1117
1140
|
}
|
|
@@ -1162,6 +1185,58 @@ function validateConfigFile(raw, path) {
|
|
|
1162
1185
|
}
|
|
1163
1186
|
config.rules = rules;
|
|
1164
1187
|
}
|
|
1188
|
+
if (raw.overrides !== void 0) {
|
|
1189
|
+
if (!Array.isArray(raw.overrides)) {
|
|
1190
|
+
throw new Error(`${path}: overrides must be an array of { route/files, rules } entries.`);
|
|
1191
|
+
}
|
|
1192
|
+
const isGlob = (v) => typeof v === "string" && v.length > 0;
|
|
1193
|
+
const isGlobs = (v) => isGlob(v) || Array.isArray(v) && v.length > 0 && v.every(isGlob);
|
|
1194
|
+
const overrides = [];
|
|
1195
|
+
raw.overrides.forEach((entry, i) => {
|
|
1196
|
+
if (!isPlainObject2(entry)) {
|
|
1197
|
+
throw new Error(`${path}: overrides[${i}] must be an object with 'route' and/or 'files', and 'rules'.`);
|
|
1198
|
+
}
|
|
1199
|
+
if (entry.route !== void 0 && !isGlobs(entry.route)) {
|
|
1200
|
+
throw new Error(
|
|
1201
|
+
`${path}: overrides[${i}].route must be a non-empty string or a non-empty array of non-empty strings.`
|
|
1202
|
+
);
|
|
1203
|
+
}
|
|
1204
|
+
if (entry.files !== void 0 && !isGlobs(entry.files)) {
|
|
1205
|
+
throw new Error(
|
|
1206
|
+
`${path}: overrides[${i}].files must be a non-empty string or a non-empty array of non-empty strings.`
|
|
1207
|
+
);
|
|
1208
|
+
}
|
|
1209
|
+
if (entry.route === void 0 && entry.files === void 0) {
|
|
1210
|
+
throw new Error(`${path}: overrides[${i}] must set 'route' and/or 'files' to scope the override.`);
|
|
1211
|
+
}
|
|
1212
|
+
if (!isPlainObject2(entry.rules)) {
|
|
1213
|
+
throw new Error(`${path}: overrides[${i}].rules must be an object of rule-id/category \u2192 setting.`);
|
|
1214
|
+
}
|
|
1215
|
+
if (Object.keys(entry.rules).length === 0) {
|
|
1216
|
+
throw new Error(`${path}: overrides[${i}].rules must contain at least one rule id or category.`);
|
|
1217
|
+
}
|
|
1218
|
+
const nonCategoryKeys = Object.keys(entry.rules).filter((k) => !CATEGORIES.includes(k));
|
|
1219
|
+
const unknown = findUnknownRuleIds(nonCategoryKeys);
|
|
1220
|
+
if (unknown.length > 0) {
|
|
1221
|
+
throw new Error(
|
|
1222
|
+
`${path}: unknown rule id(s) or categories in overrides[${i}].rules: ${unknown.join(", ")}. Known categories: ${CATEGORIES.join(", ")}. Known rule ids: ${knownRuleIds().join(", ")}`
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
for (const [key, setting] of Object.entries(entry.rules)) {
|
|
1226
|
+
if (!RULE_SETTING_VALUES.includes(setting)) {
|
|
1227
|
+
throw new Error(
|
|
1228
|
+
`${path}: overrides[${i}].rules.${key}: invalid setting '${String(setting)}'; expected ${RULE_SETTING_VALUES.join("|")}.`
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
overrides.push({
|
|
1233
|
+
...entry.route !== void 0 ? { route: entry.route } : {},
|
|
1234
|
+
...entry.files !== void 0 ? { files: entry.files } : {},
|
|
1235
|
+
rules: entry.rules
|
|
1236
|
+
});
|
|
1237
|
+
});
|
|
1238
|
+
config.overrides = overrides;
|
|
1239
|
+
}
|
|
1165
1240
|
if (raw.weights !== void 0) {
|
|
1166
1241
|
if (!isPlainObject2(raw.weights)) {
|
|
1167
1242
|
throw new Error(`${path}: weights must be an object of category \u2192 number.`);
|
|
@@ -1282,7 +1357,8 @@ async function analyzeProject(opts = {}) {
|
|
|
1282
1357
|
metaComponents: opts.metaComponents ?? file?.metaComponents ?? [],
|
|
1283
1358
|
rules: opts.rules ?? file?.rules ?? {},
|
|
1284
1359
|
failOn: opts.failOn ?? file?.failOn ?? "critical",
|
|
1285
|
-
...weights !== void 0 ? { weights } : {}
|
|
1360
|
+
...weights !== void 0 ? { weights } : {},
|
|
1361
|
+
...file?.overrides !== void 0 ? { overrides: file.overrides } : {}
|
|
1286
1362
|
});
|
|
1287
1363
|
await detectProject(rt, cwd);
|
|
1288
1364
|
const matches = routeMatcher(opts.route);
|
|
@@ -1292,10 +1368,14 @@ async function analyzeProject(opts = {}) {
|
|
|
1292
1368
|
const headings = collected.headings.filter((h) => matches(h.route));
|
|
1293
1369
|
const project = await collectProjectFacts(rt, cwd);
|
|
1294
1370
|
const components = opts.route ? [] : await collectComponentFacts(rt, cwd);
|
|
1371
|
+
const kitModules = opts.route ? [] : await collectKitModuleFacts(rt, cwd);
|
|
1295
1372
|
const selected = selectRules(allRules2, config);
|
|
1296
1373
|
const rules = opts.categories ? selected.filter((r) => opts.categories.includes(r.category)) : selected;
|
|
1297
|
-
const results =
|
|
1298
|
-
|
|
1374
|
+
const results = applyOverrides(
|
|
1375
|
+
applyRuleSeverities(
|
|
1376
|
+
await runRules(rules, { heads, images, headings, components, project, config, kitModules }),
|
|
1377
|
+
config
|
|
1378
|
+
),
|
|
1299
1379
|
config
|
|
1300
1380
|
);
|
|
1301
1381
|
return { results, config, version: readPackageVersion(), warnings };
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-vitals",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.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",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"smol-toml": "^1.7.0",
|
|
47
47
|
"svelte": "^5.56.4",
|
|
48
48
|
"tinyglobby": "^0.2.17",
|
|
49
|
-
"@svelte-vitals/core": "0.
|
|
49
|
+
"@svelte-vitals/core": "0.27.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/node": "^24.13.3"
|