@doccident/doccident 0.0.3 → 0.0.5

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/README.md CHANGED
@@ -1,17 +1,42 @@
1
1
  # doccident
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/doccident.svg)](http://badge.fury.io/js/doccident)
4
+ [![Doccident Tested](https://img.shields.io/badge/doccident-tested-brightgreen.svg)](README.md)
4
5
 
5
6
  **Test the code examples in your Markdown documentation.**
6
7
 
7
8
  ## Overview
8
9
 
9
- As an open source developer, few things are more frustrating for users than encountering broken examples in a README. `doccident` ensures your documentation remains accurate by treating your examples as testable code. It parses your Markdown files, extracts JavaScript and TypeScript code blocks, and executes them in a sandboxed environment to verify they run without errors.
10
+ As an open source developer, few things are more frustrating for users than encountering broken examples in a README. `doccident` ensures your documentation remains accurate by treating your examples as testable code. It parses your Markdown files, extracts code blocks for multiple languages, and executes them in a sandboxed environment to verify they run without errors.
11
+
12
+ ### The "Why"
13
+
14
+ This project was born out of frustration. The author once wrote a massive technical book, only to be haunted by the realization that subtle bugs had crept into the code examples and output listings during the editing process.
15
+
16
+ `doccident` solves this by automating the verification of your documentation. It doesn't just check if your code compiles; it can **execute** your snippets and **verify their output** matches what you claim in your docs. This "living documentation" approach guarantees that your readers always see correct, working code and accurate output.
17
+
18
+ **Supported Languages:**
19
+ * JavaScript (Node.js)
20
+ * TypeScript
21
+ * Python
22
+ * Shell (Bash, Sh, Zsh)
23
+ * Go
24
+ * Rust
25
+ * Fortran
26
+ * COBOL
27
+ * C
28
+ * BASIC
29
+ * Java
30
+ * Perl
31
+ * C#
32
+ * R
33
+ * Pascal
10
34
 
11
35
  > **Note**: `doccident` primarily verifies that your code *runs* without throwing exceptions. While you can add assertions to your examples to test correctness, its main goal is to ensure your documentation examples are valid and runnable.
12
36
 
13
37
  ## Installation
14
38
 
39
+ <!-- skip-example -->
15
40
  ```bash
16
41
  npm install --save-dev @doccident/doccident
17
42
  ```
@@ -20,24 +45,59 @@ npm install --save-dev @doccident/doccident
20
45
 
21
46
  Run `doccident` in your project root. By default, it recursively checks all `.md` and `.markdown` files (excluding `node_modules`).
22
47
 
48
+ <!-- skip-example -->
23
49
  ```bash
24
50
  npx doccident
25
51
  ```
26
52
 
27
53
  You can also target specific files or directories:
28
54
 
55
+ <!-- skip-example -->
29
56
  ```bash
30
57
  npx doccident docs/**/*.md
31
58
  ```
32
59
 
60
+ ### Timeout
61
+
62
+ By default, each code snippet has a 5-minute (300,000ms) timeout to prevent infinite loops or hangs. You can customize this with the `--timeout` flag (in milliseconds):
63
+
64
+ <!-- skip-example -->
65
+ ```bash
66
+ npx doccident --timeout 60000 # 60 second timeout
67
+ ```
68
+
69
+ If a snippet exceeds the timeout, it will fail with an error message indicating the timeout was reached.
70
+
33
71
  ### Language Support & Recipes
34
72
 
35
- `doccident` executes code inside `js`, `javascript`, `es6`, `ts`, or `typescript` fenced code blocks. It automatically transforms modern JavaScript and TypeScript using **esbuild** before execution.
73
+ `doccident` executes code inside fenced code blocks for the following languages:
74
+
75
+ * **JavaScript**: `js`, `javascript`, `es6`
76
+ * **TypeScript**: `ts`, `typescript`
77
+ * **Python**: `py`, `python`
78
+ * **Shell**: `sh`, `bash`, `zsh`, `shell`
79
+ * **Go**: `go`
80
+ * **Rust**: `rust`, `rs`
81
+ * **Fortran**: `fortran`, `f90`, `f95`
82
+ * **COBOL**: `cobol`, `cob`
83
+ * **C**: `c`
84
+ * **BASIC**: `basic`
85
+ * **Java**: `java`
86
+ * **Perl**: `perl`, `pl`
87
+ * **C#**: `csharp`, `cs`
88
+ * **R**: `r`
89
+ * **Pascal**: `pascal`, `pas`
90
+ * **Text/Output**: `text`, `txt`, `output` (for output verification)
91
+
92
+ It automatically transforms modern JavaScript and TypeScript using **esbuild** before execution.
36
93
 
37
94
  #### JavaScript
38
95
 
39
96
  Use `js`, `javascript`, or `es6` for JavaScript examples.
40
97
 
98
+ **Execution Model:**
99
+ Runs directly in a Node.js `vm` sandbox.
100
+
41
101
  **Recipe:**
42
102
 
43
103
  1. Use `js` fenced code blocks.
@@ -53,6 +113,9 @@ Use `js`, `javascript`, or `es6` for JavaScript examples.
53
113
 
54
114
  Use `ts` or `typescript` for TypeScript examples.
55
115
 
116
+ **Execution Model:**
117
+ Transpiled via `esbuild`, then runs in a Node.js `vm` sandbox.
118
+
56
119
  **Recipe:**
57
120
 
58
121
  1. Use `ts` fenced code blocks.
@@ -69,6 +132,356 @@ Use `ts` or `typescript` for TypeScript examples.
69
132
  console.log(user.name);
70
133
  ```
71
134
 
135
+ #### Python
136
+
137
+ Use `py` or `python` for Python examples.
138
+
139
+ **Prerequisites:**
140
+ * `python3` must be installed and available in your system path.
141
+ * **macOS**: `brew install python`
142
+ * **Ubuntu/Debian**: `sudo apt-get install python3`
143
+
144
+ **Execution Model:**
145
+ Spawns a `python3` subprocess with the code piped to stdin.
146
+
147
+ **Recipe:**
148
+
149
+ 1. Use `python` fenced code blocks.
150
+ 2. Standard library imports work out of the box.
151
+ 3. State can be shared between blocks using `<!-- share-code-between-examples -->`.
152
+
153
+ ```python
154
+ import json
155
+ data = {"key": "value"}
156
+ assert json.loads('{"key": "value"}') == data
157
+ ```
158
+
159
+ #### Shell Scripts
160
+
161
+ Use `sh`, `bash`, `zsh` or `shell` (defaults to bash) for shell examples.
162
+
163
+ **Prerequisites:**
164
+ * The specified shell (`bash`, `sh`, or `zsh`) must be available in your system path.
165
+
166
+ **Execution Model:**
167
+ Spawns a subprocess using the specified shell, with the code piped to stdin.
168
+
169
+ **Recipe:**
170
+
171
+ 1. Use specific shell tags like `bash` or `zsh` if your script relies on shell-specific syntax.
172
+ 2. Use `sh` for POSIX-compliant scripts.
173
+ 3. State (variables) can be shared between blocks using `<!-- share-code-between-examples -->`.
174
+
175
+ ```bash
176
+ export MY_VAR="hello"
177
+ ```
178
+
179
+ ```bash
180
+ if [ "$MY_VAR" != "hello" ]; then exit 1; fi
181
+ ```
182
+
183
+ #### Go
184
+
185
+ Use `go` for Go examples.
186
+
187
+ **Prerequisites:**
188
+ * `go` must be installed and available in your system path.
189
+ * **macOS**: `brew install go`
190
+ * **Ubuntu/Debian**: `sudo apt-get install golang-go`
191
+
192
+ **Execution Model:**
193
+ Writes code to a temporary file and executes it via `go run`.
194
+
195
+ **Recipe:**
196
+
197
+ 1. Use `go` fenced code blocks.
198
+ 2. You can provide a full program (including `package main`) OR a simple snippet.
199
+ 3. Simple snippets (without `package main`) are automatically wrapped in a `main` function and include `import "fmt"`.
200
+ 4. **Note**: `<!-- share-code-between-examples -->` is supported for Go snippets (auto-wrapped). Declarations (`func`, `type`, `import`) are extracted to top-level.
201
+
202
+ **Simple Snippet:**
203
+ <!-- skip-example -->
204
+ ```go
205
+ fmt.Println("Hello Go")
206
+ ```
207
+
208
+ #### Rust
209
+
210
+ Use `rust` or `rs` for Rust examples.
211
+
212
+ **Prerequisites:**
213
+ * `rustc` (Rust compiler) must be installed and available in your system path.
214
+ * **macOS**: `brew install rust`
215
+ * **Ubuntu/Debian**: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh` or `sudo apt-get install rustc`
216
+
217
+ **Execution Model:**
218
+ Compiles the code using `rustc` into a temporary binary, then executes the binary.
219
+
220
+ **Recipe:**
221
+
222
+ 1. Use `rust` fenced code blocks.
223
+ 2. You can provide a full program (including `fn main()`) OR a simple snippet.
224
+ 3. Simple snippets (without `fn main`) are automatically wrapped in a `main` function.
225
+ 4. **Note**: `<!-- share-code-between-examples -->` is supported for Rust. Attributes like `#![...]` and `extern crate` are hoisted to the crate root. Other code is wrapped in `fn main()`.
226
+
227
+ **Simple Snippet:**
228
+ <!-- skip-example -->
229
+ ```rust
230
+ println!("Hello Rust");
231
+ let x = 5;
232
+ assert_eq!(x, 5);
233
+ ```
234
+
235
+ #### Fortran
236
+
237
+ Use `fortran`, `f90`, or `f95` for Fortran examples.
238
+
239
+ **Prerequisites:**
240
+ * `gfortran` must be installed and available in your system path.
241
+ * **macOS**: `brew install gcc` (includes gfortran)
242
+ * **Ubuntu/Debian**: `sudo apt-get install gfortran`
243
+
244
+ **Execution Model:**
245
+ Compiles the code using `gfortran` into a temporary binary, then executes the binary.
246
+
247
+ **Recipe:**
248
+
249
+ 1. Use `fortran` fenced code blocks.
250
+ 2. You can provide a full program (starting with `program name`) OR a simple snippet.
251
+ 3. Simple snippets are automatically wrapped in a `program main ... end program main` block.
252
+ 4. **Note**: `<!-- share-code-between-examples -->` is supported for Fortran. Modules are extracted to the top level; `use` statements are moved to the top of `program main`.
253
+
254
+ **Simple Snippet:**
255
+ <!-- skip-example -->
256
+ ```fortran
257
+ print *, "Hello Fortran"
258
+ ```
259
+
260
+ #### COBOL
261
+
262
+ Use `cobol` or `cob` for COBOL examples.
263
+
264
+ **Prerequisites:**
265
+ * `cobc` (GnuCOBOL) must be installed and available in your system path.
266
+ * **macOS**: `brew install gnucobol`
267
+ * **Ubuntu/Debian**: `sudo apt-get install gnucobol`
268
+
269
+ **Execution Model:**
270
+ Compiles the code using `cobc -x -free` into a temporary executable, then runs it.
271
+
272
+ **Recipe:**
273
+
274
+ 1. Use `cobol` fenced code blocks.
275
+ 2. Provide a full COBOL program (including `IDENTIFICATION DIVISION`).
276
+ 3. The compiler is run in free-format mode (`-free`).
277
+ 4. **Note**: `<!-- share-code-between-examples -->` is **not** supported for COBOL.
278
+
279
+ <!-- skip-example -->
280
+ ```cobol
281
+ IDENTIFICATION DIVISION.
282
+ PROGRAM-ID. HELLO.
283
+ PROCEDURE DIVISION.
284
+ DISPLAY 'Hello COBOL'.
285
+ STOP RUN.
286
+ ```
287
+
288
+ #### C
289
+
290
+ Use `c` for C examples.
291
+
292
+ **Prerequisites:**
293
+ * `gcc` must be installed and available in your system path.
294
+ * **macOS**: `xcode-select --install` or `brew install gcc`
295
+ * **Ubuntu/Debian**: `sudo apt-get install build-essential`
296
+
297
+ **Execution Model:**
298
+ Compiles the code using `gcc` into a temporary binary, then executes the binary.
299
+
300
+ **Recipe:**
301
+
302
+ 1. Use `c` fenced code blocks.
303
+ 2. You can provide a full program (including `main()`) OR a simple snippet.
304
+ 3. Simple snippets are automatically wrapped in a `main` function and include `stdio.h`.
305
+ 4. **Note**: `<!-- share-code-between-examples -->` is supported for C. Includes and definitions (`struct`, `func`) are hoisted; statements are placed in `main()`.
306
+
307
+ **Simple Snippet:**
308
+ ```c
309
+ printf("Hello C\n");
310
+ ```
311
+
312
+ #### BASIC
313
+
314
+ Use `basic` for BASIC examples.
315
+
316
+ **Prerequisites:**
317
+ * `cbmbasic` must be installed and available in your system path.
318
+ * **macOS**: `brew install cbmbasic`
319
+ * **Ubuntu/Debian**: Build from source (see `test.yml` for example).
320
+
321
+ **Execution Model:**
322
+ Spawns a `cbmbasic` subprocess with the code piped to stdin.
323
+
324
+ **Recipe:**
325
+
326
+ 1. Use `basic` fenced code blocks.
327
+ 2. Write standard Commodore BASIC V2 code.
328
+ 3. State can be shared between blocks using `<!-- share-code-between-examples -->`.
329
+
330
+ <!-- skip-example -->
331
+ ```basic
332
+ 10 PRINT "HELLO BASIC"
333
+ 20 END
334
+ ```
335
+
336
+ #### Java
337
+
338
+ Use `java` for Java examples.
339
+
340
+ **Prerequisites:**
341
+ * `javac` and `java` must be installed and available in your system path.
342
+ * **macOS**: `brew install openjdk`
343
+ * **Ubuntu/Debian**: `sudo apt-get install default-jdk`
344
+
345
+ **Execution Model:**
346
+ Compiles the code using `javac` into a temporary class file in a unique directory, then executes it with `java`.
347
+
348
+ **Recipe:**
349
+
350
+ 1. Use `java` fenced code blocks.
351
+ 2. You can provide a full class (e.g. `public class MyClass { ... }`) OR a simple snippet.
352
+ 3. Simple snippets are automatically wrapped in a `public class Main { public static void main(String[] args) { ... } }`.
353
+ 4. **Note**: `<!-- share-code-between-examples -->` is **not** supported for Java.
354
+
355
+ **Simple Snippet:**
356
+ <!-- skip-example -->
357
+ ```java
358
+ System.out.println("Hello Java");
359
+ ```
360
+
361
+ **Full Class:**
362
+ <!-- skip-example -->
363
+ ```java
364
+ public class Greeting {
365
+ public static void main(String[] args) {
366
+ System.out.println("Hello from Greeting class");
367
+ }
368
+ }
369
+ ```
370
+
371
+ #### Perl
372
+
373
+ Use `perl` or `pl` for Perl examples.
374
+
375
+ **Prerequisites:**
376
+ * `perl` must be installed and available in your system path.
377
+ * **macOS**: Pre-installed or `brew install perl`
378
+ * **Ubuntu/Debian**: Pre-installed or `sudo apt-get install perl`
379
+
380
+ **Execution Model:**
381
+ Spawns a `perl` subprocess with the code piped to stdin.
382
+
383
+ **Recipe:**
384
+
385
+ 1. Use `perl` fenced code blocks.
386
+ 2. Standard library imports work out of the box.
387
+ 3. State can be shared between blocks using `<!-- share-code-between-examples -->`.
388
+
389
+ ```perl
390
+ print "Hello Perl\n";
391
+ ```
392
+
393
+ #### C#
394
+
395
+ Use `csharp` or `cs` for C# examples.
396
+
397
+ **Prerequisites:**
398
+ * `mono` (includes `mcs` compiler) must be installed and available in your system path.
399
+ * **macOS**: `brew install mono`
400
+ * **Ubuntu/Debian**: `sudo apt-get install mono-devel`
401
+
402
+ **Execution Model:**
403
+ Compiles the code using `mcs` into a temporary executable, then runs it with `mono`.
404
+
405
+ **Recipe:**
406
+
407
+ 1. Use `csharp` fenced code blocks.
408
+ 2. You can provide a full class (e.g. `public class Program { ... }`) OR a simple snippet.
409
+ 3. Simple snippets are automatically wrapped in a `public class Program { public static void Main(string[] args) { ... } }` and include `using System;`.
410
+ 4. **Note**: `<!-- share-code-between-examples -->` is **not** supported for C#.
411
+
412
+ **Simple Snippet:**
413
+ <!-- skip-example -->
414
+ ```csharp
415
+ Console.WriteLine("Hello C#");
416
+ ```
417
+
418
+ **Full Class:**
419
+ <!-- skip-example -->
420
+ ```csharp
421
+ using System;
422
+ public class Test {
423
+ public static void Main(string[] args) {
424
+ Console.WriteLine("Hello from Test class");
425
+ }
426
+ }
427
+ ```
428
+
429
+ #### R
430
+
431
+ Use `r` for R examples.
432
+
433
+ **Prerequisites:**
434
+ * `Rscript` must be installed and available in your system path.
435
+ * **macOS**: `brew install r`
436
+ * **Ubuntu/Debian**: `sudo apt-get install r-base`
437
+
438
+ **Execution Model:**
439
+ Spawns an `Rscript` subprocess with the code piped to stdin.
440
+
441
+ **Recipe:**
442
+
443
+ 1. Use `r` fenced code blocks.
444
+ 2. Standard R syntax works out of the box.
445
+ 3. State can be shared between blocks using `<!-- share-code-between-examples -->`.
446
+
447
+ ```r
448
+ print("Hello R")
449
+ ```
450
+
451
+ #### Pascal
452
+
453
+ Use `pascal` or `pas` for Pascal examples.
454
+
455
+ **Prerequisites:**
456
+ * `fpc` (Free Pascal Compiler) must be installed and available in your system path.
457
+ * **macOS**: `brew install fpc`
458
+ * **Ubuntu/Debian**: `sudo apt-get install fpc`
459
+
460
+ **Execution Model:**
461
+ Compiles the code using `fpc` into a temporary executable, then runs it.
462
+
463
+ **Recipe:**
464
+
465
+ 1. Use `pascal` fenced code blocks.
466
+ 2. You can provide a full program (including `program Name;`) OR a simple snippet.
467
+ 3. Simple snippets are automatically wrapped in a `program TestProgram; begin ... end.` block.
468
+ 4. **Note**: `<!-- share-code-between-examples -->` is **not** supported for Pascal.
469
+
470
+ **Simple Snippet:**
471
+ <!-- skip-example -->
472
+ ```pascal
473
+ writeln('Hello Pascal');
474
+ ```
475
+
476
+ **Full Program:**
477
+ <!-- skip-example -->
478
+ ```pascal
479
+ program Hello;
480
+ begin
481
+ writeln('Hello from Pascal program');
482
+ end.
483
+ ```
484
+
72
485
  ### Skipping Examples
73
486
 
74
487
  To skip a specific code block, add the `<!-- skip-example -->` comment immediately before it:
@@ -79,6 +492,110 @@ To skip a specific code block, add the `<!-- skip-example -->` comment immediate
79
492
  fetch('https://example.com');
80
493
  ```
81
494
 
495
+ ### Sharing Code Between Examples
496
+
497
+ By default, each code block is executed in isolation. To share state (variables, functions, classes) between multiple code blocks in the same file, add the `<!-- share-code-between-examples -->` comment. This applies to the entire file.
498
+
499
+ > **Note**: This feature is currently supported for JavaScript, TypeScript, Python, Shell, BASIC, Perl, R, Go, Rust, Fortran, and C, but **not** compiled languages like COBOL, Java, C#, and Pascal.
500
+
501
+ <!-- share-code-between-examples -->
502
+
503
+ ```python
504
+ x = 10
505
+ ```
506
+
507
+ ```python
508
+ # x is still available here
509
+ assert x == 10
510
+ ```
511
+
512
+ ### Configuration Comments
513
+
514
+ You can configure execution behavior for specific snippets using comments immediately preceding the code block.
515
+
516
+ **Arguments:** Pass arguments to the compiler or interpreter.
517
+
518
+ <!-- args: -v -->
519
+ ```python
520
+ import sys
521
+ print("Running with verbose output")
522
+ ```
523
+
524
+ **Environment Variables:** Set environment variables for the execution.
525
+
526
+ <!-- env: API_KEY=secret123 MODE=test -->
527
+ ```bash
528
+ echo "Key: $API_KEY"
529
+ ```
530
+
531
+ ### Output Verification
532
+
533
+ You can verify that a code snippet produces specific output by assigning it an ID and then referencing that ID in a subsequent block.
534
+
535
+ 1. Assign an ID to the code snippet using `<!-- id: my-snippet-name -->`.
536
+ 2. Create an output block (usually `text` or `json`) and reference the ID using `<!-- output: my-snippet-name -->`.
537
+
538
+ `doccident` will execute the first snippet, capture its stdout, and verify that it matches the content of the output block.
539
+
540
+ **Example:**
541
+
542
+ <!-- id: hello-world -->
543
+ ```js
544
+ console.log("Hello Output");
545
+ ```
546
+
547
+ <!-- output: hello-world -->
548
+ ```text
549
+ Hello Output
550
+ ```
551
+
552
+ This is useful for ensuring your documentation's "Output:" sections stay in sync with the actual code behavior.
553
+
554
+ ### Output Matching Modes
555
+
556
+ When verifying output, you can optionally specify a matching mode to handle whitespace or dynamic content.
557
+
558
+ * `exact` (default): Exact string match (trailing whitespace is trimmed).
559
+ * `ignore-whitespace`: Collapses all whitespace sequences to a single space and trims ends before comparing.
560
+ * `match:regex`: Treats the output block content as a regular expression.
561
+
562
+ **Examples:**
563
+
564
+ **Ignore Whitespace:**
565
+
566
+ <!-- id: fuzzy-output -->
567
+ ```js
568
+ console.log(" A B \n C ");
569
+ ```
570
+
571
+ <!-- output: fuzzy-output ignore-whitespace -->
572
+ ```text
573
+ A B C
574
+ ```
575
+
576
+ **Regex Matching:**
577
+
578
+ <!-- id: dynamic-output -->
579
+ ```js
580
+ console.log("Timestamp: " + Date.now());
581
+ ```
582
+
583
+ <!-- output: dynamic-output match:regex -->
584
+ ```text
585
+ ^Timestamp: \d+$
586
+ ```
587
+
588
+ ### Updating Output (Snapshots)
589
+
590
+ If you want `doccident` to automatically update your output blocks with the actual output from execution, run with the `--update-output` flag.
591
+
592
+ <!-- skip-example -->
593
+ ```bash
594
+ npx doccident --update-output
595
+ ```
596
+
597
+ This will replace the content of any `<!-- output: ... -->` block with the latest captured output from the corresponding ID. This is extremely useful when writing documentation: you can write the code example, add a placeholder output block, and let `doccident` fill it in for you.
598
+
82
599
  ## Configuration
83
600
 
84
601
  Create a `.doccident-setup.js` file in your project root to configure the test environment.
@@ -87,6 +604,7 @@ Create a `.doccident-setup.js` file in your project root to configure the test e
87
604
 
88
605
  If your examples use external libraries, provide them here. This allows your examples to `require` modules just like users would:
89
606
 
607
+ <!-- skip-example -->
90
608
  ```javascript
91
609
  // .doccident-setup.js
92
610
  module.exports = {
@@ -94,7 +612,7 @@ module.exports = {
94
612
  // Make 'my-library' available when examples call require('my-library')
95
613
  'my-library': require('./index.js'),
96
614
  'lodash': require('lodash')
97
- }
615
+ }
98
616
  };
99
617
  ```
100
618
 
@@ -102,6 +620,7 @@ module.exports = {
102
620
 
103
621
  Define global variables available to all snippets:
104
622
 
623
+ <!-- skip-example -->
105
624
  ```javascript
106
625
  module.exports = {
107
626
  globals: {
@@ -127,13 +646,14 @@ module.exports = {
127
646
  * Reads Markdown content line-by-line.
128
647
  * Uses a robust state machine to identify code fences and control comments (like `skip-example`).
129
648
  * Extracts valid snippets into structured objects containing code, file paths, and line numbers.
130
- * **TypeScript Support**: Now recognizes `ts` and `typescript` blocks in addition to JS.
649
+ * **Multi-Language Support**: Recognizes `js`, `ts`, `python`, `shell`, `go`, `rust`, `fortran`, `cobol`, `c`, `basic`, `java`, `perl`, `csharp`, `r`, and `pascal` blocks.
131
650
 
132
651
  2. **Test Runner (`src/doctest.ts`)**
133
652
  * The orchestrator of the application.
134
653
  * Iterates through parsed snippets and manages the execution lifecycle.
135
- * **Sandboxing**: Uses Node.js's `vm` module (`runInNewContext`) to execute code in isolation. This prevents examples from polluting the global scope of the runner itself, while allowing controlled injection of dependencies via the configuration.
136
- * **Transformation**: Uses **esbuild** to compile modern JavaScript and TypeScript code down to a compatible format before execution. This ensures that modern syntax and type annotations run correctly in all environments, and is significantly faster than the previous Babel implementation.
654
+ * **Sandboxing**: Uses Node.js's `vm` module (`runInNewContext`) to execute JS/TS code in isolation.
655
+ * **Subprocess Execution**: Spawns `python3`, `go`, `rustc`, `gfortran`, `cobc`, `gcc`, `cbmbasic`, `javac`/`java`, `perl`, `mcs`/`mono`, `Rscript`, `fpc`, or shell subprocesses for non-JS languages.
656
+ * **Transformation**: Uses **esbuild** to compile modern JavaScript and TypeScript code down to a compatible format before execution.
137
657
 
138
658
  3. **Reporter (`src/reporter.ts`)**
139
659
  * Collects execution results (pass, fail, skip).
@@ -145,3 +665,33 @@ module.exports = {
145
665
  * Utility functions (`src/utils.ts`) provide common helpers.
146
666
 
147
667
  This separation of concerns allows `doccident` to be easily extended—for example, by adding new parsers for different documentation formats or custom reporters for CI environments.
668
+
669
+ ## License & History
670
+
671
+ This project is licensed under the Apache License, Version 2.0.
672
+
673
+ Copyright (c) 2025 Billaud Cipher
674
+
675
+ Licensed under the Apache License, Version 2.0 (the "License");
676
+ you may not use this file except in compliance with the License.
677
+ You may obtain a copy of the License at
678
+
679
+ http://www.apache.org/licenses/LICENSE-2.0
680
+
681
+ Unless required by applicable law or agreed to in writing, software
682
+ distributed under the License is distributed on an "AS IS" BASIS,
683
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
684
+ See the License for the specific language governing permissions and
685
+ limitations under the License.
686
+
687
+ ---
688
+
689
+ **Note**: This project was originally forked from [markdown-doctest](https://github.com/nick-johnstone/markdown-doctest) by Nick Johnstone. While the original inspiration and some core concepts remain, the **entire codebase has been replaced** and significantly expanded by Billaud Cipher to support a wide range of compiled and interpreted languages, shared state mechanisms, and output verification. All subsequent additions and modifications are covered by the Apache 2.0 Software License.
690
+
691
+ ## Agentic AI Guide
692
+
693
+ This repository contains a dedicated guide for AI agents to understand how to use `doccident`. If you are an AI model tasked with maintaining this project or using it to verify documentation, please refer to:
694
+
695
+ [**doccident/guide/index.md**](./guide/index.md)
696
+
697
+ This directory contains instructions on capabilities, verification workflows, and configuration specifically structured for machine consumption.
package/bin/cmd.js CHANGED
@@ -22,7 +22,8 @@ const config = {
22
22
  require: {},
23
23
  globals: {},
24
24
  ignore: [],
25
- testOutput: false
25
+ testOutput: false,
26
+ timeout: 300000 // Default 5 minutes
26
27
  };
27
28
 
28
29
  // Setup commander
@@ -34,6 +35,8 @@ program
34
35
  .helpOption('-h, --help', 'output usage informations')
35
36
  .option('-c, --config <path>', 'custom config location', path.join(process.cwd(), '/.doccident-setup.js'))
36
37
  .option('--test-output', 'output the test results to the console')
38
+ .option('--update-output', 'update the output blocks in markdown files')
39
+ .option('--timeout <ms>', 'timeout for each snippet execution in milliseconds', '300000')
37
40
  .parse(process.argv);
38
41
 
39
42
  const options = program.opts();
@@ -57,6 +60,14 @@ const options = program.opts();
57
60
  if (options.testOutput) {
58
61
  config.testOutput = true;
59
62
  }
63
+
64
+ if (options.updateOutput) {
65
+ config.updateOutput = true;
66
+ }
67
+
68
+ if (options.timeout) {
69
+ config.timeout = parseInt(options.timeout, 10);
70
+ }
60
71
 
61
72
  // Resolve files
62
73
  try {