svelte-vitals 0.33.0 → 0.34.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 +13 -2
- package/dist/{chunk-CWCO6A5B.js → chunk-WSPRFLPP.js} +55 -20
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -1
- package/package.json +4 -3
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-WSPRFLPP.js";
|
|
13
13
|
|
|
14
14
|
// src/bin.ts
|
|
15
15
|
import mri3 from "mri";
|
|
@@ -408,9 +408,20 @@ var CATEGORY_LABELS = {
|
|
|
408
408
|
function oneLine(text) {
|
|
409
409
|
return text.replace(/\r?\n+/g, " ").trim();
|
|
410
410
|
}
|
|
411
|
+
function isEmptyDefault(spec) {
|
|
412
|
+
if (spec.kind === "string-list") return spec.default.length === 0;
|
|
413
|
+
if (spec.kind === "string-map") return Object.keys(spec.default).length === 0;
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
function isInertUntilConfigured(rule) {
|
|
417
|
+
if (!rule.options) return false;
|
|
418
|
+
const specs = Object.values(rule.options);
|
|
419
|
+
return specs.length > 0 && specs.every(isEmptyDefault);
|
|
420
|
+
}
|
|
411
421
|
function ruleLine(rule) {
|
|
412
422
|
const fixPart = rule.fix?.description ? ` Fix: ${oneLine(rule.fix.description)}` : "";
|
|
413
|
-
|
|
423
|
+
const inertPart = isInertUntilConfigured(rule) ? " (inert until configured)" : "";
|
|
424
|
+
return `- **${rule.id} \u2014 ${oneLine(rule.title)}** (${rule.severity}): ${oneLine(rule.rationale)}${fixPart}${inertPart} ([docs](${docsUrlFor(rule.id)}))`;
|
|
414
425
|
}
|
|
415
426
|
function ruleDigest() {
|
|
416
427
|
return CATEGORY_ORDER.map((category) => {
|
|
@@ -54,7 +54,10 @@ import { defaultConfig } from "@svelte-vitals/core";
|
|
|
54
54
|
import {
|
|
55
55
|
ROBOTS_SOURCE_PATHS,
|
|
56
56
|
SITEMAP_SOURCE_PATHS,
|
|
57
|
-
|
|
57
|
+
SVELTE_CONFIG_FILES,
|
|
58
|
+
VITE_CONFIG_FILES,
|
|
59
|
+
findMinifyDisabled,
|
|
60
|
+
resolveKitPathsBase
|
|
58
61
|
} from "@svelte-vitals/core";
|
|
59
62
|
var ProjectError = class extends Error {
|
|
60
63
|
constructor(message) {
|
|
@@ -143,14 +146,6 @@ async function robotsRefsSitemap(rt, cwd) {
|
|
|
143
146
|
return void 0;
|
|
144
147
|
}
|
|
145
148
|
}
|
|
146
|
-
var VITE_CONFIG_FILES = [
|
|
147
|
-
"vite.config.js",
|
|
148
|
-
"vite.config.mjs",
|
|
149
|
-
"vite.config.ts",
|
|
150
|
-
"vite.config.cjs",
|
|
151
|
-
"vite.config.mts",
|
|
152
|
-
"vite.config.cts"
|
|
153
|
-
];
|
|
154
149
|
async function detectViteMinifyDisabled(rt, cwd) {
|
|
155
150
|
const exists = await Promise.all(VITE_CONFIG_FILES.map((f) => rt.exists(rt.join(cwd, f))));
|
|
156
151
|
const file = VITE_CONFIG_FILES[exists.indexOf(true)];
|
|
@@ -162,12 +157,32 @@ async function detectViteMinifyDisabled(rt, cwd) {
|
|
|
162
157
|
return void 0;
|
|
163
158
|
}
|
|
164
159
|
}
|
|
160
|
+
async function readFirstConfig(rt, cwd, files) {
|
|
161
|
+
for (const file of files) {
|
|
162
|
+
const path = rt.join(cwd, file);
|
|
163
|
+
if (!await rt.exists(path)) continue;
|
|
164
|
+
try {
|
|
165
|
+
return { file, source: await rt.readFile(path) };
|
|
166
|
+
} catch {
|
|
167
|
+
return void 0;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return void 0;
|
|
171
|
+
}
|
|
172
|
+
async function detectKitPathsBase(rt, cwd) {
|
|
173
|
+
const [viteConfig, svelteConfig] = await Promise.all([
|
|
174
|
+
readFirstConfig(rt, cwd, VITE_CONFIG_FILES),
|
|
175
|
+
readFirstConfig(rt, cwd, SVELTE_CONFIG_FILES)
|
|
176
|
+
]);
|
|
177
|
+
return resolveKitPathsBase(viteConfig, svelteConfig);
|
|
178
|
+
}
|
|
165
179
|
async function collectProjectFacts(rt, cwd) {
|
|
166
|
-
const [hasRobotsTxt, hasSitemap, htmlLang, viteMinifyDisabled] = await Promise.all([
|
|
180
|
+
const [hasRobotsTxt, hasSitemap, htmlLang, viteMinifyDisabled, kitPathsBase] = await Promise.all([
|
|
167
181
|
existsAny(rt, cwd, ROBOTS_SOURCE_PATHS),
|
|
168
182
|
existsAny(rt, cwd, SITEMAP_SOURCE_PATHS),
|
|
169
183
|
detectAppHtmlLang(rt, cwd),
|
|
170
|
-
detectViteMinifyDisabled(rt, cwd)
|
|
184
|
+
detectViteMinifyDisabled(rt, cwd),
|
|
185
|
+
detectKitPathsBase(rt, cwd)
|
|
171
186
|
]);
|
|
172
187
|
const robotsReferencesSitemap = await robotsRefsSitemap(rt, cwd);
|
|
173
188
|
return {
|
|
@@ -175,7 +190,8 @@ async function collectProjectFacts(rt, cwd) {
|
|
|
175
190
|
hasSitemap,
|
|
176
191
|
htmlLang,
|
|
177
192
|
...robotsReferencesSitemap !== void 0 ? { robotsReferencesSitemap } : {},
|
|
178
|
-
...viteMinifyDisabled ? { viteMinifyDisabled } : {}
|
|
193
|
+
...viteMinifyDisabled ? { viteMinifyDisabled } : {},
|
|
194
|
+
...kitPathsBase ? { kitPathsBase } : {}
|
|
179
195
|
};
|
|
180
196
|
}
|
|
181
197
|
|
|
@@ -1167,16 +1183,27 @@ async function playMascotGreeting(opts) {
|
|
|
1167
1183
|
import { existsSync as existsSync2 } from "fs";
|
|
1168
1184
|
import { join as join5 } from "path";
|
|
1169
1185
|
import { pathToFileURL } from "url";
|
|
1186
|
+
import {
|
|
1187
|
+
CATEGORIES,
|
|
1188
|
+
defaultConfig as defaultConfig2,
|
|
1189
|
+
resolveRuleOptions,
|
|
1190
|
+
shouldSkipRangeCheck,
|
|
1191
|
+
validateRuleSetting
|
|
1192
|
+
} from "@svelte-vitals/core";
|
|
1170
1193
|
|
|
1171
1194
|
// src/rules-config.ts
|
|
1172
1195
|
import { allRules } from "@svelte-vitals/core";
|
|
1173
1196
|
var KNOWN_IDS = new Set(allRules.map((r) => r.id));
|
|
1197
|
+
var RULE_BY_ID = new Map(allRules.map((r) => [r.id, r]));
|
|
1174
1198
|
function findUnknownRuleIds(ids) {
|
|
1175
1199
|
return [...new Set(ids.filter((id) => !KNOWN_IDS.has(id)))];
|
|
1176
1200
|
}
|
|
1177
1201
|
function knownRuleIds() {
|
|
1178
1202
|
return [...KNOWN_IDS].sort();
|
|
1179
1203
|
}
|
|
1204
|
+
function ruleOptionsSpec(id) {
|
|
1205
|
+
return RULE_BY_ID.get(id)?.options;
|
|
1206
|
+
}
|
|
1180
1207
|
function buildRulesConfig(allow, ignore) {
|
|
1181
1208
|
const rules = {};
|
|
1182
1209
|
if (allow.length > 0) {
|
|
@@ -1188,17 +1215,23 @@ function buildRulesConfig(allow, ignore) {
|
|
|
1188
1215
|
|
|
1189
1216
|
// src/config-file.ts
|
|
1190
1217
|
var CONFIG_FILENAMES = ["svelte-vitals.config.mjs", "svelte-vitals.config.js", "svelte-vitals.config.ts"];
|
|
1191
|
-
var CATEGORIES = ["seo", "performance", "correctness", "security", "architecture"];
|
|
1192
1218
|
var TREAT_DYNAMIC_AS_VALUES = ["pass", "warn", "fail"];
|
|
1193
1219
|
var FAIL_ON_VALUES = ["critical", "warning", "info"];
|
|
1194
1220
|
var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["treatDynamicAs", "metaComponents", "rules", "failOn", "weights", "overrides"]);
|
|
1195
|
-
var RULE_SETTING_VALUES = ["off", "critical", "warning", "info"];
|
|
1196
1221
|
function isPlainObject2(value) {
|
|
1197
1222
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1198
1223
|
}
|
|
1199
1224
|
function isMissingExtensionLoaderError(err) {
|
|
1200
1225
|
return err instanceof Error && ("code" in err && err.code === "ERR_UNKNOWN_FILE_EXTENSION" || /Unknown file extension/.test(err.message));
|
|
1201
1226
|
}
|
|
1227
|
+
function validateSetting(path, where, key, setting, allowOptions, baseline, skipRangeCheck) {
|
|
1228
|
+
const errors = validateRuleSetting(`${where}.${key}`, key, setting, ruleOptionsSpec(key), {
|
|
1229
|
+
allowOptions,
|
|
1230
|
+
...baseline !== void 0 ? { baseline } : {},
|
|
1231
|
+
...skipRangeCheck !== void 0 ? { skipRangeCheck } : {}
|
|
1232
|
+
});
|
|
1233
|
+
if (errors.length > 0) throw new Error(`${path}: ${errors.join(" ")}`);
|
|
1234
|
+
}
|
|
1202
1235
|
function validateConfigFile(raw, path) {
|
|
1203
1236
|
const warnings = [];
|
|
1204
1237
|
const config = {};
|
|
@@ -1241,6 +1274,7 @@ function validateConfigFile(raw, path) {
|
|
|
1241
1274
|
`${path}: unknown rule id(s) in rules: ${unknown.join(", ")}. Known rule ids: ${knownRuleIds().join(", ")}`
|
|
1242
1275
|
);
|
|
1243
1276
|
}
|
|
1277
|
+
for (const [key, setting] of Object.entries(rules)) validateSetting(path, "rules", key, setting, true);
|
|
1244
1278
|
config.rules = rules;
|
|
1245
1279
|
}
|
|
1246
1280
|
if (raw.overrides !== void 0) {
|
|
@@ -1250,7 +1284,8 @@ function validateConfigFile(raw, path) {
|
|
|
1250
1284
|
const isGlob = (v) => typeof v === "string" && v.length > 0;
|
|
1251
1285
|
const isGlobs = (v) => isGlob(v) || Array.isArray(v) && v.length > 0 && v.every(isGlob);
|
|
1252
1286
|
const overrides = [];
|
|
1253
|
-
raw.overrides
|
|
1287
|
+
const rawOverrides = raw.overrides;
|
|
1288
|
+
rawOverrides.forEach((entry, i) => {
|
|
1254
1289
|
if (!isPlainObject2(entry)) {
|
|
1255
1290
|
throw new Error(`${path}: overrides[${i}] must be an object with 'route' and/or 'files', and 'rules'.`);
|
|
1256
1291
|
}
|
|
@@ -1281,11 +1316,10 @@ function validateConfigFile(raw, path) {
|
|
|
1281
1316
|
);
|
|
1282
1317
|
}
|
|
1283
1318
|
for (const [key, setting] of Object.entries(entry.rules)) {
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
}
|
|
1319
|
+
const isCategory = CATEGORIES.includes(key);
|
|
1320
|
+
const baseline = isCategory ? void 0 : resolveRuleOptions(key, ruleOptionsSpec(key), { ...defaultConfig2, rules: config.rules ?? {} });
|
|
1321
|
+
const skipRangeCheck = shouldSkipRangeCheck(rawOverrides, i, key, setting);
|
|
1322
|
+
validateSetting(path, `overrides[${i}].rules`, key, setting, !isCategory, baseline, skipRangeCheck);
|
|
1289
1323
|
}
|
|
1290
1324
|
overrides.push({
|
|
1291
1325
|
...entry.route !== void 0 ? { route: entry.route } : {},
|
|
@@ -1690,6 +1724,7 @@ export {
|
|
|
1690
1724
|
isReporterName,
|
|
1691
1725
|
findUnknownRuleIds,
|
|
1692
1726
|
knownRuleIds,
|
|
1727
|
+
ruleOptionsSpec,
|
|
1693
1728
|
buildRulesConfig,
|
|
1694
1729
|
CONFIG_FILENAMES,
|
|
1695
1730
|
loadConfigFile,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HeadTag, RuleSetting, Config, Severity, Category, Result } from '@svelte-vitals/core';
|
|
1
|
+
import { HeadTag, RuleSetting, RuleOptionsSpec, Config, Severity, Category, Result } from '@svelte-vitals/core';
|
|
2
2
|
export { defineConfig } from '@svelte-vitals/core';
|
|
3
3
|
import { AST } from 'svelte/compiler';
|
|
4
4
|
|
|
@@ -60,6 +60,8 @@ declare class ProjectError extends Error {
|
|
|
60
60
|
declare function findUnknownRuleIds(ids: string[]): string[];
|
|
61
61
|
/** All built-in rule ids, sorted — for help and error messages. */
|
|
62
62
|
declare function knownRuleIds(): string[];
|
|
63
|
+
/** The options a rule declares, or undefined when it takes none. */
|
|
64
|
+
declare function ruleOptionsSpec(id: string): RuleOptionsSpec | undefined;
|
|
63
65
|
/**
|
|
64
66
|
* Build the per-rule config map from an allow-list (--rules) and a deny-list
|
|
65
67
|
* (--ignore). An allow-list disables every rule not listed; deny always wins.
|
|
@@ -243,4 +245,4 @@ declare function applyScope(results: Result[], opts: ApplyScopeOptions): Promise
|
|
|
243
245
|
*/
|
|
244
246
|
declare function run(opts?: RunOptions): Promise<number>;
|
|
245
247
|
|
|
246
|
-
export { type AnalyzeOptions, type AnalyzeResult, type ApplyScopeOptions, type LoadedConfigFile, type ParseCache, ProjectError, type RunOptions, analyzeProject, applyScope, buildRulesConfig, findUnknownRuleIds, knownRuleIds, loadConfigFile, routeMatcher, run, spinnerEnabled };
|
|
248
|
+
export { type AnalyzeOptions, type AnalyzeResult, type ApplyScopeOptions, type LoadedConfigFile, type ParseCache, ProjectError, type RunOptions, analyzeProject, applyScope, buildRulesConfig, findUnknownRuleIds, knownRuleIds, loadConfigFile, routeMatcher, ruleOptionsSpec, run, spinnerEnabled };
|
package/dist/index.js
CHANGED
|
@@ -8,9 +8,10 @@ import {
|
|
|
8
8
|
knownRuleIds,
|
|
9
9
|
loadConfigFile,
|
|
10
10
|
routeMatcher,
|
|
11
|
+
ruleOptionsSpec,
|
|
11
12
|
run,
|
|
12
13
|
spinnerEnabled
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-WSPRFLPP.js";
|
|
14
15
|
export {
|
|
15
16
|
ProjectError,
|
|
16
17
|
analyzeProject,
|
|
@@ -21,6 +22,7 @@ export {
|
|
|
21
22
|
knownRuleIds,
|
|
22
23
|
loadConfigFile,
|
|
23
24
|
routeMatcher,
|
|
25
|
+
ruleOptionsSpec,
|
|
24
26
|
run,
|
|
25
27
|
spinnerEnabled
|
|
26
28
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-vitals",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.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",
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
"magicast": "^0.5.3",
|
|
45
45
|
"mri": "^1.2.0",
|
|
46
46
|
"smol-toml": "^1.7.0",
|
|
47
|
-
"svelte": "^5.56.
|
|
47
|
+
"svelte": "^5.56.8",
|
|
48
48
|
"tinyglobby": "^0.2.17",
|
|
49
|
-
"@svelte-vitals/core": "0.
|
|
49
|
+
"@svelte-vitals/core": "0.30.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/estree": "^1.0.9",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"build": "tsup",
|
|
57
57
|
"typecheck": "tsc --noEmit",
|
|
58
58
|
"test": "vitest run",
|
|
59
|
+
"gen:rules-index": "pnpm --filter @svelte-vitals/core build && node scripts/gen-rules-index.mjs",
|
|
59
60
|
"update-action-pin": "node scripts/gen-action-pin.mjs"
|
|
60
61
|
}
|
|
61
62
|
}
|