duckfn-docs-kit 0.2.1 → 0.4.0
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/AGENTS.md +294 -224
- package/README.md +10 -6
- package/bin/sql-verify.mjs +12 -12
- package/dist/IconButton.d.ts +22 -0
- package/dist/codemirror.d.ts +29 -0
- package/dist/index.d.ts +28 -7
- package/dist/index.js +2 -2
- package/dist/mermaid/DfkMermaid.d.ts +7 -0
- package/dist/mermaid/config.d.ts +48 -0
- package/dist/mermaid/remark.d.ts +40 -0
- package/dist/mermaid/remark.js +32 -0
- package/dist/mermaid/render.d.ts +94 -0
- package/dist/mermaid/styles.d.ts +6 -0
- package/dist/mermaid/title.d.ts +23 -0
- package/dist/{register-DKLiYs-F.js → register-Dev_kc3Z.js} +921 -579
- package/dist/remark.d.ts +1 -1
- package/dist/sql/browserRunner.d.ts +41 -0
- package/dist/sql/browserRunner.js +186 -0
- package/dist/sql/client.js +1 -1
- package/dist/sql/harness.d.ts +59 -0
- package/dist/sql/harness.js +8328 -0
- package/dist/sql/remark.d.ts +6 -1
- package/dist/sql/renderers.d.ts +2 -0
- package/dist/sql/runtime.d.ts +20 -0
- package/dist/sql/verify.d.ts +4 -5
- package/dist/sql/verify.js +36 -49
- package/package.json +6 -2
- package/src/IconButton.ts +50 -0
- package/src/codemirror.ts +88 -0
- package/src/index.ts +31 -7
- package/src/mermaid/DfkMermaid.css +289 -0
- package/src/mermaid/DfkMermaid.ts +557 -0
- package/src/mermaid/config.ts +74 -0
- package/src/mermaid/remark.ts +98 -0
- package/src/mermaid/render.ts +178 -0
- package/src/mermaid/styles.ts +24 -0
- package/src/mermaid/title.ts +127 -0
- package/src/register.ts +3 -0
- package/src/remark.ts +1 -1
- package/src/sql/DfkSql.css +13 -10
- package/src/sql/DfkSql.ts +11 -46
- package/src/sql/browserRunner.ts +402 -0
- package/src/sql/harness.ts +134 -0
- package/src/sql/remark.ts +6 -1
- package/src/sql/renderers.ts +24 -3
- package/src/sql/runtime.ts +44 -0
- package/src/sql/sql.css +13 -11
- package/src/sql/verify.ts +23 -41
- package/dist/sql/editor.d.ts +0 -16
- package/dist/sql/nodeRunner.d.ts +0 -51
- package/dist/sql/nodeRunner.js +0 -115
- package/src/sql/editor.ts +0 -75
- package/src/sql/nodeRunner.ts +0 -298
package/AGENTS.md
CHANGED
|
@@ -1,224 +1,294 @@
|
|
|
1
|
-
# duckfn-docs-kit — usage guide for agents and site authors
|
|
2
|
-
|
|
3
|
-
This is the **consumer-facing** companion to [`README.md`](./README.md): the README says what to
|
|
4
|
-
import and how to wire it into `docusaurus.config.ts`, this file states the **contracts and the
|
|
5
|
-
traps** — the things that are easy to get subtly wrong when you write a docs page or review one.
|
|
6
|
-
|
|
7
|
-
Read it before writing runnable SQL blocks or configuring preloads.
|
|
8
|
-
|
|
9
|
-
> Developing the kit itself? Its internal conventions (rendering contract, shadow-DOM rules,
|
|
10
|
-
> release flow) are in `CONVENTIONS.md` in the repository. That file is **not** published; this one
|
|
11
|
-
> is, so it is what a dependency reader sees.
|
|
12
|
-
|
|
13
|
-
## The three things that most often go wrong
|
|
14
|
-
|
|
15
|
-
1. **A runnable block shows only the result of its *last* statement.** Stacking several independent
|
|
16
|
-
examples in one block means the reader sees one result and the others silently vanish. One
|
|
17
|
-
example per block; several statements only for a preamble (`SET`, `CREATE`, …) that the last
|
|
18
|
-
query needs.
|
|
19
|
-
2. **`show: "html"` / `"iframe"` / `"svg"` need to be told which column holds the
|
|
20
|
-
than one result column you **must** name it: `"field": "<column>"`. Without
|
|
21
|
-
nothing to preview. `"tab_name"` names the column that labels each preview
|
|
22
|
-
tabs read `Row 1`, `Row 2`, …
|
|
23
|
-
3. **Only a block whose info string is JSON with `"type":"duckfn"` becomes runnable.** A bare
|
|
24
|
-
```` ```sql ```` block (or any other metastring) stays a plain, un-runnable code block — no Run
|
|
25
|
-
button, nothing executed.
|
|
26
|
-
|
|
27
|
-
## Install and wire it up
|
|
28
|
-
|
|
29
|
-
See [`README.md`](./README.md) — install, the three `docusaurus.config.ts` plugins, and the one CSS
|
|
30
|
-
import. Everything below assumes that is already done.
|
|
31
|
-
|
|
32
|
-
## Runnable SQL blocks
|
|
33
|
-
|
|
34
|
-
### The shape
|
|
35
|
-
|
|
36
|
-
A fenced block whose info string is a JSON config. The block itself becomes a CodeMirror editor
|
|
37
|
-
with a Run button; nothing executes until the reader clicks it.
|
|
38
|
-
|
|
39
|
-
````md
|
|
40
|
-
```sql {"type":"duckfn"}
|
|
41
|
-
SELECT 40 + 2 AS answer;
|
|
42
|
-
```
|
|
43
|
-
````
|
|
44
|
-
|
|
45
|
-
Works in `.md` and `.mdx` alike — the metastring is rewritten during the build, before either format
|
|
46
|
-
is compiled.
|
|
47
|
-
|
|
48
|
-
### Config reference
|
|
49
|
-
|
|
50
|
-
| Field | Meaning |
|
|
51
|
-
| --- | --- |
|
|
52
|
-
| `type` | `"duckfn"`. Required — this is what makes the block runnable. |
|
|
53
|
-
| `show` | `table` (default), `text`, `html`, `iframe`, `svg`. See *Result renderers*. |
|
|
54
|
-
| `field` | The column holding the markup, for `html` / `iframe` / `svg`. Required when the result has more than one column. |
|
|
55
|
-
| `tab_name` | The column whose value labels each preview tab. Defaults to `Row N`. |
|
|
56
|
-
| `option.width` · `option.height` | CSS lengths for the preview box (`"100%"`, `"640px"`). |
|
|
57
|
-
| `option.sandbox` | Sandbox tokens for the iframe, replacing the default `allow-scripts`. Widen deliberately. |
|
|
58
|
-
| `extensions` | Extra extension names to `LOAD` before this block runs, on top of the site's preloads. |
|
|
59
|
-
| `repository` | Where those extensions come from: `community`, `core`, or a repository URL. |
|
|
60
|
-
| `allowUnsignedExtensions` | Accept an unverifiable signature. Site-wide via the preload config, or per block; the first block to initialise the engine settles it. |
|
|
61
|
-
| `expect` | `ok` (default) or `error`. `error` declares "this block must fail" — see *Testing*. |
|
|
62
|
-
|
|
63
|
-
### Behaviour you have to design around
|
|
64
|
-
|
|
65
|
-
- **The result shown is the last statement's.** A block with `SET …; CREATE …; SELECT …` shows the
|
|
66
|
-
`SELECT`. A block with three independent `SELECT`s shows the third one only.
|
|
67
|
-
- **Default `show`:** a single column with a single row renders as `text`; anything else renders as
|
|
68
|
-
a `table`. Set `show` explicitly when the shape matters.
|
|
69
|
-
- **One DuckDB-Wasm instance per page, one connection per page.** Blocks on the same page share
|
|
70
|
-
state — a table or macro created in one block is visible to the next — and pages are isolated
|
|
71
|
-
from each other. Do not write a block that depends on another *page*.
|
|
72
|
-
- **The site's preloaded extensions are already loaded.** Call into them directly; do not add
|
|
73
|
-
`extensions` for the extension the site documents.
|
|
74
|
-
- **Errors are a result, not a broken block.** A failing statement renders its message in the result
|
|
75
|
-
area and keeps whatever the reader typed.
|
|
76
|
-
- **Every result has a tab strip** (even a plain table), and the fullscreen toggle lives at its right
|
|
77
|
-
end. Table results bring sorting, resizable rows/columns, a right-click menu and header drag.
|
|
78
|
-
|
|
79
|
-
### Result renderers
|
|
80
|
-
|
|
81
|
-
| `show` | What it renders | Needs |
|
|
82
|
-
| --- | --- | --- |
|
|
83
|
-
| `table` | The result grid. | — |
|
|
84
|
-
| `text` | A bare scalar, as one line. | A single column/row result. |
|
|
85
|
-
| `html` / `iframe` | One tab per row; the markup goes into a sandboxed `iframe` (`srcdoc`), with a trailing `Table` tab that is always last. | `field` (unless the result has exactly one column). `tab_name` to label tabs. |
|
|
86
|
-
| `svg` | The markup is spliced **into the page** (one tab per row, trailing `Table` tab). | Same as above. |
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
origin
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
1
|
+
# duckfn-docs-kit — usage guide for agents and site authors
|
|
2
|
+
|
|
3
|
+
This is the **consumer-facing** companion to [`README.md`](./README.md): the README says what to
|
|
4
|
+
import and how to wire it into `docusaurus.config.ts`, this file states the **contracts and the
|
|
5
|
+
traps** — the things that are easy to get subtly wrong when you write a docs page or review one.
|
|
6
|
+
|
|
7
|
+
Read it before writing runnable SQL blocks or configuring preloads.
|
|
8
|
+
|
|
9
|
+
> Developing the kit itself? Its internal conventions (rendering contract, shadow-DOM rules,
|
|
10
|
+
> release flow) are in `CONVENTIONS.md` in the repository. That file is **not** published; this one
|
|
11
|
+
> is, so it is what a dependency reader sees.
|
|
12
|
+
|
|
13
|
+
## The three things that most often go wrong
|
|
14
|
+
|
|
15
|
+
1. **A runnable block shows only the result of its *last* statement.** Stacking several independent
|
|
16
|
+
examples in one block means the reader sees one result and the others silently vanish. One
|
|
17
|
+
example per block; several statements only for a preamble (`SET`, `CREATE`, …) that the last
|
|
18
|
+
query needs.
|
|
19
|
+
2. **`show: "html"` / `"iframe"` / `"svg"` / `"mermaid"` need to be told which column holds the
|
|
20
|
+
markup.** With more than one result column you **must** name it: `"field": "<column>"`. Without
|
|
21
|
+
it the renderer has nothing to preview. `"tab_name"` names the column that labels each preview
|
|
22
|
+
tab, and without it tabs read `Row 1`, `Row 2`, …
|
|
23
|
+
3. **Only a block whose info string is JSON with `"type":"duckfn"` becomes runnable.** A bare
|
|
24
|
+
```` ```sql ```` block (or any other metastring) stays a plain, un-runnable code block — no Run
|
|
25
|
+
button, nothing executed.
|
|
26
|
+
|
|
27
|
+
## Install and wire it up
|
|
28
|
+
|
|
29
|
+
See [`README.md`](./README.md) — install, the three `docusaurus.config.ts` plugins, and the one CSS
|
|
30
|
+
import. Everything below assumes that is already done.
|
|
31
|
+
|
|
32
|
+
## Runnable SQL blocks
|
|
33
|
+
|
|
34
|
+
### The shape
|
|
35
|
+
|
|
36
|
+
A fenced block whose info string is a JSON config. The block itself becomes a CodeMirror editor
|
|
37
|
+
with a Run button; nothing executes until the reader clicks it.
|
|
38
|
+
|
|
39
|
+
````md
|
|
40
|
+
```sql {"type":"duckfn"}
|
|
41
|
+
SELECT 40 + 2 AS answer;
|
|
42
|
+
```
|
|
43
|
+
````
|
|
44
|
+
|
|
45
|
+
Works in `.md` and `.mdx` alike — the metastring is rewritten during the build, before either format
|
|
46
|
+
is compiled.
|
|
47
|
+
|
|
48
|
+
### Config reference
|
|
49
|
+
|
|
50
|
+
| Field | Meaning |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `type` | `"duckfn"`. Required — this is what makes the block runnable. |
|
|
53
|
+
| `show` | `table` (default), `text`, `html`, `iframe`, `svg`, `mermaid`. See *Result renderers*. |
|
|
54
|
+
| `field` | The column holding the markup, for `html` / `iframe` / `svg` / `mermaid`. Required when the result has more than one column. |
|
|
55
|
+
| `tab_name` | The column whose value labels each preview tab. Defaults to `Row N`. |
|
|
56
|
+
| `option.width` · `option.height` | CSS lengths for the preview box (`"100%"`, `"640px"`). |
|
|
57
|
+
| `option.sandbox` | Sandbox tokens for the iframe, replacing the default `allow-scripts`. Widen deliberately. |
|
|
58
|
+
| `extensions` | Extra extension names to `LOAD` before this block runs, on top of the site's preloads. |
|
|
59
|
+
| `repository` | Where those extensions come from: `community`, `core`, or a repository URL. |
|
|
60
|
+
| `allowUnsignedExtensions` | Accept an unverifiable signature. Site-wide via the preload config, or per block; the first block to initialise the engine settles it. |
|
|
61
|
+
| `expect` | `ok` (default) or `error`. `error` declares "this block must fail" — see *Testing*. |
|
|
62
|
+
|
|
63
|
+
### Behaviour you have to design around
|
|
64
|
+
|
|
65
|
+
- **The result shown is the last statement's.** A block with `SET …; CREATE …; SELECT …` shows the
|
|
66
|
+
`SELECT`. A block with three independent `SELECT`s shows the third one only.
|
|
67
|
+
- **Default `show`:** a single column with a single row renders as `text`; anything else renders as
|
|
68
|
+
a `table`. Set `show` explicitly when the shape matters.
|
|
69
|
+
- **One DuckDB-Wasm instance per page, one connection per page.** Blocks on the same page share
|
|
70
|
+
state — a table or macro created in one block is visible to the next — and pages are isolated
|
|
71
|
+
from each other. Do not write a block that depends on another *page*.
|
|
72
|
+
- **The site's preloaded extensions are already loaded.** Call into them directly; do not add
|
|
73
|
+
`extensions` for the extension the site documents.
|
|
74
|
+
- **Errors are a result, not a broken block.** A failing statement renders its message in the result
|
|
75
|
+
area and keeps whatever the reader typed.
|
|
76
|
+
- **Every result has a tab strip** (even a plain table), and the fullscreen toggle lives at its right
|
|
77
|
+
end. Table results bring sorting, resizable rows/columns, a right-click menu and header drag.
|
|
78
|
+
|
|
79
|
+
### Result renderers
|
|
80
|
+
|
|
81
|
+
| `show` | What it renders | Needs |
|
|
82
|
+
| --- | --- | --- |
|
|
83
|
+
| `table` | The result grid. | — |
|
|
84
|
+
| `text` | A bare scalar, as one line. | A single column/row result. |
|
|
85
|
+
| `html` / `iframe` | One tab per row; the markup goes into a sandboxed `iframe` (`srcdoc`), with a trailing `Table` tab that is always last. | `field` (unless the result has exactly one column). `tab_name` to label tabs. |
|
|
86
|
+
| `svg` | The markup is spliced **into the page** (one tab per row, trailing `Table` tab). | Same as above. |
|
|
87
|
+
| `mermaid` | The cell is handed to `<dfk-mermaid>`, so the reader gets a real diagram with zoom, fullscreen, source editing and SVG download. One tab per row, trailing `Table` tab. | Same as above. |
|
|
88
|
+
|
|
89
|
+
Two facts worth knowing before you pick one:
|
|
90
|
+
|
|
91
|
+
- `html` and `iframe` are the *same* renderer. The frame is sandboxed with `allow-scripts` and
|
|
92
|
+
**without** `allow-same-origin`, so a report's JavaScript runs while the frame keeps an opaque
|
|
93
|
+
origin — that is what makes charts work, and it is also why the parent page cannot read
|
|
94
|
+
`iframe.contentDocument` (it is `null` by design).
|
|
95
|
+
- `svg` shares the page, so anything that could execute or navigate — `script`, `foreignObject`,
|
|
96
|
+
`on*` handlers, `javascript:` links — is stripped before insertion.
|
|
97
|
+
|
|
98
|
+
### Examples
|
|
99
|
+
|
|
100
|
+
A table result, and a scalar that degrades to text:
|
|
101
|
+
|
|
102
|
+
````md
|
|
103
|
+
```sql {"type":"duckfn","show":"table"}
|
|
104
|
+
SELECT * FROM range(10) WHERE range > 5;
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```sql {"type":"duckfn"}
|
|
108
|
+
SELECT 1;
|
|
109
|
+
```
|
|
110
|
+
````
|
|
111
|
+
|
|
112
|
+
An HTML (or iframe) report — note `field` and `tab_name`:
|
|
113
|
+
|
|
114
|
+
````md
|
|
115
|
+
```sql {"type":"duckfn","show":"iframe","field":"html","tab_name":"label","option":{"height":"170px"}}
|
|
116
|
+
SELECT * FROM (VALUES
|
|
117
|
+
('Bars', '<!doctype html><body><h4>Quarterly revenue</h4><svg viewBox="0 0 240 80">…</svg></body>')
|
|
118
|
+
) AS t(label, html);
|
|
119
|
+
```
|
|
120
|
+
````
|
|
121
|
+
|
|
122
|
+
An inline SVG, and an extension that is not preloaded:
|
|
123
|
+
|
|
124
|
+
````md
|
|
125
|
+
```sql {"type":"duckfn","show":"svg","option":{"height":"140px"}}
|
|
126
|
+
SELECT '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40"/></svg>';
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```sql {"type":"duckfn","show":"table","extensions":["inet"]}
|
|
130
|
+
SELECT '127.0.0.1'::INET::VARCHAR AS ip;
|
|
131
|
+
```
|
|
132
|
+
````
|
|
133
|
+
|
|
134
|
+
A diagram built by a query (the same element a ```` ```mermaid ```` fence produces):
|
|
135
|
+
|
|
136
|
+
````md
|
|
137
|
+
```sql {"type":"duckfn","show":"mermaid"}
|
|
138
|
+
SELECT 'flowchart LR' || chr(10)
|
|
139
|
+
|| ' A["a SELECT"] --> B["one result cell"]' AS diagram;
|
|
140
|
+
```
|
|
141
|
+
````
|
|
142
|
+
|
|
143
|
+
### Mistakes to check for when reviewing a page
|
|
144
|
+
|
|
145
|
+
- Several independent examples stacked in one block — only the last result is visible. **Split
|
|
146
|
+
them into one block per example.**
|
|
147
|
+
- `show: "html"` / `"iframe"` / `"svg"` / `"mermaid"` with a multi-column result and no `field`.
|
|
148
|
+
- No `tab_name`, so the preview tabs read `Row 1`, `Row 2`, … instead of something meaningful.
|
|
149
|
+
- A bare ```` ```sql ```` block where a runnable one was intended (it renders as a plain listing).
|
|
150
|
+
- Declaring `extensions` for the extension the site already preloads.
|
|
151
|
+
- A block that depends on a table created on a *different* page.
|
|
152
|
+
|
|
153
|
+
## Mermaid diagrams (`remarkMermaid`)
|
|
154
|
+
|
|
155
|
+
````ts
|
|
156
|
+
// docusaurus.config.ts, in the docs preset's `remarkPlugins`
|
|
157
|
+
remarkPlugins: [remarkMermaid],
|
|
158
|
+
````
|
|
159
|
+
|
|
160
|
+
A ```` ```mermaid ```` fence becomes a `<dfk-mermaid>` element that renders the diagram **in the
|
|
161
|
+
browser** (mermaid is a lazy `import()`, so a page with no diagram never downloads it). Do **not**
|
|
162
|
+
also install `@docusaurus/theme-mermaid` or list it in `themes`, and do not set `markdown.mermaid`:
|
|
163
|
+
the kit's element replaces both, and two renderers on one page would fight.
|
|
164
|
+
|
|
165
|
+
What the reader gets, in the element's top-right corner on hover: **reset zoom** (wheel zooms,
|
|
166
|
+
dragging pans once zoomed), **fullscreen**, **edit the source** in a CodeMirror dialog, and
|
|
167
|
+
**download SVG**.
|
|
168
|
+
|
|
169
|
+
- **The file is named after the section it sits in.** `1. Expansion.svg`, not
|
|
170
|
+
`mermaid-diagram.svg`, in a cascade that walks from the most specific source to the most general:
|
|
171
|
+
the diagram's own title (mermaid frontmatter, `---\ntitle: …\n---`) → the nearest heading above
|
|
172
|
+
it → the document title → `mermaid-diagram.svg`. So a diagram is best named by the heading it
|
|
173
|
+
lives under; give it a frontmatter `title:` when the heading is not the name you want. The name
|
|
174
|
+
goes through `filenamify`, so nothing a filesystem chokes on (`:`, `?`, `*`, `|`, …) reaches the
|
|
175
|
+
file.
|
|
176
|
+
- **The diagram is inert until it is zoomed.** At fit the pointer is the browser's: the cursor is
|
|
177
|
+
the normal one (an I-beam over a label), and dragging selects text — the labels are still text,
|
|
178
|
+
and copying one should work. Zooming in is what turns the pointer into a `grab` hand and gives a
|
|
179
|
+
drag to panning; **Reset zoom** hands it back. There is no mode switch to remember.
|
|
180
|
+
|
|
181
|
+
- **The palette is a site choice, not a page one.** The kit's default is the `neo` look with
|
|
182
|
+
`redux-color` / `redux-dark-color`; a site overrides it in its own config, which also keeps the
|
|
183
|
+
kit fork-free for downstream docs sites:
|
|
184
|
+
|
|
185
|
+
````ts
|
|
186
|
+
remarkMermaid({config: {theme: {light: 'neutral', dark: 'dark'}, options: {look: 'classic'}}})
|
|
187
|
+
````
|
|
188
|
+
|
|
189
|
+
`theme` is per colour mode (the element re-renders on a theme switch); `look` has no light/dark
|
|
190
|
+
counterpart and lives in `options`. Mermaid silently ignores a value it does not recognise, so
|
|
191
|
+
check a diagram in a browser — a build proves nothing here.
|
|
192
|
+
- **Diagrams render per page, in the page's own colour mode** — read from `<html data-theme>` (the
|
|
193
|
+
attribute written before first paint), not from a framework hook. That is what keeps a dark-mode
|
|
194
|
+
first load from painting a light diagram and then a dark one.
|
|
195
|
+
- **Labels**: keep them quoted (`A["text"]`), use `<br/>` for a line break, and avoid a bare `#` or
|
|
196
|
+
an unescaped `&`. A syntax error shows up in the page, not in the build.
|
|
197
|
+
- A ```` ```mermaid ```` fence inside a longer fence (documenting it, as here) is *not* turned into
|
|
198
|
+
a diagram — it is text inside the outer code block.
|
|
199
|
+
|
|
200
|
+
## Preloading extensions (the `dfkExtensions` plugin)
|
|
201
|
+
|
|
202
|
+
The site declares an ordered preload list; the kit fetches the release assets at dev/build startup,
|
|
203
|
+
injects the list into every page and loads them — in order — while DuckDB initialises. Blocks can
|
|
204
|
+
then call into those extensions without declaring anything.
|
|
205
|
+
|
|
206
|
+
Three source kinds:
|
|
207
|
+
|
|
208
|
+
| Entry | Meaning |
|
|
209
|
+
| --- | --- |
|
|
210
|
+
| `'json'` | A name: `LOAD json` from the official repository. |
|
|
211
|
+
| `{name: 'h3', repository: 'community'}` | `community`, `core` or a repository URL. On wasm `INSTALL` only records *where* a later `LOAD` fetches from. |
|
|
212
|
+
| `{url: 'duckdb-extensions/x.duckdb_extension.wasm', release: {repository, asset}}` | The site serves the file itself; with `release`, the build fetches that asset from the repository's latest release (cached by sha256 in `<siteDir>/.cache/duckfn-docs-kit/`). |
|
|
213
|
+
|
|
214
|
+
Constraints that bite:
|
|
215
|
+
|
|
216
|
+
- **The file name is a contract**: the text before the first dot is the entry symbol DuckDB looks
|
|
217
|
+
up, so a release asset named `duckfn-wasm_eh.duckdb_extension.wasm` must be served as
|
|
218
|
+
`duckfn.duckdb_extension.wasm` (the `url` decides the file name).
|
|
219
|
+
- **Platforms must match**: a `wasm_eh` extension needs a runtime bundle on the `eh` platform. Pin
|
|
220
|
+
`@duckdb/duckdb-wasm` to the exact version whose bundled DuckDB is ABI-compatible with the
|
|
221
|
+
extension build.
|
|
222
|
+
- **Unsigned third-party extensions need `allowUnsignedExtensions: true`** (the WebAssembly
|
|
223
|
+
equivalent of `duckdb -unsigned`). Community extensions are signed and load without it.
|
|
224
|
+
|
|
225
|
+
## Testing the blocks (`duckfn-sql-verify`)
|
|
226
|
+
|
|
227
|
+
The kit runs every block in a **real browser**, on the same runtime the page uses, so what CI
|
|
228
|
+
checks is what a reader gets:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
duckfn-sql-verify --site . # or: npx duckfn-sql-verify --site .
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
It collects every runnable block (`docs/` plus each `i18n/<locale>/…/current/` by default), runs it
|
|
235
|
+
in DuckDB-Wasm **in a headless browser** (driven with `playwright-core`, launching your system
|
|
236
|
+
Chrome/Edge via `executablePath` — so no browser download) with the site's extension loaded, and
|
|
237
|
+
fails the process when a block does not behave as it declares. It is fully offline: the engine and
|
|
238
|
+
the extension are served from local files. Wire it into `package.json` as
|
|
239
|
+
`"test": "duckfn-sql-verify --site ."`.
|
|
240
|
+
|
|
241
|
+
- **A block that demonstrates a failure must say so**: `{"type":"duckfn","expect":"error"}`. The
|
|
242
|
+
check is two-way — a block that declares `error` and starts succeeding is reported too — and a
|
|
243
|
+
`-- error:` comment in the SQL is *not* read; only the metadata counts.
|
|
244
|
+
- Useful options: `--extension <path|url>`, `--platform eh|mvp`, `--content <dir>` (repeatable),
|
|
245
|
+
`--browser <path>` (the Chrome/Edge executable; otherwise a detected one or `DFK_BROWSER`),
|
|
246
|
+
`--timeout <ms>`, `--report <file>`, `--quiet`. It needs `playwright-core`, which the kit lists
|
|
247
|
+
as a dependency; unlike `playwright` it never downloads a browser.
|
|
248
|
+
- The default extension is the single file under `static/duckdb-extensions/`.
|
|
249
|
+
- **File-system examples stay plain code blocks.** Under DuckDB-Wasm the raw file system is not
|
|
250
|
+
POSIX-faithful: `dfn_file_exists` reads a missing file as "opened" (always `true`), writes/append
|
|
251
|
+
byte order is wrong, and there is no existence primitive in DuckDB's C API to correct it. So keep
|
|
252
|
+
any `COPY … TO` / `output_dir` / file-write demo as a non-runnable block and note the reason.
|
|
253
|
+
|
|
254
|
+
## TOC collapse control (`dfkTocToggle()`)
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
plugins: [dfkTocToggle()],
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Adds a collapse button to the desktop table of contents and remembers the choice in
|
|
261
|
+
`localStorage` (`duckfn:toc-collapsed`). Custom labels come from the plugin's `labels` option,
|
|
262
|
+
keyed by a lower-cased `html-lang` prefix (`{en: {hide, show}, 'zh-hans': {…}}`).
|
|
263
|
+
|
|
264
|
+
## Version placeholder (`remarkVersionPlaceholder`)
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
remarkPlugins: [[remarkVersionPlaceholder, {version: DUCKFN_VERSION}]],
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Replaces `{{DUCKFN_VERSION}}` inside `text`, `inlineCode` and `code` nodes, so a release updates one
|
|
271
|
+
file instead of every page. It only touches that exact placeholder — anything else is left alone.
|
|
272
|
+
|
|
273
|
+
## Home-page components
|
|
274
|
+
|
|
275
|
+
`<dfk-hero>`, `<dfk-features>`, `<dfk-next-steps>` (along with `<dfk-sql>` and `<dfk-mermaid>`,
|
|
276
|
+
which the plugins generate) are registered by the barrel import (`duckfn-docs-kit`). The home
|
|
277
|
+
components are **setter-driven and do not reflect attributes**:
|
|
278
|
+
give them named setters (`setTitle`, `setTagline`, `setFeatures`, …), not markup content. They
|
|
279
|
+
render into shadow roots, inherit `--duckfn-*` / `--ifm-*` CSS variables from the page, and are
|
|
280
|
+
safe to call before the element is connected.
|
|
281
|
+
|
|
282
|
+
## Troubleshooting
|
|
283
|
+
|
|
284
|
+
| Symptom | Likely cause |
|
|
285
|
+
| --- | --- |
|
|
286
|
+
| A code block has no Run button | Its info string is not JSON with `"type":"duckfn"`. |
|
|
287
|
+
| The block runs but nothing appears in the preview | `show: "html"` / `"iframe"` / `"svg"` without `field` on a multi-column result. |
|
|
288
|
+
| The preview tabs are labelled `Row 1`, `Row 2`, … | No `tab_name`. |
|
|
289
|
+
| Clicking Run shows an error like `Table with name … does not exist` | The block depends on something created on another page, or on a statement that is no longer the last one in its block. |
|
|
290
|
+
| `LOAD` fails with a signature error | `allowUnsignedExtensions: true` missing for a third-party asset. |
|
|
291
|
+
| A preloaded extension fails to load | The served file name's pre-dot part does not match the extension's entry symbol, or the platform does not match the runtime bundle. |
|
|
292
|
+
| Only the last of several examples shows a result | That is the contract — split the block. |
|
|
293
|
+
| A ```` ```mermaid ```` fence renders as a plain code block | `remarkMermaid` is not in the docs preset's `remarkPlugins`; and if `@docusaurus/theme-mermaid` is still installed, remove it and `markdown.mermaid`. |
|
|
294
|
+
| A diagram is blank, or shows a message instead | The mermaid source does not parse — the message carries mermaid's own error text. |
|
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# duckfn-docs-kit
|
|
2
2
|
|
|
3
3
|
Shared building blocks for [duckfn](https://github.com/shijianjs/duckfn)-family
|
|
4
|
-
DuckDB extension documentation sites: runnable SQL blocks,
|
|
5
|
-
a TOC collapse control, the home-page web components and
|
|
6
|
-
remark plugin. Each one is a self-contained entry point
|
|
7
|
-
wires into its own config — the alternative is copying
|
|
8
|
-
extension's docs site.
|
|
4
|
+
DuckDB extension documentation sites: runnable SQL blocks, mermaid diagrams,
|
|
5
|
+
extension preloading, a TOC collapse control, the home-page web components and
|
|
6
|
+
the version-placeholder remark plugin. Each one is a self-contained entry point
|
|
7
|
+
that a Docusaurus 3 site wires into its own config — the alternative is copying
|
|
8
|
+
the same glue into every extension's docs site.
|
|
9
9
|
|
|
10
10
|
Plain TypeScript over the native DOM: no React and no UI framework of its own.
|
|
11
11
|
The components are retained-mode classes — they build their DOM once, expose
|
|
@@ -22,9 +22,10 @@ npm install duckfn-docs-kit
|
|
|
22
22
|
|
|
23
23
|
| Import | Runs in | What it provides |
|
|
24
24
|
| --- | --- | --- |
|
|
25
|
-
| `duckfn-docs-kit` | browser |
|
|
25
|
+
| `duckfn-docs-kit` | browser | Custom elements (`<dfk-hero>`, `<dfk-features>`, `<dfk-next-steps>`, `<dfk-sql>`, `<dfk-mermaid>`), `registerDfkElements()` and the value types their setters accept |
|
|
26
26
|
| `duckfn-docs-kit/remark` | Node (build) | `remarkVersionPlaceholder`: replaces `{{DUCKFN_VERSION}}` inside `text` / `inlineCode` / `code` nodes |
|
|
27
27
|
| `duckfn-docs-kit/sql/remark` | Node (build) | `remarkRunnableSql`: turns fenced `sql {"type":"duckfn",…}` blocks into `<dfk-sql>` elements |
|
|
28
|
+
| `duckfn-docs-kit/mermaid/remark` | Node (build) | `remarkMermaid`: turns ```` ```mermaid ```` fences into `<dfk-mermaid>` diagrams |
|
|
28
29
|
| `duckfn-docs-kit/sql/extensions` | Node (build) | `dfkExtensions()` Docusaurus plugin: preloads a site's DuckDB extensions before the first block runs |
|
|
29
30
|
| `duckfn-docs-kit/toc-toggle/plugin` | Node (build) | `dfkTocToggle()` Docusaurus plugin: adds the TOC collapse control |
|
|
30
31
|
| `duckfn-docs-kit/toc-toggle/TocToggle` | browser | The TOC collapse class, for a site that drives it itself |
|
|
@@ -43,6 +44,7 @@ import {dfkExtensions} from 'duckfn-docs-kit/sql/extensions';
|
|
|
43
44
|
import {dfkTocToggle} from 'duckfn-docs-kit/toc-toggle/plugin';
|
|
44
45
|
import {remarkVersionPlaceholder} from 'duckfn-docs-kit/remark';
|
|
45
46
|
import {remarkRunnableSql} from 'duckfn-docs-kit/sql/remark';
|
|
47
|
+
import {remarkMermaid} from 'duckfn-docs-kit/mermaid/remark';
|
|
46
48
|
import {DUCKFN_VERSION} from './duckfn-version';
|
|
47
49
|
|
|
48
50
|
export default {
|
|
@@ -54,6 +56,8 @@ export default {
|
|
|
54
56
|
remarkPlugins: [
|
|
55
57
|
[remarkVersionPlaceholder, {version: DUCKFN_VERSION}],
|
|
56
58
|
remarkRunnableSql,
|
|
59
|
+
// ```mermaid fences become diagrams; no @docusaurus/theme-mermaid.
|
|
60
|
+
remarkMermaid,
|
|
57
61
|
],
|
|
58
62
|
},
|
|
59
63
|
},
|
package/bin/sql-verify.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* The `duckfn-sql-verify` executable.
|
|
4
|
-
*
|
|
5
|
-
* A hand-written wrapper rather than a built entry: Vite's library build emits
|
|
6
|
-
* ESM and does not preserve a shebang, and npm only needs one file with one and
|
|
7
|
-
* an executable bit. `dist/` is built by `prepack`, so the import below always
|
|
8
|
-
* resolves in a published tarball.
|
|
9
|
-
*/
|
|
10
|
-
import {cliMain} from '../dist/sql/verify.js';
|
|
11
|
-
|
|
12
|
-
await cliMain(process.argv.slice(2));
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The `duckfn-sql-verify` executable.
|
|
4
|
+
*
|
|
5
|
+
* A hand-written wrapper rather than a built entry: Vite's library build emits
|
|
6
|
+
* ESM and does not preserve a shebang, and npm only needs one file with one and
|
|
7
|
+
* an executable bit. `dist/` is built by `prepack`, so the import below always
|
|
8
|
+
* resolves in a published tarball.
|
|
9
|
+
*/
|
|
10
|
+
import {cliMain} from '../dist/sql/verify.js';
|
|
11
|
+
|
|
12
|
+
await cliMain(process.argv.slice(2));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A compact icon-only button with a hover/focus tooltip, built once and then
|
|
3
|
+
* mutated. Shared by `<dfk-sql>`'s code-block cluster and `<dfk-mermaid>`'s
|
|
4
|
+
* diagram cluster: both want the same "floating icon row over content" idiom,
|
|
5
|
+
* and neither wants a second implementation of it.
|
|
6
|
+
*
|
|
7
|
+
* The tooltip is also the accessible name — an icon-only control has no text to
|
|
8
|
+
* fall back on. The two class names are written by this module and styled in
|
|
9
|
+
* *each* consumer's shadow-root CSS; that duplication is unavoidable (a shadow
|
|
10
|
+
* boundary stops one sheet from reaching the other tree), so the rules carry the
|
|
11
|
+
* same names and are kept in sync by hand.
|
|
12
|
+
*/
|
|
13
|
+
export declare class IconButton {
|
|
14
|
+
#private;
|
|
15
|
+
readonly root: HTMLButtonElement;
|
|
16
|
+
constructor(icon: string, onClick: () => void);
|
|
17
|
+
setIcon(icon: string): void;
|
|
18
|
+
setLabel(text: string): void;
|
|
19
|
+
/** Marks a toggle as currently on (e.g. the SQL block's wrap toggle). */
|
|
20
|
+
setOn(on: boolean): void;
|
|
21
|
+
setDisabled(disabled: boolean): void;
|
|
22
|
+
}
|