@dogsbay/format-dogsbay-md 0.2.0-beta.5 → 0.2.0-beta.50

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 (50) hide show
  1. package/dist/attributes.d.ts +16 -1
  2. package/dist/attributes.d.ts.map +1 -1
  3. package/dist/attributes.js +14 -2
  4. package/dist/attributes.js.map +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +44 -3
  7. package/dist/cli.js.map +1 -1
  8. package/dist/directives.js +23 -1
  9. package/dist/directives.js.map +1 -1
  10. package/dist/escape.d.ts +29 -0
  11. package/dist/escape.d.ts.map +1 -1
  12. package/dist/escape.js +66 -1
  13. package/dist/escape.js.map +1 -1
  14. package/dist/index.d.ts +4 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/inline.d.ts +17 -0
  19. package/dist/inline.d.ts.map +1 -1
  20. package/dist/inline.js +123 -6
  21. package/dist/inline.js.map +1 -1
  22. package/dist/nav-file.d.ts +24 -3
  23. package/dist/nav-file.d.ts.map +1 -1
  24. package/dist/nav-file.js +31 -11
  25. package/dist/nav-file.js.map +1 -1
  26. package/dist/nav.d.ts +7 -0
  27. package/dist/nav.d.ts.map +1 -1
  28. package/dist/nav.js +14 -2
  29. package/dist/nav.js.map +1 -1
  30. package/dist/parse.d.ts.map +1 -1
  31. package/dist/parse.js +328 -4
  32. package/dist/parse.js.map +1 -1
  33. package/dist/plugin-containers.d.ts +1 -1
  34. package/dist/plugin-containers.d.ts.map +1 -1
  35. package/dist/plugin-containers.js +13 -0
  36. package/dist/plugin-containers.js.map +1 -1
  37. package/dist/renderers/diagrams.d.ts +25 -0
  38. package/dist/renderers/diagrams.d.ts.map +1 -0
  39. package/dist/renderers/diagrams.js +71 -0
  40. package/dist/renderers/diagrams.js.map +1 -0
  41. package/dist/renderers/mermaid.d.ts +24 -0
  42. package/dist/renderers/mermaid.d.ts.map +1 -0
  43. package/dist/renderers/mermaid.js +135 -0
  44. package/dist/renderers/mermaid.js.map +1 -0
  45. package/dist/serialize.js +80 -6
  46. package/dist/serialize.js.map +1 -1
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/types.js +18 -1
  49. package/dist/types.js.map +1 -1
  50. package/package.json +5 -2
@@ -8,12 +8,27 @@
8
8
  export interface RenderedAttrs {
9
9
  id?: string;
10
10
  classes?: string[];
11
- props?: Record<string, string | number | boolean | undefined>;
11
+ /**
12
+ * Props captured from `TreeNode.props`. Primitive values (string,
13
+ * number, boolean) round-trip through inline `{key="value"}` form.
14
+ * Arrays / plain objects are preserved here too — `renderAttrs`
15
+ * skips them (inline form can't represent them) but the
16
+ * directive renderer's `shouldUseYaml` branch picks them up and
17
+ * routes the directive to YAML body form, where complex values
18
+ * survive intact.
19
+ */
20
+ props?: Record<string, unknown>;
12
21
  }
13
22
  /**
14
23
  * Render an attribute block.
15
24
  * Returns `{ #id .a .b key="value" }` or "" if no attrs.
16
25
  * Leading space included so callers can append directly to content.
26
+ *
27
+ * Inline form can only carry primitive values. Arrays / objects in
28
+ * `props` are silently skipped here — the caller is expected to have
29
+ * already routed those to YAML body form (see `shouldUseYaml` in
30
+ * directives.ts). If a non-primitive does reach this point, dropping
31
+ * it is the safest fallback (there's no inline syntax for it).
17
32
  */
18
33
  export declare function renderAttrs(attrs: RenderedAttrs): string;
