padrone 1.1.0 → 1.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/CHANGELOG.md +97 -1
- package/LICENSE +1 -1
- package/README.md +60 -30
- package/dist/args-DFEI7_G_.mjs +197 -0
- package/dist/args-DFEI7_G_.mjs.map +1 -0
- package/dist/chunk-y_GBKt04.mjs +5 -0
- package/dist/codegen/index.d.mts +305 -0
- package/dist/codegen/index.d.mts.map +1 -0
- package/dist/codegen/index.mjs +1358 -0
- package/dist/codegen/index.mjs.map +1 -0
- package/dist/completion.d.mts +64 -0
- package/dist/completion.d.mts.map +1 -0
- package/dist/completion.mjs +417 -0
- package/dist/completion.mjs.map +1 -0
- package/dist/docs/index.d.mts +34 -0
- package/dist/docs/index.d.mts.map +1 -0
- package/dist/docs/index.mjs +405 -0
- package/dist/docs/index.mjs.map +1 -0
- package/dist/formatter-XroimS3Q.d.mts +83 -0
- package/dist/formatter-XroimS3Q.d.mts.map +1 -0
- package/dist/help-CgGP7hQU.mjs +1229 -0
- package/dist/help-CgGP7hQU.mjs.map +1 -0
- package/dist/index.d.mts +120 -546
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1220 -1204
- package/dist/index.mjs.map +1 -1
- package/dist/test.d.mts +112 -0
- package/dist/test.d.mts.map +1 -0
- package/dist/test.mjs +138 -0
- package/dist/test.mjs.map +1 -0
- package/dist/types-BS7RP5Ls.d.mts +1059 -0
- package/dist/types-BS7RP5Ls.d.mts.map +1 -0
- package/dist/update-check-EbNDkzyV.mjs +146 -0
- package/dist/update-check-EbNDkzyV.mjs.map +1 -0
- package/package.json +61 -21
- package/src/args.ts +457 -0
- package/src/cli/completions.ts +29 -0
- package/src/cli/docs.ts +86 -0
- package/src/cli/doctor.ts +330 -0
- package/src/cli/index.ts +159 -0
- package/src/cli/init.ts +135 -0
- package/src/cli/link.ts +320 -0
- package/src/cli/wrap.ts +152 -0
- package/src/codegen/README.md +118 -0
- package/src/codegen/code-builder.ts +226 -0
- package/src/codegen/discovery.ts +232 -0
- package/src/codegen/file-emitter.ts +73 -0
- package/src/codegen/generators/barrel-file.ts +16 -0
- package/src/codegen/generators/command-file.ts +197 -0
- package/src/codegen/generators/command-tree.ts +124 -0
- package/src/codegen/index.ts +33 -0
- package/src/codegen/parsers/fish.ts +163 -0
- package/src/codegen/parsers/help.ts +378 -0
- package/src/codegen/parsers/merge.ts +158 -0
- package/src/codegen/parsers/zsh.ts +221 -0
- package/src/codegen/schema-to-code.ts +199 -0
- package/src/codegen/template.ts +69 -0
- package/src/codegen/types.ts +143 -0
- package/src/colorizer.ts +2 -2
- package/src/command-utils.ts +504 -0
- package/src/completion.ts +110 -97
- package/src/create.ts +1048 -308
- package/src/docs/index.ts +607 -0
- package/src/errors.ts +131 -0
- package/src/formatter.ts +195 -73
- package/src/help.ts +159 -58
- package/src/index.ts +12 -15
- package/src/interactive.ts +169 -0
- package/src/parse.ts +52 -21
- package/src/repl-loop.ts +317 -0
- package/src/runtime.ts +304 -0
- package/src/shell-utils.ts +83 -0
- package/src/test.ts +285 -0
- package/src/type-helpers.ts +10 -10
- package/src/type-utils.ts +124 -14
- package/src/types.ts +752 -154
- package/src/update-check.ts +244 -0
- package/src/wrap.ts +44 -40
- package/src/zod.d.ts +2 -2
- package/src/options.ts +0 -180
package/dist/test.d.mts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { b as PadroneRuntime, n as AnyPadroneCommand } from "./types-BS7RP5Ls.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/test.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Result from a single command execution in test mode.
|
|
6
|
+
* Extends the standard PadroneCommandResult with captured I/O.
|
|
7
|
+
*/
|
|
8
|
+
type TestCliResult = {
|
|
9
|
+
/** The matched command. */command: AnyPadroneCommand; /** Validated arguments (undefined if validation failed). */
|
|
10
|
+
args: unknown; /** Action handler return value (undefined if validation failed or no action). */
|
|
11
|
+
result: unknown; /** Validation issues, if any. */
|
|
12
|
+
issues: {
|
|
13
|
+
message: string;
|
|
14
|
+
path?: PropertyKey[];
|
|
15
|
+
}[] | undefined; /** All values passed to `runtime.output()`. */
|
|
16
|
+
stdout: unknown[]; /** All strings passed to `runtime.error()`. */
|
|
17
|
+
stderr: string[]; /** The thrown error, if the command threw (routing error, action error, etc.). */
|
|
18
|
+
error?: unknown;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Result from a REPL test session.
|
|
22
|
+
*/
|
|
23
|
+
type TestReplResult = {
|
|
24
|
+
/** One entry per successfully executed command (validation errors are captured in stderr, not here). */results: Omit<TestCliResult, 'stdout' | 'stderr'>[]; /** All output from the entire REPL session. */
|
|
25
|
+
stdout: unknown[]; /** All errors from the entire REPL session. */
|
|
26
|
+
stderr: string[];
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Fluent builder for setting up CLI test scenarios.
|
|
30
|
+
*/
|
|
31
|
+
type TestCliBuilder = {
|
|
32
|
+
/** Set the CLI input string (e.g. `'deploy --env production'`). */args(input: string): TestCliBuilder; /** Set environment variables visible to the command. */
|
|
33
|
+
env(vars: Record<string, string | undefined>): TestCliBuilder; /** Provide mock answers for interactive prompts. Keys are field names. */
|
|
34
|
+
prompt(answers: Record<string, unknown>): TestCliBuilder; /** Provide mock config files. Keys are file paths, values are parsed config objects. */
|
|
35
|
+
config(files: Record<string, Record<string, unknown>>): TestCliBuilder; /** Provide mock stdin data (simulates piped input). */
|
|
36
|
+
stdin(data: string): TestCliBuilder;
|
|
37
|
+
/**
|
|
38
|
+
* Execute a single command via `eval()` and return the result with captured I/O.
|
|
39
|
+
* @param input - Optional CLI input string. Overrides `.args()` if provided.
|
|
40
|
+
*/
|
|
41
|
+
run(input?: string): Promise<TestCliResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Run a REPL session with the given sequence of inputs.
|
|
44
|
+
* Each string in the array is fed as one line of input.
|
|
45
|
+
* The session ends after all inputs are consumed (EOF).
|
|
46
|
+
*/
|
|
47
|
+
repl(inputs: string[]): Promise<TestReplResult>;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Creates a fluent test builder for a Padrone program.
|
|
51
|
+
* Captures all I/O and provides a clean interface for assertions.
|
|
52
|
+
*
|
|
53
|
+
* Works with any test framework (bun:test, vitest, jest, node:test, etc.).
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { testCli } from 'padrone/test'
|
|
58
|
+
*
|
|
59
|
+
* const result = await testCli(myProgram)
|
|
60
|
+
* .args('deploy --env production')
|
|
61
|
+
* .env({ API_KEY: 'xxx' })
|
|
62
|
+
* .run()
|
|
63
|
+
*
|
|
64
|
+
* expect(result.result).toBe('Deployed')
|
|
65
|
+
* expect(result.stdout).toContain('Deploying...')
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* // Shorthand: pass input directly to run()
|
|
71
|
+
* const result = await testCli(myProgram).run('deploy --env production')
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* // Test interactive prompts
|
|
77
|
+
* const result = await testCli(myProgram)
|
|
78
|
+
* .args('init')
|
|
79
|
+
* .prompt({ name: 'myapp', template: 'react' })
|
|
80
|
+
* .run()
|
|
81
|
+
*
|
|
82
|
+
* expect(result.args).toEqual({ name: 'myapp', template: 'react' })
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* // Test REPL sessions
|
|
88
|
+
* const { results } = await testCli(myProgram)
|
|
89
|
+
* .repl(['greet World', 'add --a=2 --b=3'])
|
|
90
|
+
*
|
|
91
|
+
* expect(results[0].result).toBe('Hello, World!')
|
|
92
|
+
* expect(results[1].result).toBe(5)
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
/**
|
|
96
|
+
* Any program-like object that has `eval`, `runtime`, and `repl` methods.
|
|
97
|
+
* Avoids strict variance issues with `AnyPadroneProgram`.
|
|
98
|
+
*/
|
|
99
|
+
type TestableProgram = {
|
|
100
|
+
eval: (input: string, prefs?: {
|
|
101
|
+
autoOutput?: boolean;
|
|
102
|
+
}) => any;
|
|
103
|
+
runtime: (runtime: PadroneRuntime) => TestableProgram;
|
|
104
|
+
repl: (options?: {
|
|
105
|
+
greeting?: false;
|
|
106
|
+
hint?: false;
|
|
107
|
+
}) => AsyncIterable<any>;
|
|
108
|
+
};
|
|
109
|
+
declare function testCli(program: TestableProgram): TestCliBuilder;
|
|
110
|
+
//#endregion
|
|
111
|
+
export { TestCliBuilder, TestCliResult, TestReplResult, testCli };
|
|
112
|
+
//# sourceMappingURL=test.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.d.mts","names":[],"sources":["../src/test.ts"],"mappings":";;;;AAOA;;;KAAY,aAAA;EAEV,2BAAA,OAAA,EAAS,iBAAA,EAET;EAAA,IAAA,WAIA;EAFA,MAAA,WAE2B;EAA3B,MAAA;IAAU,OAAA;IAAiB,IAAA,GAAO,WAAA;EAAA,iBAM7B;EAJL,MAAA,aAUU;EARV,MAAA;EAEA,KAAA;AAAA;;;;KAMU,cAAA;EAMJ,wGAJN,OAAA,EAAS,IAAA,CAAK,aAAA,0BAUJ;EARV,MAAA;EAEA,MAAA;AAAA;;;;KAMU,cAAA;EAQI,mEANd,IAAA,CAAK,KAAA,WAAgB,cAAA,EAQA;EANrB,GAAA,CAAI,IAAA,EAAM,MAAA,+BAAqC,cAAA,EAW1B;EATrB,MAAA,CAAO,OAAA,EAAS,MAAA,oBAA0B,cAAA,EAelB;EAbxB,MAAA,CAAO,KAAA,EAAO,MAAA,SAAe,MAAA,qBAA2B,cAAA,EAazB;EAX/B,KAAA,CAAM,IAAA,WAAe,cAAA;EARhB;;;;EAaL,GAAA,CAAI,KAAA,YAAiB,OAAA,CAAQ,aAAA;EAXkB;;;;;EAiB/C,IAAA,CAAK,MAAA,aAAmB,OAAA,CAAQ,cAAA;AAAA;;;;;;;;;;;;;;;;;AAChC;;;;;;;;;;;;;;;;;;;;;;;AA0DF;;;;;;;;;;;KANK,eAAA;EACH,IAAA,GAAO,KAAA,UAAe,KAAA;IAAU,UAAA;EAAA;EAChC,OAAA,GAAU,OAAA,EAAS,cAAA,KAAmB,eAAA;EACtC,IAAA,GAAO,OAAA;IAAY,QAAA;IAAkB,IAAA;EAAA,MAAmB,aAAA;AAAA;AAAA,iBAG1C,OAAA,CAAQ,OAAA,EAAS,eAAA,GAAkB,cAAA"}
|
package/dist/test.mjs
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
//#region src/test.ts
|
|
2
|
+
function testCli(program) {
|
|
3
|
+
let input;
|
|
4
|
+
let envVars;
|
|
5
|
+
let promptAnswers;
|
|
6
|
+
let configFiles;
|
|
7
|
+
let stdinData;
|
|
8
|
+
const builder = {
|
|
9
|
+
args(args) {
|
|
10
|
+
input = args;
|
|
11
|
+
return builder;
|
|
12
|
+
},
|
|
13
|
+
env(vars) {
|
|
14
|
+
envVars = vars;
|
|
15
|
+
return builder;
|
|
16
|
+
},
|
|
17
|
+
prompt(answers) {
|
|
18
|
+
promptAnswers = answers;
|
|
19
|
+
return builder;
|
|
20
|
+
},
|
|
21
|
+
config(files) {
|
|
22
|
+
configFiles = files;
|
|
23
|
+
return builder;
|
|
24
|
+
},
|
|
25
|
+
stdin(data) {
|
|
26
|
+
stdinData = data;
|
|
27
|
+
return builder;
|
|
28
|
+
},
|
|
29
|
+
async run(runInput) {
|
|
30
|
+
const stdout = [];
|
|
31
|
+
const stderr = [];
|
|
32
|
+
const runtime = buildRuntime(stdout, stderr, {
|
|
33
|
+
envVars,
|
|
34
|
+
promptAnswers,
|
|
35
|
+
configFiles,
|
|
36
|
+
stdinData
|
|
37
|
+
});
|
|
38
|
+
const testProgram = program.runtime(runtime);
|
|
39
|
+
try {
|
|
40
|
+
return toTestResult(await testProgram.eval(runInput ?? input ?? "", { autoOutput: false }), stdout, stderr);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
stderr.push(err instanceof Error ? err.message : String(err));
|
|
43
|
+
return {
|
|
44
|
+
command: void 0,
|
|
45
|
+
args: void 0,
|
|
46
|
+
result: void 0,
|
|
47
|
+
issues: void 0,
|
|
48
|
+
stdout,
|
|
49
|
+
stderr,
|
|
50
|
+
error: err
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
async repl(inputs) {
|
|
55
|
+
const stdout = [];
|
|
56
|
+
const stderr = [];
|
|
57
|
+
const runtime = buildRuntime(stdout, stderr, {
|
|
58
|
+
envVars,
|
|
59
|
+
promptAnswers,
|
|
60
|
+
configFiles,
|
|
61
|
+
readLine: createMockReadLine(inputs)
|
|
62
|
+
});
|
|
63
|
+
const testProgram = program.runtime(runtime);
|
|
64
|
+
const results = [];
|
|
65
|
+
for await (const r of testProgram.repl({
|
|
66
|
+
greeting: false,
|
|
67
|
+
hint: false
|
|
68
|
+
})) results.push({
|
|
69
|
+
command: r.command,
|
|
70
|
+
args: r.args,
|
|
71
|
+
result: r.result,
|
|
72
|
+
issues: r.argsResult?.issues
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
results,
|
|
76
|
+
stdout,
|
|
77
|
+
stderr
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
return builder;
|
|
82
|
+
}
|
|
83
|
+
function toTestResult(evalResult, stdout, stderr) {
|
|
84
|
+
return {
|
|
85
|
+
command: evalResult.command,
|
|
86
|
+
args: evalResult.args,
|
|
87
|
+
result: evalResult.result,
|
|
88
|
+
issues: evalResult.argsResult?.issues,
|
|
89
|
+
stdout,
|
|
90
|
+
stderr
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function buildRuntime(stdout, stderr, opts) {
|
|
94
|
+
const runtime = {
|
|
95
|
+
output: (...args) => stdout.push(...args),
|
|
96
|
+
error: (text) => stderr.push(text)
|
|
97
|
+
};
|
|
98
|
+
if (opts.envVars) runtime.env = () => opts.envVars;
|
|
99
|
+
if (opts.promptAnswers) {
|
|
100
|
+
runtime.interactive = "supported";
|
|
101
|
+
runtime.prompt = async (config) => opts.promptAnswers[config.name];
|
|
102
|
+
}
|
|
103
|
+
if (opts.configFiles) {
|
|
104
|
+
runtime.loadConfigFile = (path) => opts.configFiles[path];
|
|
105
|
+
runtime.findFile = (names) => names.find((n) => n in opts.configFiles);
|
|
106
|
+
}
|
|
107
|
+
if (opts.readLine) runtime.readLine = opts.readLine;
|
|
108
|
+
if (opts.stdinData !== void 0) runtime.stdin = {
|
|
109
|
+
isTTY: false,
|
|
110
|
+
async text() {
|
|
111
|
+
return opts.stdinData;
|
|
112
|
+
},
|
|
113
|
+
async *lines() {
|
|
114
|
+
const lines = opts.stdinData.split("\n");
|
|
115
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
116
|
+
for (const line of lines) yield line;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
else runtime.stdin = {
|
|
120
|
+
isTTY: true,
|
|
121
|
+
async text() {
|
|
122
|
+
return "";
|
|
123
|
+
},
|
|
124
|
+
async *lines() {}
|
|
125
|
+
};
|
|
126
|
+
return runtime;
|
|
127
|
+
}
|
|
128
|
+
function createMockReadLine(inputs) {
|
|
129
|
+
let index = 0;
|
|
130
|
+
return async (_prompt) => {
|
|
131
|
+
if (index >= inputs.length) return null;
|
|
132
|
+
return inputs[index++] ?? null;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { testCli };
|
|
137
|
+
|
|
138
|
+
//# sourceMappingURL=test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.mjs","names":[],"sources":["../src/test.ts"],"sourcesContent":["import type { InteractivePromptConfig, PadroneRuntime } from './runtime.ts';\nimport type { AnyPadroneCommand, PadroneCommandResult } from './types.ts';\n\n/**\n * Result from a single command execution in test mode.\n * Extends the standard PadroneCommandResult with captured I/O.\n */\nexport type TestCliResult = {\n /** The matched command. */\n command: AnyPadroneCommand;\n /** Validated arguments (undefined if validation failed). */\n args: unknown;\n /** Action handler return value (undefined if validation failed or no action). */\n result: unknown;\n /** Validation issues, if any. */\n issues: { message: string; path?: PropertyKey[] }[] | undefined;\n /** All values passed to `runtime.output()`. */\n stdout: unknown[];\n /** All strings passed to `runtime.error()`. */\n stderr: string[];\n /** The thrown error, if the command threw (routing error, action error, etc.). */\n error?: unknown;\n};\n\n/**\n * Result from a REPL test session.\n */\nexport type TestReplResult = {\n /** One entry per successfully executed command (validation errors are captured in stderr, not here). */\n results: Omit<TestCliResult, 'stdout' | 'stderr'>[];\n /** All output from the entire REPL session. */\n stdout: unknown[];\n /** All errors from the entire REPL session. */\n stderr: string[];\n};\n\n/**\n * Fluent builder for setting up CLI test scenarios.\n */\nexport type TestCliBuilder = {\n /** Set the CLI input string (e.g. `'deploy --env production'`). */\n args(input: string): TestCliBuilder;\n /** Set environment variables visible to the command. */\n env(vars: Record<string, string | undefined>): TestCliBuilder;\n /** Provide mock answers for interactive prompts. Keys are field names. */\n prompt(answers: Record<string, unknown>): TestCliBuilder;\n /** Provide mock config files. Keys are file paths, values are parsed config objects. */\n config(files: Record<string, Record<string, unknown>>): TestCliBuilder;\n /** Provide mock stdin data (simulates piped input). */\n stdin(data: string): TestCliBuilder;\n /**\n * Execute a single command via `eval()` and return the result with captured I/O.\n * @param input - Optional CLI input string. Overrides `.args()` if provided.\n */\n run(input?: string): Promise<TestCliResult>;\n /**\n * Run a REPL session with the given sequence of inputs.\n * Each string in the array is fed as one line of input.\n * The session ends after all inputs are consumed (EOF).\n */\n repl(inputs: string[]): Promise<TestReplResult>;\n};\n\n/**\n * Creates a fluent test builder for a Padrone program.\n * Captures all I/O and provides a clean interface for assertions.\n *\n * Works with any test framework (bun:test, vitest, jest, node:test, etc.).\n *\n * @example\n * ```ts\n * import { testCli } from 'padrone/test'\n *\n * const result = await testCli(myProgram)\n * .args('deploy --env production')\n * .env({ API_KEY: 'xxx' })\n * .run()\n *\n * expect(result.result).toBe('Deployed')\n * expect(result.stdout).toContain('Deploying...')\n * ```\n *\n * @example\n * ```ts\n * // Shorthand: pass input directly to run()\n * const result = await testCli(myProgram).run('deploy --env production')\n * ```\n *\n * @example\n * ```ts\n * // Test interactive prompts\n * const result = await testCli(myProgram)\n * .args('init')\n * .prompt({ name: 'myapp', template: 'react' })\n * .run()\n *\n * expect(result.args).toEqual({ name: 'myapp', template: 'react' })\n * ```\n *\n * @example\n * ```ts\n * // Test REPL sessions\n * const { results } = await testCli(myProgram)\n * .repl(['greet World', 'add --a=2 --b=3'])\n *\n * expect(results[0].result).toBe('Hello, World!')\n * expect(results[1].result).toBe(5)\n * ```\n */\n/**\n * Any program-like object that has `eval`, `runtime`, and `repl` methods.\n * Avoids strict variance issues with `AnyPadroneProgram`.\n */\ntype TestableProgram = {\n eval: (input: string, prefs?: { autoOutput?: boolean }) => any;\n runtime: (runtime: PadroneRuntime) => TestableProgram;\n repl: (options?: { greeting?: false; hint?: false }) => AsyncIterable<any>;\n};\n\nexport function testCli(program: TestableProgram): TestCliBuilder {\n let input: string | undefined;\n let envVars: Record<string, string | undefined> | undefined;\n let promptAnswers: Record<string, unknown> | undefined;\n let configFiles: Record<string, Record<string, unknown>> | undefined;\n let stdinData: string | undefined;\n\n const builder: TestCliBuilder = {\n args(args: string) {\n input = args;\n return builder;\n },\n env(vars) {\n envVars = vars;\n return builder;\n },\n prompt(answers) {\n promptAnswers = answers;\n return builder;\n },\n config(files) {\n configFiles = files;\n return builder;\n },\n stdin(data: string) {\n stdinData = data;\n return builder;\n },\n\n async run(runInput?: string) {\n const stdout: unknown[] = [];\n const stderr: string[] = [];\n\n const runtime = buildRuntime(stdout, stderr, { envVars, promptAnswers, configFiles, stdinData });\n const testProgram = program.runtime(runtime);\n\n try {\n const evalResult = await testProgram.eval(runInput ?? input ?? '', { autoOutput: false });\n return toTestResult(evalResult, stdout, stderr);\n } catch (err) {\n stderr.push(err instanceof Error ? err.message : String(err));\n return {\n command: undefined as unknown as AnyPadroneCommand,\n args: undefined,\n result: undefined,\n issues: undefined,\n stdout,\n stderr,\n error: err,\n };\n }\n },\n\n async repl(inputs: string[]) {\n const stdout: unknown[] = [];\n const stderr: string[] = [];\n\n const runtime = buildRuntime(stdout, stderr, {\n envVars,\n promptAnswers,\n configFiles,\n readLine: createMockReadLine(inputs),\n });\n\n const testProgram = program.runtime(runtime);\n const results: Omit<TestCliResult, 'stdout' | 'stderr'>[] = [];\n\n for await (const r of testProgram.repl({ greeting: false, hint: false })) {\n results.push({\n command: r.command,\n args: r.args,\n result: r.result,\n issues: r.argsResult?.issues as TestCliResult['issues'],\n });\n }\n\n return { results, stdout, stderr };\n },\n };\n\n return builder;\n}\n\nfunction toTestResult(evalResult: PadroneCommandResult, stdout: unknown[], stderr: string[]): TestCliResult {\n return {\n command: evalResult.command,\n args: evalResult.args,\n result: evalResult.result,\n issues: evalResult.argsResult?.issues as TestCliResult['issues'],\n stdout,\n stderr,\n };\n}\n\nfunction buildRuntime(\n stdout: unknown[],\n stderr: string[],\n opts: {\n envVars?: Record<string, string | undefined>;\n promptAnswers?: Record<string, unknown>;\n configFiles?: Record<string, Record<string, unknown>>;\n readLine?: (prompt: string) => Promise<string | null>;\n stdinData?: string;\n },\n): PadroneRuntime {\n const runtime: PadroneRuntime = {\n output: (...args: unknown[]) => stdout.push(...args),\n error: (text: string) => stderr.push(text),\n };\n\n if (opts.envVars) {\n runtime.env = () => opts.envVars!;\n }\n\n if (opts.promptAnswers) {\n runtime.interactive = 'supported';\n runtime.prompt = async (config: InteractivePromptConfig) => opts.promptAnswers![config.name];\n }\n\n if (opts.configFiles) {\n runtime.loadConfigFile = (path: string) => opts.configFiles![path];\n runtime.findFile = (names: string[]) => names.find((n) => n in opts.configFiles!);\n }\n\n if (opts.readLine) {\n runtime.readLine = opts.readLine;\n }\n\n if (opts.stdinData !== undefined) {\n runtime.stdin = {\n isTTY: false,\n async text() {\n return opts.stdinData!;\n },\n async *lines() {\n const lines = opts.stdinData!.split('\\n');\n // Remove trailing empty line from final newline (matches readline behavior)\n if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop();\n for (const line of lines) {\n yield line;\n }\n },\n };\n } else {\n // No stdin data: simulate a TTY (no piped input) to avoid reading from process.stdin\n runtime.stdin = {\n isTTY: true,\n async text() {\n return '';\n },\n async *lines() {\n // no lines\n },\n };\n }\n\n return runtime;\n}\n\nfunction createMockReadLine(inputs: string[]): (prompt: string) => Promise<string | null> {\n let index = 0;\n return async (_prompt: string): Promise<string | null> => {\n if (index >= inputs.length) return null;\n return inputs[index++] ?? null;\n };\n}\n"],"mappings":"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"}
|