@svelte-vitals/core 0.8.0 → 0.9.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/index.d.ts CHANGED
@@ -66,6 +66,8 @@ interface Config {
66
66
  rules: Record<string, RuleSetting>;
67
67
  /** Minimum severity that fails the run / CI (design §6). */
68
68
  failOn: Severity;
69
+ /** Per-category weights for the combined Health score (default: equal, 1 each) (#10). */
70
+ weights?: Partial<Record<Category, number>>;
69
71
  }
70
72
  declare const defaultConfig: Config;
71
73
  /** Merge user config over defaults. Identity helper for config files (design §6). */
@@ -320,6 +322,15 @@ interface ScoreOptions {
320
322
  declare function computeScore(results: Result[], config: Config, options?: ScoreOptions): ScoreResult;
321
323
  /** Compute an independent score per category present in `results` (issue #10). */
322
324
  declare function scoresByCategory(results: Result[], config: Config): Partial<Record<Category, ScoreResult>>;
325
+ interface HealthResult {
326
+ /** Weighted overall score across present categories (0–100). */
327
+ health: number;
328
+ categories: Partial<Record<Category, ScoreResult>>;
329
+ /** Effective weight used per present category. */
330
+ weights: Partial<Record<Category, number>>;
331
+ }
332
+ /** Combined weighted Health score over the categories present in `results` (#10). */
333
+ declare function computeHealth(results: Result[], config: Config): HealthResult;
323
334
 
324
335
  declare function issueOf(result: Result): {
325
336
  fix?: Fix | undefined;
@@ -338,7 +349,7 @@ type JsonIssue = ReturnType<typeof issueOf> & {
338
349
  interface JsonReport {
339
350
  version: string;
340
351
  score: number;
341
- scoreModel: ScoreModel;
352
+ weights: Partial<Record<Category, number>>;
342
353
  categories: Record<string, {
343
354
  score: number;
344
355
  scoreModel: ScoreModel;
@@ -379,4 +390,4 @@ declare function selectRules(rules: Rule[], config: Config): Rule[];
379
390
  /** Apply per-rule severity overrides to results (design §6). */
380
391
  declare function applyRuleSeverities(results: Result[], config: Config): Result[];
381
392
 
382
- export { type Category, type Classification, type Config, type ConsoleReportOptions, type Detection, type Fix, type HeadProvider, type HeadTag, type ImageInfo, type JsonReport, type Presence, type Project, ROBOTS_SOURCE_PATHS, type ResolvedHead, type ResolvedImages, type Result, type Rule, type RuleContext, type RuleInfo, type RuleSetting, type Runtime, SITEMAP_SOURCE_PATHS, type Scope, type ScoreModel, type ScoreOptions, type ScoreResult, type Severity, type Summary, type TreatDynamicAs, type Value, allRules, applyRuleSeverities, buildJsonReport, classify, computeScore, defaultConfig, defaultProject, defineConfig, docsUrlFor, effectiveSeverity, explainRule, formatAgentReport, formatConsoleReport, formatGithubReport, formatJsonReport, formatSarifReport, hasFailureAtOrAbove, headTagRule, imageRule, isPenalized, perf001ImageDimensions, perf002ImageLoading, runRules, scoresByCategory, selectRules, seo001Title, seo002Description, seo003Canonical, seo004OgImage, seo005OgTitle, seo006Robots, seo007Sitemap, seo008JsonLd, seo009HtmlLang, summarize };
393
+ export { type Category, type Classification, type Config, type ConsoleReportOptions, type Detection, type Fix, type HeadProvider, type HeadTag, type HealthResult, type ImageInfo, type JsonReport, type Presence, type Project, ROBOTS_SOURCE_PATHS, type ResolvedHead, type ResolvedImages, type Result, type Rule, type RuleContext, type RuleInfo, type RuleSetting, type Runtime, SITEMAP_SOURCE_PATHS, type Scope, type ScoreModel, type ScoreOptions, type ScoreResult, type Severity, type Summary, type TreatDynamicAs, type Value, allRules, applyRuleSeverities, buildJsonReport, classify, computeHealth, computeScore, defaultConfig, defaultProject, defineConfig, docsUrlFor, effectiveSeverity, explainRule, formatAgentReport, formatConsoleReport, formatGithubReport, formatJsonReport, formatSarifReport, hasFailureAtOrAbove, headTagRule, imageRule, isPenalized, perf001ImageDimensions, perf002ImageLoading, runRules, scoresByCategory, selectRules, seo001Title, seo002Description, seo003Canonical, seo004OgImage, seo005OgTitle, seo006Robots, seo007Sitemap, seo008JsonLd, seo009HtmlLang, summarize };
package/dist/index.js CHANGED
@@ -490,6 +490,27 @@ function scoresByCategory(results, config) {
490
490
  for (const [cat, rs] of byCat) out[cat] = computeScore(rs, config);
491
491
  return out;
492
492
  }
493
+ function computeHealth(results, config) {
494
+ const categories = scoresByCategory(results, config);
495
+ const weights = {};
496
+ let weighted = 0;
497
+ let total = 0;
498
+ for (const cat of Object.keys(categories)) {
499
+ const w = config.weights?.[cat] ?? 1;
500
+ if (!Number.isFinite(w) || w < 0) {
501
+ throw new RangeError(`invalid weight for '${cat}'; expected a finite number >= 0.`);
502
+ }
503
+ weights[cat] = w;
504
+ weighted += categories[cat].score * w;
505
+ total += w;
506
+ }
507
+ if (Object.keys(weights).length === 0) return { health: 100, categories, weights };
508
+ if (total === 0) {
509
+ throw new RangeError("Health weights sum to 0; at least one present category must have a positive weight.");
510
+ }
511
+ const health = Math.round(weighted / total);
512
+ return { health, categories, weights };
513
+ }
493
514
 
494
515
  // src/reporter/console.ts
495
516
  var RULE = "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
@@ -531,9 +552,9 @@ function byRouteTree(results, config) {
531
552
  }
532
553
  function formatConsoleReport(results, config, options = {}) {
533
554
  const summary = summarize(results, config);
534
- const byCat = scoresByCategory(results, config);
555
+ const { health, categories: byCat } = computeHealth(results, config);
535
556
  const present2 = CATEGORY_ORDER.filter((c) => byCat[c] !== void 0);
536
- const header = [`Svelte Vitals \xB7 ${options.mode ?? "static mode"}`, ""];
557
+ const header = [`Svelte Vitals \xB7 ${options.mode ?? "static mode"}`, "", `Health: ${health}/100`];
537
558
  for (const c of present2) {
538
559
  header.push(scoreLine(CATEGORY_LABEL[c] ?? c, byCat[c]));
539
560
  }
@@ -580,10 +601,8 @@ function issueOf(result) {
580
601
  };
581
602
  }
582
603
  function buildJsonReport(results, config, meta) {
583
- const seoResults = results.filter((r) => (r.category ?? "seo") === "seo");
584
- const { score, scoreModel } = computeScore(seoResults, config);
604
+ const { health, categories: byCat, weights } = computeHealth(results, config);
585
605
  const summary = summarize(results, config);
586
- const byCat = scoresByCategory(results, config);
587
606
  const categories = Object.fromEntries(
588
607
  Object.entries(byCat).map(([cat, sr]) => [cat, { score: sr.score, scoreModel: sr.scoreModel }])
589
608
  );
@@ -599,7 +618,7 @@ function buildJsonReport(results, config, meta) {
599
618
  issues: rs.filter((r) => isPenalized(r.detection, config.treatDynamicAs)).map((r) => ({ ...issueOf(r), severity: effectiveSeverity(r, config) }))
600
619
  }));
601
620
  const siteIssues = results.filter((r) => r.route === void 0 && isPenalized(r.detection, config.treatDynamicAs)).map((r) => ({ ...issueOf(r), severity: effectiveSeverity(r, config) }));
602
- return { version: meta.version, score, scoreModel, categories, summary, routes, siteIssues };
621
+ return { version: meta.version, score: health, weights, categories, summary, routes, siteIssues };
603
622
  }
604
623
  function formatJsonReport(results, config, meta) {
605
624
  return JSON.stringify(buildJsonReport(results, config, meta), null, 2);
@@ -612,7 +631,8 @@ function mdTags(text) {
612
631
  }
613
632
  function formatAgentReport(results, config) {
614
633
  const failing = results.filter((r) => classify(r, config) === "fail");
615
- const lines = ["# svelte-vitals \u2014 fixes", ""];
634
+ const { health } = computeHealth(results, config);
635
+ const lines = ["# svelte-vitals \u2014 fixes", "", `Health: ${health}/100`, ""];
616
636
  if (failing.length === 0) {
617
637
  lines.push("No issues to fix.", "");
618
638
  return lines.join("\n").replace(/\n+$/, "\n");
@@ -771,6 +791,7 @@ export {
771
791
  applyRuleSeverities,
772
792
  buildJsonReport,
773
793
  classify,
794
+ computeHealth,
774
795
  computeScore,
775
796
  defaultConfig,
776
797
  defaultProject,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svelte-vitals/core",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Shared, runtime-agnostic core for svelte-vitals (types, rule engine, scorer, reporter).",
5
5
  "type": "module",
6
6
  "license": "MIT",