@cudoment/cudoc 0.1.0 → 0.2.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 (101) hide show
  1. package/README.md +20 -47
  2. package/dist/dataset.d.ts +10 -0
  3. package/dist/dataset.d.ts.map +1 -0
  4. package/dist/dataset.js +44 -0
  5. package/dist/dataset.js.map +1 -0
  6. package/dist/document.d.ts +74 -0
  7. package/dist/document.d.ts.map +1 -0
  8. package/dist/document.js +435 -0
  9. package/dist/document.js.map +1 -0
  10. package/dist/internal/core/ast/validate.d.ts.map +1 -1
  11. package/dist/internal/core/ast/validate.js +9 -2
  12. package/dist/internal/core/ast/validate.js.map +1 -1
  13. package/dist/internal/core/query/nodes.d.ts.map +1 -1
  14. package/dist/internal/core/query/nodes.js +3 -1
  15. package/dist/internal/core/query/nodes.js.map +1 -1
  16. package/dist/internal/core/query/sections.d.ts.map +1 -1
  17. package/dist/internal/core/query/sections.js +2 -1
  18. package/dist/internal/core/query/sections.js.map +1 -1
  19. package/dist/internal/core/syntax/heading-metadata.js +1 -1
  20. package/dist/internal/core/syntax/heading-metadata.js.map +1 -1
  21. package/dist/internal/transforms/table-cell-list/build-table-cell-children.d.ts +5 -0
  22. package/dist/internal/transforms/table-cell-list/build-table-cell-children.d.ts.map +1 -0
  23. package/dist/internal/transforms/table-cell-list/build-table-cell-children.js +169 -0
  24. package/dist/internal/transforms/table-cell-list/build-table-cell-children.js.map +1 -0
  25. package/dist/internal/transforms/table-cell-list/elements.d.ts +15 -0
  26. package/dist/internal/transforms/table-cell-list/elements.d.ts.map +1 -0
  27. package/dist/internal/transforms/table-cell-list/elements.js +16 -0
  28. package/dist/internal/transforms/table-cell-list/elements.js.map +1 -0
  29. package/dist/internal/transforms/table-cell-list/index.d.ts +18 -0
  30. package/dist/internal/transforms/table-cell-list/index.d.ts.map +1 -0
  31. package/dist/internal/transforms/table-cell-list/index.js +45 -0
  32. package/dist/internal/transforms/table-cell-list/index.js.map +1 -0
  33. package/dist/internal/transforms/table-cell-list/nodes.d.ts +9 -0
  34. package/dist/internal/transforms/table-cell-list/nodes.d.ts.map +1 -0
  35. package/dist/internal/transforms/table-cell-list/nodes.js +24 -0
  36. package/dist/internal/transforms/table-cell-list/nodes.js.map +1 -0
  37. package/dist/internal/transforms/table-cell-list/parse-inline-markdown.d.ts +6 -0
  38. package/dist/internal/transforms/table-cell-list/parse-inline-markdown.d.ts.map +1 -0
  39. package/dist/internal/transforms/table-cell-list/parse-inline-markdown.js +101 -0
  40. package/dist/internal/transforms/table-cell-list/parse-inline-markdown.js.map +1 -0
  41. package/dist/internal/transforms/table-cell-list/parse-table-cell-list.d.ts +22 -0
  42. package/dist/internal/transforms/table-cell-list/parse-table-cell-list.d.ts.map +1 -0
  43. package/dist/internal/transforms/table-cell-list/parse-table-cell-list.js +315 -0
  44. package/dist/internal/transforms/table-cell-list/parse-table-cell-list.js.map +1 -0
  45. package/dist/internal/transforms/table-column-layout/create-table.d.ts +45 -0
  46. package/dist/internal/transforms/table-column-layout/create-table.d.ts.map +1 -0
  47. package/dist/internal/transforms/table-column-layout/create-table.js +121 -0
  48. package/dist/internal/transforms/table-column-layout/create-table.js.map +1 -0
  49. package/dist/internal/transforms/table-column-layout/index.d.ts +51 -0
  50. package/dist/internal/transforms/table-column-layout/index.d.ts.map +1 -0
  51. package/dist/internal/transforms/table-column-layout/index.js +96 -0
  52. package/dist/internal/transforms/table-column-layout/index.js.map +1 -0
  53. package/dist/internal/transforms/table-column-layout/split-cell.d.ts +24 -0
  54. package/dist/internal/transforms/table-column-layout/split-cell.d.ts.map +1 -0
  55. package/dist/internal/transforms/table-column-layout/split-cell.js +219 -0
  56. package/dist/internal/transforms/table-column-layout/split-cell.js.map +1 -0
  57. package/dist/markdown.d.ts +10 -0
  58. package/dist/markdown.d.ts.map +1 -0
  59. package/dist/markdown.js +47 -0
  60. package/dist/markdown.js.map +1 -0
  61. package/dist/node/cli.d.ts +3 -0
  62. package/dist/node/cli.d.ts.map +1 -0
  63. package/dist/node/cli.js +37 -0
  64. package/dist/node/cli.js.map +1 -0
  65. package/dist/node/dataset.d.ts +19 -0
  66. package/dist/node/dataset.d.ts.map +1 -0
  67. package/dist/node/dataset.js +51 -0
  68. package/dist/node/dataset.js.map +1 -0
  69. package/dist/node/library.d.ts +56 -0
  70. package/dist/node/library.d.ts.map +1 -0
  71. package/dist/node/library.js +163 -0
  72. package/dist/node/library.js.map +1 -0
  73. package/dist/node/paths.d.ts.map +1 -1
  74. package/dist/node/paths.js +1 -1
  75. package/dist/node/paths.js.map +1 -1
  76. package/dist/node/prepare-embeds.d.ts +13 -0
  77. package/dist/node/prepare-embeds.d.ts.map +1 -0
  78. package/dist/node/prepare-embeds.js +54 -0
  79. package/dist/node/prepare-embeds.js.map +1 -0
  80. package/dist/node/resolve-embed.d.ts +33 -0
  81. package/dist/node/resolve-embed.d.ts.map +1 -0
  82. package/dist/node/resolve-embed.js +386 -0
  83. package/dist/node/resolve-embed.js.map +1 -0
  84. package/dist/node/storage.d.ts +10 -0
  85. package/dist/node/storage.d.ts.map +1 -0
  86. package/dist/node/storage.js +85 -0
  87. package/dist/node/storage.js.map +1 -0
  88. package/dist/query.d.ts +1 -0
  89. package/dist/query.d.ts.map +1 -1
  90. package/dist/query.js +1 -0
  91. package/dist/query.js.map +1 -1
  92. package/dist/render.d.ts +11 -0
  93. package/dist/render.d.ts.map +1 -0
  94. package/dist/render.js +63 -0
  95. package/dist/render.js.map +1 -0
  96. package/dist/sections.d.ts +15 -0
  97. package/dist/sections.d.ts.map +1 -0
  98. package/dist/sections.js +40 -0
  99. package/dist/sections.js.map +1 -0
  100. package/package.json +66 -5
  101. package/styles.css +34 -0
