@procedures/cli-kit 0.0.0-stage → 0.36.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/dist/ask.js ADDED
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Questions for missing arguments.
3
+ *
4
+ * When a person runs a program in a terminal and a required argument is missing, the program
5
+ * asks for it. The question shows the name, the type and the description of the field. The
6
+ * program does not ask when stdin or stdout is not a terminal, when the environment variable CI
7
+ * is set, with `--no-input`, or when the procedure sets `interactive: false` in its CLI metadata.
8
+ * Then a missing argument is an error of the input.
9
+ */
10
+ import { convertValue } from "./fields.js";
11
+ /** This function gives the terminal state of this process. */
12
+ export function processTerminal() {
13
+ return {
14
+ stdinIsTTY: process.stdin.isTTY === true,
15
+ stdoutIsTTY: process.stdout.isTTY === true,
16
+ env: process.env,
17
+ };
18
+ }
19
+ /** This function gives true when the program can ask for a missing argument. */
20
+ export function canAsk(noInput, meta, terminal) {
21
+ if (noInput || meta.interactive === false) {
22
+ return false;
23
+ }
24
+ const ci = terminal.env["CI"];
25
+ if (ci !== undefined && ci !== "" && ci !== "false" && ci !== "0") {
26
+ return false;
27
+ }
28
+ return terminal.stdinIsTTY && terminal.stdoutIsTTY;
29
+ }
30
+ /** The required fields that the input does not give (a field with a default is not missing) */
31
+ export function missingFields(fields, input) {
32
+ return fields.filter((field) => field.required && field.defaultValue === undefined && input[field.name] === undefined);
33
+ }
34
+ /** The question of a field: its name, its type and its description */
35
+ export function questionOf(field) {
36
+ const many = field.fieldType.kind === "array" ? " (separate the values with spaces)" : "";
37
+ const description = field.description ? `: ${field.description}` : "";
38
+ return `${field.name} (${field.type})${description}${many}`;
39
+ }
40
+ /**
41
+ * Ask for each missing field, in order, and convert each answer by the type of its field. An
42
+ * array field takes the words of the answer.
43
+ */
44
+ export async function askMissing(missing, input, ask) {
45
+ const result = { ...input };
46
+ for (const field of missing) {
47
+ const answer = await ask(field, questionOf(field));
48
+ if ("cancelled" in answer) {
49
+ return { ok: false, cancelled: true, error: "Cancelled" };
50
+ }
51
+ if (typeof answer.value !== "string") {
52
+ result[field.name] = answer.value;
53
+ continue;
54
+ }
55
+ const kind = field.fieldType.kind;
56
+ if (kind === "array") {
57
+ const words = answer.value.trim().split(/\s+/).filter((word) => word.length > 0);
58
+ const item = field.fieldType.item ?? { kind: "any" };
59
+ const values = [];
60
+ for (const word of words) {
61
+ const converted = convertValue(word, item, field.name);
62
+ if (!converted.ok)
63
+ return { ok: false, cancelled: false, error: converted.error };
64
+ values.push(converted.value);
65
+ }
66
+ result[field.name] = values;
67
+ continue;
68
+ }
69
+ const converted = convertValue(answer.value, field.fieldType, field.name);
70
+ if (!converted.ok) {
71
+ return { ok: false, cancelled: false, error: converted.error };
72
+ }
73
+ result[field.name] = converted.value;
74
+ }
75
+ return { ok: true, input: result };
76
+ }
77
+ /** The asker of the terminal: a yes/no question for a boolean, a choice for an enum, text otherwise */
78
+ export const terminalAsker = async (field, message) => {
79
+ // The prompts load only when the program asks
80
+ const prompts = await import("@clack/prompts");
81
+ let value;
82
+ if (field.fieldType.kind === "boolean") {
83
+ value = await prompts.confirm({ message });
84
+ }
85
+ else if (field.fieldType.kind === "enum" && field.enumValues) {
86
+ const options = field.enumValues.map((option) => ({ value: option, label: option }));
87
+ value = await prompts.select({ message, options });
88
+ }
89
+ else {
90
+ value = await prompts.text({ message });
91
+ }
92
+ return prompts.isCancel(value) ? { cancelled: true } : { value };
93
+ };
94
+ //# sourceMappingURL=ask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask.js","sourceRoot":"","sources":["../src/ask.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,117 @@
1
+ /**
2
+ * A command line for a procedure registry.
3
+ *
4
+ * `createProcedureCli()` makes a program from the procedures: the flags come from the input
5
+ * schemas, and the help comes from the metadata. A missing argument is a question in a
6
+ * terminal. A value `@<file>` is the text of the file. A format hook of a procedure writes its
7
+ * human output.
8
+ */
9
+ import { type Method } from "@procedures/client";
10
+ import { type GlobalFlag, type Globals } from "./args.js";
11
+ import { type Asker, type Terminal } from "./ask.js";
12
+ import { type CommandLike } from "./fields.js";
13
+ import { type OutputFormat, type Print } from "./format.js";
14
+ /** The global flags of each program of `createProcedureCli()`. The option `globals` adds more. */
15
+ export declare const STANDARD_GLOBAL_FLAGS: readonly GlobalFlag[];
16
+ /** The commands of a program: a list of procedures or descriptions, or a registry. */
17
+ export type CommandSource = readonly CommandLike[] | {
18
+ getAll(): readonly CommandLike[];
19
+ };
20
+ /** The options of a call of a `CliClient`. */
21
+ export interface CliCallOptions {
22
+ /** The signal that aborts the call. */
23
+ signal?: AbortSignal | undefined;
24
+ }
25
+ /**
26
+ * The client that runs the commands, for example a `Client` of `@procedures/client` over HTTP.
27
+ * The command line uses `stream()` when the client has it, and else `call()`.
28
+ */
29
+ export interface CliClient {
30
+ /** This function gives each item of the result of a procedure. */
31
+ stream?(method: Method, payload: unknown, options?: CliCallOptions): AsyncIterable<unknown>;
32
+ /** This function gives the result of a procedure. */
33
+ call?(method: Method, payload: unknown, options?: CliCallOptions): Promise<unknown>;
34
+ }
35
+ /** The data that a format hook gets. */
36
+ export interface FormatContext {
37
+ /** The path of the command. */
38
+ path: readonly string[];
39
+ /** The input of the command. */
40
+ input: unknown;
41
+ /** The output format: `text` or `streaming`. */
42
+ format: OutputFormat;
43
+ /** The print functions of the program. */
44
+ print: Print;
45
+ }
46
+ /**
47
+ * A format hook writes the human output of one procedure. It gives a text or lines, and the
48
+ * program prints them. Or it prints with `context.print` and gives nothing. The program uses a
49
+ * hook only for the formats `text` and `streaming`. `--json` and `--format table` do not use it.
50
+ */
51
+ export type FormatHook = (result: unknown, context: FormatContext) => string | readonly string[] | undefined | void;
52
+ /** The options of `createProcedureCli()`. */
53
+ export interface ProcedureCliOptions {
54
+ /** The name of the program, as a person types it. */
55
+ name: string;
56
+ /** The version that `--version` shows. Without it, `--version` shows the help. */
57
+ version?: string | undefined;
58
+ /** The text after the name in the first line of the help. */
59
+ description?: string | undefined;
60
+ /**
61
+ * The commands: procedures, descriptions of procedures, or a registry. A function gives them
62
+ * when the program starts, for example from a lazy import.
63
+ */
64
+ procedures: CommandSource | (() => CommandSource | Promise<CommandSource>);
65
+ /**
66
+ * The client that runs the commands. A function makes the client from the global flags, for
67
+ * example from `--port`. Without a client, the commands run in this process on the procedures.
68
+ */
69
+ client?: CliClient | ((globals: Globals) => CliClient | Promise<CliClient>) | undefined;
70
+ /** More global flags. A flag with the long name of a standard flag replaces it. */
71
+ globals?: readonly GlobalFlag[] | undefined;
72
+ /** The format hooks, by the path of the procedure with dots, for example `"job.status"`. */
73
+ format?: Readonly<Record<string, FormatHook>> | undefined;
74
+ /** The print functions. The default writes plain text to the console. */
75
+ print?: Print | undefined;
76
+ /** The lines of the help after the list of the commands. */
77
+ footer?: readonly string[] | undefined;
78
+ /** The terminal state that decides if the program asks. Tests give a fake. */
79
+ terminal?: Terminal | undefined;
80
+ /** The function that asks one question. Tests give a fake. */
81
+ ask?: Asker | undefined;
82
+ /**
83
+ * The function that reads a file for a value `@<file>`. The default reads the file as UTF-8.
84
+ * `false` turns `@<file>` off: a value that starts with `@` stays text.
85
+ */
86
+ readFile?: ((path: string) => string) | false | undefined;
87
+ }
88
+ /** The options of one run. */
89
+ export interface ProcedureCliRunOptions {
90
+ /** The signal that aborts the call of the command. */
91
+ signal?: AbortSignal | undefined;
92
+ }
93
+ /** A program of `createProcedureCli()`. */
94
+ export interface ProcedureCli {
95
+ /** The name of the program. */
96
+ readonly name: string;
97
+ /** The global flags of the program. */
98
+ readonly globals: readonly GlobalFlag[];
99
+ /**
100
+ * This function starts one command line (without the program name) and gives the exit code.
101
+ * The exit code is 1 for an unknown command, an invalid input, an error or a failed result.
102
+ * Else the exit code is 0.
103
+ */
104
+ run(argv: readonly string[], options?: ProcedureCliRunOptions): Promise<number>;
105
+ }
106
+ /**
107
+ * This function makes a command line for a procedure registry. The program gives help, `--json`,
108
+ * questions for missing arguments, `@<file>` input and short flags from `meta.shorts`.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * const cli = createProcedureCli({ name: "tool", version: "1.0.0", procedures: registry });
113
+ * process.exitCode = await cli.run(process.argv.slice(2));
114
+ * ```
115
+ */
116
+ export declare function createProcedureCli(options: ProcedureCliOptions): ProcedureCli;
117
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/cli.js ADDED
@@ -0,0 +1,253 @@
1
+ /**
2
+ * A command line for a procedure registry.
3
+ *
4
+ * `createProcedureCli()` makes a program from the procedures: the flags come from the input
5
+ * schemas, and the help comes from the metadata. A missing argument is a question in a
6
+ * terminal. A value `@<file>` is the text of the file. A format hook of a procedure writes its
7
+ * human output.
8
+ */
9
+ import { readFileSync } from "node:fs";
10
+ import { Client, LocalTransport, ProcedureRegistry, pathToMethod, } from "@procedures/client";
11
+ import { findChildren, parseCommandLine } from "./args.js";
12
+ import { askMissing, canAsk, missingFields, processTerminal, terminalAsker } from "./ask.js";
13
+ import { failureOf } from "./failure.js";
14
+ import { fieldsOf, resultFieldsOf } from "./fields.js";
15
+ import { formatOutput, plainPrint } from "./format.js";
16
+ import { generateHelp, groupHelp, rootHelp, validationMessage } from "./help.js";
17
+ /** The global flags of each program of `createProcedureCli()`. The option `globals` adds more. */
18
+ export const STANDARD_GLOBAL_FLAGS = [
19
+ { long: "help", short: "h", takesValue: false, description: "Show the help" },
20
+ { long: "version", short: "v", takesValue: false, hidden: true, description: "Show the version" },
21
+ { long: "format", short: "f", takesValue: true, description: "The output format: text, json, table or streaming" },
22
+ { long: "json", takesValue: false, description: "Write the result as JSON (the same as --format json)" },
23
+ { long: "data", takesValue: true, description: "The input as a JSON object, or @<file> for a file with the JSON object" },
24
+ { long: "no-input", takesValue: false, description: "Never ask for a missing argument (also when CI is set)" },
25
+ ];
26
+ const OUTPUT_FORMATS = ["text", "json", "table", "streaming"];
27
+ /** This function gives the global flags: the standard flags, then the flags of the options. */
28
+ function mergeGlobals(extra) {
29
+ const names = new Set(extra.map((flag) => flag.long));
30
+ return [...STANDARD_GLOBAL_FLAGS.filter((flag) => !names.has(flag.long)), ...extra];
31
+ }
32
+ /** This function gives the list of a command source. */
33
+ function commandsOf(source) {
34
+ return "getAll" in source ? source.getAll() : source;
35
+ }
36
+ /** This function gives the text of an error. */
37
+ function messageOf(error) {
38
+ return error instanceof Error ? error.message : String(error);
39
+ }
40
+ /** This function makes a client in this process over the procedures of a source. */
41
+ function localClient(source) {
42
+ let registry;
43
+ if (source instanceof ProcedureRegistry) {
44
+ registry = source;
45
+ }
46
+ else {
47
+ registry = new ProcedureRegistry();
48
+ for (const procedure of commandsOf(source))
49
+ registry.register(procedure);
50
+ }
51
+ const client = new Client({ transport: new LocalTransport({ registry }) }).useRegistry(registry);
52
+ return {
53
+ stream: (method, payload, options) => client.stream(method, payload, options?.signal ? { signal: options.signal } : {}),
54
+ };
55
+ }
56
+ /** This function gives each item of the result of a call. */
57
+ async function* itemsOf(client, method, payload, options) {
58
+ if (client.stream) {
59
+ yield* client.stream(method, payload, options);
60
+ return;
61
+ }
62
+ if (client.call) {
63
+ yield await client.call(method, payload, options);
64
+ return;
65
+ }
66
+ throw new Error("The client has no stream() and no call()");
67
+ }
68
+ /**
69
+ * This function makes a command line for a procedure registry. The program gives help, `--json`,
70
+ * questions for missing arguments, `@<file>` input and short flags from `meta.shorts`.
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * const cli = createProcedureCli({ name: "tool", version: "1.0.0", procedures: registry });
75
+ * process.exitCode = await cli.run(process.argv.slice(2));
76
+ * ```
77
+ */
78
+ export function createProcedureCli(options) {
79
+ const { name } = options;
80
+ const globalFlags = mergeGlobals(options.globals ?? []);
81
+ const readFile = options.readFile === false ? undefined : (options.readFile ?? ((path) => readFileSync(path, "utf8")));
82
+ const run = async (argv, runOptions = {}) => {
83
+ const print = options.print ?? plainPrint();
84
+ let code = 0;
85
+ const fail = (message, hint) => {
86
+ print.error(message);
87
+ if (hint)
88
+ print.info(hint);
89
+ code = 1;
90
+ };
91
+ try {
92
+ const source = typeof options.procedures === "function" ? await options.procedures() : options.procedures;
93
+ const commands = commandsOf(source);
94
+ const parsed = parseCommandLine(argv, commands, { name, globals: globalFlags, readFile });
95
+ const { path, procedure, globals } = parsed;
96
+ const command = `${name} ${path.join(" ")}`;
97
+ // An unknown command is the first problem to report
98
+ if (path.length > 0 && !procedure) {
99
+ const isGroup = findChildren(commands, path).length > 0;
100
+ if (!isGroup || parsed.extraArguments.length > 0) {
101
+ const words = [...path, ...parsed.extraArguments.slice(0, 1)];
102
+ fail(`Unknown command: ${name} ${words.join(" ")}`, `Run '${name} --help' for available commands.`);
103
+ return code;
104
+ }
105
+ }
106
+ if (parsed.errors.length > 0) {
107
+ for (const error of parsed.errors)
108
+ print.error(error);
109
+ print.info(`Run '${path.length > 0 ? `${command} --help` : `${name} --help`}' for the options.`);
110
+ return 1;
111
+ }
112
+ if (globals["version"] === true && options.version !== undefined) {
113
+ print.info(`${name} v${options.version}`);
114
+ return 0;
115
+ }
116
+ const formatOverride = globals["json"] === true ? "json" : globals["format"] === undefined ? undefined : String(globals["format"]);
117
+ if (formatOverride !== undefined && !OUTPUT_FORMATS.includes(formatOverride)) {
118
+ fail(`Invalid format: ${formatOverride}. Valid formats: ${OUTPUT_FORMATS.join(", ")}`);
119
+ return code;
120
+ }
121
+ // The help of the program, of a group or of a command
122
+ if (path.length === 0) {
123
+ const title = `${name}${options.version !== undefined ? ` v${options.version}` : ""}${options.description ? ` - ${options.description}` : ""}`;
124
+ for (const line of rootHelp(commands, { name, title, footer: options.footer }))
125
+ print.info(line);
126
+ return 0;
127
+ }
128
+ if (globals["help"] === true || !procedure) {
129
+ if (procedure) {
130
+ const meta = (procedure.metadata ?? {});
131
+ print.info(generateHelp(path, meta, fieldsOf(procedure), resultFieldsOf(procedure), { name, globals: globalFlags }));
132
+ }
133
+ else {
134
+ for (const line of groupHelp(name, commands, path) ?? [])
135
+ print.info(line);
136
+ }
137
+ return 0;
138
+ }
139
+ const meta = (procedure.metadata ?? {});
140
+ const outputFormat = (formatOverride ?? meta.output ?? "text");
141
+ // --data: the input as one JSON object. The flags and the arguments go over its fields.
142
+ let input = parsed.input;
143
+ if (globals["data"] !== undefined) {
144
+ let text = String(globals["data"]);
145
+ if (text.startsWith("@") && !text.startsWith("@@") && text.length > 1) {
146
+ if (!readFile) {
147
+ fail(`--data ${text}: this program reads no files`);
148
+ return code;
149
+ }
150
+ text = readFile(text.slice(1));
151
+ }
152
+ else if (text.startsWith("@@")) {
153
+ text = text.slice(1);
154
+ }
155
+ let data;
156
+ try {
157
+ data = JSON.parse(text);
158
+ }
159
+ catch (error) {
160
+ fail(`--data needs a JSON object: ${messageOf(error)}`);
161
+ return code;
162
+ }
163
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
164
+ fail("--data needs a JSON object");
165
+ return code;
166
+ }
167
+ input = { ...data, ...input };
168
+ }
169
+ // A required argument that is missing: in a terminal, the program asks for it
170
+ const missing = missingFields(fieldsOf(procedure), input);
171
+ if (missing.length > 0 && canAsk(globals["no-input"] === true, meta, options.terminal ?? processTerminal())) {
172
+ const asked = await askMissing(missing, input, options.ask ?? terminalAsker);
173
+ if (!asked.ok) {
174
+ fail(asked.cancelled ? "Cancelled" : `Invalid input for ${command}:\n ${asked.error}`);
175
+ return code;
176
+ }
177
+ input = asked.input;
178
+ }
179
+ // A procedure with a schema validates the input here. A description without a schema
180
+ // leaves the validation to the client.
181
+ let validated = input;
182
+ const schema = procedure.input;
183
+ if (typeof schema?.parse === "function") {
184
+ try {
185
+ validated = schema.parse(input);
186
+ }
187
+ catch (error) {
188
+ fail(`Invalid input for ${command}:\n ${validationMessage(error)}`, `Run '${command} --help' for the options.`);
189
+ return code;
190
+ }
191
+ }
192
+ else {
193
+ const stillMissing = missingFields(fieldsOf(procedure), input);
194
+ if (stillMissing.length > 0) {
195
+ const names = stillMissing.map((field) => `${field.name}: Required`).join("\n ");
196
+ fail(`Invalid input for ${command}:\n ${names}`, `Run '${command} --help' for the options.`);
197
+ return code;
198
+ }
199
+ }
200
+ const client = options.client === undefined
201
+ ? localClient(source)
202
+ : typeof options.client === "function"
203
+ ? await options.client(globals)
204
+ : options.client;
205
+ // Each item prints when it arrives. A failed item makes the command fail.
206
+ const hook = outputFormat === "text" || outputFormat === "streaming" ? options.format?.[path.join(".")] : undefined;
207
+ let failure;
208
+ const printItem = (item) => {
209
+ const text = hook ? hook(item, { path, input: validated, format: outputFormat, print }) : undefined;
210
+ if (typeof text === "string") {
211
+ print.info(text);
212
+ }
213
+ else if (Array.isArray(text)) {
214
+ for (const line of text)
215
+ print.info(line);
216
+ }
217
+ else if (!hook) {
218
+ formatOutput(print, item, outputFormat);
219
+ }
220
+ failure ??= failureOf(item);
221
+ };
222
+ const spinner = outputFormat === "streaming" ? print.spin(`Running ${path.join(" ")}...`) : undefined;
223
+ try {
224
+ let items = 0;
225
+ for await (const item of itemsOf(client, pathToMethod(path), validated, { signal: runOptions.signal })) {
226
+ if (spinner && items === 0)
227
+ spinner.stop();
228
+ items++;
229
+ printItem(item);
230
+ }
231
+ if (spinner) {
232
+ if (failure === undefined)
233
+ spinner.succeed(`${path.join(" ")} complete`);
234
+ else
235
+ spinner.fail(`${path.join(" ")} failed`);
236
+ }
237
+ }
238
+ catch (error) {
239
+ spinner?.stop();
240
+ throw error;
241
+ }
242
+ if (failure !== undefined) {
243
+ fail(`${command} failed: ${failure}`);
244
+ }
245
+ }
246
+ catch (error) {
247
+ fail(`Error: ${messageOf(error)}`);
248
+ }
249
+ return code;
250
+ };
251
+ return { name, globals: globalFlags, run };
252
+ }
253
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Procedure-level failure
3
+ *
4
+ * A procedure reports a failure in one of three ways, and the command line exits with code 1 for each:
5
+ *
6
+ * 1. It throws an error. This is the usual way.
7
+ * 2. It returns an object with `success: false`. Use this when the result has more to show,
8
+ * for example the list of problems of `lib audit`.
9
+ * 3. It returns an object with a numeric `exitCode` that is not 0. Use this for a procedure that
10
+ * runs an external command (`vitest run`, `shell run`), so the caller sees the command's result.
11
+ *
12
+ * For a streaming procedure, each item is examined: one failed item makes the command fail.
13
+ */
14
+ /** A short description of the failure that a result reports, or undefined when it reports none */
15
+ export declare function failureOf(result: unknown): string | undefined;
16
+ //# sourceMappingURL=failure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure.d.ts","sourceRoot":"","sources":["../src/failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,kGAAkG;AAClG,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAa7D"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Procedure-level failure
3
+ *
4
+ * A procedure reports a failure in one of three ways, and the command line exits with code 1 for each:
5
+ *
6
+ * 1. It throws an error. This is the usual way.
7
+ * 2. It returns an object with `success: false`. Use this when the result has more to show,
8
+ * for example the list of problems of `lib audit`.
9
+ * 3. It returns an object with a numeric `exitCode` that is not 0. Use this for a procedure that
10
+ * runs an external command (`vitest run`, `shell run`), so the caller sees the command's result.
11
+ *
12
+ * For a streaming procedure, each item is examined: one failed item makes the command fail.
13
+ */
14
+ /** A short description of the failure that a result reports, or undefined when it reports none */
15
+ export function failureOf(result) {
16
+ if (!result || typeof result !== "object" || Array.isArray(result)) {
17
+ return undefined;
18
+ }
19
+ const record = result;
20
+ const exitCode = record["exitCode"];
21
+ if (typeof exitCode === "number" && exitCode !== 0) {
22
+ return `exit code ${exitCode}`;
23
+ }
24
+ if (record["success"] === false) {
25
+ return firstText(record["error"]) ?? firstText(record["errors"]) ?? firstText(record["message"]) ?? "success: false";
26
+ }
27
+ return undefined;
28
+ }
29
+ /** The first text of a value: a string, the message of an error object, or the first of a list */
30
+ function firstText(value) {
31
+ if (typeof value === "string" && value.length > 0) {
32
+ return value;
33
+ }
34
+ if (Array.isArray(value)) {
35
+ for (const item of value) {
36
+ const text = firstText(item);
37
+ if (text)
38
+ return text;
39
+ }
40
+ return undefined;
41
+ }
42
+ if (value && typeof value === "object" && typeof value.message === "string") {
43
+ return value.message;
44
+ }
45
+ return undefined;
46
+ }
47
+ //# sourceMappingURL=failure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure.js","sourceRoot":"","sources":["../src/failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,kGAAkG;AAClG,MAAM,UAAU,SAAS,CAAC,MAAe;IACvC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,MAAM,GAAG,MAAiC,CAAC;IACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IACpC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACnD,OAAO,aAAa,QAAQ,EAAE,CAAC;IACjC,CAAC;IACD,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,KAAK,EAAE,CAAC;QAChC,OAAO,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,gBAAgB,CAAC;IACvH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kGAAkG;AAClG,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAC;QACxB,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAQ,KAA+B,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACvG,OAAQ,KAA6B,CAAC,OAAO,CAAC;IAChD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}