@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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/cli.ts", "../src/parser.ts", "../src/renderer.ts", "../src/typecheck.ts", "../src/shell.ts", "../src/resolver.ts", "../src/describe-format.ts"],
4
+ "sourcesContent": ["#!/usr/bin/env node\nimport { readFileSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { join, dirname, basename, extname, resolve } from 'node:path'\nimport { spawnSync } from 'node:child_process'\nimport { parse } from './parser.ts'\nimport { render } from './renderer.ts'\nimport { typecheck } from './typecheck.ts'\nimport { stripTypesFlag, watchFilesAndWait } from './shell.ts'\nimport { resolveOutputFiles } from './resolver.ts'\nimport { resolveDescribeFormat, resetDescribeFormat } from './describe-format.ts'\n\n// --- Argument parsing ---\n\nconst args = process.argv.slice(2)\n\nfunction extractFlag(flag: string): boolean {\n const idx = args.indexOf(flag)\n if (idx === -1) return false\n args.splice(idx, 1)\n return true\n}\n\nfunction extractFlagValue(flag: string): string | undefined {\n const idx = args.indexOf(flag)\n if (idx === -1) {\n // Check for --flag=value format\n const eqIdx = args.findIndex(arg => arg.startsWith(flag + '='))\n if (eqIdx === -1) return undefined\n const value = args[eqIdx]!.slice(flag.length + 1)\n args.splice(eqIdx, 1)\n return value\n }\n const value = args[idx + 1]\n args.splice(idx, 2)\n return value\n}\n\nconst showHelp = extractFlag('--help') || extractFlag('-h')\nconst dryrun = extractFlag('--dryrun')\nconst runTests = extractFlag('--test')\nconst runTypecheck = extractFlag('--typecheck')\nconst updateSnapshots = extractFlag('--update-snapshots') || extractFlag('-u')\nconst wait = extractFlag('--wait')\nconst outFlag = extractFlagValue('--out')\nconst outputDir = extractFlagValue('--outDir')\nconst describeFormat = extractFlagValue('--describe') || '##'\n\n// Helper to parse test summary from output\nfunction parseTestSummary(output: string): { passed: number; failed: number; total: number; hasFailed: boolean } {\n const lines = output.split('\\n')\n let stats = { passed: 0, failed: 0, total: 0, hasFailed: false }\n \n for (const line of lines) {\n if (line.includes('\u2139 pass')) {\n const match = line.match(/pass\\s+(\\d+)/)\n if (match) stats.passed = parseInt(match[1])\n }\n if (line.includes('\u2139 fail')) {\n const match = line.match(/fail\\s+(\\d+)/)\n if (match) stats.failed = parseInt(match[1])\n }\n if (line.includes('\u2139 tests')) {\n const match = line.match(/tests\\s+(\\d+)/)\n if (match) stats.total = parseInt(match[1])\n }\n }\n \n stats.hasFailed = stats.failed > 0\n return stats\n}\n\n// Check for unknown options\nconst unknownOptions = args.filter(a => a.startsWith('--') || (a.startsWith('-') && a.length > 1 && a !== '-'))\nif (unknownOptions.length > 0) {\n console.error(`error: unknown option${unknownOptions.length > 1 ? 's' : ''}: ${unknownOptions.join(', ')}`)\n process.exit(1)\n}\n\nconst inputPaths = args.filter(a => !a.startsWith('--'))\n\n// --- File name rewriting helper ---\n\nfunction getOutputFileName(inputPath: string): string {\n const base = basename(inputPath)\n // Check if file ends with .lit-md.ts or .lit-md.js pattern\n if (base.endsWith('.lit-md.ts') || base.endsWith('.lit-md.js')) {\n // Remove the entire .lit-md.ts or .lit-md.js extension\n return base.slice(0, -(base.endsWith('.lit-md.ts') ? '.lit-md.ts'.length : '.lit-md.js'.length)) + '.md'\n }\n // Otherwise, remove the final extension (.ts, .js, etc.) and add .md\n return basename(inputPath, extname(inputPath)) + '.md'\n}\n\n// --- Help ---\n\nif (showHelp) {\n console.log(`lit-md - Generate markdown documentation from test files\n\nUsage: lit-md [options] <file.ts|js> [file2 ...]\n\nOptions:\n --help, -h Show this help message\n --test Run tests before generating markdown\n --typecheck Run type checking before generating markdown\n --dryrun Show what would be written without writing files\n -u, --update-snapshots Update snapshot files instead of generating markdown\n --wait After generating, keep the process alive and watch for file\n changes. Press space to manually regenerate, Ctrl+C to exit.\n Works with --test and --typecheck (reruns on each change).\n --out <output.md> Write to a specific output file (requires single input)\n --outDir <dir> Write generated markdown files to this directory\n --describe <format> Control describe() block rendering (default: ##)\n Formats:\n hidden - Omit describes\n # - Render as h1 headers, nested as h2, h3, etc.\n ## - Render as h2 headers, nested as h3, h4, etc. (default)\n ### - Render as h3 headers, nested as h4, h5, etc.\n #### - Render as h4 headers, nested as h5, h6, etc.\n auto - Dynamically determine level based on document structure\n (h1 if no headers exist, else one level deeper than last header)\n\nBy default, output is written to stdout. Use --out or --outDir to write to files.\n\nExamples:\n lit-md README.md.test.ts # outputs to stdout\n lit-md --test --typecheck README.md.test.ts # outputs to stdout after testing\n lit-md --wait README.md.test.ts # outputs to stdout, then waits for changes\n lit-md --out /tmp/docs.md README.md.test.ts # writes to file\n lit-md --outDir ./docs src/**/*.md.test.ts # writes to directory\n lit-md --describe=\"#\" README.md.test.ts # outputs to stdout with custom format\n lit-md --describe=\"auto\" README.md.test.ts # outputs to stdout with auto format\n`)\n process.exit(0)\n}\n\n// --- Validation ---\n\nif (!inputPaths.length) {\n console.error('Usage: lit-md [--test] [--typecheck] [--dryrun] [-u|--update-snapshots] [--out <output.md>] [--outDir <dir>] <file.ts|js> [file2 ...]')\n process.exit(1)\n}\n\nconst validDescribeFormats = ['hidden', 'auto', '#', '##', '###', '####']\nif (!validDescribeFormats.includes(describeFormat)) {\n console.error(`error: invalid --describe format: ${describeFormat}. Valid formats: ${validDescribeFormats.join(', ')}`)\n process.exit(1)\n}\n\nif (outFlag && outputDir) {\n console.error('error: --out and --outDir are mutually exclusive')\n process.exit(1)\n}\n\nif (outFlag && inputPaths.length > 1) {\n console.error('error: --out can only be used with a single input file')\n process.exit(1)\n}\n\nif (runTypecheck) {\n const jsFiles = inputPaths.filter(f => extname(f) === '.js')\n if (jsFiles.length) {\n console.error(`error: --typecheck requires .ts files; received: ${jsFiles.join(', ')}`)\n process.exit(1)\n }\n}\n\n// --- Typecheck ---\n// NOTE: Moved into executeTasks() to run on each regeneration when --wait is used\n\n// --- Run tests ---\n// NOTE: Moved into executeTasks() to run on each regeneration when --wait is used\n\n// --- Generate markdown ---\n\nasync function generateMarkdown(): Promise<void> {\n let filesGenerated = 0\n \n for (const inputPath of inputPaths) {\n // Reset the describe format override before processing each file\n resetDescribeFormat()\n \n // Import the file to allow module-level setup (like setDescribeFormat calls)\n const absolutePath = resolve(inputPath)\n try {\n // Suppress test output during import and test execution\n const origStdoutWrite = process.stdout.write\n const origStderrWrite = process.stderr.write\n const origLog = console.log\n const origInfo = console.info\n const origWarn = console.warn\n try {\n process.stdout.write = () => true as any\n process.stderr.write = () => true as any\n console.log = () => {}\n console.info = () => {}\n console.warn = () => {}\n await import(absolutePath)\n // Wait for deferred test execution to complete while output is suppressed\n await new Promise(resolve => setTimeout(resolve, 100))\n } finally {\n process.stdout.write = origStdoutWrite\n process.stderr.write = origStderrWrite\n console.log = origLog\n console.info = origInfo\n console.warn = origWarn\n }\n } catch {\n // File might not be valid JavaScript/TypeScript module, continue\n }\n \n const src = readFileSync(inputPath, 'utf8')\n const lang = extname(inputPath) === '.js' ? 'javascript' : 'typescript'\n let nodes = parse(src, lang)\n if (!dryrun) {\n nodes = resolveOutputFiles(nodes)\n }\n // Use resolved format (CLI value + file override)\n const finalDescribeFormat = resolveDescribeFormat(describeFormat)\n const md = render(nodes, finalDescribeFormat)\n\n let outPath: string | null = null\n let isStdout = false\n if (updateSnapshots) {\n const outputFileName = getOutputFileName(inputPath)\n const fileNameWithoutMd = outputFileName.slice(0, -3) // Remove .md\n outPath = join(dirname(resolve(inputPath)), `${fileNameWithoutMd}.snapshot.md`)\n } else if (outFlag) {\n outPath = outFlag\n } else if (outputDir) {\n mkdirSync(outputDir, { recursive: true })\n outPath = join(outputDir, getOutputFileName(inputPath))\n } else {\n isStdout = true\n }\n\n if (dryrun) {\n if (isStdout) {\n console.error(`dry run: would write to stdout`)\n } else {\n console.error(`dry run: would write ${outPath}`)\n }\n } else if (isStdout) {\n process.stdout.write(md + '\\n')\n } else {\n writeFileSync(outPath!, md + '\\n', 'utf8')\n filesGenerated++\n }\n }\n \n // Show summary if files were written\n if (!dryrun && filesGenerated > 0) {\n const fileWord = filesGenerated === 1 ? 'file' : 'files'\n console.error(`\u2705 Generated ${filesGenerated} ${fileWord}`)\n }\n}\n\nasync function executeTasks(): Promise<void> {\n // Run typecheck before generation (if enabled)\n if (runTypecheck) {\n const result = typecheck(inputPaths.map(p => resolve(p)))\n if (!result.ok) {\n for (const msg of result.messages) console.error(msg)\n console.error('\u274C Typecheck failed')\n // In wait mode, report error but continue; in normal mode, exit\n if (!wait) process.exit(1)\n // Continue to markdown generation even if typecheck failed\n } else {\n console.error('\u2705 Typecheck passed')\n }\n }\n\n // Run tests before generation (if enabled)\n if (runTests) {\n const stripFlag = stripTypesFlag()\n const nodeArgs = ['--test', ...(stripFlag ? [stripFlag] : []), ...inputPaths.map(p => resolve(p))]\n \n // In wait mode, capture output for summary display; otherwise inherit (show full output)\n const spawnOptions = wait ? { encoding: 'utf-8' as const } : { stdio: 'inherit' as const, env: process.env }\n \n const result = spawnSync(process.execPath, nodeArgs, spawnOptions)\n \n // Handle output based on mode\n if (wait && result.stdout) {\n // In wait mode: capture output and show condensed summary\n const output = result.stdout.toString()\n const stats = parseTestSummary(output)\n \n if (stats.hasFailed) {\n // Extract and show failures section\n const failureStart = output.indexOf('\u2716 failing tests')\n if (failureStart !== -1) {\n const failureSection = output.substring(failureStart)\n console.error(failureSection)\n }\n console.error(`\\n\u274C Tests failed: ${stats.failed}/${stats.total} failed`)\n } else {\n // All passed: show one-line summary\n console.log(`\u2705 Tests passed: ${stats.passed} passed`)\n }\n }\n \n if (result.status !== 0) {\n // In wait mode, report error but continue; in normal mode, exit\n if (!wait) process.exit(result.status ?? 1)\n // Continue to markdown generation even if tests failed\n }\n }\n\n // Generate markdown (always do this, even if tests/typecheck failed)\n await generateMarkdown()\n}\n\n;(async () => {\n await executeTasks()\n\n // If --wait flag is set and we're in an interactive terminal, enter the watch loop\n if (wait && process.stdin.isTTY) {\n while (true) {\n const trigger = await watchFilesAndWait(inputPaths)\n // On spacebar or file change, regenerate\n await executeTasks()\n }\n }\n})()\n\n\n\n", "import ts from 'typescript'\nimport { spawnSync } from 'node:child_process'\nimport { writeFileSync, mkdtempSync, rmSync, readFileSync } from 'node:fs'\nimport { join, isAbsolute } from 'node:path'\nimport { tmpdir } from 'node:os'\n\nexport type ProseNode = { kind: 'prose'; text: string; terminal?: true; noBlankAfter?: true; noBlankBefore?: true }\nexport type CodeNode = { kind: 'code'; lang: string; text: string; title?: string }\nexport type DescribeNode = { kind: 'describe'; name: string; depth: number }\n\nexport type ShellCommandExecution = {\n stdout: string\n outputFiles: Map<string, string>\n exitCode: number\n}\n\nexport type InputFileInfo = { path: string, content: string }\nexport type OutputFileDisplayNode = {\n kind: 'output-file-display'\n path: string\n lang: string\n cmd: string\n inputFiles: Array<InputFileInfo>\n execution?: ShellCommandExecution\n}\nexport type DocNode = ProseNode | CodeNode | OutputFileDisplayNode | DescribeNode\n\nexport function parse(src: string, lang = 'typescript'): DocNode[] {\n if (!src.trim()) return []\n\n const sf = ts.createSourceFile('input.ts', src, ts.ScriptTarget.Latest, true)\n const nodes: DocNode[] = []\n const processedCommentRanges = new Set<number>()\n let pendingFileLabel: string | undefined = undefined\n let lastCommentEnd = 0\n let pendingNewParagraph = false\n\n function extractLeadingComments(pos: number): void {\n const ranges = ts.getLeadingCommentRanges(src, pos) ?? []\n for (const r of ranges) {\n if (processedCommentRanges.has(r.pos)) continue\n processedCommentRanges.add(r.pos)\n const raw = src.slice(r.pos, r.end)\n\n const gap = lastCommentEnd > 0 ? src.slice(lastCommentEnd, r.pos) : ''\n const hasBlankLineBefore = gap !== '' && /^[ \\t\\n]*$/.test(gap) && /\\n[ \\t]*\\n/.test(gap)\n lastCommentEnd = r.end\n\n // Check for // file: directive first\n if (r.kind === ts.SyntaxKind.SingleLineCommentTrivia) {\n const fileMatch = raw.match(/^\\/\\/\\s*file:\\s*(.+)$/)\n if (fileMatch) {\n pendingFileLabel = fileMatch[1]!.trim()\n continue\n }\n }\n\n const prose = commentToProse(raw, r.kind)\n if (prose !== null) {\n if (hasBlankLineBefore && prose === '') {\n pendingNewParagraph = true\n } else if ((hasBlankLineBefore || pendingNewParagraph) && prose !== '') {\n nodes.push({ kind: 'prose', text: prose })\n pendingNewParagraph = false\n } else {\n mergeOrPushProse(nodes, prose)\n }\n }\n }\n }\n\n function visitStatements(statements: ts.NodeArray<ts.Statement>, depth: number = 0, parentBlock?: ts.Block): void {\n for (const stmt of statements) {\n extractLeadingComments(stmt.getFullStart())\n processStatement(stmt, depth)\n }\n \n // Extract trailing comments after the last statement\n if (statements.length > 0 && parentBlock) {\n const lastStatement = statements[statements.length - 1]!\n extractLeadingComments(lastStatement.end)\n }\n }\n\n function processStatement(stmt: ts.Statement, depth: number = 0): void {\n // Check for // keep:full (multi-line statements)\n const fullStmt = getFullStatement(stmt, src)\n if (fullStmt !== null) {\n const title = pendingFileLabel\n pendingFileLabel = undefined\n mergeOrPushCode(nodes, fullStmt, lang, title)\n return\n }\n\n // Check if this statement has // keep comment (single-line)\n const lineText = getStatementLine(stmt, src)\n if (lineText !== null && hasKeepComment(lineText)) {\n const title = pendingFileLabel\n pendingFileLabel = undefined\n const cleanedLine = lineText.replace(/\\s*\\/\\/\\s*keep\\b.*$/, '')\n mergeOrPushCode(nodes, cleanedLine, lang, title)\n return\n }\n\n // Handle import declarations (legacy code path, now handled above)\n if (ts.isImportDeclaration(stmt)) {\n return\n }\n\n // Detect test('name', () => { ... }) calls\n if (ts.isExpressionStatement(stmt)) {\n const expr = stmt.expression\n\n\n\n if (ts.isCallExpression(expr) && ts.isIdentifier(expr.expression)) {\n const name = expr.expression.text\n if (name === 'test' || name === 'it' || name === 'example') {\n const testName = getStringArg(expr, 0)\n const body = getFnBody(expr, 1)\n if (body) {\n const code = extractBodyCode(src, body)\n if (code.trim()) {\n const title = pendingFileLabel\n pendingFileLabel = undefined\n // Check if we can find a prose node with a trailing code fence to merge with\n // (looking past any describe nodes)\n let proseNodeIdx = -1\n for (let i = nodes.length - 1; i >= 0; i--) {\n if (nodes[i]!.kind === 'prose') {\n proseNodeIdx = i\n break\n } else if (nodes[i]!.kind !== 'describe') {\n // Stop if we hit a non-prose, non-describe node\n break\n }\n }\n \n if (proseNodeIdx >= 0) {\n const proseNode = nodes[proseNodeIdx]!\n const fenceMatch = extractTrailingFence((proseNode as any).text)\n if (fenceMatch) {\n (proseNode as any).text = fenceMatch.prose;\n (proseNode as any).noBlankAfter = true\n // Remove any describe nodes between the prose and here\n nodes.splice(proseNodeIdx + 1)\n const mergedCode = fenceMatch.fenceCode + '\\n' + code\n nodes.push(codeNode(lang, mergedCode, title))\n } else if (proseNodeIdx === nodes.length - 1) {\n // Prose directly precedes this code block (no describe nodes in between), suppress blank line\n (proseNode as any).noBlankAfter = true\n nodes.push(codeNode(lang, code, title))\n } else {\n // There are describe nodes between prose and code, don't suppress blank line\n nodes.push(codeNode(lang, code, title))\n }\n } else {\n nodes.push(codeNode(lang, code, title))\n }\n } else if (body && !ts.isBlock(body)) {\n // Expression body that extracted to empty/whitespace - warn about this\n const lines = src.slice(body.getFullStart(), body.getEnd()).split('\\n').length\n if (lines > 2) {\n console.warn(`\u26A0 Warning: ${name}('${testName}') expression body (${lines} lines) did not produce output`)\n }\n }\n return\n }\n }\n if (name === 'describe') {\n const descName = getStringArg(expr, 0)\n const body = getFnBody(expr, 1)\n if (body && ts.isBlock(body) && descName !== null) {\n nodes.push({ kind: 'describe', name: descName, depth })\n visitStatements(body.statements, depth + 1, body)\n return\n }\n }\n if (name === 'metaExample') {\n const body = getFnBody(expr, 1)\n if (body) {\n const code = extractBodyCode(src, body)\n if (code.trim()) {\n const title = pendingFileLabel\n pendingFileLabel = undefined\n // 1. Raw example call (original source, assertions not rewritten)\n const rawCall = dedentCallSource(src.slice(expr.getStart(), expr.getEnd()))\n .replace(/^metaExample\\b/, 'example')\n nodes.push(codeNode(lang, rawCall, title))\n // 2. \"becomes\" prose\n nodes.push({ kind: 'prose', text: 'becomes', noBlankBefore: true, noBlankAfter: true })\n // 3. Rendered output as an md code block\n const langAlias = lang === 'typescript' ? 'ts' : lang === 'javascript' ? 'js' : lang\n const innerFence = `\\`\\`\\`${langAlias}\\n${code}\\n\\`\\`\\``\n nodes.push(codeNode('md', innerFence))\n }\n }\n return\n }\n if (name === 'shellExample') {\n const cmd = getStringArg(expr, 0)\n if (cmd !== null) {\n const title = pendingFileLabel\n pendingFileLabel = undefined\n const optsArg = expr.arguments[1]\n const opts = optsArg && ts.isObjectLiteralExpression(optsArg) ? optsArg : undefined\n\n // Check if meta: true is explicitly set\n const metaProp = opts ? getProp(opts, 'meta') : undefined\n const hasMeta = metaProp && metaProp.initializer.kind === ts.SyntaxKind.TrueKeyword\n \n // If meta is true, add a code block showing the reconstructed shellExample call\n if (hasMeta) {\n const reconstructed = reconstructShellExampleWithoutMeta(src, expr, cmd, opts)\n nodes.push(codeNode('ts', reconstructed))\n // Add \"becomes\" separator\n nodes.push({ kind: 'prose', text: 'becomes', noBlankBefore: true, noBlankAfter: true })\n }\n\n if (opts) processShellExampleInputFiles(opts, nodes)\n\n const inputFiles = opts ? extractStaticInputFiles(opts) : []\n\n const exitCodeProp = opts ? getProp(opts, 'exitCode') : undefined\n const expectedExitCode = exitCodeProp && ts.isNumericLiteral(exitCodeProp.initializer)\n ? parseInt(exitCodeProp.initializer.text, 10)\n : 0\n\n let execution: ShellCommandExecution | null = null\n if (opts && isExecutionNeeded(opts)) {\n const outputPaths = extractOutputFilePaths(opts)\n execution = executeShellCommand(cmd, inputFiles, outputPaths, expectedExitCode)\n }\n\n const displayCommand = opts ? readBoolOption(getProp(opts, 'displayCommand')) : true\n\n const lines: string[] = displayCommand ? [`$ ${cmd}`] : []\n if (opts) appendShellExampleAnnotations(opts, lines, execution)\n if (lines.length > 0) {\n nodes.push(codeNode('sh', lines.join('\\n'), title))\n }\n\n if (opts) processShellExampleOutputFiles(src, opts, nodes, cmd, inputFiles, execution)\n }\n return\n }\n }\n }\n }\n\n visitStatements(sf.statements)\n\n // Capture comments before EOF token\n extractLeadingComments(sf.endOfFileToken.getFullStart())\n\n return nodes\n}\n\n/** Typed helper: find a PropertyAssignment by name in an ObjectLiteralExpression. */\nfunction getProp(obj: ts.ObjectLiteralExpression, name: string): ts.PropertyAssignment | undefined {\n return obj.properties.find(\n (p): p is ts.PropertyAssignment => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === name\n )\n}\n\n/** Returns false if prop's initializer is `false` or the string `'hidden'`, true otherwise. */\nfunction readBoolOption(prop: ts.PropertyAssignment | undefined): boolean {\n if (!prop) return true\n const init = prop.initializer\n if (init.kind === ts.SyntaxKind.FalseKeyword) return false\n if (ts.isStringLiteralLike(init) && init.text === 'hidden') return false\n return true\n}\n\n/** Returns false if prop's initializer is `false`, true otherwise. */\nfunction readFlag(prop: ts.PropertyAssignment | undefined): boolean {\n if (!prop) return true\n return prop.initializer.kind !== ts.SyntaxKind.FalseKeyword\n}\n\n/** Escapes a string value for safe embedding in a TypeScript single-quoted string literal. */\nfunction escapeForSingleQuotedString(s: string): string {\n return s\n .replace(/\\\\/g, '\\\\\\\\') // backslashes must be escaped first\n .replace(/'/g, \"\\\\'\") // then single quotes\n .replace(/\\n/g, '\\\\n') // newlines\n .replace(/\\r/g, '\\\\r') // carriage returns\n}\n\n/** Reconstructs shellExample call without the meta option. */\nfunction reconstructShellExampleWithoutMeta(src: string, expr: ts.CallExpression, cmd: string, opts: ts.ObjectLiteralExpression | undefined): string {\n const escapedCmd = escapeForSingleQuotedString(cmd)\n if (!opts) {\n return `shellExample('${escapedCmd}')`\n }\n\n // Extract options text and remove meta: true\n const optsText = src.slice(opts.getStart(), opts.getEnd())\n \n // Remove \"meta: true,\" or \"meta: true\" variations\n let cleanedOpts = optsText\n .replace(/,?\\s*meta:\\s*true\\s*,?/g, ',') // Remove meta: true with surrounding commas\n .replace(/^\\{\\s*,/, '{') // Remove leading comma after {\n .replace(/,\\s*\\}$/, '}') // Remove trailing comma before }\n \n return `shellExample('${escapedCmd}'${cleanedOpts !== '{}' ? `, ${cleanedOpts}` : ''})`\n}\n\n/** Create a CodeNode, omitting the `title` key entirely when undefined. */\nfunction codeNode(lang: string, text: string, title?: string): CodeNode {\n return title !== undefined ? { kind: 'code', lang, text, title } : { kind: 'code', lang, text }\n}\n\nfunction getStringArg(call: ts.CallExpression, index: number): string | null {\n const arg = call.arguments[index]\n if (arg && ts.isStringLiteralLike(arg)) return arg.text\n return null\n}\n\nfunction getFnBody(call: ts.CallExpression, index: number): ts.Block | ts.Expression | null {\n const arg = call.arguments[index]\n if (!arg) return null\n if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {\n return arg.body\n }\n return null\n}\n\nfunction extractBodyCode(src: string, bodyOrBlock: ts.Block | ts.Expression): string {\n if (!ts.isBlock(bodyOrBlock)) {\n // Expression body - extract the expression as a single \"statement\"\n return src.slice(bodyOrBlock.getFullStart(), bodyOrBlock.getEnd()).trim()\n }\n const stmts = bodyOrBlock.statements\n if (!stmts.length) return ''\n\n // Compute block indentation from the column of the first statement token\n const firstStart = stmts[0]!.getStart()\n const lineStart = src.lastIndexOf('\\n', firstStart - 1) + 1\n const indent = firstStart - lineStart\n\n // Include trailing // comment on the last statement's line\n const lastStmt = stmts[stmts.length - 1]!\n const lastEnd = lastStmt.getEnd()\n const lastLineEnd = src.indexOf('\\n', lastEnd)\n const textAfterLast = src.slice(lastEnd, lastLineEnd === -1 ? src.length : lastLineEnd)\n const extractEnd = /^\\s*\\/\\//.test(textAfterLast)\n ? (lastLineEnd === -1 ? src.length : lastLineEnd)\n : lastEnd\n\n // Extract from the full start of the first statement (includes leading whitespace/comments)\n const base = stmts[0]!.getFullStart()\n let raw = src.slice(base, extractEnd)\n\n // Rewrite recognized assertion statements (end-to-start to preserve offsets)\n const replacements: Array<{ start: number; end: number; text: string }> = []\n for (const stmt of stmts) {\n const rewritten = tryRewriteAssertion(src, stmt, indent)\n if (rewritten !== null) {\n replacements.push({ start: stmt.getStart() - base, end: stmt.getEnd() - base, text: rewritten })\n }\n }\n replacements.sort((a, b) => b.start - a.start)\n for (const r of replacements) {\n raw = raw.slice(0, r.start) + r.text + raw.slice(r.end)\n }\n\n // Dedent: remove `indent` leading spaces from any line that starts with at least that many spaces.\n // Lines with fewer leading spaces (e.g. template literal content) are kept as-is.\n let result = raw\n .split('\\n')\n .map(line => (line.length >= indent && line.slice(0, indent).trim() === '') ? line.slice(indent) : line)\n .join('\\n')\n .trim()\n\n // Clean up excessive blank lines from dropped statements (preserve intentional single blank lines)\n result = result.replace(/\\n\\n\\n+/g, '\\n\\n')\n\n // Transform nested assert.ok(expr) \u2192 expr // OK\n result = transformNestedAssertOk(result)\n\n return result\n}\n\n/** Strip the shared indentation (determined from the closing line) from a raw call source. */\nfunction dedentCallSource(callText: string): string {\n const lines = callText.split('\\n')\n if (lines.length <= 1) return callText\n const lastLine = lines[lines.length - 1]!\n const closingIndent = lastLine.length - lastLine.trimStart().length\n if (closingIndent === 0) return callText\n return lines.map((line, i) => {\n if (i === 0) return line\n return line.length >= closingIndent && line.slice(0, closingIndent).trim() === ''\n ? line.slice(closingIndent)\n : line\n }).join('\\n')\n}\n\nfunction commentToProse(raw: string, kind: ts.CommentKind): string | null {\n if (kind === ts.SyntaxKind.SingleLineCommentTrivia) {\n return raw.replace(/^\\/\\/\\s?/, '')\n }\n if (kind === ts.SyntaxKind.MultiLineCommentTrivia) {\n const inner = raw\n .replace(/^\\/\\*+/, '')\n .replace(/\\*+\\/$/, '')\n .split('\\n')\n .map(l => l.replace(/^\\s*\\*\\s?/, ''))\n .join('\\n')\n .trim()\n return inner || null\n }\n return null\n}\n\nfunction isKeptImport(text: string): boolean {\n return /\\/\\/\\s*keep\\b/.test(text)\n}\n\nfunction hasKeepComment(text: string): boolean {\n return /\\/\\/\\s*keep\\b/.test(text)\n}\n\nfunction isFullKeep(text: string): boolean {\n return /\\/\\/\\s*keep:full\\b/.test(text)\n}\n\n/** Extract the full line text of a statement (from statement start to end of line).\n * Returns null if the statement spans multiple lines or we can't extract it. */\nfunction getStatementLine(stmt: ts.Statement, src: string): string | null {\n const lineEnd = src.indexOf('\\n', stmt.getEnd())\n const lineText = src.slice(stmt.getStart(), lineEnd === -1 ? src.length : lineEnd).trimEnd()\n \n // Check if statement fits on one line (heuristic: doesn't contain opening brace on different line)\n const lines = lineText.split('\\n')\n if (lines.length > 1) {\n // Multi-line statement - for now, only process if it's a simple case\n return null\n }\n \n return lineText\n}\n\n/** Extract a full multi-line statement including body.\n * Searches for // keep:full comment and extracts the entire statement.\n * Returns null if // keep:full not found. */\nfunction getFullStatement(stmt: ts.Statement, src: string): string | null {\n const stmtStart = stmt.getStart()\n const stmtEnd = stmt.getEnd()\n \n // Only check the first line for // keep:full to avoid false positives\n // from the directive appearing in nested comments or string content.\n const firstLineEnd = src.indexOf('\\n', stmtStart)\n const firstLine = src.slice(stmtStart, firstLineEnd === -1 ? src.length : firstLineEnd)\n if (!isFullKeep(firstLine)) {\n return null\n }\n\n // Extract the entire statement\n const stmtText = src.slice(stmtStart, stmtEnd)\n \n // Compute the indentation of the first line to dedent\n const firstLineMatch = stmtText.match(/^(\\s*)/)\n const baseIndent = firstLineMatch ? firstLineMatch[1]!.length : 0\n \n // Dedent all lines by the base indentation\n const dedented = stmtText\n .split('\\n')\n .map(line => {\n if (line.length >= baseIndent && line.slice(0, baseIndent).trim() === '') {\n return line.slice(baseIndent)\n }\n return line\n })\n .join('\\n')\n .trimEnd()\n \n // Strip the // keep:full comment\n const cleaned = dedented.replace(/\\s*\\/\\/\\s*keep:full\\b.*$/gm, '')\n \n return cleaned\n}\n\n/** Rewrite a recognized assert.X(actual, expected) statement to a readable comment form.\n * Returns the rewritten string, or null if the statement is not a recognized assertion.\n * Special case: assert.ok() at statement level returns empty string (drops the line). */\nfunction tryRewriteAssertion(src: string, stmt: ts.Statement, bodyIndent: number): string | null {\n if (!ts.isExpressionStatement(stmt)) return null\n const expr = stmt.expression\n if (!ts.isCallExpression(expr)) return null\n if (!ts.isPropertyAccessExpression(expr.expression)) return null\n\n const obj = expr.expression.expression\n const method = expr.expression.name.text\n if (!ts.isIdentifier(obj) || obj.text !== 'assert') return null\n\n // assert.ok(value) at statement level \u2192 drop the line (empty string)\n if (method === 'ok') {\n return ''\n }\n\n // assert.throws(() => expr, pattern?) \u2192 expr // throws [pattern]\n if (method === 'throws') {\n const fn = expr.arguments[0]\n if (!fn) return null\n if (ts.isArrowFunction(fn) && !ts.isBlock(fn.body)) {\n const exprText = src.slice(fn.body.getStart(), fn.body.getEnd())\n const patternArg = expr.arguments[1]\n const patternText = patternArg ? src.slice(patternArg.getStart(), patternArg.getEnd()) : null\n return patternText ? `${exprText} // throws ${patternText}` : `${exprText} // throws`\n }\n return null\n }\n\n const [actual, expected] = expr.arguments\n if (!actual || !expected) return null\n\n if (['equal', 'strictEqual', 'deepEqual', 'deepStrictEqual'].includes(method)) {\n return formatComparison(src, actual, expected, '=>', bodyIndent)\n }\n if (['notEqual', 'notStrictEqual', 'notDeepEqual', 'notDeepStrictEqual'].includes(method)) {\n return formatComparison(src, actual, expected, '!=', bodyIndent)\n }\n\n return null\n}\n\nfunction formatComparison(\n src: string,\n actual: ts.Expression,\n expected: ts.Expression,\n op: string,\n bodyIndent: number\n): string {\n const actualText = src.slice(actual.getStart(), actual.getEnd())\n const expectedRaw = src.slice(expected.getStart(), expected.getEnd())\n\n // Dedent continuation lines by their minimum indentation\n const expectedText = dedentContinuationLines(expectedRaw)\n\n const lines = expectedText.split('\\n')\n if (lines.length === 1) {\n return `${actualText} // ${op} ${expectedText}`\n }\n // Multi-line: first line appended to actual, remaining lines become // comments\n // Continuation lines are indented so that `//` aligns with the opening `//` after dedenting\n const first = lines[0]!\n const indent = ' '.repeat(actualText.length + 1 + bodyIndent)\n const rest = lines.slice(1).map(l => `${indent}// ${l}`)\n return [`${actualText} // ${op} ${first}`, ...rest].join('\\n')\n}\n\n/** Dedent continuation lines (lines after the first) by their minimum indentation. */\nfunction dedentContinuationLines(text: string): string {\n const lines = text.split('\\n')\n if (lines.length === 1) return text\n const contLines = lines.slice(1).filter(l => l.trim().length > 0)\n if (!contLines.length) return text\n const minInd = Math.min(...contLines.map(l => l.length - l.trimStart().length))\n if (minInd === 0) return text\n return [\n lines[0]!,\n ...lines.slice(1).map(l => (l.length >= minInd && l.slice(0, minInd).trim() === '') ? l.slice(minInd) : l)\n ].join('\\n')\n}\n\n\n/** If prose ends with a ```\u2026``` fence, split it off. Returns null if no trailing fence. */\nfunction extractTrailingFence(prose: string): { prose: string; fenceCode: string } | null {\n // Match a trailing fenced code block: ```(lang)?\\n...\\n```\n const match = prose.match(/^([\\s\\S]*?)\\n?```[^\\n]*\\n([\\s\\S]*?)```\\s*$/)\n if (!match) return null\n return {\n prose: match[1]!.trimEnd(),\n fenceCode: match[2]!.trimEnd()\n }\n}\n\nfunction mergeOrPushCode(nodes: DocNode[], text: string, lang: string, title: string | undefined): void {\n const last = nodes[nodes.length - 1]\n // Merge consecutive kept imports into one code block\n if (last?.kind === 'code' && last.title === undefined && title === undefined) {\n last.text = last.text + '\\n' + text\n } else {\n nodes.push(codeNode(lang, text, title))\n }\n}\n\nfunction mergeOrPushProse(nodes: DocNode[], text: string): void {\n const last = nodes[nodes.length - 1]\n if (last?.kind === 'prose' && !last.terminal) {\n last.text = last.text + '\\n' + text\n } else {\n nodes.push({ kind: 'prose', text })\n }\n}\n\n/** Transform nested assert.ok(expr) calls to expr // OK */\nfunction transformNestedAssertOk(code: string): string {\n // Heuristic: replaces assert.ok(expr) \u2192 expr // OK; may miss complex cases\n return code.replace(/assert\\.ok\\(([^)]+)\\)/g, '$1 // OK')\n}\n\n\n\n/** Helper to detect language from file extension */\nfunction getLanguageFromExtension(filePath: string): string {\n const ext = filePath.split('.').pop()?.toLowerCase() || ''\n const langMap: Record<string, string> = {\n ts: 'typescript',\n tsx: 'typescript',\n js: 'javascript',\n jsx: 'javascript',\n json: 'json',\n md: 'markdown',\n yaml: 'yaml',\n yml: 'yaml',\n sh: 'sh',\n bash: 'bash',\n py: 'python',\n rs: 'rust',\n go: 'go',\n java: 'java',\n cs: 'csharp',\n rb: 'ruby',\n php: 'php',\n html: 'html',\n css: 'css',\n xml: 'xml',\n txt: 'text'\n }\n return langMap[ext] || ext || 'text'\n}\n\n/** Helper to detect if a language supports C-style comments (// ...) */\nfunction supportsCStyleComments(lang: string): boolean {\n const cStyleLangs = new Set([\n 'typescript', 'javascript', 'java', 'csharp', 'go', 'rust',\n 'cpp', 'c', 'objc', 'swift', 'kotlin', 'scala', 'groovy'\n ])\n return cStyleLangs.has(lang)\n}\n\n/** Extracts input files from shellExample options and creates separate code blocks */\nfunction processShellExampleInputFiles(opts: ts.ObjectLiteralExpression, nodes: DocNode[]): void {\n const inputFilesProp = getProp(opts, 'inputFiles')\n \n if (!inputFilesProp || !ts.isArrayLiteralExpression(inputFilesProp.initializer)) {\n return\n }\n\n for (const el of inputFilesProp.initializer.elements) {\n if (!ts.isObjectLiteralExpression(el)) continue\n const pathProp = getProp(el, 'path')\n const contentProp = getProp(el, 'content')\n const displayPathProp = getProp(el, 'displayPath')\n const summaryProp = getProp(el, 'summary')\n const displayProp = getProp(el, 'display')\n const displayContent = readBoolOption(displayProp)\n\n if (!pathProp || !ts.isStringLiteralLike(pathProp.initializer)) continue\n const filePath = pathProp.initializer.text\n\n const displayPath = readBoolOption(displayPathProp)\n const summary = readFlag(summaryProp)\n\n if (contentProp && displayContent && ts.isStringLiteralLike(contentProp.initializer)) {\n const content = contentProp.initializer.text\n const lang = getLanguageFromExtension(filePath)\n \n // Add label/prose based on language type (only if summary and displayPath are true)\n if (!supportsCStyleComments(lang) && displayPath && summary) {\n // Non-C-style: add prose label before code block\n nodes.push({ kind: 'prose', text: `With input file \\`${filePath}\\`:`, noBlankAfter: true })\n }\n \n // Create code block with label for C-style languages (only if summary and displayPath are true)\n let blockText = content\n if (supportsCStyleComments(lang) && displayPath && summary) {\n blockText = `// Input file \"${filePath}\":\\n${content}`\n }\n \n nodes.push({ kind: 'code', lang, text: blockText })\n }\n }\n}\n\nconst OUTPUT_FILE_INLINE_LIMIT = 60\n\n/** Emits separate prose/code nodes for output file assertions, after the sh block */\nfunction processShellExampleOutputFiles(\n src: string,\n opts: ts.ObjectLiteralExpression,\n nodes: DocNode[],\n cmd: string,\n inputFiles: Array<InputFileInfo>,\n execution: ShellCommandExecution | null\n): void {\n const outputFilesProp = getProp(opts, 'outputFiles')\n\n if (!outputFilesProp || !ts.isArrayLiteralExpression(outputFilesProp.initializer)) {\n return\n }\n\n for (const el of outputFilesProp.initializer.elements) {\n if (!ts.isObjectLiteralExpression(el)) continue\n const pathProp = getProp(el, 'path')\n const containsProp = getProp(el, 'contains')\n const matchesProp = getProp(el, 'matches')\n const displayProp = getProp(el, 'display')\n const displayPathProp = getProp(el, 'displayPath')\n const summaryProp = getProp(el, 'summary')\n \n const display = displayProp && ts.isStringLiteralLike(displayProp.initializer)\n ? displayProp.initializer.text : undefined\n\n if (!pathProp || !ts.isStringLiteralLike(pathProp.initializer)) continue\n const filePath = pathProp.initializer.text\n const lang = getLanguageFromExtension(filePath)\n\n const displayPath = readBoolOption(displayPathProp)\n const summary = readFlag(summaryProp)\n\n let emitDisplayNode = display !== 'none'\n\n if (matchesProp && ts.isRegularExpressionLiteral(matchesProp.initializer)) {\n if (summary) {\n const regexText = src.slice(matchesProp.initializer.getStart(), matchesProp.initializer.getEnd())\n const proseText = displayPath \n ? `Output file \\`${filePath}\\` matches \\`${regexText}\\`.`\n : `Matches \\`${regexText}\\`.`\n nodes.push({ kind: 'prose', text: proseText, terminal: true })\n }\n } else if (containsProp && ts.isStringLiteralLike(containsProp.initializer)) {\n const text = containsProp.initializer.text\n const isMultiLine = text.includes('\\n')\n if (!isMultiLine && text.length < OUTPUT_FILE_INLINE_LIMIT) {\n // Short single-line: backtick format\n if (summary) {\n const proseText = displayPath\n ? `Output file \\`${filePath}\\` contains \\`${text}\\`.`\n : `Contains \\`${text}\\`.`\n nodes.push({ kind: 'prose', text: proseText, terminal: true })\n }\n } else {\n // Truncate to 60 chars or first newline for the summary\n const firstNewline = text.indexOf('\\n')\n const truncateAt = isMultiLine ? Math.min(firstNewline, OUTPUT_FILE_INLINE_LIMIT) : OUTPUT_FILE_INLINE_LIMIT\n const truncated = text.slice(0, truncateAt)\n if (isMultiLine) {\n // Multi-line: colon + excerpt code block; no display node (excerpt IS the content spec)\n if (summary) {\n const proseText = displayPath\n ? `Output file \\`${filePath}\\` contains ${truncated}...:`\n : `Contains ${truncated}...:`\n nodes.push({ kind: 'prose', text: proseText, terminal: true, noBlankAfter: true })\n }\n nodes.push({ kind: 'code', lang, text: `...\\n${text}\\n...` })\n emitDisplayNode = false\n } else {\n // Long single-line: truncated summary, period\n if (summary) {\n const proseText = displayPath\n ? `Output file \\`${filePath}\\` contains ${truncated}....`\n : `Contains ${truncated}....`\n nodes.push({ kind: 'prose', text: proseText, terminal: true })\n }\n }\n }\n } else {\n // Neither contains nor matches: display the full file contents\n if (summary) {\n const proseText = displayPath\n ? `Output file \\`${filePath}\\`:`\n : `Output:`\n nodes.push({ kind: 'prose', text: proseText, terminal: true, noBlankAfter: true })\n }\n emitDisplayNode = true\n }\n\n if (emitDisplayNode) {\n const node: OutputFileDisplayNode = { kind: 'output-file-display', path: filePath, lang, cmd, inputFiles }\n if (execution) {\n node.execution = execution\n }\n nodes.push(node)\n }\n }\n}\n\n/** Extracts inputFiles entries statically from a shellExample opts AST node */\nfunction extractStaticInputFiles(opts: ts.ObjectLiteralExpression): Array<InputFileInfo> {\n const inputFilesProp = getProp(opts, 'inputFiles')\n if (!inputFilesProp || !ts.isArrayLiteralExpression(inputFilesProp.initializer)) return []\n const result: Array<InputFileInfo> = []\n for (const el of inputFilesProp.initializer.elements) {\n if (!ts.isObjectLiteralExpression(el)) continue\n const pathProp = getProp(el, 'path')\n const contentProp = getProp(el, 'content')\n if (!pathProp || !ts.isStringLiteralLike(pathProp.initializer)) continue\n if (!contentProp || !ts.isStringLiteralLike(contentProp.initializer)) continue\n result.push({ path: pathProp.initializer.text, content: contentProp.initializer.text })\n }\n return result\n}\n\n/** Determines if command execution is needed based on shellExample options */\nfunction isExecutionNeeded(opts: ts.ObjectLiteralExpression): boolean {\n // Check if stdout.display is true\n const stdoutProp = getProp(opts, 'stdout')\n if (stdoutProp && ts.isObjectLiteralExpression(stdoutProp.initializer)) {\n const displayProp = getProp(stdoutProp.initializer as ts.ObjectLiteralExpression, 'display')\n if (displayProp && displayProp.initializer.kind === ts.SyntaxKind.TrueKeyword) {\n return true\n }\n }\n\n // Check if any outputFiles need display\n const outputFilesProp = getProp(opts, 'outputFiles')\n if (!outputFilesProp || !ts.isArrayLiteralExpression(outputFilesProp.initializer)) {\n return false\n }\n\n for (const el of outputFilesProp.initializer.elements) {\n if (!ts.isObjectLiteralExpression(el)) continue\n const displayProp = getProp(el, 'display')\n const containsProp = getProp(el, 'contains')\n const matchesProp = getProp(el, 'matches')\n \n // display !== 'none' means we need to execute\n const display = displayProp && ts.isStringLiteralLike(displayProp.initializer)\n ? displayProp.initializer.text : undefined\n \n // Need execution if display is not 'none' AND (no contains/matches OR they're multi-line)\n if (display !== 'none') {\n const hasMatches = matchesProp && ts.isRegularExpressionLiteral(matchesProp.initializer)\n\n if (!containsProp && !hasMatches) {\n // No inline assertion - need to execute to get full file content\n return true\n }\n if (containsProp && ts.isStringLiteralLike(containsProp.initializer)) {\n const text = containsProp.initializer.text\n if (text.includes('\\n') || text.length >= OUTPUT_FILE_INLINE_LIMIT) {\n // Multi-line or long content - need to execute\n return true\n }\n }\n }\n }\n\n return false\n}\n\n/** Extracts output file paths from shellExample options that need execution */\nfunction extractOutputFilePaths(opts: ts.ObjectLiteralExpression): string[] {\n const outputFilesProp = getProp(opts, 'outputFiles')\n if (!outputFilesProp || !ts.isArrayLiteralExpression(outputFilesProp.initializer)) {\n return []\n }\n\n const paths: string[] = []\n for (const el of outputFilesProp.initializer.elements) {\n if (!ts.isObjectLiteralExpression(el)) continue\n const pathProp = getProp(el, 'path')\n if (pathProp && ts.isStringLiteralLike(pathProp.initializer)) {\n paths.push(pathProp.initializer.text)\n }\n }\n return paths\n}\n\n/** Executes a shell command with optional input files and captures stdout + output files */\nfunction executeShellCommand(cmd: string, inputFiles: Array<InputFileInfo>, outputFilePaths: string[], expectedExitCode = 0): ShellCommandExecution | null {\n const tmpDir = mkdtempSync(join(tmpdir(), 'lit-md-exec-'))\n const resolvePath = (p: string) => isAbsolute(p) ? p : join(tmpDir, p)\n try {\n // Write input files\n for (const f of inputFiles) {\n writeFileSync(resolvePath(f.path), f.content, 'utf8')\n }\n\n // Execute command\n const result = spawnSync(cmd, { shell: true, encoding: 'utf8', cwd: tmpDir })\n \n // Capture output files when exit code matches expectation\n const outputFiles = new Map<string, string>()\n if ((result.status ?? 1) === expectedExitCode) {\n for (const filePath of outputFilePaths) {\n try {\n const content = readFileSync(resolvePath(filePath), 'utf8')\n outputFiles.set(filePath, content)\n } catch {\n // File doesn't exist or can't be read - skip it\n }\n }\n }\n\n return {\n stdout: result.stdout.trimEnd(),\n outputFiles,\n exitCode: result.status ?? 1\n }\n } catch (e) {\n return null\n } finally {\n rmSync(tmpDir, { recursive: true, force: true })\n }\n}\n\n/** Reads shellExample options and appends annotation lines (# => ..., single-line # input-file: ...) */\nfunction appendShellExampleAnnotations(\n opts: ts.ObjectLiteralExpression,\n lines: string[],\n execution: ShellCommandExecution | null\n): void {\n for (const prop of opts.properties) {\n if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue\n const key = prop.name.text\n\n if (key === 'exitCode' && ts.isNumericLiteral(prop.initializer)) {\n const code = parseInt(prop.initializer.text, 10)\n if (code !== 0) {\n lines.push(`# exits: ${code}`)\n }\n }\n\n if (key === 'stdout' && ts.isObjectLiteralExpression(prop.initializer)) {\n const containsProp = getProp(prop.initializer as ts.ObjectLiteralExpression, 'contains')\n const displayProp = getProp(prop.initializer as ts.ObjectLiteralExpression, 'display')\n \n // If display is true, use cached execution or show the contains assertion\n if (displayProp && displayProp.initializer.kind === ts.SyntaxKind.TrueKeyword) {\n if (execution && execution.exitCode === 0) {\n lines.push(execution.stdout)\n }\n } else if (containsProp && ts.isStringLiteralLike(containsProp.initializer)) {\n // Show contains assertion only if display is not true\n lines.push(containsProp.initializer.text)\n }\n }\n\n if (key === 'inputFiles' && ts.isArrayLiteralExpression(prop.initializer)) {\n for (const el of prop.initializer.elements) {\n if (!ts.isObjectLiteralExpression(el)) continue\n const pathProp = getProp(el, 'path')\n const contentProp = getProp(el, 'content')\n const displayPathProp = getProp(el, 'displayPath')\n const summaryProp = getProp(el, 'summary')\n\n if (!pathProp || !ts.isStringLiteralLike(pathProp.initializer)) continue\n const filePath = pathProp.initializer.text\n\n const displayPath = readBoolOption(displayPathProp)\n const summary = readFlag(summaryProp)\n\n if (contentProp && ts.isStringLiteralLike(contentProp.initializer)) {\n const content = contentProp.initializer.text\n const lang = getLanguageFromExtension(filePath)\n // Only add single-line annotation for C-style languages; others emit a separate code block\n // Skip if displayPath or summary is false\n if (!content.includes('\\n') && supportsCStyleComments(lang) && displayPath && summary) {\n lines.push(`# Input file \\`${filePath}\\` contains \\`${content}\\``)\n }\n }\n }\n }\n }\n}\n", "import type { DocNode, CodeNode } from './parser.ts'\n\nconst langAliases: Record<string, string> = {\n typescript: 'ts',\n javascript: 'js',\n}\n\n/** Merges consecutive code blocks of the same language */\nfunction mergeConsecutiveCodeBlocks(nodes: DocNode[]): DocNode[] {\n if (nodes.length === 0) return nodes\n \n const result: DocNode[] = []\n let currentCodeBlock: CodeNode | null = null\n \n for (const node of nodes) {\n if (node.kind === 'code') {\n if (currentCodeBlock && currentCodeBlock.lang === node.lang && !currentCodeBlock.title && !node.title) {\n // Merge with current block\n currentCodeBlock.text += '\\n\\n' + node.text\n } else {\n // Save previous block and start new one\n if (currentCodeBlock) result.push(currentCodeBlock)\n currentCodeBlock = { ...node }\n }\n } else {\n // Non-code node: flush current block and add this node\n if (currentCodeBlock) {\n result.push(currentCodeBlock)\n currentCodeBlock = null\n }\n result.push(node)\n }\n }\n \n // Don't forget the last code block\n if (currentCodeBlock) result.push(currentCodeBlock)\n \n return result\n}\n\nexport function render(nodes: DocNode[], describeFormat: string = 'hidden'): string {\n const merged = mergeConsecutiveCodeBlocks(nodes.filter(n => n.kind !== 'output-file-display'))\n if (!merged.length) return ''\n let out = ''\n let lastHeaderLevel = 0\n for (let i = 0; i < merged.length; i++) {\n if (i > 0) {\n const prev = merged[i - 1]!\n const curr = merged[i]!\n const noBlank = (prev.kind === 'prose' && prev.noBlankAfter) ||\n (curr.kind === 'prose' && curr.noBlankBefore)\n out += noBlank ? '\\n' : '\\n\\n'\n }\n const rendered = renderNode(merged[i]!, describeFormat, lastHeaderLevel)\n out += rendered\n // Update lastHeaderLevel after rendering\n const node = merged[i]!\n if (node.kind === 'describe' && describeFormat !== 'hidden') {\n const baseLevel = describeFormat === 'auto' ? lastHeaderLevel : describeFormat.length\n lastHeaderLevel = baseLevel + node.depth\n lastHeaderLevel = Math.min(lastHeaderLevel, 6)\n } else if (node.kind === 'prose') {\n // Check for headers in prose and update lastHeaderLevel\n const proseHeaderLevel = getMaxHeaderLevelInProse(node.text)\n if (proseHeaderLevel > 0) {\n lastHeaderLevel = proseHeaderLevel\n }\n }\n }\n return out\n}\n\nfunction renderNode(node: DocNode, describeFormat: string = 'hidden', lastHeaderLevel: number = 0): string {\n if (node.kind === 'prose') return node.text\n if (node.kind === 'output-file-display') return ''\n if (node.kind === 'describe') {\n if (describeFormat === 'hidden') return ''\n let baseLevel: number\n if (describeFormat === 'auto') {\n // If no headers yet, start at h1. Otherwise, go one level deeper than last header\n baseLevel = lastHeaderLevel === 0 ? 1 : lastHeaderLevel + 1\n } else {\n // Explicit format (e.g., \"#\", \"##\", etc.)\n baseLevel = describeFormat.length > 0 ? describeFormat.length : 1\n }\n const level = baseLevel + node.depth\n const hashes = '#'.repeat(Math.min(level, 6))\n return `${hashes} ${node.name}`\n }\n const lang = langAliases[node.lang] ?? node.lang\n // Omit language if it's 'text'\n const info = lang === 'text' ? (node.title ?? '') : (node.title ? `${lang} ${node.title}` : lang)\n \n // Use dynamic fence delimiters to handle nested code blocks\n // Find the longest sequence of backticks in the content\n const maxBackticks = findMaxBacktickSequence(node.text)\n const fenceLength = Math.max(3, maxBackticks + 1)\n const fence = '`'.repeat(fenceLength)\n \n return `${fence}${info}\\n${node.text}\\n${fence}`\n}\n\nfunction findMaxBacktickSequence(text: string): number {\n let maxSeq = 0\n let currentSeq = 0\n for (const char of text) {\n if (char === '`') {\n currentSeq++\n maxSeq = Math.max(maxSeq, currentSeq)\n } else {\n currentSeq = 0\n }\n }\n return maxSeq\n}\n\n/** Detects the maximum header level in prose text (1-6) */\nfunction getMaxHeaderLevelInProse(text: string): number {\n let maxLevel = 0\n const lines = text.split('\\n')\n for (const line of lines) {\n // Match lines that start with # characters\n const match = line.match(/^(#+)\\s/)\n if (match) {\n const level = match[1].length\n maxLevel = Math.max(maxLevel, Math.min(level, 6))\n }\n }\n return maxLevel\n}\n", "import ts from 'typescript'\nimport { join } from 'path'\n\nexport interface TypecheckResult {\n ok: boolean\n messages: string[]\n}\n\nexport function typecheck(files: string[]): TypecheckResult {\n // Only look for tsconfig.json in the exact CWD (no upward walk).\n // This matches the user's expectation: run lit-md from the project root,\n // and if a tsconfig.json is there, it will be used.\n const tsConfigPath = join(process.cwd(), 'tsconfig.json')\n const configPath = ts.sys.fileExists(tsConfigPath) ? tsConfigPath : undefined\n\n let compilerOptions: ts.CompilerOptions\n\n if (configPath) {\n const configFile = ts.readConfigFile(configPath, ts.sys.readFile)\n if (configFile.error) {\n return { ok: false, messages: [ts.flattenDiagnosticMessageText(configFile.error.messageText, '\\n')] }\n }\n const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, ts.sys.getCurrentDirectory())\n compilerOptions = { ...parsed.options, noEmit: true }\n } else {\n // Sensible defaults when no tsconfig.json is present\n compilerOptions = {\n strict: true,\n noEmit: true,\n module: ts.ModuleKind.NodeNext,\n moduleResolution: ts.ModuleResolutionKind.NodeNext,\n target: ts.ScriptTarget.ESNext,\n allowImportingTsExtensions: true,\n }\n }\n\n const program = ts.createProgram(files, compilerOptions)\n const diagnostics = ts.getPreEmitDiagnostics(program)\n\n if (!diagnostics.length) return { ok: true, messages: [] }\n\n // Use TypeScript's built-in formatting with colors and context for better readability\n const formatted = ts.formatDiagnosticsWithColorAndContext(diagnostics, {\n getCanonicalFileName: fileName => fileName,\n getCurrentDirectory: () => process.cwd(),\n getNewLine: () => '\\n',\n })\n\n return { ok: false, messages: [formatted] }\n}\n\n", "import { spawnSync } from 'node:child_process'\nimport { readFileSync, writeFileSync, unlinkSync, mkdtempSync, rmSync, existsSync } from 'node:fs'\nimport { isAbsolute, resolve, join, dirname, extname } from 'node:path'\nimport { tmpdir } from 'node:os'\nimport { test, describe } from 'node:test'\nimport assert from 'node:assert/strict'\n\nexport { test as example, test as metaExample, describe } from 'node:test'\n\n// Module-level alias registry: name \u2192 resolved shell command string\nconst _aliases = new Map<string, string>()\n\n/**\n * Register a shell alias. `cmdString` may be a plain path or a command with\n * arguments (e.g. `'node --experimental-strip-types ./cli.ts'`). Any token\n * that looks like a file path (contains `/` or starts with `.`) is resolved\n * relative to `process.cwd()` at call time. The resulting alias is prepended\n * to every shell command executed by `shellExample`.\n *\n * Alias calls produce **no markdown output**.\n */\nexport function alias(name: string, cmdString: string): void {\n const resolved = resolveCmdPath(cmdString)\n _aliases.set(name, resolved)\n}\n\n/** Internal: clear all registered aliases. Used in tests for isolation. */\nexport function _clearAliases(): void {\n _aliases.clear()\n}\n\n/** Resolve path-like tokens in a command string to absolute paths. */\nfunction resolveCmdPath(cmdString: string): string {\n return cmdString.replace(/\\S+/g, token => {\n if (token.startsWith('/') || token.startsWith('./') || token.startsWith('../') ||\n (!isAbsolute(token) && token.includes('/'))) {\n return resolve(process.cwd(), token)\n }\n return token\n })\n}\n\n/** Build shell alias prefix lines to prepend to commands. */\nfunction buildAliasPrefix(): string {\n if (_aliases.size === 0) return ''\n const lines = [..._aliases.entries()].map(([name, cmd]) => `alias ${name}='${cmd}'`)\n return lines.join('\\n') + '\\n'\n}\n\n/** Check if content matches a pattern (string or regex). */\nfunction matchesPattern(content: string, pattern: string | RegExp): boolean {\n return pattern instanceof RegExp ? pattern.test(content) : content.includes(pattern)\n}\n\nexport interface ShellFileAssertion {\n path: string\n contains?: string | RegExp\n matches?: string | RegExp\n displayPath?: boolean | 'hidden'\n summary?: boolean\n}\n\ntype ExampleInputFile = {\n path: string;\n content: string;\n displayPath?: boolean | 'hidden';\n display?: boolean | 'hidden';\n summary?: boolean\n}\n\nexport interface ShellExampleOpts {\n stdout?: { contains?: string | RegExp; matches?: string | RegExp; display?: boolean }\n outputFiles?: ShellFileAssertion[]\n inputFiles?: Array<ExampleInputFile>\n displayCommand?: boolean | 'hidden'\n meta?: boolean\n exitCode?: number\n timeout?: number // Timeout in milliseconds, default 3000\n}\n\n/** Internal: executes a shell command and runs any assertions. Throws on failure.\n * Exported for direct testing. */\nexport function _runShellExample(cmd: string, opts: ShellExampleOpts): void {\n const tmpDir = mkdtempSync(join(tmpdir(), 'lit-md-shell-'))\n const resolvePath = (p: string) => isAbsolute(p) ? p : join(tmpDir, p)\n try {\n for (const f of opts.inputFiles ?? []) {\n writeFileSync(resolvePath(f.path), f.content, 'utf8')\n }\n const prefix = buildAliasPrefix()\n const fullCmd = prefix ? `${prefix}${cmd}` : cmd\n const timeoutMs = opts.timeout ?? 3000\n const result = spawnSync(fullCmd, { shell: true, encoding: 'utf8', cwd: tmpDir, timeout: timeoutMs })\n \n // Check for timeout error\n if (result.error && (result.error as NodeJS.ErrnoException).code === 'ETIMEDOUT') {\n throw new Error(`Command timed out after ${timeoutMs}ms: ${cmd}`)\n }\n \n const actualExitCode = result.status ?? 1\n if (opts.exitCode !== undefined) {\n if (actualExitCode !== opts.exitCode) {\n const err = result.stderr || result.error?.message || ''\n throw new Error(`Command failed: ${cmd}\\nexit ${actualExitCode} (expected exit code ${opts.exitCode})${err ? ': ' + err : ''}`)\n }\n } else if (actualExitCode !== 0) {\n const err = result.stderr || result.error?.message || ''\n throw new Error(`Command failed: ${cmd}\\nexit ${actualExitCode}${err ? ': ' + err : ''}`)\n }\n const stdout = result.stdout\n if (opts.stdout !== undefined) {\n if (opts.stdout.contains !== undefined) {\n const actualDesc = stdout === '' ? '(empty)' : stdout\n assert.ok(\n matchesPattern(stdout, opts.stdout.contains),\n `stdout did not contain: ${JSON.stringify(opts.stdout.contains)}\\nActual: ${actualDesc}`\n )\n }\n if (opts.stdout.matches !== undefined) {\n const actualDesc = stdout === '' ? '(empty)' : stdout\n assert.ok(\n matchesPattern(stdout, opts.stdout.matches),\n `stdout did not match: ${opts.stdout.matches}\\nActual: ${actualDesc}`\n )\n }\n }\n for (const fa of opts.outputFiles ?? []) {\n let content: string\n try {\n content = readFileSync(resolvePath(fa.path), 'utf8')\n } catch (e) {\n const err = e as NodeJS.ErrnoException\n if (err.code === 'ENOENT') {\n throw new Error(`Output file not found: ${fa.path}\\n\\nThe command may not have created this file, or it may be in a different location.\\nCommand: ${cmd}`)\n }\n throw e\n }\n const actualDesc = content === '' ? '(empty)' : content\n if (fa.contains !== undefined) {\n assert.ok(\n matchesPattern(content, fa.contains),\n `file ${fa.path} does not contain: ${JSON.stringify(fa.contains)}\\nActual:\\n${actualDesc}`\n )\n }\n if (fa.matches !== undefined) {\n assert.ok(\n matchesPattern(content, fa.matches),\n `file ${fa.path} does not match: ${fa.matches}\\nActual:\\n${actualDesc}`\n )\n }\n }\n // Clean up absolute-path inputFiles (relative ones are removed with tmpDir below)\n for (const f of opts.inputFiles ?? []) {\n if (isAbsolute(f.path)) try { unlinkSync(f.path) } catch {}\n }\n } finally {\n rmSync(tmpDir, { recursive: true, force: true })\n }\n}\n\n\n\n/** Registers a node:test test that executes the shell command and verifies assertions. */\nexport function shellExample(cmd: string, opts: ShellExampleOpts = {}): void {\n const timeoutMs = opts.timeout ?? 3000\n test(cmd, { timeout: timeoutMs }, () => _runShellExample(cmd, opts))\n}\n\n/**\n * Returns `'--experimental-strip-types'` on Node.js versions where the flag is required\n * (v22.6\u2013v23.5), or `''` on versions where TypeScript stripping is stable (v23.6+).\n */\nexport function stripTypesFlag(): string {\n const parts = process.versions.node.split('.')\n const major = parseInt(parts[0] ?? '0', 10)\n const minor = parseInt(parts[1] ?? '0', 10)\n if (major === 22 && minor >= 6) return '--experimental-strip-types'\n if (major === 23 && minor < 6) return '--experimental-strip-types'\n return ''\n}\n\n/**\n * Extract import paths from a TypeScript/JavaScript file using regex.\n * Returns absolute paths to files that could be imported.\n */\nfunction extractImportPaths(filePath: string, baseDir: string): Set<string> {\n const importedPaths = new Set<string>()\n try {\n const content = readFileSync(filePath, 'utf8')\n \n // Match import statements: import ... from 'path' or \"path\"\n const importRegex = /import\\s+(?:(?:{[^}]*})|(?:\\*\\s+as\\s+\\w+)|(?:\\w+))?(?:\\s*,\\s*(?:{[^}]*}|\\*\\s+as\\s+\\w+|\\w+))*\\s+from\\s+['\"]([^'\"]+)['\"]/g\n \n // Match require statements: require('path') or require(\"path\")\n const requireRegex = /require\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g\n \n let match\n while ((match = importRegex.exec(content)) !== null) {\n const importPath = match[1]\n if (importPath && !importPath.startsWith('.') && !importPath.startsWith('/')) {\n // Skip node_modules and absolute imports\n continue\n }\n const resolved = resolveImportPath(importPath, baseDir)\n if (resolved) importedPaths.add(resolved)\n }\n \n while ((match = requireRegex.exec(content)) !== null) {\n const importPath = match[1]\n if (importPath && !importPath.startsWith('.') && !importPath.startsWith('/')) {\n continue\n }\n const resolved = resolveImportPath(importPath, baseDir)\n if (resolved) importedPaths.add(resolved)\n }\n } catch {\n // If we can't read the file, skip it\n }\n \n return importedPaths\n}\n\n/**\n * Resolve an import path to an actual file path.\n * Handles .ts, .js, .tsx, .jsx extensions and directory index files.\n */\nfunction resolveImportPath(importPath: string, baseDir: string): string | null {\n const basePath = resolve(baseDir, importPath)\n \n // Try the path as-is\n if (existsSync(basePath)) return basePath\n \n // Try with common extensions\n for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {\n if (existsSync(basePath + ext)) {\n return basePath + ext\n }\n }\n \n // Try as a directory with index file\n for (const indexFile of ['index.ts', 'index.tsx', 'index.js', 'index.jsx']) {\n const indexPath = join(basePath, indexFile)\n if (existsSync(indexPath)) {\n return indexPath\n }\n }\n \n return null\n}\n\n/**\n * Recursively collect all dependencies of input files.\n * Returns a set of all files that should be watched.\n */\nfunction collectAllDependencies(inputPaths: string[], visited = new Set<string>()): Set<string> {\n const allDeps = new Set<string>(inputPaths.map(p => resolve(p)))\n const toProcess = [...inputPaths]\n \n while (toProcess.length > 0) {\n const current = toProcess.shift()!\n const resolvedCurrent = resolve(current)\n \n if (visited.has(resolvedCurrent)) continue\n visited.add(resolvedCurrent)\n \n const deps = extractImportPaths(resolvedCurrent, dirname(resolvedCurrent))\n for (const dep of deps) {\n allDeps.add(dep)\n if (!visited.has(dep)) {\n toProcess.push(dep)\n }\n }\n }\n \n return allDeps\n}\n\n/**\n * Watch input files for changes and listen for keyboard input.\n * Returns 'spacebar' if user presses spacebar, or 'filechange' if a file changes.\n * Exit cleanly on Ctrl+C (SIGINT). Gracefully handles non-TTY environments by\n * resolving immediately.\n */\nexport async function watchFilesAndWait(inputPaths: string[]): Promise<'spacebar' | 'filechange'> {\n // Check if stdin is a TTY (interactive terminal)\n if (!process.stdin.isTTY) {\n // Non-interactive environment: resolve immediately without waiting\n return 'spacebar'\n }\n\n const { watch } = await import('node:fs')\n\n let lastChangeTime = 0\n const DEBOUNCE_MS = 300\n let changeDetected = false\n\n // Collect all dependencies to watch, not just the input files\n const filesToWatch = collectAllDependencies(inputPaths)\n\n const watchers = Array.from(filesToWatch).map(filePath => {\n return watch(filePath, (eventType) => {\n const now = Date.now()\n // Debounce: only consider changes if enough time has passed\n if (now - lastChangeTime >= DEBOUNCE_MS) {\n lastChangeTime = now\n changeDetected = true\n }\n })\n })\n\n // Set up signal handlers for clean exit\n const exitHandler = () => {\n watchers.forEach(w => w.close())\n process.stdin.setRawMode(false)\n process.exit(0)\n }\n\n process.on('SIGINT', exitHandler)\n process.on('SIGTERM', exitHandler)\n\n // Display wait message\n console.error('Press space to regenerate, q to quit...')\n\n // Set raw mode to detect individual key presses\n process.stdin.setRawMode(true)\n process.stdin.resume()\n\n return new Promise<'spacebar' | 'filechange'>(resolve => {\n const onData = (data: Buffer) => {\n const char = data[0]\n // 0x20 is the spacebar\n if (char === 0x20) {\n cleanup()\n resolve('spacebar')\n } else if (char === 0x03 || char === 0x71 || char === 0x78 || char === 0x1b) {\n // Ctrl+C (0x03), q (0x71), x (0x78), or esc (0x1b)\n cleanup()\n process.exit(0)\n }\n }\n\n const checkForChanges = setInterval(() => {\n if (changeDetected) {\n cleanup()\n console.error('Files changed, regenerating...')\n resolve('filechange')\n }\n }, 50)\n\n const cleanup = () => {\n process.stdin.off('data', onData)\n clearInterval(checkForChanges)\n process.stdin.setRawMode(false)\n process.stdin.pause()\n process.removeListener('SIGINT', exitHandler)\n process.removeListener('SIGTERM', exitHandler)\n watchers.forEach(w => w.close())\n }\n\n process.stdin.on('data', onData)\n })\n}\n", "import { spawnSync } from 'node:child_process'\nimport { readFileSync, writeFileSync, mkdtempSync, rmSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { tmpdir } from 'node:os'\nimport type { DocNode, OutputFileDisplayNode } from './parser.ts'\n\n/**\n * Resolves `output-file-display` nodes by using cached execution results (if available) or\n * executing the shell command, reading the output file, and replacing the node with a code block.\n * Updates the preceding prose summary to end with `:` (instead of `.`) when content is shown.\n * Handles empty files and command failures appropriately.\n */\nexport function resolveOutputFiles(nodes: DocNode[]): DocNode[] {\n const result: DocNode[] = []\n for (const node of nodes) {\n if (node.kind !== 'output-file-display') {\n result.push(node)\n continue\n }\n const content = runAndCapture(node)\n if (content !== null) {\n const prev = result[result.length - 1]\n if (content.trim()) {\n // File has content: add code block, change period to colon in preceding prose\n if (prev?.kind === 'prose' && prev.text.endsWith('.')) {\n result[result.length - 1] = { ...prev, text: prev.text.slice(0, -1) + ':', noBlankAfter: true }\n }\n result.push({ kind: 'code', lang: node.lang, text: content.trimEnd() })\n } else {\n // File is empty: replace period or colon with \" is empty.\"\n if (prev?.kind === 'prose' && (prev.text.endsWith(':') || prev.text.endsWith('.'))) {\n result[result.length - 1] = { ...prev, text: prev.text.slice(0, -1) + ' is empty.' }\n }\n }\n }\n // If content is null (command failed), silently drop the display node\n }\n return result\n}\n\nfunction runAndCapture(node: OutputFileDisplayNode): string | null {\n // Use cached execution if available\n if (node.execution) {\n if (node.execution.exitCode !== 0) return null\n const content = node.execution.outputFiles.get(node.path)\n return content ?? null\n }\n\n // Fall back to direct execution if no cache\n const tmpDir = mkdtempSync(join(tmpdir(), 'lit-md-cap-'))\n try {\n for (const f of node.inputFiles) {\n writeFileSync(join(tmpDir, f.path), f.content, 'utf8')\n }\n const result = spawnSync(node.cmd, { shell: true, encoding: 'utf8', cwd: tmpDir })\n if (result.status !== 0) return null\n try {\n return readFileSync(join(tmpDir, node.path), 'utf8')\n } catch {\n return null\n }\n } finally {\n rmSync(tmpDir, { recursive: true, force: true })\n }\n}\n", "export type DescribeFormatType = 'hidden' | '#' | '##' | '###' | '####' | 'auto'\n\nlet overrideFormat: DescribeFormatType | undefined = undefined\n\n/**\n * Set the describe format for the current file, overriding the CLI --describe option.\n * This must be called at the top of the file, before any examples or describes.\n * \n * @param format - The format to use for rendering describe() block names:\n * - 'hidden': omit describe names (default)\n * - '#', '##', '###', '####': render as H1-H4 headers with nesting support\n * - 'auto': dynamically determine level based on document structure (h1 if no headers exist, else one level deeper than last header)\n * \n * @example\n * ```ts\n * import { setDescribeFormat } from '@ndp-software/lit-md'\n * setDescribeFormat('##')\n * // All describe() blocks in this file will be rendered as H2+ headers\n * ```\n */\nexport function setDescribeFormat(format: DescribeFormatType): void {\n if (overrideFormat !== undefined && overrideFormat !== format) {\n console.warn(`setDescribeFormat called multiple times with different formats: ${overrideFormat} -> ${format}. Only the last call will be used.`)\n }\n overrideFormat = format\n}\n\n/**\n * Get the current describe format override (if any).\n * Returns undefined if no override has been set.\n * @internal\n */\nexport function getDescribeFormatOverride(): DescribeFormatType | undefined {\n return overrideFormat\n}\n\n/**\n * Reset the describe format override.\n * Mainly useful for testing.\n * @internal\n */\nexport function resetDescribeFormat(): void {\n overrideFormat = undefined\n}\n\n/**\n * Resolve the final describe format to use.\n * Takes the CLI format and applies the override if set.\n * @internal\n */\nexport function resolveDescribeFormat(cliFormat: string): string {\n return overrideFormat ?? cliFormat\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["readFileSync", "writeFileSync", "join", "dirname", "extname", "resolve", "spawnSync", "describeFormat", "ts", "join", "readFileSync", "writeFileSync", "mkdtempSync", "rmSync", "isAbsolute", "join", "test", "describe", "readFileSync", "join", "inputPaths", "resolve", "spawnSync", "readFileSync", "writeFileSync", "mkdtempSync", "rmSync", "join", "tmpdir", "value", "extname", "resolve", "readFileSync", "join", "dirname", "writeFileSync", "spawnSync"]
7
+ }
package/docs/cli.md ADDED
@@ -0,0 +1,74 @@
1
+ ## CLI
2
+
3
+ By default, output is written to stdout.
4
+
5
+ ```ts
6
+ // Input file "tmp.ts":
7
+ // # My Document
8
+ import { example } from 'node:test'
9
+ example('test', () => {})
10
+ ```
11
+
12
+ ```sh
13
+ $ lit-md tmp.ts
14
+ # My Document
15
+ ```
16
+
17
+ ### Custom output path
18
+
19
+ Use --out to write to a different location.
20
+
21
+ ```ts
22
+ // Input file "tmp.ts":
23
+ // # Documentation
24
+ import { example } from 'node:test'
25
+ ```
26
+
27
+ ```sh
28
+ $ lit-md tmp.ts --out /tmp/docs.md
29
+ ```
30
+
31
+ Output file `/tmp/docs.md` contains `# Documentation`.
32
+
33
+ ### Help
34
+
35
+ Use `lit-md --help` for options.
36
+
37
+ ```sh
38
+ $ lit-md --help
39
+ lit-md - Generate markdown documentation from test files
40
+
41
+ Usage: lit-md [options] <file.ts|js> [file2 ...]
42
+
43
+ Options:
44
+ --help, -h Show this help message
45
+ --test Run tests before generating markdown
46
+ --typecheck Run type checking before generating markdown
47
+ --dryrun Show what would be written without writing files
48
+ -u, --update-snapshots Update snapshot files instead of generating markdown
49
+ --wait After generating, keep the process alive and watch for file
50
+ changes. Press space to manually regenerate, Ctrl+C to exit.
51
+ Works with --test and --typecheck (reruns on each change).
52
+ --out <output.md> Write to a specific output file (requires single input)
53
+ --outDir <dir> Write generated markdown files to this directory
54
+ --describe <format> Control describe() block rendering (default: ##)
55
+ Formats:
56
+ hidden - Omit describes
57
+ # - Render as h1 headers, nested as h2, h3, etc.
58
+ ## - Render as h2 headers, nested as h3, h4, etc. (default)
59
+ ### - Render as h3 headers, nested as h4, h5, etc.
60
+ #### - Render as h4 headers, nested as h5, h6, etc.
61
+ auto - Dynamically determine level based on document structure
62
+ (h1 if no headers exist, else one level deeper than last header)
63
+
64
+ By default, output is written to stdout. Use --out or --outDir to write to files.
65
+
66
+ Examples:
67
+ lit-md README.md.test.ts # outputs to stdout
68
+ lit-md --test --typecheck README.md.test.ts # outputs to stdout after testing
69
+ lit-md --wait README.md.test.ts # outputs to stdout, then waits for changes
70
+ lit-md --out /tmp/docs.md README.md.test.ts # writes to file
71
+ lit-md --outDir ./docs src/**/*.md.test.ts # writes to directory
72
+ lit-md --describe="#" README.md.test.ts # outputs to stdout with custom format
73
+ lit-md --describe="auto" README.md.test.ts # outputs to stdout with auto format
74
+ ```