@loomcli/core 0.4.0 → 0.5.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/chain.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { prepareDispatch, routeInvocation } from './command.js';
2
2
  import { InternalError, reasonOf, routedSubject, toFailure } from './errors.js';
3
- import { inspectGraph } from './inspect.js';
4
- import { booleanValue } from './options.js';
5
- import { pluginSentence } from './plugin.js';
3
+ import { inspectGraph, nodeAt } from './inspect.js';
4
+ import { isSupplied } from './options.js';
5
+ import { loadDefault, pluginSentence, pluginSpellings, pluginValues } from './plugin.js';
6
6
  /**
7
7
  * The view one run selects, which is one value whichever middleware wrote it. The assignment is
8
8
  * kept as it arrived, because a JavaScript caller reaches the setter with any value and the check
@@ -72,79 +72,33 @@ class ViewSelection {
72
72
  function isMiddlewareExport(value) {
73
73
  return typeof value === 'function';
74
74
  }
75
- /** Whether one option name was supplied as a token, in any spelling a declaration accepts. */
76
- function supplied(scan, name) {
77
- return scan.strings.has(name) || scan.lists.has(name) || scan.booleans.has(name);
78
- }
79
- /** A collected value, or the declared array default, as this run's own copy. */
80
- function collectedValue(collected, declared) {
81
- if (collected) {
82
- return [...collected];
83
- }
84
- return Array.isArray(declared) ? [...declared] : [];
85
- }
86
75
  /**
87
- * One plugin's own option values for one run: what the pre-scan produced, or the declared default,
88
- * filled without validation. A collected value and an array default are copied, so a middleware
89
- * that writes to what it received changes neither the declaration nor the next run.
76
+ * Whether one plugin's declared activation matched. A listed option activates when argv or an input
77
+ * source supplied it, whatever value it holds, and a declared default never does.
90
78
  */
