1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
|
# Doc Code Block Verification System
This system automatically extracts and compiles Rust code blocks from docs, ensuring all example code stays usable in CI.
## Config
Specify which Markdown files to verify via [`verified-docs.toml`](https://github.com/mingling-rs/mingling/blob/main/verified-docs.toml) in the project root.
You can also test a single file via command-line arg:
```sh
./run-tools.sh test-all-markdown-code docs/pages/1-getting-started.md
```
```powershell
.\run-tools.ps1 test-all-markdown-code docs/pages/1-getting-started.md
```
## Default Rules
Every verified ` ```rust ` code block gets the following injected automatically at compile time — no need to write them explicitly in the block:
### 1. `#![allow(dead_code)]` and `#![allow(unused)]`
Added at the top of the generated `main.rs` to suppress dead-code warnings from partial code snippets.
### 2. `use mingling::prelude::*;`
If the block already has `use mingling::prelude::*;`, it won't be inserted again.
Otherwise it's inserted automatically (with `#[allow(unused_imports)]`).
### 3. `fn main() {}`
If the block **does not contain** a `fn main` definition, an empty `fn main() {}` is appended,
so the block can compile as a standalone binary project.
### 4. `mingling::macros::gen_program!();`
If the block **does not contain** a `gen_program!()` call,
`mingling::macros::gen_program!();` is appended automatically.
This call is required by the mingling framework.
### 5. Build Cache Dedup — Shared Dep Hash
Code blocks with the same `Features` and `Dependencies` are automatically grouped into the same compile group, sharing one `Cargo.toml` and build artifacts, avoiding redundant compilations.
> [!NOTE]
>
> Hash input (all sorted):
>
> 1. Feature list
> 2. External dep name list
> 3. External dep version list
> 4. `name=version` pairs
>
> Uses FNV-1a 64-bit hash, stable across runs.
## Verification Steps
After the **default rules** are applied, each block goes through:
### 1. Block Extraction
- Only ` ```rust ` fenced code blocks are extracted.
- Empty blocks (no code lines) are skipped.
- Blocks with `// NOT VERIFIED` alone are skipped.
### 2. Temp Project Generation
Each block (or each dedup-hash group) gets its own Cargo project:
```
.temp/doc-test/<hash>/
├── Cargo.toml
└── src/
└── main.rs
```
### 3. Build Verification
Compiled with `cargo build --release`, stderr inherited to the terminal for real-time progress.
- **Build OK** → **PASS**
- **Build FAIL** → **FAIL**, last 20 lines of error captured.
### 4. Report
After all tests, a report is written to `.temp/DOCS-TEST-RESULT.md`, containing:
- Total tests, passed, failed
- Table of results per block (block #, file, line, status)
- Detailed errors for failed blocks
### 5. Exit Code
- Any block fails → non-zero exit code (blocks CI pipeline).
- All pass → zero exit code.
---
## Metadata Tag Rules
At the start of a ` ```rust ` block (before code content), use these comment headers to declare metadata. Headers are parsed in order; everything after them is treated as code:
### `// NOT VERIFIED`
Marks the block **not to be compiled**. Use for illustrative snippets that can't compile on their own.
```rust
// NOT VERIFIED
// This block is illustrative only, won't be compiled
fn placeholder() {}
```
### `// BUILD TIME`
Marks the block as a `build.rs` script instead of `src/main.rs`. The block code is wrapped in `fn main() { }` and written to `build.rs`. A stub `fn main() {}` is generated for `src/main.rs`.
```rust
// BUILD TIME
// Features: ["builds", "pathf"]
analyze_and_build_type_mapping().unwrap();
```
### `// Features: [...]`
Declares the mingling crate features needed by this block, as a JSON string array. These features are written into `Cargo.toml`'s `[dependencies]`.
```rust
// Features: ["full", "serde"]
```
### `// Dependencies:`
Declares external crate deps needed by the block. After `// Dependencies:`, each dep goes on one line: `// crate_name = "version"`.
```rust
// Dependencies:
// serde = "1"
// clap = "4"
```
> [!TIP]
>
> **Special handling**:
>
> For deps named `serde` or `clap` with a plain string version,
>
> `features = ["derive"]` is auto-added.
>
> If the version uses a TOML inline table (e.g. `{ version = "1", features = ["derive"] }`),
>
> it's kept as-is.
---
## `@@@` Lines (Hidden Compilation)
Lines starting with `@@@` are **hidden from the rendered documentation** but still included in compilation.
This is useful when you want to show only the core logic while keeping the block fully compilable:
```rust
// This line is visible in docs
@@@// This line is hidden but still compiled
@@@fn setup() { /* hidden boilerplate */ }
```
### How it works
| Stage | Handling |
| --------------------- | ------------------------------------------------------------------------------------------------ |
| **docsify rendering** | `@@@` lines are stripped before markdown is rendered (via `beforeEach` plugin) |
| **CI verification** | `@@@` prefix is stripped during block parsing, remaining content is treated as regular Rust code |
### Convention
Use `@@@` for:
- `fn main() {}` / `gen_program!()` when the block doesn't need to show them
- Common `use` imports that would distract from the example
- Type definitions (`pack!`, `#[derive]`) that are necessary for compilation but not the focus
- Helper functions that the reader doesn't need to see
> [!TIP]
> `@@@` is the replacement for `// NOT VERIFIED` — instead of marking a block as uncompilable,
> hide the boilerplate and keep everything compiling.
---
## Structure Overview
| Module | Responsibility |
| --------------------------------------------- | ----------------------------------------------------------------------------------- |
| `dev_tools/src/verify.rs` | Block parsing, Cargo.toml/main.rs generation, build exec, hash dedup, report output |
| `dev_tools/src/bin/test-all-markdown-code.rs` | Entry point: read config, collect files, orchestrate tests, aggregate results |
| `verified-docs.toml` | Specifies which doc files to verify |
---
## Full Example
````markdown
```rust
// Features: ["parser"]
// Dependencies:
// serde = "1"
// Example code ...
```
````
The above block compiles equivalently to:
```rust
#![allow(dead_code)]
#![allow(unused)]
#[allow(unused_imports)]
use mingling::prelude::*;
// Example code ...
fn main() {}
mingling::macros::gen_program!();
```
`Cargo.toml` will contain:
```toml
[dependencies]
mingling = { path = "../../mingling", features = ["parser"] }
serde = { version = "1", features = ["derive"] }
```
|