@rse/specbook 1.3.2 → 1.4.1

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/README.md +9 -2
  2. package/dst/specbook-api.d.ts +5 -1
  3. package/dst/specbook-api.js +23 -9
  4. package/dst/specbook-cli.js +8 -5
  5. package/dst/specbook-cmd-export.js +2 -2
  6. package/dst/specbook-cmd-init.js +16 -2
  7. package/dst/specbook-coverage.js +1 -1
  8. package/dst/specbook-diagram.d.ts +1 -1
  9. package/dst/specbook-diagram.js +12 -10
  10. package/dst/specbook-export-ast.d.ts +1 -1
  11. package/dst/specbook-export-ast.js +21 -4
  12. package/dst/specbook-export-code.d.ts +14 -0
  13. package/dst/specbook-export-code.js +155 -0
  14. package/dst/specbook-export-common.d.ts +8 -2
  15. package/dst/specbook-export-common.js +126 -6
  16. package/dst/specbook-export-diagram.d.ts +15 -0
  17. package/dst/specbook-export-diagram.js +211 -0
  18. package/dst/specbook-export-html-fold.d.ts +20 -0
  19. package/dst/specbook-export-html-fold.js +458 -0
  20. package/dst/specbook-export-html-render.d.ts +51 -0
  21. package/dst/specbook-export-html-render.js +748 -0
  22. package/dst/specbook-export-html-search.js +6 -5
  23. package/dst/specbook-export-html-template.d.ts +21 -0
  24. package/dst/specbook-export-html-template.js +282 -0
  25. package/dst/specbook-export-html-widget.d.ts +12 -0
  26. package/dst/specbook-export-html-widget.js +605 -0
  27. package/dst/specbook-export-html.css +325 -50
  28. package/dst/specbook-export-html.js +62 -1931
  29. package/dst/specbook-export-image.d.ts +2 -0
  30. package/dst/specbook-export-image.js +161 -9
  31. package/dst/specbook-export-md.js +60 -12
  32. package/dst/specbook-format-schema.d.ts +1 -1
  33. package/dst/specbook-format-schema.js +1 -1
  34. package/dst/specbook-format-spec.d.ts +1 -0
  35. package/dst/specbook-format-spec.js +1 -0
  36. package/dst/specbook-format.md +173 -19
  37. package/dst/specbook-format.yaml +265 -24
  38. package/dst/specbook-ignore.js +2 -0
  39. package/dst/specbook-link.js +21 -5
  40. package/dst/specbook-mcp.js +9 -5
  41. package/dst/specbook-parse-common.d.ts +24 -0
  42. package/dst/specbook-parse-common.js +137 -10
  43. package/dst/specbook-parse-semantic.js +2 -0
  44. package/dst/specbook-parse-syntax.js +81 -20
  45. package/dst/specbook-parse.js +1 -1
  46. package/dst/specbook-project.d.ts +1 -0
  47. package/dst/specbook-project.js +10 -1
  48. package/dst/specbook-theme.d.ts +1 -0
  49. package/dst/specbook-theme.js +2 -0
  50. package/package.json +18 -12
@@ -53,9 +53,10 @@
53
53
  is an outermost paragraph-level element within an article or
54
54
  the title page abstract (a lone paragraph being the unit itself),
55
55
  i.e. one not nested inside another unit (like a paragraph in a
56
- table cell, covered by its table row), where a diagram is
57
- searched by its space-joined SVG text labels (its raw text
58
- content runs them together), and where the explicit anchor id
56
+ table cell, covered by its table row, or a code listing in its
57
+ diagram block), where a diagram is searched by its space-joined
58
+ SVG text labels (its raw text content runs them together), a code
59
+ listing by its text content, and where the explicit anchor id
59
60
  of an object heading or table row joins the searched text */
