@dogsbay/format-mkdocs 0.2.0-beta.13 → 0.2.0-beta.130

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 (147) hide show
  1. package/dist/cli.d.ts +0 -1
  2. package/dist/cli.js +115 -5
  3. package/dist/export/capabilities.d.ts +22 -0
  4. package/dist/export/capabilities.js +213 -0
  5. package/dist/export/to-astro.d.ts +0 -1
  6. package/dist/export/to-astro.js +10 -2
  7. package/dist/export/to-mkdocs-project.d.ts +12 -1
  8. package/dist/export/to-mkdocs-project.js +279 -64
  9. package/dist/export/to-mkdocs.d.ts +53 -4
  10. package/dist/export/to-mkdocs.js +905 -104
  11. package/dist/importer.d.ts +0 -1
  12. package/dist/importer.js +3 -2
  13. package/dist/index.d.ts +21 -4
  14. package/dist/index.js +40 -4
  15. package/dist/inline-walker.d.ts +0 -1
  16. package/dist/inline-walker.js +0 -1
  17. package/dist/loader.d.ts +1 -2
  18. package/dist/loader.js +28 -9
  19. package/dist/parse.d.ts +0 -1
  20. package/dist/parse.js +0 -1
  21. package/dist/renderers/mermaid.d.ts +0 -1
  22. package/dist/renderers/mermaid.js +0 -1
  23. package/dist/rules/admonition.d.ts +0 -1
  24. package/dist/rules/admonition.js +0 -1
  25. package/dist/rules/annotations.d.ts +0 -1
  26. package/dist/rules/annotations.js +0 -1
  27. package/dist/rules/autodoc.d.ts +1 -2
  28. package/dist/rules/autodoc.js +1 -3
  29. package/dist/rules/blocks.d.ts +0 -1
  30. package/dist/rules/blocks.js +0 -1
  31. package/dist/rules/content-tabs.d.ts +0 -1
  32. package/dist/rules/content-tabs.js +0 -1
  33. package/dist/rules/docusaurus-admonitions.d.ts +0 -1
  34. package/dist/rules/docusaurus-admonitions.js +0 -1
  35. package/dist/rules/file-include.d.ts +0 -1
  36. package/dist/rules/file-include.js +0 -1
  37. package/dist/rules/footnotes.d.ts +0 -1
  38. package/dist/rules/footnotes.js +0 -1
  39. package/dist/rules/icon-shortcode.d.ts +0 -1
  40. package/dist/rules/icon-shortcode.js +0 -1
  41. package/dist/rules/keys.d.ts +0 -1
  42. package/dist/rules/keys.js +0 -1
  43. package/dist/rules/link-rewrite.d.ts +0 -1
  44. package/dist/rules/link-rewrite.js +0 -1
  45. package/dist/rules/math.d.ts +0 -1
  46. package/dist/rules/math.js +0 -1
  47. package/dist/rules/md-in-html.d.ts +0 -1
  48. package/dist/rules/md-in-html.js +0 -1
  49. package/dist/rules/snippets.d.ts +0 -1
  50. package/dist/rules/snippets.js +0 -1
  51. package/dist/rules/templates.d.ts +0 -1
  52. package/dist/rules/templates.js +0 -1
  53. package/dist/rules/variants.d.ts +0 -1
  54. package/dist/rules/variants.js +0 -1
  55. package/dist/tree.d.ts +0 -1
  56. package/dist/tree.js +0 -1
  57. package/dist/utils/indent.d.ts +0 -1
  58. package/dist/utils/indent.js +0 -1
  59. package/dist/utils/types.d.ts +0 -1
  60. package/dist/utils/types.js +0 -1
  61. package/dist/walker.d.ts +0 -1
  62. package/dist/walker.js +0 -1
  63. package/package.json +13 -12
  64. package/dist/autodoc/markdown-generator.d.ts +0 -6
  65. package/dist/autodoc/markdown-generator.d.ts.map +0 -1
  66. package/dist/autodoc/markdown-generator.js +0 -242
  67. package/dist/autodoc/markdown-generator.js.map +0 -1
  68. package/dist/autodoc/module-resolver.d.ts +0 -8
  69. package/dist/autodoc/module-resolver.d.ts.map +0 -1
  70. package/dist/autodoc/module-resolver.js +0 -218
  71. package/dist/autodoc/module-resolver.js.map +0 -1
  72. package/dist/autodoc/python-docstring.d.ts +0 -7
  73. package/dist/autodoc/python-docstring.d.ts.map +0 -1
  74. package/dist/autodoc/python-docstring.js +0 -324
  75. package/dist/autodoc/python-docstring.js.map +0 -1
  76. package/dist/autodoc/python-parser.d.ts +0 -10
  77. package/dist/autodoc/python-parser.d.ts.map +0 -1
  78. package/dist/autodoc/python-parser.js +0 -541
  79. package/dist/autodoc/python-parser.js.map +0 -1
  80. package/dist/autodoc/tree-builder.d.ts +0 -9
  81. package/dist/autodoc/tree-builder.d.ts.map +0 -1
  82. package/dist/autodoc/tree-builder.js +0 -279
  83. package/dist/autodoc/tree-builder.js.map +0 -1
  84. package/dist/autodoc/types.d.ts +0 -128
  85. package/dist/autodoc/types.d.ts.map +0 -1
  86. package/dist/autodoc/types.js +0 -2
  87. package/dist/autodoc/types.js.map +0 -1
  88. package/dist/cli.d.ts.map +0 -1
  89. package/dist/cli.js.map +0 -1
  90. package/dist/export/to-astro.d.ts.map +0 -1
  91. package/dist/export/to-astro.js.map +0 -1
  92. package/dist/export/to-mkdocs-project.d.ts.map +0 -1
  93. package/dist/export/to-mkdocs-project.js.map +0 -1
  94. package/dist/export/to-mkdocs.d.ts.map +0 -1
  95. package/dist/export/to-mkdocs.js.map +0 -1
  96. package/dist/importer.d.ts.map +0 -1
  97. package/dist/importer.js.map +0 -1
  98. package/dist/index.d.ts.map +0 -1
  99. package/dist/index.js.map +0 -1
  100. package/dist/inline-walker.d.ts.map +0 -1
  101. package/dist/inline-walker.js.map +0 -1
  102. package/dist/loader.d.ts.map +0 -1
  103. package/dist/loader.js.map +0 -1
  104. package/dist/parse.d.ts.map +0 -1
  105. package/dist/parse.js.map +0 -1
  106. package/dist/renderers/mermaid.d.ts.map +0 -1
  107. package/dist/renderers/mermaid.js.map +0 -1
  108. package/dist/rules/admonition.d.ts.map +0 -1
  109. package/dist/rules/admonition.js.map +0 -1
  110. package/dist/rules/annotations.d.ts.map +0 -1
  111. package/dist/rules/annotations.js.map +0 -1
  112. package/dist/rules/autodoc.d.ts.map +0 -1
  113. package/dist/rules/autodoc.js.map +0 -1
  114. package/dist/rules/blocks.d.ts.map +0 -1
  115. package/dist/rules/blocks.js.map +0 -1
  116. package/dist/rules/content-tabs.d.ts.map +0 -1
  117. package/dist/rules/content-tabs.js.map +0 -1
  118. package/dist/rules/docusaurus-admonitions.d.ts.map +0 -1
  119. package/dist/rules/docusaurus-admonitions.js.map +0 -1
  120. package/dist/rules/file-include.d.ts.map +0 -1
  121. package/dist/rules/file-include.js.map +0 -1
  122. package/dist/rules/footnotes.d.ts.map +0 -1
  123. package/dist/rules/footnotes.js.map +0 -1
  124. package/dist/rules/icon-shortcode.d.ts.map +0 -1
  125. package/dist/rules/icon-shortcode.js.map +0 -1
  126. package/dist/rules/keys.d.ts.map +0 -1
  127. package/dist/rules/keys.js.map +0 -1
  128. package/dist/rules/link-rewrite.d.ts.map +0 -1
  129. package/dist/rules/link-rewrite.js.map +0 -1
  130. package/dist/rules/math.d.ts.map +0 -1
  131. package/dist/rules/math.js.map +0 -1
  132. package/dist/rules/md-in-html.d.ts.map +0 -1
  133. package/dist/rules/md-in-html.js.map +0 -1
  134. package/dist/rules/snippets.d.ts.map +0 -1
  135. package/dist/rules/snippets.js.map +0 -1
  136. package/dist/rules/templates.d.ts.map +0 -1
  137. package/dist/rules/templates.js.map +0 -1
  138. package/dist/rules/variants.d.ts.map +0 -1
  139. package/dist/rules/variants.js.map +0 -1
  140. package/dist/tree.d.ts.map +0 -1
  141. package/dist/tree.js.map +0 -1
  142. package/dist/utils/indent.d.ts.map +0 -1
  143. package/dist/utils/indent.js.map +0 -1
  144. package/dist/utils/types.d.ts.map +0 -1
  145. package/dist/utils/types.js.map +0 -1
  146. package/dist/walker.d.ts.map +0 -1
  147. package/dist/walker.js.map +0 -1