19
34
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;CAC/D;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CA0BxD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC1C,WAAW,GAAE,MAAM,EAAO,GACzB,aAAa,CA8Bf"}
1
+ {"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CA6BxD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC1C,WAAW,GAAE,MAAM,EAAO,GACzB,aAAa,CAiCf"}
@@ -9,6 +9,12 @@
9
9
  * Render an attribute block.
10
10
  * Returns `{ #id .a .b key="value" }` or "" if no attrs.
11
11
  * Leading space included so callers can append directly to content.
12
+ *
13
+ * Inline form can only carry primitive values. Arrays / objects in
14
+ * `props` are silently skipped here — the caller is expected to have
15
+ * already routed those to YAML body form (see `shouldUseYaml` in
16
+ * directives.ts). If a non-primitive does reach this point, dropping
17
+ * it is the safest fallback (there's no inline syntax for it).
12
18
  */
13
19
  export function renderAttrs(attrs) {
14
20
  const parts = [];
@@ -29,6 +35,10 @@ export function renderAttrs(attrs) {
29
35
  parts.push(key);
30
36
  continue;
31
37
  }
38
+ // Skip arrays / plain objects — inline form can't represent
39
+ // them. They survive via the YAML body branch upstream.
40
+ if (typeof value === "object")
41
+ continue;
32
42
  parts.push(`${key}=${escapeAttrValue(String(value))}`);
33
43
  }
34
44
  }
@@ -71,8 +81,10 @@ export function splitProps(props, excludeKeys = []) {
71
81
  }
72
82
  if (value === null || value === undefined)
73
83
  continue;
74
- if (typeof value === "object")
75
- continue; // skip nested structures
84
+ // Pass arrays / objects through. Inline-form rendering will skip
85
+ // them (`renderAttrs`); YAML-body rendering preserves them
86
+ // (`attrsToYaml`). The `shouldUseYaml` heuristic in directives.ts
87
+ // detects their presence and routes the directive accordingly.
76
88
  cleanProps[key] = value;
77
89
  }
