@hatua/model 0.0.0 → 0.1.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/LICENSE +21 -0
- package/dist/authoring.d.ts +47 -0
- package/dist/blocks.d.ts +119 -0
- package/dist/blocks.test.d.ts +1 -0
- package/dist/connections.d.ts +61 -0
- package/dist/connections.test.d.ts +1 -0
- package/dist/diagnostic.d.ts +60 -0
- package/dist/execution.d.ts +43 -0
- package/dist/fixtures.d.ts +10 -0
- package/dist/generated/diagnostics.d.ts +18 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +965 -0
- package/dist/loops.test.d.ts +1 -0
- package/dist/metadata.d.ts +45 -0
- package/dist/metadata.test.d.ts +1 -0
- package/dist/rules.conformance.test.d.ts +1 -0
- package/dist/scope.d.ts +162 -0
- package/dist/scope.test.d.ts +1 -0
- package/dist/segment.d.ts +107 -0
- package/dist/segment.test.d.ts +1 -0
- package/dist/slots.d.ts +161 -0
- package/dist/slots.test.d.ts +1 -0
- package/dist/tree.d.ts +311 -0
- package/dist/tree.test.d.ts +1 -0
- package/dist/validity.d.ts +167 -0
- package/dist/validity.test.d.ts +1 -0
- package/package.json +27 -5
- package/README.md +0 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Manifest, WorkflowExecution } from '@hatua/schema';
|
|
2
|
+
/**
|
|
3
|
+
* Run metadata is derived, not reported.
|
|
4
|
+
*
|
|
5
|
+
* A component declares each metadata key as a `measure` (summable — tokens,
|
|
6
|
+
* cost, retries) or a `dimension` (groupable — model, region). Given only
|
|
7
|
+
* per-step values, that is enough for Hatua to compute run totals and pivots
|
|
8
|
+
* like "tokens per model" itself.
|
|
9
|
+
*
|
|
10
|
+
* The alternative — runners reporting their own run-level summaries with their
|
|
11
|
+
* own schemas — would mean every runner shapes the Runs view differently, and
|
|
12
|
+
* Hatua could render none of them generically.
|
|
13
|
+
*/
|
|
14
|
+
export interface MetadataDescriptor {
|
|
15
|
+
k: string;
|
|
16
|
+
label: string;
|
|
17
|
+
role: 'measure' | 'dimension';
|
|
18
|
+
unit?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface MeasureTotal {
|
|
21
|
+
key: string;
|
|
22
|
+
label: string;
|
|
23
|
+
unit?: string;
|
|
24
|
+
total: number;
|
|
25
|
+
}
|
|
26
|
+
export interface Pivot {
|
|
27
|
+
measure: string;
|
|
28
|
+
measureLabel: string;
|
|
29
|
+
dimension: string;
|
|
30
|
+
dimensionLabel: string;
|
|
31
|
+
unit?: string;
|
|
32
|
+
rows: {
|
|
33
|
+
value: string;
|
|
34
|
+
total: number;
|
|
35
|
+
}[];
|
|
36
|
+
}
|
|
37
|
+
/** Every metadata key any manifest declares, keyed by component `use`. */
|
|
38
|
+
export declare function descriptorsByUse(manifests: readonly Manifest[]): Map<string, MetadataDescriptor[]>;
|
|
39
|
+
/** Sum every declared measure across the run. */
|
|
40
|
+
export declare function totals(execution: WorkflowExecution, descriptors: Map<string, MetadataDescriptor[]>, useOf: (stepId: string) => string | undefined): MeasureTotal[];
|
|
41
|
+
/**
|
|
42
|
+
* Sum a measure grouped by a dimension — "tokens per model". Both must be
|
|
43
|
+
* declared by the same component, since only then do they co-occur on a sample.
|
|
44
|
+
*/
|
|
45
|
+
export declare function pivot(execution: WorkflowExecution, descriptors: Map<string, MetadataDescriptor[]>, useOf: (stepId: string) => string | undefined, measureKey: string, dimensionKey: string): Pivot | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/scope.d.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { TypeNode } from '@hatua/expressions';
|
|
2
|
+
import { Block, ContextKey, Manifest, Step, WorkflowDefinition } from '@hatua/schema';
|
|
3
|
+
import { BoardId, StepRef } from './tree';
|
|
4
|
+
/**
|
|
5
|
+
* What a step may reference. The reference tree is built from this, which is
|
|
6
|
+
* what makes a broken mapping unexpressible rather than merely discouraged.
|
|
7
|
+
*/
|
|
8
|
+
export interface ScopeEntry {
|
|
9
|
+
/**
|
|
10
|
+
* The whole addressable path, e.g. `steps.s2`, `triggers.nightly`,
|
|
11
|
+
* `var.digest_to`, `params.entry`, `run.tenant`, `TRIGGER`.
|
|
12
|
+
*
|
|
13
|
+
* Always below a root, never at one — which is what lets a Step be called
|
|
14
|
+
* `run` and a parameter be called `steps` (ADR-0014).
|
|
15
|
+
*/
|
|
16
|
+
path: string;
|
|
17
|
+
/**
|
|
18
|
+
* Where the value comes from, which is what the reference tree groups by and
|
|
19
|
+
* what decides a row's icon.
|
|
20
|
+
*
|
|
21
|
+
* `context` is the Host's Run Context — ambient values it supplies to every
|
|
22
|
+
* execution. It sits beside `trigger` and `var` rather than under them
|
|
23
|
+
* because it is neither: nothing in the document declares it, and unlike a
|
|
24
|
+
* variable it cannot be edited from the builder at all.
|
|
25
|
+
*/
|
|
26
|
+
kind: 'step' | 'trigger' | 'param' | 'var' | 'context' | 'builtin';
|
|
27
|
+
label: string;
|
|
28
|
+
/**
|
|
29
|
+
* One sentence about the value, shown under the focused row in the completion
|
|
30
|
+
* list. Only the Host's Run Context declares one today — a manifest output
|
|
31
|
+
* has nowhere to put a sentence — so absent is the ordinary case and a row
|
|
32
|
+
* without one simply shows nothing rather than a placeholder.
|
|
33
|
+
*/
|
|
34
|
+
description?: string;
|
|
35
|
+
/**
|
|
36
|
+
* The shape of what it yields.
|
|
37
|
+
*
|
|
38
|
+
* This is what makes an entry usable by `@hatua/expressions`' type checker,
|
|
39
|
+
* which takes `ScopeEntry[]` as an argument precisely so it can stay ignorant
|
|
40
|
+
* of manifests and of this package. One scope, two readers: the reference
|
|
41
|
+
* tree reads `label` and `kind`, the checker reads `path` and `type`.
|
|
42
|
+
*/
|
|
43
|
+
type: TypeNode;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The steps a given step may reference: its ancestors and the earlier siblings
|
|
47
|
+
* of every ancestor. Sibling branches are deliberately out of scope, so a user
|
|
48
|
+
* cannot express a mapping that could not resolve at run time.
|
|
49
|
+
*
|
|
50
|
+
* The walk is rooted at the Step's own Board and never leaves it. A Block's
|
|
51
|
+
* steps do not see the call site's ancestry, which is the whole reason a call is
|
|
52
|
+
* a cross-link with a contract and a jump is not (ADR-0013).
|
|
53
|
+
*/
|
|
54
|
+
export declare function upstreamOf(doc: WorkflowDefinition, ref: StepRef): Step[];
|
|
55
|
+
/**
|
|
56
|
+
* Everything a Board offers with no position in its tree.
|
|
57
|
+
*
|
|
58
|
+
* **Never a Step's output.** A variable's value has no position — it is not
|
|
59
|
+
* reached by running anything — so no Step is guaranteed to have run by the
|
|
60
|
+
* time it is evaluated, and offering one would express a mapping that cannot
|
|
61
|
+
* resolve. Everything here is available unconditionally for the mirror-image
|
|
62
|
+
* reason: a workflow cannot run without a Trigger firing, the Host supplies Run
|
|
63
|
+
* Context to every execution, a parameter is filled by the caller before the
|
|
64
|
+
* Block starts, and a variable is Board-scoped rather than positional.
|
|
65
|
+
*
|
|
66
|
+
* The two Boards offer different things, and the difference IS the contract:
|
|
67
|
+
*
|
|
68
|
+
* | | root Board | a Block's |
|
|
69
|
+
* | --- | --- | --- |
|
|
70
|
+
* | `run.*` | Run Context | the same — the one thing that crosses |
|
|
71
|
+
* | `triggers.*`, `TRIGGER` | the parameter contract | absent |
|
|
72
|
+
* | `params.*` | absent | the parameter contract |
|
|
73
|
+
* | `var.*` | the workflow's | the Block's, rebuilt per call |
|
|
74
|
+
*
|
|
75
|
+
* A Block cannot read the workflow's variables or ask which Trigger fired.
|
|
76
|
+
* Run Context is the single exception because nothing in the document declares
|
|
77
|
+
* it: the Host supplies it to every execution, so it is exact on every path of
|
|
78
|
+
* every Board with no intersection to compute (ADR-0013).
|
|
79
|
+
*
|
|
80
|
+
* It exists as its own function because the Board panel needs scope without a
|
|
81
|
+
* Step to ask about. `scopeFor` is this plus the upstream Steps, so the two
|
|
82
|
+
* readers share one definition of the unpositioned half rather than drifting.
|
|
83
|
+
*/
|
|
84
|
+
export declare function boardScope(doc: WorkflowDefinition, board?: BoardId, manifests?: readonly Manifest[], context?: readonly ContextKey[]): ScopeEntry[];
|
|
85
|
+
/**
|
|
86
|
+
* Everything addressable from a step: the unpositioned scope above, plus the
|
|
87
|
+
* upstream steps.
|
|
88
|
+
*
|
|
89
|
+
* Only steps are constrained by tree position, because only a step can fail to
|
|
90
|
+
* have run.
|
|
91
|
+
*/
|
|
92
|
+
export declare function scopeFor(doc: WorkflowDefinition, ref: StepRef, manifests?: readonly Manifest[], context?: readonly ContextKey[], memo?: ScopeMemo): ScopeEntry[];
|
|
93
|
+
/**
|
|
94
|
+
* What one walk has already worked out, so a second walk over the same document
|
|
95
|
+
* does not work it out again.
|
|
96
|
+
*
|
|
97
|
+
* A scope is *positional*, so asking for every Step's is asking n times — and
|
|
98
|
+
* each answer names every Step upstream of it, so the answers together hold
|
|
99
|
+
* n²/2 entries. Recomputing each one costs a fresh type tree per upstream Step
|
|
100
|
+
* per Step, which is what makes a whole-document pass superlinear: a thousand
|
|
101
|
+
* Steps take a second, and `validateDefinition` runs on every keystroke.
|
|
102
|
+
*
|
|
103
|
+
* Shared by passing one of these to every `scopeFor` in the pass. Created per
|
|
104
|
+
* pass and never held in the module: the document is an argument, and a cache
|
|
105
|
+
* outliving the call would be answering about a document that has since been
|
|
106
|
+
* edited.
|
|
107
|
+
*/
|
|
108
|
+
export interface ScopeMemo {
|
|
109
|
+
/** One loop's element type, which is what makes nested loops linear. */
|
|
110
|
+
readonly elements: ElementMemo;
|
|
111
|
+
/** One upstream Step's entry, keyed by `stepKey`. */
|
|
112
|
+
readonly entries: Map<string, ScopeEntry>;
|
|
113
|
+
/** One Board's unpositioned scope: its Triggers, its contract, its variables. */
|
|
114
|
+
readonly boards: Map<string, ScopeEntry[]>;
|
|
115
|
+
}
|
|
116
|
+
export declare const newScopeMemo: () => ScopeMemo;
|
|
117
|
+
/**
|
|
118
|
+
* The type one path names, read out of a scope, or null when nothing declares
|
|
119
|
+
* it.
|
|
120
|
+
*
|
|
121
|
+
* Longest prefix first, because a scope path is dotted and is one entry rather
|
|
122
|
+
* than two: `steps.s2` is an entry and `steps` is not, so `steps.s2.messages`
|
|
123
|
+
* has to try three segments before two. That is the same rule `validate.ts`
|
|
124
|
+
* walks a Member chain by, restated here for a caller that has a path and no
|
|
125
|
+
* expression — reading a *declared* type is not checking one, and reaching for
|
|
126
|
+
* the checker would mean manufacturing diagnostics nobody asked for in order to
|
|
127
|
+
* throw them away.
|
|
128
|
+
*/
|
|
129
|
+
export declare function typeAtPath(scope: readonly ScopeEntry[], path: string): TypeNode | null;
|
|
130
|
+
/**
|
|
131
|
+
* What one element of a `core.for_each`'s list is, or null when the document
|
|
132
|
+
* does not say.
|
|
133
|
+
*
|
|
134
|
+
* This is the whole of `t: item`. The loop's `list` is a `ref` field, so its
|
|
135
|
+
* declared type is `unknown` and the ordinary Slot check learns nothing from
|
|
136
|
+
* it; the shape is one level below whatever it points at, which is exactly the
|
|
137
|
+
* `of:` the source output declared. Null when `list` is missing, is not a plain
|
|
138
|
+
* Reference, names nothing, or names something that is not a list — and null
|
|
139
|
+
* means `item` stays `item`, which the checker treats as matching anything.
|
|
140
|
+
* Guessing `object` instead would be a shape nothing declared.
|
|
141
|
+
*/
|
|
142
|
+
export declare function loopElementType(doc: WorkflowDefinition, board: BoardId, step: Step, manifests?: readonly Manifest[], context?: readonly ContextKey[], resolving?: ReadonlySet<string>, elements?: ElementMemo): TypeNode | null;
|
|
143
|
+
/**
|
|
144
|
+
* What one loop's element resolves to, for the length of one top-level walk.
|
|
145
|
+
*
|
|
146
|
+
* A Step's element type is a property of the document, so one walk asking for
|
|
147
|
+
* the same loop twice is asking the same question twice — and the walk asks for
|
|
148
|
+
* it once per path that reaches it, which is what makes the cost exponential
|
|
149
|
+
* without this. The map is created per `scopeFor` rather than held in the
|
|
150
|
+
* module: the document is an argument, and a cache outliving the call would be
|
|
151
|
+
* answering about a document that has since been edited.
|
|
152
|
+
*/
|
|
153
|
+
type ElementMemo = Map<string, TypeNode | null>;
|
|
154
|
+
/**
|
|
155
|
+
* What a Block's outputs are, as a scope entry's type at the call site.
|
|
156
|
+
*
|
|
157
|
+
* Read where the Block is declared rather than from a manifest, which is what
|
|
158
|
+
* makes a call type-check before its body is written: the declaration is the
|
|
159
|
+
* contract, and `core.return` only binds values to it.
|
|
160
|
+
*/
|
|
161
|
+
export declare function blockOutputType(block: Block | undefined): TypeNode;
|
|
162
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Step, WorkflowDefinition } from '@hatua/schema';
|
|
2
|
+
import { Board, BoardId, StepRef } from './tree';
|
|
3
|
+
/**
|
|
4
|
+
* A contiguous stretch of sibling **Steps** in one region of one **Board**.
|
|
5
|
+
*
|
|
6
|
+
* The shape a selection takes and the shape extraction consumes (ADR-0018,
|
|
7
|
+
* ADR-0020). A Segment of one is a Segment: a single container together with
|
|
8
|
+
* its whole body is the flattening case a Block exists for.
|
|
9
|
+
*
|
|
10
|
+
* ## Named by Steps, never by positions
|
|
11
|
+
*
|
|
12
|
+
* `{ board, steps }` and not a start index and a length. A Segment is held
|
|
13
|
+
* across edits, and an index range means a Step added above it silently changes
|
|
14
|
+
* which Steps are in it — the argument `RegionRef` makes about `branchIndex`,
|
|
15
|
+
* which it accepts only because a Branch has no id and a Step has one.
|
|
16
|
+
*
|
|
17
|
+
* So contiguity is *derived* rather than stored, by `segmentSteps` against the
|
|
18
|
+
* Board being drawn. What the shape does carry structurally is the **one
|
|
19
|
+
* Board**: a `readonly StepRef[]` can express a selection spanning two Boards,
|
|
20
|
+
* which is not a Segment and never can be, and hoisting the Board out makes
|
|
21
|
+
* that unrepresentable rather than something every reader has to filter for.
|
|
22
|
+
*/
|
|
23
|
+
export interface Segment {
|
|
24
|
+
readonly board: BoardId;
|
|
25
|
+
/** The Steps, by id, in document order. Never empty. */
|
|
26
|
+
readonly steps: readonly string[];
|
|
27
|
+
}
|
|
28
|
+
/** One Step's place among its siblings: the list it sits in, and where. */
|
|
29
|
+
export interface Siblings {
|
|
30
|
+
readonly steps: readonly Step[];
|
|
31
|
+
readonly index: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The sibling list holding one Step, and its position in it.
|
|
35
|
+
*
|
|
36
|
+
* The whole of "are these two Steps siblings": two ids resolve to the same
|
|
37
|
+
* `steps` array or they do not. Identity of the array is the test rather than a
|
|
38
|
+
* path, because `regionsOf` hands the region's own list over and a Board holds
|
|
39
|
+
* exactly one array per region.
|
|
40
|
+
*/
|
|
41
|
+
export declare function siblingsOf(board: Board, id: string): Siblings | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* The Segment reaching from one Step to another, or `undefined` when the two
|
|
44
|
+
* are not siblings.
|
|
45
|
+
*
|
|
46
|
+
* The *only* way a Segment of more than one Step is built, which is what makes
|
|
47
|
+
* "a selection is always extractable" true by construction rather than by a
|
|
48
|
+
* check somebody has to remember to run (ADR-0020). Order of the arguments does
|
|
49
|
+
* not matter: a user may extend a selection upwards, and the Steps come back in
|
|
50
|
+
* document order either way.
|
|
51
|
+
*/
|
|
52
|
+
export declare function segmentBetween(board: Board, anchorId: string, headId: string): Segment | undefined;
|
|
53
|
+
/** A Segment holding one Step. */
|
|
54
|
+
export declare const segmentOf: ({ board, id }: StepRef) => Segment;
|
|
55
|
+
/**
|
|
56
|
+
* The Steps a Segment actually names on a Board, in document order.
|
|
57
|
+
*
|
|
58
|
+
* Every consumer's way in, and the place a Segment held across an edit is
|
|
59
|
+
* reconciled with the document as it is now: a Step that has been removed drops
|
|
60
|
+
* out, and what is left is still contiguous because removal closes the gap.
|
|
61
|
+
*
|
|
62
|
+
* Empty means the Segment names nothing on this Board — a Board that is gone, a
|
|
63
|
+
* Block that was deleted, or a Segment whose every Step has been removed. A
|
|
64
|
+
* caller showing a selection draws nothing for it; a caller acting on one has
|
|
65
|
+
* nothing to act on.
|
|
66
|
+
*/
|
|
67
|
+
export declare function segmentSteps(doc: WorkflowDefinition, segment: Segment): readonly Step[];
|
|
68
|
+
/**
|
|
69
|
+
* Whether a Segment names this Step, for a surface deciding whether to draw a
|
|
70
|
+
* card as selected.
|
|
71
|
+
*
|
|
72
|
+
* A Board comparison and not only an id: ids are Board-local, so two Blocks may
|
|
73
|
+
* each hold a Step called `ret` and a bare id highlights both (ADR-0013).
|
|
74
|
+
*/
|
|
75
|
+
export declare const segmentHolds: (segment: Segment | undefined, ref: StepRef) => boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The Step one place from the Segment's head, in the direction given, or
|
|
78
|
+
* `undefined` at the end of the sibling list.
|
|
79
|
+
*
|
|
80
|
+
* What `Shift`+`↑`/`↓` moves. The *head* moves and the anchor stays, so the
|
|
81
|
+
* same keystroke grows a Segment and shrinks it from the other end.
|
|
82
|
+
*/
|
|
83
|
+
export declare function siblingFrom(board: Board, id: string, step: 1 | -1): string | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Whether a Segment holds a `core.return`, anywhere inside it.
|
|
86
|
+
*
|
|
87
|
+
* What extraction refuses (ADR-0018). Moved onto a new Board, a return binds to
|
|
88
|
+
* the *new* Block's `outputs:` and ends a Block the author did not mean it to
|
|
89
|
+
* end — behaviour the move silently changes, with nothing malformed for a rule
|
|
90
|
+
* to report. So the gesture is not offered rather than repaired.
|
|
91
|
+
*
|
|
92
|
+
* Nested and not only the Segment's own Steps: a return inside a Fork branch
|
|
93
|
+
* inside the Segment moves with it and binds exactly the same way.
|
|
94
|
+
*
|
|
95
|
+
* Takes the Steps a Segment resolves to rather than the Segment, so a caller
|
|
96
|
+
* that has already asked `segmentSteps` — which is every caller, because the
|
|
97
|
+
* count beside the action comes from the same answer — does not resolve twice.
|
|
98
|
+
*
|
|
99
|
+
* **`extractBlock` cannot call this, and asks the same question its own way.**
|
|
100
|
+
* A command runs against a document that does not project (ADR-0001), so it has
|
|
101
|
+
* no `Step[]` to hand over and walks the YAML AST instead. The two agree because
|
|
102
|
+
* `regionsOf` here and `stepEntriesIn` there enumerate the same regions — a
|
|
103
|
+
* Branch's steps, a body, a handler — which is a coupling neither file states on
|
|
104
|
+
* its own. A region kind added to one and not the other makes the canvas offer
|
|
105
|
+
* an enabled action on the one selection the command refuses.
|
|
106
|
+
*/
|
|
107
|
+
export declare const segmentReturns: (steps: readonly Step[]) => boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/slots.d.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { Slot, ValueType } from '@hatua/expressions';
|
|
2
|
+
import { Manifest, Step, Variable, WorkflowDefinition, MAPPABLE_FIELD_KINDS } from '@hatua/schema';
|
|
3
|
+
import { BoardId } from './tree';
|
|
4
|
+
/**
|
|
5
|
+
* The bridge between a Component Manifest and the expression language.
|
|
6
|
+
*
|
|
7
|
+
* `@hatua/expressions` deliberately knows nothing about manifests: it takes a
|
|
8
|
+
* `Slot` and a `ScopeEntry[]` as arguments, which is what keeps it depending on
|
|
9
|
+
* `@hatua/schema` alone and stops a cycle forming with this package. The cost is
|
|
10
|
+
* that *something* has to turn a step and its manifest into those arguments, and
|
|
11
|
+
* this is it — once per language, so a runner never restates the field-kind to
|
|
12
|
+
* type mapping and cannot get it subtly different from the builder.
|
|
13
|
+
*/
|
|
14
|
+
/** The kinds whose value is a Template. Everything else holds a literal. */
|
|
15
|
+
export type MappableFieldKind = (typeof MAPPABLE_FIELD_KINDS)[number];
|
|
16
|
+
/**
|
|
17
|
+
* What each mappable field kind's value must produce.
|
|
18
|
+
*
|
|
19
|
+
* Keyed by `MappableFieldKind` rather than by `string`, so the compiler refuses
|
|
20
|
+
* both a missing kind and an invented one. A loose `Record<string, ValueType>`
|
|
21
|
+
* accepts entries for `bool`, `enum`, `secret` and `conn` — kinds `isMappable`
|
|
22
|
+
* rejects before this is ever read, so they are unreachable — while silently
|
|
23
|
+
* tolerating the omission of `map`, which is mappable. That is the same "two
|
|
24
|
+
* definitions of one thing" failure a Reference regex would be, and the key
|
|
25
|
+
* type is what stops it.
|
|
26
|
+
*
|
|
27
|
+
* `mono` and `textarea` are text that renders differently. `ref` is `unknown` on
|
|
28
|
+
* purpose: a ref field holds whatever it points at, and the check belongs at the
|
|
29
|
+
* far end. `map` has no single type at all — each of its entries declares its
|
|
30
|
+
* own, which is why `slotsFor` never reads this for one.
|
|
31
|
+
*/
|
|
32
|
+
export declare const FIELD_KIND_TYPES: Readonly<Record<MappableFieldKind, ValueType>>;
|
|
33
|
+
/** One entry of a `map` field: a name, a Template, and the type it must produce. */
|
|
34
|
+
export interface MapEntry {
|
|
35
|
+
key: string;
|
|
36
|
+
value: string;
|
|
37
|
+
type: ValueType;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The Slots a step's `with:` map resolves into.
|
|
41
|
+
*
|
|
42
|
+
* A `map` field contributes one Slot per entry, named `<field>.<key>`, because
|
|
43
|
+
* each entry is separately typed and separately wrong.
|
|
44
|
+
*/
|
|
45
|
+
export declare function slotsFor(step: Step, manifest: Manifest): Slot[];
|
|
46
|
+
/**
|
|
47
|
+
* The Slot a branch's `when` resolves into.
|
|
48
|
+
*
|
|
49
|
+
* Separate from `slotsFor` because a branch is not a step and has no manifest —
|
|
50
|
+
* and because its type is not declared anywhere: a condition is a boolean, and
|
|
51
|
+
* that is the whole reason `when: "{{steps.s2.count}} > 0"` can be refused at design
|
|
52
|
+
* time rather than misread at run time.
|
|
53
|
+
*/
|
|
54
|
+
export declare const whenSlot: (when: string) => Slot;
|
|
55
|
+
/** The verb whose outputs come from its own configuration. */
|
|
56
|
+
export declare const MAPPING_VERB = "core.map";
|
|
57
|
+
/** The verb that iterates a collection. */
|
|
58
|
+
export declare const FOR_EACH_VERB = "core.for_each";
|
|
59
|
+
/** The verb that branches. */
|
|
60
|
+
export declare const FORK_VERB = "core.fork";
|
|
61
|
+
/** The verb that writes one of its Board's variables. */
|
|
62
|
+
export declare const SET_VAR_VERB = "core.set_var";
|
|
63
|
+
/**
|
|
64
|
+
* The field a `core.for_each` iterates, and the one `item` is resolved through.
|
|
65
|
+
*
|
|
66
|
+
* A constant rather than a literal at three call sites, because it is a name two
|
|
67
|
+
* languages and one manifest have to agree on: `item` means "one element of
|
|
68
|
+
* whatever THIS key points at", so a reader looking under a different key
|
|
69
|
+
* resolves `item` to nothing and reports no type at all.
|
|
70
|
+
*/
|
|
71
|
+
export declare const FOR_EACH_LIST_FIELD = "list";
|
|
72
|
+
/**
|
|
73
|
+
* The output key a container binds for the children it owns.
|
|
74
|
+
*
|
|
75
|
+
* Both are ordinary manifest outputs of the container Step, read as
|
|
76
|
+
* `{{steps.<container id>.<key>}}`. That is the whole binding mechanism, and it
|
|
77
|
+
* is one mechanism rather than two: ADR-0014 closed the path roots so that a
|
|
78
|
+
* structural idea could not take a bare word away from users, and a Step id is
|
|
79
|
+
* already one segment below `steps.`. Two nested loops cannot shadow each other,
|
|
80
|
+
* because two Steps cannot share an id on one Board.
|
|
81
|
+
*/
|
|
82
|
+
export declare const ITEM_BINDING = "item";
|
|
83
|
+
/**
|
|
84
|
+
* The Slot a `core.repeat`'s `until` resolves into.
|
|
85
|
+
*
|
|
86
|
+
* The mirror of `whenSlot`, and for the same reason: a condition is a boolean,
|
|
87
|
+
* and no manifest field can say so — `FIELD_KIND_TYPES` has no mappable boolean
|
|
88
|
+
* at all, because `bool` holds a literal rather than a Template. That is why
|
|
89
|
+
* `until` is a structural key beside `steps:` rather than a field under `with:`.
|
|
90
|
+
* Under `with:` it would type-check as text, so `{{ steps.s2.count }}` would
|
|
91
|
+
* pass as a termination condition.
|
|
92
|
+
*
|
|
93
|
+
* A repeat tests this AFTER its body, so the body always runs at least once.
|
|
94
|
+
*/
|
|
95
|
+
export declare const repeatSlot: (until: string) => Slot;
|
|
96
|
+
/**
|
|
97
|
+
* The type a variable's `{{ var.<key> }}`, its initial `value` and every
|
|
98
|
+
* `core.set_var` writing it are all checked against.
|
|
99
|
+
*
|
|
100
|
+
* Declared rather than read off the value. A var is the one addressable thing
|
|
101
|
+
* whose content changes while the document does not, so inferring its type from
|
|
102
|
+
* the literal in the file would make the marking a lie the moment a
|
|
103
|
+
* `core.set_var` wrote something else — and every downstream check was answered
|
|
104
|
+
* against it (ADR-0013).
|
|
105
|
+
*
|
|
106
|
+
* `unknown` for a var carrying no `t` at all — absent or empty alike, matching
|
|
107
|
+
* the Go SDK, because a hand-edit is exactly what reaches here and `t: ""` is as
|
|
108
|
+
* plausible a one as a missing key. The schema requires a type, so refusing to
|
|
109
|
+
* check is the honest answer where guessing `text` would refuse a document over
|
|
110
|
+
* a type nothing declared.
|
|
111
|
+
*/
|
|
112
|
+
export declare const variableType: (variable: Variable) => ValueType;
|
|
113
|
+
/**
|
|
114
|
+
* The Slot a `core.set_var`'s `value` resolves into, typed by the variable it
|
|
115
|
+
* names.
|
|
116
|
+
*
|
|
117
|
+
* The third verb a manifest cannot describe, alongside a call and a
|
|
118
|
+
* `core.return`, and for the same reason: what its field must produce is
|
|
119
|
+
* declared elsewhere in the document. Here it is the Board's `vars`, which is
|
|
120
|
+
* also why a `core.set_var` inside a Block can only ever name that Block's —
|
|
121
|
+
* `vars` is read from the Board the Step sits on, so there is no reaching out.
|
|
122
|
+
*
|
|
123
|
+
* Takes the Board rather than a list of variables, so the caller cannot supply
|
|
124
|
+
* the wrong one: the Go SDK's `SetVarSlot` has the same signature, and a runner
|
|
125
|
+
* handed a list would be the one deciding whether a Block falls back to the
|
|
126
|
+
* workflow's variables — which is the rule this verb exists inside.
|
|
127
|
+
*
|
|
128
|
+
* Null when the step names no variable, or names one the Board does not
|
|
129
|
+
* declare: both have their own diagnostic, and resolving a Template against a
|
|
130
|
+
* type nothing declared would report a mismatch the user cannot act on.
|
|
131
|
+
*/
|
|
132
|
+
export declare function setVarSlot(doc: WorkflowDefinition, board: BoardId, step: Step): Slot | null;
|
|
133
|
+
/**
|
|
134
|
+
* The Slot a variable's initial value resolves into.
|
|
135
|
+
*
|
|
136
|
+
* A var's `value` may hold `{{ … }}`, and until `t` was declared there was
|
|
137
|
+
* nothing to check it against. Null for a literal: only a Template is a Slot.
|
|
138
|
+
*/
|
|
139
|
+
export declare function variableSlot(variable: Variable): Slot | null;
|
|
140
|
+
/** The `{key, value, type}` entries of a `map` field, ignoring anything malformed. */
|
|
141
|
+
export declare function mapEntries(value: unknown): MapEntry[];
|
|
142
|
+
/**
|
|
143
|
+
* The Slots a Step's `with:` map resolves into, whichever kind of Step it is.
|
|
144
|
+
*
|
|
145
|
+
* One entry point, so a caller never has to know that a call, a `core.return`
|
|
146
|
+
* and a `core.set_var` are the three verbs a Component Manifest cannot
|
|
147
|
+
* describe: what each of their fields must produce is declared elsewhere in the
|
|
148
|
+
* document — in a Block's `params`, in a Block's `outputs`, in the Board's
|
|
149
|
+
* `vars` — and a caller that only asked `slotsFor` would check nothing at a
|
|
150
|
+
* call site at all. `sdk/go`'s `SlotsForStep` is the same dispatch.
|
|
151
|
+
*
|
|
152
|
+
* Empty where the document does not say: a call naming a Block that is not
|
|
153
|
+
* declared, a return on the root Board, a `core.set_var` naming no variable.
|
|
154
|
+
* Each of those has its own diagnostic, and resolving a Template against a
|
|
155
|
+
* contract nothing declares would report a second problem about the first one.
|
|
156
|
+
*
|
|
157
|
+
* A branch's `when:` and a `core.repeat`'s `until:` are NOT here. They are
|
|
158
|
+
* structural keys beside `steps:` rather than fields under `with:`, which is
|
|
159
|
+
* exactly what lets them be boolean — `whenSlot` and `repeatSlot` are theirs.
|
|
160
|
+
*/
|
|
161
|
+
export declare function slotsForStep(doc: WorkflowDefinition, board: BoardId, step: Step, manifest: Manifest | undefined): Slot[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|