Skip to content

Commit 8d2066a

Browse files
committed
docs: document script-driven generators
1 parent 581b015 commit 8d2066a

4 files changed

Lines changed: 88 additions & 2 deletions

File tree

docs/modules/ROOT/pages/generators.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ Unknown top-level keys are silently ignored so future schema additions stay non-
200200
If the same id appears under more than one addon root, the first one wins: that root's manifest sets the format's escape rules.
201201
Later roots can still contribute layered partials and helpers under the same id through the existing template-loading path, so a project can supplement a shared format without redefining it.
202202

203+
To add a generator that builds its output structure, rather than rendering one page per symbol from templates, see xref:script-driven-generators.adoc[Script-driven generators].
204+
203205
== Stylesheet Options
204206

205207
The HTML and AsciiDoc generators ship a bundled stylesheet that is inlined by default. You can replace or layer styles with the following options (available in config files and on the CLI):
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
= Script-driven generators
2+
3+
A data-driven generator renders one page per symbol from templates. When you need a different output structure, e.g. one file per namespace, or a single artifact aggregated across every symbol, such as a search index, a template generator cannot express it, because the page-per-symbol shape is fixed by the host. A script-driven generator hands the whole emit to a Lua or JavaScript script, which traverses the corpus and writes whatever files it wants. No C++ and no templates are involved.
4+
5+
A generator directory is script-driven when its mrdocs-generator.yml names an entry script:
6+
7+
[source,yaml]
8+
----
9+
script: generator.lua
10+
----
11+
12+
The `script` key holds a path to a Lua (.lua) or JavaScript (.js) file, relative to the generator directory. Naming a script is what distinguishes the two flavors: a manifest with a `script` key is script-driven, otherwise the directory is a data-driven (template) generator. As with template generators, the directory name is the generator id you select with `--generator`.
13+
14+
== The `generate` entry point
15+
16+
The script defines a single entry point, a function named `generate`:
17+
18+
[source,lua]
19+
----
20+
function generate(corpus, output, config, params)
21+
-- ...
22+
end
23+
----
24+
25+
`corpus.symbols` is the array of every symbol. Each symbol carries the same fields the template and helper layers see, plus a flat `_id` string suitable as a stable per-symbol URL fragment.
26+
27+
`output.write(relativePath, contents)` writes one file under the configured output directory, which is the path specified with `--output` on the command line, or with the `output` key in the config file; that's the same location the built-in generators write to. The path is resolved relative to that directory and may not escape it; an absolute path or one that climbs above the output directory is rejected. Parent directories are created as needed.
28+
29+
Because the script owns the output, it also owns what a per-page generator would otherwise do for it: the URLs it emits, and any escaping of the content it writes. The host does not apply an escape map to a script-driven generator's output.
30+
31+
`config` is the resolved configuration: the same object the templates receive, holding every value from the config file and the command line. See xref:config-file.adoc[the configuration reference] for the available keys.
32+
33+
`params` is this generator's own parameters, read from the optional `params:` mapping in its mrdocs-generator.yml. A scalar value is a string (a script coerces numbers or booleans itself); nested mappings and sequences become objects and arrays. It is an empty object when the manifest declares no parameters. For example:
34+
35+
[source,yaml]
36+
----
37+
script: generator.lua
38+
params:
39+
title: API Reference
40+
----
41+
42+
makes `params.title` available to the script.
43+
44+
`config` and `params` are trailing arguments, so a generator that needs neither can omit them, and use `function generate(corpus, output)`.
45+
46+
JavaScript looks up `generate` as a global function, so a JavaScript generator must define one (`function generate(corpus, output, config, params) { ... }`). Lua accepts that same named-global form, or - equivalently - the function value the chunk returns:
47+
48+
[source,lua]
49+
----
50+
-- Equivalent, in Lua, to a global function named generate.
51+
return function(corpus, output, config, params)
52+
-- ...
53+
end
54+
----
55+
56+
Unlike a corpus-transform extension, whose hook is optional, a generator must define a `generate` function: selecting the generator is a request for output, so a missing entry point is an error.
57+
58+
== Example: a search index
59+
60+
This generator emits a single search-index.json aggregating every symbol, an artifact no per-page generator can produce:
61+
62+
[source,lua]
63+
----
64+
-- Quote a string as a JSON value.
65+
local function json_string(s)
66+
s = s:gsub('\\', '\\\\'):gsub('"', '\\"')
67+
return '"' .. s .. '"'
68+
end
69+
70+
function generate(corpus, output)
71+
local entries = {}
72+
for _, sym in ipairs(corpus.symbols) do
73+
local name = sym.name or ""
74+
if name ~= "" then
75+
entries[#entries + 1] =
76+
'{"name":' .. json_string(name) ..
77+
',"url":' .. json_string(sym._id .. ".html") .. "}"
78+
end
79+
end
80+
output.write(
81+
"search-index.json",
82+
"[" .. table.concat(entries, ",") .. "]")
83+
end
84+
----

docs/mrdocs.schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@
252252
},
253253
"generator": {
254254
"default": "adoc",
255-
"description": "The generator is responsible for creating the documentation from the extracted symbols. The generator uses the extracted symbols and the templates to create the documentation. The built-in generators include `adoc`, `html`, and `xml`; data-driven generators can be added by dropping a template folder under <addon>/generator/<name>/.",
255+
"description": "The generator is responsible for creating the documentation from the extracted symbols. The generator uses the extracted symbols and the templates to create the documentation. The built-in generators include `adoc`, `html`, and `xml`; data-driven generators can be added by dropping a template folder under <addon>/generator/<name>/; script-driven generators instead ship a Lua or JavaScript script that produces the output.",
256256
"title": "Generator used to create the documentation",
257257
"type": "string"
258258
},

src/lib/ConfigOptions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@
397397
{
398398
"name": "generator",
399399
"brief": "Generator used to create the documentation",
400-
"details": "The generator is responsible for creating the documentation from the extracted symbols. The generator uses the extracted symbols and the templates to create the documentation. The built-in generators include `adoc`, `html`, and `xml`; data-driven generators can be added by dropping a template folder under <addon>/generator/<name>/.",
400+
"details": "The generator is responsible for creating the documentation from the extracted symbols. The generator uses the extracted symbols and the templates to create the documentation. The built-in generators include `adoc`, `html`, and `xml`; data-driven generators can be added by dropping a template folder under <addon>/generator/<name>/; script-driven generators instead ship a Lua or JavaScript script that produces the output.",
401401
"type": "string",
402402
"default": "adoc"
403403
},

0 commit comments

Comments
 (0)