60
61
  const index = () => {
61
62
  if (indexed)
@@ -69,12 +70,12 @@
69
70
  els.forEach((el) => {
70
71
  let parent = el.parentElement
71
72
  while (parent !== null && parent !== root) {
72
- if (/^(TR|TD|TH|LI|P|BLOCKQUOTE)$/.test(parent.tagName))
73
+ if (/^(TR|TD|TH|LI|P|BLOCKQUOTE)$/.test(parent.tagName) || parent.classList.contains("diagram"))
73
74
  return
74
75
  parent = parent.parentElement
75
76
  }
76
77
  const id = (el.dataset.id ?? "").toLowerCase()
77
- const text = ((el.classList.contains("diagram") ?
78
+ const text = ((el.classList.contains("diagram") && el.dataset.type !== "listing" ?
78
79
  Array.from(el.querySelectorAll("text")).map((t) => t.textContent ?? "").join(" ") :
79
80
  (el.textContent ?? "")) + " " + id).toLowerCase()
80
81
  const words = new Set(text.split(/[^\p{L}\p{N}]+/u).filter((w) => w !== ""))
@@ -0,0 +1,21 @@
1
+ import nunjucks from "nunjucks";
2
+ declare const templates: {
3
+ Document: string;
4
+ Placeholder: string;
5
+ TitlePage: string;
6
+ Toc: string;
7
+ TocPanel: string;
8
+ TocPanelEntries: string;
9
+ Doc: string;
10
+ Artifact: string;
11
+ Object: string;
12
+ Coverage: string;
13
+ Properties: string;
14
+ Description: string;
15
+ Table: string;
16
+ TableChunked: string;
17
+ TableCompact: string;
18
+ };
19
+ export declare const safe: (html: string) => nunjucks.runtime.SafeString;
20
+ export declare const render: (name: keyof typeof templates, context: object) => string;
21
+ export {};
@@ -0,0 +1,282 @@
1
+ /*
2
+ ** Specification Book (SpecBook)
3
+ ** Copyright (c) 2026 Dr. Ralf S. Engelschall <rse@engelschall.com>
4
+ ** Licensed under Apache 2.0 <https://spdx.org/licenses/Apache-2.0>
5
+ */
6
+ import nunjucks from "nunjucks";
7
+ import nunjucksAddons from "@rse/nunjucks-addons";
8
+ import textframe from "textframe";
9
+ /* ==== Templates ==== */
10
+ /* the built-in Nunjucks templates for the HTML export */
11
+ const templates = {
12
+ /* <Document/> */
13
+ "Document": textframe `
14
+ <!DOCTYPE html>
15
+ <html{% if Document.lang %} lang="{{ Document.lang }}"{% endif %}{% if Document.theme %} class="theme-{{ Document.theme }}"{% endif %}>
16
+ <head>
17
+ <meta charset="utf-8"/>
18
+ <title>{{ Document.title }}</title>
19
+ <style>
20
+ {{ Document.css }}
21
+ </style>
22
+ <script>
23
+ {{ Document.themescript }}
24
+ </script>
25
+ </head>
26
+ <body>
27
+ {% if Document.realtime %}<div class="realtime-status disconnected" title="live preview connection"><svg class="realtime-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 8V2"/><path d="M15 8V2"/><path d="M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/><path d="M12 22v-5"/></svg></div>{% endif %}
28
+ <div class="theme-switch" onclick="themeSwitch()" title="switch color theme"><svg class="theme-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="12" cy="12" r="8.5"/><path d="M12 3.5 A 8.5 8.5 0 0 0 12 20.5 Z" fill="currentColor" stroke="none"/></svg></div>
29
+ {% if Document.info %}<div class="info-switch" title="toggle description popups"><svg class="info-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="12" cy="12" r="8.5"/><line x1="12" y1="11" x2="12" y2="16"/><line x1="12" y1="7.75" x2="12.01" y2="7.75"/></svg></div>{% endif %}
30
+ <div class="search" id="search">
31
+ <div class="search-toggle" id="search-toggle" title="toggle search field"><svg class="search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="3.5,4.5 20.5,4.5 14,12.5 14,20 10,17.5 10,12.5"/></svg></div>
32
+ <div class="search-field">
33
+ <input type="text" id="search-input" placeholder="Filter&hellip; (fuzzy matched keywords)" autocomplete="off" spellcheck="false"/>
34
+ <span class="search-clear" id="search-clear" title="clear search">&#x00D7;</span>
35
+ </div>
36
+ </div>
37
+ {%- if not Document.omitted.all %}
38
+ <div class="fold-switch">
39
+ <div class="fold-toggle" title="toggle folding controls"><svg class="fold-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M7 3.5l5 5 5-5"/><path d="M7 20.5l5-5 5 5"/></svg></div>
40
+ <div class="fold-controls">
41
+ {% if not Document.omitted.graph %}<div class="fold-graphs" title="fold/unfold all graph diagrams"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="5.5" cy="5.5" r="3"/><circle cx="18.5" cy="5.5" r="3"/><circle cx="12" cy="18.5" r="3"/><path d="M7.3 8.1 10.6 15.9"/><path d="M16.7 8.1 13.4 15.9"/></svg></div>{% endif %}
42
+ {% if not Document.omitted.hub %}<div class="fold-hubs" title="fold/unfold all hub diagrams"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3.5"/><circle cx="3.5" cy="4.5" r="2"/><circle cx="3.5" cy="19.5" r="2"/><circle cx="20.5" cy="4.5" r="2"/><circle cx="20.5" cy="19.5" r="2"/><path d="M5.5 4.5H10V9.1"/><path d="M18.5 4.5H14V9.1"/><path d="M5.5 19.5H10V14.9"/><path d="M18.5 19.5H14V14.9"/></svg></div>{% endif %}
43
+ {% if not Document.omitted.grid %}<div class="fold-grids" title="fold/unfold all grid diagrams"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="3.5" width="7" height="7" rx="1"/><rect x="13.5" y="3.5" width="7" height="7" rx="1"/><rect x="3.5" y="13.5" width="7" height="7" rx="1"/><rect x="13.5" y="13.5" width="7" height="7" rx="1"/></svg></div>{% endif %}
44
+ {% if not Document.omitted.code %}<div class="fold-codes" title="fold/unfold all diagrams as code"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 7l-5 5 5 5"/><path d="M16 7l5 5-5 5"/><path d="M13.5 4l-3 16"/></svg></div>{% endif %}
45
+ {% if not Document.omitted.image %}<div class="fold-images" title="fold/unfold all images"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2.5" y="3.5" width="19" height="17" rx="2"/><circle cx="8.5" cy="9" r="2"/><path d="M21.5 15.5l-5-5-11 10"/></svg></div>{% endif %}
46
+ {% if not Document.omitted.listing %}<div class="fold-listings" title="fold/unfold all code listings"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 6h11.5"/><path d="M9 12h11.5"/><path d="M9 18h7"/><path d="M3.5 6h.01"/><path d="M3.5 12h.01"/><path d="M3.5 18h.01"/></svg></div>{% endif %}
47
+ {% for level in [ 1, 2, 3 ] %}{% if not Document.omitted["level" ~ level] %}<div class="fold-level{{ level }}" title="fold/unfold all diagrams from nesting level {{ level }} on"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2.5" y="2.5" width="11" height="11" rx="1.5"/><rect x="6.5" y="6.5" width="3" height="3" rx="0.5"/><text x="19.5" y="23" text-anchor="middle" font-size="14.5" font-weight="bold" fill="currentColor" stroke="none">{{ level }}</text></svg></div>{% endif %}{% endfor %}
48
+ {% if not Document.omitted.text %}<div class="fold-texts" title="fold/unfold all cell texts"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 7V4.5h15V7"/><path d="M12 4.5v15"/><path d="M8.5 19.5h7"/></svg></div>{% endif %}
49
+ </div>
50
+ </div>
51
+ {%- endif %}
52
+ <div class="scroll-progress" title="scroll to top"><svg class="scroll-ring" viewBox="0 0 44 44" fill="none" stroke-width="2.5"><circle class="scroll-todo" cx="22" cy="22" r="20"/><circle class="scroll-done" cx="22" cy="22" r="20" stroke-linecap="round" pathLength="1" stroke-dasharray="1" stroke-dashoffset="1"/></svg><svg class="scroll-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19V5"/><path d="M5 12l7-7 7 7"/></svg></div>
53
+ {{ Document.tocpanel }}
54
+ {{ Document.titlepage }}
55
+ {{ Document.toc }}
56
+ {{ Document.doc }}
57
+ {{ Document.artifacts }}
58
+ {% if Document.search %}<script>{{ Document.search }}</script>{% endif %}
59
+ <script>{{ Document.progress }}</script>
60
+ <script>{{ Document.fold }}</script>
61
+ <script>{{ Document.maximize }}</script>
62
+ {% if Document.tocpanel %}<script>{{ Document.tocscript }}</script>{% endif %}
63
+ {% if Document.info %}<script>{{ Document.info }}</script>{% endif %}
64
+ {% if Document.realtime %}<script class="realtime">{{ Document.realtime }}</script>{% endif %}
65
+ </body>
66
+ </html>
67
+ `,
68
+ /* <Placeholder/> */
69
+ "Placeholder": textframe `
70
+ <!DOCTYPE html>
71
+ <html>
72
+ <head>
73
+ <meta charset="utf-8"/>
74
+ <title>{{ Placeholder.title }}</title>
75
+ <style>
76
+ {{ Placeholder.css }}
77
+ </style>
78
+ <script>
79
+ {{ Placeholder.themescript }}
80
+ </script>
81
+ </head>
82
+ <body>
83
+ <div class="placeholder">{{ Placeholder.message }}</div>
84
+ <script class="realtime">{{ Placeholder.realtime }}</script>
85
+ </body>
86
+ </html>
87
+ `,
88
+ /* <TitlePage/> */
89
+ "TitlePage": textframe `
90
+ <div class="titlepage" id="titlepage">
91
+ {% if TitlePage.logo %}<div class="logo">{{ TitlePage.logo }}</div>{% endif %}
92
+ <div class="title">{{ TitlePage.title }}</div>
93
+ {% if TitlePage.subtitle %}<div class="subtitle">{{ TitlePage.subtitle }}</div>{% endif %}
94
+ {% if TitlePage.author %}<div class="author">{{ TitlePage.author }}</div>{% endif %}
95
+ <table class="meta">
96
+ {% if TitlePage.version %}<tr><td class="label">Version:</td><td>{{ TitlePage.version }}</td></tr>{% endif %}
97
+ <tr><td class="label">Created:</td><td>{{ TitlePage.created }}</td></tr>
98
+ <tr><td class="label">Modified:</td><td>{{ TitlePage.modified }}</td></tr>
99
+ </table>
100
+ {{ TitlePage.description }}
101
+ {{ TitlePage.properties }}
102
+ </div>
103
+ `,
104
+ /* <Toc/> */
105
+ "Toc": textframe `
106
+ <nav class="toc" id="toc">
107
+ <h1>Table of Contents</h1>
108
+ <table>
109
+ {% for entry in Toc.entries %}
110
+ <tr class="level-{{ entry.level }}"><td><a href="#{{ entry.id }}"><span class="object-kind"{% if entry.info %} data-info="{{ entry.info }}" data-info-path="{{ entry.infopath }}"{% endif %}>{{ entry.kind }}:</span> <span class="object-name"{% if entry.spec %} data-info-spec="{{ entry.spec }}"{% endif %}>{{ entry.name }}</span> <span class="link-symbol">&#x26AD;</span></a></td>{% if entry.page %}<td class="page"><a href="#{{ entry.id }}">{{ entry.page }}</a></td>{% endif %}</tr>
111
+ {% endfor %}
112
+ </table>
113
+ </nav>
114
+ `,
115
+ /* <TocPanel/> */
116
+ "TocPanel": textframe `
117
+ <nav class="toc-panel">
118
+ <div class="toc-tab" title="toggle table of contents"><svg class="toc-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg></div>
119
+ <div class="toc-list">
120
+ <ul class="extra">
121
+ {% if TocPanel.title %}<li><a href="#titlepage"><span class="entry">Title</span></a></li>{% endif %}
122
+ <li><a href="#toc"><span class="entry">Table of Contents</span></a></li>
123
+ {% if TocPanel.doc %}<li><a href="#doc"><span class="entry">Diagram of Contents</span></a></li>{% endif %}
124
+ </ul>
125
+ {{ TocPanel.entries }}
126
+ </div>
127
+ </nav>
128
+ `,
129
+ /* <TocPanelEntries/> */
130
+ "TocPanelEntries": textframe `
131
+ <ul>
132
+ {% for entry in Entries %}
133
+ <li><a href="#{{ entry.id }}"><span class="entry"><span class="object-kind"{% if entry.info %} data-info="{{ entry.info }}" data-info-path="{{ entry.infopath }}"{% endif %}>{{ entry.kind }}:</span> <span class="object-name"{% if entry.spec %} data-info-spec="{{ entry.spec }}"{% endif %}>{{ entry.name }}</span></span></a>{{ entry.children }}</li>
134
+ {% endfor %}
135
+ </ul>
136
+ `,
137
+ /* <Doc/> */
138
+ "Doc": textframe `
139
+ <nav class="doc" id="doc">
140
+ <h1>Diagram of Contents</h1>
141
+ {{ Doc.diagram }}
142
+ </nav>
143
+ `,
144
+ /* <Artifact/> */
145
+ "Artifact": textframe `
146
+ <article>
147
+ {{ Artifact.objects }}
148
+ </article>
149
+ `,
150
+ /* <Object/> */
151
+ "Object": textframe `
152
+ <section>
153
+ <h{{ Object.level }} id="{{ Object.id }}"{% if Object.anchor %} data-id="{{ Object.anchor }}"{% endif %}><span class="object-kind"{% if Object.info %} data-info="{{ Object.info }}" data-info-path="{{ Object.infopath }}"{% endif %}>{{ Object.kind }}:</span> <span class="object-name"{% if Object.spec %} data-info-spec="{{ Object.spec }}"{% endif %}>{{ Object.name }}</span>{% if Object.primary %} <span class="primary-marker">&#x2318;</span>{% endif %}{% if Object.paren %} <span class="anchor-paren">({{ Object.paren }})</span>{% endif %} <a href="#{{ Object.id }}"><span class="anchor-symbol">&#x2693;&#xFE0E;</span></a></h{{ Object.level }}>
154
+ {{ Object.diagram }}
155
+ {{ Object.properties }}
156
+ {{ Object.description }}
157
+ {{ Object.coverage }}
158
+ {{ Object.children }}
159
+ </section>
160
+ `,
161
+ /* <Coverage/> */
162
+ "Coverage": textframe `
163
+ <table class="coverage">
164
+ <thead>
165
+ <tr><th>Coverage</th><th>Covered</th><th>Total</th><th class="ratio">Ratio</th></tr>
166
+ </thead>
167
+ <tbody>
168
+ {% for entry in Coverage %}
169
+ <tr{% if entry.even %} class="even"{% endif %}><td>{{ entry.label }}</td><td>{{ entry.covered }}</td><td>{{ entry.total }}</td><td class="ratio"><span class="bar"><span style="width: {{ entry.ratio }}%"></span></span> {{ entry.ratio }}%</td></tr>
170
+ {% endfor %}
171
+ </tbody>
172
+ </table>
173
+ `,
174
+ /* <Properties/> */
175
+ "Properties": textframe `
176
+ <table class="props"{% if Fold %} data-fold-height="{{ Fold }}"{% endif %}>
177
+ {% for property in Properties %}
178
+ <tr><td class="key property-name"><span{% if property.info %} data-info="{{ property.info }}" data-info-path="{{ property.infopath }}" data-info-prop="{{ property.key }}"{% endif %}>{{ property.key }}</span></td><td>{{ property.value }}</td></tr>
179
+ {% endfor %}
180
+ </table>
181
+ `,
182
+ /* <Description/> */
183
+ "Description": textframe `
184
+ {%- if Description.block %}
185
+ <div class="description">{{ Description.description }}{% if Description.rationale %}
186
+ <p class="rationale">&mdash; <span class="keyword">BECAUSE</span> {{ Description.rationale }}</p>{% endif %}</div>
187
+ {%- elif Description.description or Description.rationale %}
188
+ <p class="description">{{ Description.description }}{% if Description.rationale %}
189
+ <span class="rationale">&mdash; <span class="keyword">BECAUSE</span> {{ Description.rationale }}</span>{% endif %}</p>
190
+ {%- endif %}
191
+ {%- if Description.elaboration %}
192
+ <div class="description">{{ Description.elaboration }}</div>
193
+ {%- endif %}
194
+ {%- for embedding in Description.embeddings %}
195
+ <div class="embedding">{{ embedding }}</div>
196
+ {%- endfor %}
197
+ `,
198
+ /* <Table/> */
199
+ "Table": textframe `
200
+ <table class="objects"{% if Table.fold %} data-fold-height="{{ Table.fold }}"{% endif %}>
201
+ <thead>
202
+ <tr>
203
+ <th class="object-kind"><span{% if Table.info %} data-info="{{ Table.info }}" data-info-path="{{ Table.infopath }}"{% endif %}>{{ Table.head }}</span></th>
204
+ {%- for key in Table.keys %}<th class="property-name"><span{% if Table.info %} data-info="{{ Table.info }}" data-info-path="{{ Table.infopath }}" data-info-prop="{{ key }}"{% endif %}>{{ key }}</span></th>{% endfor %}
205
+ {%- if Table.desc %}<th class="description" style="width: {{ Table.width }}%">Description</th>{% endif %}
206
+ </tr>
207
+ </thead>
208
+ <tbody>
209
+ {% for row in Table.rows %}
210
+ <tr id="{{ row.id }}"{% if row.anchor %} data-id="{{ row.anchor }}"{% endif %}{% if row.even %} class="even"{% endif %}>
211
+ <td><span{% if row.spec %} data-info-spec="{{ row.spec }}"{% endif %}>{{ row.name }}</span>{% if row.primary %} <span class="primary-marker">&#x2318;</span>{% endif %}{% if row.paren %} <span class="anchor-paren">({{ row.paren }})</span>{% endif %} <a href="#{{ row.id }}"><span class="anchor-symbol">&#x2693;&#xFE0E;</span></a></td>
212
+ {%- for value in row.values %}<td>{{ value }}</td>{% endfor %}
213
+ {%- if Table.desc %}<td>{{ row.description }}</td>{% endif %}
214
+ </tr>
215
+ {% endfor %}
216
+ </tbody>
217
+ </table>
218
+ `,
219
+ /* <TableChunked/> */
220
+ "TableChunked": textframe `
221
+ <table class="objects"{% if Table.fold %} data-fold-height="{{ Table.fold }}"{% endif %}>
222
+ <thead>
223
+ <tr>
224
+ <th class="object-kind"><span{% if Table.info %} data-info="{{ Table.info }}" data-info-path="{{ Table.infopath }}"{% endif %}>{{ Table.head }}</span></th>
225
+ <th class="description">Properties{% if Table.desc %} &amp; Description{% endif %}</th>
226
+ </tr>
227
+ </thead>
228
+ <tbody>
229
+ {% for row in Table.rows %}
230
+ <tr id="{{ row.id }}"{% if row.anchor %} data-id="{{ row.anchor }}"{% endif %}{% if row.even %} class="even"{% endif %}>
231
+ <td><span{% if row.spec %} data-info-spec="{{ row.spec }}"{% endif %}>{{ row.name }}</span>{% if row.primary %} <span class="primary-marker">&#x2318;</span>{% endif %}{% if row.paren %} <span class="anchor-paren">({{ row.paren }})</span>{% endif %} <a href="#{{ row.id }}"><span class="anchor-symbol">&#x2693;&#xFE0E;</span></a></td>
232
+ <td class="chunks">
233
+ <table class="chunks">
234
+ {% for chunk in row.chunks %}
235
+ <tr>{% for cell in chunk %}<th{% if not cell.desc %} class="property-name"{% endif %}{% if cell.span > 1 %} colspan="{{ cell.span }}"{% endif %}><span{% if not cell.desc and Table.info %} data-info="{{ Table.info }}" data-info-path="{{ row.spec }}" data-info-prop="{{ cell.key }}"{% endif %}>{{ cell.key }}</span></th>{% endfor %}</tr>
236
+ <tr>{% for cell in chunk %}<td{% if cell.span > 1 %} colspan="{{ cell.span }}"{% endif %}>{{ cell.value }}</td>{% endfor %}</tr>
237
+ {% endfor %}
238
+ </table>
239
+ </td>
240
+ </tr>
241
+ {% endfor %}
242
+ </tbody>
243
+ </table>
244
+ `,
245
+ /* <TableCompact/> */
246
+ "TableCompact": textframe `
247
+ <table class="objects"{% if Table.fold %} data-fold-height="{{ Table.fold }}"{% endif %}>
248
+ <thead>
249
+ <tr>
250
+ <th class="object-kind"><span{% if Table.info %} data-info="{{ Table.info }}" data-info-path="{{ Table.infopath }}"{% endif %}>{{ Table.head }}</span></th>
251
+ <th class="description">{{ Table.label }}</th>
252
+ </tr>
253
+ </thead>
254
+ <tbody>
255
+ {% for row in Table.rows %}
256
+ <tr id="{{ row.id }}"{% if row.anchor %} data-id="{{ row.anchor }}"{% endif %}{% if row.even %} class="even"{% endif %}>
257
+ <td><span{% if row.spec %} data-info-spec="{{ row.spec }}"{% endif %}>{{ row.name }}</span>{% if row.primary %} <span class="primary-marker">&#x2318;</span>{% endif %}{% if row.paren %} <span class="anchor-paren">({{ row.paren }})</span>{% endif %} <a href="#{{ row.id }}"><span class="anchor-symbol">&#x2693;&#xFE0E;</span></a></td>
258
+ <td class="compact">{{ row.content }}</td>
259
+ </tr>
260
+ {% endfor %}
261
+ </tbody>
262
+ </table>
263
+ `
264
+ };
265
+ /* the Nunjucks environment with the @rse/nunjucks-addons extensions */
266
+ const env = new nunjucks.Environment(null, { autoescape: true });
267
+ nunjucksAddons(env);
268
+ /* mark pre-rendered HTML as safe for template interpolation */
269
+ export const safe = (html) => new nunjucks.runtime.SafeString(html);
270
+ /* the built-in Nunjucks templates compiled on first use, as
271
+ renderString() would re-compile a template on every single call
272
+ (i.e. for every rendered object, property table, and description) */
273
+ const compiled = new Map();
274
+ /* render one of the built-in Nunjucks templates with a context */
275
+ export const render = (name, context) => {
276
+ let template = compiled.get(name);
277
+ if (template === undefined) {
278
+ template = new nunjucks.Template(templates[name], env, undefined, true);
279
+ compiled.set(name, template);
280
+ }
281
+ return template.render(context);
282
+ };
@@ -0,0 +1,12 @@
1
+ export declare const themeScript: string;
2
+ export declare const placeholderStylesheet: string;
3
+ export declare const realtimeScript: string;
4
+ export declare const scrollProgressScript: string;
5
+ export declare const maximizeScript: string;
6
+ export declare const tocPanelScript: string;
7
+ export type InfoEntry = {
8
+ d?: string;
9
+ p?: Record<string, string>;
10
+ };
11
+ export type SpecEntry = [id: string, parent: number, kind: string, name: string, desc: string];
12
+ export declare const infoScript: (info: InfoEntry[], spec: SpecEntry[]) => string;