@ndp-software/lit-md 0.3.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/LICENSE.md +3 -0
- package/README.md +125 -0
- package/dist/cli.js +1273 -0
- package/dist/cli.js.map +7 -0
- package/docs/cli.md +74 -0
- package/docs/how-wait-mode-works.md +381 -0
- package/docs/shell-examples.md +254 -0
- package/package.json +58 -0
- package/src/cli.ts +327 -0
- package/src/describe-format.ts +53 -0
- package/src/docs/README.lit-md.ts +126 -0
- package/src/docs/cli.lit-md.ts +44 -0
- package/src/docs/shell-examples.lit-md.ts +243 -0
- package/src/index.ts +7 -0
- package/src/parser.ts +970 -0
- package/src/renderer.ts +130 -0
- package/src/resolver.ts +65 -0
- package/src/shell.ts +362 -0
- package/src/typecheck.ts +51 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import {alias, example, describe, stripTypesFlag, shellExample} from '../index.ts'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
describe('shellExample', () => {
|
|
6
|
+
/*
|
|
7
|
+
`shellExample` provides a more structured way to include shell commands,
|
|
8
|
+
with support for
|
|
9
|
+
- input file generation and
|
|
10
|
+
- output file assertions, and
|
|
11
|
+
- more detailed stdout assertions.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
shellExample('echo "hello world"', {meta: true, stdout: {display: true}})
|
|
15
|
+
|
|
16
|
+
// Can contain assertions on stdout, which appear as comments in the emitted markdown.
|
|
17
|
+
// Assertions can use `contains` or `matches`, with either strings or regex patterns.
|
|
18
|
+
example('with stdout assertion', () => {
|
|
19
|
+
shellExample('echo "ok"', {stdout: {contains: 'ok'}})
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// stdout.matches provides an alternative assertion method:
|
|
23
|
+
example('with stdout matches', () => {
|
|
24
|
+
shellExample('echo "version 1.0.0"', {stdout: {matches: /version \d+\.\d+\.\d+/}})
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
// Can provide input files that are created before the command runs,
|
|
28
|
+
// and output file assertions that check for files created by the command and their contents.
|
|
29
|
+
example('with output files', () => {
|
|
30
|
+
shellExample('cp input.txt output.txt', {
|
|
31
|
+
inputFiles: [{path: 'input.txt', content: 'hello world'}],
|
|
32
|
+
outputFiles: [{path: 'output.txt', contains: 'hello world'}]
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
// Output file assertions can check contents with `contains` (substring or regex) or `matches` (regex or string).
|
|
37
|
+
// Both properties are optional — you can specify just one, or display file contents without assertions.
|
|
38
|
+
example('with regex match', () => {
|
|
39
|
+
shellExample('cp input.txt output.txt', {
|
|
40
|
+
inputFiles: [{path: 'input.txt', content: 'first line\nsecond line'}],
|
|
41
|
+
outputFiles: [{path: 'output.txt', matches: /^first/}]
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// File assertions can also use regex in contains or strings in matches:
|
|
46
|
+
example('flexible assertion types', () => {
|
|
47
|
+
shellExample('cp input.txt output.txt', {
|
|
48
|
+
inputFiles: [{path: 'input.txt', content: 'data.json'}],
|
|
49
|
+
outputFiles: [{path: 'output.txt', contains: /\.json/}]
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// You can even output the output file contents, or the stdout:
|
|
54
|
+
example('output file contents', () => {
|
|
55
|
+
shellExample('echo "Hello, World!" | tee greeting.txt', {
|
|
56
|
+
stdout: {
|
|
57
|
+
contains: "Hello",
|
|
58
|
+
display: true /* outputs standard out after the command */
|
|
59
|
+
},
|
|
60
|
+
outputFiles: [{
|
|
61
|
+
contains: 'Hello',
|
|
62
|
+
path: 'greeting.txt',
|
|
63
|
+
// display: true, /* by default display, but suppress with `display: false` */
|
|
64
|
+
summary: true
|
|
65
|
+
}]
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
shellExample('echo "Hello, World!" | tee greeting.txt', {
|
|
69
|
+
stdout: {contains: "Hello", display: true},
|
|
70
|
+
outputFiles: [{contains: 'Hello', path: 'greeting.txt', summary: true}]
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// You can also display the `shellExample` call itself in the output using the `meta` option:
|
|
74
|
+
example('with meta option', () =>
|
|
75
|
+
shellExample('echo "Hello, World!"', {
|
|
76
|
+
meta: true,
|
|
77
|
+
stdout: {}
|
|
78
|
+
})
|
|
79
|
+
)
|
|
80
|
+
shellExample('echo "Hello, World!"', {
|
|
81
|
+
meta: true,
|
|
82
|
+
stdout: {}
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// Input and output files can display their contents:
|
|
86
|
+
example('display inputFile contents', () =>
|
|
87
|
+
shellExample('cat input.txt', {
|
|
88
|
+
inputFiles: [{
|
|
89
|
+
path: 'input.txt',
|
|
90
|
+
content: 'File contents to display',
|
|
91
|
+
display: true, // Show file contents in output
|
|
92
|
+
displayPath: true,
|
|
93
|
+
summary: true
|
|
94
|
+
}],
|
|
95
|
+
stdout: {display: true}
|
|
96
|
+
})
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
describe('Advanced Usage', () => {
|
|
101
|
+
/*
|
|
102
|
+
shellExample provides more control and structured options for shell command examples. Use when you need to:
|
|
103
|
+
|
|
104
|
+
- Capture and display stdout dynamically
|
|
105
|
+
- Create input files before running
|
|
106
|
+
- Assert output files match patterns
|
|
107
|
+
- Hide/customize what's displayed
|
|
108
|
+
- Show the function call itself with `meta: true`
|
|
109
|
+
*/
|
|
110
|
+
example('basic shellExample', () => shellExample('echo "hello world"'))
|
|
111
|
+
/*
|
|
112
|
+
With Assertions
|
|
113
|
+
*/
|
|
114
|
+
example('contains', () => shellExample('echo "ok"', {
|
|
115
|
+
stdout: {contains: 'ok'}
|
|
116
|
+
}))
|
|
117
|
+
|
|
118
|
+
/*
|
|
119
|
+
Exit Code Assertions
|
|
120
|
+
*/
|
|
121
|
+
example('with exitCode success (0)', () => shellExample('echo "success"', {
|
|
122
|
+
exitCode: 0,
|
|
123
|
+
stdout: {display: true}
|
|
124
|
+
}))
|
|
125
|
+
|
|
126
|
+
example('with exitCode for failure', () => shellExample('false', {
|
|
127
|
+
exitCode: 1
|
|
128
|
+
}))
|
|
129
|
+
|
|
130
|
+
example('with exitCode mismatch detection', () => shellExample('true', {
|
|
131
|
+
exitCode: 0,
|
|
132
|
+
stdout: {display: true}
|
|
133
|
+
}))
|
|
134
|
+
/*
|
|
135
|
+
Input and Output Files
|
|
136
|
+
*/
|
|
137
|
+
example('matches', () => shellExample('cat input.txt > output.txt', {
|
|
138
|
+
inputFiles: [
|
|
139
|
+
{path: 'input.txt', content: 'Hello'}
|
|
140
|
+
],
|
|
141
|
+
outputFiles: [
|
|
142
|
+
{path: 'output.txt', matches: /Hello/}
|
|
143
|
+
]
|
|
144
|
+
}))
|
|
145
|
+
|
|
146
|
+
/*
|
|
147
|
+
Timeout Configuration
|
|
148
|
+
*/
|
|
149
|
+
example('with timeout (default 3000ms)', () => shellExample('echo "quick"', {
|
|
150
|
+
timeout: 3000,
|
|
151
|
+
stdout: {display: true}
|
|
152
|
+
}))
|
|
153
|
+
|
|
154
|
+
example('with custom short timeout', () => shellExample('echo "instant"', {
|
|
155
|
+
timeout: 500,
|
|
156
|
+
stdout: {display: true}
|
|
157
|
+
}))
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
/*
|
|
161
|
+
Options Reference
|
|
162
|
+
|
|
163
|
+
#### displayCommand
|
|
164
|
+
|
|
165
|
+
- Type: `boolean` | `'hidden'`
|
|
166
|
+
- When 'hidden' or false, command is executed but not shown in output
|
|
167
|
+
- Default: true (command is shown)
|
|
168
|
+
|
|
169
|
+
#### stdout
|
|
170
|
+
|
|
171
|
+
- Type: { contains?: string | RegExp; matches?: string | RegExp; display?: boolean }
|
|
172
|
+
- `contains`: Assert output contains this string or matches regex pattern (optional)
|
|
173
|
+
- `matches`: Assert output matches this string (substring) or regex pattern (optional)
|
|
174
|
+
- `display`: When true, dynamically execute and show actual stdout (default: false)
|
|
175
|
+
- At least one of contains/matches is typically specified, but both are optional
|
|
176
|
+
|
|
177
|
+
#### outputFiles
|
|
178
|
+
|
|
179
|
+
Array of output file assertions:
|
|
180
|
+
|
|
181
|
+
- `path`: File path (relative to temp directory)
|
|
182
|
+
- `contains`: String or regex to check if file contains this value (optional)
|
|
183
|
+
- `matches`: String or regex to check if file matches this value (optional)
|
|
184
|
+
- `displayPath`: Show the filename (default: true)
|
|
185
|
+
- `summary`: Show summary line before contents (default: true)
|
|
186
|
+
|
|
187
|
+
#### inputFiles
|
|
188
|
+
|
|
189
|
+
Array of input files to create:
|
|
190
|
+
|
|
191
|
+
- `path`: File path
|
|
192
|
+
- `content`: File contents
|
|
193
|
+
- `displayPath`: Show the filename (default: true)
|
|
194
|
+
- `display`: Show the file contents (default: true)
|
|
195
|
+
- `summary`: Show summary line (default: true)
|
|
196
|
+
|
|
197
|
+
#### exitCode
|
|
198
|
+
|
|
199
|
+
- Type: `number`
|
|
200
|
+
- Asserts the command exits with this specific code
|
|
201
|
+
- When not specified, expects exit code 0 (success)
|
|
202
|
+
- Useful for testing expected failures (e.g., exitCode: 1)
|
|
203
|
+
- If actual exit code doesn't match, command fails with detailed error message
|
|
204
|
+
|
|
205
|
+
#### timeout
|
|
206
|
+
|
|
207
|
+
- Type: `number`
|
|
208
|
+
- Command timeout in milliseconds
|
|
209
|
+
- Default: 3000 (3 seconds)
|
|
210
|
+
- If command runs longer than timeout, throws ETIMEDOUT error
|
|
211
|
+
- Useful for preventing infinite loops or very long-running commands
|
|
212
|
+
|
|
213
|
+
#### meta
|
|
214
|
+
|
|
215
|
+
- Type: `boolean`
|
|
216
|
+
- When true, outputs a fenced code block showing the `shellExample` call itself before the command output
|
|
217
|
+
- The `meta: true` option is removed from the reconstructed call for cleaner documentation
|
|
218
|
+
- Default: false (only shows the command and its output)
|
|
219
|
+
- Useful for showing both the code and its result in documentation
|
|
220
|
+
|
|
221
|
+
#### Example with All Options
|
|
222
|
+
|
|
223
|
+
*/
|
|
224
|
+
example('all options', () =>
|
|
225
|
+
shellExample(
|
|
226
|
+
'cat input.txt && echo "Done" | tee result.log', {
|
|
227
|
+
displayCommand: true,
|
|
228
|
+
inputFiles: [
|
|
229
|
+
{path: 'input.txt', content: 'Config data', displayPath: true, display: true, summary: true}
|
|
230
|
+
],
|
|
231
|
+
stdout: {
|
|
232
|
+
contains: 'Done',
|
|
233
|
+
display: true, // Show actual output
|
|
234
|
+
matches: /Done/ // Both contains and matches are optional
|
|
235
|
+
},
|
|
236
|
+
outputFiles: [
|
|
237
|
+
{path: 'result.log', matches: /Done/, displayPath: true, summary: true}
|
|
238
|
+
],
|
|
239
|
+
exitCode: 0, // Assert successful exit
|
|
240
|
+
timeout: 5000 // Set 5 second timeout
|
|
241
|
+
}))
|
|
242
|
+
})
|
|
243
|
+
})
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { parse } from './parser.ts'
|
|
2
|
+
export { render } from './renderer.ts'
|
|
3
|
+
export type { DocNode, ProseNode, CodeNode } from './parser.ts'
|
|
4
|
+
export { example, metaExample, shellExample, describe, alias, stripTypesFlag } from './shell.ts'
|
|
5
|
+
export type { ShellExampleOpts, ShellFileAssertion } from './shell.ts'
|
|
6
|
+
export { setDescribeFormat } from './describe-format.ts'
|
|
7
|
+
export type { DescribeFormatType } from './describe-format.ts'
|