@ndp-software/lit-md 0.3.0 → 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/README.md CHANGED
@@ -74,12 +74,8 @@ example('multiply example', () => {
74
74
 
75
75
  ```
76
76
 
77
- ```sh
78
- $ lit-md tmp.ts --out out.md
79
- ```
80
-
81
- Output file `out.md`:
82
- ````markdown
77
+ ````sh
78
+ $ lit-md my-readme.ts
83
79
  ## My Project README.
84
80
 
85
81
  This is a really great project!
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@ndp-software/lit-md",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Literate test files that generate README.md",
5
5
  "license": "UNLICENSED -- All rights reserved. See LICENSE file.",
6
6
  "author": "Andy Peterson <andy@ndpsoftware.com>",
7
7
  "type": "module",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": ""
10
+ "url": "https://github.com/ndp-software/lit-md"
11
11
  },
12
12
  "keywords": [
13
13
  "literate programming",
@@ -30,10 +30,6 @@
30
30
  "docs/**/*",
31
31
  "src/**/*"
32
32
  ],
33
- "exports": {
34
- "main": "./dist/index.js",
35
- "types": "./dist/index.d.ts"
36
- },
37
33
  "scripts": {
38
34
  "prepublishOnly": "npm run verify && npm run build",
39
35
  "readme": "node ./src/cli.ts --test --typecheck --out ./README.md src/docs/README.lit-md.ts",
@@ -66,10 +66,11 @@ what appears in the output and how it looks.
66
66
 
67
67
  # A simple example
68
68
  */
69
- shellExample(`lit-md tmp.ts --out out.md`, {
69
+ shellExample(`lit-md my-readme.ts`, {
70
70
  inputFiles: [{
71
- path: 'tmp.ts',
71
+ path: 'my-readme.ts',
72
72
  displayPath: false,
73
+ display: true,
73
74
  content: `
74
75
  describe('My Project README.', () => {
75
76
  /*
@@ -91,9 +92,11 @@ example('multiply example', () => {
91
92
  })
92
93
  `
93
94
  }],
94
- outputFiles: [{
95
- path: "out.md"
96
- }]
95
+ displayCommand: true,
96
+ stdout: {
97
+ display: true,
98
+ contains: 'This is a really great project!'
99
+ }
97
100
  })
98
101
 
99
102
  /*
package/src/parser.ts CHANGED
@@ -3,6 +3,7 @@ import { spawnSync } from 'node:child_process'
3
3
  import { writeFileSync, mkdtempSync, rmSync, readFileSync } from 'node:fs'
4
4
  import { join, isAbsolute } from 'node:path'
5
5
  import { tmpdir } from 'node:os'
6
+ import { buildAliasPrefix } from './shell.ts'
6
7
 
7
8
  export type ProseNode = { kind: 'prose'; text: string; terminal?: true; noBlankAfter?: true; noBlankBefore?: true }
8
9
  export type CodeNode = { kind: 'code'; lang: string; text: string; title?: string }
@@ -230,6 +231,13 @@ export function parse(src: string, lang = 'typescript'): DocNode[] {
230
231
  if (opts && isExecutionNeeded(opts)) {
231
232
  const outputPaths = extractOutputFilePaths(opts)
232
233
  execution = executeShellCommand(cmd, inputFiles, outputPaths, expectedExitCode)
234
+
235
+ // Fail if exit code doesn't match expectations
236
+ if (execution && execution.exitCode !== expectedExitCode) {
237
+ throw new Error(
238
+ `shellExample failed: ${cmd}\nexit ${execution.exitCode} (expected exit code ${expectedExitCode})`
239
+ )
240
+ }
233
241
  }
234
242
 
235
243
  const displayCommand = opts ? readBoolOption(getProp(opts, 'displayCommand')) : true
@@ -881,8 +889,10 @@ function executeShellCommand(cmd: string, inputFiles: Array<InputFileInfo>, outp
881
889
  writeFileSync(resolvePath(f.path), f.content, 'utf8')
882
890
  }
883
891
 
884
- // Execute command
885
- const result = spawnSync(cmd, { shell: true, encoding: 'utf8', cwd: tmpDir })
892
+ // Execute command with alias prefix
893
+ const prefix = buildAliasPrefix()
894
+ const fullCmd = prefix ? `${prefix}${cmd}` : cmd
895
+ const result = spawnSync(fullCmd, { shell: true, encoding: 'utf8', cwd: tmpDir })
886
896
 
887
897
  // Capture output files when exit code matches expectation
888
898
  const outputFiles = new Map<string, string>()
@@ -930,10 +940,16 @@ function appendShellExampleAnnotations(
930
940
  const containsProp = getProp(prop.initializer as ts.ObjectLiteralExpression, 'contains')
931
941
  const displayProp = getProp(prop.initializer as ts.ObjectLiteralExpression, 'display')
932
942
 
933
- // If display is true, use cached execution or show the contains assertion
943
+ // If display is true, use cached execution to show stdout
934
944
  if (displayProp && displayProp.initializer.kind === ts.SyntaxKind.TrueKeyword) {
935
945
  if (execution && execution.exitCode === 0) {
936
946
  lines.push(execution.stdout)
947
+ } else if (execution && execution.exitCode !== 0) {
948
+ // This shouldn't happen now since we throw on exit code mismatch
949
+ lines.push(`# [ERROR] stdout unavailable (exit code: ${execution.exitCode})`)
950
+ } else {
951
+ // This shouldn't happen now since we throw on errors
952
+ lines.push(`# [ERROR] stdout unavailable (execution failed)`)
937
953
  }
938
954
  } else if (containsProp && ts.isStringLiteralLike(containsProp.initializer)) {
939
955
  // Show contains assertion only if display is not true
package/src/shell.ts CHANGED
@@ -41,7 +41,7 @@ function resolveCmdPath(cmdString: string): string {
41
41
  }
42
42
 
43
43
  /** Build shell alias prefix lines to prepend to commands. */
44
- function buildAliasPrefix(): string {
44
+ export function buildAliasPrefix(): string {
45
45
  if (_aliases.size === 0) return ''
46
46
  const lines = [..._aliases.entries()].map(([name, cmd]) => `alias ${name}='${cmd}'`)
47
47
  return lines.join('\n') + '\n'
@@ -109,6 +109,10 @@ export function _runShellExample(cmd: string, opts: ShellExampleOpts): void {
109
109
  }
110
110
  const stdout = result.stdout
111
111
  if (opts.stdout !== undefined) {
112
+ // If display is true, stdout must not be empty
113
+ if (opts.stdout.display && (!stdout || stdout.trim() === '')) {
114
+ throw new Error(`stdout.display: true but command produced no output (exit code: ${actualExitCode})`)
115
+ }
112
116
  if (opts.stdout.contains !== undefined) {
113
117
  const actualDesc = stdout === '' ? '(empty)' : stdout
114
118
  assert.ok(