@svelte-vitals/core 0.35.0 → 0.36.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
@@ -1269,6 +1269,24 @@ declare const architectureDirectoryNaming: Rule;
1269
1269
  */
1270
1270
  declare const architectureReservedDirectoryNames: Rule;
1271
1271
 
1272
+ /**
1273
+ * architecture/reserved-name-placement — a reserved directory name may appear only in the places
1274
+ * declared for it (design 2026-08-06). L3: inert until a placement is declared.
1275
+ *
1276
+ * The sibling `architecture/reserved-directory-names` says "at this position, only these names"; it
1277
+ * cannot say "this name, only at these positions", which for a name appearing in several kinds of
1278
+ * place is what a convention actually states.
1279
+ *
1280
+ * All three maps match the same directory — the reserved-name directory's parent — and differ only in
1281
+ * what else they require of it: nothing, that it is a capitalised unit, that it is a unit of either
1282
+ * case. A name's permitted positions are the UNION of its entries across the three, because a real
1283
+ * convention permits one name under a unit, under a grouping and under a route directory at once.
1284
+ *
1285
+ * There are no pass results, for the reason the sibling records: `computeScore` seeds every distinct
1286
+ * `route` at 100 and averages, and a directory has no pre-existing score key.
1287
+ */
1288
+ declare const architectureReservedNamePlacement: Rule;
1289
+
1272
1290
  declare const architectureRouteComponentImport: Rule;
1273
1291
 
1274
1292
  declare const architectureDocLinkTarget: Rule;
@@ -1636,4 +1654,4 @@ declare function escapeHtml(s: string): string;
1636
1654
  */
1637
1655
  declare function safeHref(url: string): string | null;
1638
1656
 
