nimbus-docs 0.1.11 → 0.1.13

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.
@@ -0,0 +1,37 @@
1
+ import { HastPluginDefinition } from "satteri";
2
+
3
+ //#region src/markdown/external-links.d.ts
4
+ /** Default arrow affordance (space + U+2197). Exported so a consumer's
5
+ * heading-slug plugin can strip it before computing ids. */
6
+ declare const EXTERNAL_LINK_ARROW = " \u2197";
7
+ interface ExternalLinksOptions {
8
+ /** `target` attribute set on external links. Default `"_blank"`. */
9
+ target?: string;
10
+ /** `rel` tokens set on external links. Default `["noopener"]`. */
11
+ rel?: string[];
12
+ /**
13
+ * Arrow affordance appended after the link text (inside the anchor), unless
14
+ * the link wraps an image. `null` disables it. Default `" ↗"`.
15
+ */
16
+ arrow?: string | null;
17
+ /** Class on the arrow `<span>`. Default `"external-link"`. */
18
+ arrowClass?: string;
19
+ /**
20
+ * Hosts considered internal (left undecorated). Default: none — any absolute
21
+ * `http(s)`/protocol-relative link is external (rehype-external-links default).
22
+ */
23
+ internalHosts?: string[];
24
+ }
25
+ declare function externalLinks(options?: ExternalLinksOptions): HastPluginDefinition;
26
+ //#endregion
27
+ //#region src/markdown/title-figure.d.ts
28
+ interface TitleFigureOptions {
29
+ /** Class on the generated `<figure>`. Default: none. */
30
+ figureClass?: string;
31
+ /** Class on the generated `<figcaption>`. Default: none. */
32
+ figcaptionClass?: string;
33
+ }
34
+ declare function titleFigure(options?: TitleFigureOptions): HastPluginDefinition;
35
+ //#endregion
36
+ export { EXTERNAL_LINK_ARROW, type ExternalLinksOptions, type TitleFigureOptions, externalLinks, titleFigure };
37
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","names":[],"sources":["../src/markdown/external-links.ts","../src/markdown/title-figure.ts"],"mappings":";;;;;cAkBa,mBAAA;AAAA,UAEI,oBAAA;EAgBF;EAdb,MAAA;EAgC2B;EA9B3B,GAAA;EAgCqB;;;;EA3BrB,KAAA;EA2BqB;EAzBrB,UAAA;;;ACfF;;EDoBE,aAAA;AAAA;AAAA,iBAkBc,aAAA,CACd,OAAA,GAAS,oBAAA,GACR,oBAAA;;;UCxCc,kBAAA;EDef;ECbA,WAAA;EDkBa;EChBb,eAAA;AAAA;AAAA,iBAqBc,WAAA,CACd,OAAA,GAAS,kBAAA,GACR,oBAAA"}
@@ -0,0 +1,126 @@
1
+ //#region src/markdown/types.ts
2
+ /** Narrow a node to an element, optionally of a given tagName. */
3
+ function isElement(node, tagName) {
4
+ return !!node && node.type === "element" && (tagName === void 0 || node.tagName === tagName);
5
+ }
6
+
7
+ //#endregion
8
+ //#region src/markdown/external-links.ts
9
+ /** Default arrow affordance (space + U+2197). Exported so a consumer's
10
+ * heading-slug plugin can strip it before computing ids. */
11
+ const EXTERNAL_LINK_ARROW = " ↗";
12
+ const EXTERNAL = /^(?:https?:)?\/\//i;
13
+ function hasImgChild(node) {
14
+ return (node.children ?? []).some((c) => isElement(c, "img"));
15
+ }
16
+ function hostOf(href) {
17
+ try {
18
+ return new URL(href.startsWith("//") ? `https:${href}` : href).host;
19
+ } catch {
20
+ return null;
21
+ }
22
+ }
23
+ function externalLinks(options = {}) {
24
+ const target = options.target ?? "_blank";
25
+ const rel = options.rel ?? ["noopener"];
26
+ const arrow = options.arrow === void 0 ? EXTERNAL_LINK_ARROW : options.arrow;
27
+ const arrowClass = options.arrowClass ?? "external-link";
28
+ const internalHosts = options.internalHosts;
29
+ return {
30
+ name: "nimbus:external-links",
31
+ element: {
32
+ filter: ["a"],
33
+ visit(node) {
34
+ const href = node.properties?.href;
35
+ if (typeof href !== "string" || !EXTERNAL.test(href)) return;
36
+ if (internalHosts && internalHosts.length > 0) {
37
+ const host = hostOf(href);
38
+ if (host && internalHosts.includes(host)) return;
39
+ }
40
+ const children = [...node.children ?? []];
41
+ if (arrow !== null && !hasImgChild(node)) children.push({
42
+ type: "element",
43
+ tagName: "span",
44
+ properties: { className: [arrowClass] },
45
+ children: [{
46
+ type: "text",
47
+ value: arrow
48
+ }]
49
+ });
50
+ return {
51
+ type: "element",
52
+ tagName: "a",
53
+ properties: {
54
+ ...node.properties,
55
+ target,
56
+ rel
57
+ },
58
+ children
59
+ };
60
+ }
61
+ }
62
+ };
63
+ }
64
+
65
+ //#endregion
66
+ //#region src/markdown/title-figure.ts
67
+ const WHITESPACE_ONLY = /^\s*$/;
68
+ function isStandaloneImageParagraph(node) {
69
+ let sawImage = false;
70
+ for (const child of node.children ?? []) {
71
+ if (child.type === "text") {
72
+ if (!WHITESPACE_ONLY.test(child.value)) return false;
73
+ continue;
74
+ }
75
+ if (isElement(child, "img")) {
76
+ sawImage = true;
77
+ continue;
78
+ }
79
+ return false;
80
+ }
81
+ return sawImage;
82
+ }
83
+ function titleFigure(options = {}) {
84
+ const figureProps = options.figureClass ? { className: [options.figureClass] } : {};
85
+ const figcaptionProps = options.figcaptionClass ? { className: [options.figcaptionClass] } : {};
86
+ function build(img) {
87
+ const title = `${img.properties?.title ?? ""}`;
88
+ if (!title) return img;
89
+ return {
90
+ type: "element",
91
+ tagName: "figure",
92
+ properties: { ...figureProps },
93
+ children: [{
94
+ type: "element",
95
+ tagName: "img",
96
+ properties: { ...img.properties },
97
+ children: []
98
+ }, {
99
+ type: "element",
100
+ tagName: "figcaption",
101
+ properties: { ...figcaptionProps },
102
+ children: [{
103
+ type: "text",
104
+ value: title
105
+ }]
106
+ }]
107
+ };
108
+ }
109
+ return {
110
+ name: "nimbus:title-figure",
111
+ element: {
112
+ filter: ["p"],
113
+ visit(node, ctx) {
114
+ if (!isStandaloneImageParagraph(node)) return;
115
+ const figures = (node.children ?? []).filter((c) => isElement(c, "img")).map(build);
116
+ if (figures.length === 0) return;
117
+ for (const fig of figures) ctx.insertBefore(node, fig);
118
+ ctx.removeNode(node);
119
+ }
120
+ }
121
+ };
122
+ }
123
+
124
+ //#endregion
125
+ export { EXTERNAL_LINK_ARROW, externalLinks, titleFigure };
126
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","names":[],"sources":["../src/markdown/types.ts","../src/markdown/external-links.ts","../src/markdown/title-figure.ts"],"sourcesContent":["// Shared types for `nimbus-docs/markdown`. Sourced from `satteri` (a direct\n// dependency); `@types/hast` is not available here, so the node shapes these\n// plugins build are declared as minimal structural interfaces.\n\nimport type {\n HastPluginDefinition,\n HastVisitorContext,\n} from \"satteri\";\n\nexport type { HastPluginDefinition, HastVisitorContext };\n\nexport interface HastElement {\n type: \"element\";\n tagName: string;\n properties?: Record<string, unknown> | null;\n children?: HastChild[];\n}\n\nexport interface HastText {\n type: \"text\";\n value: string;\n}\n\nexport type HastChild = HastElement | HastText | { type: string; value?: string };\n\n/** Narrow a node to an element, optionally of a given tagName. */\nexport function isElement(\n node: { type: string; tagName?: string } | null | undefined,\n tagName?: string,\n): node is HastElement {\n return (\n !!node &&\n node.type === \"element\" &&\n (tagName === undefined || node.tagName === tagName)\n );\n}\n\n/** Normalise a hast `className` property to a string[]. */\nexport function classNames(node: HastElement): string[] {\n const cn = node.properties?.className;\n if (Array.isArray(cn)) return cn.map(String);\n if (typeof cn === \"string\") return cn.split(/\\s+/).filter(Boolean);\n return [];\n}\n","/**\n * Decorates external links (absolute `http(s)`/protocol-relative): sets\n * `target`/`rel` and appends an arrow affordance after the link text, unless\n * the link wraps an image. Defaults mirror the common `rehype-external-links`\n * setup, so `externalLinks()` is a drop-in.\n *\n * nimbus(config, { markdown: { hastPlugins: [externalLinks()] } })\n *\n * This runs before Sätteri's built-in heading-ids, whose text collection\n * re-includes the arrow and cannot be told to strip it. So an external link\n * inside a heading would pollute that heading's slug unless the consumer owns\n * heading slugging and strips `EXTERNAL_LINK_ARROW` before slugging.\n */\nimport type { HastChild, HastElement, HastPluginDefinition } from \"./types\";\nimport { isElement } from \"./types\";\n\n/** Default arrow affordance (space + U+2197). Exported so a consumer's\n * heading-slug plugin can strip it before computing ids. */\nexport const EXTERNAL_LINK_ARROW = \" ↗\";\n\nexport interface ExternalLinksOptions {\n /** `target` attribute set on external links. Default `\"_blank\"`. */\n target?: string;\n /** `rel` tokens set on external links. Default `[\"noopener\"]`. */\n rel?: string[];\n /**\n * Arrow affordance appended after the link text (inside the anchor), unless\n * the link wraps an image. `null` disables it. Default `\" ↗\"`.\n */\n arrow?: string | null;\n /** Class on the arrow `<span>`. Default `\"external-link\"`. */\n arrowClass?: string;\n /**\n * Hosts considered internal (left undecorated). Default: none — any absolute\n * `http(s)`/protocol-relative link is external (rehype-external-links default).\n */\n internalHosts?: string[];\n}\n\n// Absolute http(s) or protocol-relative `//host`.\nconst EXTERNAL = /^(?:https?:)?\\/\\//i;\n\nfunction hasImgChild(node: HastElement): boolean {\n return (node.children ?? []).some((c) => isElement(c, \"img\"));\n}\n\nfunction hostOf(href: string): string | null {\n try {\n return new URL(href.startsWith(\"//\") ? `https:${href}` : href).host;\n } catch {\n return null;\n }\n}\n\nexport function externalLinks(\n options: ExternalLinksOptions = {},\n): HastPluginDefinition {\n const target = options.target ?? \"_blank\";\n const rel = options.rel ?? [\"noopener\"];\n const arrow = options.arrow === undefined ? EXTERNAL_LINK_ARROW : options.arrow;\n const arrowClass = options.arrowClass ?? \"external-link\";\n const internalHosts = options.internalHosts;\n\n const plugin = {\n name: \"nimbus:external-links\",\n element: {\n filter: [\"a\"],\n visit(node: HastElement) {\n const href = node.properties?.href;\n if (typeof href !== \"string\" || !EXTERNAL.test(href)) return;\n if (internalHosts && internalHosts.length > 0) {\n const host = hostOf(href);\n if (host && internalHosts.includes(host)) return;\n }\n\n const children: HastChild[] = [...(node.children ?? [])];\n if (arrow !== null && !hasImgChild(node)) {\n children.push({\n type: \"element\",\n tagName: \"span\",\n properties: { className: [arrowClass] },\n children: [{ type: \"text\", value: arrow }],\n });\n }\n\n return {\n type: \"element\",\n tagName: \"a\",\n properties: { ...node.properties, target, rel },\n children,\n } as HastElement;\n },\n },\n };\n\n return plugin as unknown as HastPluginDefinition;\n}\n","/**\n * Turns a titled standalone image into a captioned figure:\n * <p><img title=\"cap\"></p> -> <figure><img …><figcaption>cap</figcaption></figure>\n * Untitled standalone images are unwrapped without a caption.\n *\n * nimbus(config, { markdown: { hastPlugins: [titleFigure()] } })\n *\n * `rehype-title-figure` only acts on root-level paragraphs; Sätteri's filtered\n * visitors expose no ancestors, so we instead require the paragraph to contain\n * only image(s) plus whitespace. A standalone-image paragraph nested in a\n * list/aside/blockquote is therefore also transformed; mixed text+image\n * paragraphs are left untouched.\n */\nimport type { HastChild, HastElement, HastPluginDefinition } from \"./types\";\nimport { isElement } from \"./types\";\n\nexport interface TitleFigureOptions {\n /** Class on the generated `<figure>`. Default: none. */\n figureClass?: string;\n /** Class on the generated `<figcaption>`. Default: none. */\n figcaptionClass?: string;\n}\n\nconst WHITESPACE_ONLY = /^\\s*$/;\n\nfunction isStandaloneImageParagraph(node: HastElement): boolean {\n let sawImage = false;\n for (const child of node.children ?? []) {\n if (child.type === \"text\") {\n if (!WHITESPACE_ONLY.test((child as { value: string }).value)) return false;\n continue;\n }\n if (isElement(child, \"img\")) {\n sawImage = true;\n continue;\n }\n return false;\n }\n return sawImage;\n}\n\nexport function titleFigure(\n options: TitleFigureOptions = {},\n): HastPluginDefinition {\n const figureProps = options.figureClass\n ? { className: [options.figureClass] }\n : {};\n const figcaptionProps = options.figcaptionClass\n ? { className: [options.figcaptionClass] }\n : {};\n\n function build(img: HastElement): HastElement {\n const title = `${img.properties?.title ?? \"\"}`;\n if (!title) return img;\n return {\n type: \"element\",\n tagName: \"figure\",\n properties: { ...figureProps },\n children: [\n { type: \"element\", tagName: \"img\", properties: { ...img.properties }, children: [] },\n {\n type: \"element\",\n tagName: \"figcaption\",\n properties: { ...figcaptionProps },\n children: [{ type: \"text\", value: title }],\n },\n ],\n };\n }\n\n const plugin = {\n name: \"nimbus:title-figure\",\n element: {\n filter: [\"p\"],\n visit(node: HastElement, ctx: { insertBefore(n: unknown, x: unknown): void; removeNode(n: unknown): void }) {\n if (!isStandaloneImageParagraph(node)) return;\n const figures = (node.children ?? [])\n .filter((c): c is HastElement => isElement(c, \"img\"))\n .map(build);\n if (figures.length === 0) return;\n for (const fig of figures as HastChild[]) ctx.insertBefore(node, fig);\n ctx.removeNode(node);\n },\n },\n };\n\n return plugin as unknown as HastPluginDefinition;\n}\n"],"mappings":"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"}
package/dist/schemas.d.ts CHANGED
@@ -18,7 +18,7 @@ interface DocSchemaConfig<TFields extends Record<string, z.ZodTypeAny> = Record<
18
18
  * For typed Astro `image()` fields or per-collection field narrowing, use
