svelte-vitals 0.5.2 → 0.6.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
@@ -6,7 +6,7 @@ import {
6
6
  knownRuleIds,
7
7
  readPackageVersion,
8
8
  run
9
- } from "./chunk-LQPB2WAL.js";
9
+ } from "./chunk-LWN65ZOR.js";
10
10
 
11
11
  // src/bin.ts
12
12
  import mri from "mri";
@@ -164,6 +164,13 @@ function attrValue(attributes, name) {
164
164
  if (v && v.type === "ExpressionTag") return "dynamic";
165
165
  return "absent";
166
166
  }
167
+ function lineOf(source, offset) {
168
+ if (typeof offset !== "number" || offset < 0) return 0;
169
+ let line = 1;
170
+ const end = Math.min(offset, source.length);
171
+ for (let i = 0; i < end; i++) if (source[i] === "\n") line++;
172
+ return line;
173
+ }
167
174
  function findAttr(attributes, name) {
168
175
  if (!Array.isArray(attributes)) return void 0;
169
176
  return attributes.find((a) => a?.type === "Attribute" && a.name === name);
@@ -231,16 +238,39 @@ function collectComponents(node, acc) {
231
238
  if (key in node) collectComponents(node[key], acc);
232
239
  }
233
240
  }
241
+ function collectImages(node, source, acc) {
242
+ if (Array.isArray(node)) {
243
+ for (const child of node) collectImages(child, source, acc);
244
+ return;
245
+ }
246
+ if (!node || typeof node !== "object") return;
247
+ if (node.type === "RegularElement" && node.name === "img") {
248
+ const attrs = node.attributes ?? [];
249
+ const hasSpread = attrs.some((a) => a?.type === "SpreadAttribute");
250
+ acc.push({
251
+ hasWidth: hasSpread || Boolean(findAttr(attrs, "width")),
252
+ hasHeight: hasSpread || Boolean(findAttr(attrs, "height")),
253
+ hasLoading: hasSpread || Boolean(findAttr(attrs, "loading")),
254
+ line: lineOf(source, node.start)
255
+ });
256
+ }
257
+ for (const key of CHILD_NODE_KEYS) {
258
+ if (key in node) collectImages(node[key], source, acc);
259
+ }
260
+ }
234
261
  function parseFile(source, filename) {
235
262
  const ast = parse(source, { modern: true, filename });
236
263
  const heads = [];
237
264
  collectSvelteHeads(ast.fragment ?? ast, heads);
238
265
  const components = [];
239
266
  collectComponents(ast.fragment ?? ast, components);
267
+ const images = [];
268
+ collectImages(ast.fragment ?? ast, source, images);
240
269
  return {
241
270
  headTags: heads.flatMap(tagsFromHead),
242
271
  components,
243
- imports: collectImports(ast)
272
+ imports: collectImports(ast),
273
+ images
244
274
  };
245
275
  }
246
276
 
@@ -403,9 +433,13 @@ async function resolveRoute(rt, cwd, pageRel, config) {
403
433
  const composed = /* @__PURE__ */ new Map();
404
434
  let broadOwn = false;
405
435
  let broadInherited = false;
436
+ const images = [];
406
437
  for (const { rel, isPage } of files) {
407
438
  const source = await rt.readFile(rt.join(cwd, rel));
408
439
  const parsed = parseFile(source, rel);
440
+ for (const img of parsed.images) {
441
+ images.push({ ...img, file: rel });
442
+ }
409
443
  const resolved = await resolveFileTags(rt, cwd, rel, parsed, config, MAX_DEPTH, /* @__PURE__ */ new Set([rel]));
410
444
  for (const tag of resolved.tags) {
411
445
  composed.set(tagKey(tag), { ...tag, presence: isPage ? "own" : "inherited", file: rel });
@@ -422,20 +456,20 @@ async function resolveRoute(rt, cwd, pageRel, config) {
422
456
  if (!composed.has(key)) composed.set(key, { ...tag, presence });
423
457
  }
424
458
  }
459
+ const route = deriveRoute(pageRel);
425
460
  return {
426
- route: deriveRoute(pageRel),
427
- source: "static",
428
- tags: [...composed.values()],
429
- file: pageRel
461
+ head: { route, source: "static", tags: [...composed.values()], file: pageRel },
462
+ images: { route, images }
463
+ };
464
+ }
465
+ async function collectRoutes(rt, cwd, config = defaultConfig) {
466
+ const pages = await enumerateRoutePages(rt, cwd);
467
+ const facts = await Promise.all(pages.map((page) => resolveRoute(rt, cwd, page, config)));
468
+ return {
469
+ heads: facts.map((f) => f.head),
470
+ images: facts.map((f) => f.images)
430
471
  };
431
472
  }
432
- var sourceHeadProvider = {
433
- mode: "static",
434
- async collect(rt, cwd, config = defaultConfig) {
435
- const pages = await enumerateRoutePages(rt, cwd);
436
- return Promise.all(pages.map((page) => resolveRoute(rt, cwd, page, config)));
437
- }
438
- };
439
473
 
440
474
  // src/version.ts
441
475
  import { readFileSync } from "fs";
@@ -513,10 +547,12 @@ async function analyzeProject(opts = {}) {
513
547
  });
514
548
  await detectProject(rt, cwd);
515
549
  const matches = routeMatcher(opts.route);
516
- const heads = (await sourceHeadProvider.collect(rt, cwd, config)).filter((h) => matches(h.route));
550
+ const collected = await collectRoutes(rt, cwd, config);
551
+ const heads = collected.heads.filter((h) => matches(h.route));
552
+ const images = collected.images.filter((i) => matches(i.route));
517
553
  const project = await collectProjectFacts(rt, cwd);
518
554
  const rules = selectRules(allRules2, config);
519
- const results = applyRuleSeverities(await runRules(rules, { heads, project, config }), config);
555
+ const results = applyRuleSeverities(await runRules(rules, { heads, images, project, config }), config);
520
556
  return { results, config, version: readPackageVersion() };
521
557
  }
522
558
  async function run(opts = {}) {
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  knownRuleIds,
7
7
  routeMatcher,
8
8
  run
9
- } from "./chunk-LQPB2WAL.js";
9
+ } from "./chunk-LWN65ZOR.js";
10
10
  export {
11
11
  ProjectError,
12
12
  analyzeProject,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-vitals",
3
- "version": "0.5.2",
3
+ "version": "0.6.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",
@@ -42,7 +42,7 @@
42
42
  "mri": "^1.2.0",
43
43
  "svelte": "^5.56.3",
44
44
  "tinyglobby": "^0.2.17",
45
- "@svelte-vitals/core": "0.7.0"
45
+ "@svelte-vitals/core": "0.8.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/node": "^24.7.0"