@loomcli/core 0.1.1 → 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.
Files changed (57) hide show
  1. package/dist/application.d.ts +73 -28
  2. package/dist/application.js +334 -99
  3. package/dist/chain.d.ts +68 -0
  4. package/dist/chain.js +372 -0
  5. package/dist/command.d.ts +201 -46
  6. package/dist/command.js +713 -57
  7. package/dist/environment.d.ts +22 -0
  8. package/dist/environment.js +1 -0
  9. package/dist/errors.d.ts +31 -51
  10. package/dist/errors.js +58 -90
  11. package/dist/extension.d.ts +99 -0
  12. package/dist/extension.js +330 -0
  13. package/dist/facts.d.ts +39 -0
  14. package/dist/facts.js +95 -0
  15. package/dist/globals.d.ts +49 -28
  16. package/dist/globals.js +104 -58
  17. package/dist/glyphs.generated.d.ts +464 -0
  18. package/dist/glyphs.generated.js +491 -0
  19. package/dist/host.js +2 -1
  20. package/dist/index.d.ts +21 -6
  21. package/dist/index.js +7 -2
  22. package/dist/inspect.d.ts +69 -12
  23. package/dist/inspect.js +83 -26
  24. package/dist/lanes.d.ts +26 -0
  25. package/dist/lanes.js +45 -0
  26. package/dist/options.d.ts +7 -0
  27. package/dist/options.js +9 -0
  28. package/dist/output.d.ts +93 -15
  29. package/dist/output.js +307 -34
  30. package/dist/plugin.d.ts +132 -0
  31. package/dist/plugin.js +278 -0
  32. package/dist/rendering.d.ts +21 -0
  33. package/dist/rendering.js +72 -0
  34. package/dist/sequence.d.ts +41 -0
  35. package/dist/sequence.js +225 -0
  36. package/dist/signals.d.ts +52 -0
  37. package/dist/signals.js +85 -0
  38. package/dist/style-ansi.d.ts +13 -0
  39. package/dist/style-ansi.js +306 -0
  40. package/dist/style-layout.d.ts +29 -0
  41. package/dist/style-layout.js +228 -0
  42. package/dist/style-resolve.d.ts +6 -0
  43. package/dist/style-resolve.js +26 -0
  44. package/dist/style-state.d.ts +14 -0
  45. package/dist/style-state.js +179 -0
  46. package/dist/style-wire.d.ts +31 -0
  47. package/dist/style-wire.js +201 -0
  48. package/dist/style.d.ts +86 -0
  49. package/dist/style.js +201 -0
  50. package/dist/theme.d.ts +3 -0
  51. package/dist/theme.js +22 -0
  52. package/dist/types.d.ts +222 -26
  53. package/dist/validation.d.ts +12 -3
  54. package/dist/validation.js +34 -17
  55. package/dist/view.d.ts +180 -0
  56. package/dist/view.js +307 -0
  57. package/package.json +2 -1
package/dist/inspect.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import type { BuiltCommand } from './command.js';
2
- import type { BuiltGlobals } from './globals.js';
1
+ import type { BuiltGraph } from './command.js';
2
+ import type { DeclaredResult } from './types.js';
3
3
  /** One declared argument. `default` wraps the declared value, so an explicit `undefined` shows. */
