@dogsbay/format-openknowledge 0.2.0-beta.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @dogsbay/format-openknowledge
2
+
3
+ Export a Dogsbay corpus so it opens cleanly in
4
+ [Inkeep OpenKnowledge](https://openknowledge.ai): MDX in the dialect it
5
+ parses (GFM + github-alerts + math + mdx-jsx, no `remark-directive`), with
6
+ the Fumadocs component vocabulary.
7
+
8
+ ```bash
9
+ npx dogsbay convert docs/ --to openknowledge -o ok-vault/
10
+ # or, from a Dogsbay site: npx dogsbay site build --to openknowledge
11
+ ```
12
+
13
+ ## What it fixes (measured on a real corpus)
14
+
15
+ | Symptom in OpenKnowledge | Cause | This exporter |
16
+ |---|---|---|
17
+ | nearly every internal link dead | extension-less root-relative paths resolved source-relative | root-absolute `/path/page.md#heading-slug`, resolved against every exported page |
18
+ | `^anchor` on every heading and in the outline | Obsidian block ids | no anchors emitted; deep links use the heading's text slug (`-1`, `-2` on repeats) |
19
+ | `dogsbay-*` fences shown as raw code | the vault encoding | plain fences; deflists as readable term lists; tabs/callouts/folds as `<Tabs>`, `> [!NOTE]`/`<Callout>`, `<Accordion>` |
20
+
21
+ Every degradation is declared in `OPENKNOWLEDGE_CAPABILITIES`, recorded in
22
+ an export ledger, and written to `.dogsbay/export-report.md` (a dot-dir,
23
+ which OpenKnowledge does not index) with the links that pointed outside the
24
+ export, any fragment that named no heading, and path collisions. An export
25
+ that records an undeclared loss throws.
26
+
27
+ Anchors use OpenKnowledge's OWN slug rule (`toWikiLinkSlug`: NFKD, marks
28
+ stripped, lowercase, runs of non-letters/digits → one `-`; not
29
+ github-slugger), computed over every heading the page emits — nested ones
30
+ and api symbols included — so a deep link lands on the section. Links carry
31
+ the real extension (`.mdx` when a page has JSX). Verified: 154/154 FastAPI
32
+ pages compile under a strict `@mdx-js/mdx` stack; 0 `^anchors`; 0
33
+ `dogsbay-*` fences.
34
+
35
+ ## Layout
36
+
37
+ Pages are written at their slug path (`guides/install.md`); a page that
38
+ carries JSX is `.mdx`. Frontmatter: `title`, `description`, `tags`, plus
39
+ scalar source keys. Media mounted by the importer is copied to `_assets/`.
40
+
41
+ ## Capabilities
42
+
43
+ See `src/capabilities.ts` (`full` / `partial` with a note): `<Steps>` and
44
+ `<Cards>` land on OpenKnowledge's wildcard (editable raw MDX, not
45
+ rendered); code line-highlights and annotations have no affordance and are
46
+ dropped (recorded); raw HTML is converted to markdown (MDX rejects
47
+ unbalanced HTML).
48
+
49
+ Design: `dogsbay-research/plans/format-openknowledge.md`.
@@ -0,0 +1,14 @@
1
+ /**
2
+ * What the OpenKnowledge exporter can and cannot represent — a CONTRACT
3
+ * (the format-docusaurus pattern): `validateCapabilities` rejects any
4
+ * non-full entry without a note, a test asserts every TreeNode type the
5
+ * serializer handles appears here, and the ledger every export produces is
6
+ * validated against it. Measured against OpenKnowledge v0.57.x
7
+ * (dogsbay-research/plans/format-openknowledge.md §3); re-verify on drift.
8
+ *
9
+ * Support levels: full — round-trips faithfully · partial — survives with
10
+ * reduced fidelity · none — cannot be represented (always recorded).
11
+ */
12
+ import type { CapabilityDeclaration } from "@dogsbay/serialize-core";
13
+ export declare const OPENKNOWLEDGE_CAPABILITIES: CapabilityDeclaration[];
14
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE,eAAO,MAAM,0BAA0B,EAAE,qBAAqB,EAkJ7D,CAAC"}
@@ -0,0 +1,141 @@
1
+ export const OPENKNOWLEDGE_CAPABILITIES = [
2
+ // ── Core markdown ────────────────────────────────────────
3
+ { feature: "heading", support: "full", rendersAs: "`#`–`######` — NO `^anchor`; links use the heading's text slug" },
4
+ { feature: "paragraph", support: "full" },
5
+ { feature: "prose", support: "full", rendersAs: "inline markdown; `{ } <` escaped for MDX" },
6
+ { feature: "unordered-list", support: "full", rendersAs: "`- item`" },
7
+ { feature: "ordered-list", support: "full", rendersAs: "`1. item`" },
8
+ { feature: "list-item", support: "full" },
9
+ { feature: "blockquote", support: "full", rendersAs: "`> …`" },
10
+ { feature: "hr", support: "full", rendersAs: "`---`" },
11
+ { feature: "references", support: "full", rendersAs: "link reference definitions with rewritten targets" },
12
+ { feature: "footnote-list", support: "full" },
13
+ { feature: "footnote-def", support: "full", rendersAs: "`[^label]: …`" },
14
+ { feature: "related", support: "full", rendersAs: "bold label + the link list" },
15
+ {
16
+ feature: "frontmatter",
17
+ support: "partial",
18
+ rendersAs: "page frontmatter written by the project layer (title, description, tags, aliases, scalar keys)",
19
+ note: "Non-scalar source keys other than tags/aliases are dropped (recorded). A `.md` page that turns out to carry JSX is written `.mdx` and recorded.",
20
+ },
21
+ {
22
+ feature: "table",
23
+ support: "partial",
24
+ rendersAs: "GFM pipe table",
25
+ note: "GFM cells are single-line: a block inside a cell is flattened; a caption becomes italic text below the table.",
26
+ },
27
+ {
28
+ feature: "html",
29
+ support: "partial",
30
+ rendersAs: "markdown converted from the HTML",
31
+ note: "MDX rejects unbalanced or non-JSX HTML, so raw HTML is converted (inline tags → markdown, the rest stripped). Layout-only markup is lost.",
32
+ },
33
+ // ── Native OpenKnowledge constructs (§3.1) ───────────────
34
+ {
35
+ feature: "code",
36
+ support: "partial",
37
+ rendersAs: "plain fence — language on the info string, `title=\"…\"` as fence meta",
38
+ note: "Never the `dogsbay-code` envelope. Line highlights and code annotations have no OpenKnowledge affordance and are dropped (recorded).",
39
+ },
40
+ {
41
+ feature: "callout",
42
+ support: "partial",
43
+ rendersAs: "GFM alert `> [!NOTE]`; `<Callout type title>` when it has a custom title",
44
+ note: "OpenKnowledge renders the five GFM alert types (note/tip/important/warning/caution); other Dogsbay variants map to the nearest one and a custom icon is dropped.",
45
+ },
46
+ {
47
+ feature: "details",
48
+ support: "partial",
49
+ rendersAs: "`<Accordion title defaultOpen>`",
50
+ note: "Their Accordion has no variant/colour prop; a fold variant is lost.",
51
+ },
52
+ { feature: "tabs", support: "full", rendersAs: "`<Tabs><Tab label>`" },
53
+ { feature: "tab", support: "full", rendersAs: "`<Tab label>`" },
54
+ { feature: "diagram", support: "full", rendersAs: "```mermaid fence" },
55
+ { feature: "math-block", support: "full", rendersAs: "`$$ … $$`" },
56
+ { feature: "figure", support: "full", rendersAs: "`<Image src alt caption />` (or the image + italic caption)" },
57
+ { feature: "youtube", support: "full", rendersAs: "`<Video src=\"https://www.youtube.com/watch?v=…\" />`" },
58
+ // ── Wildcard JSX (§3.2/3.3) — content survives, rendering does not ──
59
+ {
60
+ feature: "steps",
61
+ support: "partial",
62
+ rendersAs: "`<Steps><Step title>` (Fumadocs vocabulary)",
63
+ note: "Unregistered in OpenKnowledge: renders as an editable raw-MDX block, not as numbered steps.",
64
+ },
65
+ { feature: "step", support: "partial", rendersAs: "`<Step title>`", note: "See steps." },
66
+ { feature: "substeps", support: "partial", rendersAs: "children emitted in place", note: "Nested step numbering is not modelled." },
67
+ {
68
+ feature: "cards",
69
+ support: "partial",
70
+ rendersAs: "`<Cards><Card title href icon>`",
71
+ note: "Unregistered in OpenKnowledge: renders as an editable raw-MDX block; the `href` is rewritten so it stays a real link in the source.",
72
+ },
73
+ { feature: "grid", support: "partial", rendersAs: "`<Cards>`", note: "See cards." },
74
+ { feature: "card", support: "partial", rendersAs: "`<Card title href icon>`", note: "See cards." },
75
+ {
76
+ feature: "deflist",
77
+ support: "partial",
78
+ rendersAs: "bulleted term list — `- **term**` with the definition nested",
79
+ note: "OpenKnowledge has no definition-list construct. Emitted as readable markdown (prose stays prose; 13,614 instances on the reference corpus), re-importable as a list.",
80
+ },
81
+ { feature: "dt", support: "partial", rendersAs: "`**term**`", note: "See deflist." },
82
+ { feature: "dd", support: "partial", rendersAs: "definition body", note: "See deflist." },
83
+ {
84
+ feature: "link-button",
85
+ support: "partial",
86
+ rendersAs: "plain markdown link",
87
+ note: "Navigational: a link feeds their graph and backlinks; a rendered block that cannot navigate would be worse. Button styling is lost.",
88
+ },
89
+ { feature: "annotation-list", support: "partial", rendersAs: "children in place", note: "Annotation numbering is not modelled." },
90
+ { feature: "html-container", support: "partial", rendersAs: "children in place", note: "The container's own markup is dropped." },
91
+ {
92
+ feature: "html-inline",
93
+ support: "partial",
94
+ rendersAs: "paired inline tags → markdown (`<a>` link, `<b>` bold, `<code>` span, `<abbr title>` → \"text (title)\")",
95
+ note: "OpenKnowledge shows lowercase inline tags as literal text, so they are converted; a tag with no markdown equivalent is unwrapped (recorded).",
96
+ },
97
+ { feature: "kbd", support: "partial", rendersAs: "code spans joined with `+`", note: "No <kbd> rendering in OpenKnowledge." },
98
+ { feature: "icon", support: "partial", rendersAs: "`:name:` text", note: "No icon registry in OpenKnowledge; the name is kept as text." },
99
+ { feature: "highlight", support: "full", rendersAs: "`==text==` (OpenKnowledge's highlight promoter)" },
100
+ {
101
+ feature: "mdx-raw",
102
+ support: "partial",
103
+ rendersAs: "the raw JSX/MDX source, verbatim",
104
+ note: "An importer's never-drop component (Mintlify <Update>, Docusaurus JSX, …) is passed through to OpenKnowledge's wildcard: shown as an editable raw-MDX block, content preserved, not rendered.",
105
+ },
106
+ { feature: "accordion-group", support: "partial", rendersAs: "the accordions in place", note: "No group container; each fold is its own <Accordion>." },
107
+ // ── API reference nodes ──────────────────────────────────
108
+ { feature: "api-class", support: "partial", rendersAs: "heading + signature fence", note: "No API-reference component; rendered as prose." },
109
+ { feature: "api-member", support: "partial", rendersAs: "heading + signature fence", note: "See api-class." },
110
+ { feature: "api-doc", support: "partial", rendersAs: "markdown converted from the doc HTML", note: "See html." },
111
+ { feature: "api-params", support: "partial", rendersAs: "GFM table (name | description · type · default)", note: "One line per cell; nested markup in a parameter doc is flattened." },
112
+ { feature: "api-source", support: "full", rendersAs: "source line + python fence" },
113
+ // ── Not represented ──────────────────────────────────────
114
+ //
115
+ // Added after `tests/export-conformance.test.ts` caught them being
116
+ // degraded or dropped at runtime with nothing declared. An undeclared
117
+ // loss is the failure mode this table exists to prevent: the export
118
+ // "succeeds", the ledger is silent, and the content is simply gone.
119
+ {
120
+ feature: "math",
121
+ support: "partial",
122
+ rendersAs: "the expression's source text, as plain prose",
123
+ note: "No `$…$` / `$$…$$` emission — the serializer has no math case, so " +
124
+ "the formula survives as text and stops rendering as math.",
125
+ },
126
+ {
127
+ feature: "avatar",
128
+ support: "none",
129
+ note: "No OpenKnowledge equivalent in the Fumadocs vocabulary, and no " +
130
+ "sensible prose fallback for an image-with-initials — dropped.",
131
+ },
132
+ {
133
+ feature: "link-card",
134
+ support: "none",
135
+ note: "Distinct from `card`: a link-card carries only an href and derives " +
136
+ "its own title. With no target metadata at export time there is " +
137
+ "nothing to put in a `<Card>` — dropped rather than emitting an " +
138
+ "empty card.",
139
+ },
140
+ ];
141
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { FormatPlugin } from "@dogsbay/types";
2
+ export declare const plugin: FormatPlugin;
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAuB,MAAM,gBAAgB,CAAC;AAIxE,eAAO,MAAM,MAAM,EAAE,YA6DpB,CAAC"}
package/dist/cli.js ADDED
@@ -0,0 +1,94 @@
1
+ /**
2
+ * `dogsbay convert <src> --to openknowledge` / `dogsbay site build --to openknowledge`.
3
+ * Writes the export folder plus a `dogsbay-export-report.md` with the
4
+ * capability ledger and any unresolved links, so a loss is a line in a
5
+ * report, never a surprise in the editor.
6
+ */
7
+ import { existsSync, mkdirSync, writeFileSync, cpSync, readdirSync, statSync, copyFileSync } from "node:fs";
8
+ import { join, dirname, relative } from "node:path";
9
+ import { formatLedgerReport } from "@dogsbay/serialize-core";
10
+ import { exportOpenKnowledge } from "./project.js";
11
+ export const plugin = {
12
+ name: "openknowledge",
13
+ canImport: false,
14
+ canExport: true,
15
+ detectSource: (path) => existsSync(join(path, ".ok")),
16
+ importOptions: [],
17
+ exportOptions: [
18
+ { flags: "--mdx", description: "Write every page as .mdx (default: .md unless the page carries JSX)" },
19
+ ],
20
+ async export(pages, nav, output, opts) {
21
+ const result = exportOpenKnowledge(pages, nav, {
22
+ siteName: opts.siteName,
23
+ section: opts.section,
24
+ alwaysMdx: opts.mdx === true,
25
+ });
26
+ for (const [filePath, content] of result.files) {
27
+ const full = join(output, filePath);
28
+ mkdirSync(dirname(full), { recursive: true });
29
+ writeFileSync(full, content);
30
+ }
31
+ // media: importers rewrite refs to `/_assets/…`; copy the mounted dirs there (root-absolute resolves in OpenKnowledge)
32
+ const mounts = opts.assetMounts;
33
+ for (const mount of mounts ?? []) {
34
+ if (!existsSync(mount.dir))
35
+ continue;
36
+ const dest = mount.into ? join(output, "_assets", mount.into) : join(output, "_assets");
37
+ mkdirSync(dest, { recursive: true });
38
+ cpSync(mount.dir, dest, { recursive: true });
39
+ }
40
+ // co-located media (the mkdocs shape: images beside the markdown, referenced root-absolute `/img/…`):
41
+ // copied at the same relative path so a root-absolute src resolves in OpenKnowledge
42
+ const sourceDir = opts.sourceDir;
43
+ if (sourceDir && existsSync(sourceDir))
44
+ copyImages(sourceDir, output);
45
+ const report = [
46
+ "# OpenKnowledge export report",
47
+ "",
48
+ `${result.files.size} pages written.`,
49
+ "",
50
+ formatLedgerReport(result.ledger, "openknowledge"),
51
+ "",
52
+ result.unresolvedPages.length
53
+ ? `## Links to pages outside this export (${result.unresolvedPages.length})\n\n${result.unresolvedPages.slice(0, 200).map((u) => `- ${u.page}: ${u.href}`).join("\n")}`
54
+ : "No links to pages outside this export.",
55
+ "",
56
+ result.unresolvedFragments.length
57
+ ? `## Fragments naming no heading on the target (${result.unresolvedFragments.length}) — kept verbatim\n\n${result.unresolvedFragments.slice(0, 200).map((u) => `- ${u.page}: ${u.href}`).join("\n")}`
58
+ : "Every heading fragment resolved to a heading on its target page.",
59
+ "",
60
+ result.collisions.length
61
+ ? `## Path collisions (${result.collisions.length}) — written under a disambiguated name\n\n${result.collisions.map((c) => `- ${c.page}: ${c.path} → ${c.renamedTo}`).join("\n")}`
62
+ : "No path collisions.",
63
+ "",
64
+ "Note: OpenKnowledge skips folders named dist, build, out, output, vendor, env — a corpus section with one of those names is invisible there.",
65
+ "",
66
+ ].join("\n");
67
+ // a dot-directory: OpenKnowledge does not index it (a report at the root would become a page);
68
+ // written MDX-safe anyway (a ledger detail may quote `<abbr title>` or `{…}`)
69
+ mkdirSync(join(output, ".dogsbay"), { recursive: true });
70
+ writeFileSync(join(output, ".dogsbay", "export-report.md"), report.replace(/[<{}]/g, (c) => `\\${c}`));
71
+ console.log(`Generated ${result.files.size} OpenKnowledge pages (report: .dogsbay/export-report.md)`);
72
+ },
73
+ };
74
+ const IMAGE_EXT = /\.(png|jpe?g|gif|svg|webp|avif|ico)$/i;
75
+ /** Copy every image under `sourceDir` to the same relative path under `outDir` (skipping VCS/vendor dirs). */
76
+ function copyImages(sourceDir, outDir) {
77
+ const walk = (dir) => {
78
+ for (const name of readdirSync(dir)) {
79
+ if (name === ".git" || name === "node_modules" || name.startsWith("."))
80
+ continue;
81
+ const full = join(dir, name);
82
+ const st = statSync(full);
83
+ if (st.isDirectory())
84
+ walk(full);
85
+ else if (IMAGE_EXT.test(name)) {
86
+ const dest = join(outDir, relative(sourceDir, full));
87
+ mkdirSync(dirname(dest), { recursive: true });
88
+ copyFileSync(full, dest);
89
+ }
90
+ }
91
+ };
92
+ walk(sourceDir);
93
+ }
94
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { treeToOpenKnowledge, defaultHref, escapeMdxText, splitFragment, type OpenKnowledgeSerializeOptions } from "./serialize.js";
2
+ export { exportOpenKnowledge, pageAnchors, type OpenKnowledgeExport, type OpenKnowledgeExportOptions } from "./project.js";
3
+ export { OPENKNOWLEDGE_CAPABILITIES } from "./capabilities.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AACpI,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,KAAK,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC3H,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { treeToOpenKnowledge, defaultHref, escapeMdxText, splitFragment } from "./serialize.js";
2
+ export { exportOpenKnowledge, pageAnchors } from "./project.js";
3
+ export { OPENKNOWLEDGE_CAPABILITIES } from "./capabilities.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAsC,MAAM,gBAAgB,CAAC;AACpI,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAA6D,MAAM,cAAc,CAAC;AAC3H,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Project layout for an OpenKnowledge export — a folder of `.md`/`.mdx`
3
+ * files OpenKnowledge opens in place.
4
+ *
5
+ * - Every page is written at its SLUG PATH (`guides/install.md`), mirroring
6
+ * the source tree. Two pages that normalize to one path (`guides` and
7
+ * `guides/index`, or a case-only difference — macOS/Windows filesystems
8
+ * are case-insensitive) are a COLLISION: the second is written under a
9
+ * disambiguated name and recorded, never silently overwritten (the
10
+ * Obsidian target once lost 107 of 988 pages that way).
11
+ * - Navigation in OpenKnowledge IS the file tree, graph, outline and
12
+ * backlinks — all fed by links, so `dogsbay-nav` is not ported (§3.3).
13
+ * - Links are rewritten with knowledge of EVERY page: root-absolute targets
14
+ * with the REAL extension (`.mdx` when the page carries JSX — decided from
15
+ * the tree before any link is written; OpenKnowledge itself resolves either,
16
+ * GitHub/VS Code do not), and a fragment mapped to the anchor OpenKnowledge
17
+ * computes for the target heading — ITS slug rule (`toWikiLinkSlug`: NFKD,
18
+ * strip marks, lowercase, runs of non-letter/digit → one `-`, trimmed;
19
+ * `-1`, `-2` on repeats, in document order over every heading it will see,
20
+ * nested ones included) — so a deep link lands on the section. A Dogsbay
21
+ * heading id (`props.slug`) or a text slug in the SOURCE both resolve. A
22
+ * fragment naming no known heading is kept verbatim and reported.
23
+ * - Frontmatter: `title` + `description` (their conventions), `tags` and
24
+ * `aliases` (OpenKnowledge reads both), and scalar source keys; other keys
25
+ * are dropped and recorded.
26
+ */
27
+ import type { ExportPage, NavItem, TreeNode } from "@dogsbay/types";
28
+ import { ExportLedger } from "@dogsbay/serialize-core";
29
+ export interface OpenKnowledgeExportOptions {
30
+ siteName?: string;
31
+ /** Prefix folder for every page (multi-source exports). */
32
+ section?: string;
33
+ /** Always write `.mdx` (default: `.md` unless the page carries JSX). */
34
+ alwaysMdx?: boolean;
35
+ }
36
+ export interface OpenKnowledgeExport {
37
+ /** Path (POSIX, relative to the output root) → file content. */
38
+ files: Map<string, string>;
39
+ ledger: ExportLedger;
40
+ /** Links whose fragment named no heading on the target page (kept verbatim). */
41
+ unresolvedFragments: Array<{
42
+ page: string;
43
+ href: string;
44
+ }>;
45
+ /** Links whose target page is not in the export (kept as a root-absolute `.md` path). */
46
+ unresolvedPages: Array<{
47
+ page: string;
48
+ href: string;
49
+ }>;
50
+ /** Pages whose path collided with an earlier page's; written under `renamedTo`. */
51
+ collisions: Array<{
52
+ page: string;
53
+ path: string;
54
+ renamedTo: string;
55
+ }>;
56
+ }
57
+ /**
58
+ * OpenKnowledge's own anchor rule (open-knowledge `packages/core/src/utils/
59
+ * slug.ts` `toWikiLinkSlug`): NOT github-slugger. `_` becomes `-`, runs of
60
+ * punctuation collapse to one `-`, diacritics fold, non-Latin letters stay.
61
+ */
62
+ export declare function okSlug(text: string): string;
63
+ /**
64
+ * fragment → anchor for ONE page: every heading it will emit, in order,
65
+ * OpenKnowledge-slugged with `-1`, `-2` on repeats. Keys: the Dogsbay id
66
+ * (`props.slug`), the Dogsbay text slug (what a source link would use, with
67
+ * Dogsbay's own `-1` dedupe), and the OpenKnowledge anchor itself.
68
+ */
69
+ export declare function pageAnchors(headings: Array<{
70
+ slug: string;
71
+ text: string;
72
+ }>): Map<string, string>;
73
+ export declare function treeNeedsMdx(nodes: TreeNode[]): boolean;
74
+ export declare function exportOpenKnowledge(pages: ExportPage[], _nav: NavItem[], options?: OpenKnowledgeExportOptions): OpenKnowledgeExport;
75
+ //# sourceMappingURL=project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAqE,MAAM,yBAAyB,CAAC;AAI1H,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,gFAAgF;IAChF,mBAAmB,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,yFAAyF;IACzF,eAAe,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvD,mFAAmF;IACnF,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtE;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ3C;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBhG;AAMD,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAavD;AAID,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,GAAE,0BAA+B,GAAG,mBAAmB,CA8EvI"}
@@ -0,0 +1,174 @@
1
+ import { ExportLedger, slugifyHeadingText, yamlScalar, validateLedgerAgainstCapabilities } from "@dogsbay/serialize-core";
2
+ import { treeToOpenKnowledge, defaultHref, splitFragment, collectEmittedHeadings } from "./serialize.js";
3
+ import { OPENKNOWLEDGE_CAPABILITIES } from "./capabilities.js";
4
+ /**
5
+ * OpenKnowledge's own anchor rule (open-knowledge `packages/core/src/utils/
6
+ * slug.ts` `toWikiLinkSlug`): NOT github-slugger. `_` becomes `-`, runs of
7
+ * punctuation collapse to one `-`, diacritics fold, non-Latin letters stay.
8
+ */
9
+ export function okSlug(text) {
10
+ return text
11
+ .trim()
12
+ .normalize("NFKD")
13
+ .replace(/\p{M}/gu, "")
14
+ .toLowerCase()
15
+ .replace(/[^\p{L}\p{N}]+/gu, "-")
16
+ .replace(/^-+|-+$/g, "");
17
+ }
18
+ /**
19
+ * fragment → anchor for ONE page: every heading it will emit, in order,
20
+ * OpenKnowledge-slugged with `-1`, `-2` on repeats. Keys: the Dogsbay id
21
+ * (`props.slug`), the Dogsbay text slug (what a source link would use, with
22
+ * Dogsbay's own `-1` dedupe), and the OpenKnowledge anchor itself.
23
+ */
24
+ export function pageAnchors(headings) {
25
+ const out = new Map();
26
+ const used = new Map();
27
+ const usedDogsbay = new Map();
28
+ for (const h of headings) {
29
+ const base = okSlug(h.text) || "section";
30
+ const n = used.get(base) ?? 0;
31
+ used.set(base, n + 1);
32
+ const anchor = n === 0 ? base : `${base}-${n}`;
33
+ const dText = slugifyHeadingText(h.text);
34
+ const dn = usedDogsbay.get(dText) ?? 0;
35
+ usedDogsbay.set(dText, dn + 1);
36
+ const dSlug = dn === 0 ? dText : `${dText}-${dn}`;
37
+ for (const key of [h.slug, dSlug, dText, anchor])
38
+ if (key && !out.has(key))
39
+ out.set(key, anchor);
40
+ }
41
+ return out;
42
+ }
43
+ const normalizeSlug = (s) => s.replace(/^\/+|\/+$/g, "").replace(/\/index$/, "") || "index";
44
+ /** Node types whose emission is JSX (must be `.mdx`); mirrors serialize.ts. */
45
+ const JSX_TYPES = new Set(["tabs", "details", "steps", "cards", "grid", "card", "youtube", "mdx-raw"]);
46
+ export function treeNeedsMdx(nodes) {
47
+ const walk = (n) => {
48
+ if (JSX_TYPES.has(n.type))
49
+ return true;
50
+ if (n.type === "callout") {
51
+ const variant = String(n.props?.variant ?? n.props?.type ?? "note").toLowerCase();
52
+ const title = n.props?.title;
53
+ const auto = variant.charAt(0).toUpperCase() + variant.slice(1);
54
+ if (typeof title === "string" && title && title !== auto)
55
+ return true;
56
+ }
57
+ if (n.type === "figure" && n.props?.caption)
58
+ return true;
59
+ return (n.children ?? []).some(walk);
60
+ };
61
+ return nodes.some(walk);
62
+ }
63
+ const JSX_MARK = /^\s*<(Callout|Accordion|Tabs|Steps|Cards|Card|Image|Video)\b/m;
64
+ export function exportOpenKnowledge(pages, _nav, options = {}) {
65
+ const files = new Map();
66
+ const ledger = new ExportLedger();
67
+ const unresolvedFragments = [];
68
+ const unresolvedPages = [];
69
+ const collisions = [];
70
+ const prefix = options.section ? options.section.replace(/^\/+|\/+$/g, "") + "/" : "";
71
+ const placed = [];
72
+ const byKey = new Map();
73
+ const takenPaths = new Map(); // lowercased path → page slug
74
+ const contentPages = pages.filter((p) => !(p.fragment || p.frontmatter?._fragment === true));
75
+ for (const page of contentPages) {
76
+ const key = normalizeSlug(page.slug);
77
+ let path = prefix + key;
78
+ if (takenPaths.has(path.toLowerCase())) {
79
+ const renamed = `${path}--${page.slug.replace(/[^A-Za-z0-9._-]+/g, "-")}`;
80
+ collisions.push({ page: page.slug, path, renamedTo: renamed });
81
+ path = renamed;
82
+ }
83
+ takenPaths.set(path.toLowerCase(), page.slug);
84
+ const ext = options.alwaysMdx || treeNeedsMdx(page.tree) ? "mdx" : "md";
85
+ const entry = { page, key, path, ext, anchors: pageAnchors(collectEmittedHeadings(page.tree)) };
86
+ placed.push(entry);
87
+ if (!byKey.has(key))
88
+ byKey.set(key, entry); // a collided page is reachable by its own file, not by the shared key
89
+ }
90
+ // pass 2: serialize with a resolver that knows every page
91
+ for (const self of placed) {
92
+ const { page } = self;
93
+ ledger.setPage(page.slug);
94
+ // relative links resolve against the page's ORIGINAL directory (`guides/index` → `guides/`)
95
+ const rawSlug = page.slug.replace(/^\/+|\/+$/g, "");
96
+ const dir = rawSlug.includes("/") ? rawSlug.slice(0, rawSlug.lastIndexOf("/") + 1) : "";
97
+ const href = (raw) => {
98
+ if (/^[a-z][a-z0-9+.-]*:/i.test(raw) || raw.startsWith("//"))
99
+ return raw;
100
+ const [pathPart, frag] = splitFragment(raw);
101
+ if (!pathPart) {
102
+ const a = self.anchors.get(frag);
103
+ if (!a && frag)
104
+ unresolvedFragments.push({ page: page.slug, href: raw });
105
+ return `#${a ?? frag}`;
106
+ }
107
+ let target = pathPart.replace(/\.(md|mdx)$/i, "");
108
+ if (!target.startsWith("/")) {
109
+ const parts = [];
110
+ for (const seg of (dir + target).split("/")) {
111
+ if (!seg || seg === ".")
112
+ continue;
113
+ if (seg === "..")
114
+ parts.pop();
115
+ else
116
+ parts.push(seg);
117
+ }
118
+ target = "/" + parts.join("/");
119
+ }
120
+ const key = normalizeSlug(target);
121
+ const hit = byKey.get(key);
122
+ if (!hit) {
123
+ unresolvedPages.push({ page: page.slug, href: raw });
124
+ return defaultHref(`/${prefix}${key}${frag ? `#${frag}` : ""}`);
125
+ }
126
+ let anchor = frag;
127
+ if (frag) {
128
+ const a = hit.anchors.get(frag);
129
+ if (!a)
130
+ unresolvedFragments.push({ page: page.slug, href: raw });
131
+ anchor = a ?? frag;
132
+ }
133
+ return `/${hit.path}.${hit.ext}${anchor ? `#${anchor}` : ""}`;
134
+ };
135
+ const body = treeToOpenKnowledge(page.tree, { href, ledger, page: page.slug });
136
+ // the tree predicate must agree with what was emitted; if JSX slipped through, `.mdx` wins (links to it may say `.md`; OpenKnowledge resolves either)
137
+ const ext = self.ext === "md" && JSX_MARK.test(body) ? "mdx" : self.ext;
138
+ if (ext !== self.ext)
139
+ ledger.record({ feature: "frontmatter", page: page.slug, action: "approximated", detail: "page carries JSX the tree predicate did not foresee; written as .mdx (links to it say .md)" });
140
+ const fm = frontmatterFor(page, ledger);
141
+ files.set(`${self.path}.${ext}`, `${fm}${body}${body.endsWith("\n") ? "" : "\n"}`);
142
+ }
143
+ const problems = validateLedgerAgainstCapabilities(ledger, OPENKNOWLEDGE_CAPABILITIES);
144
+ if (problems.length)
145
+ throw new Error(`OpenKnowledge export recorded an undeclared loss: ${problems.join("; ")}`);
146
+ return { files, ledger, unresolvedFragments, unresolvedPages, collisions };
147
+ }
148
+ function frontmatterFor(page, ledger) {
149
+ const src = page.frontmatter ?? {};
150
+ const lines = [];
151
+ const title = typeof src.title === "string" && src.title ? src.title : page.title;
152
+ if (title)
153
+ lines.push(`title: ${yamlScalar(title)}`);
154
+ if (typeof src.description === "string" && src.description)
155
+ lines.push(`description: ${yamlScalar(src.description)}`);
156
+ for (const listKey of ["tags", "aliases"]) {
157
+ const v = src[listKey];
158
+ const items = Array.isArray(v) ? v.filter((t) => typeof t === "string") : typeof v === "string" && v ? [v] : [];
159
+ if (items.length)
160
+ lines.push(`${listKey}: [${items.map(yamlScalar).join(", ")}]`);
161
+ }
162
+ for (const [k, v] of Object.entries(src)) {
163
+ if (["title", "description", "tags", "aliases"].includes(k) || k.startsWith("_"))
164
+ continue;
165
+ if (typeof v === "string")
166
+ lines.push(`${k}: ${yamlScalar(v)}`);
167
+ else if (typeof v === "number" || typeof v === "boolean")
168
+ lines.push(`${k}: ${v}`);
169
+ else if (v !== null && v !== undefined)
170
+ ledger.record({ feature: "frontmatter", page: page.slug, action: "dropped", detail: `frontmatter key "${k}" (${Array.isArray(v) ? "list" : typeof v}) not carried` });
171
+ }
172
+ return lines.length ? `---\n${lines.join("\n")}\n---\n\n` : "";
173
+ }
174
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"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"}