19
19
  * the richer `defineSchema(ctx => ...)` factory instead.
20
20
  */
21
- declare function defineDocSchema<TFields extends Record<string, z.ZodTypeAny> = Record<string, never>>(config?: DocSchemaConfig<TFields>): z.ZodObject<(("prev" | "next" | "title" | "description" | "mode" | "sidebar" | "head" | "banner" | "draft" | "noindex" | "searchable" | "tableOfContents" | "lastUpdated" | "socialImage" | "previousSlug" | "external_link") & keyof TFields extends never ? {
21
+ declare function defineDocSchema<TFields extends Record<string, z.ZodTypeAny> = Record<string, never>>(config?: DocSchemaConfig<TFields>): z.ZodObject<(("prev" | "next" | "title" | "description" | "mode" | "hideChildren" | "sidebar" | "head" | "banner" | "draft" | "noindex" | "searchable" | "tableOfContents" | "lastUpdated" | "socialImage" | "previousSlug" | "external_link") & keyof TFields extends never ? {
22
22
  title: z.ZodString;
23
23
  description: z.ZodOptional<z.ZodString>;
24
24
  mode: z.ZodDefault<z.ZodEnum<{
@@ -60,6 +60,7 @@ declare function defineDocSchema<TFields extends Record<string, z.ZodTypeAny> =
60
60
  }, z.core.$strip>]>>;
61
61
  }, z.core.$strip>>;
62
62
  }, z.core.$strip>]>>;
63
+ hideChildren: z.ZodOptional<z.ZodBoolean>;
63
64
  head: z.ZodDefault<z.ZodArray<z.ZodObject<{
64
65
  tag: z.ZodEnum<{
65
66
  title: "title";
@@ -147,6 +148,7 @@ declare function defineDocSchema<TFields extends Record<string, z.ZodTypeAny> =
147
148
  }, z.core.$strip>]>>;
148
149
  }, z.core.$strip>>;
149
150
  }, z.core.$strip>]>>;
151
+ hideChildren: z.ZodOptional<z.ZodBoolean>;
150
152
  head: z.ZodDefault<z.ZodArray<z.ZodObject<{
151
153
  tag: z.ZodEnum<{
152
154
  title: "title";
@@ -232,9 +234,9 @@ interface DefineSchemaOptions {
232
234
  * }),
233
235
  * };
234
236
  */
235
- declare function defineSchema(factory: (ctx: astro_content0.SchemaContext) => DefineSchemaOptions): (ctx: astro_content0.SchemaContext) => z.ZodObject<Readonly<{
237
+ declare function defineSchema(factory: (ctx: astro_content0.SchemaContext) => DefineSchemaOptions): (ctx: astro_content0.SchemaContext) => z.ZodIntersection<z.ZodObject<any, z.core.$strip>, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>> | z.ZodObject<Readonly<{
236
238
  [k: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
237
- }>, z.core.$loose> | z.ZodIntersection<z.ZodObject<any, z.core.$strip>, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
239
+ }>, z.core.$loose>;
238
240
  /** Default docs schema. Equivalent to `defineDocSchema()`. */
239
241
  declare const docsSchema: z.ZodObject<{
240
242
  [x: string]: never;
@@ -306,6 +308,7 @@ declare const lenientDocsSchema: z.ZodObject<{
306
308
  }, z.core.$strip>]>>;
307
309
  }, z.core.$strip>>;
308
310
  }, z.core.$strip>]>>;
