@ontrails/commander 0.2.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 +355 -0
- package/README.md +64 -0
- package/package.json +37 -0
- package/src/index.ts +5 -0
- package/src/multiselect-argv.ts +182 -0
- package/src/surface.ts +150 -0
- package/src/to-commander.ts +940 -0
package/src/surface.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surface helpers for wiring a topo to Commander.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
BaseSurfaceOptions,
|
|
7
|
+
Layer,
|
|
8
|
+
OverlayEnvelopeLike,
|
|
9
|
+
ResourceOverrideMap,
|
|
10
|
+
Topo,
|
|
11
|
+
TrailContextInit,
|
|
12
|
+
} from '@ontrails/core';
|
|
13
|
+
import type {
|
|
14
|
+
ActionResultContext,
|
|
15
|
+
CliFlag,
|
|
16
|
+
InputResolver,
|
|
17
|
+
ResolveCliPermitFromToken,
|
|
18
|
+
} from '@ontrails/cli';
|
|
19
|
+
import { defaultOnResult, deriveCliCommands } from '@ontrails/cli';
|
|
20
|
+
import type { ToCommanderOptions } from './to-commander.js';
|
|
21
|
+
import { toCommander } from './to-commander.js';
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Options
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Options for creating Commander CLI surfaces from a Trails topo.
|
|
29
|
+
*/
|
|
30
|
+
export interface CreateProgramOptions extends BaseSurfaceOptions {
|
|
31
|
+
readonly createContext?:
|
|
32
|
+
| (() => TrailContextInit | Promise<TrailContextInit>)
|
|
33
|
+
| undefined;
|
|
34
|
+
readonly description?: string | undefined;
|
|
35
|
+
readonly layers?: readonly Layer[] | undefined;
|
|
36
|
+
readonly name?: string | undefined;
|
|
37
|
+
readonly onResult?: ((ctx: ActionResultContext) => Promise<void>) | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* App-authored overlay envelopes (conventionally the app module's
|
|
40
|
+
* `trailsOverlays` export); the `surfaces` envelope's `cli` bindings
|
|
41
|
+
* render synonym and command-group routes onto the program.
|
|
42
|
+
*/
|
|
43
|
+
readonly overlays?: readonly OverlayEnvelopeLike[] | undefined;
|
|
44
|
+
readonly presets?: CliFlag[][] | undefined;
|
|
45
|
+
readonly resources?: ResourceOverrideMap | undefined;
|
|
46
|
+
readonly resolveInput?: InputResolver | undefined;
|
|
47
|
+
readonly resolvePermitFromToken?: ResolveCliPermitFromToken | undefined;
|
|
48
|
+
readonly version?: string | undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Result returned by running the Commander surface bootstrap.
|
|
53
|
+
*/
|
|
54
|
+
export interface SurfaceCliResult {
|
|
55
|
+
readonly exitCode: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// createProgram
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
const deriveCommanderOptions = (
|
|
63
|
+
graph: Topo,
|
|
64
|
+
options: CreateProgramOptions
|
|
65
|
+
): ToCommanderOptions => {
|
|
66
|
+
const commanderOpts: ToCommanderOptions = {
|
|
67
|
+
name: options.name ?? graph.name,
|
|
68
|
+
topoName: graph.name,
|
|
69
|
+
};
|
|
70
|
+
if (options.version !== undefined || graph.version !== undefined) {
|
|
71
|
+
commanderOpts.version = options.version ?? graph.version;
|
|
72
|
+
}
|
|
73
|
+
if (options.description !== undefined || graph.description !== undefined) {
|
|
74
|
+
commanderOpts.description = options.description ?? graph.description;
|
|
75
|
+
}
|
|
76
|
+
return commanderOpts;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Create a Commander program from a topo without parsing argv.
|
|
81
|
+
*
|
|
82
|
+
* @remarks This is a host materialization boundary. Derivation failures are
|
|
83
|
+
* thrown for the caller's CLI bootstrap code after `deriveCliCommands` has
|
|
84
|
+
* already represented the framework error as a Result.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* import { createProgram } from '@ontrails/commander';
|
|
89
|
+
*
|
|
90
|
+
* const program = createProgram(graph, { name: 'demo' });
|
|
91
|
+
* program.parse();
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export const createProgram = (
|
|
95
|
+
graph: Topo,
|
|
96
|
+
options: CreateProgramOptions = {}
|
|
97
|
+
) => {
|
|
98
|
+
const commandsResult = deriveCliCommands(graph, {
|
|
99
|
+
configValues: options.configValues,
|
|
100
|
+
createContext: options.createContext,
|
|
101
|
+
exclude: options.exclude,
|
|
102
|
+
include: options.include,
|
|
103
|
+
intent: options.intent,
|
|
104
|
+
layers: options.layers,
|
|
105
|
+
onResult: options.onResult ?? defaultOnResult,
|
|
106
|
+
overlays: options.overlays,
|
|
107
|
+
presets: options.presets,
|
|
108
|
+
resolveInput: options.resolveInput,
|
|
109
|
+
resolvePermitFromToken: options.resolvePermitFromToken,
|
|
110
|
+
resources: options.resources,
|
|
111
|
+
validate: options.validate,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (commandsResult.isErr()) {
|
|
115
|
+
throw commandsResult.error;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return toCommander(
|
|
119
|
+
commandsResult.value,
|
|
120
|
+
deriveCommanderOptions(graph, options)
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// surface
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Parse argv for a topo through Commander.
|
|
130
|
+
*
|
|
131
|
+
* Returns the process exit code without calling `process.exit()`, so callers
|
|
132
|
+
* can run cleanup before terminating. The CLI `surface()` entry point
|
|
133
|
+
* delegates here and lets the process exit naturally.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* import { surface } from '@ontrails/commander';
|
|
138
|
+
*
|
|
139
|
+
* const { exitCode } = await surface(graph, { name: 'demo' });
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export const surface = async (
|
|
143
|
+
graph: Topo,
|
|
144
|
+
options: CreateProgramOptions = {}
|
|
145
|
+
): Promise<SurfaceCliResult> => {
|
|
146
|
+
const program = createProgram(graph, options);
|
|
147
|
+
await program.parseAsync();
|
|
148
|
+
const { exitCode } = process;
|
|
149
|
+
return { exitCode: typeof exitCode === 'number' ? exitCode : 0 };
|
|
150
|
+
};
|