package/dist/cli.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  import type { FormatPlugin } from "@dogsbay/types";
2
2
  export declare const plugin: FormatPlugin;
3
- //# sourceMappingURL=cli.d.ts.map
package/dist/cli.js CHANGED
@@ -1,10 +1,14 @@
1
- import { existsSync } from "node:fs";
2
- import { join } from "node:path";
1
+ import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, writeFileSync, copyFileSync } from "node:fs";
2
+ import { dirname, extname, join } from "node:path";
3
3
  import { importMkdocsProject } from "./importer.js";
4
+ import { exportMkdocsProject } from "./export/to-mkdocs-project.js";
5
+ import { formatLedgerReport } from "@dogsbay/serialize-core";
6
+ import { MKDOCS_CAPABILITIES } from "./export/capabilities.js";
4
7
  export const plugin = {
5
8
  name: "mkdocs",
6
9
  canImport: true,
7
10
  canExport: true,
11
+ capabilities: MKDOCS_CAPABILITIES,
8
12
  detectSource: (path) => existsSync(join(path, "mkdocs.yml")),
9
13
  importOptions: [
10
14
  { flags: "--theme <name>", description: "Theme preset (default, material)", default: "default" },
@@ -12,7 +16,15 @@ export const plugin = {
12
16
  { flags: "--custom-css <files>", description: "Custom CSS files to copy (comma-separated)" },
13
17
  { flags: "--docusaurus-admonitions", description: "Enable Docusaurus-style ::: admonitions" },
14
18
  ],
15
- exportOptions: [],
19
+ // NOT `--theme`: `dogsbay convert` already owns that flag for the Astro
20
+ // preset, with a default of "default" — which reached this exporter as
21
+ // `theme: name: default`, a theme MkDocs does not have, and every
22
+ // `convert --to mkdocs` project failed its first `mkdocs build`.
23
+ exportOptions: [
24
+ { flags: "--mkdocs-theme <name>", description: "MkDocs theme for the emitted mkdocs.yml (material | mkdocs | readthedocs)", default: "material" },
25
+ { flags: "--site-url <url>", description: "site_url for the emitted mkdocs.yml" },
26
+ { flags: "--repo-url <url>", description: "repo_url for the emitted mkdocs.yml" },
27
+ ],
16
28
  async import(source, opts) {
17
29
  const { pages, nav, config } = await importMkdocsProject(source, opts);
18
30
  // Attach config metadata for the exporter to consume
@@ -26,7 +38,105 @@ export const plugin = {
26
38
  if (extraCss && Array.isArray(extraCss)) {
27
39
  opts.extraCss = extraCss;
28
40
  }
29
- return { pages, nav };
41
+ // Slugs are relative to `docs_dir`, not to the project root — so an
42
+ // `{% include %}` in a page means a file under THERE.
43
+ return { pages, nav, contentRoot: join(source, config.docsDir) };
44
+ },
45
+ /**
46
+ * Export: TreeNode pages + nav → a complete MkDocs project.
47
+ *
48
+ * `exportMkdocsProject` is I/O-free and returns a path → content map, so
49
+ * everything this method does is create directories and write bytes. It was
50
+ * written and unit-tested long before it was reachable: `cli.ts` declared
51
+ * `canExport: true` with no `export` method, and `resolveExporter()` filters
52
+ * on `canExport && f.export`, so `--to mkdocs` reported an unknown target
53
+ * while the serializer sat in the same package. That predicate exists
54
+ * BECAUSE of this plugin.
55
+ */
56
+ async export(pages, nav, output, opts) {
57
+ const result = exportMkdocsProject(pages, nav, {
58
+ siteName: opts.siteName ?? "Documentation",
59
+ siteUrl: opts.siteUrl,
60
+ repoUrl: opts.repoUrl,
61
+ copyright: opts.copyright,
62
+ poweredBy: opts.poweredBy,
63
+ theme: mkdocsTheme(opts),
64
+ });
65
+ for (const [filePath, content] of result.files) {
66
+ const fullPath = join(output, filePath);
67
+ mkdirSync(dirname(fullPath), { recursive: true });
68
+ writeFileSync(fullPath, content);
69
+ }
70
+ console.log(`Generated ${result.files.size} MkDocs files`);
71
+ // Mounted asset dirs, copied under docs/ at the ROOT their refs were
72
+ // rewritten to (`_assets` for an imported corpus, `images`/`assets` for
73
+ // hand-authored content). The serializer emits those refs relative to
74
+ // each page, so the file has to land exactly there or every image 404s
75
+ // with a clean exit code.
76
+ const mounts = opts.assetMounts;
77
+ for (const mount of mounts ?? []) {
78
+ if (!existsSync(mount.dir))
79
+ continue;
80
+ const root = mount.root ?? "_assets";
81
+ const dest = mount.into ? join(output, "docs", root, mount.into) : join(output, "docs", root);
82
+ mkdirSync(dest, { recursive: true });
83
+ if (mount.mediaOnly) {
84
+ copyMediaTree(mount.dir, dest);
85
+ continue;
86
+ }
87
+ // Skip symlinks rather than copy them: relative links are rewritten to
88
+ // ABSOLUTE paths into the source checkout, so the output only works on
89
+ // the machine that produced it. AsciiBinder corpora are full of them.
90
+ cpSync(mount.dir, dest, {
91
+ recursive: true,
92
+ dereference: false,
93
+ filter: (src) => !lstatSync(src).isSymbolicLink(),
94
+ });
95
+ }
96
+ // Co-located media next to the markdown (the mkdocs shape itself).
97
+ const sourceDir = opts.sourceDir;
98
+ if (sourceDir && existsSync(sourceDir))
99
+ copyMediaTree(sourceDir, join(output, "docs"));
100
+ if (!result.ledger.isEmpty) {
101
+ console.log(formatLedgerReport(result.ledger, "mkdocs"));
102
+ }
30
103
  },
31
104
  };
32
- //# sourceMappingURL=cli.js.map
105
+ const MEDIA_EXT = new Set([".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".avif", ".mp4", ".webm", ".pdf", ".ico"]);
106
+ /**
107
+ * Copy media files only, preserving the directory shape. Never follows a
108
+ * symlink: AsciiBinder corpora symlink every section back to one images
109
+ * tree, and following them copied a 64 MB tree once per link.
110
+ */
111
+ function copyMediaTree(from, to) {
112
+ for (const entry of readdirSync(from, { withFileTypes: true })) {
113
+ if (entry.isSymbolicLink())
114
+ continue;
115
+ const src = join(from, entry.name);
116
+ if (entry.isDirectory()) {
117
+ if (entry.name === "node_modules" || entry.name.startsWith("."))
118
+ continue;
119
+ copyMediaTree(src, join(to, entry.name));
120
+ continue;
121
+ }
122
+ if (!MEDIA_EXT.has(extname(entry.name).toLowerCase()))
123
+ continue;
124
+ // Always copy. A same-size skip saved nothing measurable and silently
125
+ // kept a stale file when a one-character SVG edit left the size unchanged.
126
+ mkdirSync(to, { recursive: true });
127
+ copyFileSync(src, join(to, entry.name));
128
+ }
129
+ }
130
+ const MKDOCS_THEMES = new Set(["material", "mkdocs", "readthedocs"]);
131
+ /**
132
+ * The MkDocs theme to write. `--mkdocs-theme` wins; a bare `theme` is honoured
133
+ * only when it names a theme MkDocs actually has, so the Astro preset default
134
+ * ("default") that `convert` passes through can never reach mkdocs.yml.
135
+ */
136
+ function mkdocsTheme(opts) {
137
+ for (const candidate of [opts.mkdocsTheme, opts.theme]) {
138
+ if (typeof candidate === "string" && MKDOCS_THEMES.has(candidate))
139
+ return candidate;
140
+ }
141
+ return "material";
142
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * What the MkDocs (Material + PyMdown) exporter can and cannot represent.
3
+ *
4
+ * This is a CONTRACT, not commentary: `validateCapabilities` rejects any
5
+ * non-full entry without a note, and `tests/capabilities.test.ts` asserts every
6
+ * row of the component × format matrix (`MATRIX_ROWS` in
7
+ * @dogsbay/serialize-core) is declared exactly once. Each cell was set by
8
+ * reading `to-mkdocs.ts` / `to-mkdocs-project.ts` AND running the serializer
9
+ * on real parsed dogsbay-md, not from the extension list.
10
+ *
11
+ * Support levels:
12
+ * full — round-trips faithfully (given the extensions the project
13
+ * emitter enables in mkdocs.yml)
14
+ * partial — survives with reduced fidelity (styling/semantics lost)
15
+ * none — no MkDocs construct; the wrapper is dropped and the content
16
+ * flattened into plain blocks (recorded as the node type)
17
+ *
18
+ * A `partial` here is not necessarily recorded per page — several are known
19
+ * structural limits the serializer does not ledger (noted where so).
20
+ */
21
+ import type { CapabilityDeclaration } from "@dogsbay/serialize-core";
22
+ export declare const MKDOCS_CAPABILITIES: CapabilityDeclaration[];
@@ -0,0 +1,213 @@
1
+ export const MKDOCS_CAPABILITIES = [
2
+ // ── Blocks ──────────────────────────────────────────────
3
+ {
4
+ feature: "heading",
5
+ support: "partial",
6
+ rendersAs: "`#`–`######` with the authored id as `{ #id }` (attr_list)",
7
+ note: "The id survives; heading classes (`{.cls}`) are dropped, unrecorded.",
8
+ },
9
+ { feature: "paragraph", support: "full" },
10
+ { feature: "blockquote", support: "full", rendersAs: "`> …`" },
11
+ { feature: "unordered-list", support: "full", rendersAs: "`- item`, four-space continuation; task items via pymdownx.tasklist" },
12
+ { feature: "ordered-list", support: "full", rendersAs: "`1. item` (start number kept)" },
13
+ { feature: "hr", support: "full", rendersAs: "`---`" },
14
+ {
15
+ feature: "table",
16
+ support: "partial",
17
+ rendersAs: "GFM pipe table; `<table markdown>` with `markdown=\"block\"` cells when a cell holds block content or spans",
18
+ note: "The table's caption, id and classes are dropped, unrecorded.",
19
+ },
20
+ {
21
+ feature: "code",
22
+ support: "partial",
23
+ rendersAs: "fence with language, `title=\"…\"` and `hl_lines` (pymdownx.highlight + superfences)",
24
+ note: "Code annotations are not recreated: the `(N)!` markers come back as literal `(N)` in the code (no `.annotate` class, no `content.code.annotate` feature), unrecorded.",
25
+ },
26
+ {
27
+ feature: "math-block",
28
+ support: "partial",
29
+ rendersAs: "`$$ … $$` (pymdownx.arithmatex, generic)",
30
+ note: "The LaTeX survives, but arithmatex `generic` needs MathJax/KaTeX in `extra_javascript` and the emitted mkdocs.yml adds none, so it is not typeset until one is added.",
31
+ },
32
+ { feature: "deflist", support: "full", rendersAs: "`Term` / `: definition` (def_list)" },
33
+ { feature: "figure", support: "full", rendersAs: "`<figure markdown>` + `<figcaption>` (md_in_html); the bare image when there is no caption" },
34
+ { feature: "footnote-list", support: "full", rendersAs: "`[^label]: …` (footnotes)" },
35
+ { feature: "html", support: "full", rendersAs: "raw HTML passed through, site-rooted asset paths made relative" },
36
+ { feature: "html-container", support: "full", rendersAs: "`<tag attrs markdown>` (md_in_html); `on*` attributes stripped" },
37
+ {
38
+ feature: "diagram",
39
+ support: "partial",
40
+ rendersAs: "```mermaid fence (superfences custom fence → Material's Mermaid)",
41
+ note: "Only Mermaid is rendered. Any other diagram language (plantuml, d2, …) is emitted as a fence no configured extension renders, so it shows as source code — unrecorded.",
42
+ },
43
+ { feature: "youtube", support: "full", rendersAs: "`<iframe>` on youtube-nocookie.com" },
44
+ // ── Components ──────────────────────────────────────────
45
+ {
46
+ feature: "callout",
47
+ support: "partial",
48
+ rendersAs: "`!!! type \"title\"` (admonition)",
49
+ note: "Variants Material lacks map to the nearest (`caution`/`important` → warning, keeping the word as the title); a custom per-callout icon is dropped, unrecorded.",
50
+ },
51
+ { feature: "details", support: "full", rendersAs: "`??? type \"title\"` / `???+` when open (pymdownx.details)" },
52
+ { feature: "details-sheet", support: "partial", rendersAs: "a normal collapsible block", note: "MkDocs Material has no side-sheet component: a `sheet` details is written as an ordinary collapsible block, content intact." },
53
+ { feature: "theme", support: "partial", rendersAs: "the content, unthemed", note: "MkDocs Material has no scoped themes: the wrapper is dropped and the content kept, in the page's own theme." },
54
+ { feature: "tabs-variant", support: "partial", rendersAs: "the default tabs", note: "MkDocs Material draws one tab style: a pills or underline variant shows as the default." },
55
+ { feature: "tone", support: "partial", rendersAs: "untinted cards", note: "MkDocs Material cards take no tone: the colour is lost, the content kept." },
56
+ { feature: "tabs", support: "full", rendersAs: "`=== \"Label\"` (pymdownx.tabbed, alternate_style)" },
57
+ {
58
+ feature: "steps",
59
+ support: "partial",
60
+ rendersAs: "ordered list with bold step titles",
61
+ note: "MkDocs has no steps component; recorded as `steps` degraded.",
62
+ },
63
+ {
64
+ feature: "accordion",
65
+ support: "partial",
66
+ rendersAs: "one `??? note \"Label\"` fold per item (pymdownx.details)",
67
+ note: "Material has no accordion: items fold independently, so opening one does not close the others, and a `defaultValue` is not applied.",
68
+ },
69
+ {
70
+ feature: "cards",
71
+ support: "partial",
72
+ rendersAs: "`<div class=\"grid cards\" markdown>` list (Material grid cards)",
73
+ note: "A column count is dropped — Material's grid is responsive. Unrecorded.",
74
+ },
75
+ {
76
+ feature: "card",
77
+ support: "partial",
78
+ rendersAs: "grid-card list item: bold title, body, `[:octicons-arrow-right-24: Title](href)`",
79
+ note: "The card's icon is dropped (unrecorded); an href becomes a trailing link rather than a clickable card.",
80
+ },
81
+ {
82
+ feature: "link-card",
83
+ support: "partial",
84
+ rendersAs: "bold title, description, trailing arrow link (a grid card when inside `cards`)",
85
+ note: "No link-card component; outside a card grid it is plain blocks. Unrecorded.",
86
+ },
87
+ {
88
+ feature: "files",
89
+ support: "partial",
90
+ rendersAs: "the nested list",
91
+ note: "No file-tree view: folders and files are a nested bulleted list.",
92
+ },
93
+ {
94
+ feature: "grid",
95
+ support: "partial",
96
+ rendersAs: "`<div class=\"grid cards\" markdown>` list",
97
+ note: "Rendered with CARD styling (not Material's plain `grid`); the column count is dropped and each `grid-item` wrapper is recorded as `grid-item`.",
98
+ },
99
+ {
100
+ feature: "link-button",
101
+ support: "partial",
102
+ rendersAs: "`[label](href){ .md-button .md-button--primary }`",
103
+ note: "Always the primary style — a variant is dropped. An unsafe href is dropped and recorded.",
104
+ },
105
+ {
106
+ feature: "related",
107
+ support: "partial",
108
+ rendersAs: "bold label + the link list",
109
+ note: "No related-links component: the semantic block becomes plain markdown.",
110
+ },
111
+ {
112
+ feature: "example",
113
+ support: "partial",
114
+ rendersAs: "the rendered children as plain blocks",
115
+ note: "No MkDocs example container: the wrapper is dropped (recorded) and the example's source listing (`props.source`) is lost; the preview content is kept.",
116
+ },
117
+ {
118
+ feature: "container",
119
+ support: "partial",
120
+ rendersAs: "the children as plain blocks",
121
+ note: "No MkDocs equivalent: the wrapper, its name and classes are dropped (recorded); the content is kept.",
122
+ },
123
+ {
124
+ feature: "annotation-list",
125
+ support: "partial",
126
+ rendersAs: "a plain ordered list after the code block",
127
+ note: "Material code annotations are not recreated (see `code`): the list renders as an ordinary numbered list. Unrecorded.",
128
+ },
129
+ // ── API reference ───────────────────────────────────────
130
+ {
131
+ feature: "endpoint",
132
+ support: "none",
133
+ rendersAs: "children only, or `<!-- unsupported: endpoint -->`",
134
+ note: "No case: method, path and summary are lost; any children are kept as plain blocks. Recorded as `endpoint` (action `degraded`, even when nothing survives).",
135
+ },
136
+ {
137
+ feature: "api-doc",
138
+ support: "partial",
139
+ rendersAs: "the docstring HTML converted to inline markdown",
140
+ note: "`props.html` is FLATTENED to one line: paragraphs, lists and code blocks run together with no separators (`<p>A.</p><ul><li>one</li>` → `A.one`). Unrecorded. Children-only api-docs are fine.",
141
+ },
142
+ {
143
+ feature: "api-class",
144
+ support: "partial",
145
+ rendersAs: "`### kind \\`name\\``, `Bases:` line, signature as a python fence",
146
+ note: "Plain headings and code, not mkdocstrings' object markup; the signature is always labelled python.",
147
+ },
148
+ {
149
+ feature: "api-member",
150
+ support: "partial",
151
+ rendersAs: "`#### kind \\`name\\``, signature as a python fence",
152
+ note: "As api-class.",
153
+ },
154
+ {
155
+ feature: "api-params",
156
+ support: "partial",
157
+ rendersAs: "raw HTML PARAMETER/DESCRIPTION table (mkdocstrings' layout)",
158
+ note: "Raw HTML without mkdocstrings' classes, so Material styles it as a plain table.",
159
+ },
160
+ {
161
+ feature: "api-source",
162
+ support: "partial",
163
+ rendersAs: "`*Source: file:line*` + a python fence",
164
+ note: "Not a collapsible source block; the code is always labelled python.",
165
+ },
166
+ // ── Inline ──────────────────────────────────────────────
167
+ {
168
+ feature: "link",
169
+ support: "partial",
170
+ rendersAs: "`[text](href \"title\"){ attrs }`; exported pages as relative `.md` links",
171
+ note: "An inline `:button[…]` link loses its button styling (no `.md-button`), unrecorded. An unsafe href is dropped (text kept) and recorded.",
172
+ },
173
+ {
174
+ feature: "image",
175
+ support: "full",
176
+ rendersAs: "`![alt](src \"title\"){ width height }` with a page-relative path (an unsafe src is refused, alt kept, and recorded)",
177
+ },
178
+ { feature: "kbd", support: "full", rendersAs: "`++ctrl+s++` (pymdownx.keys); a non-name key as a quoted key" },
179
+ {
180
+ feature: "math",
181
+ support: "partial",
182
+ rendersAs: "`$…$` (pymdownx.arithmatex, generic)",
183
+ note: "As math-block: not typeset until MathJax/KaTeX is added to `extra_javascript`.",
184
+ },
185
+ { feature: "highlight", support: "full", rendersAs: "`==text==` (pymdownx.mark)" },
186
+ {
187
+ feature: "badge",
188
+ support: "partial",
189
+ rendersAs: "plain text",
190
+ note: "No badge construct: the label is kept, the variant dropped. Recorded as `badge` degraded.",
191
+ },
192
+ {
193
+ feature: "icon",
194
+ support: "partial",
195
+ rendersAs: "`:name:` (pymdownx.emoji, Material/octicons/fontawesome/simple icon sets)",
196
+ note: "The library prefix is dropped (`lucide:check` → `:check:`); a name outside the Material emoji index renders as literal `:name:` text. Unrecorded.",
197
+ },
198
+ { feature: "footnote-ref", support: "full", rendersAs: "`[^label]` (footnotes)" },
199
+ { feature: "html-inline", support: "full", rendersAs: "raw inline HTML passed through" },
200
+ // ── Named concerns the exporter already records ─────────
201
+ {
202
+ feature: "include",
203
+ support: "partial",
204
+ rendersAs: "`--8<-- \"path\"` (pymdownx.snippets)",
205
+ note: "Includes are realized before export; one that arrives unresolved is emitted as a snippet reference and recorded.",
206
+ },
207
+ {
208
+ feature: "nav-entry",
209
+ support: "partial",
210
+ rendersAs: "mkdocs.yml `nav:` entry",
211
+ note: "A nav entry pointing at a page not in the export (or a section with no exported pages) is dropped and recorded.",
212
+ },
213
+ ];
@@ -23,4 +23,3 @@ export declare function escapeAttr(s: string): string;
23
23
  /** Escape text for use directly in an Astro template (not inside an expression). */
24
24
  export declare function escapeTemplate(s: string): string;
25
25
  export declare function treeToAstro(nodes: TreeNode[], options?: AstroGenOptions): AstroGenResult;
26
- //# sourceMappingURL=to-astro.d.ts.map
@@ -57,7 +57,12 @@ export function escapeExpr(s) {
57
57
  // JSON.stringify handles all special characters (quotes, backslashes, newlines, etc.)
58
58
  // and produces a valid JS string literal. This avoids template literal edge cases
59
59
  // where backtick + brace combinations create false expression boundaries.
60
- return JSON.stringify(s);
60
+ //
61
+ // `<` becomes \u003c: Astro parses the template as HTML before the expression is
62
+ // JavaScript, so a `<script>` inside a string (a code block showing one, say) would
63
+ // be taken for a real script tag and its text compiled as JavaScript. Vite's
64
+ // dependency scan then fails to parse it and a production build breaks.
65
+ return JSON.stringify(s).replace(/</g, "\\u003c");
61
66
  }
62
67
  /** Escape for use in an HTML attribute value (double-quoted). */
63
68
  export function escapeAttr(s) {
@@ -244,6 +249,8 @@ function inlineNodeToTemplate(node) {
244
249
  return `<sup><a href="#fn-${escapeAttr(node.label)}" id="fnref-${escapeAttr(node.label)}" class="text-primary hover:underline">[${escapeTemplate(node.label)}]</a></sup>`;
245
250
  case "kbd":
246
251
  return node.keys.map((k) => `<kbd>${escapeTemplate(k)}</kbd>`).join("+");
252
+ case "badge":
253
+ return `<span data-badge data-variant="${escapeAttr(node.variant ?? "default")}">${escapeTemplate(node.text)}</span>`;
247
254
  case "math":
248
255
  return `<code class="math-inline">${escapeTemplate(node.latex)}</code>`;
249
256
  case "icon":
@@ -285,6 +292,8 @@ function inlineNodeToHtml(node) {
285
292
  return `<sup><a href="#fn-${escapeAttr(node.label)}" id="fnref-${escapeAttr(node.label)}" class="text-primary hover:underline">[${escapeHtml(node.label)}]</a></sup>`;
286
293
  case "kbd":
287
294
  return node.keys.map((k) => `<kbd>${escapeHtml(k)}</kbd>`).join("+");
295
+ case "badge":
296
+ return `<span data-badge data-variant="${escapeAttr(node.variant ?? "default")}">${escapeHtml(node.text)}</span>`;
288
297
  case "math":
289
298
  return `<code class="math-inline">${escapeHtml(node.latex)}</code>`;
290
299
  case "icon":
@@ -548,4 +557,3 @@ function indentStr(text, spaces) {
548
557
  function escapeHtml(s) {
549
558
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
550
559
  }
551
- //# sourceMappingURL=to-astro.js.map
@@ -1,4 +1,5 @@
1
1
  import type { ExportPage, NavItem } from "@dogsbay/types";
2
+ import { ExportLedger } from "@dogsbay/serialize-core";
2
3
  /**
3
4
  * Options for project export.
4
5
  */
@@ -10,6 +11,15 @@ export interface MkdocsProjectOptions {
10
11
  extraExtensions?: string[];
11
12
  /** Theme name (default: "material") */
12
13
  theme?: string;
14
+ /** Existing footer copyright, if the site declares one. */
15
+ copyright?: string;
16
+ /**
17
+ * Append "Powered by DogsBay" to the footer. Default ON; `poweredBy: false`
18
+ * in dogsbay.config.yml removes it. MkDocs has no attribution slot, so it
19
+ * rides along in `copyright:` — the one string Material renders in the
20
+ * footer. See docs/powered-by.md.
21
+ */
22
+ poweredBy?: boolean;
13
23
  }
14
24
  /**
15
25
  * Result of a project export.
@@ -18,10 +28,11 @@ export interface MkdocsProjectOptions {
18
28
  export interface MkdocsProjectExport {
19
29
  files: Map<string, string>;
20
30
  mkdocsYml: string;
31
+ /** What could not be represented, per page. Empty is the goal, not the assumption. */
32
+ ledger: ExportLedger;
21
33
  }
22
34
  /**
23
35
  * Export a set of pages + navigation to a complete MkDocs project.
24
36
  * Returns file map (path → content) including mkdocs.yml and all .md files.
25
37
  */
26
38
  export declare function exportMkdocsProject(pages: ExportPage[], nav: NavItem[], options: MkdocsProjectOptions): MkdocsProjectExport;
27
- //# sourceMappingURL=to-mkdocs-project.d.ts.map