311
+ hideChildren: z.ZodOptional<z.ZodBoolean>;
309
312
  head: z.ZodDefault<z.ZodArray<z.ZodObject<{
310
313
  tag: z.ZodEnum<{
311
314
  title: "title";
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.d.ts","names":[],"sources":["../src/schemas.ts"],"mappings":";;;;UAkBiB,eAAA,iBACC,MAAA,SAAe,CAAA,CAAE,UAAA,IAAc,MAAA;EAAhB;;;;;EAO/B,MAAA,GAAS,OAAA;AAAA;AAmRX;;;;;;;;AAAA,iBAAgB,eAAA,iBACE,MAAA,SAAe,CAAA,CAAE,UAAA,IAAc,MAAA,gBAAA,CAC/C,MAAA,GAAQ,eAAA,CAAgB,OAAA,IAAa,CAAA,CAAA,SAAA,2NAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAyBtB,mBAAA;EACf,MAAA,GAAS,CAAA,CAAE,UAAA;EACX,MAAA,GAAS,MAAA,SAAe,CAAA,CAAE,UAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6BZ,YAAA,CACd,OAAA,GAAU,GAAA,EADgB,cAAA,CACa,aAAA,KAAkB,mBAAA,IAEjD,GAAA,EAFoE,cAAA,CAEvC,aAAA,KAAa,CAAA,CAAA,SAAA,CAAA,QAAA;EAAA;;;cA8BvC,UAAA,EAAU,CAAA,CAAA,SAAA;EAAA;GAAoB,CAAA,CAAA,IAAA,CAAA,MAAA;;cAW9B,cAAA,EAAc,CAAA,CAAA,UAAA,CAAA,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;iBAeX,oBAAA,iBACE,MAAA,SAAe,CAAA,CAAE,UAAA,IAAc,MAAA,gBAAA,CAC/C,MAAA;EAAU,MAAA,GAAS,OAAA;AAAA,IAAc,CAAA,CAAA,SAAA,mBAAA,OAAA;;;;;;cAmBtB,iBAAA,EAAiB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAGjB,qBAAA,EAAqB,CAAA,CAAA,SAAA;;;;cAU5B,mBAAA,EAAmB,CAAA,CAAA,SAAA;;;;;;;KAQb,aAAA,GAAgB,CAAA,CAAE,KAAA,QAAa,mBAAA;;cAG9B,gBAAA,EAAgB,CAAA,CAAA,SAAA"}
1
+ {"version":3,"file":"schemas.d.ts","names":[],"sources":["../src/schemas.ts"],"mappings":";;;;UAkBiB,eAAA,iBACC,MAAA,SAAe,CAAA,CAAE,UAAA,IAAc,MAAA;EAAhB;;;;;EAO/B,MAAA,GAAS,OAAA;AAAA;AA0RX;;;;;;;;AAAA,iBAAgB,eAAA,iBACE,MAAA,SAAe,CAAA,CAAE,UAAA,IAAc,MAAA,gBAAA,CAC/C,MAAA,GAAQ,eAAA,CAAgB,OAAA,IAAa,CAAA,CAAA,SAAA,4OAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAyBtB,mBAAA;EACf,MAAA,GAAS,CAAA,CAAE,UAAA;EACX,MAAA,GAAS,MAAA,SAAe,CAAA,CAAE,UAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6BZ,YAAA,CACd,OAAA,GAAU,GAAA,EADgB,cAAA,CACa,aAAA,KAAkB,mBAAA,IAEjD,GAAA,EAFoE,cAAA,CAEvC,aAAA,KAAa,CAAA,CAAA,eAAA,CAAA,CAAA,CAAA,SAAA,MAAA,CAAA,CAAA,IAAA,CAAA,MAAA,GAAA,CAAA,CAAA,OAAA,mBAAA,CAAA,CAAA,IAAA,CAAA,iBAAA,uBAAA,CAAA,CAAA,SAAA,CAAA,QAAA;EAAA;;;cA8BvC,UAAA,EAAU,CAAA,CAAA,SAAA;EAAA;GAAoB,CAAA,CAAA,IAAA,CAAA,MAAA;;cAW9B,cAAA,EAAc,CAAA,CAAA,UAAA,CAAA,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;iBAeX,oBAAA,iBACE,MAAA,SAAe,CAAA,CAAE,UAAA,IAAc,MAAA,gBAAA,CAC/C,MAAA;EAAU,MAAA,GAAS,OAAA;AAAA,IAAc,CAAA,CAAA,SAAA,mBAAA,OAAA;;;;;;cAmBtB,iBAAA,EAAiB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAGjB,qBAAA,EAAqB,CAAA,CAAA,SAAA;;;;cAU5B,mBAAA,EAAmB,CAAA,CAAA,SAAA;;;;;;;KAQb,aAAA,GAAgB,CAAA,CAAE,KAAA,QAAa,mBAAA;;cAG9B,gBAAA,EAAgB,CAAA,CAAA,SAAA"}
package/dist/schemas.js CHANGED
@@ -111,6 +111,7 @@ function baseDocSchema() {
111
111
  description: z.string({ error: "\"description\" must be a string" }).optional(),
112
112
  mode: z.enum(["doc", "custom"], { error: "\"mode\" must be \"doc\" or \"custom\"" }).default("doc"),
113
113
  sidebar: z.union([z.literal(false), sidebarSchema]).optional(),
114
+ hideChildren: z.boolean({ error: "\"hideChildren\" must be true or false" }).optional(),
114
115
  head: z.array(headElementSchema).default([]),
115
116
  banner: bannerSchema.optional(),
116
117
  draft: z.boolean({ error: "\"draft\" must be true or false" }).default(false),
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.js","names":[],"sources":["../src/schemas.ts"],"sourcesContent":["/**\n * Content schemas for Nimbus.\n *\n * `docsSchema` is the default frontmatter contract for the `docs` collection.\n * `partialsSchema` is the contract for `<Render file=\"...\" />` partials.\n * `defineDocSchema(config)` returns a customizable schema for advanced users\n * composing schemas outside the `docsCollection()` factory.\n *\n * Error messages target content authors, not framework developers.\n * Astro 6 ships Zod v4 via `astro/zod`. The v4 API uses a single `error`\n * field on every schema constructor — NOT v3's `required_error` /\n * `invalid_type_error` / `errorMap`.\n */\n\nimport { z } from \"astro/zod\";\nimport { withStrictKeys } from \"./_internal/strict-keys.js\";\nimport { isAbsoluteUrl } from \"./_internal/url.js\";\n\nexport interface DocSchemaConfig<\n TFields extends Record<string, z.ZodTypeAny> = Record<string, never>,\n> {\n /**\n * Additional frontmatter fields merged into the default schema.\n * Generic-typed so the call-site shape is preserved through to\n * `entry.data.<field>` access in consumer code.\n */\n fields?: TFields;\n}\n\n// ---------------------------------------------------------------------------\n// Building blocks\n// ---------------------------------------------------------------------------\n\nconst sidebarBadgeSchema = z.union([\n z.string(),\n z.object({\n text: z.string({ error: 'sidebar badge needs a \"text\" field' }),\n variant: z\n .enum(\n [\"default\", \"info\", \"note\", \"success\", \"tip\", \"warning\", \"caution\", \"danger\"],\n {\n error:\n '\"variant\" must be one of: default, info, note, success, tip, warning, caution, danger',\n },\n )\n .default(\"default\"),\n }),\n]);\n\n// Group-level overrides for sidebar entries that act as a group label\n// (i.e. an `index.mdx` whose siblings become the group's children).\n// Starlight parity — sites migrating from Starlight write these as\n// `sidebar: { group: { … } }`. Apply only when the entry is the index\n// of a directory containing other entries.\nconst sidebarGroupSchema = z.object({\n /** Override the group label (defaults to the directory name). */\n label: z.string({ error: '\"sidebar.group.label\" must be a string' }).optional(),\n /** Override the group badge (defaults to none). */\n badge: sidebarBadgeSchema.optional(),\n});\n\nconst sidebarSchema = z.object({\n order: z.number({ error: '\"sidebar.order\" must be a number' }).optional(),\n label: z.string({ error: '\"sidebar.label\" must be a string' }).optional(),\n badge: sidebarBadgeSchema.optional(),\n hidden: z.boolean({ error: '\"sidebar.hidden\" must be true or false' }).optional(),\n hideChildren: z\n .boolean({ error: '\"sidebar.hideChildren\" must be true or false' })\n .optional(),\n /** Group-level overrides; see `sidebarGroupSchema`. */\n group: sidebarGroupSchema.optional(),\n});\n\nconst prevNextSchema = z\n .union([\n z.string(),\n z.object({ link: z.string().optional(), label: z.string().optional() }),\n z.literal(false),\n ])\n .optional();\n\n// Head elements: every HTML tag that's valid as a direct child of <head>.\n// The earlier enum was meta/link/script/style only, which rejected the\n// equally-valid `title`, `noscript`, and `base` — needed on a page that\n// overrides the browser tab title via\n// `head: [{ tag: title, content: \"Overview\" }]`. Keeping it an enum (vs.\n// a free `z.string()`) so typos still fail loudly, just over the full\n// real set rather than a curated subset.\nconst headElementSchema = z.object({\n tag: z.enum([\"meta\", \"link\", \"script\", \"style\", \"title\", \"noscript\", \"base\"], {\n error:\n 'head element \"tag\" must be one of: meta, link, script, style, title, noscript, base',\n }),\n attrs: z.record(z.string(), z.string()).default({}),\n content: z.string().optional(),\n});\n\n// Mirrors `BannerProps` in types.ts. Layouts consume this directly off\n// `entry.data.banner` and render the `<Banner>` component with it, so the\n// schema is framework-owned (not user-extensible territory).\nconst bannerSchema = z.object({\n content: z.string({ error: 'banner \"content\" must be a string' }),\n type: z\n .enum([\"note\", \"tip\", \"caution\", \"danger\"], {\n error: 'banner \"type\" must be one of: note, tip, caution, danger',\n })\n .optional(),\n dismissible: z\n .object({\n id: z.string({\n error: 'banner \"dismissible.id\" must be a string — a stable identifier you bump when banner content meaningfully changes',\n }),\n days: z.number({ error: 'banner \"dismissible.days\" must be a number' }).optional(),\n })\n .optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Removed/renamed frontmatter keys — surface migration errors loudly\n// ---------------------------------------------------------------------------\n\n/**\n * Frontmatter keys the schema does not accept, mapped to a migration\n * message. Without this, Zod's default `.strip()` behavior would silently\n * drop an unrecognized key — the page would build, but with subtly\n * different behavior (the toggle just disappears). That's a confusing\n * failure mode for an authoring contract, so these fail loudly instead.\n *\n * `withFrontmatterKeyCheck` (below) consults this map. Hits get the\n * friendly migration message verbatim; everything else falls through to a\n * generic \"Unknown frontmatter key\" error so typos don't sneak past either.\n */\nconst REMOVED_FRONTMATTER_KEYS: Record<string, string> = {\n template:\n 'was renamed to \"mode\". Replace `template: \"doc\"` with `mode: \"doc\"`, and `template: \"splash\"` with `mode: \"custom\"`.',\n pagefind:\n 'was renamed to \"searchable\". Same boolean shape; the default now derives from `noindex` (a non-crawlable page is non-searchable unless you set `searchable: true` explicitly).',\n llms:\n \"was removed. Every published page is now listed in /llms.txt; use `noindex: true` to keep a page out of both search engines and the LLM index.\",\n aiDeprioritize:\n \"was removed. The framework no longer emits an agent-downrank signal. If you want a page hidden from agents, use `noindex: true`.\",\n hero:\n \"was removed. Compose your hero in the MDX body using user-owned components; there is no longer a `hero` frontmatter contract.\",\n};\n\n/**\n * Apply this AFTER any `.extend()` so user-added fields are recognized\n * as valid. Wraps the schema in `.passthrough().superRefine()` so removed\n * keys raise a guided migration error; other unknown keys raise a\n * generic error pointing at `defineSchema({ extend: ... })`.\n */\nfunction withFrontmatterKeyCheck<T extends z.ZodObject<z.ZodRawShape>>(schema: T) {\n return withStrictKeys(schema, {\n removedKeys: REMOVED_FRONTMATTER_KEYS,\n contextLabel: \"Frontmatter key\",\n unknownHint: (key) =>\n `If you meant to add a custom field, declare it in your collection's schema via \\`defineSchema({ extend: z.object({ ${key}: ... }) })\\`.`,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Base docs schema\n// ---------------------------------------------------------------------------\n\nfunction baseDocSchema() {\n return z.object({\n title: z.string({\n error: (iss) =>\n iss.input === undefined\n ? 'Missing required \"title\" in frontmatter. Every doc needs:\\n\\n ---\\n title: \"Your Page Title\"\\n ---'\n : `\"title\" must be a string, received ${typeof iss.input}`,\n }),\n description: z.string({ error: '\"description\" must be a string' }).optional(),\n mode: z\n .enum([\"doc\", \"custom\"], {\n error: '\"mode\" must be \"doc\" or \"custom\"',\n })\n .default(\"doc\"),\n sidebar: z.union([z.literal(false), sidebarSchema]).optional(),\n head: z.array(headElementSchema).default([]),\n banner: bannerSchema.optional(),\n draft: z.boolean({ error: '\"draft\" must be true or false' }).default(false),\n noindex: z.boolean({ error: '\"noindex\" must be true or false' }).default(false),\n /**\n * Whether this page is included in the site search index. When omitted,\n * derives from `noindex` (a page that's not crawlable is by default not\n * searchable). Set explicitly to override — e.g. `{ noindex: true,\n * searchable: true }` keeps the page out of search engines but findable\n * in the site's own search.\n */\n searchable: z\n .boolean({ error: '\"searchable\" must be true or false' })\n .optional(),\n tableOfContents: z\n .union([\n z.literal(false),\n z\n .object({\n minHeadingLevel: z\n .number({ error: '\"minHeadingLevel\" must be a number (1-6)' })\n .int()\n .min(1)\n .max(6)\n .default(2),\n maxHeadingLevel: z\n .number({ error: '\"maxHeadingLevel\" must be a number (1-6)' })\n .int()\n .min(1)\n .max(6)\n .default(3),\n })\n .refine((v) => v.minHeadingLevel <= v.maxHeadingLevel, {\n message: \"minHeadingLevel must be <= maxHeadingLevel\",\n }),\n ])\n .optional(),\n lastUpdated: z.coerce\n .date({ error: '\"lastUpdated\" must be a valid date (e.g. 2024-01-15)' })\n .optional(),\n /**\n * Explicit per-page social/OG image override (path or absolute URL).\n * When omitted, the page route is expected to fall back to a\n * programmatically-generated card or the site-wide `config.socialImage`.\n */\n socialImage: z\n .string({ error: '\"socialImage\" must be a string (path or URL)' })\n .optional(),\n prev: prevNextSchema,\n next: prevNextSchema,\n /**\n * Versioning rename escape hatch.\n *\n * When a page is renamed between versions (the URL slug changes), the\n * newer version's frontmatter declares the slug it had in an older\n * version. The framework uses this to link the pages as cross-version\n * alternates and to emit a `<link rel=\"canonical\">` to the current\n * version's URL.\n *\n * Example: `docs-v1/old-name.mdx` was renamed in v2 to `new-name.mdx`.\n * On the new page (`docs/new-name.mdx`, current version), set:\n *\n * previousSlug: old-name\n *\n * Now `/new-name` and `/v1/old-name` are linked as the same logical\n * page in `<head>` alternates, and the v1 page's canonical points to\n * `/new-name`.\n *\n * Accepts a single slug string (the page's id in the older version)\n * or an array of strings when the page has been renamed across more\n * than one version.\n */\n previousSlug: z\n .union([z.string(), z.array(z.string())], {\n error: '\"previousSlug\" must be a string or array of strings',\n })\n .optional(),\n /**\n * Rewrite this page's sidebar link to point at an external (or\n * cross-section) URL. The page still builds at its filesystem path —\n * `external_link` only changes how the sidebar links to it. The link\n * renders with `target=\"_blank\" rel=\"noopener\"` and is treated as\n * external by header/footer chrome.\n *\n * Must be either an absolute URL (`https://…`, `mailto:…`,\n * protocol-relative `//cdn.…`) or a site-absolute path (`/foo/bar`).\n * Relative strings (`\"foo\"`, `\"./bar\"`) and empty strings are\n * rejected — the sidebar builder consumes this directly as an\n * `<a href>`, and a relative href against the entry's own URL\n * would route somewhere unintended (typically into the entry's\n * own subtree). An empty string would produce an indexHref of\n * `\"\"` on group landings, breaking the link entirely.\n *\n * Useful to redirect deprecated pages to their replacements without\n * 301s.\n */\n external_link: z\n .string({\n error: '\"external_link\" must be a URL or absolute path',\n })\n .refine((v) => v.length > 0 && (isAbsoluteUrl(v) || v.startsWith(\"/\")), {\n message:\n '\"external_link\" must be a non-empty absolute URL (e.g. \"https://example.com/foo\") ' +\n 'or a site-absolute path (e.g. \"/replacement-page\"). ' +\n \"Relative paths are rejected because they'd resolve against the entry's own URL rather than where the author intended.\",\n })\n .optional(),\n });\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Build a customizable docs schema. Use this when composing schemas outside\n * the `docsCollection()` factory (e.g. multiple docs collections with\n * different shapes).\n *\n * For typed Astro `image()` fields or per-collection field narrowing, use\n * the richer `defineSchema(ctx => ...)` factory instead.\n */\nexport function defineDocSchema<\n TFields extends Record<string, z.ZodTypeAny> = Record<string, never>,\n>(config: DocSchemaConfig<TFields> = {}) {\n const base = baseDocSchema();\n // Always extend (with `{}` when no fields) so the result type is\n // `ZodObject<baseShape & TFields>` rather than a union of branches.\n // A union widens the consumer view of `entry.data.X` to the intersection\n // of branch fields, which is \"no fields\" for the false branch and\n // re-erases everything we just preserved.\n const merged = base.extend((config.fields ?? {}) as TFields);\n // Cast back to the underlying ZodObject. Runtime wrap (`.passthrough()\n // .superRefine()`) stays — the unknown-key check still fires. But tsdown\n // collapses ZodEffects emissions to `ZodObject<Record<string, ZodType<unknown>>>`,\n // erasing every framework field type at every consumer's `entry.data.X`\n // access. The cast preserves the field shapes through .d.ts emission.\n return withFrontmatterKeyCheck(merged) as unknown as typeof merged;\n}\n\n/**\n * Factory options for `defineSchema`.\n *\n * - `extend`: additional fields merged into the framework schema. Use\n * this for user-defined frontmatter (`author`, `tags`, `cover`).\n * - `narrow`: replaces framework fields with tighter types within this\n * collection. Use when a collection has stricter rules — e.g.\n * `{ mode: z.literal(\"doc\") }` says no landing pages in this collection.\n */\nexport interface DefineSchemaOptions {\n extend?: z.ZodTypeAny;\n narrow?: Record<string, z.ZodTypeAny>;\n}\n\n/**\n * Build a typed docs schema with access to the Astro `SchemaContext`.\n * Use this when you want typed image fields (`ctx.image()`), per-\n * collection narrowing of framework fields, or both. The simpler\n * `defineDocSchema({ fields })` factory is still available for the\n * common case of just adding fields.\n *\n * import { defineCollection } from \"astro:content\";\n * import { z } from \"astro/zod\";\n * import { defineSchema } from \"nimbus-docs/schemas\";\n *\n * export const collections = {\n * docs: defineCollection({\n * loader: ...,\n * schema: defineSchema((ctx) => ({\n * extend: z.object({\n * cover: ctx.image().optional(),\n * author: z.string().optional(),\n * }),\n * narrow: {\n * mode: z.literal(\"doc\"), // no landing pages here\n * },\n * })),\n * }),\n * };\n */\nexport function defineSchema(\n factory: (ctx: import(\"astro:content\").SchemaContext) => DefineSchemaOptions,\n) {\n return (ctx: import(\"astro:content\").SchemaContext) => {\n const { extend, narrow } = factory(ctx);\n let schema = baseDocSchema() as z.ZodObject<any>;\n\n // narrowing first (overrides framework fields)\n if (narrow) {\n schema = schema.extend(narrow);\n }\n\n // additive extension (new user fields). Prefer .merge for ZodObject\n // (preserves object-ness for downstream .extend); fall back to .and\n // for any other Zod type (intersection, union, etc.).\n if (extend) {\n if (extend instanceof z.ZodObject) {\n schema = schema.merge(extend);\n } else {\n // Intersection path — `.and()` returns ZodIntersection, on which\n // we can't run `withFrontmatterKeyCheck` (it operates on ZodObject's\n // `.shape`). Users on this path lose the removed-key migration\n // diagnostic; they own that trade-off by reaching for the\n // non-object extend.\n return schema.and(extend);\n }\n }\n\n return withFrontmatterKeyCheck(schema);\n };\n}\n\n/** Default docs schema. Equivalent to `defineDocSchema()`. */\nexport const docsSchema = defineDocSchema();\n\nconst partialsObjectSchema = z.object({\n /**\n * Declared parameters this partial accepts.\n * Suffix with `?` for optional params: `[\"name\", \"deprecated?\"]`\n */\n params: z.array(z.string()).optional(),\n});\n\n/** Schema for partials (`<Render file=\"...\" />` snippets). */\nexport const partialsSchema = partialsObjectSchema.default({});\n\n/**\n * Build a customizable partials schema. Mirrors `defineDocSchema` — use\n * when porting upstream partials that ship product-specific frontmatter\n * keys (e.g. CF's `inputParameters`) and you want them to validate without\n * editing the source files.\n *\n * import { z } from \"astro/zod\";\n * import { partialsCollection } from \"nimbus-docs/content\";\n *\n * defineCollection(partialsCollection({\n * schemaFields: { inputParameters: z.string().optional() },\n * }));\n */\nexport function definePartialsSchema<\n TFields extends Record<string, z.ZodTypeAny> = Record<string, never>,\n>(config: { fields?: TFields } = {}) {\n // Same generic preservation trick as `defineDocSchema` — always extend\n // (even with `{}`) so the result type stays `ZodObject<base & TFields>`\n // rather than a union with the no-fields branch erasing types.\n const merged = partialsObjectSchema.extend((config.fields ?? {}) as TFields);\n return merged as unknown as typeof merged;\n}\n\n// ---------------------------------------------------------------------------\n// Lenient variants — used by `nimbus-docs lint` (`nimbus/frontmatter-shape`).\n//\n// The standalone lint CLI can't yet see a site's extended\n// `content.config.ts` schema, so it validates the *types* of the fields\n// the framework owns while tolerating user-added fields (passthrough).\n// Unknown-key detection is deferred to when the engine can load the real\n// per-collection schema.\n// ---------------------------------------------------------------------------\n\n/** Docs frontmatter, framework fields type-checked, extra keys allowed. */\nexport const lenientDocsSchema = baseDocSchema().passthrough();\n\n/** Partials frontmatter, framework fields type-checked, extra keys allowed. */\nexport const lenientPartialsSchema = partialsObjectSchema.passthrough();\n\n// ---------------------------------------------------------------------------\n// Components collection — used by sites documenting their own UI components.\n// Pair with `componentsCollection()` from `nimbus-docs/content`. Authoring\n// pattern: hero `<Showcase>` block + `<Example>` blocks in the MDX body, with\n// `props` declared in frontmatter for a generated prop table.\n// ---------------------------------------------------------------------------\n\n/** One row in a component's `props` frontmatter array. */\nconst componentPropSchema = z.object({\n name: z.string({ error: 'prop needs a \"name\"' }),\n type: z.string({ error: 'prop needs a \"type\"' }),\n defaultValue: z.string().optional(),\n required: z.boolean().default(false),\n description: z.string({ error: 'prop needs a \"description\"' }),\n});\n\nexport type ComponentProp = z.infer<typeof componentPropSchema>;\n\n/** Default schema for the components collection. */\nexport const componentsSchema = z.object({\n title: z.string({\n error: (iss) =>\n iss.input === undefined\n ? 'Missing \"title\" in frontmatter — display name used in the sidebar and page header.'\n : `\"title\" must be a string, received ${typeof iss.input}`,\n }),\n tagline: z.string({\n error: (iss) =>\n iss.input === undefined\n ? 'Missing \"tagline\" in frontmatter — one-sentence summary shown under the title.'\n : `\"tagline\" must be a string, received ${typeof iss.input}`,\n }),\n props: z.array(componentPropSchema).default([]),\n});\n"],"mappings":";;;;;;;;;;;;;;;;;AAiCA,MAAM,qBAAqB,EAAE,MAAM,CACjC,EAAE,QAAQ,EACV,EAAE,OAAO;CACP,MAAM,EAAE,OAAO,EAAE,OAAO,wCAAsC,CAAC;CAC/D,SAAS,EACN,KACC;EAAC;EAAW;EAAQ;EAAQ;EAAW;EAAO;EAAW;EAAW;EAAS,EAC7E,EACE,OACE,2FACH,CACF,CACA,QAAQ,UAAU;CACtB,CAAC,CACH,CAAC;AAOF,MAAM,qBAAqB,EAAE,OAAO;CAElC,OAAO,EAAE,OAAO,EAAE,OAAO,4CAA0C,CAAC,CAAC,UAAU;CAE/E,OAAO,mBAAmB,UAAU;CACrC,CAAC;AAEF,MAAM,gBAAgB,EAAE,OAAO;CAC7B,OAAO,EAAE,OAAO,EAAE,OAAO,sCAAoC,CAAC,CAAC,UAAU;CACzE,OAAO,EAAE,OAAO,EAAE,OAAO,sCAAoC,CAAC,CAAC,UAAU;CACzE,OAAO,mBAAmB,UAAU;CACpC,QAAQ,EAAE,QAAQ,EAAE,OAAO,4CAA0C,CAAC,CAAC,UAAU;CACjF,cAAc,EACX,QAAQ,EAAE,OAAO,kDAAgD,CAAC,CAClE,UAAU;CAEb,OAAO,mBAAmB,UAAU;CACrC,CAAC;AAEF,MAAM,iBAAiB,EACpB,MAAM;CACL,EAAE,QAAQ;CACV,EAAE,OAAO;EAAE,MAAM,EAAE,QAAQ,CAAC,UAAU;EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU;EAAE,CAAC;CACvE,EAAE,QAAQ,MAAM;CACjB,CAAC,CACD,UAAU;AASb,MAAM,oBAAoB,EAAE,OAAO;CACjC,KAAK,EAAE,KAAK;EAAC;EAAQ;EAAQ;EAAU;EAAS;EAAS;EAAY;EAAO,EAAE,EAC5E,OACE,yFACH,CAAC;CACF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;CACnD,SAAS,EAAE,QAAQ,CAAC,UAAU;CAC/B,CAAC;AAKF,MAAM,eAAe,EAAE,OAAO;CAC5B,SAAS,EAAE,OAAO,EAAE,OAAO,uCAAqC,CAAC;CACjE,MAAM,EACH,KAAK;EAAC;EAAQ;EAAO;EAAW;EAAS,EAAE,EAC1C,OAAO,8DACR,CAAC,CACD,UAAU;CACb,aAAa,EACV,OAAO;EACN,IAAI,EAAE,OAAO,EACX,OAAO,sHACR,CAAC;EACF,MAAM,EAAE,OAAO,EAAE,OAAO,gDAA8C,CAAC,CAAC,UAAU;EACnF,CAAC,CACD,UAAU;CACd,CAAC;;;;;;;;;;;;AAiBF,MAAM,2BAAmD;CACvD,UACE;CACF,UACE;CACF,MACE;CACF,gBACE;CACF,MACE;CACH;;;;;;;AAQD,SAAS,wBAA8D,QAAW;AAChF,QAAO,eAAe,QAAQ;EAC5B,aAAa;EACb,cAAc;EACd,cAAc,QACZ,sHAAsH,IAAI;EAC7H,CAAC;;AAOJ,SAAS,gBAAgB;AACvB,QAAO,EAAE,OAAO;EACd,OAAO,EAAE,OAAO,EACd,QAAQ,QACN,IAAI,UAAU,SACV,8GACA,sCAAsC,OAAO,IAAI,SACxD,CAAC;EACF,aAAa,EAAE,OAAO,EAAE,OAAO,oCAAkC,CAAC,CAAC,UAAU;EAC7E,MAAM,EACH,KAAK,CAAC,OAAO,SAAS,EAAE,EACvB,OAAO,0CACR,CAAC,CACD,QAAQ,MAAM;EACjB,SAAS,EAAE,MAAM,CAAC,EAAE,QAAQ,MAAM,EAAE,cAAc,CAAC,CAAC,UAAU;EAC9D,MAAM,EAAE,MAAM,kBAAkB,CAAC,QAAQ,EAAE,CAAC;EAC5C,QAAQ,aAAa,UAAU;EAC/B,OAAO,EAAE,QAAQ,EAAE,OAAO,mCAAiC,CAAC,CAAC,QAAQ,MAAM;EAC3E,SAAS,EAAE,QAAQ,EAAE,OAAO,qCAAmC,CAAC,CAAC,QAAQ,MAAM;EAQ/E,YAAY,EACT,QAAQ,EAAE,OAAO,wCAAsC,CAAC,CACxD,UAAU;EACb,iBAAiB,EACd,MAAM,CACL,EAAE,QAAQ,MAAM,EAChB,EACG,OAAO;GACN,iBAAiB,EACd,OAAO,EAAE,OAAO,8CAA4C,CAAC,CAC7D,KAAK,CACL,IAAI,EAAE,CACN,IAAI,EAAE,CACN,QAAQ,EAAE;GACb,iBAAiB,EACd,OAAO,EAAE,OAAO,8CAA4C,CAAC,CAC7D,KAAK,CACL,IAAI,EAAE,CACN,IAAI,EAAE,CACN,QAAQ,EAAE;GACd,CAAC,CACD,QAAQ,MAAM,EAAE,mBAAmB,EAAE,iBAAiB,EACrD,SAAS,8CACV,CAAC,CACL,CAAC,CACD,UAAU;EACb,aAAa,EAAE,OACZ,KAAK,EAAE,OAAO,0DAAwD,CAAC,CACvE,UAAU;EAMb,aAAa,EACV,OAAO,EAAE,OAAO,kDAAgD,CAAC,CACjE,UAAU;EACb,MAAM;EACN,MAAM;EAuBN,cAAc,EACX,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,EACxC,OAAO,yDACR,CAAC,CACD,UAAU;EAoBb,eAAe,EACZ,OAAO,EACN,OAAO,oDACR,CAAC,CACD,QAAQ,MAAM,EAAE,SAAS,MAAM,cAAc,EAAE,IAAI,EAAE,WAAW,IAAI,GAAG,EACtE,SACE,qQAGH,CAAC,CACD,UAAU;EACd,CAAC;;;;;;;;;;AAeJ,SAAgB,gBAEd,SAAmC,EAAE,EAAE;AAavC,QAAO,wBAZM,eAAe,CAMR,OAAQ,OAAO,UAAU,EAAE,CAAa,CAMtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CxC,SAAgB,aACd,SACA;AACA,SAAQ,QAA+C;EACrD,MAAM,EAAE,QAAQ,WAAW,QAAQ,IAAI;EACvC,IAAI,SAAS,eAAe;AAG5B,MAAI,OACF,UAAS,OAAO,OAAO,OAAO;AAMhC,MAAI,OACF,KAAI,kBAAkB,EAAE,UACtB,UAAS,OAAO,MAAM,OAAO;MAO7B,QAAO,OAAO,IAAI,OAAO;AAI7B,SAAO,wBAAwB,OAAO;;;;AAK1C,MAAa,aAAa,iBAAiB;AAE3C,MAAM,uBAAuB,EAAE,OAAO,EAKpC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU,EACvC,CAAC;;AAGF,MAAa,iBAAiB,qBAAqB,QAAQ,EAAE,CAAC;;;;;;;;;;;;;;AAe9D,SAAgB,qBAEd,SAA+B,EAAE,EAAE;AAKnC,QADe,qBAAqB,OAAQ,OAAO,UAAU,EAAE,CAAa;;;AAe9E,MAAa,oBAAoB,eAAe,CAAC,aAAa;;AAG9D,MAAa,wBAAwB,qBAAqB,aAAa;;AAUvE,MAAM,sBAAsB,EAAE,OAAO;CACnC,MAAM,EAAE,OAAO,EAAE,OAAO,yBAAuB,CAAC;CAChD,MAAM,EAAE,OAAO,EAAE,OAAO,yBAAuB,CAAC;CAChD,cAAc,EAAE,QAAQ,CAAC,UAAU;CACnC,UAAU,EAAE,SAAS,CAAC,QAAQ,MAAM;CACpC,aAAa,EAAE,OAAO,EAAE,OAAO,gCAA8B,CAAC;CAC/D,CAAC;;AAKF,MAAa,mBAAmB,EAAE,OAAO;CACvC,OAAO,EAAE,OAAO,EACd,QAAQ,QACN,IAAI,UAAU,SACV,yFACA,sCAAsC,OAAO,IAAI,SACxD,CAAC;CACF,SAAS,EAAE,OAAO,EAChB,QAAQ,QACN,IAAI,UAAU,SACV,qFACA,wCAAwC,OAAO,IAAI,SAC1D,CAAC;CACF,OAAO,EAAE,MAAM,oBAAoB,CAAC,QAAQ,EAAE,CAAC;CAChD,CAAC"}
1
+ {"version":3,"file":"schemas.js","names":[],"sources":["../src/schemas.ts"],"sourcesContent":["/**\n * Content schemas for Nimbus.\n *\n * `docsSchema` is the default frontmatter contract for the `docs` collection.\n * `partialsSchema` is the contract for `<Render file=\"...\" />` partials.\n * `defineDocSchema(config)` returns a customizable schema for advanced users\n * composing schemas outside the `docsCollection()` factory.\n *\n * Error messages target content authors, not framework developers.\n * Astro 6 ships Zod v4 via `astro/zod`. The v4 API uses a single `error`\n * field on every schema constructor — NOT v3's `required_error` /\n * `invalid_type_error` / `errorMap`.\n */\n\nimport { z } from \"astro/zod\";\nimport { withStrictKeys } from \"./_internal/strict-keys.js\";\nimport { isAbsoluteUrl } from \"./_internal/url.js\";\n\nexport interface DocSchemaConfig<\n TFields extends Record<string, z.ZodTypeAny> = Record<string, never>,\n> {\n /**\n * Additional frontmatter fields merged into the default schema.\n * Generic-typed so the call-site shape is preserved through to\n * `entry.data.<field>` access in consumer code.\n */\n fields?: TFields;\n}\n\n// ---------------------------------------------------------------------------\n// Building blocks\n// ---------------------------------------------------------------------------\n\nconst sidebarBadgeSchema = z.union([\n z.string(),\n z.object({\n text: z.string({ error: 'sidebar badge needs a \"text\" field' }),\n variant: z\n .enum(\n [\"default\", \"info\", \"note\", \"success\", \"tip\", \"warning\", \"caution\", \"danger\"],\n {\n error:\n '\"variant\" must be one of: default, info, note, success, tip, warning, caution, danger',\n },\n )\n .default(\"default\"),\n }),\n]);\n\n// Group-level overrides for sidebar entries that act as a group label\n// (i.e. an `index.mdx` whose siblings become the group's children),\n// written as `sidebar: { group: { … } }`. Apply only when the entry is\n// the index of a directory containing other entries.\nconst sidebarGroupSchema = z.object({\n /** Override the group label (defaults to the directory name). */\n label: z.string({ error: '\"sidebar.group.label\" must be a string' }).optional(),\n /** Override the group badge (defaults to none). */\n badge: sidebarBadgeSchema.optional(),\n});\n\nconst sidebarSchema = z.object({\n order: z.number({ error: '\"sidebar.order\" must be a number' }).optional(),\n label: z.string({ error: '\"sidebar.label\" must be a string' }).optional(),\n badge: sidebarBadgeSchema.optional(),\n hidden: z.boolean({ error: '\"sidebar.hidden\" must be true or false' }).optional(),\n hideChildren: z\n .boolean({ error: '\"sidebar.hideChildren\" must be true or false' })\n .optional(),\n /** Group-level overrides; see `sidebarGroupSchema`. */\n group: sidebarGroupSchema.optional(),\n});\n\nconst prevNextSchema = z\n .union([\n z.string(),\n z.object({ link: z.string().optional(), label: z.string().optional() }),\n z.literal(false),\n ])\n .optional();\n\n// Head elements: every HTML tag that's valid as a direct child of <head>.\n// The earlier enum was meta/link/script/style only, which rejected the\n// equally-valid `title`, `noscript`, and `base` — needed on a page that\n// overrides the browser tab title via\n// `head: [{ tag: title, content: \"Overview\" }]`. Keeping it an enum (vs.\n// a free `z.string()`) so typos still fail loudly, just over the full\n// real set rather than a curated subset.\nconst headElementSchema = z.object({\n tag: z.enum([\"meta\", \"link\", \"script\", \"style\", \"title\", \"noscript\", \"base\"], {\n error:\n 'head element \"tag\" must be one of: meta, link, script, style, title, noscript, base',\n }),\n attrs: z.record(z.string(), z.string()).default({}),\n content: z.string().optional(),\n});\n\n// Mirrors `BannerProps` in types.ts. Layouts consume this directly off\n// `entry.data.banner` and render the `<Banner>` component with it, so the\n// schema is framework-owned (not user-extensible territory).\nconst bannerSchema = z.object({\n content: z.string({ error: 'banner \"content\" must be a string' }),\n type: z\n .enum([\"note\", \"tip\", \"caution\", \"danger\"], {\n error: 'banner \"type\" must be one of: note, tip, caution, danger',\n })\n .optional(),\n dismissible: z\n .object({\n id: z.string({\n error: 'banner \"dismissible.id\" must be a string — a stable identifier you bump when banner content meaningfully changes',\n }),\n days: z.number({ error: 'banner \"dismissible.days\" must be a number' }).optional(),\n })\n .optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Removed/renamed frontmatter keys — surface migration errors loudly\n// ---------------------------------------------------------------------------\n\n/**\n * Frontmatter keys the schema does not accept, mapped to a migration\n * message. Without this, Zod's default `.strip()` behavior would silently\n * drop an unrecognized key — the page would build, but with subtly\n * different behavior (the toggle just disappears). That's a confusing\n * failure mode for an authoring contract, so these fail loudly instead.\n *\n * `withFrontmatterKeyCheck` (below) consults this map. Hits get the\n * friendly migration message verbatim; everything else falls through to a\n * generic \"Unknown frontmatter key\" error so typos don't sneak past either.\n */\nconst REMOVED_FRONTMATTER_KEYS: Record<string, string> = {\n template:\n 'was renamed to \"mode\". Replace `template: \"doc\"` with `mode: \"doc\"`, and `template: \"splash\"` with `mode: \"custom\"`.',\n pagefind:\n 'was renamed to \"searchable\". Same boolean shape; the default now derives from `noindex` (a non-crawlable page is non-searchable unless you set `searchable: true` explicitly).',\n llms:\n \"was removed. Every published page is now listed in /llms.txt; use `noindex: true` to keep a page out of both search engines and the LLM index.\",\n aiDeprioritize:\n \"was removed. The framework no longer emits an agent-downrank signal. If you want a page hidden from agents, use `noindex: true`.\",\n hero:\n \"was removed. Compose your hero in the MDX body using user-owned components; there is no longer a `hero` frontmatter contract.\",\n};\n\n/**\n * Apply this AFTER any `.extend()` so user-added fields are recognized\n * as valid. Wraps the schema in `.passthrough().superRefine()` so removed\n * keys raise a guided migration error; other unknown keys raise a\n * generic error pointing at `defineSchema({ extend: ... })`.\n */\nfunction withFrontmatterKeyCheck<T extends z.ZodObject<z.ZodRawShape>>(schema: T) {\n return withStrictKeys(schema, {\n removedKeys: REMOVED_FRONTMATTER_KEYS,\n contextLabel: \"Frontmatter key\",\n unknownHint: (key) =>\n `If you meant to add a custom field, declare it in your collection's schema via \\`defineSchema({ extend: z.object({ ${key}: ... }) })\\`.`,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Base docs schema\n// ---------------------------------------------------------------------------\n\nfunction baseDocSchema() {\n return z.object({\n title: z.string({\n error: (iss) =>\n iss.input === undefined\n ? 'Missing required \"title\" in frontmatter. Every doc needs:\\n\\n ---\\n title: \"Your Page Title\"\\n ---'\n : `\"title\" must be a string, received ${typeof iss.input}`,\n }),\n description: z.string({ error: '\"description\" must be a string' }).optional(),\n mode: z\n .enum([\"doc\", \"custom\"], {\n error: '\"mode\" must be \"doc\" or \"custom\"',\n })\n .default(\"doc\"),\n sidebar: z.union([z.literal(false), sidebarSchema]).optional(),\n /**\n * Top-level alias of `sidebar.hideChildren`. When the page is a section\n * index, collapses the group to a single link. The nested\n * `sidebar.hideChildren` still works and takes precedence.\n */\n hideChildren: z\n .boolean({ error: '\"hideChildren\" must be true or false' })\n .optional(),\n head: z.array(headElementSchema).default([]),\n banner: bannerSchema.optional(),\n draft: z.boolean({ error: '\"draft\" must be true or false' }).default(false),\n noindex: z.boolean({ error: '\"noindex\" must be true or false' }).default(false),\n /**\n * Whether this page is included in the site search index. When omitted,\n * derives from `noindex` (a page that's not crawlable is by default not\n * searchable). Set explicitly to override — e.g. `{ noindex: true,\n * searchable: true }` keeps the page out of search engines but findable\n * in the site's own search.\n */\n searchable: z\n .boolean({ error: '\"searchable\" must be true or false' })\n .optional(),\n tableOfContents: z\n .union([\n z.literal(false),\n z\n .object({\n minHeadingLevel: z\n .number({ error: '\"minHeadingLevel\" must be a number (1-6)' })\n .int()\n .min(1)\n .max(6)\n .default(2),\n maxHeadingLevel: z\n .number({ error: '\"maxHeadingLevel\" must be a number (1-6)' })\n .int()\n .min(1)\n .max(6)\n .default(3),\n })\n .refine((v) => v.minHeadingLevel <= v.maxHeadingLevel, {\n message: \"minHeadingLevel must be <= maxHeadingLevel\",\n }),\n ])\n .optional(),\n lastUpdated: z.coerce\n .date({ error: '\"lastUpdated\" must be a valid date (e.g. 2024-01-15)' })\n .optional(),\n /**\n * Explicit per-page social/OG image override (path or absolute URL).\n * When omitted, the page route is expected to fall back to a\n * programmatically-generated card or the site-wide `config.socialImage`.\n */\n socialImage: z\n .string({ error: '\"socialImage\" must be a string (path or URL)' })\n .optional(),\n prev: prevNextSchema,\n next: prevNextSchema,\n /**\n * Versioning rename escape hatch.\n *\n * When a page is renamed between versions (the URL slug changes), the\n * newer version's frontmatter declares the slug it had in an older\n * version. The framework uses this to link the pages as cross-version\n * alternates and to emit a `<link rel=\"canonical\">` to the current\n * version's URL.\n *\n * Example: `docs-v1/old-name.mdx` was renamed in v2 to `new-name.mdx`.\n * On the new page (`docs/new-name.mdx`, current version), set:\n *\n * previousSlug: old-name\n *\n * Now `/new-name` and `/v1/old-name` are linked as the same logical\n * page in `<head>` alternates, and the v1 page's canonical points to\n * `/new-name`.\n *\n * Accepts a single slug string (the page's id in the older version)\n * or an array of strings when the page has been renamed across more\n * than one version.\n */\n previousSlug: z\n .union([z.string(), z.array(z.string())], {\n error: '\"previousSlug\" must be a string or array of strings',\n })\n .optional(),\n /**\n * Rewrite this page's sidebar link to point at an external (or\n * cross-section) URL. The page still builds at its filesystem path —\n * `external_link` only changes how the sidebar links to it. The link\n * renders with `target=\"_blank\" rel=\"noopener\"` and is treated as\n * external by header/footer chrome.\n *\n * Must be either an absolute URL (`https://…`, `mailto:…`,\n * protocol-relative `//cdn.…`) or a site-absolute path (`/foo/bar`).\n * Relative strings (`\"foo\"`, `\"./bar\"`) and empty strings are\n * rejected — the sidebar builder consumes this directly as an\n * `<a href>`, and a relative href against the entry's own URL\n * would route somewhere unintended (typically into the entry's\n * own subtree). An empty string would produce an indexHref of\n * `\"\"` on group landings, breaking the link entirely.\n *\n * Useful to redirect deprecated pages to their replacements without\n * 301s.\n */\n external_link: z\n .string({\n error: '\"external_link\" must be a URL or absolute path',\n })\n .refine((v) => v.length > 0 && (isAbsoluteUrl(v) || v.startsWith(\"/\")), {\n message:\n '\"external_link\" must be a non-empty absolute URL (e.g. \"https://example.com/foo\") ' +\n 'or a site-absolute path (e.g. \"/replacement-page\"). ' +\n \"Relative paths are rejected because they'd resolve against the entry's own URL rather than where the author intended.\",\n })\n .optional(),\n });\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Build a customizable docs schema. Use this when composing schemas outside\n * the `docsCollection()` factory (e.g. multiple docs collections with\n * different shapes).\n *\n * For typed Astro `image()` fields or per-collection field narrowing, use\n * the richer `defineSchema(ctx => ...)` factory instead.\n */\nexport function defineDocSchema<\n TFields extends Record<string, z.ZodTypeAny> = Record<string, never>,\n>(config: DocSchemaConfig<TFields> = {}) {\n const base = baseDocSchema();\n // Always extend (with `{}` when no fields) so the result type is\n // `ZodObject<baseShape & TFields>` rather than a union of branches.\n // A union widens the consumer view of `entry.data.X` to the intersection\n // of branch fields, which is \"no fields\" for the false branch and\n // re-erases everything we just preserved.\n const merged = base.extend((config.fields ?? {}) as TFields);\n // Cast back to the underlying ZodObject. Runtime wrap (`.passthrough()\n // .superRefine()`) stays — the unknown-key check still fires. But tsdown\n // collapses ZodEffects emissions to `ZodObject<Record<string, ZodType<unknown>>>`,\n // erasing every framework field type at every consumer's `entry.data.X`\n // access. The cast preserves the field shapes through .d.ts emission.\n return withFrontmatterKeyCheck(merged) as unknown as typeof merged;\n}\n\n/**\n * Factory options for `defineSchema`.\n *\n * - `extend`: additional fields merged into the framework schema. Use\n * this for user-defined frontmatter (`author`, `tags`, `cover`).\n * - `narrow`: replaces framework fields with tighter types within this\n * collection. Use when a collection has stricter rules — e.g.\n * `{ mode: z.literal(\"doc\") }` says no landing pages in this collection.\n */\nexport interface DefineSchemaOptions {\n extend?: z.ZodTypeAny;\n narrow?: Record<string, z.ZodTypeAny>;\n}\n\n/**\n * Build a typed docs schema with access to the Astro `SchemaContext`.\n * Use this when you want typed image fields (`ctx.image()`), per-\n * collection narrowing of framework fields, or both. The simpler\n * `defineDocSchema({ fields })` factory is still available for the\n * common case of just adding fields.\n *\n * import { defineCollection } from \"astro:content\";\n * import { z } from \"astro/zod\";\n * import { defineSchema } from \"nimbus-docs/schemas\";\n *\n * export const collections = {\n * docs: defineCollection({\n * loader: ...,\n * schema: defineSchema((ctx) => ({\n * extend: z.object({\n * cover: ctx.image().optional(),\n * author: z.string().optional(),\n * }),\n * narrow: {\n * mode: z.literal(\"doc\"), // no landing pages here\n * },\n * })),\n * }),\n * };\n */\nexport function defineSchema(\n factory: (ctx: import(\"astro:content\").SchemaContext) => DefineSchemaOptions,\n) {\n return (ctx: import(\"astro:content\").SchemaContext) => {\n const { extend, narrow } = factory(ctx);\n let schema = baseDocSchema() as z.ZodObject<any>;\n\n // narrowing first (overrides framework fields)\n if (narrow) {\n schema = schema.extend(narrow);\n }\n\n // additive extension (new user fields). Prefer .merge for ZodObject\n // (preserves object-ness for downstream .extend); fall back to .and\n // for any other Zod type (intersection, union, etc.).\n if (extend) {\n if (extend instanceof z.ZodObject) {\n schema = schema.merge(extend);\n } else {\n // Intersection path — `.and()` returns ZodIntersection, on which\n // we can't run `withFrontmatterKeyCheck` (it operates on ZodObject's\n // `.shape`). Users on this path lose the removed-key migration\n // diagnostic; they own that trade-off by reaching for the\n // non-object extend.\n return schema.and(extend);\n }\n }\n\n return withFrontmatterKeyCheck(schema);\n };\n}\n\n/** Default docs schema. Equivalent to `defineDocSchema()`. */\nexport const docsSchema = defineDocSchema();\n\nconst partialsObjectSchema = z.object({\n /**\n * Declared parameters this partial accepts.\n * Suffix with `?` for optional params: `[\"name\", \"deprecated?\"]`\n */\n params: z.array(z.string()).optional(),\n});\n\n/** Schema for partials (`<Render file=\"...\" />` snippets). */\nexport const partialsSchema = partialsObjectSchema.default({});\n\n/**\n * Build a customizable partials schema. Mirrors `defineDocSchema` — use\n * when porting upstream partials that ship product-specific frontmatter\n * keys (e.g. CF's `inputParameters`) and you want them to validate without\n * editing the source files.\n *\n * import { z } from \"astro/zod\";\n * import { partialsCollection } from \"nimbus-docs/content\";\n *\n * defineCollection(partialsCollection({\n * schemaFields: { inputParameters: z.string().optional() },\n * }));\n */\nexport function definePartialsSchema<\n TFields extends Record<string, z.ZodTypeAny> = Record<string, never>,\n>(config: { fields?: TFields } = {}) {\n // Same generic preservation trick as `defineDocSchema` — always extend\n // (even with `{}`) so the result type stays `ZodObject<base & TFields>`\n // rather than a union with the no-fields branch erasing types.\n const merged = partialsObjectSchema.extend((config.fields ?? {}) as TFields);\n return merged as unknown as typeof merged;\n}\n\n// ---------------------------------------------------------------------------\n// Lenient variants — used by `nimbus-docs lint` (`nimbus/frontmatter-shape`).\n//\n// The standalone lint CLI can't yet see a site's extended\n// `content.config.ts` schema, so it validates the *types* of the fields\n// the framework owns while tolerating user-added fields (passthrough).\n// Unknown-key detection is deferred to when the engine can load the real\n// per-collection schema.\n// ---------------------------------------------------------------------------\n\n/** Docs frontmatter, framework fields type-checked, extra keys allowed. */\nexport const lenientDocsSchema = baseDocSchema().passthrough();\n\n/** Partials frontmatter, framework fields type-checked, extra keys allowed. */\nexport const lenientPartialsSchema = partialsObjectSchema.passthrough();\n\n// ---------------------------------------------------------------------------\n// Components collection — used by sites documenting their own UI components.\n// Pair with `componentsCollection()` from `nimbus-docs/content`. Authoring\n// pattern: hero `<Showcase>` block + `<Example>` blocks in the MDX body, with\n// `props` declared in frontmatter for a generated prop table.\n// ---------------------------------------------------------------------------\n\n/** One row in a component's `props` frontmatter array. */\nconst componentPropSchema = z.object({\n name: z.string({ error: 'prop needs a \"name\"' }),\n type: z.string({ error: 'prop needs a \"type\"' }),\n defaultValue: z.string().optional(),\n required: z.boolean().default(false),\n description: z.string({ error: 'prop needs a \"description\"' }),\n});\n\nexport type ComponentProp = z.infer<typeof componentPropSchema>;\n\n/** Default schema for the components collection. */\nexport const componentsSchema = z.object({\n title: z.string({\n error: (iss) =>\n iss.input === undefined\n ? 'Missing \"title\" in frontmatter — display name used in the sidebar and page header.'\n : `\"title\" must be a string, received ${typeof iss.input}`,\n }),\n tagline: z.string({\n error: (iss) =>\n iss.input === undefined\n ? 'Missing \"tagline\" in frontmatter — one-sentence summary shown under the title.'\n : `\"tagline\" must be a string, received ${typeof iss.input}`,\n }),\n props: z.array(componentPropSchema).default([]),\n});\n"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { a as Severity, i as RuleCode, n as Diagnostic, o as SeverityConfig, r as DiagnosticFix, t as AuthoringRuleCode } from "./diagnostic-CnxJwVpT.js";
2
+ import { HastPluginInput, MdastPluginInput } from "satteri";
2
3
 
3
4
  //#region src/types.d.ts
4
5
  /**
@@ -204,6 +205,19 @@ interface SidebarConfig {
204
205
  * @default "full"
205
206
  */
206
207
  scope?: "full" | "section";
208
+ /**
209
+ * Isolate the rail below the top-level section, so a sub-path becomes its
210
+ * own rail. `boundaries` is a list of segment globs (`*` matches one
211
+ * segment); a page under a matched boundary has its rail descended to the
212
+ * group covering that prefix. Matching is by descendant href, so it works
213
+ * for index-less folders. Pairs with `scope: "section"`; a non-matching
214
+ * page is unaffected.
215
+ *
216
+ * @example { boundaries: ["guides/*"] }
217
+ */
218
+ isolate?: {
219
+ boundaries: string[];
220
+ };
207
221
  /**
208
222
  * Collapse every autogenerated group by default. When `true`, all
209
223
  * groups in the sidebar render closed initially; the group that
@@ -277,6 +291,18 @@ type SidebarConfigItem = string | {
277
291
  items: SidebarConfigItem[];
278
292
  collapsed?: boolean;
279
293
  badge?: SidebarBadge;
294
+ /**
295
+ * The URL prefix this group occupies (e.g. `/api`). Marks the group as
296
+ * a section that owns a URL segment which may have no page of its own.
297
+ * Used with `landing`.
298
+ */
299
+ segment?: string;
300
+ /**
301
+ * Where the group's label links. May differ from `segment` when the
302
+ * segment URL itself has no page. Becomes the group's `indexHref`, so
303
+ * breadcrumbs and the rail point at a real page rather than a dead URL.
304
+ */
305
+ landing?: string;
280
306
  };
281
307
  type BadgeVariant = "default" | "info" | "note" | "success" | "tip" | "warning" | "caution" | "danger";
282
308
  type SidebarBadge = string | {
@@ -308,14 +334,11 @@ interface SidebarGroupItem {
308
334
  children: SidebarItem[];
309
335
  _indexId?: string;
310
336
  /**
311
- * URL of the group's landing page (the directory's `index.mdx`), when
312
- * one exists. When set, the renderer should make the group label
313
- * clickable (matching the Fumadocs / Fern / Docusaurus pattern where
314
- * the group label IS the link to the landing page, and the landing
315
- * page is NOT duplicated as a child of the group).
316
- *
317
- * When `undefined`, the group has no landing page and the label is
318
- * a non-interactive header — children are the only navigable items.
337
+ * URL of the group's landing page (the directory's `index.mdx`), when one
338
+ * exists. When set, the renderer makes the group label a link to the
339
+ * landing page, which is not duplicated as a child of the group. When
340
+ * `undefined`, the label is a non-interactive header and only the
341
+ * children navigate.
319
342
  */
320
343
  indexHref?: string;
321
344
  /** True when the group's landing page is the current route. */
@@ -328,6 +351,13 @@ interface SidebarGroupItem {
328
351
  * When omitted/false, `indexHref` is an in-site path.
329
352
  */
330
353
  indexIsExternal?: boolean;
354
+ /**
355
+ * The URL prefix this group occupies, when declared as a synthetic
356
+ * section via the config `segment` key (e.g. `/ai`). Lets a section own
357
+ * a URL segment that has no page of its own; the clickable landing lives
358
+ * on `indexHref`.
359
+ */
360
+ segment?: string;
331
361
  /**
332
362
  * Internal: the URL prefix where this group's content lives, when
333
363
  * derived from an `autogenerate` config item. `deriveSidebarSections`
@@ -340,6 +370,22 @@ interface SidebarGroupItem {
340
370
  _prefix?: string;
341
371
  }
342
372
  type SidebarItem = SidebarLinkItem | SidebarExternalLinkItem | SidebarGroupItem;
373
+ /**
374
+ * A pass over the final sidebar tree (after scope and isolate), returning
375
+ * the transformed tree. Passed to `getSidebar` as an argument rather than
376
+ * via config, which is JSON-serialized and cannot carry functions.
377
+ *
378
+ * `sectionSlug` is seg0 and `module` is seg1 of the current path;
379
+ * `indexEntryId` is the active section group's landing entry id, or
380
+ * `undefined` for an index-less section.
381
+ */
382
+ type SidebarTransform = (ctx: {
383
+ tree: SidebarItem[];
384
+ sectionSlug: string;
385
+ module?: string;
386
+ currentSlug: string;
387
+ indexEntryId?: string;
388
+ }) => SidebarItem[] | Promise<SidebarItem[]>;
343
389
  interface TOCItem {
344
390
  depth: number;
345
391
  text: string;
@@ -347,7 +393,12 @@ interface TOCItem {
347
393
  }
348
394
  interface Breadcrumb {
349
395
  label: string;
350
- href: string;
396
+ /**
397
+ * Destination URL. Optional: a crumb for a node with no landing page
398
+ * (e.g. an index-less folder) has no `href` and renders non-interactive.
399
+ * Renderers must emit a `<span>` when `href` is absent.
400
+ */
401
+ href?: string;
351
402
  }
352
403
  interface PrevNextLink {
353
404
  label: string;
@@ -487,5 +538,5 @@ interface DocsPageProps extends BasePageProps {
487
538
  prevNext: PrevNext;
488
539
  }
489
540
  //#endregion
490
- export { type AuthoringRuleCode, BadgeVariant, BannerProps, BasePageProps, Breadcrumb, type Diagnostic, type DiagnosticFix, DocsPageProps, FeaturesConfig, HeadElement, NimbusConfig, PrevNext, PrevNextLink, PrevNextOverrides, ResolvedVersions, type RuleCode, SearchConfig, SearchProvider, SearchResult, type Severity, type SeverityConfig, SidebarBadge, SidebarConfig, SidebarConfigItem, SidebarExternalLinkItem, SidebarGroupItem, SidebarItem, SidebarLinkItem, SidebarSection, TOCItem, VersionAlternateRecord, VersionAlternatesTable, VersionPageRef, VersionStatus, VersionsConfig };
541
+ export { type AuthoringRuleCode, BadgeVariant, BannerProps, BasePageProps, Breadcrumb, type Diagnostic, type DiagnosticFix, DocsPageProps, FeaturesConfig, type HastPluginInput, HeadElement, type MdastPluginInput, NimbusConfig, PrevNext, PrevNextLink, PrevNextOverrides, ResolvedVersions, type RuleCode, SearchConfig, SearchProvider, SearchResult, type Severity, type SeverityConfig, SidebarBadge, SidebarConfig, SidebarConfigItem, SidebarExternalLinkItem, SidebarGroupItem, SidebarItem, SidebarLinkItem, SidebarSection, SidebarTransform, TOCItem, VersionAlternateRecord, VersionAlternatesTable, VersionPageRef, VersionStatus, VersionsConfig };
491
542
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nimbus-docs",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Docs, for humans and agents",
@@ -46,6 +46,10 @@
46
46
  "types": "./dist/client.d.ts",
47
47
  "import": "./dist/client.js"
48
48
  },
49
+ "./markdown": {
50
+ "types": "./dist/markdown.d.ts",
51
+ "import": "./dist/markdown.js"
52
+ },
49
53
  "./react": {
50
54
  "types": "./dist/react.d.ts",
51
55
  "import": "./dist/react.js"
@@ -60,12 +64,6 @@
60
64
  "dist",
61
65
  "src/components"
62
66
  ],
63
- "scripts": {
64
- "build": "tsdown",
65
- "dev": "tsdown --watch",
66
- "typecheck": "tsc --noEmit",
67
- "test": "node --import tsx --test \"test/**/*.test.ts\""
68
- },
69
67
  "peerDependencies": {
70
68
  "astro": ">=6.4.0",
71
69
  "react": ">=19.0.0",
@@ -104,13 +102,21 @@
104
102
  "yaml": "^2.7.1"
105
103
  },
106
104
  "devDependencies": {
105
+ "@mdx-js/mdx": "^3.1.1",
107
106
  "@shikijs/types": "^4.1.0",
108
107
  "@types/react": "^19.2.6",
109
108
  "@types/react-dom": "^19.2.3",
110
109
  "astro": "^6.4.0",
111
110
  "jsdom": "^29.1.1",
111
+ "shiki": "^4.2.0",
112
112
  "tsdown": "^0.20.3",
113
113
  "tsx": "^4.22.3",
114
114
  "typescript": "^5.8.3"
115
+ },
116
+ "scripts": {
117
+ "build": "tsdown",
118
+ "dev": "tsdown --watch",
119
+ "typecheck": "tsc --noEmit",
120
+ "test": "node --import tsx --test \"test/**/*.test.ts\""
115
121
  }
116
- }
122
+ }