1639
- export { APP_SCRIPT, APP_STYLE, type AppSnapshot, BAND_COLOR, CATEGORIES, CHILD_NODE_KEYS, type Category, type Classification, type CompiledOverride, type ComponentFacts, type Config, type ConsoleReportOptions, type Detection, type EachBlockFact, type EffectFact, type Fix, type HeadProvider, type HeadTag, type HeadingInfo, type HealthResult, type ImageInfo, type JsonReport, type KitAlias, type KitModuleFacts, type OrphanEffectFact, type Palette, type Presence, type Project, ROBOTS_SOURCE_PATHS, type RawKitAliases, type ResolvedHead, type ResolvedHeadings, type ResolvedImages, type Result, type RouteBadge, type Rule, type RuleContext, type RuleEvidence, type RuleInfo, type RuleOptionInfo, type RuleOptionSpec, type RuleOptions, type RuleOptionsSpec, type RuleOverride, type RuleSetting, type RuleSettingObject, type Runtime, SITEMAP_SOURCE_PATHS, SVELTE_CONFIG_FILES, type Scope, type ScoreModel, type ScoreOptions, type ScoreResult, type Severity, type SourceSpan, type Summary, type SuppressionDirective, type TreatDynamicAs, VITE_CONFIG_FILES, type Value, type ViteKitConfigResult, allRules, applyOverrides, applyRuleSeverities, architectureComponentSize, architectureDirectoryNaming, architectureDocLinkTarget, architecturePrivateScopeImport, architecturePropCount, architectureReservedDirectoryNames, architectureRouteComponentImport, architectureUnitEntryFile, attrText, attrTextOf, attrValue, attrValueOf, buildHtmlDocument, buildJsonReport, classify, collectComponentFacts, collectKitModuleFacts, collectSourceFiles, compileOverrides, computeHealth, computeScore, correctnessBasePathNavigation, correctnessCheckableBindValue, correctnessEachIndexKey, correctnessEachKey, correctnessEffectAsDerived, correctnessEffectAsOnMount, correctnessInstanceBrowserGlobal, correctnessNonreactiveBuiltinState, correctnessOrphanEffect, correctnessOrphanLifecycle, correctnessPropMutation, correctnessServerBrowserGlobal, correctnessStalePropDerivation, correctnessUnmutatedState, defaultConfig, defaultProject, defineConfig, docsUrlFor, effectiveSeverity, emptyComponentFacts, emptyKitModuleFacts, escapeHtml, explainRule, findAttr, findKitAliasesInSvelteConfig, findKitPathsBaseInSvelteConfig, findKitPathsBaseInViteConfig, findMinifyDisabled, formatAgentReport, formatConsoleReport, formatGithubReport, formatHtmlReport, formatJsonReport, formatMarkdownReport, formatSarifReport, hasFailureAtOrAbove, headTagRule, imageRule, intOption, isMentionedAnywhere, isPenalized, lineOf, linkRule, listOption, mapOption, noColorPalette, overrideMatches, parseComponentFacts, parseKitModuleFacts, performanceFontPreloadCrossorigin, performanceHeavyImport, performanceImageDimensions, performanceImageLoadingHint, performanceLcpImage, performanceLoadWaterfall, performanceMinifyDisabled, performanceNamespaceImport, performancePreconnect, performancePreloadMissingAs, performanceRenderBlockingScript, performanceResponsiveImage, performanceSequentialAwaits, performanceStateRaw, renderAppShell, resolveKitAliases, resolveKitPathsBase, resolveRuleOptions, resolveRunesModuleSpecifier, runRules, safeHref, scoreBand, scoreColor, scoresByCategory, securityHandlerStateWrite, securityJavascriptUrl, securityRawHtml, securityServerModuleState, securitySharedStateImport, selectRules, seoCanonicalUrl, seoCharset, seoDescriptionLength, seoDescriptionPresence, seoDuplicateDescription, seoDuplicateTitle, seoHeadingLevelSkip, seoHreflang, seoHtmlLang, seoImageAlt, seoIndexability, seoJsonLd, seoJsonLdDateFormat, seoJsonLdDeprecatedType, seoJsonLdPlaceholder, seoJsonLdRelativeUrl, seoJsonLdRequiredProps, seoJsonLdValidity, seoOgDescription, seoOgImage, seoOgTitle, seoOgUrl, seoRobotsTxt, seoSingleH1, seoSitemapInRobots, seoSitemapXml, seoSsrDisabled, seoTitleLength, seoTitlePresence, seoTwitterCard, seoViewport, settingOptions, settingSeverity, shouldSkipRangeCheck, summarize, textFromNodes, validateRuleOptions, validateRuleSetting, valueFromNodes };
1657
+ export { APP_SCRIPT, APP_STYLE, type AppSnapshot, BAND_COLOR, CATEGORIES, CHILD_NODE_KEYS, type Category, type Classification, type CompiledOverride, type ComponentFacts, type Config, type ConsoleReportOptions, type Detection, type EachBlockFact, type EffectFact, type Fix, type HeadProvider, type HeadTag, type HeadingInfo, type HealthResult, type ImageInfo, type JsonReport, type KitAlias, type KitModuleFacts, type OrphanEffectFact, type Palette, type Presence, type Project, ROBOTS_SOURCE_PATHS, type RawKitAliases, type ResolvedHead, type ResolvedHeadings, type ResolvedImages, type Result, type RouteBadge, type Rule, type RuleContext, type RuleEvidence, type RuleInfo, type RuleOptionInfo, type RuleOptionSpec, type RuleOptions, type RuleOptionsSpec, type RuleOverride, type RuleSetting, type RuleSettingObject, type Runtime, SITEMAP_SOURCE_PATHS, SVELTE_CONFIG_FILES, type Scope, type ScoreModel, type ScoreOptions, type ScoreResult, type Severity, type SourceSpan, type Summary, type SuppressionDirective, type TreatDynamicAs, VITE_CONFIG_FILES, type Value, type ViteKitConfigResult, allRules, applyOverrides, applyRuleSeverities, architectureComponentSize, architectureDirectoryNaming, architectureDocLinkTarget, architecturePrivateScopeImport, architecturePropCount, architectureReservedDirectoryNames, architectureReservedNamePlacement, architectureRouteComponentImport, architectureUnitEntryFile, attrText, attrTextOf, attrValue, attrValueOf, buildHtmlDocument, buildJsonReport, classify, collectComponentFacts, collectKitModuleFacts, collectSourceFiles, compileOverrides, computeHealth, computeScore, correctnessBasePathNavigation, correctnessCheckableBindValue, correctnessEachIndexKey, correctnessEachKey, correctnessEffectAsDerived, correctnessEffectAsOnMount, correctnessInstanceBrowserGlobal, correctnessNonreactiveBuiltinState, correctnessOrphanEffect, correctnessOrphanLifecycle, correctnessPropMutation, correctnessServerBrowserGlobal, correctnessStalePropDerivation, correctnessUnmutatedState, defaultConfig, defaultProject, defineConfig, docsUrlFor, effectiveSeverity, emptyComponentFacts, emptyKitModuleFacts, escapeHtml, explainRule, findAttr, findKitAliasesInSvelteConfig, findKitPathsBaseInSvelteConfig, findKitPathsBaseInViteConfig, findMinifyDisabled, formatAgentReport, formatConsoleReport, formatGithubReport, formatHtmlReport, formatJsonReport, formatMarkdownReport, formatSarifReport, hasFailureAtOrAbove, headTagRule, imageRule, intOption, isMentionedAnywhere, isPenalized, lineOf, linkRule, listOption, mapOption, noColorPalette, overrideMatches, parseComponentFacts, parseKitModuleFacts, performanceFontPreloadCrossorigin, performanceHeavyImport, performanceImageDimensions, performanceImageLoadingHint, performanceLcpImage, performanceLoadWaterfall, performanceMinifyDisabled, performanceNamespaceImport, performancePreconnect, performancePreloadMissingAs, performanceRenderBlockingScript, performanceResponsiveImage, performanceSequentialAwaits, performanceStateRaw, renderAppShell, resolveKitAliases, resolveKitPathsBase, resolveRuleOptions, resolveRunesModuleSpecifier, runRules, safeHref, scoreBand, scoreColor, scoresByCategory, securityHandlerStateWrite, securityJavascriptUrl, securityRawHtml, securityServerModuleState, securitySharedStateImport, selectRules, seoCanonicalUrl, seoCharset, seoDescriptionLength, seoDescriptionPresence, seoDuplicateDescription, seoDuplicateTitle, seoHeadingLevelSkip, seoHreflang, seoHtmlLang, seoImageAlt, seoIndexability, seoJsonLd, seoJsonLdDateFormat, seoJsonLdDeprecatedType, seoJsonLdPlaceholder, seoJsonLdRelativeUrl, seoJsonLdRequiredProps, seoJsonLdValidity, seoOgDescription, seoOgImage, seoOgTitle, seoOgUrl, seoRobotsTxt, seoSingleH1, seoSitemapInRobots, seoSitemapXml, seoSsrDisabled, seoTitleLength, seoTitlePresence, seoTwitterCard, seoViewport, settingOptions, settingSeverity, shouldSkipRangeCheck, summarize, textFromNodes, validateRuleOptions, validateRuleSetting, valueFromNodes };
package/dist/index.js CHANGED
@@ -2499,7 +2499,7 @@ function detect(head, match) {
2499
2499
  return tag ? { presence: tag.presence, value: tag.value } : { presence: "none", value: "absent" };
2500
2500
  }