4
4
  interface ArgumentNode {
5
5
  readonly name: string;
6
+ readonly description: string | undefined;
6
7
  readonly required: boolean;
7
8
  readonly variadic: boolean;
8
9
  readonly validated: boolean;
@@ -10,11 +11,24 @@ interface ArgumentNode {
10
11
  readonly default: {
11
12
  readonly value: unknown;
12
13
  } | undefined;
14
+ readonly extensions: Readonly<Record<string, unknown>>;
13
15
  }
14
- /** One declared option, in the shape its type gives it. Spellings are the accepted CLI forms. */
16
+ /**
17
+ * One declared option, in the shape its type gives it. Spellings are the accepted CLI forms, and
18
+ * `scope` tells an application's own option from a plugin option, which reaches no action. An
19
+ * option a plugin's lifecycle hook declared on a Command is that Command's own in every respect, so
20
+ * it reads `application` and names no plugin.
21
+ * `hidden` is `false` unless the declaration says `true`, and `deprecated` is the declared
22
+ * migration message or `undefined`. A listing projection omits a hidden node and marks a
23
+ * deprecated one; parsing binds without reading either.
24
+ */
15
25
  type OptionNode = {
16
26
  readonly type: 'string';
17
27
  readonly name: string;
28
+ readonly description: string | undefined;
29
+ readonly hidden: boolean;
30
+ readonly deprecated: string | undefined;
31
+ readonly scope: 'application' | 'plugin';
18
32
  readonly long: string | null;
19
33
  readonly short: string | null;
20
34
  readonly required: boolean;
@@ -24,38 +38,81 @@ type OptionNode = {
24
38
  readonly default: {
25
39
  readonly value: unknown;
26
40
  } | undefined;
41
+ readonly extensions: Readonly<Record<string, unknown>>;
27
42
  } | {
28
43
  readonly type: 'boolean';
29
44
  readonly name: string;
45
+ readonly description: string | undefined;
46
+ readonly hidden: boolean;
47
+ readonly deprecated: string | undefined;
48
+ readonly scope: 'application' | 'plugin';
30
49
  readonly long: string | null;
31
50
  readonly short: string | null;
32
51
  readonly negative: string | null;
33
52
  readonly polarity: 'positive' | 'negative' | 'both';
53
+ readonly extensions: Readonly<Record<string, unknown>>;
34
54
  };
35
55
  /**
36
56
  * One Command in the graph. `name` is `null` for the root, and `path` is its route from it.
37
- * `aliases` holds the hidden aliases in declaration order, so a Command appears once, under its
38
- * canonical name, and `path` never holds an alias.
57
+ * `aliases` holds the aliases in declaration order, so a Command appears once, under its canonical
58
+ * name, and `path` never holds an alias. The root reports the Application's description, so a
59
+ * projection that walks nodes never special-cases it, and it reads `hidden: false` and
60
+ * `deprecated: undefined`, the two core facts a listing reads on every other node.
39
61
  */
40
62
  interface CommandNode {
41
63
  readonly name: string | null;
42
64
  readonly aliases: readonly string[];
43
65
  readonly path: readonly string[];
66
+ readonly description: string | undefined;
67
+ readonly hidden: boolean;
68
+ readonly deprecated: string | undefined;
44
69
  readonly hasAction: boolean;
70
+ readonly result: ResultNode | null;
45
71
  readonly arguments: readonly ArgumentNode[];
46
72
  readonly options: readonly OptionNode[];
47
73
  readonly children: readonly CommandNode[];
74
+ readonly extensions: Readonly<Record<string, unknown>>;
75
+ }
76
+ /**
77
+ * The result one Command declares: the unit its action emits, the view names in record order, and
78
+ * the name of the view core renders when nothing selects another.
79
+ */
80
+ interface ResultNode {
81
+ readonly kind: 'value' | 'rows';
82
+ readonly views: readonly string[];
83
+ readonly default: string;
48
84
  }
49
- /** One built graph as plain data. The globals appear once here and in no `CommandNode`. */
85
+ /**
86
+ * One built graph as plain data. The globals appear once here and in no `CommandNode`. `version`
87
+ * and `description` are the Application's own core facts. `version` is the declared string, or
88
+ * `0.0.0` when the Application declares none, so it is never `undefined`. `description` stays
89
+ * `undefined` where the Application declares none.
90
+ */
50
91
  interface CommandGraph {
51
92
  readonly name: string;
93
+ readonly version: string;
94
+ readonly description: string | undefined;
52
95
  readonly globals: readonly OptionNode[];
53
96
  readonly root: CommandNode;
54
97
  }
55
- /** Renders one built graph as frozen plain data. Nothing here reads a host fact or a schema. */
56
- declare function inspectGraph(name: string, graph: {
57
- globals: BuiltGlobals;
58
- root: BuiltCommand;
98
+ /**
99
+ * A snapshot of one value. Arrays and plain objects are copied and frozen to any depth, so a
100
+ * consumer cannot reach the source through the copy, and a later call reports the value again.
101
+ * Primitives and library objects, such as a class instance or a `Date` a schema produced, are
102
+ * reported as they are, because core cannot copy them meaningfully. The graph reads it for a
103
+ * declared value and the chain reads it for the request one middleware holds.
104
+ */
105
+ export declare function snapshot(value: unknown): unknown;
106
+ /** The declared result as plain data, or `null` on a Command that declares none. */
107
+ declare function resultNode(result: DeclaredResult | undefined): ResultNode | null;
108
+ /**
109
+ * Renders one built graph as frozen plain data. Nothing here reads a host fact or a schema. The
110
+ * globals list holds the application's own options, then each installed plugin's in installation
111
+ * order, which is the order the globals table holds them in.
112
+ */
113
+ declare function inspectGraph(name: string, graph: BuiltGraph, facts: {
114
+ description: string | undefined;
115
+ version: string;
59
116
  }): CommandGraph;
60
- export type { ArgumentNode, CommandGraph, CommandNode, OptionNode };
61
- export { inspectGraph };
117
+ export type { ArgumentNode, CommandGraph, CommandNode, OptionNode, ResultNode };
118
+ export { inspectGraph, resultNode };
package/dist/inspect.js CHANGED
@@ -1,4 +1,7 @@
1
+ import { isPlainObject } from './facts.js';
1
2
  import { validatesOmission } from './validation.js';
3
+ /** A declaration that carries no extension value publishes one shared, empty frozen record. */
4
+ const noExtensions = Object.freeze({});
2
5
  /**
3
6
  * Reads the spellings out of the compiled table the parser uses, so inspection cannot report a
4
7
  * form the parser does not accept. Each entry carries its own role, so the naming convention has
@@ -13,20 +16,14 @@ function spellingsOf(table, name) {
13
16
  }
14
17
  return spellings;
15
18
  }
16
- /** A structural value core can copy faithfully. Anything else is a library object it leaves alone. */
17
- function isPlainObject(value) {
18
- if (value === null || typeof value !== 'object') {
19
- return false;
20
- }
21
- const prototype = Object.getPrototypeOf(value);
22
- return prototype === Object.prototype || prototype === null;
23
- }
24
19
  /**
25
- * A snapshot of one declared value. Arrays and plain objects are copied and frozen to any depth, so
26
- * a consumer cannot reach the declaration through the graph, and a later call reports the declared
27
- * value again. Primitives and library objects are reported as they are.
20
+ * A snapshot of one value. Arrays and plain objects are copied and frozen to any depth, so a
21
+ * consumer cannot reach the source through the copy, and a later call reports the value again.
22
+ * Primitives and library objects, such as a class instance or a `Date` a schema produced, are
23
+ * reported as they are, because core cannot copy them meaningfully. The graph reads it for a
24
+ * declared value and the chain reads it for the request one middleware holds.
28
25
  */
29
- function snapshot(value) {
26
+ export function snapshot(value) {
30
27
  if (Array.isArray(value)) {
31
28
  return Object.freeze(value.map((entry) => snapshot(entry)));
32
29
  }
@@ -39,18 +36,40 @@ function snapshot(value) {
39
36
  function declaredDefault(config) {
40
37
  return 'default' in config ? Object.freeze({ value: snapshot(config.default) }) : undefined;
41
38
  }
42
- function optionNode(input, table) {
39
+ /** One declaration's extension record, which is the shared empty one when it carries no value. */
40
+ function extensionsOf(records, declaration) {
41
+ return records.get(declaration) ?? noExtensions;
42
+ }
43
+ function optionNode(input, { records, scope, table }) {
43
44
  const { config, name } = input;
44
45
  const { long, negative, short } = spellingsOf(table, name);
46
+ const extensions = extensionsOf(records, input);
45
47
  const node = config.type === 'boolean'
46
- ? { long, name, negative, polarity: config.polarity ?? 'positive', short, type: 'boolean' }
48
+ ? {
49
+ deprecated: config.deprecated,
50
+ description: config.description,
51
+ extensions,
52
+ hidden: config.hidden === true,
53
+ long,
54
+ name,
55
+ negative,
56
+ polarity: config.polarity ?? 'positive',
57
+ scope,
58
+ short,
59
+ type: 'boolean',
60
+ }
47
61
  : {
48
62
  default: declaredDefault(config),
63
+ deprecated: config.deprecated,
64
+ description: config.description,
65
+ extensions,
66
+ hidden: config.hidden === true,
49
67
  long,
50
68
  // The parser reads the same test, so a collection reports as one here and there.
51
69
  multiple: config.multiple === true,
52
70
  name,
53
71
  required: config.required === true,
72
+ scope,
54
73
  short,
55
74
  type: 'string',
56
75
  validateOmitted: validatesOmission(input),
@@ -59,10 +78,12 @@ function optionNode(input, table) {
59
78
  return Object.freeze(node);
60
79
  }
61
80
  /** The built slots already answer presence and arity, so the node repeats no config reading. */
62
- function argumentNode(slot) {
81
+ function argumentNode(slot, records) {
63
82
  const { config, name } = slot.input;
64
83
  const node = {
65
84
  default: declaredDefault(config),
85
+ description: config.description,
86
+ extensions: extensionsOf(records, slot.input),
66
87
  name,
67
88
  required: slot.required,
68
89
  validateOmitted: validatesOmission(slot.input),
@@ -71,28 +92,64 @@ function argumentNode(slot) {
71
92
  };
72
93
  return Object.freeze(node);
73
94
  }
74
- function optionNodes(inputs, table) {
75
- return Object.freeze(inputs.filter((input) => input.kind === 'option').map((input) => optionNode(input, table)));
95
+ function optionNodes(inputs, read) {
96
+ return inputs.filter((input) => input.kind === 'option').map((input) => optionNode(input, read));
76
97
  }
77
- function commandNode(command, path) {
98
+ /**
99
+ * One Command as frozen plain data. A child reports the description its own declaration carries,
100
+ * and the root reports the Application's, which is why the caller supplies that one.
101
+ */
102
+ function commandNode(command, place) {
103
+ const { path, records } = place;
78
104
  const node = {
79
105
  aliases: Object.freeze([...command.aliases]),
80
- arguments: Object.freeze(command.arguments.map((slot) => argumentNode(slot))),
81
- children: Object.freeze([...command.children].map(([name, child]) => commandNode(child, Object.freeze([...path, name])))),
106
+ arguments: Object.freeze(command.arguments.map((slot) => argumentNode(slot, records))),
107
+ children: Object.freeze([...command.children].map(([name, child]) => commandNode(child, { path: Object.freeze([...path, name]), records }))),
108
+ deprecated: command.deprecated,
109
+ description: 'description' in place ? place.description : command.description,
110
+ extensions: command.extensions,
82
111
  hasAction: command.dispatch !== undefined,
112
+ hidden: command.hidden,
83
113
  name: command.name,
84
- options: optionNodes(command.inputs, command.options),
114
+ options: Object.freeze(optionNodes(command.inputs, { records, scope: 'application', table: command.options })),
85
115
  path,
116
+ result: resultNode(command.result),
86
117
  };
87
118
  return Object.freeze(node);
88
119
  }
89
- /** Renders one built graph as frozen plain data. Nothing here reads a host fact or a schema. */
90
- function inspectGraph(name, graph) {
120
+ /** The declared result as plain data, or `null` on a Command that declares none. */
121
+ function resultNode(result) {
122
+ if (!result) {
123
+ return null;
124
+ }
125
+ return Object.freeze({
126
+ default: result.default,
127
+ kind: result.kind,
128
+ views: Object.freeze([...result.views.keys()]),
129
+ });
130
+ }
131
+ /**
132
+ * Renders one built graph as frozen plain data. Nothing here reads a host fact or a schema. The
133
+ * globals list holds the application's own options, then each installed plugin's in installation
134
+ * order, which is the order the globals table holds them in.
135
+ */
136
+ function inspectGraph(name, graph, facts) {
137
+ const records = graph.extensions;
138
+ const table = graph.globals.options;
91
139
  const inspected = {
92
- globals: optionNodes(graph.globals.inputs, graph.globals.options),
140
+ description: facts.description,
141
+ globals: Object.freeze([
142
+ ...optionNodes(graph.globals.inputs, { records, scope: 'application', table }),
143
+ ...graph.globals.plugins.flatMap((installed) => optionNodes(installed.inputs, { records, scope: 'plugin', table })),
144
+ ]),
93
145
  name,
94
- root: commandNode(graph.root, Object.freeze([])),
146
+ root: commandNode(graph.root, {
147
+ description: facts.description,
148
+ path: Object.freeze([]),
149
+ records,
150
+ }),
151
+ version: facts.version,
95
152
  };
96
153
  return Object.freeze(inspected);
97
154
  }
98
- export { inspectGraph };
155
+ export { inspectGraph, resultNode };
@@ -0,0 +1,26 @@
1
+ import type { AnyDeclaredView, DeclaredView } from './view.js';
2
+ /** The five semantic methods, each with the glyph and the style token its lane carries. */
3
+ type Lane = 'error' | 'info' | 'print' | 'success' | 'warn';
4
+ /**
5
+ * The five lane views core declares, one per semantic method. An application replaces the function
6
+ * of any of them through `views`, and the replacement owns the gutter the default supplies.
7
+ */
8
+ declare const lanes: Readonly<Record<Lane, DeclaredView<string>>>;
9
+ /**
10
+ * What one sequence that stopped early reports: the Command it belongs to, the rows its source
11
+ * produced before the stop, and the rows core wrote. `head` is no row, so it is not counted.
12
+ */
13
+ interface IncompleteResult {
14
+ path: readonly string[];
15
+ yielded: number;
16
+ written: number;
17
+ }
18
+ /**
19
+ * The line a sequence writes on stderr when it stopped before its end, so an empty result and a
20
+ * truncated one never read alike. An override that returns the empty string silences it.
21
+ */
22
+ declare const incompleteResult: DeclaredView<IncompleteResult>;
23
+ /** Every view core declares, so one build register holds their identities from the start. */
24
+ declare const coreViews: readonly AnyDeclaredView[];
25
+ export type { IncompleteResult, Lane };
26
+ export { coreViews, incompleteResult, lanes };
package/dist/lanes.js ADDED
@@ -0,0 +1,45 @@
1
+ import { routedSubject } from './errors.js';
2
+ import { glyph } from './glyphs.generated.js';
3
+ import { view } from './view.js';
4
+ /**
5
+ * The identity prefix core's own views take, the package name by the plugin-identity convention.
6
+ * Core compiles from `src` alone, so the name is spelled here rather than read from the manifest.
7
+ */
8
+ const core = '@loomcli/core';
9
+ /**
10
+ * The default function of a marked lane: the matching glyph and one space before the first line,
11
+ * and continuation lines indented by the measured gutter without repeating the glyph. The
12
+ * semantic method appends the newline, so the view returns none.
13
+ */
14
+ function marked(mark) {
15
+ return (message, context) => {
16
+ const glyphText = glyph[mark];
17
+ const gutter = ' '.repeat(context.width(glyphText) + 1);
18
+ return `${context.style[mark](glyphText)} ${message.replace(/(?<newline>\r?\n)(?!$)/gu, `$<newline>${gutter}`)}`;
19
+ };
20
+ }
21
+ /** One lane view over the original message string, line breaks and authored styles included. */
22
+ function lane(name, render) {
23
+ return view(`${core}/lanes/${name}`, { render });
24
+ }
25
+ /**
26
+ * The five lane views core declares, one per semantic method. An application replaces the function
27
+ * of any of them through `views`, and the replacement owns the gutter the default supplies.
28
+ */
29
+ const lanes = {
30
+ error: lane('error', marked('error')),
31
+ info: lane('info', marked('info')),
32
+ print: lane('print', (message) => message),
33
+ success: lane('success', marked('success')),
34
+ warn: lane('warn', marked('warning')),
35
+ };
36
+ /**
37
+ * The line a sequence writes on stderr when it stopped before its end, so an empty result and a
38
+ * truncated one never read alike. An override that returns the empty string silences it.
39
+ */
40
+ const incompleteResult = view(`${core}/results/incomplete`, {
41
+ render: ({ path, written, yielded }) => `Output is incomplete: ${routedSubject(path)} stopped after ${yielded} rows, ${written} written.\n`,
42
+ });
43
+ /** Every view core declares, so one build register holds their identities from the start. */
44
+ const coreViews = [...Object.values(lanes), incompleteResult];
45
+ export { coreViews, incompleteResult, lanes };
package/dist/options.d.ts CHANGED
@@ -22,6 +22,13 @@ type OptionForm = {
22
22
  type OptionSpelling = OptionForm & {
23
23
  role: SpellingRole;
24
24
  };
25
+ /**
26
+ * One Boolean option's value for one invocation: the value the parser consumed, or the value its
27
+ * declared polarity gives an absent option. A negative-only option is absent as `true`, because its
28
+ * one spelling turns the value off. Every scope reads it here, so a plugin option and a validated
29
+ * declaration answer the same rule.
30
+ */
31
+ export declare function booleanValue(values: OptionValues, name: string, config: OptionConfig): boolean;
25
32
  export declare function compileOptions(declarations: readonly OptionDeclaration[], subject: string): Map<string, OptionSpelling>;
26
33
  /** Consumes global options anywhere before the passthrough delimiter and leaves the rest routable. */
27
34
  export declare function extractGlobals(spellings: ReadonlyMap<string, OptionSpelling>, tokens: readonly string[]): {
package/dist/options.js CHANGED
@@ -48,6 +48,15 @@ function addSpelling(spellings, spelling, option) {
48
48
  }
49
49
  spellings.set(spelling, option);
50
50
  }
51
+ /**
52
+ * One Boolean option's value for one invocation: the value the parser consumed, or the value its
53
+ * declared polarity gives an absent option. A negative-only option is absent as `true`, because its
54
+ * one spelling turns the value off. Every scope reads it here, so a plugin option and a validated
55
+ * declaration answer the same rule.
56
+ */
57
+ export function booleanValue(values, name, config) {
58
+ return values.booleans.get(name) ?? config.polarity === 'negative';
59
+ }
51
60
  export function compileOptions(declarations, subject) {
52
61
  const spellings = new Map();
53
62
  const names = new Set();
package/dist/output.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  import type { Writable } from 'node:stream';
2
- import type { Host, Out } from './types.js';
2
+ import type { Lane } from './lanes.js';
3
+ import type { RenderingPolicy } from './rendering.js';
4
+ import type { Palette } from './style-state.js';
5
+ import type { ActionChannel, Host, OpenResult, Out, ResultBinding, ViewContext } from './types.js';
6
+ import type { ViewRegistry } from './view.js';
3
7
  type WriteState = {
4
8
  kind: 'ok';
5
9
  } | {
@@ -7,44 +11,118 @@ type WriteState = {
7
11
  error: unknown;
8
12
  };
9
13
  /** The semantic calls, which choose a destination. A rendered value has no purpose of its own. */
10
- type Purpose = 'print' | 'info' | 'success' | 'warn' | 'error';
14
+ type Purpose = Lane;
15
+ /** The two streams every write site names. */
16
+ type Stream = 'stdout' | 'stderr';
11
17
  export declare class Output {
12
- readonly host: Pick<Host, 'stdout' | 'stderr'>;
18
+ readonly host: Host;
19
+ private readonly signal;
13
20
  private readonly destinations;
14
21
  private renderFault;
15
- readonly out: Out;
16
- constructor(host: Pick<Host, 'stdout' | 'stderr'>);
17
- /** A semantic message is one line on its destination; only `print` writes to stdout. */
18
- emit(kind: Purpose, message: string): Promise<void>;
22
+ private readonly stops;
23
+ private route;
24
+ /**
25
+ * The channel every caller writes through. It is typed with the result left open, because the
26
+ * declaration a call answers to is checked where the action was authored.
27
+ */
28
+ readonly out: Out<OpenResult>;
29
+ private palette;
30
+ private policy;
31
+ private registry;
32
+ style: import("./style.js").ContextualStyle;
33
+ constructor(host: Host, signal: AbortSignal);
34
+ /**
35
+ * The channel one action receives. On a Command that declares a result nothing the action writes
36
+ * but the result reaches stdout: `print` and `render` move to stderr, and they move the view
37
+ * context with the destination, so capability detection follows the stream the bytes reach. The
38
+ * destination is decided here, from the declaration, and never from the view a run selected.
39
+ */
40
+ channel(binding: ResultBinding): ActionChannel;
41
+ /**
42
+ * One `out.results` call on the action's channel. The declaration decides the unit, the selected
43
+ * view decides how it renders, and stdout carries the result under either one. The selected
44
+ * view is the one a middleware named before the action dispatched, or the declaration's default
45
+ * when none did. A call the declaration does not answer for is a fault of the lane and writes
46
+ * nothing.
47
+ */
48
+ private results;
49
+ /**
50
+ * One fault of the results lane: the call rejects, and the same failure is reported after this
51
+ * invocation's primary outcome, so a call the action never awaited still turns a would-be 0 into
52
+ * 1 and one the action let propagate is reported once.
53
+ */
54
+ private resultFault;
55
+ /** The registry one invocation resolves through, republished as each contributor is read. */
56
+ useViews(registry: ViewRegistry): void;
57
+ /** The routed path, published once routing resolved it, which an incomplete sequence names. */
58
+ useRoute(path: readonly string[]): void;
59
+ /** What this invocation's output raised beside its calls, in the order it was raised. */
60
+ get stopped(): readonly unknown[];
61
+ configure(policy: RenderingPolicy, palette: Palette): void;
62
+ context(destination: Stream): ViewContext;
63
+ /**
64
+ * A semantic message is one line on its destination; only `print` writes to stdout. The message
65
+ * is checked before the lane view runs, and this call appends the one newline after it, so a
66
+ * lane view returns none and an override that returns the empty string still writes one.
67
+ */
68
+ emit(kind: Purpose, message: string, destination: Stream): Promise<void>;
19
69
  /**
20
70
  * The failure report of one invocation. Like `render`, the text is queued on its destination
21
- * exactly as given: the caller already carries its own trailing newline, whether that text came
22
- * from a registered renderer or from core's own default text.
71
+ * after style resolution: the caller already carries its own trailing newline, whether that text
72
+ * came from a resolved view or from core's own default text.
23
73
  */
24
74
  report(text: string): Promise<void>;
25
75
  /**
26
- * The renderer owns every byte, so its text is queued on stdout exactly as returned. A throw or
27
- * a non-string return rejects this call alone: nothing is written for it, later output still
28
- * writes, and the recorded cause ends the invocation once the action has completed.
76
+ * One `out.render` call, dispatched on the shape of the view it was handed. The two shapes are
77
+ * exclusive, so a JavaScript author's value that carries both, or neither, is the output-view
78
+ * fault of this call and nothing is written for it.
79
+ */
80
+ private renderValue;
81
+ /**
82
+ * The view one sequence writes through, in the shape its own view carries. The caller supplies
83
+ * the contributors the view resolves through: `out.render`'s call-site view resolves through
84
+ * this invocation's registry, as ADR-0021 requires, and a result's view resolves through none,
85
+ * because a result's selected view is replaced by view name alone.
86
+ */
87
+ private sequenceView;
88
+ /**
89
+ * One sequence, which holds its place on the destination from here until its last piece is
90
+ * written. The returned rejection is observed here as well, because an action that never awaits
91
+ * the call must not end the process with an unhandled rejection.
92
+ */
93
+ private sequence;
94
+ /**
95
+ * The line one incomplete sequence writes on stderr, ahead of the fault's own report. It resolves
96
+ * through the registry like any other rendered output, so an override that returns the empty
97
+ * string silences it and one that throws is a view fault. A stderr that has failed already takes
98
+ * the plain fallback path and no further.
99
+ */
100
+ private incomplete;
101
+ /**
102
+ * The write site owns its newline; core resolves the view's marked text before queuing it. A
103
+ * throw or a non-string return rejects this call alone: nothing is written for it, later output
104
+ * still writes, and the recorded cause ends the invocation once the action has completed.
29
105
  */
30
106
  private rendered;
31
107
  /**
32
- * The rejected call. The first renderer failure is the reported one, so a later one adds no
108
+ * The rejected call. The first view failure is the reported one, so a later one adds no
33
109
  * second diagnostic, and the rejection is observed here as well, because an action that never
34
110
  * awaits the call must not end the process with an unhandled rejection.
35
111
  */
36
112
  private renderFailed;
37
- /** What a renderer failed with during this invocation, if one did. */
113
+ /** What a view failed with during this invocation, if one did. */
38
114
  get fault(): {
39
115
  cause: unknown;
40
116
  } | undefined;
117
+ /** The queue one stream writes through, opened the first time this invocation reaches it. */
118
+ private destination;
41
119
  private write;
42
120
  settle(): Promise<WriteState>;
43
121
  dispose(): void;
44
122
  }
45
123
  /**
46
124
  * The plain fallback path: a fresh destination on stderr, outside the invocation's queues and
47
- * outside every registration, so no application code runs on it. The caller composes the newlines
125
+ * outside every override, so no application code runs on it. The caller composes the newlines
48
126
  * between whatever it is reporting, then passes the one string this writes verbatim. A failed
49
127
  * write ends reporting.
50
128
  */