@dogsbay/format-asciidoc 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 +40 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +354 -0
- package/dist/cli.js.map +1 -0
- package/dist/detect.d.ts +47 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +73 -0
- package/dist/detect.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/inline-walker.d.ts +17 -0
- package/dist/inline-walker.d.ts.map +1 -0
- package/dist/inline-walker.js +167 -0
- package/dist/inline-walker.js.map +1 -0
- package/dist/loaders/antora.d.ts +3 -0
- package/dist/loaders/antora.d.ts.map +1 -0
- package/dist/loaders/antora.js +874 -0
- package/dist/loaders/antora.js.map +1 -0
- package/dist/loaders/asciibinder.d.ts +3 -0
- package/dist/loaders/asciibinder.d.ts.map +1 -0
- package/dist/loaders/asciibinder.js +229 -0
- package/dist/loaders/asciibinder.js.map +1 -0
- package/dist/loaders/dominance.d.ts +15 -0
- package/dist/loaders/dominance.d.ts.map +1 -0
- package/dist/loaders/dominance.js +86 -0
- package/dist/loaders/dominance.js.map +1 -0
- package/dist/loaders/master-adoc.d.ts +3 -0
- package/dist/loaders/master-adoc.d.ts.map +1 -0
- package/dist/loaders/master-adoc.js +178 -0
- package/dist/loaders/master-adoc.js.map +1 -0
- package/dist/loaders/plain.d.ts +3 -0
- package/dist/loaders/plain.d.ts.map +1 -0
- package/dist/loaders/plain.js +58 -0
- package/dist/loaders/plain.js.map +1 -0
- package/dist/loaders/types.d.ts +117 -0
- package/dist/loaders/types.d.ts.map +1 -0
- package/dist/loaders/types.js +2 -0
- package/dist/loaders/types.js.map +1 -0
- package/dist/loaders/util.d.ts +15 -0
- package/dist/loaders/util.d.ts.map +1 -0
- package/dist/loaders/util.js +49 -0
- package/dist/loaders/util.js.map +1 -0
- package/dist/parse.d.ts +178 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +150 -0
- package/dist/parse.js.map +1 -0
- package/dist/tree.d.ts +2 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +2 -0
- package/dist/tree.js.map +1 -0
- package/dist/walker.d.ts +8 -0
- package/dist/walker.d.ts.map +1 -0
- package/dist/walker.js +210 -0
- package/dist/walker.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plain corpus loader — walks every `.adoc` under the source dir
|
|
3
|
+
* and treats directory structure as nav. The MVP / default loader;
|
|
4
|
+
* also the fallback when no topology marker is present.
|
|
5
|
+
*
|
|
6
|
+
* Lineage: this logic used to live inline in `cli.ts` (Phase 8a).
|
|
7
|
+
* Phase 9a extracted it behind the CorpusLoader contract so other
|
|
8
|
+
* loaders (master-adoc, asciibinder, antora) can sit alongside it.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
11
|
+
import { basename, join, relative } from "node:path";
|
|
12
|
+
import { isAsciidocDominant } from "./dominance.js";
|
|
13
|
+
import { buildNavFromDirectoryMirror, prettifyName } from "./util.js";
|
|
14
|
+
function walkAdocFiles(dir, root, out = []) {
|
|
15
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
16
|
+
const full = join(dir, entry.name);
|
|
17
|
+
if (entry.isDirectory()) {
|
|
18
|
+
walkAdocFiles(full, root, out);
|
|
19
|
+
}
|
|
20
|
+
else if (entry.name.endsWith(".adoc")) {
|
|
21
|
+
const rel = relative(root, full).replace(/\\/g, "/");
|
|
22
|
+
const slug = rel.replace(/\.adoc$/, "");
|
|
23
|
+
out.push({ filePath: full, slug });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
export const plainLoader = {
|
|
29
|
+
name: "plain",
|
|
30
|
+
/**
|
|
31
|
+
* Claims a directory only when it is asciidoc-DOMINANT (more `.adoc` than
|
|
32
|
+
* `.md`, ignoring dot/dependency dirs) — not merely when some `.adoc` file
|
|
33
|
+
* exists somewhere. Mere presence meant one vendored
|
|
34
|
+
* `node_modules/**\/README.adoc` made an entire markdown corpus import as
|
|
35
|
+
* AsciiDoc, dropping every page. See ./dominance.ts.
|
|
36
|
+
*/
|
|
37
|
+
detect(sourceDir) {
|
|
38
|
+
return isAsciidocDominant(sourceDir);
|
|
39
|
+
},
|
|
40
|
+
async load(sourceDir, opts) {
|
|
41
|
+
if (!existsSync(sourceDir)) {
|
|
42
|
+
throw new Error(`Source directory not found: ${sourceDir}`);
|
|
43
|
+
}
|
|
44
|
+
const st = statSync(sourceDir);
|
|
45
|
+
if (!st.isDirectory()) {
|
|
46
|
+
throw new Error(`Source must be a directory: ${sourceDir}`);
|
|
47
|
+
}
|
|
48
|
+
const hrefPrefix = opts.hrefPrefix ?? "";
|
|
49
|
+
const files = walkAdocFiles(sourceDir, sourceDir);
|
|
50
|
+
const pages = files.map((f) => ({
|
|
51
|
+
filePath: f.filePath,
|
|
52
|
+
slug: f.slug,
|
|
53
|
+
}));
|
|
54
|
+
const nav = buildNavFromDirectoryMirror(pages.map((p) => ({ slug: p.slug, title: prettifyName(basename(p.slug)) })), hrefPrefix);
|
|
55
|
+
return { pages, nav };
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=plain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plain.js","sourceRoot":"","sources":["../../src/loaders/plain.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,2BAA2B,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEtE,SAAS,aAAa,CACpB,GAAW,EACX,IAAY,EACZ,MAA4C,EAAE;IAE9C,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACrD,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YACxC,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAiB;IACvC,IAAI,EAAE,OAAO;IAEb;;;;;;OAMG;IACH,MAAM,CAAC,SAAiB;QACtB,OAAO,kBAAkB,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,SAAiB,EAAE,IAAgB;QAC5C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,+BAA+B,SAAS,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC/B,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,+BAA+B,SAAS,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,aAAa,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAClD,MAAM,KAAK,GAAiB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC5C,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,IAAI,EAAE,CAAC,CAAC,IAAI;SACb,CAAC,CAAC,CAAC;QACJ,MAAM,GAAG,GAAG,2BAA2B,CACrC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAC3E,UAAU,CACX,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACxB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CorpusLoader contract — Phase 9a.
|
|
3
|
+
*
|
|
4
|
+
* AsciiDoc corpora come in distinct topology shapes:
|
|
5
|
+
*
|
|
6
|
+
* - **plain** (Phase 9a) — flat .adoc walk; directory mirrors nav.
|
|
7
|
+
* - **master-adoc** (Phase 9a) — AAP convention: each `master.adoc`
|
|
8
|
+
* is a title; its include:: chain
|
|
9
|
+
* defines the module ordering.
|
|
10
|
+
* - **asciibinder** (Phase 9b) — `_topic_maps/_topic_map.yml` +
|
|
11
|
+
* distros (OpenShift).
|
|
12
|
+
* - **antora** (Phase 9c) — `antora-playbook.yml` + per-component
|
|
13
|
+
* `antora.yml` (version axis maps to
|
|
14
|
+
* Dogsbay's version axis).
|
|
15
|
+
*
|
|
16
|
+
* Each loader is a thin enumerator: discover the corpus, decide which
|
|
17
|
+
* .adoc files become pages, propose a nav. Loaders do NOT parse —
|
|
18
|
+
* `cli.ts` runs `parseAsciidocToTree` on each `PageSource.filePath`.
|
|
19
|
+
* Keeping the split clean means loaders can be tested in isolation
|
|
20
|
+
* against their topology fixtures without depending on the full
|
|
21
|
+
* markdown-it pipeline.
|
|
22
|
+
*
|
|
23
|
+
* See plans/asciidoc-corpus-loaders.md for the four-loader rollout
|
|
24
|
+
* + axis-translation bridge spec.
|
|
25
|
+
*/
|
|
26
|
+
import type { NavItem } from "@dogsbay/types";
|
|
27
|
+
export interface PageSource {
|
|
28
|
+
/** Absolute filesystem path to the .adoc file. */
|
|
29
|
+
filePath: string;
|
|
30
|
+
/**
|
|
31
|
+
* URL slug for this page (e.g. `"guides/install"`). The cli's
|
|
32
|
+
* caller is free to prepend its own hrefPrefix when emitting.
|
|
33
|
+
*/
|
|
34
|
+
slug: string;
|
|
35
|
+
/**
|
|
36
|
+
* AsciiDoc `:leveloffset:` adjustment if the loader's topology
|
|
37
|
+
* implies one (master.adoc includes carry `leveloffset=+1`, etc.).
|
|
38
|
+
* Engine handles the actual offset; loader just declares it.
|
|
39
|
+
*/
|
|
40
|
+
leveloffset?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Per-page attribute context contributed by the loader's topology
|
|
43
|
+
* (AAP `_attributes/attributes.adoc`, Antora component attributes,
|
|
44
|
+
* AsciiBinder distro filters). Merged onto the global attributes
|
|
45
|
+
* passed to the engine + Minja.
|
|
46
|
+
*/
|
|
47
|
+
attributes?: Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
export interface LoaderOpts {
|
|
50
|
+
/**
|
|
51
|
+
* URL prefix to apply when building nav hrefs. The CLI fills this
|
|
52
|
+
* in from the consumer site's section mount; loaders just append
|
|
53
|
+
* `/<slug>` after.
|
|
54
|
+
*/
|
|
55
|
+
hrefPrefix?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Target distro for AsciiBinder corpora. When set, topic-map
|
|
58
|
+
* entries whose `Distros:` list doesn't include this distro are
|
|
59
|
+
* skipped (both from the page list and the nav). Entries with no
|
|
60
|
+
* `Distros:` field are treated as universal and always kept —
|
|
61
|
+
* matching AsciiBinder's own build-time filter.
|
|
62
|
+
*
|
|
63
|
+
* Without this option, every entry flows through and pages with
|
|
64
|
+
* the same `File:` but different `Distros:` collide in the nav
|
|
65
|
+
* (`Fedora CoreOS` and `Red Hat Enterprise Linux CoreOS` both
|
|
66
|
+
* pointing at `architecture-rhcos.md`). Other loaders ignore this
|
|
67
|
+
* option — they don't have a distro concept.
|
|
68
|
+
*/
|
|
69
|
+
distro?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Topic-map path for the AsciiBinder loader, relative to the source
|
|
72
|
+
* root. Defaults to the AsciiBinder convention
|
|
73
|
+
* `_topic_maps/_topic_map.yml`. Override for corpora that name their
|
|
74
|
+
* topic map differently (e.g. a distro-specific `_topic_map_ms.yml`),
|
|
75
|
+
* used by both `detect()` and `load()` so a custom-named corpus can
|
|
76
|
+
* be auto-detected and loaded without editing the source. Other
|
|
77
|
+
* loaders ignore this option.
|
|
78
|
+
*/
|
|
79
|
+
topicMap?: string;
|
|
80
|
+
}
|
|
81
|
+
export interface LoaderResult {
|
|
82
|
+
pages: PageSource[];
|
|
83
|
+
nav: NavItem[];
|
|
84
|
+
/**
|
|
85
|
+
* Optional list of distro names declared by the corpus (AsciiBinder
|
|
86
|
+
* `_distro_map.yml` or topic-level `Distros:` aggregation). Surfaced
|
|
87
|
+
* for forward-compatibility with distro-axis emission per the
|
|
88
|
+
* "axis translation" bridge spec in plans/asciidoc-corpus-loaders.md.
|
|
89
|
+
* Today's callers don't consume it; the data is informational only.
|
|
90
|
+
*/
|
|
91
|
+
distros?: string[];
|
|
92
|
+
}
|
|
93
|
+
export interface CorpusLoader {
|
|
94
|
+
/** Identifier surfaced via the CLI's `--loader <name>` override. */
|
|
95
|
+
name: "plain" | "asciibinder" | "master-adoc" | "antora";
|
|
96
|
+
/**
|
|
97
|
+
* Heuristic detection: does this directory look like this corpus
|
|
98
|
+
* shape? Detection is best-effort; the CLI's `--loader` override
|
|
99
|
+
* always wins. detect() must NOT throw — return false on any
|
|
100
|
+
* unexpected state.
|
|
101
|
+
*
|
|
102
|
+
* `opts` carries the same loader options passed to `load()` so
|
|
103
|
+
* detection can honour overrides (e.g. a non-default `topicMap`
|
|
104
|
+
* name for AsciiBinder). Loaders that don't need options may accept
|
|
105
|
+
* just `sourceDir`.
|
|
106
|
+
*/
|
|
107
|
+
detect(sourceDir: string, opts?: LoaderOpts): boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Enumerate pages + build nav. Loaders may walk the filesystem,
|
|
110
|
+
* read topology files (`master.adoc`, `_topic_map.yml`,
|
|
111
|
+
* `antora.yml`), and resolve includes. They MUST NOT parse the
|
|
112
|
+
* `.adoc` body — that's `cli.ts`'s job, per the separation in
|
|
113
|
+
* the plan.
|
|
114
|
+
*/
|
|
115
|
+
load(sourceDir: string, opts: LoaderOpts): Promise<LoaderResult>;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/loaders/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,GAAG,EAAE,OAAO,EAAE,CAAC;IACf;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,IAAI,EAAE,OAAO,GAAG,aAAa,GAAG,aAAa,GAAG,QAAQ,CAAC;IACzD;;;;;;;;;;OAUG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IACtD;;;;;;OAMG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAClE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/loaders/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { NavItem } from "@dogsbay/types";
|
|
2
|
+
export declare function prettifyName(slug: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Compose a nav tree that mirrors an on-disk directory layout from
|
|
5
|
+
* a flat list of `{ slug, title }` pages. Subdirectories become
|
|
6
|
+
* NavItem groups; leaves are `{ label, href: <hrefPrefix>/<slug> }`.
|
|
7
|
+
*
|
|
8
|
+
* Shared between the plain loader and (with topology overlay) the
|
|
9
|
+
* master-adoc loader's per-title grouping.
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildNavFromDirectoryMirror(pages: {
|
|
12
|
+
slug: string;
|
|
13
|
+
title: string;
|
|
14
|
+
}[], hrefPrefix: string): NavItem[];
|
|
15
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/loaders/util.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE9C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,EACxC,UAAU,EAAE,MAAM,GACjB,OAAO,EAAE,CA6BX"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for the corpus loaders.
|
|
3
|
+
*/
|
|
4
|
+
import { basename, dirname } from "node:path";
|
|
5
|
+
export function prettifyName(slug) {
|
|
6
|
+
return slug
|
|
7
|
+
.split(/[-_]/)
|
|
8
|
+
.filter(Boolean)
|
|
9
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
10
|
+
.join(" ");
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Compose a nav tree that mirrors an on-disk directory layout from
|
|
14
|
+
* a flat list of `{ slug, title }` pages. Subdirectories become
|
|
15
|
+
* NavItem groups; leaves are `{ label, href: <hrefPrefix>/<slug> }`.
|
|
16
|
+
*
|
|
17
|
+
* Shared between the plain loader and (with topology overlay) the
|
|
18
|
+
* master-adoc loader's per-title grouping.
|
|
19
|
+
*/
|
|
20
|
+
export function buildNavFromDirectoryMirror(pages, hrefPrefix) {
|
|
21
|
+
const groups = new Map();
|
|
22
|
+
groups.set("", []);
|
|
23
|
+
for (const page of pages) {
|
|
24
|
+
const dir = dirname(page.slug);
|
|
25
|
+
const key = dir === "." ? "" : dir;
|
|
26
|
+
if (!groups.has(key))
|
|
27
|
+
groups.set(key, []);
|
|
28
|
+
groups.get(key).push({
|
|
29
|
+
label: page.title,
|
|
30
|
+
href: `${hrefPrefix}/${page.slug}`,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
// Wrap each non-root directory as a group under its parent —
|
|
34
|
+
// deepest-first so child groups exist when parents wrap them.
|
|
35
|
+
const sortedKeys = [...groups.keys()].sort((a, b) => b.split("/").length - a.split("/").length);
|
|
36
|
+
for (const key of sortedKeys) {
|
|
37
|
+
if (key === "")
|
|
38
|
+
continue;
|
|
39
|
+
const parent = dirname(key) === "." ? "" : dirname(key);
|
|
40
|
+
if (!groups.has(parent))
|
|
41
|
+
groups.set(parent, []);
|
|
42
|
+
groups.get(parent).push({
|
|
43
|
+
label: prettifyName(basename(key)),
|
|
44
|
+
children: groups.get(key),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return groups.get("");
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/loaders/util.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAG9C,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI;SACR,KAAK,CAAC,MAAM,CAAC;SACb,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAClD,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CACzC,KAAwC,EACxC,UAAkB;IAElB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC5C,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAEnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,GAAG,GAAG,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,IAAI,CAAC;YACpB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,GAAG,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE;SACnC,CAAC,CAAC;IACL,CAAC;IAED,6DAA6D;IAC7D,8DAA8D;IAC9D,MAAM,UAAU,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CACxC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CACpD,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,GAAG,KAAK,EAAE;YAAE,SAAS;QACzB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACxD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,IAAI,CAAC;YACvB,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAClC,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAE;SAC3B,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;AACzB,CAAC"}
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AsciiDoc → TreeNode pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Three composable stages, each independently testable:
|
|
5
|
+
*
|
|
6
|
+
* 1. @dogsbay/adoc2md-modular — AsciiDoc → Markdown-with-Minja-directives.
|
|
7
|
+
* Pure syntactic translation. The engine emits `{{ name }}` for
|
|
8
|
+
* attribute refs, `{% if name %}` for conditionals, `{% include %}`
|
|
9
|
+
* for include::, `{% set name = "value" %}` for in-doc :name: entries.
|
|
10
|
+
* 2. @dogsbay/minja — resolve directives against the
|
|
11
|
+
* attribute context. undefinedBehavior: "preserve" lets unresolved
|
|
12
|
+
* attrs / conditionals survive into the markdown so a downstream
|
|
13
|
+
* pass can finish the job.
|
|
14
|
+
* 3. markdown-it + walker — Markdown → Token[] → TreeNode[].
|
|
15
|
+
* Each format-X package owns its own walker per the convention
|
|
16
|
+
* (see plans/format-asciidoc-import.md Phase 6).
|
|
17
|
+
*
|
|
18
|
+
* Notably we do NOT register markdown-it-attrs here. The engine emits
|
|
19
|
+
* `{id="…"}` after headings (from AsciiDoc `[id="…"]` block anchors)
|
|
20
|
+
* and md-attrs would consume those — but it would also consume any
|
|
21
|
+
* trailing `{% endif %}` / `{{ var }}` at the end of a paragraph as a
|
|
22
|
+
* malformed attribute block, dropping the directive and breaking the
|
|
23
|
+
* build-time preprocessor pass. md2md sidestepped this by fully
|
|
24
|
+
* resolving Nunjucks at convert time (single-pass), so no directives
|
|
25
|
+
* survived to collide. We support a two-pass model (migrate-asciidoc
|
|
26
|
+
* preserves directives so the build-time preprocessor can substitute
|
|
27
|
+
* later from config), which means the directives ARE present when
|
|
28
|
+
* markdown-it tokenises. So we leave md-attrs out of this stage and
|
|
29
|
+
* let `extractHeadings` (cli.ts) parse `{id="…"}` / `{#anchor}`
|
|
30
|
+
* trailers out of heading text manually — a localised concern that
|
|
31
|
+
* doesn't risk eating directives in paragraph content. md-attrs runs
|
|
32
|
+
* at Astro render time, after the preprocessor has resolved
|
|
33
|
+
* directives, where the collision can't happen.
|
|
34
|
+
*
|
|
35
|
+
* See plans/format-asciidoc-import.md for the full architecture rationale.
|
|
36
|
+
*/
|
|
37
|
+
import type MarkdownIt from "markdown-it";
|
|
38
|
+
import type { TreeNode } from "@dogsbay/types";
|
|
39
|
+
export interface ParseAsciidocOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Filesystem path of the source `.adoc` file. Used as the base for
|
|
42
|
+
* `include::` directive resolution (both at AsciiDoc convert time
|
|
43
|
+
* via adoc2md-modular's `basePath` AND at Minja resolution time
|
|
44
|
+
* for the same directive after conversion). Optional; without it
|
|
45
|
+
* includes won't resolve, but unresolved `{% include %}` directives
|
|
46
|
+
* are preserved as text per Minja's `undefinedBehavior: "preserve"`.
|
|
47
|
+
*/
|
|
48
|
+
filePath?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Containment root for `{% include %}` resolution at the Minja stage
|
|
51
|
+
* (issue #027). When set, an include target that resolves (after
|
|
52
|
+
* symlinks) OUTSIDE this directory is refused and the parse fails —
|
|
53
|
+
* without it, a crafted include in an untrusted corpus splices any
|
|
54
|
+
* file the process can read into the page. Callers that walk a corpus
|
|
55
|
+
* pass the corpus root; unset = uncontained (backward compatible for
|
|
56
|
+
* direct single-file API use).
|
|
57
|
+
*/
|
|
58
|
+
includeRoot?: string;
|
|
59
|
+
/**
|
|
60
|
+
* AsciiDoc attribute values. Surfaces in two places:
|
|
61
|
+
* - `adoc2md-modular`'s `attributes` option (mostly a no-op today —
|
|
62
|
+
* the engine emits `{{ name }}` for everything anyway).
|
|
63
|
+
* - Minja's render context — this is where the actual substitution
|
|
64
|
+
* happens. Any `{{ name }}` whose `name` is in this map gets
|
|
65
|
+
* resolved; the rest are preserved.
|
|
66
|
+
*/
|
|
67
|
+
attributes?: Record<string, unknown>;
|
|
68
|
+
/**
|
|
69
|
+
* Caller-supplied env values merged into the markdown-it env object.
|
|
70
|
+
* Available to plugins; format-asciidoc itself doesn't read from env.
|
|
71
|
+
*/
|
|
72
|
+
envOverrides?: Record<string, unknown>;
|
|
73
|
+
/**
|
|
74
|
+
* Definition-list output format passed to the engine. Dogsbay defaults
|
|
75
|
+
* to `'pandoc'` (a real `term` / `: desc` list that markdown-it-deflist
|
|
76
|
+
* renders as `<dl>`) rather than the engine's generic `'markdown'`
|
|
77
|
+
* default (a lossy bulleted-bold-term hack that can't nest). `<dl>` is
|
|
78
|
+
* what Dogsbay's renderer natively understands (deflist → `deflist`
|
|
79
|
+
* TreeNode → `<dl>`). See plans/dlist-markdown-indentation.md and
|
|
80
|
+
* adoc2md-modular DD-009.
|
|
81
|
+
*/
|
|
82
|
+
dlistFormat?: "markdown" | "html" | "pandoc";
|
|
83
|
+
/**
|
|
84
|
+
* Admonition output format passed to the engine. Dogsbay defaults to
|
|
85
|
+
* `'docusaurus'` (`:::note`) — its native callout directive, which
|
|
86
|
+
* renders as an Alert component — rather than the engine's generic
|
|
87
|
+
* `'html'` default (`<dl><dt>📌 NOTE</dt>…`). adoc2md-modular DD-010.
|
|
88
|
+
* All three admonition shapes respect this option — block-form
|
|
89
|
+
* `[NOTE]\n====`, bare `[NOTE]` + paragraph, and line-form
|
|
90
|
+
* `NOTE: …` (which the engine expands to block form internally).
|
|
91
|
+
*/
|
|
92
|
+
admonitionFormat?: "html" | "mkdocs" | "docusaurus" | "github";
|
|
93
|
+
/**
|
|
94
|
+
* Attribute names the caller KNOWS are false — the corpus's other distro
|
|
95
|
+
* flags in a single-distro migrate (AsciiBinder loaders surface the full
|
|
96
|
+
* set on LoaderResult.distros). Drives the engine's conditional STATE
|
|
97
|
+
* tracking only; never drops output text.
|
|
98
|
+
*/
|
|
99
|
+
falseAttributes?: string[];
|
|
100
|
+
/** Clamp over-declared rowspans to fitting rows (issue #031). Opt-in. */
|
|
101
|
+
clampRowspans?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Docroot-relative slug of the source page (e.g. `"architecture/admission-plug-ins"`).
|
|
104
|
+
* Threaded into adoc2md-modular so cross-doc xref hrefs resolve to
|
|
105
|
+
* root-relative paths instead of file-relative `../…` (which is off by one
|
|
106
|
+
* under Astro's default directory-style URLs). See
|
|
107
|
+
* plans/xref-absolute-hrefs.md.
|
|
108
|
+
*/
|
|
109
|
+
sourcePath?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Antora corpus mode — passed through to the engine. Enables
|
|
112
|
+
* module-coordinate xref translation (`xref:module:page[]`),
|
|
113
|
+
* resource-ID include resolution (`include::partial$…[]`), and
|
|
114
|
+
* output-relative `{% include %}` paths. Set by cli.ts when the
|
|
115
|
+
* antora corpus loader was picked. See plans/antora-support-gaps.md.
|
|
116
|
+
*/
|
|
117
|
+
antora?: boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Emit `[role]`/`[.role]` as markdown-it-attrs classes and keep
|
|
120
|
+
* role-styled inline marks as `<span class>` — only safe when the
|
|
121
|
+
* downstream parser runs markdown-it-attrs (the migrate → dogsbay-md
|
|
122
|
+
* flow). Fragments always had this on; pages did not, so a page and
|
|
123
|
+
* its own fragment copy disagreed on every role (#076 follow-up).
|
|
124
|
+
*/
|
|
125
|
+
blockRoles?: boolean;
|
|
126
|
+
/** Antora playbook mode (#067): loaded components by name → {dir, prefix}. */
|
|
127
|
+
antoraComponents?: Record<string, {
|
|
128
|
+
dir: string;
|
|
129
|
+
prefix: string;
|
|
130
|
+
}>;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Parse an AsciiDoc source string into TreeNode[].
|
|
134
|
+
*
|
|
135
|
+
* Async because Minja's renderer is async (handles I/O for includes
|
|
136
|
+
* and supports timeout enforcement).
|
|
137
|
+
*
|
|
138
|
+
* Mirrors `parseToTree` from `format-mkdocs` in shape: takes a
|
|
139
|
+
* markdown-it instance + source, returns `{ tree, env }`.
|
|
140
|
+
*/
|
|
141
|
+
export declare function parseAsciidocToTree(md: MarkdownIt, src: string, opts?: ParseAsciidocOptions): Promise<{
|
|
142
|
+
tree: TreeNode[];
|
|
143
|
+
env: Record<string, unknown>;
|
|
144
|
+
/**
|
|
145
|
+
* Raw engine output — `asciidocToMarkdown(src)` — before any
|
|
146
|
+
* Minja evaluation, before markdown-it tokenisation. The most
|
|
147
|
+
* faithful possible markdown rendition of the AsciiDoc source:
|
|
148
|
+
*
|
|
149
|
+
* - `{% set %}` directives intact (build-time preprocessor
|
|
150
|
+
* evaluates them when it has the attribute context).
|
|
151
|
+
* - `{% include %}` directives intact (not inlined here —
|
|
152
|
+
* build-time preprocessor handles inclusion against the
|
|
153
|
+
* resolved attribute context).
|
|
154
|
+
* - `{%- if %}` directives with whitespace-control intact
|
|
155
|
+
* (`-` stripping fires at *resolution* time, not parse
|
|
156
|
+
* time; preserving it keeps the migrated file rendering
|
|
157
|
+
* identically to the original `.adoc` once a real build
|
|
158
|
+
* resolves the conditionals).
|
|
159
|
+
* - `{{ var }}` references intact, regardless of whether
|
|
160
|
+
* `opts.attributes` supplied a value.
|
|
161
|
+
*
|
|
162
|
+
* Surfaced for `migrate-asciidoc`'s benefit: writing this to disk
|
|
163
|
+
* preserves the line structure of the original `.adoc` (each
|
|
164
|
+
* `ifdef`/`endif` block on its own line, blank lines between
|
|
165
|
+
* major blocks). Running Minja at migrate time would collapse
|
|
166
|
+
* lines (`-` trim fuses adjacent lines), consume `{% set %}`
|
|
167
|
+
* metadata, and inline `{% include %}` content — all undesirable
|
|
168
|
+
* for editable source.
|
|
169
|
+
*
|
|
170
|
+
* The `tree` field is the post-Minja-preserve, fully-parsed
|
|
171
|
+
* TreeNode shape — that's what the runtime path (format-astro
|
|
172
|
+
* emit, direct `from: asciidoc` builds) consumes. The two
|
|
173
|
+
* fields exist for two different downstream consumers; they're
|
|
174
|
+
* NOT derived from each other.
|
|
175
|
+
*/
|
|
176
|
+
intermediateMd: string;
|
|
177
|
+
}>;
|
|
178
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,KAAK,UAAU,MAAM,aAAa,CAAC;AAK1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/C,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAErC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEvC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;IAE7C;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ,CAAC;IAE/D;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,yEAAyE;IACzE,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,UAAU,EACd,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,oBAAyB,GAC9B,OAAO,CAAC;IACT,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC,CAiGD"}
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { dirname } from "node:path";
|
|
2
|
+
import { asciidocToMarkdown } from "@dogsbay/adoc2md-modular";
|
|
3
|
+
import { render as minjaRender, FileSystemLoader } from "@dogsbay/minja";
|
|
4
|
+
import { maskMinjaInCode, unmaskMinjaInCode, stripInlineMinjaMarkers } from "@dogsbay/format-dogsbay-md";
|
|
5
|
+
import { tokensToTree } from "./walker.js";
|
|
6
|
+
/**
|
|
7
|
+
* Parse an AsciiDoc source string into TreeNode[].
|
|
8
|
+
*
|
|
9
|
+
* Async because Minja's renderer is async (handles I/O for includes
|
|
10
|
+
* and supports timeout enforcement).
|
|
11
|
+
*
|
|
12
|
+
* Mirrors `parseToTree` from `format-mkdocs` in shape: takes a
|
|
13
|
+
* markdown-it instance + source, returns `{ tree, env }`.
|
|
14
|
+
*/
|
|
15
|
+
export async function parseAsciidocToTree(md, src, opts = {}) {
|
|
16
|
+
// Stage 1 — AsciiDoc → Markdown-with-Minja-directives.
|
|
17
|
+
// Dogsbay house defaults: 'pandoc' dlists + 'docusaurus' admonitions —
|
|
18
|
+
// the shapes Dogsbay's renderer natively understands (<dl> via
|
|
19
|
+
// markdown-it-deflist; :::note → Alert). The engine keeps its generic
|
|
20
|
+
// 'markdown'/'html' defaults; the consumer selects. See DD-009/DD-010.
|
|
21
|
+
const intermediateMd = asciidocToMarkdown(src, {
|
|
22
|
+
attributes: opts.attributes,
|
|
23
|
+
basePath: opts.filePath,
|
|
24
|
+
dlistFormat: opts.dlistFormat ?? "pandoc",
|
|
25
|
+
admonitionFormat: opts.admonitionFormat ?? "docusaurus",
|
|
26
|
+
sourcePath: opts.sourcePath,
|
|
27
|
+
antora: opts.antora ?? false,
|
|
28
|
+
...(opts.antoraComponents ? { antoraComponents: opts.antoraComponents } : {}),
|
|
29
|
+
blockRoles: opts.blockRoles ?? false,
|
|
30
|
+
falseAttributes: opts.falseAttributes ?? [],
|
|
31
|
+
clampRowspans: opts.clampRowspans ?? false,
|
|
32
|
+
// Tag-filtered includes splice file content at CONVERT time, below
|
|
33
|
+
// the Minja layer — the engine enforces the same containment there
|
|
34
|
+
// (#027 review finding F1).
|
|
35
|
+
includeRoot: opts.includeRoot,
|
|
36
|
+
});
|
|
37
|
+
// Stage 2 — resolve Minja directives. Preserve mode means unresolved
|
|
38
|
+
// refs survive as literal `{{ name }}` / `{% if … %}` text in the
|
|
39
|
+
// output. That text passes through markdown-it as part of the
|
|
40
|
+
// surrounding paragraph; the consumer can re-render with a richer
|
|
41
|
+
// context later if needed.
|
|
42
|
+
//
|
|
43
|
+
// basePath is the file's DIRECTORY (not the file itself) so
|
|
44
|
+
// Minja's FileSystemLoader can join relative `{% include %}`
|
|
45
|
+
// targets correctly. Earlier passes used `opts.filePath` directly,
|
|
46
|
+
// which produced ENOTDIR errors trying to treat the .adoc file as
|
|
47
|
+
// a directory.
|
|
48
|
+
//
|
|
49
|
+
// We wrap the render call in try/catch so that a Minja parse
|
|
50
|
+
// error (e.g. hyphenated identifiers in `{% if product-version %}`,
|
|
51
|
+
// which Minja's expression grammar doesn't accept) doesn't abort
|
|
52
|
+
// the entire import. Fall back to the engine output unchanged —
|
|
53
|
+
// every surviving directive lives on as literal text in the
|
|
54
|
+
// markdown, matching `preserve` mode's intent for whole-block
|
|
55
|
+
// failures the same way it handles single-variable failures. We
|
|
56
|
+
// log a warning so the user knows why some directives didn't
|
|
57
|
+
// resolve.
|
|
58
|
+
const basePath = opts.filePath ? dirname(opts.filePath) : "";
|
|
59
|
+
let resolvedMd;
|
|
60
|
+
try {
|
|
61
|
+
// Code regions are content, not directives: mask `{{`/`{%` openers
|
|
62
|
+
// inside fences and inline code before the string evaluator runs
|
|
63
|
+
// (the same shared guard site-build uses), restore verbatim after.
|
|
64
|
+
// Without this, a code example like Helm's `{{ .Values.name }}`
|
|
65
|
+
// whose name collides with a defined doc attribute was silently
|
|
66
|
+
// substituted at import.
|
|
67
|
+
const rendered = await minjaRender(maskMinjaInCode(intermediateMd), {
|
|
68
|
+
context: opts.attributes ?? {},
|
|
69
|
+
undefinedBehavior: "preserve",
|
|
70
|
+
hyphenToUnderscore: true,
|
|
71
|
+
basePath,
|
|
72
|
+
loader: new FileSystemLoader(process.cwd(), { root: opts.includeRoot }),
|
|
73
|
+
});
|
|
74
|
+
// The inline `{minja}` markers (engine-planted attr refs, #030) have
|
|
75
|
+
// done their job — strip them, or this parser (which deliberately
|
|
76
|
+
// excludes markdown-it-attrs) leaks them as literal text nodes.
|
|
77
|
+
resolvedMd = stripInlineMinjaMarkers(unmaskMinjaInCode(rendered));
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
// A containment refusal (#027) is a security event, not a parse
|
|
81
|
+
// hiccup — rethrow so the caller's per-page handling surfaces it
|
|
82
|
+
// (cli.ts logs the page and counts the failure) instead of quietly
|
|
83
|
+
// preserving directives.
|
|
84
|
+
if (err instanceof Error && err.name === "IncludeContainmentError") {
|
|
85
|
+
throw err;
|
|
86
|
+
}
|
|
87
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
88
|
+
const where = opts.filePath ? ` in ${opts.filePath}` : "";
|
|
89
|
+
console.warn(`asciidoc parse: Minja render failed${where}, preserving raw directives (${msg})`);
|
|
90
|
+
resolvedMd = stripInlineMinjaMarkers(intermediateMd);
|
|
91
|
+
}
|
|
92
|
+
// Stage 3 — markdown-it parse + walker.
|
|
93
|
+
const env = { ...(opts.envOverrides ?? {}) };
|
|
94
|
+
const tokens = md.parse(resolvedMd, env);
|
|
95
|
+
const tree = flattenProseWrappers(tokensToTree(tokens));
|
|
96
|
+
// `intermediateMd` is the RAW engine output — pre-Minja,
|
|
97
|
+
// pre-markdown-it. The faithful AsciiDoc → markdown
|
|
98
|
+
// translation. migrate-asciidoc writes this to disk so all
|
|
99
|
+
// `{% set %}` / `{% include %}` / `{%- if %}` directives
|
|
100
|
+
// survive verbatim for the build-time preprocessor to handle.
|
|
101
|
+
// (Returning `resolvedMd` here would consume `{% set %}` lines,
|
|
102
|
+
// inline `{% include %}` content, and fuse lines via `{%-`
|
|
103
|
+
// whitespace control — all wrong for editable migrated source.)
|
|
104
|
+
// The `tree` is parsed from the Minja-resolved form (`resolvedMd`)
|
|
105
|
+
// for accurate runtime rendering when used directly via
|
|
106
|
+
// `from: asciidoc` — a separate consumer with separate needs.
|
|
107
|
+
return { tree, env, intermediateMd };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Normalise the walker's "wrapped" shape into the "flat" shape that
|
|
111
|
+
* every other TreeNode consumer expects.
|
|
112
|
+
*
|
|
113
|
+
* The format-mkdocs walker (which we inherit) wraps inline content
|
|
114
|
+
* of heading / paragraph / list-item / dt / dd nodes in a single
|
|
115
|
+
* `{type:"prose", inline: [...]}` child instead of attaching
|
|
116
|
+
* `inline` directly to the parent. format-dogsbay-md's serializer
|
|
117
|
+
* and most downstream consumers read `node.inline`; lifting the
|
|
118
|
+
* inline up here means every consumer sees a single canonical shape
|
|
119
|
+
* and we don't have to thread cross-shape tolerance through every
|
|
120
|
+
* call site.
|
|
121
|
+
*
|
|
122
|
+
* Recursive — handles nested blocks (e.g. list_item containing a
|
|
123
|
+
* paragraph).
|
|
124
|
+
*/
|
|
125
|
+
function flattenProseWrappers(nodes) {
|
|
126
|
+
const FLATTENABLE = new Set([
|
|
127
|
+
"heading",
|
|
128
|
+
"paragraph",
|
|
129
|
+
"list_item",
|
|
130
|
+
"dt",
|
|
131
|
+
"dd",
|
|
132
|
+
]);
|
|
133
|
+
return nodes.map((node) => {
|
|
134
|
+
let out = node;
|
|
135
|
+
if (FLATTENABLE.has(node.type) &&
|
|
136
|
+
Array.isArray(node.children) &&
|
|
137
|
+
node.children.length === 1 &&
|
|
138
|
+
node.children[0].type === "prose" &&
|
|
139
|
+
Array.isArray(node.children[0].inline)) {
|
|
140
|
+
const prose = node.children[0];
|
|
141
|
+
out = { ...node, inline: prose.inline };
|
|
142
|
+
delete out.children;
|
|
143
|
+
}
|
|
144
|
+
else if (Array.isArray(node.children)) {
|
|
145
|
+
out = { ...node, children: flattenProseWrappers(node.children) };
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAqCA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,MAAM,IAAI,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAEzG,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAqG3C;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAc,EACd,GAAW,EACX,OAA6B,EAAE;IAsC/B,uDAAuD;IACvD,uEAAuE;IACvE,+DAA+D;IAC/D,sEAAsE;IACtE,uEAAuE;IACvE,MAAM,cAAc,GAAG,kBAAkB,CAAC,GAAG,EAAE;QAC7C,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,QAAQ;QACzC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,IAAI,YAAY;QACvD,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK;QAC5B,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,KAAK;QACpC,eAAe,EAAE,IAAI,CAAC,eAAe,IAAI,EAAE;QAC3C,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,KAAK;QAC1C,mEAAmE;QACnE,mEAAmE;QACnE,4BAA4B;QAC5B,WAAW,EAAE,IAAI,CAAC,WAAW;KAC9B,CAAC,CAAC;IAEH,qEAAqE;IACrE,kEAAkE;IAClE,8DAA8D;IAC9D,kEAAkE;IAClE,2BAA2B;IAC3B,EAAE;IACF,4DAA4D;IAC5D,6DAA6D;IAC7D,mEAAmE;IACnE,kEAAkE;IAClE,eAAe;IACf,EAAE;IACF,6DAA6D;IAC7D,oEAAoE;IACpE,iEAAiE;IACjE,gEAAgE;IAChE,4DAA4D;IAC5D,8DAA8D;IAC9D,gEAAgE;IAChE,6DAA6D;IAC7D,WAAW;IACX,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,IAAI,UAAkB,CAAC;IACvB,IAAI,CAAC;QACH,mEAAmE;QACnE,iEAAiE;QACjE,mEAAmE;QACnE,gEAAgE;QAChE,gEAAgE;QAChE,yBAAyB;QACzB,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,cAAc,CAAC,EAAE;YAClE,OAAO,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE;YAC9B,iBAAiB,EAAE,UAAU;YAC7B,kBAAkB,EAAE,IAAI;YACxB,QAAQ;YACR,MAAM,EAAE,IAAI,gBAAgB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;SACxE,CAAC,CAAC;QACH,qEAAqE;QACrE,kEAAkE;QAClE,gEAAgE;QAChE,UAAU,GAAG,uBAAuB,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,gEAAgE;QAChE,iEAAiE;QACjE,mEAAmE;QACnE,yBAAyB;QACzB,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,yBAAyB,EAAE,CAAC;YACnE,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,OAAO,CAAC,IAAI,CACV,sCAAsC,KAAK,gCAAgC,GAAG,GAAG,CAClF,CAAC;QACF,UAAU,GAAG,uBAAuB,CAAC,cAAc,CAAC,CAAC;IACvD,CAAC;IAED,wCAAwC;IACxC,MAAM,GAAG,GAA4B,EAAE,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,CAAC;IACtE,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,oBAAoB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IAExD,yDAAyD;IACzD,oDAAoD;IACpD,2DAA2D;IAC3D,yDAAyD;IACzD,8DAA8D;IAC9D,gEAAgE;IAChE,2DAA2D;IAC3D,gEAAgE;IAChE,mEAAmE;IACnE,wDAAwD;IACxD,8DAA8D;IAC9D,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC;AACvC,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAS,oBAAoB,CAAC,KAAiB;IAC7C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;QAC1B,SAAS;QACT,WAAW;QACX,WAAW;QACX,IAAI;QACJ,IAAI;KACL,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,IAAI,GAAG,GAAG,IAAI,CAAC;QACf,IACE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAC1B,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;YAC5B,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;YACzB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAc,CAAC,IAAI,KAAK,OAAO;YAC/C,KAAK,CAAC,OAAO,CAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAc,CAAC,MAAM,CAAC,EACpD,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAa,CAAC;YAC3C,GAAG,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAA4B,EAAE,CAAC;YAC9D,OAAQ,GAA8B,CAAC,QAAQ,CAAC;QAClD,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxC,GAAG,GAAG,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,oBAAoB,CAAC,IAAI,CAAC,QAAsB,CAAC,EAAE,CAAC;QACjF,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/tree.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../src/tree.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/tree.js
ADDED
package/dist/tree.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../src/tree.ts"],"names":[],"mappings":""}
|
package/dist/walker.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type Token from "markdown-it/lib/token.mjs";
|
|
2
|
+
import type { TreeNode } from "./tree.js";
|
|
3
|
+
/**
|
|
4
|
+
* Convert a markdown-it token stream into a TreeNode[].
|
|
5
|
+
* Handles open/close token pairs by recursively collecting children.
|
|
6
|
+
*/
|
|
7
|
+
export declare function tokensToTree(tokens: Token[]): TreeNode[];
|
|
8
|
+
//# sourceMappingURL=walker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walker.d.ts","sourceRoot":"","sources":["../src/walker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,2BAA2B,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAG1C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,CAkCxD"}
|