78
90
  if (Object.keys(cleanProps).length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"attributes.js","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"attributes.js","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAgC,MAAM,gBAAgB,CAAC;AA2HjF,eAAO,MAAM,MAAM,EAAE,YAcpB,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAgC,MAAM,gBAAgB,CAAC;AAoKjF,eAAO,MAAM,MAAM,EAAE,YAcpB,CAAC"}
package/dist/cli.js CHANGED
@@ -9,6 +9,7 @@ import { join, relative, basename } from "node:path";
9
9
  import { parseMeta } from "@dogsbay/types";
10
10
  import { dogsbayMdToTree } from "./parse.js";
11
11
  import { buildNavFromDirectory } from "./nav.js";
12
+ import { renderDiagrams } from "./renderers/diagrams.js";
12
13
  /**
13
14
  * Detect whether a directory contains a Dogsbay MD source tree.
14
15
  *
@@ -61,22 +62,51 @@ async function importDogsbayMd(source, opts) {
61
62
  const taxonomyNames = Array.isArray(opts.taxonomyNames)
62
63
  ? opts.taxonomyNames
63
64
  : undefined;
65
+ // Pre-parse pass — opt-out via `diagrams: false`. When enabled
66
+ // (default), `code` fences with `lang: mermaid` get transformed
67
+ // to `diagram` nodes with pre-rendered SVG. Fail-open: if mmdc
68
+ // (mermaid-cli) isn't installed the code block is left as-is and
69
+ // a one-line warning is printed. See plans/mermaid-dogsbay-md.md.
70
+ const diagramsOn = opts.diagrams !== false;
64
71
  for (const { filePath, slug } of files) {
65
72
  const content = readFileSync(filePath, "utf-8");
66
73
  const { tree, frontmatter } = dogsbayMdToTree(content);
74
+ if (diagramsOn) {
75
+ await renderDiagrams(tree);
76
+ }
67
77
  const title = String(frontmatter.title
68
78
  ?? prettifyName(basename(slug)));
69
- // Extract heading metadata for TOC
79
+ // Extract heading metadata for TOC AND backfill `node.props.slug`
80
+ // so format-astro's headingToAstro emits a matching `id` on the
81
+ // rendered `<h2>` / `<h3>`. Without this, the TOC's
82
+ // `<a href="#quick-start">` had nothing to scroll to — the
83
+ // heading was emitted without an id because the tree didn't
84
+ // carry the slug. Mirrors format-mkdocs/src/loader.ts:312.
85
+ //
86
+ // Duplicate slugs get `-1`, `-2` suffixes so two `## Foo`
87
+ // headings on the same page produce distinct anchors. Same
88
+ // collision-handling shape as MkDocs.
70
89
  const headings = [];
90
+ const seen = new Map();
71
91
  for (const node of tree) {
72
92
  if (node.type === "heading" && node.inline) {
73
93
  const text = node.inline
74
94
  .map((n) => (n.type === "text" ? n.text : ""))
75
95
  .join("")
76
96
  .trim();
97
+ let slug = node.props?.slug;
98
+ if (!slug) {
99
+ const baseSlug = slugify(text);
100
+ const count = seen.get(baseSlug) ?? 0;
101
+ slug = count === 0 ? baseSlug : `${baseSlug}-${count}`;
102
+ seen.set(baseSlug, count + 1);
103
+ if (!node.props)
104
+ node.props = { level: 1 };
105
+ node.props.slug = slug;
106
+ }
77
107
  headings.push({
78
108
  depth: node.props?.level ?? 1,
79
- slug: node.props?.slug ?? slugify(text),
109
+ slug,
80
110
  text,
81
111
  });
82
112
  }
@@ -95,7 +125,18 @@ async function importDogsbayMd(source, opts) {
95
125
  }
96
126
  const navFilePath = opts.nav || undefined;
97
127
  const hrefPrefix = typeof opts.hrefPrefix === "string" ? opts.hrefPrefix : undefined;
98
- const nav = buildNavFromDirectory(source, { navFilePath, hrefPrefix });
128
+ // `--strict` at the CLI layer maps to "fail" here. `loadNavFile`
129
+ // already throws on the first miss in fail mode; the build
130
+ // surfaces the throw as a fatal error and exits non-zero.
131
+ // See plans/site-build-strict.md.
132
+ const missingNavTargets = opts.missingNavTargets === "fail"
133
+ ? "fail"
134
+ : undefined;
135
+ const nav = buildNavFromDirectory(source, {
136
+ navFilePath,
137
+ hrefPrefix,
138
+ missingFile: missingNavTargets,
139
+ });
99
140
  return { pages, nav };
100
141
  }
101
142
  function prettifyName(slug) {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -38,6 +38,17 @@ export function renderBlockDirective(input, ctx) {
38
38
  }
39
39
  /**
40
40
  * Decide if a set of attributes warrants YAML body form.
41
+ *
42
+ * Forced when:
43
+ * - prop count exceeds the threshold (default 3),
44
+ * - any string value contains a newline (inline form normalises
45
+ * newlines to spaces, which loses author intent),
46
+ * - any value is a boolean (the inline shorthand `{flag}` parses
47
+ * as the empty string, not `true`, so booleans don't round-
48
+ * trip — caught during Phase 4 autodoc-directive tests), OR
49
+ * - any value is an array / object / nested structure (inline
50
+ * form has no syntax for those — without YAML they get
51
+ * dropped by `renderAttrs`).
41
52
  */
42
53
  function shouldUseYaml(attrs, ctx) {
43
54
  const propCount = (attrs.id ? 1 : 0) +
@@ -45,11 +56,22 @@ function shouldUseYaml(attrs, ctx) {
45
56
  Object.keys(attrs.props ?? {}).length;
46
57
  if (propCount > ctx.yamlThreshold)
47
58
  return true;
48
- // Multi-line or complex string values force YAML
49
59
  if (attrs.props) {
50
60
  for (const value of Object.values(attrs.props)) {
61
+ // Multi-line strings would lose their structure in inline form.
51
62
  if (typeof value === "string" && value.includes("\n"))
52
63
  return true;
64
+ // Booleans don't round-trip through the inline-attrs form —
65
+ // `{flag}` parses as "" (empty string). YAML preserves the
66
+ // type. Same logic applies to numbers in principle, but
67
+ // numbers do survive inline (parsed back as strings; consumers
68
+ // tolerate that). Booleans break consumers that check `=== true`.
69
+ if (typeof value === "boolean")
70
+ return true;
71
+ // Arrays / nested objects can't be expressed in inline form at
72
+ // all; only YAML body preserves them.
73
+ if (value !== null && typeof value === "object")
74
+ return true;
53
75
  }
54
76
  }
55
77
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"directives.js","sourceRoot":"","sources":["../src/directives.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"directives.js","sourceRoot":"","sources":["../src/directives.ts"],"names":[],"mappings":"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"}
package/dist/escape.d.ts CHANGED
@@ -4,10 +4,39 @@
4
4
  * Two rules drive everything here:
5
5
  * 1. Content must round-trip through a markdown-it parser cleanly.
6
6
  * 2. When ambiguous, prefer escaping — a reader never sees broken syntax.
7
+ *
8
+ * Dogsbay-MD is a SUPERSET of CommonMark: it includes Minja directives
9
+ * (`{{ var }}`, `{% if %}`, `{% include %}`, `{# comment #}`). Those
10
+ * directives have their own syntax and must NOT be escape-mangled —
11
+ * a path like `./_attributes/foo.md` inside `{% include "..." %}`
12
+ * has to survive as-is so the build-time preprocessor can resolve it.
13
+ * `escapePreservingMinja` is the seam: it splits text on directive
14
+ * boundaries, escapes only the prose segments, and leaves directives
15
+ * verbatim. Every text-escape entry point in this package is built
16
+ * on top of it.
17
+ */
18
+ /**
19
+ * Apply a per-segment escape function to text, treating Minja
20
+ * directives as opaque atoms that pass through verbatim.
21
+ *
22
+ * The shape:
23
+ * "Hello {{ name }} — see {% include \"path.md\" %} for details."
24
+ * ↓ split on directives
25
+ * ["Hello ", "{{ name }}", " — see ", "{% include \"path.md\" %}", " for details."]
26
+ * ↓ escape only non-directive segments
27
+ * [esc("Hello "), "{{ name }}", esc(" — see "), "{% include \"path.md\" %}", esc(" for details.")]
28
+ * ↓ join
29
+ * "Hello {{ name }} — see {% include \"path.md\" %} for details."
30
+ *
31
+ * Text with no directives short-circuits to a single escape call,
32
+ * so the fast path is unchanged for the common case.
7
33
  */
34
+ export declare function escapePreservingMinja(text: string, escape: (segment: string) => string): string;
8
35
  /**
9
36
  * Escape markdown-active characters in text content.
10
37
  * Only escapes what would change parsing; leaves everything else alone.
38
+ * Minja directives (`{{ … }}`, `{% … %}`, `{# … #}`) pass through
39
+ * verbatim — see escapePreservingMinja.
11
40
  */
12
41
  export declare function escapeText(text: string): string;
13
42
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"escape.d.ts","sourceRoot":"","sources":["../src/escape.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,aAAa,GAAE,GAAG,GAAG,GAAS,GAC7B,MAAM,CAOR;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKnE"}
1
+ {"version":3,"file":"escape.d.ts","sourceRoot":"","sources":["../src/escape.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAiBH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAClC,MAAM,CAkBR;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAQD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,aAAa,GAAE,GAAG,GAAG,GAAS,GAC7B,MAAM,CAOR;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKnE"}
package/dist/escape.js CHANGED
@@ -4,13 +4,78 @@
4
4
  * Two rules drive everything here:
5
5
  * 1. Content must round-trip through a markdown-it parser cleanly.
6
6
  * 2. When ambiguous, prefer escaping — a reader never sees broken syntax.
7
+ *
8
+ * Dogsbay-MD is a SUPERSET of CommonMark: it includes Minja directives
9
+ * (`{{ var }}`, `{% if %}`, `{% include %}`, `{# comment #}`). Those
10
+ * directives have their own syntax and must NOT be escape-mangled —
11
+ * a path like `./_attributes/foo.md` inside `{% include "..." %}`
12
+ * has to survive as-is so the build-time preprocessor can resolve it.
13
+ * `escapePreservingMinja` is the seam: it splits text on directive
14
+ * boundaries, escapes only the prose segments, and leaves directives
15
+ * verbatim. Every text-escape entry point in this package is built
16
+ * on top of it.
17
+ */
18
+ /**
19
+ * Matches a complete Minja directive:
20
+ * - `{{ … }}` variable / filter pipeline
21
+ * - `{% … %}` block (if / endif / for / set / include / raw / …)
22
+ * - `{# … #}` comment
23
+ *
24
+ * Lazy match (`*?`) terminates at the FIRST closing delimiter, which
25
+ * matches Minja's grammar — directives can't legitimately nest by
26
+ * the same delimiter. `[\s\S]` so multi-line directives are handled
27
+ * (e.g. `{% if x %}\n…\n{% endif %}` is two separate matches; the
28
+ * inner content isn't a single directive).
29
+ */
30
+ const MINJA_DIRECTIVE_RE = /\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}|\{#[\s\S]*?#\}/g;
31
+ /**
32
+ * Apply a per-segment escape function to text, treating Minja
33
+ * directives as opaque atoms that pass through verbatim.
34
+ *
35
+ * The shape:
36
+ * "Hello {{ name }} — see {% include \"path.md\" %} for details."
37
+ * ↓ split on directives
38
+ * ["Hello ", "{{ name }}", " — see ", "{% include \"path.md\" %}", " for details."]
39
+ * ↓ escape only non-directive segments
40
+ * [esc("Hello "), "{{ name }}", esc(" — see "), "{% include \"path.md\" %}", esc(" for details.")]
41
+ * ↓ join
42
+ * "Hello {{ name }} — see {% include \"path.md\" %} for details."
43
+ *
44
+ * Text with no directives short-circuits to a single escape call,
45
+ * so the fast path is unchanged for the common case.
7
46
  */
47
+ export function escapePreservingMinja(text, escape) {
48
+ // Fast path: no directive opener anywhere → straight escape.
49
+ if (!text.includes("{{") && !text.includes("{%") && !text.includes("{#")) {
50
+ return escape(text);
51
+ }
52
+ const parts = [];
53
+ let lastEnd = 0;
54
+ // matchAll iterates left-to-right with global flag; safe to reset
55
+ // via fresh exec context per call (regex is stateless when used
56
+ // this way).
57
+ for (const match of text.matchAll(MINJA_DIRECTIVE_RE)) {
58
+ const start = match.index ?? 0;
59
+ if (start > lastEnd)
60
+ parts.push(escape(text.slice(lastEnd, start)));
61
+ parts.push(match[0]);
62
+ lastEnd = start + match[0].length;
63
+ }
64
+ if (lastEnd < text.length)
65
+ parts.push(escape(text.slice(lastEnd)));
66
+ return parts.join("");
67
+ }
8
68
  /**
9
69
  * Escape markdown-active characters in text content.
10
70
  * Only escapes what would change parsing; leaves everything else alone.
71
+ * Minja directives (`{{ … }}`, `{% … %}`, `{# … #}`) pass through
72
+ * verbatim — see escapePreservingMinja.
11
73
  */
12
74
  export function escapeText(text) {
13
- return text
75
+ return escapePreservingMinja(text, escapeTextSegment);
76
+ }
77
+ function escapeTextSegment(segment) {
78
+ return segment
14
79
  .replace(/\\/g, "\\\\")
15
80
  .replace(/([*_`~[\]()<>#|{}])/g, "\\$1");
16
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"escape.js","sourceRoot":"","sources":["../src/escape.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI;SACR,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;SACtB,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,4DAA4D;IAC5D,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;IACjE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,gBAA2B,GAAG;IAE9B,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,GAAG,aAAa,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5E,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9C,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM;YAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACzD,CAAC;IACD,OAAO,aAAa,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,OAAO,GAAG,QAAQ,CAAC;IACzB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9C,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM;YAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACzD,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,OAAe,EAAE,MAAc;IACpD,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,OAAO,OAAO;SACX,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SACpD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAAe;IACzD,OAAO,OAAO;SACX,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;SAC1B,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;SACxB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"escape.js","sourceRoot":"","sources":["../src/escape.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -6,5 +6,8 @@ export type { ParseResult, ParseOptions } from "./parse.js";
6
6
  export { buildNavFromDirectory } from "./nav.js";
7
7
  export type { BuildNavOptions } from "./nav.js";
8
8
  export { loadNavFile } from "./nav-file.js";
9
- export type { NavFile, NavFileItem, LoadNavFileOptions } from "./nav-file.js";
9
+ export type { NavFile, NavFileItem, LoadNavFileOptions, MissingNavTarget, } from "./nav-file.js";
10
+ export { renderDiagrams } from "./renderers/diagrams.js";
11
+ export type { RenderDiagramsOptions } from "./renderers/diagrams.js";
12
+ export { renderMermaidSvg, setMmdcOverride, findMmdc } from "./renderers/mermaid.js";
10
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EACV,OAAO,EACP,WAAW,EACX,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,YAAY,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -7,4 +7,6 @@ export { inlineToDogsbayMd } from "./inline.js";
7
7
  export { dogsbayMdToTree, parseInline } from "./parse.js";
8
8
  export { buildNavFromDirectory } from "./nav.js";
9
9
  export { loadNavFile } from "./nav-file.js";
10
+ export { renderDiagrams } from "./renderers/diagrams.js";
11
+ export { renderMermaidSvg, setMmdcOverride, findMmdc } from "./renderers/mermaid.js";
10
12
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,kDAAkD;AAClD,mCAAmC;AAEnC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGlE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,kDAAkD;AAClD,mCAAmC;AAEnC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGlE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAQ5C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/inline.d.ts CHANGED
@@ -4,6 +4,23 @@
4
4
  import type { InlineNode } from "@dogsbay/types";
5
5
  /**
6
6
  * Serialize a flat array of inline nodes to markdown.
7
+ *
8
+ * Stack-based emit: maintains a stack of currently-open formatting
9
+ * marks and, between successive text nodes, opens/closes only the
10
+ * delta between current-stack and desired-formats. This produces:
11
+ *
12
+ * - `*foo bar*` (not `*foo** **bar*`) for sibling italic text runs,
13
+ * fixing the multi-line-emphasis case where the parser splits
14
+ * `*a\nb*` into three italic text nodes.
15
+ * - `*foo \`code\` bar*` (not `*foo*\`code\`*bar*`) for italic
16
+ * text bracketing inline code — non-text nodes don't disturb the
17
+ * open-format stack, so the wrapper stays open across them.
18
+ * - `**This is *not* news.**` (not `**This is *****not***** news.**`)
19
+ * for bold-around-italic — only italic opens/closes between the
20
+ * three text spans; the outer bold stays open the whole time.
21
+ *
22
+ * Round-trip stable on every case validated against the parser's
23
+ * output (see roundtrip.test.ts).
7
24
  */
8
25
  export declare function inlineToDogsbayMd(nodes: InlineNode[] | undefined): string;
9
26
  //# sourceMappingURL=inline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../src/inline.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,gBAAgB,CAAC;AAG3D;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,SAAS,GAAG,MAAM,CAGzE"}
1
+ {"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../src/inline.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAe,UAAU,EAAY,MAAM,gBAAgB,CAAC;AAiBxE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,SAAS,GAAG,MAAM,CA2CzE"}
package/dist/inline.js CHANGED
@@ -1,11 +1,88 @@
1
1
  import { escapeAttrValue } from "./attributes.js";
2
+ import { escapePreservingMinja } from "./escape.js";
3
+ // Canonical nesting order: outermost → innermost. Strike outer, italic
4
+ // middle, bold inner. Matches the historical renderText() ordering and
5
+ // CommonMark community convention (`***strong-em***` reads as em(strong)).
6
+ const FORMAT_ORDER = ["strikethrough", "italic", "bold"];
7
+ const FORMAT_MARK = {
8
+ strikethrough: "~~",
9
+ italic: "*",
10
+ bold: "**",
11
+ };
2
12
  /**
3
13
  * Serialize a flat array of inline nodes to markdown.
14
+ *
15
+ * Stack-based emit: maintains a stack of currently-open formatting
16
+ * marks and, between successive text nodes, opens/closes only the
17
+ * delta between current-stack and desired-formats. This produces:
18
+ *
19
+ * - `*foo bar*` (not `*foo** **bar*`) for sibling italic text runs,
20
+ * fixing the multi-line-emphasis case where the parser splits
21
+ * `*a\nb*` into three italic text nodes.
22
+ * - `*foo \`code\` bar*` (not `*foo*\`code\`*bar*`) for italic
23
+ * text bracketing inline code — non-text nodes don't disturb the
24
+ * open-format stack, so the wrapper stays open across them.
25
+ * - `**This is *not* news.**` (not `**This is *****not***** news.**`)
26
+ * for bold-around-italic — only italic opens/closes between the
27
+ * three text spans; the outer bold stays open the whole time.
28
+ *
29
+ * Round-trip stable on every case validated against the parser's
30
+ * output (see roundtrip.test.ts).
4
31
  */
5
32
  export function inlineToDogsbayMd(nodes) {
6
33
  if (!nodes || nodes.length === 0)
7
34
  return "";
8
- return nodes.map(renderInline).join("");
35
+ const out = [];
36
+ const stack = [];
37
+ for (const node of nodes) {
38
+ if (node.type === "text") {
39
+ const desired = desiredFormatSet(node);
40
+ // Keep the stack prefix while every entry is still wanted;
41
+ // pop the first unwanted format and everything above it. This
42
+ // avoids unnecessary close/reopen pairs — e.g. when we go from
43
+ // {bold} to {bold, italic}, we just open italic INSIDE the
44
+ // already-open bold rather than closing bold, opening italic,
45
+ // reopening bold (which produces the dreaded `*****`).
46
+ let keep = 0;
47
+ while (keep < stack.length && desired.has(stack[keep]))
48
+ keep++;
49
+ while (stack.length > keep) {
50
+ out.push(FORMAT_MARK[stack.pop()]);
51
+ }
52
+ // Add still-missing formats. Canonical order is used only when
53
+ // the stack is empty; otherwise additions append on top of
54
+ // whatever's already nested. Both nestings round-trip to the
55
+ // same tree.
56
+ for (const fmt of FORMAT_ORDER) {
57
+ if (desired.has(fmt) && !stack.includes(fmt)) {
58
+ out.push(FORMAT_MARK[fmt]);
59
+ stack.push(fmt);
60
+ }
61
+ }
62
+ out.push(escapeInlineText(node.text));
63
+ }
64
+ else {
65
+ // Non-text inline (code, link, image, …) doesn't carry format
66
+ // flags; leave the open-format stack alone so a wrapper that
67
+ // bridges across it (like `*foo \`code\` bar*`) survives.
68
+ out.push(renderInline(node));
69
+ }
70
+ }
71
+ // Close anything still open at the end.
72
+ while (stack.length > 0) {
73
+ out.push(FORMAT_MARK[stack.pop()]);
74
+ }
75
+ return out.join("");
76
+ }
77
+ function desiredFormatSet(node) {
78
+ const s = new Set();
79
+ if (node.strikethrough)
80
+ s.add("strikethrough");
81
+ if (node.italic)
82
+ s.add("italic");
83
+ if (node.bold)
84
+ s.add("bold");
85
+ return s;
9
86
  }
10
87
  function renderInline(node) {
11
88
  switch (node.type) {
@@ -37,9 +114,11 @@ function renderInline(node) {
37
114
  }
38
115
  }
39
116
  function renderText(node) {
117
+ // Single-node fallback for callers that bypass inlineToDogsbayMd.
118
+ // The grouped path strips format flags before emitting body content;
119
+ // this branch handles the rare standalone case (e.g. nodeToDogsbayMd
120
+ // on a lone text node).
40
121
  let text = escapeInlineText(node.text);
41
- // Apply annotations from outside in: strikethrough, italic, bold
42
- // Order produces canonical output: ~~*_**text**_*~~
43
122
  if (node.bold)
44
123
  text = `**${text}**`;
45
124
  if (node.italic)
@@ -52,13 +131,46 @@ function renderLink(node) {
52
131
  const label = inlineToDogsbayMd(node.children);
53
132
  const href = escapeLinkDest(node.href);
54
133
  const title = node.title ? ` ${escapeAttrValue(node.title)}` : "";
55
- return `[${label}](${href}${title})`;
134
+ const attrs = renderInlineAttrs(node.attrs);
135
+ return `[${label}](${href}${title})${attrs}`;
136
+ }
137
+ /**
138
+ * Render an inline attribute block (`{.class #id key="val"}`) for
139
+ * InlineLink (and, in future phases, InlineImage / InlineSpan).
140
+ *
141
+ * Mirrors the block-level `renderAttrs` ordering: id, classes, then
142
+ * remaining keys. Returns "" when no attrs are present so the caller
143
+ * can append unconditionally.
144
+ */
145
+ function renderInlineAttrs(attrs) {
146
+ if (!attrs)
147
+ return "";
148
+ const parts = [];
149
+ if (attrs.id)
150
+ parts.push(`#${attrs.id}`);
151
+ if (attrs.class) {
152
+ for (const cls of attrs.class.split(/\s+/)) {
153
+ if (cls)
154
+ parts.push(`.${cls}`);
155
+ }
156
+ }
157
+ for (const [key, value] of Object.entries(attrs)) {
158
+ if (value === undefined)
159
+ continue;
160
+ if (key === "id" || key === "class")
161
+ continue;
162
+ parts.push(`${key}=${escapeAttrValue(String(value))}`);
163
+ }
164
+ if (parts.length === 0)
165
+ return "";
166
+ return `{${parts.join(" ")}}`;
56
167
  }
57
168
  function renderImage(node) {
58
169
  const alt = node.alt ? escapeInlineText(node.alt) : "";
59
170
  const src = escapeLinkDest(node.src);
60
171
  const title = node.title ? ` ${escapeAttrValue(node.title)}` : "";
61
- return `![${alt}](${src}${title})`;
172
+ const attrs = renderInlineAttrs(node.attrs);
173
+ return `![${alt}](${src}${title})${attrs}`;
62
174
  }
63
175
  function renderInlineCode(text) {
64
176
  // Choose a backtick run that doesn't appear in the content
@@ -98,9 +210,14 @@ function renderIcon(node) {
98
210
  /**
99
211
  * Escape markdown-active characters in inline text.
100
212
  * Balance: aggressive enough to round-trip, not so aggressive that readable text
101
- * becomes a thicket of backslashes.
213
+ * becomes a thicket of backslashes. Minja directives (`{{ … }}`, `{% … %}`,
214
+ * `{# … #}`) pass through verbatim — see escapePreservingMinja in escape.ts
215
+ * for the seam.
102
216
  */
103
217
  function escapeInlineText(text) {
218
+ return escapePreservingMinja(text, escapeInlineTextSegment);
219
+ }
220
+ function escapeInlineTextSegment(text) {
104
221
  // CommonMark rule: `_` is emphasis only at word boundaries (not intraword).
105
222
  // So `snake_case` needs no escaping. Only escape `_` at word boundaries.
106
223
  return text