svelte-vitals 0.32.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 +27 -19
- 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 +8 -6
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";
|
|
@@ -341,12 +341,6 @@ function isConfigTargetId(id) {
|
|
|
341
341
|
return CONFIG_TARGETS.some((t) => t.id === id);
|
|
342
342
|
}
|
|
343
343
|
|
|
344
|
-
// src/ci/action-pin-comment.ts
|
|
345
|
-
function actionPinComment(version) {
|
|
346
|
-
return `action-v${version}`;
|
|
347
|
-
}
|
|
348
|
-
var ACTION_PIN_COMMENT_RE = /#\s*(?:action-v|@svelte-vitals\/action@)(\S+)/;
|
|
349
|
-
|
|
350
344
|
// src/ci/workflow.ts
|
|
351
345
|
var WORKFLOW_PATH = ".github/workflows/svelte-vitals.yml";
|
|
352
346
|
var CHECKOUT_SHA = "9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0";
|
|
@@ -377,7 +371,7 @@ function buildWorkflowYaml(opts) {
|
|
|
377
371
|
` - uses: actions/checkout@${CHECKOUT_SHA} # ${CHECKOUT_VERSION}`,
|
|
378
372
|
" with:",
|
|
379
373
|
" fetch-depth: 0",
|
|
380
|
-
` - uses: oekazuma/svelte-vitals
|
|
374
|
+
` - uses: oekazuma/svelte-vitals-action@${actionSha} # v${actionVersion}`,
|
|
381
375
|
" with:",
|
|
382
376
|
" diff: origin/${{ github.base_ref }}",
|
|
383
377
|
" baseline: origin/${{ github.base_ref }}",
|
|
@@ -414,9 +408,20 @@ var CATEGORY_LABELS = {
|
|
|
414
408
|
function oneLine(text) {
|
|
415
409
|
return text.replace(/\r?\n+/g, " ").trim();
|
|
416
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
|
+
}
|
|
417
421
|
function ruleLine(rule) {
|
|
418
422
|
const fixPart = rule.fix?.description ? ` Fix: ${oneLine(rule.fix.description)}` : "";
|
|
419
|
-
|
|
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)}))`;
|
|
420
425
|
}
|
|
421
426
|
function ruleDigest() {
|
|
422
427
|
return CATEGORY_ORDER.map((category) => {
|
|
@@ -1004,8 +1009,8 @@ function readInstalledViteVersion(io) {
|
|
|
1004
1009
|
}
|
|
1005
1010
|
|
|
1006
1011
|
// src/ci/action-pin.generated.ts
|
|
1007
|
-
var ACTION_SHA = "
|
|
1008
|
-
var ACTION_VERSION = "0.
|
|
1012
|
+
var ACTION_SHA = "67ec0af79398845d01e4371d4953d08f6f6a244f";
|
|
1013
|
+
var ACTION_VERSION = "0.4.0";
|
|
1009
1014
|
|
|
1010
1015
|
// src/install/index.ts
|
|
1011
1016
|
function detectPackageManagerNear(io, appDir) {
|
|
@@ -1577,8 +1582,12 @@ import { join as join5 } from "path";
|
|
|
1577
1582
|
import mri2 from "mri";
|
|
1578
1583
|
|
|
1579
1584
|
// src/ci/upgrade.ts
|
|
1580
|
-
var
|
|
1581
|
-
var
|
|
1585
|
+
var CANONICAL_PATH = "oekazuma/svelte-vitals-action";
|
|
1586
|
+
var ACTION_USES_LINE = /^(?<indent>\s*-\s*uses:\s*(?:&\S+\s+)?)(?<repoPath>oekazuma\/svelte-vitals(?:-action|\/packages\/action))@(?<ref>[^\s#]+)(?<comment>\s*#.*)?$/;
|
|
1587
|
+
var PIN_COMMENT_RE = /#\s*(?:v|action-v|@svelte-vitals\/action@)(\S+)/;
|
|
1588
|
+
function isCanonicalComment(comment, version) {
|
|
1589
|
+
return comment.trim() === `# v${version}`;
|
|
1590
|
+
}
|
|
1582
1591
|
function upgradeActionPin(content, sha, version) {
|
|
1583
1592
|
const lines = content.split("\n");
|
|
1584
1593
|
let replaced = 0;
|
|
@@ -1588,17 +1597,16 @@ function upgradeActionPin(content, sha, version) {
|
|
|
1588
1597
|
const bare = eol ? line.slice(0, -1) : line;
|
|
1589
1598
|
const match = ACTION_USES_LINE.exec(bare);
|
|
1590
1599
|
if (!match || !match.groups) return line;
|
|
1591
|
-
const { indent: indent2, ref } = match.groups;
|
|
1592
|
-
if (indent2 === void 0 || ref === void 0) return line;
|
|
1600
|
+
const { indent: indent2, repoPath, ref } = match.groups;
|
|
1601
|
+
if (indent2 === void 0 || repoPath === void 0 || ref === void 0) return line;
|
|
1593
1602
|
const comment = match.groups.comment ?? "";
|
|
1594
|
-
const commentMatch =
|
|
1595
|
-
|
|
1596
|
-
if (ref === sha && isCanonicalComment) return line;
|
|
1603
|
+
const commentMatch = PIN_COMMENT_RE.exec(comment);
|
|
1604
|
+
if (ref === sha && isCanonicalComment(comment, version) && repoPath === CANONICAL_PATH) return line;
|
|
1597
1605
|
if (from === void 0) {
|
|
1598
1606
|
from = commentMatch ? commentMatch[1] : ref.slice(0, 7);
|
|
1599
1607
|
}
|
|
1600
1608
|
replaced += 1;
|
|
1601
|
-
return `${indent2}${sha} # ${
|
|
1609
|
+
return `${indent2}${CANONICAL_PATH}@${sha} # v${version}${eol}`;
|
|
1602
1610
|
});
|
|
1603
1611
|
if (replaced === 0) {
|
|
1604
1612
|
const hasAnyReference = lines.some((line) => ACTION_USES_LINE.test(line.endsWith("\r") ? line.slice(0, -1) : line));
|
|
@@ -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,17 +44,19 @@
|
|
|
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",
|
|
53
53
|
"@types/node": "^24.13.3"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
|
-
"build": "
|
|
57
|
-
"typecheck": "
|
|
58
|
-
"test": "
|
|
56
|
+
"build": "tsup",
|
|
57
|
+
"typecheck": "tsc --noEmit",
|
|
58
|
+
"test": "vitest run",
|
|
59
|
+
"gen:rules-index": "pnpm --filter @svelte-vitals/core build && node scripts/gen-rules-index.mjs",
|
|
60
|
+
"update-action-pin": "node scripts/gen-action-pin.mjs"
|
|
59
61
|
}
|
|
60
62
|
}
|