You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The corpus-extensions page and the script-driven-generators page
documented two halves of one feature: scripts under addons/extensions
that declare transforms and generators through the `register_*` hooks.
This folds the generator material into the extensions page, which now
covers both hooks and the shared `ctx` object, and removes the separate
page.
Copy file name to clipboardExpand all lines: docs/modules/ROOT/pages/extensions/corpus-extensions.adoc
+58-15Lines changed: 58 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,11 @@
1
-
= Corpus Extensions
1
+
= Extensions
2
2
3
-
Use an extension to rewrite metadata across many symbols at once: backfill briefs from a naming convention, tag symbols by group, mark generated code as "see below" in the output. Extensions run between extraction and rendering, so every generator sees the change.
3
+
An extension is a Lua or JavaScript script that runs as part of a Mr.Docs build and shapes the documentation in a way templates alone cannot. There are two kinds, and a single script may declare either or both:
4
+
5
+
* A *corpus transform* rewrites metadata across many symbols at once: backfill briefs from a naming convention, tag symbols by group, mark generated code as "see below" in the output. Transforms run between extraction and rendering, so every generator sees the change.
6
+
* A *generator* owns the whole emit: instead of rendering one page per symbol, it traverses the corpus and writes whatever files it wants. That lets it produce shapes the per-page generators cannot, such as a single artifact aggregated across every symbol.
7
+
8
+
A script declares a transform with `register_transform(fn)` and a generator with `register_generator(id, fn)`. Either way the registered function receives a single context object, `ctx`.
4
9
5
10
== Languages and addon locations
6
11
@@ -14,9 +19,21 @@ Both scripting languages reach the same `mrdocs` API. The choice is a trade-off,
14
19
* *Lua* is the language designed to be embedded. Mr.Docs links it whole, so scripts have access to the entire Lua standard library (`string`, `table`, `math`, `io`, `os`) and can do filesystem work or text munging without leaving the script. The cost is that fewer people read Lua at a glance than read JavaScript. If you're already familiar with Lua, it is the more powerful choice.
15
20
====
16
21
17
-
== Accessing the corpus
22
+
== The context object
23
+
24
+
Every registered function receives one argument, `ctx`:
25
+
26
+
* `ctx.corpus` is the corpus. Its `symbols` field is a flat array of every extracted symbol; what a script can do with those symbols depends on the kind of extension, described in the sections below.
27
+
* `ctx.config` is the resolved configuration: the same object the templates receive, holding every value from the config file and the command line. See xref:configuration/reference.adoc[the configuration reference] for the available keys.
28
+
29
+
A generator's `ctx` carries one more field, `ctx.output`, covered under <<generators>>.
18
30
19
-
A script extends Mr.Docs by calling `register_transform(fn)` with a function that takes the corpus. Mr.Docs invokes each registered function once, in registration order, with a flat view of the corpus. A script can register several transforms, or none at all; if it registers nothing, Mr.Docs warns that the script had no effect and moves on.
31
+
A script can register any number of transforms and generators, or none at all. If it registers nothing, Mr.Docs warns that the script had no effect and moves on.
32
+
33
+
[#corpus-transforms]
34
+
== Corpus transforms
35
+
36
+
A transform is a function passed to `register_transform`. Mr.Docs invokes each registered function once, in registration order, with the `ctx` object. A flat view of the corpus reaches the script through `ctx.corpus`.
The `corpus` object provides functions that expose the symbol graph. The `corpus.symbols` field is a flat array containing every extracted symbol. Scripts that need queries like "all members of `X`" simply walk the array and filter.
57
+
The `ctx.corpus` object provides functions that expose the symbol graph. The `ctx.corpus.symbols` field is a flat array containing every extracted symbol. Scripts that need queries like "all members of `X`" simply walk the array and filter.
41
58
42
59
For instance, the following scripts count the symbols of each kind and report the totals at the end of the run:
43
60
@@ -48,10 +65,10 @@ JavaScript::
48
65
.`addons/extensions/count_by_kind.js`
49
66
[source,javascript]
50
67
----
51
-
register_transform(function(corpus) {
68
+
register_transform(function(ctx) {
52
69
var counts = {};
53
-
for (var i = 0; i < corpus.symbols.length; ++i) {
54
-
var k = corpus.symbols[i].kind;
70
+
for (var i = 0; i < ctx.corpus.symbols.length; ++i) {
71
+
var k = ctx.corpus.symbols[i].kind;
55
72
counts[k] = (counts[k] || 0) + 1;
56
73
}
57
74
for (var k in counts) {
@@ -65,9 +82,9 @@ Lua::
65
82
.`addons/extensions/count_by_kind.lua`
66
83
[source,lua]
67
84
----
68
-
register_transform(function(corpus)
85
+
register_transform(function(ctx)
69
86
local counts = {}
70
-
for _, sym in ipairs(corpus.symbols) do
87
+
for _, sym in ipairs(ctx.corpus.symbols) do
71
88
counts[sym.kind] = (counts[sym.kind] or 0) + 1
72
89
end
73
90
for k, v in pairs(counts) do
@@ -77,12 +94,12 @@ end)
77
94
----
78
95
======
79
96
80
-
Each entry in `corpus.symbols` is a proxy for a live Mr.Docs symbol. The fields of each object are at xref:extensions/dom-reference.adoc[the DOM reference].
97
+
Each entry in `ctx.corpus.symbols` is a proxy for a live Mr.Docs symbol. The fields of each object are at xref:extensions/dom-reference.adoc[the DOM reference].
81
98
82
99
When a script knows a symbol's id and needs to act on that one symbol:
83
100
84
-
* `corpus.get(id)` returns the proxy for it or `null` if the id is unknown
85
-
* `corpus.lookup(name)` does a global-namespace name lookup and returns the proxy (or `null`)
101
+
* `ctx.corpus.get(id)` returns the proxy for it or `null` if the id is unknown
102
+
* `ctx.corpus.lookup(name)` does a global-namespace name lookup and returns the proxy (or `null`)
86
103
87
104
.`subclass-tree.cpp`
88
105
[source,cpp]
@@ -122,7 +139,7 @@ Shape
122
139
----
123
140
124
141
[[modifying-the-corpus]]
125
-
== Modifying the corpus
142
+
=== Modifying the corpus
126
143
127
144
Scripts modify the corpus by assigning to fields on a symbol proxy. Each assignment lands directly in the underlying Mr.Docs symbol. The runtime validates each assignment and raises an exception on an invalid value. An uncaught error in an extension aborts the build and includes the script's path and the error message.
128
145
@@ -160,7 +177,7 @@ Every `is_foo_bar` function then ships with "Returns true if foo bar." Authors o
When the value being written needs to reference another symbol, the second symbol's `id` is what makes the link clickable in the rendered output rather than a plain string.
166
183
@@ -203,3 +220,29 @@ The two-pass shape (index, then look up) is the idiom whenever a write needs to
203
220
Notice in this example that `s.doc.sees` receives a list of polymorphic types that represent a paragraph in `s.doc.sees.children`. These polymorphic objects accept an object with a `kind:` selector that names the concrete derived class to construct.
204
221
====
205
222
223
+
[[generators]]
224
+
== Generators
225
+
226
+
The built-in generators render one page per symbol. 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, that page-per-symbol shape cannot express it. A generator hands the whole emit to the script instead: it traverses the corpus and writes whatever files it wants. No C++ and no templates are involved.
227
+
228
+
A script declares a generator with `register_generator(id, fn)`. The `id` is the name you select on the command line with `--generator=<id>`; a registered generator takes precedence over a built-in of the same name. Selecting a generator is a request for output, so its function does the work directly, the page-per-symbol fallback the built-ins provide does not apply.
229
+
230
+
The function receives the same `ctx` a transform does, plus `ctx.output`:
231
+
232
+
* `ctx.corpus.symbols` is the array of every symbol. Each carries the same fields the template and helper layers see, plus a flat `_id` string suitable as a stable per-symbol URL fragment. A generator reads the corpus rather than mutating it.
233
+
* `ctx.config` is the resolved configuration, as above.
234
+
* `ctx.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.
235
+
236
+
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. Mr.Docs does not apply an escape map to a generator's output.
237
+
238
+
=== Example: a search index
239
+
240
+
A complete, runnable example lives at `examples/generators/script-driven/search-index/`. The extension declares a `search-index` generator that emits a single search-index.json aggregating every symbol, an artifact no per-page generator can produce:
To build the output structure yourself, e.g. one file per namespace or a single aggregated artifact like a search index, hand the whole emit to a script instead of rendering one page per symbol. See xref:extensions/script-driven-generators.adoc[Script-driven generators].
249
+
To build the output structure yourself, e.g. one file per namespace or a single aggregated artifact like a search index, hand the whole emit to a script instead of rendering one page per symbol. See the xref:extensions/corpus-extensions.adoc#generators[generators] section of the extensions page.
0 commit comments