astroidjs 0.12.1 → 0.13.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.
Files changed (133) hide show
  1. package/README.md +42 -42
  2. package/bin/astroid.mjs +25 -25
  3. package/dist/analytics/index.d.ts +3 -3
  4. package/dist/analytics/index.js +9 -9
  5. package/dist/astro/csp.d.ts +5 -5
  6. package/dist/astro/csp.js +6 -6
  7. package/dist/astro/index.js +1 -1
  8. package/dist/auth/index.d.ts +2 -2
  9. package/dist/auth/index.js +5 -5
  10. package/dist/commerce/adapters.d.ts +6 -6
  11. package/dist/commerce/adapters.js +9 -9
  12. package/dist/commerce/checkout-scaffold.d.ts +5 -5
  13. package/dist/commerce/checkout-scaffold.js +9 -9
  14. package/dist/commerce/checkout.d.ts +12 -12
  15. package/dist/commerce/checkout.js +7 -7
  16. package/dist/commerce/loader.d.ts +2 -2
  17. package/dist/commerce/loader.js +3 -3
  18. package/dist/commerce/mirror.d.ts +4 -4
  19. package/dist/commerce/mirror.js +9 -9
  20. package/dist/commerce/roles.d.ts +10 -10
  21. package/dist/commerce/roles.js +13 -13
  22. package/dist/commerce/secrets.d.ts +9 -9
  23. package/dist/commerce/secrets.js +9 -9
  24. package/dist/commerce/sync.d.ts +7 -7
  25. package/dist/commerce/sync.js +5 -5
  26. package/dist/components/sections.d.ts +9 -9
  27. package/dist/components/sections.js +12 -12
  28. package/dist/config.d.ts +62 -62
  29. package/dist/config.js +18 -18
  30. package/dist/email/inquiry.d.ts +2 -2
  31. package/dist/email/inquiry.js +1 -1
  32. package/dist/email/send.d.ts +4 -4
  33. package/dist/email/send.js +7 -7
  34. package/dist/email/templates.js +3 -3
  35. package/dist/email/theme.d.ts +1 -1
  36. package/dist/email/theme.js +4 -4
  37. package/dist/errors.d.ts +1 -1
  38. package/dist/errors.js +1 -1
  39. package/dist/index.js +1 -1
  40. package/dist/map/pmtiles.d.ts +5 -5
  41. package/dist/map/pmtiles.js +5 -5
  42. package/dist/map/scaffold.d.ts +2 -2
  43. package/dist/map/scaffold.js +4 -4
  44. package/dist/map/style.d.ts +4 -4
  45. package/dist/map/style.js +1 -1
  46. package/dist/portal/config.d.ts +2 -2
  47. package/dist/portal/config.js +3 -3
  48. package/dist/portal/guard.d.ts +4 -4
  49. package/dist/portal/guard.js +4 -4
  50. package/dist/portal/nav.js +2 -2
  51. package/dist/portal/scaffold.d.ts +4 -4
  52. package/dist/portal/scaffold.js +6 -6
  53. package/dist/portal/session.d.ts +2 -2
  54. package/dist/portal/session.js +5 -5
  55. package/dist/portfolio/scaffold.d.ts +1 -1
  56. package/dist/portfolio/scaffold.js +4 -4
  57. package/dist/project/actions.d.ts +1 -1
  58. package/dist/project/actions.js +6 -6
  59. package/dist/project/generate.d.ts +4 -4
  60. package/dist/project/generate.js +15 -15
  61. package/dist/project/index.js +1 -1
  62. package/dist/project/scaffold.d.ts +2 -2
  63. package/dist/project/scaffold.js +11 -11
  64. package/dist/pwa/generate.d.ts +11 -11
  65. package/dist/pwa/generate.js +12 -12
  66. package/dist/queues/consumer.d.ts +3 -3
  67. package/dist/queues/consumer.js +2 -2
  68. package/dist/queues/messages.d.ts +4 -4
  69. package/dist/queues/messages.js +2 -2
  70. package/dist/queues/scaffold.d.ts +4 -4
  71. package/dist/queues/scaffold.js +8 -8
  72. package/dist/queues/webhook.d.ts +5 -5
  73. package/dist/queues/webhook.js +3 -3
  74. package/dist/realtime/scaffold.d.ts +4 -4
  75. package/dist/realtime/scaffold.js +8 -8
  76. package/dist/schema/collections.d.ts +6 -6
  77. package/dist/schema/collections.js +23 -23
  78. package/dist/schema/framework.d.ts +1 -1
  79. package/dist/schema/framework.js +2 -2
  80. package/dist/schema/generate.js +2 -2
  81. package/dist/schema/index.js +1 -1
  82. package/dist/secrets.d.ts +6 -6
  83. package/dist/secrets.js +6 -6
  84. package/dist/security/csp-origins.d.ts +1 -1
  85. package/dist/security/csp-origins.js +3 -3
  86. package/dist/security/rate-rules.d.ts +2 -2
  87. package/dist/security/rate-rules.js +8 -8
  88. package/dist/seo/resolve.d.ts +5 -5
  89. package/dist/seo/resolve.js +2 -2
  90. package/dist/seo/routes.d.ts +5 -5
  91. package/dist/seo/routes.js +3 -3
  92. package/dist/seo/structured-data.d.ts +6 -6
  93. package/dist/seo/structured-data.js +7 -7
  94. package/dist/status.d.ts +5 -5
  95. package/dist/status.js +7 -7
  96. package/dist/tenancy/index.d.ts +3 -3
  97. package/dist/tenancy/index.js +6 -6
  98. package/dist/worker/generate.d.ts +2 -2
  99. package/dist/worker/generate.js +19 -19
  100. package/dist/worker/index.js +1 -1
  101. package/dist/worker/routes.js +1 -1
  102. package/dist/workflow/advance.d.ts +3 -3
  103. package/dist/workflow/advance.js +6 -6
  104. package/dist/workflow/config.d.ts +4 -4
  105. package/dist/workflow/config.js +4 -4
  106. package/dist/workflow/generate.d.ts +2 -2
  107. package/dist/workflow/generate.js +4 -4
  108. package/package.json +3 -4
  109. package/src/components/Collection.tsx +5 -5
  110. package/src/components/Editable.astro +9 -9
  111. package/src/components/JustifiedGallery.astro +8 -8
  112. package/src/components/MediaSlot.astro +12 -12
  113. package/src/components/PortalShell.astro +4 -4
  114. package/src/components/RegisterSW.astro +3 -3
  115. package/src/components/Section.astro +8 -8
  116. package/src/components/Sections.astro +6 -6
  117. package/src/components/Seo.astro +3 -3
  118. package/src/components/StageBar.astro +3 -3
  119. package/src/components/StructuredData.astro +2 -2
  120. package/src/components/justify.ts +9 -9
  121. package/src/components/media-meta.ts +10 -10
  122. package/src/components/sections/AboutIntro.astro +1 -1
  123. package/src/components/sections/Contact.astro +1 -1
  124. package/src/components/sections/Cta.astro +1 -1
  125. package/src/components/sections/Faq.astro +1 -1
  126. package/src/components/sections/FeatureGrid.astro +2 -2
  127. package/src/components/sections/Hero.astro +1 -1
  128. package/src/components/sections/PricingTiers.astro +1 -1
  129. package/src/components/sections/ProductGrid.astro +1 -1
  130. package/src/components/sections/SplitImage.astro +1 -1
  131. package/src/components/sections/Steps.astro +1 -1
  132. package/src/components/sections/Testimonial.astro +1 -1
  133. package/src/components/sections.ts +17 -17
