@doccident/doccident 0.0.2 → 0.0.4
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 +315 -123
- package/bin/cmd.js +25 -24
- package/dist/doctest.js +89 -102
- package/dist/languages/c.js +58 -0
- package/dist/languages/cobol.js +50 -0
- package/dist/languages/fortran.js +56 -0
- package/dist/languages/go.js +45 -0
- package/dist/languages/interface.js +2 -0
- package/dist/languages/javascript.js +24 -0
- package/dist/languages/python.js +31 -0
- package/dist/languages/rust.js +56 -0
- package/dist/languages/shell.js +37 -0
- package/dist/parse-code-snippets-from-markdown.js +53 -30
- package/dist/reporter.js +78 -0
- package/dist/types.js +2 -0
- package/dist/utils.js +6 -0
- package/package.json +12 -18
package/README.md
CHANGED
|
@@ -1,179 +1,371 @@
|
|
|
1
|
-
|
|
2
|
-
[](https://travis-ci.org/Widdershin/doccident)
|
|
3
|
-
[](https://greenkeeper.io/)
|
|
1
|
+
# doccident
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
[](http://badge.fury.io/js/doccident)
|
|
4
|
+
[](README.md)
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
**Test the code examples in your Markdown documentation.**
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
## Overview
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
---
|
|
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.
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
**Supported Languages:**
|
|
13
|
+
* JavaScript (Node.js)
|
|
14
|
+
* TypeScript
|
|
15
|
+
* Python
|
|
16
|
+
* Shell (Bash, Sh, Zsh)
|
|
17
|
+
* Go
|
|
18
|
+
* Rust
|
|
19
|
+
* Fortran
|
|
20
|
+
* COBOL
|
|
21
|
+
* C
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
Just `npm install @doccident/doccident` and run `doccident`. It will run all of the Javascript code examples tucked away in your markdown, and let you know if any blow up.
|
|
23
|
+
> **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.
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
---
|
|
25
|
+
## Installation
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
<!-- skip-example -->
|
|
28
|
+
```bash
|
|
29
|
+
npm install --save-dev @doccident/doccident
|
|
30
|
+
```
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
var a = 5;
|
|
32
|
+
## Usage
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
Run `doccident` in your project root. By default, it recursively checks all `.md` and `.markdown` files (excluding `node_modules`).
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
<!-- skip-example -->
|
|
37
|
+
```bash
|
|
38
|
+
npx doccident
|
|
31
39
|
```
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
You can also target specific files or directories:
|
|
34
42
|
|
|
43
|
+
<!-- skip-example -->
|
|
35
44
|
```bash
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
npx doccident docs/**/*.md
|
|
46
|
+
```
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
evalmachine.<anonymous>:7
|
|
41
|
-
console.log(a + c);
|
|
42
|
-
^
|
|
48
|
+
### Language Support & Recipes
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
`doccident` executes code inside fenced code blocks for the following languages:
|
|
51
|
+
|
|
52
|
+
* **JavaScript**: `js`, `javascript`, `es6`
|
|
53
|
+
* **TypeScript**: `ts`, `typescript`
|
|
54
|
+
* **Python**: `py`, `python`
|
|
55
|
+
* **Shell**: `sh`, `bash`, `zsh`, `shell`
|
|
56
|
+
* **Go**: `go`
|
|
57
|
+
* **Rust**: `rust`, `rs`
|
|
58
|
+
* **Fortran**: `fortran`, `f90`, `f95`
|
|
59
|
+
* **COBOL**: `cobol`, `cob`
|
|
60
|
+
* **C**: `c`
|
|
46
61
|
|
|
47
|
-
|
|
62
|
+
It automatically transforms modern JavaScript and TypeScript using **esbuild** before execution.
|
|
48
63
|
|
|
49
|
-
|
|
64
|
+
#### JavaScript
|
|
50
65
|
|
|
51
|
-
|
|
66
|
+
Use `js`, `javascript`, or `es6` for JavaScript examples.
|
|
52
67
|
|
|
53
|
-
|
|
68
|
+
**Execution Model:**
|
|
69
|
+
Runs directly in a Node.js `vm` sandbox.
|
|
54
70
|
|
|
55
|
-
|
|
56
|
-
---
|
|
71
|
+
**Recipe:**
|
|
57
72
|
|
|
58
|
-
|
|
73
|
+
1. Use `js` fenced code blocks.
|
|
74
|
+
2. Write standard JavaScript (ES6+ supported).
|
|
75
|
+
3. Use `require` to load dependencies defined in your configuration.
|
|
59
76
|
|
|
60
77
|
```js
|
|
61
|
-
|
|
78
|
+
const { sum } = require('./math-utils');
|
|
79
|
+
const result = sum(1, 2);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### TypeScript
|
|
83
|
+
|
|
84
|
+
Use `ts` or `typescript` for TypeScript examples.
|
|
85
|
+
|
|
86
|
+
**Execution Model:**
|
|
87
|
+
Transpiled via `esbuild`, then runs in a Node.js `vm` sandbox.
|
|
88
|
+
|
|
89
|
+
**Recipe:**
|
|
90
|
+
|
|
91
|
+
1. Use `ts` fenced code blocks.
|
|
92
|
+
2. Include type annotations to demonstrate correct usage.
|
|
93
|
+
3. `doccident` strips types during execution, so your examples serve as both documentation and functional tests.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
interface User {
|
|
97
|
+
id: number;
|
|
98
|
+
name: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const user: User = { id: 1, name: 'Doccident' };
|
|
102
|
+
console.log(user.name);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### Python
|
|
106
|
+
|
|
107
|
+
Use `py` or `python` for Python examples.
|
|
108
|
+
|
|
109
|
+
**Prerequisites:**
|
|
110
|
+
* `python3` must be installed and available in your system path.
|
|
111
|
+
* **macOS**: `brew install python`
|
|
112
|
+
* **Ubuntu/Debian**: `sudo apt-get install python3`
|
|
113
|
+
|
|
114
|
+
**Execution Model:**
|
|
115
|
+
Spawns a `python3` subprocess with the code piped to stdin.
|
|
116
|
+
|
|
117
|
+
**Recipe:**
|
|
118
|
+
|
|
119
|
+
1. Use `python` fenced code blocks.
|
|
120
|
+
2. Standard library imports work out of the box.
|
|
121
|
+
3. State can be shared between blocks using `<!-- share-code-between-examples -->`.
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
import json
|
|
125
|
+
data = {"key": "value"}
|
|
126
|
+
assert json.loads('{"key": "value"}') == data
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Shell Scripts
|
|
130
|
+
|
|
131
|
+
Use `sh`, `bash`, `zsh` or `shell` (defaults to bash) for shell examples.
|
|
132
|
+
|
|
133
|
+
**Prerequisites:**
|
|
134
|
+
* The specified shell (`bash`, `sh`, or `zsh`) must be available in your system path.
|
|
135
|
+
|
|
136
|
+
**Execution Model:**
|
|
137
|
+
Spawns a subprocess using the specified shell, with the code piped to stdin.
|
|
138
|
+
|
|
139
|
+
**Recipe:**
|
|
140
|
+
|
|
141
|
+
1. Use specific shell tags like `bash` or `zsh` if your script relies on shell-specific syntax.
|
|
142
|
+
2. Use `sh` for POSIX-compliant scripts.
|
|
143
|
+
3. State (variables) can be shared between blocks using `<!-- share-code-between-examples -->`.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
export MY_VAR="hello"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
if [ "$MY_VAR" != "hello" ]; then exit 1; fi
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### Go
|
|
154
|
+
|
|
155
|
+
Use `go` for Go examples.
|
|
156
|
+
|
|
157
|
+
**Prerequisites:**
|
|
158
|
+
* `go` must be installed and available in your system path.
|
|
159
|
+
* **macOS**: `brew install go`
|
|
160
|
+
* **Ubuntu/Debian**: `sudo apt-get install golang-go`
|
|
161
|
+
|
|
162
|
+
**Execution Model:**
|
|
163
|
+
Writes code to a temporary file and executes it via `go run`.
|
|
164
|
+
|
|
165
|
+
**Recipe:**
|
|
166
|
+
|
|
167
|
+
1. Use `go` fenced code blocks.
|
|
168
|
+
2. You can provide a full program (including `package main`) OR a simple snippet.
|
|
169
|
+
3. Simple snippets (without `package main`) are automatically wrapped in a `main` function and include `import "fmt"`.
|
|
170
|
+
4. **Note**: `<!-- share-code-between-examples -->` is **not** supported for Go.
|
|
171
|
+
|
|
172
|
+
**Simple Snippet:**
|
|
173
|
+
```go
|
|
174
|
+
fmt.Println("Hello Go")
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### Rust
|
|
178
|
+
|
|
179
|
+
Use `rust` or `rs` for Rust examples.
|
|
180
|
+
|
|
181
|
+
**Prerequisites:**
|
|
182
|
+
* `rustc` (Rust compiler) must be installed and available in your system path.
|
|
183
|
+
* **macOS**: `brew install rust`
|
|
184
|
+
* **Ubuntu/Debian**: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh` or `sudo apt-get install rustc`
|
|
185
|
+
|
|
186
|
+
**Execution Model:**
|
|
187
|
+
Compiles the code using `rustc` into a temporary binary, then executes the binary.
|
|
188
|
+
|
|
189
|
+
**Recipe:**
|
|
190
|
+
|
|
191
|
+
1. Use `rust` fenced code blocks.
|
|
192
|
+
2. You can provide a full program (including `fn main()`) OR a simple snippet.
|
|
193
|
+
3. Simple snippets (without `fn main`) are automatically wrapped in a `main` function.
|
|
194
|
+
4. **Note**: `<!-- share-code-between-examples -->` is **not** supported for Rust.
|
|
195
|
+
|
|
196
|
+
**Simple Snippet:**
|
|
197
|
+
```rust
|
|
198
|
+
println!("Hello Rust");
|
|
199
|
+
let x = 5;
|
|
200
|
+
assert_eq!(x, 5);
|
|
62
201
|
```
|
|
63
202
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
203
|
+
#### Fortran
|
|
204
|
+
|
|
205
|
+
Use `fortran`, `f90`, or `f95` for Fortran examples.
|
|
206
|
+
|
|
207
|
+
**Prerequisites:**
|
|
208
|
+
* `gfortran` must be installed and available in your system path.
|
|
209
|
+
* **macOS**: `brew install gcc` (includes gfortran)
|
|
210
|
+
* **Ubuntu/Debian**: `sudo apt-get install gfortran`
|
|
211
|
+
|
|
212
|
+
**Execution Model:**
|
|
213
|
+
Compiles the code using `gfortran` into a temporary binary, then executes the binary.
|
|
214
|
+
|
|
215
|
+
**Recipe:**
|
|
216
|
+
|
|
217
|
+
1. Use `fortran` fenced code blocks.
|
|
218
|
+
2. You can provide a full program (starting with `program name`) OR a simple snippet.
|
|
219
|
+
3. Simple snippets are automatically wrapped in a `program main ... end program main` block.
|
|
220
|
+
4. **Note**: `<!-- share-code-between-examples -->` is **not** supported for Fortran.
|
|
221
|
+
|
|
222
|
+
**Simple Snippet:**
|
|
223
|
+
```fortran
|
|
224
|
+
print *, "Hello Fortran"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
#### COBOL
|
|
228
|
+
|
|
229
|
+
Use `cobol` or `cob` for COBOL examples.
|
|
230
|
+
|
|
231
|
+
**Prerequisites:**
|
|
232
|
+
* `cobc` (GnuCOBOL) must be installed and available in your system path.
|
|
233
|
+
* **macOS**: `brew install gnucobol`
|
|
234
|
+
* **Ubuntu/Debian**: `sudo apt-get install gnucobol`
|
|
235
|
+
|
|
236
|
+
**Execution Model:**
|
|
237
|
+
Compiles the code using `cobc -x -free` into a temporary executable, then runs it.
|
|
238
|
+
|
|
239
|
+
**Recipe:**
|
|
240
|
+
|
|
241
|
+
1. Use `cobol` fenced code blocks.
|
|
242
|
+
2. Provide a full COBOL program (including `IDENTIFICATION DIVISION`).
|
|
243
|
+
3. The compiler is run in free-format mode (`-free`).
|
|
244
|
+
4. **Note**: `<!-- share-code-between-examples -->` is **not** supported for COBOL.
|
|
245
|
+
|
|
246
|
+
```cobol
|
|
247
|
+
IDENTIFICATION DIVISION.
|
|
248
|
+
PROGRAM-ID. HELLO.
|
|
249
|
+
PROCEDURE DIVISION.
|
|
250
|
+
DISPLAY 'Hello COBOL'.
|
|
251
|
+
STOP RUN.
|
|
67
252
|
```
|
|
68
253
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
254
|
+
#### C
|
|
255
|
+
|
|
256
|
+
Use `c` for C examples.
|
|
257
|
+
|
|
258
|
+
**Prerequisites:**
|
|
259
|
+
* `gcc` must be installed and available in your system path.
|
|
260
|
+
* **macOS**: `xcode-select --install` or `brew install gcc`
|
|
261
|
+
* **Ubuntu/Debian**: `sudo apt-get install build-essential`
|
|
262
|
+
|
|
263
|
+
**Execution Model:**
|
|
264
|
+
Compiles the code using `gcc` into a temporary binary, then executes the binary.
|
|
265
|
+
|
|
266
|
+
**Recipe:**
|
|
267
|
+
|
|
268
|
+
1. Use `c` fenced code blocks.
|
|
269
|
+
2. You can provide a full program (including `main()`) OR a simple snippet.
|
|
270
|
+
3. Simple snippets are automatically wrapped in a `main` function and include `stdio.h`.
|
|
271
|
+
4. **Note**: `<!-- share-code-between-examples -->` is **not** supported for C.
|
|
272
|
+
|
|
273
|
+
**Simple Snippet:**
|
|
274
|
+
```c
|
|
275
|
+
printf("Hello C\n");
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Skipping Examples
|
|
279
|
+
|
|
280
|
+
To skip a specific code block, add the `<!-- skip-example -->` comment immediately before it:
|
|
72
281
|
|
|
73
282
|
<!-- skip-example -->
|
|
74
283
|
```js
|
|
75
|
-
// not
|
|
76
|
-
|
|
77
|
-
var foo = download(...);
|
|
284
|
+
// This code will not be executed
|
|
285
|
+
fetch('https://example.com');
|
|
78
286
|
```
|
|
79
287
|
|
|
80
|
-
|
|
81
|
-
---
|
|
288
|
+
### Sharing Code Between Examples
|
|
82
289
|
|
|
83
|
-
|
|
290
|
+
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.
|
|
84
291
|
|
|
85
|
-
|
|
86
|
-
```js
|
|
87
|
-
// .doccident-setup.js
|
|
88
|
-
module.exports = {
|
|
89
|
-
require: {
|
|
90
|
-
Rx: require('rx')
|
|
91
|
-
},
|
|
292
|
+
> **Note**: This feature is currently supported for JavaScript, TypeScript, Python, and Shell, but **not** compiled languages like Go, Rust, Fortran, COBOL, and C.
|
|
92
293
|
|
|
93
|
-
|
|
94
|
-
$: require('jquery')
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
```
|
|
294
|
+
<!-- share-code-between-examples -->
|
|
98
295
|
|
|
99
|
-
|
|
100
|
-
|
|
296
|
+
```python
|
|
297
|
+
x = 10
|
|
298
|
+
```
|
|
101
299
|
|
|
102
|
-
|
|
300
|
+
```python
|
|
301
|
+
# x is still available here
|
|
302
|
+
assert x == 10
|
|
303
|
+
```
|
|
103
304
|
|
|
104
|
-
|
|
305
|
+
## Configuration
|
|
105
306
|
|
|
106
|
-
|
|
107
|
-
|
|
307
|
+
Create a `.doccident-setup.js` file in your project root to configure the test environment.
|
|
308
|
+
|
|
309
|
+
### Injecting Dependencies (`require`)
|
|
310
|
+
|
|
311
|
+
If your examples use external libraries, provide them here. This allows your examples to `require` modules just like users would:
|
|
312
|
+
|
|
313
|
+
```javascript
|
|
108
314
|
// .doccident-setup.js
|
|
109
315
|
module.exports = {
|
|
110
316
|
require: {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
regexRequire: {
|
|
115
|
-
'rx/(.*)': function (fullPath, matchedModuleName) {
|
|
116
|
-
return require('./dist/' + matchedModuleName);
|
|
317
|
+
// Make 'my-library' available when examples call require('my-library')
|
|
318
|
+
'my-library': require('./index.js'),
|
|
319
|
+
'lodash': require('lodash')
|
|
117
320
|
}
|
|
118
|
-
|
|
119
|
-
}
|
|
321
|
+
};
|
|
120
322
|
```
|
|
121
323
|
|
|
122
|
-
|
|
123
|
-
---
|
|
324
|
+
### Global Variables
|
|
124
325
|
|
|
125
|
-
|
|
126
|
-
in your `.doccident-setup.js` file.
|
|
127
|
-
This will speed things up drastically:
|
|
326
|
+
Define global variables available to all snippets:
|
|
128
327
|
|
|
129
|
-
|
|
130
|
-
```js
|
|
131
|
-
//.doccident-setup.js
|
|
328
|
+
```javascript
|
|
132
329
|
module.exports = {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
What if I have global state that needs to be reset after my examples run?
|
|
138
|
-
---
|
|
139
|
-
<!-- skip-example -->
|
|
140
|
-
```js
|
|
141
|
-
//.doccident-setup.js
|
|
142
|
-
module.exports = {
|
|
143
|
-
beforeEach: function () {
|
|
144
|
-
// reset your awesome global state
|
|
330
|
+
globals: {
|
|
331
|
+
$: require('jquery'),
|
|
332
|
+
window: {}
|
|
145
333
|
}
|
|
146
|
-
}
|
|
334
|
+
};
|
|
147
335
|
```
|
|
148
336
|
|
|
149
|
-
|
|
337
|
+
### Advanced Configuration
|
|
150
338
|
|
|
151
|
-
|
|
152
|
-
|
|
339
|
+
* **`regexRequire`**: Handle dynamic requires that match a pattern.
|
|
340
|
+
* **`beforeEach`**: Function to run before each snippet (e.g., to reset global state).
|
|
341
|
+
* **`transformCode`**: Pre-process code before execution (e.g., to strip out display-only syntax).
|
|
153
342
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
343
|
+
## Architecture and Approach
|
|
344
|
+
|
|
345
|
+
`doccident` is designed to be a lightweight, flexible testing harness for documentation. The codebase is modularized to separate parsing, execution, and reporting, ensuring maintainability and extensibility.
|
|
346
|
+
|
|
347
|
+
### Core Modules
|
|
348
|
+
|
|
349
|
+
1. **Parser (`src/parse-code-snippets-from-markdown.ts`)**
|
|
350
|
+
* Reads Markdown content line-by-line.
|
|
351
|
+
* Uses a robust state machine to identify code fences and control comments (like `skip-example`).
|
|
352
|
+
* Extracts valid snippets into structured objects containing code, file paths, and line numbers.
|
|
353
|
+
* **Multi-Language Support**: Recognizes `js`, `ts`, `python`, `shell`, `go`, `rust`, `fortran`, `cobol`, and `c` blocks.
|
|
354
|
+
|
|
355
|
+
2. **Test Runner (`src/doctest.ts`)**
|
|
356
|
+
* The orchestrator of the application.
|
|
357
|
+
* Iterates through parsed snippets and manages the execution lifecycle.
|
|
358
|
+
* **Sandboxing**: Uses Node.js's `vm` module (`runInNewContext`) to execute JS/TS code in isolation.
|
|
359
|
+
* **Subprocess Execution**: Spawns `python3`, `go`, `rustc`, `gfortran`, `cobc`, `gcc`, or shell subprocesses for non-JS languages.
|
|
360
|
+
* **Transformation**: Uses **esbuild** to compile modern JavaScript and TypeScript code down to a compatible format before execution.
|
|
361
|
+
|
|
362
|
+
3. **Reporter (`src/reporter.ts`)**
|
|
363
|
+
* Collects execution results (pass, fail, skip).
|
|
364
|
+
* Formats output using `chalk` for readability.
|
|
365
|
+
* **Error Mapping**: Crucially, it maps execution errors back to the specific line number in the original Markdown file, making it easy to identify exactly which line in your documentation caused the failure.
|
|
366
|
+
|
|
367
|
+
4. **Types & Utils**
|
|
368
|
+
* Shared interfaces (`src/types.ts`) ensure type safety across the application.
|
|
369
|
+
* Utility functions (`src/utils.ts`) provide common helpers.
|
|
164
370
|
|
|
165
|
-
|
|
166
|
-
---
|
|
167
|
-
|
|
168
|
-
All of these projects either run `doccident` with `npm test` or as part of their CI process:
|
|
169
|
-
|
|
170
|
-
* [lodash](https://github.com/lodash/lodash)
|
|
171
|
-
* [Moment](https://github.com/moment/momentjs.com)
|
|
172
|
-
* [RxJS](https://github.com/ReactiveX/RxJS)
|
|
173
|
-
* [most](https://github.com/cujojs/most)
|
|
174
|
-
* [xstream](https://github.com/staltz/xstream)
|
|
175
|
-
* [cyclejs/time](https://github.com/cyclejs/time)
|
|
176
|
-
* [rx.schedulers](https://github.com/Reactive-Extensions/rx.schedulers)
|
|
177
|
-
* [rx.priorityqueue](https://github.com/Reactive-Extensions/rx.priorityqueue)
|
|
178
|
-
* [rx.disposables](https://github.com/Reactive-Extensions/rx.disposables)
|
|
179
|
-
* [rx-undoable](https://github.com/Widdershin/rx-undoable)
|
|
371
|
+
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.
|
package/bin/cmd.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
const { version } = require('../package');
|
|
7
7
|
const doctest = require('..');
|
|
8
|
-
const program = require('commander');
|
|
8
|
+
const { program } = require('commander');
|
|
9
9
|
const path = require('path');
|
|
10
|
-
const
|
|
10
|
+
const fg = require('fast-glob');
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const { pathToFileURL } = require('url');
|
|
13
13
|
|
|
@@ -30,15 +30,18 @@ program
|
|
|
30
30
|
.name('doccident')
|
|
31
31
|
.description('Test all the code in your markdown docs!')
|
|
32
32
|
.version(version, '-v, --version', 'output the current version')
|
|
33
|
+
.argument('[glob]', 'glob pattern for files to test')
|
|
33
34
|
.helpOption('-h, --help', 'output usage informations')
|
|
34
35
|
.option('-c, --config <path>', 'custom config location', path.join(process.cwd(), '/.doccident-setup.js'))
|
|
35
36
|
.option('--test-output', 'output the test results to the console')
|
|
36
37
|
.parse(process.argv);
|
|
37
38
|
|
|
39
|
+
const options = program.opts();
|
|
40
|
+
|
|
38
41
|
// Parse config file
|
|
39
42
|
(async () => {
|
|
40
|
-
if (
|
|
41
|
-
const configPath = path.resolve(
|
|
43
|
+
if (options.config) {
|
|
44
|
+
const configPath = path.resolve(options.config);
|
|
42
45
|
|
|
43
46
|
if (fs.existsSync(configPath)) {
|
|
44
47
|
try {
|
|
@@ -51,33 +54,31 @@ program
|
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
if (
|
|
57
|
+
if (options.testOutput) {
|
|
55
58
|
config.testOutput = true;
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
// Resolve files
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
(err, files) => {
|
|
65
|
-
|
|
66
|
-
if (err) {
|
|
67
|
-
console.trace(err);
|
|
62
|
+
try {
|
|
63
|
+
const files = await fg(
|
|
64
|
+
program.args[0] || DEFAULT_GLOB,
|
|
65
|
+
{
|
|
66
|
+
ignore: [...config.ignore, ...DEFAULT_IGNORE]
|
|
68
67
|
}
|
|
68
|
+
);
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
// Run tests
|
|
71
|
+
const results = doctest.runTests(files, config);
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
console.log('\n');
|
|
74
|
+
doctest.printResults(results);
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
76
|
+
// Exit with error-code if any test failed
|
|
77
|
+
const failures = results.filter(result => result.status === 'fail');
|
|
78
|
+
if (failures.length > 0) {
|
|
79
|
+
process.exit(1);
|
|
81
80
|
}
|
|
82
|
-
)
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.trace(err);
|
|
83
|
+
}
|
|
83
84
|
})();
|