91
- function pluginValues(inputs, scan) {
92
- const values = {};
93
- for (const { config, name } of inputs) {
94
- const declared = config.default;
95
- if (config.type === 'boolean') {
96
- values[name] = booleanValue(scan, name, config);
97
- }
98
- else if (config.multiple === true) {
99
- values[name] = collectedValue(scan.lists.get(name), declared);
100
- }
101
- else {
102
- // Build already proved that a string option without a schema declares a string default.
103
- values[name] =
104
- scan.strings.get(name) ?? (typeof declared === 'string' ? declared : undefined);
105
- }
106
- }
107
- return values;
108
- }
109
- /** Whether one plugin's declared activation matched the tokens the pre-scan consumed. */
110
- function activates(installed, scan) {
79
+ function activates(installed, values) {
111
80
  const { middleware } = installed;
112
81
  if (!middleware) {
113
82
  return false;
114
83
  }
115
- return (middleware.activate === 'always' || middleware.activate.some((name) => supplied(scan, name)));
84
+ return (middleware.activate === 'always' || middleware.activate.some((name) => isSupplied(values, name)));
116
85
  }
117
86
  /**
118
87
  * The chain for one invocation: each installed plugin whose activation matched, in installation
119
- * order. Activation is read from the pre-scan, before any plugin code loads, so a plugin whose
120
- * option was never supplied is not in the chain and its loader is never called.
88
+ * order. Activation is read after the input-source stage and before any plugin code loads, so a
89
+ * plugin whose option no tier supplied is not in the chain and its loader is never called.
121
90
  */
122
- function activatedEntries(plugins, scan) {
91
+ function activatedEntries(plugins, values) {
123
92
  return plugins
124
- .filter((installed) => activates(installed, scan))
93
+ .filter((installed) => activates(installed, values))
125
94
  .map((installed) => ({
126
95
  identity: installed.identity,
127
96
  // Activation proved the middleware exists, so the empty loader is never the one core calls.
128
97
  load: installed.middleware?.load ?? (() => undefined),
129
- options: pluginValues(installed.inputs, scan),
98
+ options: pluginValues(installed.inputs, values),
99
+ spellings: pluginSpellings(installed.inputs, values),
130
100
  }));
131
101
  }
132
- /**
133
- * The routed node inside the inspected graph, which routing already proved reachable. A missing
134
- * segment means the two readings of one graph disagree, so the chain stops rather than hand a
135
- * middleware the wrong Command.
136
- */
137
- function nodeAt(graph, path) {
138
- let node = graph.root;
139
- for (const name of path) {
140
- const child = node.children.find((entry) => entry.name === name);
141
- if (!child) {
142
- throw new InternalError(`The routed command "${path.join(' ')}" is not in the inspected graph.`, undefined);
143
- }
144
- node = child;
145
- }
146
- return node;
147
- }
148
102
  /** A downstream promise core awaits for its completion alone; its outcome was recorded already. */
149
103
  async function quiet(pending) {
150
104
  if (pending) {
@@ -240,25 +194,12 @@ async function settle(turn, thrown) {
240
194
  // The recorded failure still decides the exit code.
241
195
  return reported(chain, state.outcome ?? (chain.invoked() ? 'dispatched' : 'taken-over'));
242
196
  }
243
- /** The module one loader answers with, whether it throws where it is called or rejects later. */
244
- async function loadModule(entry) {
245
- try {
246
- return await entry.load();
247
- }
248
- catch (error) {
249
- throw new InternalError(`Loading plugin "${entry.identity}" failed: ${reasonOf(error)}`, error);
250
- }
251
- }
252
197
  /** A plugin's module is loaded when the chain reaches it, never before. */
253
- async function loadMiddleware(entry) {
254
- const module = await loadModule(entry);
255
- const handler = module !== null && typeof module === 'object' && 'default' in module
256
- ? module.default
257
- : undefined;
258
- if (!isMiddlewareExport(handler)) {
259
- throw new InternalError(`Loading plugin "${entry.identity}" failed: the module exports no default middleware function.`, undefined);
260
- }
261
- return handler;
198
+ function loadMiddleware(entry) {
199
+ return loadDefault(entry.identity, entry.load, {
200
+ guard: isMiddlewareExport,
201
+ noun: 'middleware',
202
+ });
262
203
  }
263
204
  /** One entry's turn: its module loads here, when the chain reaches it and never before. */
264
205
  async function runEntry(entry, index, chain) {
@@ -278,7 +219,7 @@ async function runEntry(entry, index, chain) {
278
219
  }
279
220
  /** The whole chain, answering with the failure it raised when a middleware caught that failure. */
280
221
  async function runChain(invocation, routed, prepared) {
281
- const entries = activatedEntries(invocation.plugins, routed.scan);
222
+ const entries = activatedEntries(invocation.plugins, prepared.globals);
282
223
  const run = { invoked: false, raised: undefined };
283
224
  const selection = new ViewSelection(prepared.result);
284
225
  /**
@@ -304,7 +245,7 @@ async function runChain(invocation, routed, prepared) {
304
245
  return undefined;
305
246
  }
306
247
  // The graph a middleware reads is the one `inspect()` returns, built once for the run.
307
- const graph = inspectGraph(invocation.name, invocation.graph, invocation.facts);
248
+ const graph = invocation.inspected();
308
249
  const command = nodeAt(graph, routed.path);
309
250
  // Every fault this chain has reported, so the same one raised again carries no second report.
310
251
  const announced = new WeakSet();
@@ -320,6 +261,7 @@ async function runChain(invocation, routed, prepared) {
320
261
  out: invocation.out,
321
262
  request: prepared.request,
322
263
  signal: invocation.signal,
264
+ spellings: entry.spellings,
323
265
  get view() {
324
266
  return selection.read();
325
267
  },
@@ -360,8 +302,13 @@ async function runChain(invocation, routed, prepared) {
360
302
  async function runInvocation(invocation) {
361
303
  const routed = routeInvocation(invocation.graph, invocation.host.argv);
362
304
  invocation.route(routed.path);
363
- const prepared = await prepareDispatch(invocation.graph, routed, invocation);
364
- const raised = await runChain(invocation, routed, prepared);
305
+ // The graph `inspect()` returns, built at most once for the run.
306
+ // A configuration source reads its requests from it, and the chain reads it after the source.
307
+ let graph = undefined;
308
+ const inspected = () => (graph ??= inspectGraph(invocation.name, invocation.graph, invocation.facts));
309
+ const run = { ...invocation, inspected };
310
+ const prepared = await prepareDispatch(invocation.graph, routed, run);
311
+ const raised = await runChain(run, routed, prepared);
365
312
  if (raised) {
366
313
  // The chain resolved because a middleware caught the rejection.
367
314
  // The failure it caught still decides the exit code.
package/dist/command.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import type { RegisteredGlobals } from './environment.js';
2
- import type { DescriptorRegistry, ExtensionRecords, ExtensionValue } from './extension.js';
3
- import type { BuiltGlobals, GlobalsState } from './globals.js';
2
+ import type { AnyExtension, DescriptorRegistry, ExtensionRecords, ExtensionStore, ExtensionSubject, ExtensionValue } from './extension.js';
3
+ import type { BuiltGlobals, GlobalsState, GlobalTable, InputRecords } from './globals.js';
4
+ import type { CommandGraph, CommandNode } from './inspect.js';
4
5
  import { compileOptions } from './options.js';
5
6
  import type { OptionValues } from './options.js';
6
- import type { BuiltPlugin, PluginBuild } from './plugin.js';
7
+ import type { BuiltPlugin } from './plugin.js';
7
8
  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';
9
+ import type { Action, ActionChannel, ArgumentConfig, ArgumentValue, declaredTypes, DeclaredResult, DeclaredTypes, DefaultConstraint, GlobalNameConstraint, Host, PerValueConstraint, NameConstraint, OpenResult, OptionConfig, OptionValue, Out, Request, ResultBinding, ResultViews, ResultViewsOf, RowViews, ValidateOmittedConstraint } from './types.js';
9
10
  import type { ArgumentInput, DefaultValues, InputDeclaration, OptionInput, ValidatedInputs } from './validation.js';
10
11
  /** One positional slot: the declaration it fills and whether it takes the remaining tokens. */
11
12
  export interface ArgumentSlot {
@@ -13,7 +14,15 @@ export interface ArgumentSlot {
13
14
  required: boolean;
14
15
  variadic: boolean;
15
16
  }
17
+ /**
18
+ * What one dispatch hands its action. `graph` and `command` are the run's inspected graph and the
19
+ * routed node inside it, the values its middleware read. Each builds on its first read, so a run
20
+ * whose action reads neither, whose chain is empty, and which asks no configuration source renders
21
+ * no graph and calls no converter.
22
+ */
16
23
  export interface DispatchInput {
24
+ command: () => CommandNode;
25
+ graph: () => CommandGraph;
17
26
  style: ContextualStyle;
18
27
  host: Host;
19
28
  /** The action's channel, whose `results` accepts whatever the routed declaration named. */
@@ -57,8 +66,8 @@ export interface BuiltCommand {
57
66
  export declare const commandValue: unique symbol;
58
67
  /**
59
68
  * The input, alias, child, and action calls a Command can publish. Its type state is a subset,
60
- * and each call removes the names it invalidates. A Command attaches children at any depth, so
61
- * `command()` belongs to every Command and to the unnamed root alike.
69
+ * and each call removes the names it invalidates. `command()` belongs to every Command and to the
70
+ * unnamed root alike, and attach bounds how deep the children it adds may nest.
62
71
  */
63
72
  export type CommandMethod = 'action' | 'alias' | 'argument' | 'command' | 'option' | 'result' | 'rows';
64
73
  /** One Command declares arguments or attaches children, so the first call removes the other. */
@@ -69,57 +78,48 @@ export type AfterCommand<State> = Exclude<State, 'argument'>;
69
78
  export type AfterResult<State> = Exclude<State, 'result' | 'rows'>;
70
79
  /** Registering the action closes input, alias, child, and further action declarations. */
71
80
  export type AfterAction = never;
72
- /** A declaration made after its authoring phase closed; build reports the first in call order. */
73
- type LateDeclaration = {
74
- alias: string;
75
- kind: 'alias';
76
- } | {
77
- name: string;
78
- kind: 'global';
79
- } | {
80
- child: object;
81
- kind: 'child';
82
- } | {
83
- kind: 'result';
84
- } | {
85
- input: InputDeclaration;
86
- kind: 'input';
87
- };
88
81
  /**
89
- * The names one `alias()` call declares. Each call keeps its own group, so a call that names none,
90
- * which the types reject and a JavaScript author can still write, reports as the call it is.
82
+ * The private handle one graph node is reached through, without its inferred declaration types:
83
+ * what attach and the Application's walk read, and the build that compiles the node.
91
84
  */
92
- type AliasDeclaration = readonly string[];
93
- /** The private handle one graph node is built through, without its inferred declaration types. */
94
- interface CommandNodeHandle {
95
- readonly name: string | null;
85
+ export interface CommandNodeHandle {
86
+ readonly declared: Declared;
87
+ readonly hasAction: boolean;
88
+ readonly name: string;
96
89
  build(context: BuildContext): BuiltCommand;
97
90
  }
91
+ /** One attached child, under the canonical name its parent's namespace holds it by. */
92
+ export interface AttachedChild {
93
+ readonly name: string;
94
+ readonly node: CommandNodeHandle;
95
+ }
98
96
  /**
99
- * One graph build's shared state. `globals` compiles once and every Command reads it. `owners`
100
- * records the name of the parent that claimed each node, so a second parent holding the same value
101
- * is building a graph with more than one path to that node, not a tree. The build is a depth-first
102
- * walk in attachment order, and a parent claims each child as the walk reaches it, so the first
103
- * owner is the parent whose attachment the walk meets first.
97
+ * One graph build's shared state. `globals` compiles once and every Command reads it. The build is
98
+ * a depth-first walk in attachment order.
104
99
  */
105
100
  interface BuildContext {
106
101
  descriptors: DescriptorRegistry;
107
102
  extensions: ExtensionRecords;
108
103
  globals: BuiltGlobals;
109
- owners: Map<CommandNodeHandle, string | null>;
110
104
  /** The route from the root to the Command being built, which a lifecycle hook reads. */
111
105
  path: readonly string[];
112
106
  /** The installed plugins in installation order, whose hooks run over every Command. */
113
107
  plugins: readonly BuiltPlugin[];
114
108
  }
109
+ /** The handle behind a value an author built as a Command, or nothing for any other value. */
110
+ export declare function commandNode(value: unknown): CommandNodeHandle | undefined;
115
111
  /**
116
- * Everything one Command declaration holds. The transitions below copy it with fields replaced, and
117
- * the Command and Application builders share them, so one declaration call has one implementation.
112
+ * The portable name rule, for every name an operator types as a command at a shell prompt: the
113
+ * application name, every Command name, and every alias. The characters are the POSIX portable
114
+ * filename set, and a name starts with neither `-`, which reads as an option, nor `.`, which a
115
+ * shell hides.
118
116
  */
117
+ export declare function isPortableName(name: unknown): name is string;
118
+ /** The one correction every portable name diagnostic ends with. */
119
+ export declare const portableNameCorrection = "Use a nonempty name of A-Z, a-z, 0-9, \".\", \"_\", and \"-\" that does not start with \"-\" or \".\".";
119
120
  /**
120
121
  * One call of the results lane, in the order it was made. A `result()` or `rows()` call declares
121
122
  * 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
123
  */
124
124
  export type ResultCall = {
125
125
  kind: 'value' | 'rows';
@@ -129,64 +129,128 @@ export type ResultCall = {
129
129
  kind: 'views';
130
130
  views: unknown;
131
131
  };
132
+ /** The core facts a named Command declares, which its constructor checked. The root carries none. */
133
+ export interface CommandFacts {
134
+ deprecated: string | undefined;
135
+ description: string | undefined;
136
+ hidden: boolean;
137
+ }
138
+ /**
139
+ * Everything one Command declaration holds, each part checked by the call that added it. The
140
+ * transitions below copy it with fields replaced, and the Command and Application builders share
141
+ * them, so one declaration call has one implementation.
142
+ */
132
143
  export interface CommandState<Args, Options, Globals> {
133
144
  /**
134
- * The registered actions, with the declared result erased. An action is stored under the widest
145
+ * The registered action, with the declared result erased. An action is stored under the widest
135
146
  * result, so a handler typed from its own declaration stores here and the channel that carries
136
147
  * the result is built for it at dispatch.
137
148
  */
138
- actions: readonly Action<Args, Globals & Options, OpenResult>[];
139
- aliases: readonly AliasDeclaration[];
149
+ action: Action<Args, Globals & Options, OpenResult> | undefined;
150
+ aliases: readonly string[];
140
151
  bind: (values: ValidatedInputs) => {
141
152
  args: Args;
142
153
  options: Options;
143
154
  };
144
- children: readonly object[];
145
- deprecated: unknown;
146
- description: unknown;
147
- extensions: readonly unknown[];
148
- hidden: unknown;
155
+ children: readonly AttachedChild[];
156
+ /**
157
+ * Every descriptor this declaration's extension values name, by identity. The root's holds the
158
+ * whole Application's: its plugins', its global options', and every attached subtree's.
159
+ */
160
+ descriptors: ReadonlyMap<string, AnyExtension>;
161
+ /** The extension values of every layer, validated at the call that carried each one. */
162
+ extensions: ExtensionStore;
163
+ facts: CommandFacts;
149
164
  inputs: readonly InputDeclaration[];
150
- late: readonly LateDeclaration[];
151
165
  name: string | null;
152
- options: unknown;
166
+ /** The extension record each input's own call validated. */
167
+ records: InputRecords;
153
168
  results: readonly ResultCall[];
154
169
  }
170
+ /** The untyped part of a declaration, which every attach and build check reads. */
171
+ export type Declared = Pick<CommandState<unknown, unknown, unknown>, 'aliases' | 'children' | 'descriptors' | 'inputs' | 'name' | 'records' | 'results'>;
172
+ /** How the extension diagnostics of one Command's own layers name it. */
173
+ export declare function layerOf(name: string | null): ExtensionSubject;
155
174
  /**
156
- * The state every declaration starts from. The unnamed root and each named Command share it.
157
- * The declaration values arrive captured, because a later change to the options object the author
158
- * passed changes nothing the declaration holds.
175
+ * The state every declaration starts from. The unnamed root and each named Command share it. The
176
+ * declaration values arrive checked, because the constructor that read them threw for any fault.
159
177
  */
160
178
  export declare function freshState<Globals>(declaration: {
161
- deprecated: unknown;
162
- description: unknown;
163
- extensions: unknown;
164
- hidden: unknown;
179
+ descriptors: ReadonlyMap<string, AnyExtension>;
180
+ extensions: ExtensionStore;
181
+ facts: CommandFacts;
165
182
  name: string | null;
166
- options: unknown;
167
183
  }): CommandState<{}, {}, Globals>;
168
184
  /** The declared value joins `args` under its literal name, typed by its own config. */
169
185
  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>;
170
- /** The declared value joins `options` under its literal name, typed by its own config. */
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>;
174
- /** One call's names stay one group, so the empty call the types reject still reports as one. */
175
- export declare function declareAlias<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, names: AliasDeclaration): CommandState<Args, Options, Globals>;
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>;
186
+ /**
187
+ * The declared value joins `options` under its literal name, typed by its own config. The root's
188
+ * options also meet the Application's globals table, which a named Command meets when its subtree
189
+ * joins an Application.
190
+ */
191
+ export declare function declareOption<Args, Options, Globals, Name extends string, Config extends OptionConfig>(state: CommandState<Args, Options, Globals>, input: OptionInput<Name, Config>, table?: GlobalTable): CommandState<Args, Options & Record<Name, OptionValue<Config>>, Globals>;
192
+ /**
193
+ * One call's names join the Command's aliases. A call that names none, which the types reject and
194
+ * a JavaScript author can still write, reports as the call it is.
195
+ */
196
+ export declare function declareAlias<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, names: readonly string[]): CommandState<Args, Options, Globals>;
197
+ /**
198
+ * Extension layers remain open after inputs and the action have been fixed. Each layer is validated
199
+ * at its own call, against every descriptor the declaration already names.
200
+ */
201
+ export declare function declareExtensions<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, values: readonly unknown[]): CommandState<Args, Options, Globals>;
178
202
  /**
179
203
  * 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.
204
+ * action for every declaration, so the context the handler receives is read back at the call.
181
205
  */
182
206
  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. */
207
+ /**
208
+ * The result declaration, which closes both result calls. Every rule its own call can judge throws
209
+ * here; the empty record and the default wait for attach, because `views()` can still add keys.
210
+ */
184
211
  export declare function declareResult<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, kind: 'value' | 'rows', declaration: unknown): CommandState<Args, Options, Globals>;
185
212
  /** A `views()` call reshapes views and closes nothing, so it is never a late declaration. */
186
213
  export declare function declareResultViews<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, replacements: unknown, options: unknown): CommandState<Args, Options, Globals>;
187
- /** Attaching is a declaration call too, so the receiver keeps the children it already had. */
188
- export declare function attachChild<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, child: object): CommandState<Args, Options, Globals>;
189
- /** Validates one declaration against the shared globals table and compiles it for dispatch. */
214
+ /** The parent one attach reads: its name, the children it holds, and the calls that close it. */
215
+ interface AttachParent {
216
+ /** The first argument the parent declares, which no child may sit beside. */
217
+ argument: string | undefined;
218
+ children: readonly AttachedChild[];
219
+ hasAction: boolean;
220
+ name: string | null;
221
+ }
222
+ /**
223
+ * The one attach operation `Command.command()`, `Application.command()`, and a plugin's
224
+ * `commands` list share. A Command is an immutable value, so the child is final here: it is checked
225
+ * as a finished Command, against the parent's current children, and against the nesting cap from
226
+ * the shallowest level the parent can sit at.
227
+ */
228
+ export declare function attach(parent: AttachParent, node: CommandNodeHandle): AttachedChild;
229
+ /** The handle behind the value one `command()` call received; anything else is a declaration error. */
230
+ export declare function childNode(parent: string | null, child: unknown): CommandNodeHandle;
231
+ /** What an Application holds while a subtree joins it, each register a copy the caller commits. */
232
+ interface JoinScope {
233
+ descriptors: DescriptorRegistry;
234
+ /** The parent that claimed each node the Application holds, by the name a diagnostic reads. */
235
+ owners: Map<CommandNodeHandle, string | null>;
236
+ table: GlobalTable;
237
+ }
238
+ /**
239
+ * Attaches one child to an Application's root and walks the subtree it brings, once. The scope's
240
+ * registers are copies: the caller commits the owners, and the returned root holds the descriptors.
241
+ */
242
+ export declare function attachToRoot<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, node: CommandNodeHandle, scope: JoinScope): CommandState<Args, Options, Globals>;
243
+ /**
244
+ * A declaration's own options and every attached Command's, against a globals table that has just
245
+ * grown. The table's new option reads as the other side of any collision.
246
+ */
247
+ export declare function checkDeclaredOptions(state: Declared, table: GlobalTable): void;
248
+ /**
249
+ * Compiles one declaration for dispatch against the shared globals table. Every authored rule threw
250
+ * at the call or the attach that first held its data, so what can still fail here is the root's
251
+ * finished-Command rules, the root never being attached, and whatever the lifecycle hooks
252
+ * contributed.
253
+ */
190
254
  export declare function buildCommand<Args, Options, Globals>(state: CommandState<Args, Options, Globals>, context: BuildContext): BuiltCommand;
191
255
  /** One built graph: the shared globals table, the root Command, and the facts each node carries. */
192
256
  export interface BuiltGraph {
@@ -194,20 +258,20 @@ export interface BuiltGraph {
194
258
  globals: BuiltGlobals;
195
259
  root: BuiltCommand;
196
260
  }
197
- /** The globals table and the owners record each compile once per invocation and the whole graph shares them. */
198
- export declare function buildGraph<Args, Options, Globals>(root: CommandState<Args, Options, Globals>, globals: GlobalsState<Globals>, install: PluginBuild & {
199
- plugins: readonly BuiltPlugin[];
200
- }): BuiltGraph;
261
+ /**
262
+ * The globals table compiles once per build and the whole graph shares it. The root's registry
263
+ * holds every descriptor the Application names, so a hook's `extend()` call meets all of them.
264
+ */
265
+ export declare function buildGraph<Args, Options, Globals>(root: CommandState<Args, Options, Globals>, globals: GlobalsState<Globals>, plugins: readonly BuiltPlugin[]): BuiltGraph;
201
266
  export declare class CommandBuilder<Args, Options, Globals, State extends CommandMethod = CommandMethod, Result = unknown> {
202
267
  #private;
203
268
  readonly [commandValue]: true;
204
269
  readonly [declaredTypes]: DeclaredTypes<Args, Options, Globals, Result>;
205
- constructor(state: CommandState<Args, Options, Globals>);
206
- get name(): string | null;
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>;
270
+ constructor(name: string, state: CommandState<Args, Options, Globals>);
271
+ argument<const Name extends string, const Config extends ArgumentConfig>(name: Name, config: Config & NameConstraint<Name> & NoInfer<DefaultConstraint<Config>> & NoInfer<PerValueConstraint<Config>> & NoInfer<ValidateOmittedConstraint<Config>>): Command<Args & Record<Name, ArgumentValue<Config>>, Options, Globals, AfterArgument<State>, Result>;
272
+ option<const Name extends string, const Config extends OptionConfig>(name: Name, config: Config & NameConstraint<Name> & GlobalNameConstraint<Name, Globals> & NoInfer<DefaultConstraint<Config>> & NoInfer<PerValueConstraint<Config>> & NoInfer<ValidateOmittedConstraint<Config>>): Command<Args, Options & Record<Name, OptionValue<Config>>, Globals, State, Result>;
209
273
  /**
210
- * Aliases are other bare tokens that route to this Command. They invalidate no call, and the
274
+ * Aliases are other portable names that route to this Command. They invalidate no call, and the
211
275
  * tuple rest parameter rejects a call that names none.
212
276
  */
213
277
  alias(...names: [string, ...string[]]): Command<Args, Options, Globals, State, Result>;
@@ -240,12 +304,6 @@ export declare class CommandBuilder<Args, Options, Globals, State extends Comman
240
304
  /** The action closes input authoring; `extend()` remains outside this state transition. */
241
305
  action(handler: Action<Args, Globals & Options, Result>): Command<Args, Options, Globals, AfterAction, Result>;
242
306
  extend(...values: readonly ExtensionValue<'command'>[]): Command<Args, Options, Globals, State, Result>;
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;
249
307
  }
250
308
  /**
251
309
  * The authoring surface of a Command in one type state. Every call returns a new declaration value,
@@ -282,12 +340,22 @@ type CommandConstructor = new (name: string, options?: CommandOptions) => Comman
282
340
  export declare const Command: CommandConstructor;
283
341
  /** Every declaration in the graph, so defaults are validated before any token is read. */
284
342
  export declare function collectInputs(command: BuiltCommand): InputDeclaration[];
343
+ /**
344
+ * Whether a token names one of the Command's children: the Command has children and the token is
345
+ * no option token. Routing and `locate` read a bare word through this rule.
346
+ */
347
+ export declare function readsAsChild(command: BuiltCommand, token: string): boolean;
285
348
  /** Bare tokens, names or aliases, select children until a Command has none; a hyphen commits. */
286
349
  export declare function route(root: BuiltCommand, tokens: readonly string[]): {
287
350
  command: BuiltCommand;
288
351
  path: string[];
289
352
  tokens: string[];
290
353
  };
354
+ /**
355
+ * The slot the positional at one index fills: the slot at that index, else a variadic last slot,
356
+ * which accepts every later positional, else none. Binding and `locate` read positions through it.
357
+ */
358
+ export declare function argumentSlot(slots: readonly ArgumentSlot[], position: number): ArgumentSlot | undefined;
291
359
  /** One invocation after the pre-scan and routing, which the middleware chain runs on top of. */
292
360
  export interface RoutedInvocation {
293
361
  command: BuiltCommand;
@@ -303,16 +371,23 @@ export interface DispatchInvocation {
303
371
  channel: (binding: ResultBinding) => ActionChannel;
304
372
  defaults: DefaultValues;
305
373
  host: Host;
374
+ /** The graph `inspect()` returns for the run, built on its first read, which a source reads. */
375
+ inspected: () => CommandGraph;
306
376
  signal: AbortSignal;
377
+ /** The channel a configuration source writes through, whose results call names the source. */
378
+ sourceOut: Out<OpenResult>;
307
379
  style: ContextualStyle;
308
380
  }
309
381
  /**
310
382
  * One invocation prepared ahead of the middleware chain. `'ready'` carries the request a middleware
311
383
  * reads and the call that dispatches; `'held'` carries the fault this phase found, which core
312
384
  * 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.
385
+ * routed Command declared, whose views a middleware selects among, on either shape. `globals` holds
386
+ * the globals table's values after the input-source stage, which activation and every plugin's own
387
+ * options read on either shape.
314
388
  */
315
389
  export type Prepared = {
390
+ globals: OptionValues;
316
391
  result: DeclaredResult | undefined;
317
392
  } & ({
318
393
  dispatch: (view: string | null) => Promise<void>;
@@ -326,6 +401,8 @@ export type Prepared = {
326
401
  /**
327
402
  * Prepares one dispatch ahead of the middleware chain and holds whatever fault it found, so a
328
403
  * middleware reads the request before the action runs and a takeover never observes the fault.
404
+ * The phases run in order: local parsing, the input-source stage, and validation. A local fault
405
+ * outranks a configuration source's fault, and after either one core runs no validation.
329
406
  */
330
407
  export declare function prepareDispatch(graph: BuiltGraph, routed: RoutedInvocation, invocation: DispatchInvocation): Promise<Prepared>;
331
408
  export {};