2501
2501
  function headTagRule(opts) {
2502
- const docsUrl11 = docsUrlFor(opts.id);
2502
+ const docsUrl12 = docsUrlFor(opts.id);
2503
2503
  return {
2504
2504
  id: opts.id,
2505
2505
  title: opts.title,
@@ -2522,7 +2522,7 @@ function headTagRule(opts) {
2522
2522
  location: head.file,
2523
2523
  message,
2524
2524
  recommendation: opts.recommendation,
2525
- docsUrl: docsUrl11,
2525
+ docsUrl: docsUrl12,
2526
2526
  // Copy per finding: opts.fix is a rule-level template shared across all
2527
2527
  // results this rule emits; a fresh object keeps findings independent.
2528
2528
  ...opts.fix ? { fix: { ...opts.fix } } : {}
@@ -2715,7 +2715,7 @@ var seoHtmlLang = {
2715
2715
 
2716
2716
  // src/rules/perf/image-rule.ts
2717
2717
  function imageRule(opts) {
2718
- const docsUrl11 = docsUrlFor(opts.id);
2718
+ const docsUrl12 = docsUrlFor(opts.id);
2719
2719
  const category = opts.category ?? "performance";
2720
2720
  return {
2721
2721
  id: opts.id,
@@ -2739,7 +2739,7 @@ function imageRule(opts) {
2739
2739
  route: route.route,
2740
2740
  message: opts.label,
2741
2741
  recommendation: opts.recommendation,
2742
- docsUrl: docsUrl11
2742
+ docsUrl: docsUrl12
2743
2743
  });
2744
2744
  continue;
2745
2745
  }
@@ -2754,7 +2754,7 @@ function imageRule(opts) {
2754
2754
  ...img.line > 0 ? { line: img.line } : {},
2755
2755
  message: `Missing ${opts.label}`,
2756
2756
  recommendation: opts.recommendation,
2757
- docsUrl: docsUrl11,
2757
+ docsUrl: docsUrl12,
2758
2758
  ...opts.fix ? { fix: { ...opts.fix } } : {}
2759
2759
  });
2760
2760
  }
@@ -2814,7 +2814,7 @@ var performanceResponsiveImage = imageRule({
2814
2814
 
2815
2815
  // src/rules/perf/link-rule.ts
2816
2816
  function linkRule(opts) {
2817
- const docsUrl11 = docsUrlFor(opts.id);
2817
+ const docsUrl12 = docsUrlFor(opts.id);
2818
2818
  return {
2819
2819
  id: opts.id,
2820
2820
  title: opts.title,
@@ -2838,7 +2838,7 @@ function linkRule(opts) {
2838
2838
  route: head.route,
2839
2839
  message: opts.label,
2840
2840
  recommendation: opts.recommendation,
2841
- docsUrl: docsUrl11
2841
+ docsUrl: docsUrl12
2842
2842
  });
2843
2843
  continue;
2844
2844
  }
@@ -2855,7 +2855,7 @@ function linkRule(opts) {
2855
2855
  location: tag.file ?? head.file,
2856
2856
  message: `Missing ${opts.label}`,
2857
2857
  recommendation: opts.recommendation,
2858
- docsUrl: docsUrl11,
2858
+ docsUrl: docsUrl12,
2859
2859
  ...opts.fix ? { fix: { ...opts.fix } } : {}
2860
2860
  });
2861
2861
  }
@@ -3287,7 +3287,7 @@ var seoIndexability = {
3287
3287
  rationale: "A noindex directive removes the page from search results; an accidental noindex on a public route silently deindexes it.",
3288
3288
  fix: FIX5,
3289
3289
  async check(ctx) {
3290
- const docsUrl11 = docsUrlFor("seo/indexability");
3290
+ const docsUrl12 = docsUrlFor("seo/indexability");
3291
3291
  const out = [];
3292
3292
  for (const head of ctx.heads) {
3293
3293
  const noindexed = head.tags.some((t) => t.kind === "meta" && t.name === "robots" && t.noindex === true);
@@ -3302,7 +3302,7 @@ var seoIndexability = {
3302
3302
  location: head.file,
3303
3303
  message: "Route is noindex \u2014 verify this is intentional",
3304
3304
  recommendation: 'If this route should be indexed, remove noindex from its <meta name="robots">.',
3305
- docsUrl: docsUrl11,
3305
+ docsUrl: docsUrl12,
3306
3306
  fix: { ...FIX5 }
3307
3307
  });
3308
3308
  }
@@ -3553,7 +3553,7 @@ function jsonldTags(head) {
3553
3553
  return head.tags.filter((t) => t.kind === "jsonld" && typeof t.jsonld === "string");
3554
3554
  }
3555
3555
  function jsonldRule(opts) {
3556
- const docsUrl11 = docsUrlFor(opts.id);
3556
+ const docsUrl12 = docsUrlFor(opts.id);
3557
3557
  return {
3558
3558
  id: opts.id,
3559
3559
  title: opts.title,
@@ -3581,7 +3581,7 @@ function jsonldRule(opts) {
3581
3581
  location: head.file,
3582
3582
  message: problem,
3583
3583
  recommendation: opts.recommendation,
3584
- docsUrl: docsUrl11,
3584
+ docsUrl: docsUrl12,
3585
3585
  ...opts.fix ? { fix: { ...opts.fix } } : {}
3586
3586
  } : {
3587
3587
  id: opts.id,
@@ -3591,7 +3591,7 @@ function jsonldRule(opts) {
3591
3591
  route: head.route,
3592
3592
  message: opts.label,
3593
3593
  recommendation: opts.recommendation,
3594
- docsUrl: docsUrl11
3594
+ docsUrl: docsUrl12
3595
3595
  }
3596
3596
  );
3597
3597
  }
@@ -3615,7 +3615,7 @@ var seoJsonLdValidity = {
3615
3615
  lang: "svelte"
3616
3616
  },
3617
3617
  async check(ctx) {
3618
- const docsUrl11 = docsUrlFor("seo/json-ld-validity");
3618
+ const docsUrl12 = docsUrlFor("seo/json-ld-validity");
3619
3619
  const out = [];
3620
3620
  for (const head of ctx.heads) {
3621
3621
  for (const tag of jsonldTags(head)) {
@@ -3634,7 +3634,7 @@ var seoJsonLdValidity = {
3634
3634
  location: head.file,
3635
3635
  message: problem,
3636
3636
  recommendation: "Make the JSON-LD valid JSON with both @context and @type.",
3637
- docsUrl: docsUrl11,
3637
+ docsUrl: docsUrl12,
3638
3638
  fix: { ...seoJsonLdValidity.fix }
3639
3639
  } : {
3640
3640
  id: "seo/json-ld-validity",
@@ -3644,7 +3644,7 @@ var seoJsonLdValidity = {
3644
3644
  route: head.route,
3645
3645
  message: "JSON-LD validity",
3646
3646
  recommendation: "Make the JSON-LD valid JSON with both @context and @type.",
3647
- docsUrl: docsUrl11
3647
+ docsUrl: docsUrl12
3648
3648
  }
3649
3649
  );
3650
3650
  }
@@ -3755,7 +3755,7 @@ function visibleLength(s) {
3755
3755
 
3756
3756
  // src/rules/seo/length-rule.ts
3757
3757
  function lengthRule(opts) {
3758
- const docsUrl11 = docsUrlFor(opts.id);
3758
+ const docsUrl12 = docsUrlFor(opts.id);
3759
3759
  const spec = {
3760
3760
  min: { kind: "integer", default: opts.min, min: 0 },
3761
3761
  max: { kind: "integer", default: opts.max, min: 1 }
@@ -3778,7 +3778,7 @@ function lengthRule(opts) {
3778
3778
  const o = resolveRuleOptions(opts.id, spec, ctx.config, { route: head.route, file: location }, compiled);
3779
3779
  const min = intOption(o, "min", opts.min);
3780
3780
  const max = intOption(o, "max", opts.max);
3781
- const recommendation11 = typeof opts.recommendation === "function" ? opts.recommendation(o) : opts.recommendation;
3781
+ const recommendation12 = typeof opts.recommendation === "function" ? opts.recommendation(o) : opts.recommendation;
3782
3782
  const len = visibleLength(tag.text);
3783
3783
  let problem;
3784
3784
  if (len < min) problem = `${opts.noun} is too short (${len} chars; aim for ${min}\u2013${max})`;
@@ -3792,8 +3792,8 @@ function lengthRule(opts) {
3792
3792
  route: head.route,
3793
3793
  location,
3794
3794
  message: problem,
3795
- recommendation: recommendation11,
3796
- docsUrl: docsUrl11
3795
+ recommendation: recommendation12,
3796
+ docsUrl: docsUrl12
3797
3797
  } : {
3798
3798
  id: opts.id,
3799
3799
  category: "seo",
@@ -3801,8 +3801,8 @@ function lengthRule(opts) {
3801
3801
  detection: PASS,
3802
3802
  route: head.route,
3803
3803
  message: opts.label,
3804
- recommendation: recommendation11,
3805
- docsUrl: docsUrl11
3804
+ recommendation: recommendation12,
3805
+ docsUrl: docsUrl12
3806
3806
  }
3807
3807
  );
3808
3808
  }
@@ -3987,7 +3987,7 @@ var seoSingleH1 = {
3987
3987
 
3988
3988
  // src/rules/seo/uniqueness-rule.ts
3989
3989
  function uniquenessRule(opts) {
3990
- const docsUrl11 = docsUrlFor(opts.id);
3990
+ const docsUrl12 = docsUrlFor(opts.id);
3991
3991
  return {
3992
3992
  id: opts.id,
3993
3993
  title: opts.title,
@@ -4017,7 +4017,7 @@ function uniquenessRule(opts) {
4017
4017
  location: e.file,
4018
4018
  message: `${opts.noun} is duplicated across ${n} routes`,
4019
4019
  recommendation: opts.recommendation,
4020
- docsUrl: docsUrl11
4020
+ docsUrl: docsUrl12
4021
4021
  } : {
4022
4022
  id: opts.id,
4023
4023
  category: "seo",
@@ -4026,7 +4026,7 @@ function uniquenessRule(opts) {
4026
4026
  route: e.route,
4027
4027
  message: opts.label,
4028
4028
  recommendation: opts.recommendation,
4029
- docsUrl: docsUrl11
4029
+ docsUrl: docsUrl12
4030
4030
  };
4031
4031
  });
4032
4032
  }
@@ -4114,7 +4114,7 @@ function isSuppressed(m, ruleId, line) {
4114
4114
  return (m.suppressions ?? []).some((s) => s.line === line && (!s.ruleIds || s.ruleIds.includes(ruleId)));
4115
4115
  }
4116
4116
  function kitModuleRule(opts) {
4117
- const docsUrl11 = docsUrlFor(opts.id);
4117
+ const docsUrl12 = docsUrlFor(opts.id);
4118
4118
  const severity = opts.severity ?? "warning";
4119
4119
  return {
4120
4120
  id: opts.id,
@@ -4138,7 +4138,7 @@ function kitModuleRule(opts) {
4138
4138
  route: m.file,
4139
4139
  message: opts.label,
4140
4140
  recommendation: opts.recommendation,
4141
- docsUrl: docsUrl11
4141
+ docsUrl: docsUrl12
4142
4142
  });
4143
4143
  continue;
4144
4144
  }
@@ -4153,7 +4153,7 @@ function kitModuleRule(opts) {
4153
4153
  ...b.line > 0 ? { line: b.line } : {},
4154
4154
  message: b.message,
4155
4155
  recommendation: opts.recommendation,
4156
- docsUrl: docsUrl11,
4156
+ docsUrl: docsUrl12,
4157
4157
  ...opts.fix ? { fix: { ...opts.fix } } : {}
4158
4158
  });
4159
4159
  }
@@ -4189,7 +4189,7 @@ function isSuppressed2(c, ruleId, line) {
4189
4189
  return (c.suppressions ?? []).some((s) => s.line === line && (!s.ruleIds || s.ruleIds.includes(ruleId)));
4190
4190
  }
4191
4191
  function componentRule(opts) {
4192
- const docsUrl11 = docsUrlFor(opts.id);
4192
+ const docsUrl12 = docsUrlFor(opts.id);
4193
4193
  const severity = opts.severity ?? "warning";
4194
4194
  return {
4195
4195
  id: opts.id,
@@ -4205,7 +4205,7 @@ function componentRule(opts) {
4205
4205
  const compiled = compileOverrides(ctx.config);
4206
4206
  for (const c of ctx.components ?? []) {
4207
4207
  const o = resolveRuleOptions(opts.id, opts.options, ctx.config, { route: c.file, file: c.file }, compiled);
4208
- const recommendation11 = typeof opts.recommendation === "function" ? opts.recommendation(o) : opts.recommendation;
4208
+ const recommendation12 = typeof opts.recommendation === "function" ? opts.recommendation(o) : opts.recommendation;
4209
4209
  if (!opts.applies(c, o, ctx)) continue;
4210
4210
  const bad = opts.bad(c, o, ctx).filter((b) => !(b.line > 0 && isSuppressed2(c, opts.id, b.line)));
4211
4211
  if (bad.length === 0) {
@@ -4216,8 +4216,8 @@ function componentRule(opts) {
4216
4216
  detection: PASS3,
4217
4217
  route: c.file,
4218
4218
  message: opts.label,
4219
- recommendation: recommendation11,
4220
- docsUrl: docsUrl11
4219
+ recommendation: recommendation12,
4220
+ docsUrl: docsUrl12
4221
4221
  });
4222
4222
  continue;
4223
4223
  }
@@ -4231,8 +4231,8 @@ function componentRule(opts) {
4231
4231
  location: c.file,
4232
4232
  ...b.line > 0 ? { line: b.line } : {},
4233
4233
  message: b.message,
4234
- recommendation: recommendation11,
4235
- docsUrl: docsUrl11,
4234
+ recommendation: recommendation12,
4235
+ docsUrl: docsUrl12,
4236
4236
  ...opts.fix ? { fix: { ...opts.fix } } : {}
4237
4237
  });
4238
4238
  }
@@ -5265,9 +5265,11 @@ function stem(file) {
5265
5265
  return dot === -1 ? file : file.slice(0, dot);
5266
5266
  }
5267
5267
  function isUnitDir(dir, filesIn) {
5268
+ const first = baseName(dir).charCodeAt(0);
5269
+ return first >= 65 && first <= 90 && isAnyCaseUnitDir(dir, filesIn);
5270
+ }
5271
+ function isAnyCaseUnitDir(dir, filesIn) {
5268
5272
  const name = baseName(dir);
5269
- const first = name.charCodeAt(0);
5270
- if (!(first >= 65 && first <= 90)) return false;
5271
5273
  const own = filesIn.get(dir);
5272
5274
  return own !== void 0 && own.some((f) => stem(f) === name);
5273
5275
  }
@@ -5415,8 +5417,171 @@ var architectureReservedDirectoryNames = {
5415
5417
  }
5416
5418
  };
5417
5419
 
5420
+ // src/rules/architecture/reserved-name-placement.ts
5421
+ var ID7 = "architecture/reserved-name-placement";
5422
+ var docsUrl11 = docsUrlFor(ID7);
5423
+ var recommendation11 = "Move it to one of the places declared for this name, or declare this place for it.";
5424
+ var fixDescription = "Move the directory to one of the places declared for its name, rename it, or declare this place for the name.";
5425
+ var OPTIONS6 = {
5426
+ placements: { kind: "string-map", default: {} },
5427
+ capitalisedUnitPlacements: { kind: "string-map", default: {} },
5428
+ anyCaseUnitPlacements: { kind: "string-map", default: {} },
5429
+ exclude: { kind: "string-list", default: [] }
5430
+ };
5431
+ function parentOf(dir) {
5432
+ const cut = dir.lastIndexOf("/");
5433
+ return cut === -1 ? void 0 : dir.slice(0, cut);
5434
+ }
5435
+ var architectureReservedNamePlacement = {
5436
+ id: ID7,
5437
+ title: "Reserved name placement",
5438
+ category: "architecture",
5439
+ severity: "info",
5440
+ scope: "component",
5441
+ rationale: "A name reserved for one kind of place stops carrying that meaning the moment it appears somewhere else: a reader who has met one exception has to open the directory to learn what it holds.",
5442
+ fix: {
5443
+ description: fixDescription
5444
+ },
5445
+ options: OPTIONS6,
5446
+ async check(ctx) {
5447
+ const files = ctx.sourceFiles;
5448
+ if (files === void 0) return [];
5449
+ if (!isMentionedAnywhere(ctx.config, ID7)) return [];
5450
+ const compiledOverrides = compileOverrides(ctx.config);
5451
+ const dirs = /* @__PURE__ */ new Set();
5452
+ for (const f of files) for (const d of ancestorDirs2(f)) dirs.add(d);
5453
+ const filesIn = childFiles(files);
5454
+ const compile = createKeyCompiler();
5455
+ const parsed = /* @__PURE__ */ new Map();
5456
+ const globsOf = (value) => {
5457
+ let g = parsed.get(value);
5458
+ if (g === void 0) parsed.set(value, g = splitNames(value));
5459
+ return g;
5460
+ };
5461
+ const out = [];
5462
+ const label = (map, name, glob) => `${map}.${name} \u2192 ${glob}`;
5463
+ const globalOptions = resolveRuleOptions(ID7, OPTIONS6, ctx.config);
5464
+ const globalMaps = {
5465
+ placements: mapOption(globalOptions, "placements"),
5466
+ capitalisedUnitPlacements: mapOption(globalOptions, "capitalisedUnitPlacements"),
5467
+ anyCaseUnitPlacements: mapOption(globalOptions, "anyCaseUnitPlacements")
5468
+ };
5469
+ const globalAlternatives = /* @__PURE__ */ new Map();
5470
+ const emptyNames = /* @__PURE__ */ new Map();
5471
+ for (const map of Object.keys(globalMaps)) {
5472
+ for (const [name, value] of Object.entries(globalMaps[map])) {
5473
+ const globs2 = globsOf(value);
5474
+ if (globs2.length === 0) {
5475
+ emptyNames.set(`${map}.${name}`, "names no position at all");
5476
+ continue;
5477
+ }
5478
+ for (const glob of globs2) globalAlternatives.set(label(map, name, glob), { map, glob });
5479
+ }
5480
+ }
5481
+ const usedAlternatives = /* @__PURE__ */ new Set();
5482
+ const excludedDirs = [];
5483
+ const nonUnitParents = {
5484
+ capitalisedUnitPlacements: [],
5485
+ anyCaseUnitPlacements: []
5486
+ };
5487
+ const allDirs = [...dirs].sort();
5488
+ for (const dir of allDirs) {
5489
+ const o = resolveRuleOptions(ID7, OPTIONS6, ctx.config, { route: dir, file: dir }, compiledOverrides);
5490
+ const placements = mapOption(o, "placements");
5491
+ const capUnits = mapOption(o, "capitalisedUnitPlacements");
5492
+ const anyUnits = mapOption(o, "anyCaseUnitPlacements");
5493
+ if (Object.keys(placements).length === 0 && Object.keys(capUnits).length === 0 && Object.keys(anyUnits).length === 0) {
5494
+ continue;
5495
+ }
5496
+ const name = baseName(dir);
5497
+ const inPlacements = Object.hasOwn(placements, name);
5498
+ const inCapUnits = Object.hasOwn(capUnits, name);
5499
+ const inAnyUnits = Object.hasOwn(anyUnits, name);
5500
+ if (!inPlacements && !inCapUnits && !inAnyUnits) continue;
5501
+ const emptyValue = (present3, value) => present3 && globsOf(value ?? "").length === 0;
5502
+ if (emptyValue(inPlacements, placements[name]) || emptyValue(inCapUnits, capUnits[name]) || emptyValue(inAnyUnits, anyUnits[name])) {
5503
+ continue;
5504
+ }
5505
+ const excluded = compile(listOption(o, "exclude"));
5506
+ const parent = parentOf(dir);
5507
+ if (parent === void 0) continue;
5508
+ if (isExcluded(dir, ancestorDirs2(dir), excluded)) {
5509
+ if (isExcluded(parent, ancestorDirs2(parent), excluded)) excludedDirs.push(parent);
5510
+ continue;
5511
+ }
5512
+ const record = (map, value, qualifies) => {
5513
+ if (value === void 0) return false;
5514
+ const { matched } = matchKeys(parent, compile(globsOf(value), true));
5515
+ if (matched.length === 0) return false;
5516
+ if (!qualifies) {
5517
+ if (map !== "placements") nonUnitParents[map].push(parent);
5518
+ return false;
5519
+ }
5520
+ for (const glob of matched) usedAlternatives.add(label(map, name, glob));
5521
+ return true;
5522
+ };
5523
+ const byPlacement = record("placements", placements[name], true);
5524
+ const byCapUnit = record("capitalisedUnitPlacements", capUnits[name], isUnitDir(parent, filesIn));
5525
+ const byAnyUnit = record("anyCaseUnitPlacements", anyUnits[name], isAnyCaseUnitDir(parent, filesIn));
5526
+ if (byPlacement || byCapUnit || byAnyUnit) continue;
5527
+ const at = reportAt(dir, files);
5528
+ if (at === void 0) continue;
5529
+ out.push({
5530
+ id: ID7,
5531
+ category: "architecture",
5532
+ severity: "info",
5533
+ detection: { presence: "none", value: "absent" },
5534
+ route: dir,
5535
+ location: at,
5536
+ message: `${dir} is not one of the places declared for '${name}'.`,
5537
+ recommendation: recommendation11,
5538
+ docsUrl: docsUrl11,
5539
+ fix: {
5540
+ description: fixDescription
5541
+ }
5542
+ });
5543
+ }
5544
+ const notes = new Map(emptyNames);
5545
+ const unusedLabels = [...globalAlternatives.keys()].filter((k) => !usedAlternatives.has(k));
5546
+ const globOf = (key) => globalAlternatives.get(key)?.glob;
5547
+ for (const map of ["capitalisedUnitPlacements", "anyCaseUnitPlacements"]) {
5548
+ const inMap = unusedLabels.filter((k) => globalAlternatives.get(k)?.map === map);
5549
+ const hit = keysMatchingAny(inMap.map(globOf), nonUnitParents[map], compile);
5550
+ for (const k of inMap) {
5551
+ if (hit.has(globOf(k))) notes.set(k, "matched directories but never a unit");
5552
+ }
5553
+ }
5554
+ const stillUnused = unusedLabels.filter((k) => !notes.has(k));
5555
+ const globs = [...new Set(stillUnused.map(globOf))];
5556
+ const reasons = classifyUnusedKeys(globs, excludedDirs, compile);
5557
+ const reachable = keysMatchingAny(globs, allDirs, compile);
5558
+ for (const k of stillUnused) {
5559
+ const glob = globOf(k);
5560
+ if (reasons.get(glob) === "only-excluded") {
5561
+ notes.set(k, "matched only excluded directories");
5562
+ } else if (!reachable.has(glob)) {
5563
+ notes.set(k, "matched no directory");
5564
+ }
5565
+ }
5566
+ const reported = [...notes.keys()].sort();
5567
+ if (reported.length > 0) {
5568
+ const message = reported.length === 1 ? `The declaration '${reported[0]}' does not check what it says: ${notes.get(reported[0])}.` : `These declarations do not check what they say: ${reported.map((k) => `'${k}' (${notes.get(k)})`).join(", ")}.`;
5569
+ out.push({
5570
+ id: ID7,
5571
+ category: "architecture",
5572
+ severity: "info",
5573
+ detection: { presence: "none", value: "absent" },
5574
+ message,
5575
+ recommendation: "Correct the glob or the name, or remove the declaration.",
5576
+ docsUrl: docsUrl11
5577
+ });
5578
+ }
5579
+ return out;
5580
+ }
5581
+ };
5582
+
5418
5583
  // src/rules/architecture/route-component-import.ts
5419
- var ID7 = "architecture/route-component-import";
5584
+ var ID8 = "architecture/route-component-import";
5420
5585
  var EXEMPT_IMPORTERS = ["**/*.stories.svelte", "**/*.test.svelte", "**/*.spec.svelte"];
5421
5586
  var ROUTES_DIR = "src/routes/";
5422
5587
  var ROUTE_ENTRY = /^\+(page|layout)(@.*)?\.svelte$/;
@@ -5443,7 +5608,7 @@ function cachedRouteEntryImports(c, ctx) {
5443
5608
  return result;
5444
5609
  }
5445
5610
  var architectureRouteComponentImport = componentRule({
5446
- id: ID7,
5611
+ id: ID8,
5447
5612
  title: "Route component import",
5448
5613
  category: "architecture",
5449
5614
  severity: "info",
@@ -5467,7 +5632,7 @@ var architectureRouteComponentImport = componentRule({
5467
5632
  });
5468
5633
 
5469
5634
  // src/rules/architecture/doc-link-target.ts
5470
- var ID8 = "architecture/doc-link-target";
5635
+ var ID9 = "architecture/doc-link-target";
5471
5636
  function stripFragment(url) {
5472
5637
  const i = url.search(/[#?]/);
5473
5638
  return i === -1 ? url : url.slice(0, i);
@@ -5508,7 +5673,7 @@ function references(links, roots) {
5508
5673
  return out;
5509
5674
  }
5510
5675
  var architectureDocLinkTarget = componentRule({
5511
- id: ID8,
5676
+ id: ID9,
5512
5677
  title: "Documentation link target",
5513
5678
  category: "architecture",
5514
5679
  severity: "info",
@@ -5735,6 +5900,7 @@ var allRules = [
5735
5900
  architectureUnitEntryFile,
5736
5901
  architectureDirectoryNaming,
5737
5902
  architectureReservedDirectoryNames,
5903
+ architectureReservedNamePlacement,
5738
5904
  architectureRouteComponentImport,
5739
5905
  architectureDocLinkTarget,
5740
5906
  performanceHeavyImport,
@@ -7068,6 +7234,7 @@ export {
7068
7234
  architecturePrivateScopeImport,
7069
7235
  architecturePropCount,
7070
7236
  architectureReservedDirectoryNames,
7237
+ architectureReservedNamePlacement,
7071
7238
  architectureRouteComponentImport,
7072
7239
  architectureUnitEntryFile,
7073
7240
  attrText,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svelte-vitals/core",
3
- "version": "0.35.0",
3
+ "version": "0.36.0",
4
4
  "description": "Shared, runtime-agnostic core for svelte-vitals (types, rule engine, scorer, reporter).",
5
5
  "type": "module",
6
6
  "license": "MIT",