@@ -4,9 +4,9 @@
4
4
  //
5
5
  // The layout every photo grid actually wants: images keep their aspect ratios,
6
6
  // each row is exactly as wide as the container, and rows land near a target
7
- // height. CSS can't express it — `grid` needs uniform tracks, and `columns`
7
+ // height. CSS can't express it—`grid` needs uniform tracks, and `columns`
8
8
  // gives you a masonry *column* flow where reading order runs down instead of
9
- // across — so it's arithmetic, done once here rather than re-derived per site.
9
+ // across—so it's arithmetic, done once here rather than re-derived per site.
10
10
  //
11
11
  // Pure and synchronous on purpose. It's called twice for the same gallery:
12
12
  // once during SSR with the aspect ratios the media library recorded, and again
@@ -28,14 +28,14 @@ export interface JustifyItem {
28
28
  * One image in a `<JustifiedGallery>`.
29
29
  *
30
30
  * Declared here rather than in the `.astro` component so consumers can import
31
- * the type from a plain module — an `.astro` file's non-`Props` exports are
31
+ * the type from a plain module—an `.astro` file's non-`Props` exports are
32
32
  * awkward to reach from TypeScript, and a scaffolded page shouldn't have to.
33
33
  */
34
34
  export interface GalleryItem {
35
35
  src: string;
36
36
  /**
37
37
  * Alternative text. Required, and `""` is a legitimate value for a purely
38
- * decorative tile — what must not happen is the attribute going missing.
38
+ * decorative tile—what must not happen is the attribute going missing.
39
39
  */
40
40
  alt: string;
41
41
  /** Intrinsic dimensions, when the media library recorded them. Used for the
@@ -49,7 +49,7 @@ export interface GalleryItem {
49
49
 
50
50
  /** A laid-out item: its position in the input, at a concrete pixel size. */
51
51
  export interface JustifiedBox {
52
- /** Index into the input array — the caller maps this back to its own data. */
52
+ /** Index into the input array—the caller maps this back to its own data. */
53
53
  index: number;
54
54
  width: number;
55
55
  height: number;
@@ -80,8 +80,8 @@ export interface JustifyOptions {
80
80
  lastRowSlack?: number;
81
81
  }
82
82
 
83
- /** Aspect used for an item whose real ratio isn't known yet (3:2 landscape —
84
- * the most common photographic frame, so first paint is usually close). */
83
+ /** Aspect used for an item whose real ratio isn't known yet (3:2 landscape—*
84
+ the most common photographic frame, so first paint is usually close). */
85
85
  export const DEFAULT_ASPECT = 1.5;
86
86
 
87
87
  /** Clamp a caller-supplied aspect into something layout-safe. A zero or NaN
@@ -97,7 +97,7 @@ function safeAspect(aspect: number): number {
97
97
  * The rule per row: with n items of total aspect A and n−1 gaps, the height
98
98
  * that makes the row exactly fill is `(containerWidth − gap·(n−1)) / A`. Adding
99
99
  * items only ever *lowers* that height, so items are appended until it drops to
100
- * `targetHeight` and the row closes — which is why rows come out near, but
100
+ * `targetHeight` and the row closes—which is why rows come out near, but
101
101
  * never exactly at, the target.
102
102
  *
103
103
  * ```ts
@@ -135,7 +135,7 @@ export function justifyRows(items: JustifyItem[], options: JustifyOptions): Just
135
135
  // Every box but the last takes its proportional share; the last takes
136
136
  // whatever is left, so the row's widths sum to `available` exactly and the
137
137
  // right edge stays flush. An un-stretched trailing row keeps natural
138
- // widths instead — it isn't meant to reach the edge.
138
+ // widths instead—it isn't meant to reach the edge.
139
139
  const width =
140
140
  stretch && last
141
141
  ? available - used
@@ -4,8 +4,8 @@
4
4
  //
5
5
  // A section stores an image as a URL. The `alt` and `caption` an editor typed
6
6
  // live on the media ASSET, so rendering a page's images correctly means joining
7
- // every image field back to the media registry. Done naively — a query per
8
- // `<MediaSlot>` — a gallery section is thirty round-trips to D1 on every render.
7
+ // every image field back to the media registry. Done naively—a query per
8
+ // `<MediaSlot>`—a gallery section is thirty round-trips to D1 on every render.
9
9
  //
10
10
  // So the whole page is resolved in ONE bounded `IN (...)` lookup before anything
11
11
  // renders, and the result is threaded down as `mediaMeta`. This is the pattern
@@ -13,7 +13,7 @@
13
13
  //
14
14
  // The collection step is SCHEMA-DRIVEN: it walks the catalog looking for fields
15
15
  // of `type: "image"` rather than hardcoding field names. That's what keeps it
16
- // correct as sections are added — a new section with an image field is picked up
16
+ // correct as sections are added—a new section with an image field is picked up
17
17
  // because it declared one, not because someone remembered to update a list here.
18
18
  //
19
19
  // Self-contained (ships as source): type-only imports, no astroid `src/*` reach.
@@ -26,7 +26,7 @@ import type { MediaMeta } from "./sections.js";
26
26
  const CHUNK = 100;
27
27
 
28
28
  /** Walk one item's declared fields, collecting the values of `image` ones.
29
- * Recurses into `array` item fields — a gallery's images live there. */
29
+ * Recurses into `array` item fields—a gallery's images live there. */
30
30
  function collectFrom(
31
31
  item: Record<string, unknown>,
32
32
  fields: Record<string, SectionField> | undefined,
@@ -41,7 +41,7 @@ function collectFrom(
41
41
  for (const row of value) {
42
42
  if (typeof row !== "object" || row === null || Array.isArray(row)) continue;
43
43
  // With a discriminator, an item's variant contributes extra fields on
44
- // top of the shared set — an image declared only on the "image" variant
44
+ // top of the shared set—an image declared only on the "image" variant
45
45
  // of a blocks-style array would be missed otherwise.
46
46
  const sub = row as Record<string, unknown>;
47
47
  let itemFields = field.itemFields ?? {};
@@ -60,7 +60,7 @@ function collectFrom(
60
60
  /**
61
61
  * Every media URL a page's sections reference, deduplicated.
62
62
  *
63
- * Blocks are walked too, against the block catalog — a section's images and its
63
+ * Blocks are walked too, against the block catalog—a section's images and its
64
64
  * blocks' images are the same lookup, and splitting them would reintroduce the
65
65
  * per-section query this exists to avoid.
66
66
  */
@@ -96,7 +96,7 @@ export interface MediaMetaDatabase {
96
96
  /**
97
97
  * Turn a public media URL into its registry `key`.
98
98
  *
99
- * The public URL is `MEDIA_URL + "/" + key`, so this is prefix removal — but it
99
+ * The public URL is `MEDIA_URL + "/" + key`, so this is prefix removal—but it
100
100
  * has to tolerate an absolute URL too (a site whose media base is a full origin),
101
101
  * which is why it falls back to the pathname's last segment rather than assuming
102
102
  * the string starts with `mediaBase`.
@@ -105,7 +105,7 @@ export function mediaKeyFromUrl(url: string, mediaBase: string): string | null {
105
105
  if (!url) return null;
106
106
  const base = mediaBase.replace(/\/+$/, "");
107
107
  if (base && url.startsWith(`${base}/`)) return url.slice(base.length + 1);
108
- // Absolute or unexpected shape — take the path's tail, which is the key for
108
+ // Absolute or unexpected shape—take the path's tail, which is the key for
109
109
  // every URL the media route produces.
110
110
  try {
111
111
  const path = url.startsWith("http") ? new URL(url).pathname : url;
@@ -122,7 +122,7 @@ export function mediaKeyFromUrl(url: string, mediaBase: string): string | null {
122
122
  * Returns `{}` on any failure rather than throwing: missing alt text degrades a
123
123
  * page, but a media table that isn't provisioned yet must not take the whole
124
124
  * render down with it. The caller's per-image `alt` (a usage-level override)
125
- * always wins over what comes back here — this is the ASSET-level fallback.
125
+ * always wins over what comes back here—this is the ASSET-level fallback.
126
126
  */
127
127
  export async function resolveSectionMedia(
128
128
  db: MediaMetaDatabase | undefined,
@@ -131,7 +131,7 @@ export async function resolveSectionMedia(
131
131
  ): Promise<MediaMeta> {
132
132
  if (!db || urls.length === 0) return {};
133
133
 
134
- // key → the URL(s) that produced it, so results map back to what the sections
134
+ // key → the URLs that produced it, so results map back to what the sections
135
135
  // actually reference.
136
136
  const byKey = new Map<string, string[]>();
137
137
  for (const url of urls) {
@@ -1,5 +1,5 @@
1
1
  ---
2
- // A portrait beside an introduction — the "about the maker" opener.
2
+ // A portrait beside an introduction—the "about the maker" opener.
3
3
  import type { SectionRenderProps } from "../sections.js";
4
4
  import { colorwayClass, field, mediaAlt, setting } from "../sections.js";
5
5
  import Editable from "../Editable.astro";
@@ -1,5 +1,5 @@
1
1
  ---
2
- // Contact section — a heading + blurb + link to the contact route (the generated
2
+ // Contact section—a heading + blurb + link to the contact route (the generated
3
3
  // worker's contact form lives at /contact).
4
4
  import type { SectionRenderProps } from "../sections.js";
5
5
  import { colorwayClass, field, setting } from "../sections.js";
@@ -1,5 +1,5 @@
1
1
  ---
2
- // Call-to-action band. Defaults to the brand colorway — a setting token, so an
2
+ // Call-to-action band. Defaults to the brand colorway—a setting token, so an
3
3
  // editor can change it in the inspector without touching this file.
4
4
  import type { SectionRenderProps } from "../sections.js";
5
5
  import { alignClass, colorwayClass, field, setting } from "../sections.js";
@@ -3,7 +3,7 @@
3
3
  //
4
4
  // Native rather than a JS accordion on purpose: it is keyboard-accessible and
5
5
  // screen-reader-correct with no script, it works before hydration, and browser
6
- // find-in-page can open a collapsed answer — which a div-based accordion
6
+ // find-in-page can open a collapsed answer—which a div-based accordion
7
7
  // silently breaks.
8
8
  import type { SectionRenderProps } from "../sections.js";
9
9
  import { colorwayClass, field, itemField, list, setting } from "../sections.js";
@@ -1,9 +1,9 @@
1
1
  ---
2
- // Feature-grid section — value-prop cards over an `array` field.
2
+ // Feature-grid section—value-prop cards over an `array` field.
3
3
  //
4
4
  // The array is where `base` earns its keep. Each card's fields address
5
5
  // `<base>.items.<i>.<key>`, so the marker is built from the item's position
6
- // rather than a fixed slot name — which is why the schema can use a real
6
+ // rather than a fixed slot name—which is why the schema can use a real
7
7
  // repeatable array instead of the `card1…card6` flattening sites fall back to.
8
8
  // The client's path parser is depth-agnostic (it splits on `.` and coerces
9
9
  // numeric segments), so this needs nothing new on the editor side.
@@ -39,7 +39,7 @@ const ctaHref = field(item, "ctaHref");
39
39
  {subheading}
40
40
  </Editable>
41
41
  )}
42
- {/* The label is editable in place; the href is not — you can't point at a
42
+ {/* The label is editable in place; the href is not—you can't point at a
43
43
  URL, so it lives in the inspector (`inline: false` in the catalog). */}
44
44
  {ctaLabel && ctaHref && (
45
45
  <a class="btn btn-primary" href={ctaHref}>
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  // Pricing tiers. Each tier's feature list is a nested array, so a feature's
3
- // marker path is `<base>.items.<i>.features.<j>.text` — two levels of position,
3
+ // marker path is `<base>.items.<i>.features.<j>.text`—two levels of position,
4
4
  // which the client's path parser handles because it splits on `.` and coerces
5
5
  // every numeric segment.
6
6
  import type { SectionRenderProps } from "../sections.js";
@@ -4,7 +4,7 @@
4
4
  // Deliberately NOT a live catalog read. A section is stored content that an
5
5
  // editor curates; the commerce mirror has its own loader (`readCatalog`) with
6
6
  // its own freshness story. A site that wants the live catalog renders it in a
7
- // page, not through the page-builder — mixing the two would make a section's
7
+ // page, not through the page-builder—mixing the two would make a section's
8
8
  // stored value and what it displays disagree, and the editor would be editing
9
9
  // something that isn't there.
10
10
  import type { SectionRenderProps } from "../sections.js";
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  // Image beside copy. Which side the image sits on is a `_layout` token, so an
3
- // editor flips it from the inspector and Louise stores `"imageEnd"` — never a
3
+ // editor flips it from the inspector and Louise stores `"imageEnd"`—never a
4
4
  // class name. The mapping from token to CSS is here, where it belongs.
5
5
  import type { SectionRenderProps } from "../sections.js";
6
6
  import { colorwayClass, field, mediaAlt, setting } from "../sections.js";
@@ -1,5 +1,5 @@
1
1
  ---
2
- // A numbered sequence — "how it works", a commission process, an onboarding
2
+ // A numbered sequence—"how it works", a commission process, an onboarding
3
3
  // flow. The number is generated from position rather than stored, so reordering
4
4
  // steps in the inspector renumbers them with no content edit.
5
5
  import type { SectionRenderProps } from "../sections.js";
@@ -41,7 +41,7 @@ const image = field(item, "image");
41
41
  </Editable>
42
42
  {role && (
43
43
  <>
44
- {attribution && <span aria-hidden="true"> — </span>}
44
+ {attribution && <span aria-hidden="true"> · </span>}
45
45
  <Editable as="span" base={base} field="role" edit={edit}>{role}</Editable>
46
46
  </>
47
47
  )}
@@ -5,8 +5,8 @@
5
5
  //
6
6
  // This file used to define a parallel universe: a `SectionProps` union
7
7
  // discriminated on `kind`, with `colorway`/`align` as component props. Louise's
8
- // actual model — the one the on-canvas editor and the write-time validator both
9
- // read — is different in every particular, and it is the one that wins:
8
+ // actual model—the one the on-canvas editor and the write-time validator both
9
+ // read—is different in every particular, and it is the one that wins:
10
10
  //
11
11
  // • a section is a stored `SectionItem`: `{ _type, blocks?, _layout?,
12
12
  // _settings?, ...fields }`. The discriminant is `_type`, not `kind`.
@@ -16,7 +16,7 @@
16
16
  // or validated-but-uneditable.
17
17
  // • presentation choices are `_settings` / `_layout` **tokens**. Louise stores
18
18
  // the token; the site maps it to CSS. That's why COLORWAY_CLASS below stays
19
- // — it is exactly the site-owned half of that contract — while `colorway`
19
+ //: it is exactly the site-owned half of that contract—while `colorway`
20
20
  // stops being a prop and becomes a stored setting.
21
21
  //
22
22
  // ADR 0005 §2 names this file's job outright: "<Section> reads `_layout` /
@@ -26,7 +26,7 @@
26
26
  //
27
27
  // Self-contained on purpose: this module ships as SOURCE (the `.astro` files
28
28
  // beside it import it directly), so it must not reach back into astroid's built
29
- // `src/*` — only siblings and external packages. The `louise-toolkit/content`
29
+ // `src/*`—only siblings and external packages. The `louise-toolkit/content`
30
30
  // import is TYPE-ONLY, so it erases at build and never drags the validator (or
31
31
  // drizzle, which that entry pulls in) into a page bundle.
32
32
 
@@ -87,7 +87,7 @@ const tokenOptions = (map: Record<string, string>) =>
87
87
  *
88
88
  * These are closed token sets, declared as `select` (#272) so the inspector
89
89
  * renders a picker and an unknown token is rejected on write. They used to be
90
- * `text` with the valid values stuffed into `placeholder` — which meant a typo
90
+ * `text` with the valid values stuffed into `placeholder`—which meant a typo
91
91
  * wasn't a validation error at all, just a silent fallback to the default
92
92
  * inside `colorwayClass` at render time.
93
93
  */
@@ -97,7 +97,7 @@ export const SECTION_SETTINGS: Record<string, SectionField> = {
97
97
  label: "Colorway",
98
98
  inline: false,
99
99
  options: tokenOptions(COLORWAY_CLASS),
100
- // An opaque hint — the schema layer doesn't know what a swatch looks like;
100
+ // An opaque hint—the schema layer doesn't know what a swatch looks like;
101
101
  // a renderer that doesn't support it just shows a normal picker.
102
102
  display: "swatch",
103
103
  },
@@ -113,8 +113,8 @@ export const SECTION_SETTINGS: Record<string, SectionField> = {
113
113
  * What every section render component receives.
114
114
  *
115
115
  * `base` is the whole point. It is this item's path within the page's `sections`
116
- * array — `"2"` for a top-level section, `"2.blocks.0"` for a block inside it —
117
- * and every marker the component stamps is built from it. Passing it down (rather
116
+ * array—`"2"` for a top-level section, `"2.blocks.0"` for a block inside it—and
117
+ * every marker the component stamps is built from it. Passing it down (rather
118
118
  * than having each component work out its own depth) is what lets the exact same
119
119
  * component render as a section or as a block, and what keeps `data-louise-node`
120
120
  * paths correct at any nesting depth.
@@ -126,8 +126,8 @@ export interface SectionRenderProps {
126
126
  base: string;
127
127
  /** Whether to stamp edit markers. Defaults to `Astro.locals.editMode`. */
128
128
  edit?: boolean;
129
- /** Alt/caption resolved from the media registry, keyed by public URL —
130
- * looked up once for the whole page by `<Sections>`. */
129
+ /** Alt/caption resolved from the media registry, keyed by public URL—*
130
+ looked up once for the whole page by `<Sections>`. */
131
131
  mediaMeta?: MediaMeta;
132
132
  }
133
133
 
@@ -169,7 +169,7 @@ export function itemField(row: Record<string, unknown>, key: string): string | u
169
169
  *
170
170
  * The precedence is the whole reason `<Sections>` does its media lookup: a
171
171
  * per-usage `alt` on the section wins, because the same photo means something
172
- * different in a hero than in a thumbnail strip — but when there isn't one, the
172
+ * different in a hero than in a thumbnail strip—but when there isn't one, the
173
173
  * alt an editor typed once in the media library is used. That's what makes
174
174
  * fixing alt text a single edit that propagates everywhere the asset appears,
175
175
  * instead of a hunt through every page that embeds it.
@@ -188,7 +188,7 @@ export function mediaAlt(
188
188
  }
189
189
 
190
190
  /** Caption for an image, same precedence as {@link mediaAlt}. Undefined when
191
- * there is none — a missing caption renders nothing, unlike a missing alt. */
191
+ * there is none—a missing caption renders nothing, unlike a missing alt. */
192
192
  export function mediaCaption(
193
193
  mediaMeta: MediaMeta | undefined,
194
194
  src: string | undefined,
@@ -208,7 +208,7 @@ export function mediaCaption(
208
208
  * `satisfies` rather than a `: SectionCatalog` annotation, and it matters:
209
209
  * `SectionCatalog` is `Record<string, SectionDef>`, so annotating would widen
210
210
  * `keyof typeof` to `string` and throw away the literal keys. Those keys are
211
- * the project's whole section vocabulary — `SectionKind` is derived from them
211
+ * the project's whole section vocabulary—`SectionKind` is derived from them
212
212
  * (config.ts), `isRenderableSection` narrows to them, and `<Section>` indexes
213
213
  * its component map with them. Annotate this and all three silently degrade to
214
214
  * "any string", which is how the dispatcher lost its type safety once already.
@@ -221,7 +221,7 @@ export const astroidSectionCatalog = {
221
221
  heading: { type: "text", label: "Heading", validation: (r) => r.required().max(120) },
222
222
  subheading: { type: "textarea", label: "Subheading" },
223
223
  // A link URL is something you can't point at on the page, so it is not
224
- // inline — it belongs in the inspector, which is what `inline: false` says.
224
+ // inline—it belongs in the inspector, which is what `inline: false` says.
225
225
  ctaLabel: { type: "text", label: "Button label" },
226
226
  ctaHref: { type: "text", label: "Button link", inline: false },
227
227
  },
@@ -367,7 +367,7 @@ export const astroidSectionCatalog = {
367
367
  name: { type: "text", label: "Name", validation: (r) => r.required() },
368
368
  price: { type: "text", label: "Price" },
369
369
  period: { type: "text", label: "Period (e.g. /mo)" },
370
- // A list of strings isn't expressible — array items are objects — so
370
+ // A list of strings isn't expressible—array items are objects—so
371
371
  // each feature is a one-field row. That also leaves room to add an
372
372
  // `included` flag later without a data migration.
373
373
  features: {
@@ -424,7 +424,7 @@ export const astroidSectionCatalog = {
424
424
  heading: { type: "text", label: "Heading" },
425
425
  // Deliberately hand-authored rows rather than a live catalog read. A
426
426
  // section is stored content, and the commerce mirror is a separate
427
- // concern with its own loader — a site that wants the live catalog renders
427
+ // concern with its own loader—a site that wants the live catalog renders
428
428
  // `readCatalog` in its own page, not through the page-builder.
429
429
  items: {
430
430
  type: "array",
@@ -472,7 +472,7 @@ export const astroidSectionCatalog = {
472
472
  },
473
473
  } satisfies SectionCatalog;
474
474
 
475
- /** The `_type`s with a shipped render component — derived from the catalog, so
475
+ /** The `_type`s with a shipped render component—derived from the catalog, so
476
476
  * it can't drift from what `<Section>` actually dispatches. A literal union,
477
477
  * not `string`, because the catalog is declared with `satisfies`. */
478
478
  export type RenderableSectionType = keyof typeof astroidSectionCatalog;