@loomcli/core 0.2.0 → 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.
- package/dist/application.d.ts +59 -34
- package/dist/application.js +162 -59
- package/dist/chain.d.ts +25 -6
- package/dist/chain.js +99 -15
- package/dist/command.d.ts +146 -42
- package/dist/command.js +620 -78
- package/dist/environment.d.ts +22 -0
- package/dist/environment.js +1 -0
- package/dist/errors.d.ts +31 -59
- package/dist/errors.js +49 -106
- package/dist/extension.d.ts +5 -1
- package/dist/extension.js +18 -1
- package/dist/globals.d.ts +14 -25
- package/dist/globals.js +10 -61
- package/dist/glyphs.generated.d.ts +464 -0
- package/dist/glyphs.generated.js +491 -0
- package/dist/host.js +2 -1
- package/dist/index.d.ts +14 -5
- package/dist/index.js +5 -2
- package/dist/inspect.d.ts +26 -3
- package/dist/inspect.js +19 -5
- package/dist/lanes.d.ts +26 -0
- package/dist/lanes.js +45 -0
- package/dist/output.d.ts +93 -15
- package/dist/output.js +307 -34
- package/dist/plugin.d.ts +32 -16
- package/dist/plugin.js +46 -18
- package/dist/rendering.d.ts +21 -0
- package/dist/rendering.js +72 -0
- package/dist/sequence.d.ts +41 -0
- package/dist/sequence.js +225 -0
- package/dist/style-ansi.d.ts +13 -0
- package/dist/style-ansi.js +306 -0
- package/dist/style-layout.d.ts +29 -0
- package/dist/style-layout.js +228 -0
- package/dist/style-resolve.d.ts +6 -0
- package/dist/style-resolve.js +26 -0
- package/dist/style-state.d.ts +14 -0
- package/dist/style-state.js +179 -0
- package/dist/style-wire.d.ts +31 -0
- package/dist/style-wire.js +201 -0
- package/dist/style.d.ts +86 -0
- package/dist/style.js +201 -0
- package/dist/theme.d.ts +3 -0
- package/dist/theme.js +22 -0
- package/dist/types.d.ts +169 -21
- package/dist/validation.d.ts +8 -1
- package/dist/validation.js +17 -2
- package/dist/view.d.ts +180 -0
- package/dist/view.js +307 -0
- package/package.json +2 -1
package/dist/chain.js
CHANGED
|
@@ -1,8 +1,69 @@
|
|
|
1
1
|
import { prepareDispatch, routeInvocation } from './command.js';
|
|
2
|
-
import { InternalError, reasonOf, toFailure } from './errors.js';
|
|
2
|
+
import { InternalError, reasonOf, routedSubject, toFailure } from './errors.js';
|
|
3
3
|
import { inspectGraph } from './inspect.js';
|
|
4
4
|
import { booleanValue } from './options.js';
|
|
5
5
|
import { pluginSentence } from './plugin.js';
|
|
6
|
+
/**
|
|
7
|
+
* The view one run selects, which is one value whichever middleware wrote it. The assignment is
|
|
8
|
+
* kept as it arrived, because a JavaScript caller reaches the setter with any value and the check
|
|
9
|
+
* belongs at the dispatch boundary, where the fault it raises ranks behind a held fault.
|
|
10
|
+
*/
|
|
11
|
+
class ViewSelection {
|
|
12
|
+
#assigned = undefined;
|
|
13
|
+
#reached = false;
|
|
14
|
+
#result;
|
|
15
|
+
constructor(result) {
|
|
16
|
+
this.#result = result;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* What `view` reads: the assigned name, or the declaration's default until one is assigned, and
|
|
20
|
+
* `null` on a Command that declares no result, whatever was assigned there. An assignment that is
|
|
21
|
+
* not a name reads as the default, because the getter answers a view name and the assignment is
|
|
22
|
+
* the boundary's fault. The assignment itself is kept either way, so the boundary still raises it.
|
|
23
|
+
*/
|
|
24
|
+
read() {
|
|
25
|
+
if (!this.#result) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const assigned = this.#assigned;
|
|
29
|
+
if (assigned !== undefined && typeof assigned.name === 'string') {
|
|
30
|
+
return assigned.name;
|
|
31
|
+
}
|
|
32
|
+
return this.#result.default;
|
|
33
|
+
}
|
|
34
|
+
/** The last assignment before the boundary wins; one made after it changes nothing. */
|
|
35
|
+
assign(identity, name) {
|
|
36
|
+
if (!this.#reached) {
|
|
37
|
+
this.#assigned = { identity, name };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** The chain reached the dispatch boundary, so this run's view is fixed whatever follows. */
|
|
41
|
+
reach() {
|
|
42
|
+
this.#reached = true;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The name the boundary dispatches through: `null` when no middleware assigned one and the
|
|
46
|
+
* declaration's default stands. A plugin that selected a view has the name checked here.
|
|
47
|
+
*/
|
|
48
|
+
resolve(path) {
|
|
49
|
+
const assigned = this.#assigned;
|
|
50
|
+
if (assigned === undefined) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const plugin = pluginSentence(assigned.identity);
|
|
54
|
+
const { name } = assigned;
|
|
55
|
+
if (!this.#result) {
|
|
56
|
+
throw new InternalError(`${plugin} selected view "${String(name)}" on ${routedSubject(path)}, which declares no result.`, undefined);
|
|
57
|
+
}
|
|
58
|
+
if (typeof name !== 'string') {
|
|
59
|
+
throw new InternalError(`${plugin} selected a view that is not a string on ${routedSubject(path)}.`, undefined);
|
|
60
|
+
}
|
|
61
|
+
if (!this.#result.views.has(name)) {
|
|
62
|
+
throw new InternalError(`${plugin} selected view "${name}", which ${routedSubject(path)} does not name.`, undefined);
|
|
63
|
+
}
|
|
64
|
+
return name;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
6
67
|
/**
|
|
7
68
|
* The default export a loader must resolve to. A loaded module is data core never declared, so the
|
|
8
69
|
* check is the one runtime fact that decides it: the export is callable. Core calls it with the
|
|
@@ -133,8 +194,9 @@ function nextOf(turn) {
|
|
|
133
194
|
throw error;
|
|
134
195
|
});
|
|
135
196
|
state.downstream = pending;
|
|
136
|
-
// Core awaits the downstream promise itself
|
|
137
|
-
//
|
|
197
|
+
// Core awaits the downstream promise itself.
|
|
198
|
+
// A middleware that never awaits `next()` still holds the chain open.
|
|
199
|
+
// The run therefore never ends with an unobserved rejection.
|
|
138
200
|
void pending.catch(() => undefined);
|
|
139
201
|
return pending;
|
|
140
202
|
};
|
|
@@ -174,8 +236,8 @@ async function settle(turn, thrown) {
|
|
|
174
236
|
return reported(chain, 'taken-over');
|
|
175
237
|
}
|
|
176
238
|
await quiet(state.downstream);
|
|
177
|
-
// A middleware that caught the rejection reports what the chain reached
|
|
178
|
-
//
|
|
239
|
+
// A middleware that caught the rejection reports what the chain reached.
|
|
240
|
+
// The recorded failure still decides the exit code.
|
|
179
241
|
return reported(chain, state.outcome ?? (chain.invoked() ? 'dispatched' : 'taken-over'));
|
|
180
242
|
}
|
|
181
243
|
/** The module one loader answers with, whether it throws where it is called or rejects later. */
|
|
@@ -215,12 +277,23 @@ async function runEntry(entry, index, chain) {
|
|
|
215
277
|
return settle(turn, thrown);
|
|
216
278
|
}
|
|
217
279
|
/** The whole chain, answering with the failure it raised when a middleware caught that failure. */
|
|
218
|
-
async function runChain(invocation, routed,
|
|
280
|
+
async function runChain(invocation, routed, prepared) {
|
|
281
|
+
const entries = activatedEntries(invocation.plugins, routed.scan);
|
|
219
282
|
const run = { invoked: false, raised: undefined };
|
|
283
|
+
const selection = new ViewSelection(prepared.result);
|
|
284
|
+
/**
|
|
285
|
+
* The dispatch boundary: the point the chain reaches when its last middleware continues. Core
|
|
286
|
+
* raises the held fault here, so it ranks ahead of a bad view assignment, or else reads the
|
|
287
|
+
* selected view and dispatches the action.
|
|
288
|
+
*/
|
|
220
289
|
const terminal = async () => {
|
|
221
|
-
|
|
290
|
+
selection.reach();
|
|
291
|
+
if (prepared.kind === 'held') {
|
|
292
|
+
throw prepared.fault;
|
|
293
|
+
}
|
|
294
|
+
const view = selection.resolve(routed.path);
|
|
222
295
|
run.invoked = true;
|
|
223
|
-
await dispatch();
|
|
296
|
+
await prepared.dispatch(view);
|
|
224
297
|
return 'dispatched';
|
|
225
298
|
};
|
|
226
299
|
const cancelled = () => invocation.signal.aborted;
|
|
@@ -245,7 +318,14 @@ async function runChain(invocation, routed, entries) {
|
|
|
245
318
|
next,
|
|
246
319
|
options: entry.options,
|
|
247
320
|
out: invocation.out,
|
|
321
|
+
request: prepared.request,
|
|
248
322
|
signal: invocation.signal,
|
|
323
|
+
get view() {
|
|
324
|
+
return selection.read();
|
|
325
|
+
},
|
|
326
|
+
set view(name) {
|
|
327
|
+
selection.assign(entry.identity, name);
|
|
328
|
+
},
|
|
249
329
|
}),
|
|
250
330
|
invoked: () => run.invoked,
|
|
251
331
|
record: (error) => {
|
|
@@ -271,17 +351,21 @@ async function runChain(invocation, routed, entries) {
|
|
|
271
351
|
return run.raised;
|
|
272
352
|
}
|
|
273
353
|
/**
|
|
274
|
-
* Runs one invocation: the global pre-scan, routing, the
|
|
275
|
-
*
|
|
276
|
-
*
|
|
354
|
+
* Runs one invocation: the global pre-scan, routing, the dispatch this invocation prepares, and the
|
|
355
|
+
* middleware chain it then runs. Local parsing and validation run ahead of the chain so that a
|
|
356
|
+
* middleware reads the request, and the fault they find is held until the dispatch boundary. A
|
|
357
|
+
* middleware that returns without calling `next()` has taken over, so the held fault is never
|
|
358
|
+
* raised and nothing later in the chain runs.
|
|
277
359
|
*/
|
|
278
360
|
async function runInvocation(invocation) {
|
|
279
361
|
const routed = routeInvocation(invocation.graph, invocation.host.argv);
|
|
280
|
-
|
|
281
|
-
const
|
|
362
|
+
invocation.route(routed.path);
|
|
363
|
+
const prepared = await prepareDispatch(invocation.graph, routed, invocation);
|
|
364
|
+
const raised = await runChain(invocation, routed, prepared);
|
|
282
365
|
if (raised) {
|
|
283
|
-
// The chain resolved because a middleware caught the rejection.
|
|
284
|
-
//
|
|
366
|
+
// The chain resolved because a middleware caught the rejection.
|
|
367
|
+
// The failure it caught still decides the exit code.
|
|
368
|
+
// That is the rule an action's caught output rejection already follows.
|
|
285
369
|
throw raised;
|
|
286
370
|
}
|
|
287
371
|
}
|
package/dist/command.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import type { RegisteredGlobals } from './environment.js';
|
|
1
2
|
import type { DescriptorRegistry, ExtensionRecords, ExtensionValue } from './extension.js';
|
|
2
|
-
import type { BuiltGlobals,
|
|
3
|
+
import type { BuiltGlobals, GlobalsState } from './globals.js';
|
|
3
4
|
import { compileOptions } from './options.js';
|
|
4
5
|
import type { OptionValues } from './options.js';
|
|
5
6
|
import type { BuiltPlugin, PluginBuild } from './plugin.js';
|
|
6
|
-
import type {
|
|
7
|
+
import type { ContextualStyle } from './style.js';
|
|
8
|
+
import type { Action, ActionChannel, ArgumentConfig, ArgumentValue, declaredTypes, DeclaredResult, DeclaredTypes, DefaultConstraint, GlobalNameConstraint, Host, MultipleConstraint, NameConstraint, OpenResult, OptionConfig, OptionValue, Out, Request, ResultBinding, ResultViews, ResultViewsOf, RowViews, ValidateOmittedConstraint } from './types.js';
|
|
7
9
|
import type { ArgumentInput, DefaultValues, InputDeclaration, OptionInput, ValidatedInputs } from './validation.js';
|
|
8
10
|
/** One positional slot: the declaration it fills and whether it takes the remaining tokens. */
|
|
9
11
|
export interface ArgumentSlot {
|
|
@@ -12,8 +14,10 @@ export interface ArgumentSlot {
|
|
|
12
14
|
variadic: boolean;
|
|
13
15
|
}
|
|
14
16
|
export interface DispatchInput {
|
|
17
|
+
style: ContextualStyle;
|
|
15
18
|
host: Host;
|
|
16
|
-
|
|
19
|
+
/** The action's channel, whose `results` accepts whatever the routed declaration named. */
|
|
20
|
+
out: Out<OpenResult>;
|
|
17
21
|
passthrough: string[];
|
|
18
22
|
signal: AbortSignal;
|
|
19
23
|
values: ValidatedInputs;
|
|
@@ -44,29 +48,39 @@ export interface BuiltCommand {
|
|
|
44
48
|
inputs: readonly InputDeclaration[];
|
|
45
49
|
name: string | null;
|
|
46
50
|
options: ReturnType<typeof compileOptions>;
|
|
51
|
+
/** The result the Command declares, or nothing where it declares none. */
|
|
52
|
+
/** The built declaration is the shape the write site reads, so the channel carries it. */
|
|
53
|
+
result: DeclaredResult | undefined;
|
|
47
54
|
routes: ReadonlyMap<string, RoutedChild>;
|
|
48
55
|
}
|
|
49
56
|
/** Phantom key. It marks a Command value, so only a Command can be attached as a child. */
|
|
50
57
|
export declare const commandValue: unique symbol;
|
|
51
58
|
/**
|
|
52
|
-
*
|
|
59
|
+
* The input, alias, child, and action calls a Command can publish. Its type state is a subset,
|
|
53
60
|
* and each call removes the names it invalidates. A Command attaches children at any depth, so
|
|
54
61
|
* `command()` belongs to every Command and to the unnamed root alike.
|
|
55
62
|
*/
|
|
56
|
-
export type CommandMethod = 'action' | 'alias' | 'argument' | 'command' | 'option';
|
|
63
|
+
export type CommandMethod = 'action' | 'alias' | 'argument' | 'command' | 'option' | 'result' | 'rows';
|
|
57
64
|
/** One Command declares arguments or attaches children, so the first call removes the other. */
|
|
58
65
|
export type AfterArgument<State> = Exclude<State, 'command'>;
|
|
59
66
|
/** The same rule read from the other side. */
|
|
60
67
|
export type AfterCommand<State> = Exclude<State, 'argument'>;
|
|
61
|
-
/**
|
|
68
|
+
/** One Command declares one result, so either call removes both. */
|
|
69
|
+
export type AfterResult<State> = Exclude<State, 'result' | 'rows'>;
|
|
70
|
+
/** Registering the action closes input, alias, child, and further action declarations. */
|
|
62
71
|
export type AfterAction = never;
|
|
63
|
-
/** A declaration made after
|
|
72
|
+
/** A declaration made after its authoring phase closed; build reports the first in call order. */
|
|
64
73
|
type LateDeclaration = {
|
|
65
74
|
alias: string;
|
|
66
75
|
kind: 'alias';
|
|
76
|
+
} | {
|
|
77
|
+
name: string;
|
|
78
|
+
kind: 'global';
|
|
67
79
|
} | {
|
|
68
80
|
child: object;
|
|
69
81
|
kind: 'child';
|
|
82
|
+
} | {
|
|
83
|
+
kind: 'result';
|
|
70
84
|
} | {
|
|
71
85
|
input: InputDeclaration;
|
|
72
86
|
kind: 'input';
|
|
@@ -76,8 +90,8 @@ type LateDeclaration = {
|
|
|
76
90
|
* which the types reject and a JavaScript author can still write, reports as the call it is.
|
|
77
91
|
*/
|
|
78
92
|
type AliasDeclaration = readonly string[];
|
|
79
|
-
/** The
|
|
80
|
-
interface
|
|
93
|
+
/** The private handle one graph node is built through, without its inferred declaration types. */
|
|
94
|
+
interface CommandNodeHandle {
|
|
81
95
|
readonly name: string | null;
|
|
82
96
|
build(context: BuildContext): BuiltCommand;
|
|
83
97
|
}
|
|
@@ -92,15 +106,36 @@ interface BuildContext {
|
|
|
92
106
|
descriptors: DescriptorRegistry;
|
|
93
107
|
extensions: ExtensionRecords;
|
|
94
108
|
globals: BuiltGlobals;
|
|
95
|
-
owners: Map<
|
|
109
|
+
owners: Map<CommandNodeHandle, string | null>;
|
|
110
|
+
/** The route from the root to the Command being built, which a lifecycle hook reads. */
|
|
111
|
+
path: readonly string[];
|
|
112
|
+
/** The installed plugins in installation order, whose hooks run over every Command. */
|
|
113
|
+
plugins: readonly BuiltPlugin[];
|
|
96
114
|
}
|
|
97
115
|
/**
|
|
98
116
|
* Everything one Command declaration holds. The transitions below copy it with fields replaced, and
|
|
99
117
|
* the Command and Application builders share them, so one declaration call has one implementation.
|
|
100
|
-
* Absent globals stay `undefined`, so every declaration without globals agrees on identity.
|
|
101
118
|
*/
|
|
119
|
+
/**
|
|
120
|
+
* One call of the results lane, in the order it was made. A `result()` or `rows()` call declares
|
|
121
|
+
* the unit, and a `views()` call reshapes the views of whichever declaration it follows.
|
|
122
|
+
* Each record arrives unexamined, because build owns every rule the lane carries.
|
|
123
|
+
*/
|
|
124
|
+
export type ResultCall = {
|
|
125
|
+
kind: 'value' | 'rows';
|
|
126
|
+
views: unknown;
|
|
127
|
+
} | {
|
|
128
|
+
default: unknown;
|
|
129
|
+
kind: 'views';
|
|
130
|
+
views: unknown;
|
|
131
|
+
};
|
|
102
132
|
export interface CommandState<Args, Options, Globals> {
|
|
103
|
-
|
|
133
|
+
/**
|
|
134
|
+
* The registered actions, with the declared result erased. An action is stored under the widest
|
|
135
|
+
* result, so a handler typed from its own declaration stores here and the channel that carries
|
|
136
|
+
* the result is built for it at dispatch.
|
|
137
|
+
*/
|
|
138
|
+
actions: readonly Action<Args, Globals & Options, OpenResult>[];
|
|
104
139
|
aliases: readonly AliasDeclaration[];
|
|
105
140
|
bind: (values: ValidatedInputs) => {
|
|
106
141
|
args: Args;
|
|
@@ -109,13 +144,13 @@ export interface CommandState<Args, Options, Globals> {
|
|
|
109
144
|
children: readonly object[];
|
|
110
145
|
deprecated: unknown;
|
|
111
146
|
description: unknown;
|
|
112
|
-
extensions: unknown;
|
|
147
|
+
extensions: readonly unknown[];
|
|
113
148
|
hidden: unknown;
|
|
114
|
-
globals: GlobalOptions<Globals> | undefined;
|
|
115
149
|
inputs: readonly InputDeclaration[];
|
|
116
150
|
late: readonly LateDeclaration[];
|
|
117
151
|
name: string | null;
|
|
118
152
|
options: unknown;
|
|
153
|
+
results: readonly ResultCall[];
|
|
119
154
|
}
|
|
120
155
|
/**
|
|
121
156
|
* The state every declaration starts from. The unnamed root and each named Command share it.
|
|
@@ -126,7 +161,6 @@ export declare function freshState<Globals>(declaration: {
|
|
|
126
161
|
deprecated: unknown;
|
|
127
162
|
description: unknown;
|
|
128
163
|
extensions: unknown;
|
|
129
|
-
globals: GlobalOptions<Globals> | undefined;
|
|
130
164
|
hidden: unknown;
|
|
131
165
|
name: string | null;
|
|
132
166
|
options: unknown;
|
|
@@ -135,9 +169,21 @@ export declare function freshState<Globals>(declaration: {
|
|
|
135
169
|
export declare function declareArgument<Args, Options, Globals, Name extends string, Config extends ArgumentConfig>(state: CommandState<Args, Options, Globals>, input: ArgumentInput<Name, Config>): CommandState<Args & Record<Name, ArgumentValue<Config>>, Options, Globals>;
|
|
136
170
|
/** The declared value joins `options` under its literal name, typed by its own config. */
|
|
137
171
|
export declare function declareOption<Args, Options, Globals, Name extends string, Config extends OptionConfig>(state: CommandState<Args, Options, Globals>, input: OptionInput<Name, Config>): CommandState<Args, Options & Record<Name, OptionValue<Config>>, Globals>;
|
|
172
|
+
/** Globals close when composition starts; retain late calls for the shared build-order check. */
|
|
173
|
+
export declare function recordGlobalOption<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, name: string): CommandState<Args, Options, Globals>;
|
|
138
174
|
/** One call's names stay one group, so the empty call the types reject still reports as one. */
|
|
139
175
|
export declare function declareAlias<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, names: AliasDeclaration): CommandState<Args, Options, Globals>;
|
|
140
|
-
|
|
176
|
+
/** Extension layers remain open after inputs and the action have been fixed. */
|
|
177
|
+
export declare function declareExtensions<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, values: readonly ExtensionValue<'command'>[]): CommandState<Args, Options, Globals>;
|
|
178
|
+
/**
|
|
179
|
+
* The handler is typed against the result its own declaration carries, and the state holds one
|
|
180
|
+
* list for every declaration, so the context each handler receives is read back at the call.
|
|
181
|
+
*/
|
|
182
|
+
export declare function declareAction<Args, Options, Globals, Result>(state: CommandState<Args, Options, Globals>, handler: Action<Args, Globals & Options, Result>): CommandState<Args, Options, Globals>;
|
|
183
|
+
/** The result declaration, which closes both result calls and reports lateness like the rest. */
|
|
184
|
+
export declare function declareResult<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, kind: 'value' | 'rows', declaration: unknown): CommandState<Args, Options, Globals>;
|
|
185
|
+
/** A `views()` call reshapes views and closes nothing, so it is never a late declaration. */
|
|
186
|
+
export declare function declareResultViews<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, replacements: unknown, options: unknown): CommandState<Args, Options, Globals>;
|
|
141
187
|
/** Attaching is a declaration call too, so the receiver keeps the children it already had. */
|
|
142
188
|
export declare function attachChild<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, child: object): CommandState<Args, Options, Globals>;
|
|
143
189
|
/** Validates one declaration against the shared globals table and compiles it for dispatch. */
|
|
@@ -149,27 +195,57 @@ export interface BuiltGraph {
|
|
|
149
195
|
root: BuiltCommand;
|
|
150
196
|
}
|
|
151
197
|
/** The globals table and the owners record each compile once per invocation and the whole graph shares them. */
|
|
152
|
-
export declare function buildGraph<Args, Options, Globals>(root: CommandState<Args, Options, Globals>, install: PluginBuild & {
|
|
198
|
+
export declare function buildGraph<Args, Options, Globals>(root: CommandState<Args, Options, Globals>, globals: GlobalsState<Globals>, install: PluginBuild & {
|
|
153
199
|
plugins: readonly BuiltPlugin[];
|
|
154
200
|
}): BuiltGraph;
|
|
155
|
-
export declare class CommandBuilder<Args, Options, Globals, State extends CommandMethod = CommandMethod> {
|
|
201
|
+
export declare class CommandBuilder<Args, Options, Globals, State extends CommandMethod = CommandMethod, Result = unknown> {
|
|
156
202
|
#private;
|
|
157
203
|
readonly [commandValue]: true;
|
|
158
|
-
readonly [declaredTypes]: DeclaredTypes<Args, Options, Globals>;
|
|
204
|
+
readonly [declaredTypes]: DeclaredTypes<Args, Options, Globals, Result>;
|
|
159
205
|
constructor(state: CommandState<Args, Options, Globals>);
|
|
160
206
|
get name(): string | null;
|
|
161
|
-
argument<const Name extends string, const Config extends ArgumentConfig>(name: Name, config: Config & NameConstraint<Name> & NoInfer<DefaultConstraint<Config>> & NoInfer<ValidateOmittedConstraint<Config>>): Command<Args & Record<Name, ArgumentValue<Config>>, Options, Globals, AfterArgument<State
|
|
162
|
-
option<const Name extends string, const Config extends OptionConfig>(name: Name, config: Config & NameConstraint<Name> & GlobalNameConstraint<Name, Globals> & NoInfer<DefaultConstraint<Config>> & NoInfer<MultipleConstraint<Config>> & NoInfer<ValidateOmittedConstraint<Config>>): Command<Args, Options & Record<Name, OptionValue<Config>>, Globals, State>;
|
|
207
|
+
argument<const Name extends string, const Config extends ArgumentConfig>(name: Name, config: Config & NameConstraint<Name> & NoInfer<DefaultConstraint<Config>> & NoInfer<ValidateOmittedConstraint<Config>>): Command<Args & Record<Name, ArgumentValue<Config>>, Options, Globals, AfterArgument<State>, Result>;
|
|
208
|
+
option<const Name extends string, const Config extends OptionConfig>(name: Name, config: Config & NameConstraint<Name> & GlobalNameConstraint<Name, Globals> & NoInfer<DefaultConstraint<Config>> & NoInfer<MultipleConstraint<Config>> & NoInfer<ValidateOmittedConstraint<Config>>): Command<Args, Options & Record<Name, OptionValue<Config>>, Globals, State, Result>;
|
|
163
209
|
/**
|
|
164
210
|
* Aliases are other bare tokens that route to this Command. They invalidate no call, and the
|
|
165
211
|
* tuple rest parameter rejects a call that names none.
|
|
166
212
|
*/
|
|
167
|
-
alias(...names: [string, ...string[]]): Command<Args, Options, Globals, State>;
|
|
213
|
+
alias(...names: [string, ...string[]]): Command<Args, Options, Globals, State, Result>;
|
|
168
214
|
/** A child arrives in any type state, because its own action is the call that finished it. */
|
|
169
|
-
command
|
|
170
|
-
/**
|
|
171
|
-
|
|
215
|
+
command<const Child extends Command<unknown, unknown, Globals>>(child: Child & NoInfer<AttachmentConstraint<Globals, Child>>): Command<Args, Options, Globals, AfterCommand<State>, Result>;
|
|
216
|
+
/**
|
|
217
|
+
* The value this Command produces for its consumer. The type argument is stated by the author,
|
|
218
|
+
* so the views record states no type of its own and an omitted argument names none either.
|
|
219
|
+
*/
|
|
220
|
+
result<Value>(declaration: {
|
|
221
|
+
views: ResultViews<NoInfer<Value>>;
|
|
222
|
+
}): Command<Args, Options, Globals, AfterResult<State>, {
|
|
223
|
+
kind: 'value';
|
|
224
|
+
value: Value;
|
|
225
|
+
}>;
|
|
226
|
+
/** The same declaration over a sequence, whose type argument is one row. */
|
|
227
|
+
rows<Row>(declaration: {
|
|
228
|
+
views: RowViews<NoInfer<Row>>;
|
|
229
|
+
}): Command<Args, Options, Globals, AfterResult<State>, {
|
|
230
|
+
kind: 'rows';
|
|
231
|
+
row: Row;
|
|
232
|
+
}>;
|
|
233
|
+
/**
|
|
234
|
+
* Views after the fact. It merges by key, so an existing name is replaced in place and a new one
|
|
235
|
+
* is appended, and `default` names the key core renders when nothing selects another.
|
|
236
|
+
*/
|
|
237
|
+
views(replacements: ResultViewsOf<Result>, options?: {
|
|
238
|
+
default?: string;
|
|
239
|
+
}): Command<Args, Options, Globals, State, Result>;
|
|
240
|
+
/** The action closes input authoring; `extend()` remains outside this state transition. */
|
|
241
|
+
action(handler: Action<Args, Globals & Options, Result>): Command<Args, Options, Globals, AfterAction, Result>;
|
|
242
|
+
extend(...values: readonly ExtensionValue<'command'>[]): Command<Args, Options, Globals, State, Result>;
|
|
172
243
|
build(context: BuildContext): BuiltCommand;
|
|
244
|
+
/**
|
|
245
|
+
* The same runtime value in the state the calling method's return type names. Each call states
|
|
246
|
+
* its own transition, and the declared result travels with it unless the call replaces it.
|
|
247
|
+
*/
|
|
248
|
+
private derive;
|
|
173
249
|
}
|
|
174
250
|
/**
|
|
175
251
|
* The authoring surface of a Command in one type state. Every call returns a new declaration value,
|
|
@@ -178,22 +254,30 @@ export declare class CommandBuilder<Args, Options, Globals, State extends Comman
|
|
|
178
254
|
* calls a value still offers. It defaults to the state after `action()`, which publishes the fewest
|
|
179
255
|
* calls, so `Command<A, O, G>` accepts a Command in any state, a finished one included.
|
|
180
256
|
*/
|
|
181
|
-
export type Command<Args = {}, Options = {}, Globals = {}, State extends CommandMethod = AfterAction> = Pick<CommandBuilder<Args, Options, Globals, State>, typeof commandValue | typeof declaredTypes | State
|
|
257
|
+
export type Command<Args = {}, Options = {}, Globals = {}, State extends CommandMethod = AfterAction, Result = unknown> = Pick<CommandBuilder<Args, Options, Globals, State, Result>, typeof commandValue | typeof declaredTypes | 'extend' | State | ResultMethod<Result>>;
|
|
182
258
|
/**
|
|
183
|
-
*
|
|
184
|
-
*
|
|
259
|
+
* `views()` is published in every state on a declaration that carries a result, and on none that
|
|
260
|
+
* carries none. It is a key of the picked surface rather than a member of the state union, because
|
|
261
|
+
* the state union answers the calls a declaration closes and this one closes nothing.
|
|
185
262
|
*/
|
|
186
|
-
export
|
|
187
|
-
|
|
263
|
+
export type ResultMethod<Result> = unknown extends Result ? never : 'views';
|
|
264
|
+
/**
|
|
265
|
+
* The core facts and initial extension values a named Command carries.
|
|
266
|
+
*/
|
|
267
|
+
export interface CommandOptions {
|
|
188
268
|
description?: string;
|
|
189
269
|
hidden?: boolean;
|
|
190
270
|
deprecated?: string;
|
|
191
271
|
extensions?: readonly ExtensionValue<'command'>[];
|
|
192
272
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
273
|
+
/** Collect every union member's known local keys before testing for a global collision. */
|
|
274
|
+
type LocalKeys<Child> = Child extends {
|
|
275
|
+
readonly [declaredTypes]: {
|
|
276
|
+
options: infer Options;
|
|
277
|
+
};
|
|
278
|
+
} ? keyof Options : never;
|
|
279
|
+
export type AttachmentConstraint<Globals, Child> = Extract<keyof Globals, LocalKeys<Child>> extends never ? unknown : never;
|
|
280
|
+
type CommandConstructor = new (name: string, options?: CommandOptions) => Command<{}, {}, RegisteredGlobals, CommandMethod>;
|
|
197
281
|
/** The public constructor takes a name and one options object, as the Application does. */
|
|
198
282
|
export declare const Command: CommandConstructor;
|
|
199
283
|
/** Every declaration in the graph, so defaults are validated before any token is read. */
|
|
@@ -213,15 +297,35 @@ export interface RoutedInvocation {
|
|
|
213
297
|
}
|
|
214
298
|
/** Consumes the globals table, then routes the remaining bare tokens to a Command. */
|
|
215
299
|
export declare function routeInvocation(graph: BuiltGraph, argv: readonly string[]): RoutedInvocation;
|
|
216
|
-
/**
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
*/
|
|
221
|
-
export declare function prepareDispatch(graph: BuiltGraph, routed: RoutedInvocation, invocation: {
|
|
300
|
+
/** What one invocation reaches the middleware chain with. */
|
|
301
|
+
export interface DispatchInvocation {
|
|
302
|
+
/** The channel the action receives, which the results lane builds from the routed node. */
|
|
303
|
+
channel: (binding: ResultBinding) => ActionChannel;
|
|
222
304
|
defaults: DefaultValues;
|
|
223
305
|
host: Host;
|
|
224
|
-
out: Out;
|
|
225
306
|
signal: AbortSignal;
|
|
226
|
-
|
|
307
|
+
style: ContextualStyle;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* One invocation prepared ahead of the middleware chain. `'ready'` carries the request a middleware
|
|
311
|
+
* reads and the call that dispatches; `'held'` carries the fault this phase found, which core
|
|
312
|
+
* raises at the dispatch boundary and never before, so a takeover swallows it. `result` is what the
|
|
313
|
+
* routed Command declared, whose views a middleware selects among, on either shape.
|
|
314
|
+
*/
|
|
315
|
+
export type Prepared = {
|
|
316
|
+
result: DeclaredResult | undefined;
|
|
317
|
+
} & ({
|
|
318
|
+
dispatch: (view: string | null) => Promise<void>;
|
|
319
|
+
kind: 'ready';
|
|
320
|
+
request: Request;
|
|
321
|
+
} | {
|
|
322
|
+
fault: unknown;
|
|
323
|
+
kind: 'held';
|
|
324
|
+
request: null;
|
|
325
|
+
});
|
|
326
|
+
/**
|
|
327
|
+
* Prepares one dispatch ahead of the middleware chain and holds whatever fault it found, so a
|
|
328
|
+
* middleware reads the request before the action runs and a takeover never observes the fault.
|
|
329
|
+
*/
|
|
330
|
+
export declare function prepareDispatch(graph: BuiltGraph, routed: RoutedInvocation, invocation: DispatchInvocation): Promise<Prepared>;
|
|
227
331
|
export {};
|