package/README.md CHANGED
@@ -1,58 +1,31 @@
1
1
  # @cudoment/cudoc
2
2
 
3
- Reuse document sections and tables from compiled MDX ASTs. Export a snapshot during compilation, load it on the server, select content by a stable anchor and render it with your site's components.
3
+ Markdown document semantics, compilation, AST queries, cross-document embedding and dataset projection.
4
4
 
5
- ```bash
6
- npm install @cudoment/cudoc
7
- ```
8
-
9
- ## Embedding
10
-
11
- Add the export plugin after the transforms whose results you want to store:
5
+ ESM · Node.js 20+
12
6
 
13
- ```js
14
- import exportAst from "@cudoment/cudoc/embed"
15
-
16
- const remarkPlugins = [
17
- // Your remark transforms go here.
18
- [exportAst, { sourceRoot: "docs", outDir: ".cudoc/ast" }],
19
- ]
7
+ ```sh
8
+ npm install @cudoment/cudoc
20
9
  ```
21
10
 
22
- Once the source document has compiled, read it in a server component or build script:
23
-
24
11
  ```js
25
- import { loadAst, sliceSectionByAnchorId } from "@cudoment/cudoc/embed"
26
-
27
- const document = loadAst("guide/limits", { outDir: ".cudoc/ast" })
28
- const section = sliceSectionByAnchorId(document, "rate-limits")
29
- if (!section) throw new Error("Missing section: rate-limits")
30
- // Render section.children with your site's components.
12
+ import { compileDocument } from "@cudoment/cudoc/markdown"
13
+ import { renderDocument } from "@cudoment/cudoc/render"
14
+
15
+ const { tree } = compileDocument(
16
+ "## Setup (#setup)\n\n> [!NOTE] Requirements\n> Node.js 20+.",
17
+ { format: "md", syntax: {} },
18
+ )
19
+ const html = renderDocument(tree)
31
20
  ```
32
21
 
33
- The snapshot is the host's remark tree at the export plugin. Later host transforms and MDX component execution are outside it. Export and load validate the same AST contract and schema version. Section slices preserve referenced link, image and footnote definitions.
34
-
35
- Source compilation must finish before loading an embed. Keep compiler caches and exported ASTs together, and include the JSON files in deployments that read them at runtime. Queries do not execute MDX expressions; rendering and missing-reference policy belong to the consuming site.
36
-
37
- ## Entry points
38
-
39
- | Import | Runtime | Purpose |
40
- | ---------------------------------------------------------------------- | --------------- | ------------------------------------------------------- |
41
- | `@cudoment/cudoc` | Browser or Node | AST contract, validation, traversal, syntax and queries |
42
- | `@cudoment/cudoc/query` | Browser or Node | Sections, headings, text and table queries |
43
- | `@cudoment/cudoc/ast`, `@cudoment/cudoc/syntax`, `@cudoment/cudoc/mdx` | Browser or Node | Focused common APIs |
44
- | `@cudoment/cudoc/embed` | Node | AST export, loading and queries together |
45
- | `@cudoment/cudoc/node/load-ast-file` | Node | Load a known JSON file without build-time path mapping |
46
- | `@cudoment/cudoc/node/export-ast`, `@cudoment/cudoc/node/paths` | Node | Focused export and path APIs |
47
-
48
- All entries share one internal core. Internal source paths are not public exports and the core is not a separate npm package. Browser imports never depend on the Node entry points.
49
-
50
- For a server bundle that traces files, use `loadAstFile` from `@cudoment/cudoc/node/load-ast-file` with a concrete file path and configure your host's output file tracing.
51
-
52
- The optional `cudoc-remark`, `cudoc-docusaurus` and `cudoc-nextra` packages provide syntax transforms and host integration. Their publication is separate from this package.
53
-
54
- See the [embedding guide](https://github.com/cudoment/cudoc/blob/main/docs/embedding.md) and [project README](https://github.com/cudoment/cudoc#readme).
22
+ The root and query APIs provide reusable AST operations. Import compilation from `/markdown`, rendering from `/render`, and collection from `/node/library`. Node entry points belong in build/server code. `/embed` handles individual AST snapshots; complete libraries and fenced embeds use the explicit `node/*` APIs. The core has no React runtime dependency.
55
23
 
56
- ## License
24
+ Choose `host`, `cudoc` or `both` independently for `headingAnchor`, `badge`, `tableCellList`, `callout` and `link`. The representative callout is `> [!NOTE] Title`. Authors do not register cudoc React components in the recommended setup. Syntax-only rendering needs no stored JSON; cross-document embedding requires document collection.
57
25
 
58
- [MIT](./LICENSE)
26
+ - [Usage guide](https://github.com/cudoment/cudoc/tree/main/README.md#getting-started) · [한국어 가이드](https://github.com/cudoment/cudoc/tree/main/README.ko.md#시작하기)
27
+ - [Markdown syntax](https://github.com/cudoment/cudoc/tree/main/docs/syntax.md)
28
+ - [Embedding](https://github.com/cudoment/cudoc/tree/main/docs/embedding.md)
29
+ - [Standalone HTML alongside a host](https://github.com/cudoment/cudoc/tree/main/docs/html.md#export-alongside-an-existing-site)
30
+ - [API reference](https://github.com/cudoment/cudoc/tree/main/docs/api-reference/README.md)
31
+ - [Runnable examples](https://github.com/cudoment/cudoc/tree/main/examples/README.md)
@@ -0,0 +1,10 @@
1
+ import type { Root } from "mdast";
2
+ export type ProjectionOptions = {
3
+ excludeNodeTypes?: string[];
4
+ excludeComponents?: string[];
5
+ stripProperties?: string[];
6
+ };
7
+ export declare const docsDatasetProjection: ProjectionOptions;
8
+ /** Immutable recursive projection of already compiled ASTs, including nested nodes. */
9
+ export declare function projectAst(tree: Root, options?: ProjectionOptions): Root;
10
+ //# sourceMappingURL=dataset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset.d.ts","sourceRoot":"","sources":["../src/dataset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAIjC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B,CAAA;AACD,eAAO,MAAM,qBAAqB,EAAE,iBAUnC,CAAA;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,iBAAsB,GAAG,IAAI,CAgC5E"}
@@ -0,0 +1,44 @@
1
+ import { validateAstContract } from "./internal/core/ast/validate.js";
2
+ export const docsDatasetProjection = {
3
+ excludeComponents: [
4
+ "Table",
5
+ "TableHeader",
6
+ "TableBody",
7
+ "TableRow",
8
+ "TableHead",
9
+ "TableCell",
10
+ "DocDataEmbed",
11
+ ],
12
+ };
13
+ /** Immutable recursive projection of already compiled ASTs, including nested nodes. */
14
+ export function projectAst(tree, options = {}) {
15
+ validateAstContract(tree);
16
+ const strip = new Set(options.stripProperties ?? []);
17
+ if (["type", "children"].some((key) => strip.has(key)))
18
+ throw new Error("cudoc: cannot strip structural AST properties");
19
+ const project = (value) => {
20
+ if (Array.isArray(value))
21
+ return value.flatMap((item) => {
22
+ const result = project(item);
23
+ return result === undefined ? [] : [result];
24
+ });
25
+ if (!value || typeof value !== "object")
26
+ return value;
27
+ const node = value;
28
+ if (options.excludeNodeTypes?.includes(node.type) ||
29
+ (node.type?.startsWith("mdxJsx") &&
30
+ node.name &&
31
+ options.excludeComponents?.includes(node.name)))
32
+ return undefined;
33
+ return Object.fromEntries(Object.entries(value)
34
+ .filter(([key]) => !strip.has(key))
35
+ .flatMap(([key, item]) => {
36
+ const result = project(item);
37
+ return result === undefined ? [] : [[key, result]];
38
+ }));
39
+ };
40
+ const result = project(tree);
41
+ validateAstContract(result);
42
+ return result;
43
+ }
44
+ //# sourceMappingURL=dataset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset.js","sourceRoot":"","sources":["../src/dataset.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;AAOrE,MAAM,CAAC,MAAM,qBAAqB,GAAsB;IACtD,iBAAiB,EAAE;QACjB,OAAO;QACP,aAAa;QACb,WAAW;QACX,UAAU;QACV,WAAW;QACX,WAAW;QACX,cAAc;KACf;CACF,CAAA;AAED,uFAAuF;AACvF,MAAM,UAAU,UAAU,CAAC,IAAU,EAAE,UAA6B,EAAE;IACpE,mBAAmB,CAAC,IAAI,CAAC,CAAA;IACzB,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,eAAe,IAAI,EAAE,CAAC,CAAA;IACpD,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,MAAM,OAAO,GAAG,CAAC,KAAc,EAAW,EAAE;QAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACtB,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;gBAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;gBAC5B,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;YAC7C,CAAC,CAAC,CAAA;QACJ,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACrD,MAAM,IAAI,GAAG,KAAqB,CAAA;QAClC,IACE,OAAO,CAAC,gBAAgB,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;YAC7C,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC;gBAC9B,IAAI,CAAC,IAAI;gBACT,OAAO,CAAC,iBAAiB,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEjD,OAAO,SAAS,CAAA;QAClB,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;aAClB,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;aAClC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE;YACvB,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;YAC5B,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAA;QACpD,CAAC,CAAC,CACL,CAAA;IACH,CAAC,CAAA;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAS,CAAA;IACpC,mBAAmB,CAAC,MAAM,CAAC,CAAA;IAC3B,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,74 @@
1
+ /** Portable document semantics. Parser and rendering adapters share this model. */
2
+ import type { Root, PhrasingContent } from "mdast";
3
+ import type { Position } from "unist";
4
+ import { type TableColumnLayoutOptions } from "./internal/transforms/table-column-layout/index.js";
5
+ declare module "mdast" {
6
+ interface RootData {
7
+ cudocEmbedPrefix?: string;
8
+ }
9
+ }
10
+ export type SyntaxMode = "host" | "cudoc" | "both";
11
+ export type SyntaxOptions = Partial<Record<"headingAnchor" | "badge" | "tableCellList" | "callout" | "link", SyntaxMode>>;
12
+ export type Host = "markdown" | "next" | "docusaurus" | "nextra" | "vitepress" | "html" | "docs";
13
+ export type DocumentDiagnostic = {
14
+ code: string;
15
+ message: string;
16
+ position?: Position;
17
+ };
18
+ export type DocumentOptions = {
19
+ syntax?: SyntaxOptions;
20
+ host?: Host;
21
+ format?: "md" | "mdx";
22
+ calloutTypes?: string[];
23
+ components?: Record<string, {
24
+ kind: "callout" | "link" | "badge";
25
+ typeAttribute?: string;
26
+ titleAttribute?: string;
27
+ urlAttribute?: string;
28
+ }>;
29
+ tableColumnLayout?: TableColumnLayoutOptions[];
30
+ /** Hosts use their native slugger later. Standalone compilers assign IDs here. */
31
+ headingIds?: "host" | "generate";
32
+ };
33
+ export type DocumentData = {
34
+ hName?: string;
35
+ hProperties?: Record<string, unknown>;
36
+ cudoc?: {
37
+ kind: string;
38
+ type?: string;
39
+ title?: string;
40
+ badge?: string;
41
+ explicitId?: boolean;
42
+ };
43
+ [key: string]: unknown;
44
+ };
45
+ export type DocumentNode = {
46
+ type: string;
47
+ value?: string;
48
+ name?: string | null;
49
+ depth?: number;
50
+ url?: string;
51
+ identifier?: string;
52
+ label?: string;
53
+ attributes?: unknown;
54
+ children?: DocumentNode[];
55
+ position?: Position;
56
+ data?: DocumentData;
57
+ [key: string]: unknown;
58
+ };
59
+ export declare const DEFAULT_SYNTAX: Required<SyntaxOptions>;
60
+ export declare function resolveSyntax(syntax?: SyntaxOptions): Required<SyntaxOptions>;
61
+ export declare const visibleHeadingText: (node: DocumentNode) => string;
62
+ export declare const nodeText: (node: DocumentNode) => string;
63
+ export declare const isCudoc: (mode: SyntaxMode) => mode is "cudoc" | "both";
64
+ export declare const isHost: (mode: SyntaxMode) => mode is "host" | "both";
65
+ /** Read static JSX/directive attributes without evaluating expressions. */
66
+ export declare function staticAttributes(node: DocumentNode): Record<string, unknown>;
67
+ export declare function hasDynamicAttributes(node: DocumentNode): boolean;
68
+ export declare const canonicalCalloutType: (type: string) => string;
69
+ export declare function makeCallout(type: string, title: DocumentNode[], children: DocumentNode[], position?: Position): DocumentNode;
70
+ /** Convert generated/static native JSX to mdast data understood by mdast-to-hast. */
71
+ export declare function lowerNativeElements(tree: Root): void;
72
+ /** Mutates the compiler's actual tree. It never reparses the source document. */
73
+ export declare function normalizeDocument(tree: Root, source: string, options?: DocumentOptions, inlineParser?: (source: string) => PhrasingContent[]): DocumentDiagnostic[];
74
+ //# sourceMappingURL=document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,435 @@
1
+ import GithubSlugger from "github-slugger";
2
+ import { walk } from "./internal/core/walk.js";
3
+ import { parseTableCellList, buildTableCellChildren, hasTableCellListPattern, } from "./internal/transforms/table-cell-list/index.js";
4
+ import { createTableColumnLayoutTransform, resolveTableColumnLayoutOptions, } from "./internal/transforms/table-column-layout/index.js";
5
+ export const DEFAULT_SYNTAX = {
6
+ headingAnchor: "cudoc",
7
+ badge: "cudoc",
8
+ tableCellList: "cudoc",
9
+ callout: "cudoc",
10
+ link: "host",
11
+ };
12
+ export function resolveSyntax(syntax = {}) {
13
+ if (!syntax || typeof syntax !== "object" || Array.isArray(syntax))
14
+ throw new TypeError("cudoc: syntax must be an object");
15
+ for (const [key, value] of Object.entries(syntax)) {
16
+ if (!Object.hasOwn(DEFAULT_SYNTAX, key) ||
17
+ !["host", "cudoc", "both"].includes(value))
18
+ throw new TypeError(`cudoc: invalid syntax.${key}: ${value}`);
19
+ }
20
+ return { ...DEFAULT_SYNTAX, ...syntax };
21
+ }
22
+ export const visibleHeadingText = (node) => (node.children
23
+ ?.filter((n) => !["badge", "permalink"].includes(n.data?.cudoc?.kind ?? ""))
24
+ .map(nodeText)
25
+ .join("") ?? "").trim();
26
+ export const nodeText = (node) => node.value ?? node.children?.map(nodeText).join("") ?? "";
27
+ export const isCudoc = (mode) => mode !== "host";
28
+ export const isHost = (mode) => mode !== "cudoc";
29
+ /** Read static JSX/directive attributes without evaluating expressions. */
30
+ export function staticAttributes(node) {
31
+ if (!Array.isArray(node.attributes))
32
+ return { ...(node.attributes ?? {}) };
33
+ const result = {};
34
+ for (const attr of node.attributes) {
35
+ if (attr.type !== "mdxJsxAttribute" || !attr.name)
36
+ continue;
37
+ if (attr.value === null)
38
+ result[attr.name] = true;
39
+ else if (typeof attr.value === "string")
40
+ result[attr.name] = attr.value;
41
+ else if (attr.value &&
42
+ typeof attr.value === "object" &&
43
+ "value" in attr.value) {
44
+ try {
45
+ result[attr.name] = JSON.parse(String(attr.value.value));
46
+ }
47
+ catch {
48
+ /* Dynamic values stay opaque. */
49
+ }
50
+ }
51
+ }
52
+ return result;
53
+ }
54
+ export function hasDynamicAttributes(node) {
55
+ if (!Array.isArray(node.attributes))
56
+ return false;
57
+ const attrs = staticAttributes(node);
58
+ return node.attributes.some((attr) => attr.type !== "mdxJsxAttribute" ||
59
+ !attr.name ||
60
+ !Object.hasOwn(attrs, attr.name));
61
+ }
62
+ export const canonicalCalloutType = (type) => ({
63
+ info: "note",
64
+ default: "note",
65
+ error: "caution",
66
+ danger: "caution",
67
+ warn: "warning",
68
+ })[type.toLowerCase()] ?? type.toLowerCase();
69
+ const text = (value) => ({ type: "text", value });
70
+ const badgeNode = (value) => ({
71
+ type: "strong",
72
+ children: [text(value)],
73
+ data: {
74
+ hName: "span",
75
+ hProperties: { className: ["cudoc-badge"] },
76
+ cudoc: { kind: "badge" },
77
+ },
78
+ });
79
+ export function makeCallout(type, title, children, position) {
80
+ type = canonicalCalloutType(type);
81
+ return {
82
+ type: "blockquote",
83
+ position,
84
+ data: {
85
+ hName: "aside",
86
+ hProperties: {
87
+ className: ["cudoc-callout", `cudoc-callout-${type}`],
88
+ "data-callout": type,
89
+ },
90
+ cudoc: { kind: "callout", type, title: title.map(nodeText).join("") },
91
+ },
92
+ children: [
93
+ {
94
+ type: "paragraph",
95
+ data: {
96
+ hProperties: { className: ["cudoc-callout-title"] },
97
+ cudoc: { kind: "calloutTitle" },
98
+ },
99
+ children: title.length ? title : [text(type.toUpperCase())],
100
+ },
101
+ ...children,
102
+ ],
103
+ };
104
+ }
105
+ /** Split a paragraph at its first physical line break without flattening emphasis. */
106
+ function splitLine(nodes) {
107
+ const before = [];
108
+ for (let i = 0; i < nodes.length; i++) {
109
+ const node = nodes[i];
110
+ const offset = node.type === "text" ? node.value.indexOf("\n") : -1;
111
+ if (offset >= 0 || node.type === "break") {
112
+ if (offset > 0)
113
+ before.push({ ...node, value: node.value.slice(0, offset) });
114
+ const after = offset >= 0 && node.value.slice(offset + 1)
115
+ ? [{ ...node, value: node.value.slice(offset + 1) }]
116
+ : [];
117
+ return [before, [...after, ...nodes.slice(i + 1)]];
118
+ }
119
+ before.push(node);
120
+ }
121
+ return [before, []];
122
+ }
123
+ const nativeTags = new Set("a abbr b blockquote br header footer nav caption code dd del details div dl dt em figcaption figure hr i img kbd li ol p pre s section small span strong sub summary sup table tbody td th thead tr u ul aside".split(" "));
124
+ const tableTags = {
125
+ Table: "table",
126
+ TableHeader: "thead",
127
+ TableBody: "tbody",
128
+ TableRow: "tr",
129
+ TableHead: "th",
130
+ TableCell: "td",
131
+ };
132
+ /** Convert generated/static native JSX to mdast data understood by mdast-to-hast. */
133
+ export function lowerNativeElements(tree) {
134
+ const lower = (node) => {
135
+ if (node.children)
136
+ node.children = node.children.map(lower);
137
+ if (!node.type.startsWith("mdxJsx") ||
138
+ !node.name ||
139
+ !nativeTags.has(node.name) ||
140
+ hasDynamicAttributes(node))
141
+ return node;
142
+ const attrs = staticAttributes(node);
143
+ if (node.name === "br")
144
+ return { type: "break", position: node.position };
145
+ if (node.name === "a" && typeof attrs.href === "string")
146
+ return {
147
+ type: "link",
148
+ url: attrs.href,
149
+ children: node.children ?? [],
150
+ data: { hProperties: attrs },
151
+ position: node.position,
152
+ };
153
+ if (node.name === "img" && typeof attrs.src === "string")
154
+ return {
155
+ type: "image",
156
+ url: attrs.src,
157
+ alt: attrs.alt ?? "",
158
+ data: { hProperties: attrs },
159
+ position: node.position,
160
+ };
161
+ if (attrs.style && typeof attrs.style === "object")
162
+ attrs.style = Object.entries(attrs.style)
163
+ .map(([key, value]) => `${key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)}:${value}`)
164
+ .join(";");
165
+ return {
166
+ type: node.type === "mdxJsxTextElement" ? "strong" : "blockquote",
167
+ children: node.children ?? [],
168
+ position: node.position,
169
+ data: {
170
+ hName: node.name,
171
+ hProperties: attrs,
172
+ cudoc: { kind: "element" },
173
+ ...(node.data?._mdxExplicitJsx ? { _mdxExplicitJsx: true } : {}),
174
+ },
175
+ };
176
+ };
177
+ tree.children = tree.children.map((n) => lower(n));
178
+ }
179
+ /** Mutates the compiler's actual tree. It never reparses the source document. */
180
+ export function normalizeDocument(tree, source, options = {}, inlineParser) {
181
+ const syntax = resolveSyntax(options.syntax);
182
+ const host = options.host ?? "markdown";
183
+ if (![
184
+ "markdown",
185
+ "next",
186
+ "docusaurus",
187
+ "nextra",
188
+ "vitepress",
189
+ "html",
190
+ "docs",
191
+ ].includes(host))
192
+ throw new TypeError(`cudoc: unknown host ${host}`);
193
+ if (options.calloutTypes !== undefined &&
194
+ (!Array.isArray(options.calloutTypes) ||
195
+ options.calloutTypes.some((type) => typeof type !== "string" || !/^[a-z][\w-]*$/i.test(type))))
196
+ throw new TypeError("cudoc: calloutTypes must contain type names");
197
+ const diagnostics = [];
198
+ const types = new Set([
199
+ "note",
200
+ "tip",
201
+ "important",
202
+ "warning",
203
+ "caution",
204
+ ...(options.calloutTypes ?? []).map((t) => t.toLowerCase()),
205
+ ]);
206
+ const mappings = {
207
+ ...(host === "docs"
208
+ ? {
209
+ Infobox: { kind: "callout" },
210
+ Link: { kind: "link" },
211
+ IconLink: { kind: "link" },
212
+ }
213
+ : {}),
214
+ ...(host === "nextra" ? { Callout: { kind: "callout" } } : {}),
215
+ ...(host === "docusaurus"
216
+ ? { Admonition: { kind: "callout" } }
217
+ : {}),
218
+ ...options.components,
219
+ };
220
+ const warn = (node, code, message) => diagnostics.push({ code, message, position: node.position });
221
+ const fail = (node, message) => {
222
+ throw new Error(`cudoc: ${message} at ${node.position?.start.line ?? "?"}:${node.position?.start.column ?? "?"}`);
223
+ };
224
+ const normalize = (node, ancestors) => {
225
+ if (node.data?.cudoc?.kind === "badge")
226
+ return node;
227
+ if (node.type === "heading") {
228
+ const ids = [];
229
+ const existing = node.data?.hProperties?.id;
230
+ if (typeof existing === "string" &&
231
+ node.data?.cudoc?.explicitId !== false)
232
+ ids.push(existing);
233
+ const clean = (child) => {
234
+ if (child.type === "text") {
235
+ let value = child.value;
236
+ if (isCudoc(syntax.headingAnchor))
237
+ value = value.replace(/\(#([^\s)]+)\)/g, (_, id) => {
238
+ ids.push(id);
239
+ return "";
240
+ });
241
+ if (isHost(syntax.headingAnchor) &&
242
+ ["docusaurus", "vitepress"].includes(host))
243
+ value = value.replace(/\{#([^\s}]+)\}/g, (_, id) => {
244
+ ids.push(id);
245
+ return "";
246
+ });
247
+ if (isHost(syntax.headingAnchor) && host === "nextra")
248
+ value = value.replace(/\[#([^\s\]]+)\]/g, (_, id) => {
249
+ ids.push(id);
250
+ return "";
251
+ });
252
+ return [{ ...child, value }];
253
+ }
254
+ if (isHost(syntax.headingAnchor) &&
255
+ host === "docusaurus" &&
256
+ child.type.includes("Expression")) {
257
+ const match = child.value?.match(/^\s*\/\*\s*#([^\s*]+)\s*\*\/\s*$/);
258
+ if (match) {
259
+ ids.push(match[1]);
260
+ return [];
261
+ }
262
+ }
263
+ if (child.name === "Anchor" &&
264
+ isHost(syntax.headingAnchor) &&
265
+ !hasDynamicAttributes(child)) {
266
+ const attrs = staticAttributes(child);
267
+ if (typeof attrs.id === "string")
268
+ ids.push(attrs.id);
269
+ if (typeof attrs.badge === "string")
270
+ return [badgeNode(attrs.badge)];
271
+ return [];
272
+ }
273
+ if (child.children &&
274
+ ["strong", "emphasis", "delete"].includes(child.type))
275
+ child.children = child.children.flatMap(clean);
276
+ return [child];
277
+ };
278
+ node.children = node.children?.flatMap(clean);
279
+ const last = node.children?.at(-1);
280
+ if (last?.type === "text")
281
+ last.value = last.value.trimEnd();
282
+ if (new Set(ids).size > 1)
283
+ fail(node, `conflicting heading IDs: ${ids.join(", ")}`);
284
+ if (ids.length)
285
+ node.data = {
286
+ ...node.data,
287
+ hProperties: { ...node.data?.hProperties, id: ids[0] },
288
+ cudoc: { kind: "heading", explicitId: true },
289
+ };
290
+ }
291
+ if (node.type === "blockquote" && node.data?.cudoc?.kind !== "callout") {
292
+ const paragraph = node.children?.[0];
293
+ const first = paragraph?.type === "paragraph" ? paragraph.children?.[0] : undefined;
294
+ const match = first?.type === "text"
295
+ ? first.value?.match(/^\[!([\w-]+)\](?:[ \t]+|(?=\r?\n|$))/)
296
+ : undefined;
297
+ if (match &&
298
+ (isCudoc(syntax.callout) ||
299
+ (isHost(syntax.callout) && host === "vitepress"))) {
300
+ const type = match[1].toLowerCase();
301
+ if (!types.has(type))
302
+ warn(node, "UNKNOWN_CALLOUT_TYPE", `Unregistered callout type: ${match[1]}`);
303
+ else {
304
+ const parts = [
305
+ { ...first, value: first.value.slice(match[0].length) },
306
+ ...paragraph.children.slice(1),
307
+ ];
308
+ const [title, remainder] = splitLine(parts);
309
+ node = makeCallout(type, title.filter((n) => n.type !== "text" || n.value), [
310
+ ...(remainder.length
311
+ ? [{ type: "paragraph", children: remainder }]
312
+ : []),
313
+ ...node.children.slice(1),
314
+ ], node.position);
315
+ }
316
+ }
317
+ }
318
+ if (node.type === "containerDirective" &&
319
+ isHost(syntax.callout) &&
320
+ host === "docusaurus" &&
321
+ node.name &&
322
+ ["note", "tip", "info", "warning", "danger", ...types].includes(node.name)) {
323
+ const label = node.children?.[0]?.data?.directiveLabel
324
+ ? node.children[0]
325
+ : undefined;
326
+ const attrs = staticAttributes(node);
327
+ node = makeCallout(node.name, label?.children ?? [], node.children?.slice(label ? 1 : 0) ?? [], node.position);
328
+ if (typeof attrs.id === "string")
329
+ node.data.hProperties.id = attrs.id;
330
+ if (typeof attrs.class === "string")
331
+ node.data.hProperties.className.push(...attrs.class.split(/\s+/));
332
+ }
333
+ if (node.name && node.type.startsWith("mdxJsx")) {
334
+ const map = mappings[node.name];
335
+ const attrs = staticAttributes(node);
336
+ if (hasDynamicAttributes(node)) {
337
+ if (map || nativeTags.has(node.name))
338
+ warn(node, "DYNAMIC_COMPONENT", `Preserved dynamic attributes on ${node.name}; portable rendering requires an explicit renderer`);
339
+ }
340
+ else if (map?.kind === "callout" && isHost(syntax.callout))
341
+ node = makeCallout(String(attrs[map.typeAttribute ?? "type"] ?? "note"), attrs[map.titleAttribute ?? "title"]
342
+ ? [text(String(attrs[map.titleAttribute ?? "title"]))]
343
+ : [], node.children ?? [], node.position);
344
+ else if (map?.kind === "link" &&
345
+ isHost(syntax.link) &&
346
+ typeof attrs[map.urlAttribute ?? "href"] === "string")
347
+ node = {
348
+ type: "link",
349
+ url: String(attrs[map.urlAttribute ?? "href"]),
350
+ children: node.children ?? [],
351
+ position: node.position,
352
+ };
353
+ else if ((map?.kind === "badge" || node.name === "Badge") &&
354
+ isHost(syntax.badge))
355
+ node = badgeNode(nodeText(node));
356
+ else if (host === "docs" && tableTags[node.name])
357
+ node.name = tableTags[node.name];
358
+ }
359
+ if (node.type === "tableCell" &&
360
+ isCudoc(syntax.tableCellList) &&
361
+ node.position) {
362
+ const raw = source
363
+ .slice(node.position.start.offset, node.position.end.offset)
364
+ .replace(/^\s*\|\s*/, "")
365
+ .replace(/\s*\|\s*$/, "");
366
+ if (hasTableCellListPattern(raw) && raw.trim() !== "-")
367
+ node.children = buildTableCellChildren(parseTableCellList(raw, options.format ?? "md", inlineParser));
368
+ }
369
+ if (node.children)
370
+ node.children = node.children.flatMap((child) => {
371
+ if (child.type === "text" &&
372
+ isCudoc(syntax.badge) &&
373
+ ![...ancestors, node].some((p) => ["link", "linkReference", "code", "inlineCode"].includes(p.type))) {
374
+ const parts = child.value.split(/\(@([^)]*)\)/g);
375
+ if (parts.length > 1) {
376
+ if (node.type === "heading")
377
+ node.data = {
378
+ ...node.data,
379
+ cudoc: {
380
+ ...node.data?.cudoc,
381
+ kind: "heading",
382
+ badge: parts.filter((_, i) => i % 2).at(-1),
383
+ },
384
+ };
385
+ return parts.map((value, i) => i % 2 ? badgeNode(value) : text(value));
386
+ }
387
+ }
388
+ return [normalize(child, [...ancestors, node])];
389
+ });
390
+ return node;
391
+ };
392
+ tree.children = tree.children.map((n) => normalize(n, []));
393
+ for (const rule of options.tableColumnLayout ?? [])
394
+ walk({
395
+ tree,
396
+ state: { source },
397
+ preTransforms: [],
398
+ postTransforms: [
399
+ createTableColumnLayoutTransform(resolveTableColumnLayoutOptions(rule)),
400
+ ],
401
+ });
402
+ lowerNativeElements(tree);
403
+ const slugger = new GithubSlugger();
404
+ const ids = new Set();
405
+ const headings = [];
406
+ const collect = (node) => {
407
+ if (node.type === "heading")
408
+ headings.push(node);
409
+ node.children?.forEach(collect);
410
+ };
411
+ collect(tree);
412
+ for (const node of headings) {
413
+ const id = node.data?.hProperties?.id;
414
+ if (typeof id === "string") {
415
+ if (ids.has(id))
416
+ fail(node, `duplicate heading ID: ${id}`);
417
+ ids.add(id);
418
+ }
419
+ }
420
+ if (options.headingIds !== "host")
421
+ for (const node of headings)
422
+ if (!node.data?.hProperties?.id) {
423
+ const title = visibleHeadingText(node);
424
+ let id = slugger.slug(title);
425
+ while (ids.has(id))
426
+ id = slugger.slug(title);
427
+ ids.add(id);
428
+ node.data = {
429
+ ...node.data,
430
+ hProperties: { ...node.data?.hProperties, id },
431
+ };
432
+ }
433
+ return diagnostics;
434
+ }
435
+ //# sourceMappingURL=document.js.map