@telorun/analyzer 0.73.0 → 0.74.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/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +26 -7
- package/dist/artifact-axes.d.ts +14 -0
- package/dist/artifact-axes.d.ts.map +1 -0
- package/dist/artifact-axes.js +12 -0
- package/dist/artifact-layer-index.d.ts +2 -2
- package/dist/artifact-layer-index.d.ts.map +1 -1
- package/dist/artifact-layer-index.js +9 -4
- package/dist/artifact-selector.d.ts +47 -21
- package/dist/artifact-selector.d.ts.map +1 -1
- package/dist/artifact-selector.js +85 -16
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +73 -16
- package/dist/call-graph.d.ts +12 -1
- package/dist/call-graph.d.ts.map +1 -1
- package/dist/call-graph.js +22 -0
- package/dist/catch-scope.js +1 -1
- package/dist/forwarded-declaration.d.ts +26 -0
- package/dist/forwarded-declaration.d.ts.map +1 -0
- package/dist/forwarded-declaration.js +31 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/kernel-globals.d.ts.map +1 -1
- package/dist/kernel-globals.js +21 -5
- package/dist/module-alias-scope.d.ts +11 -0
- package/dist/module-alias-scope.d.ts.map +1 -1
- package/dist/module-alias-scope.js +10 -0
- package/dist/module-file-claims.d.ts +17 -1
- package/dist/module-file-claims.d.ts.map +1 -1
- package/dist/module-file-claims.js +38 -3
- package/dist/module-named-files.d.ts +72 -0
- package/dist/module-named-files.d.ts.map +1 -0
- package/dist/module-named-files.js +115 -0
- package/dist/native-entries.d.ts +83 -0
- package/dist/native-entries.d.ts.map +1 -0
- package/dist/native-entries.js +169 -0
- package/dist/normalize-inline-resources.d.ts +41 -13
- package/dist/normalize-inline-resources.d.ts.map +1 -1
- package/dist/normalize-inline-resources.js +236 -54
- package/dist/reference-field-map.d.ts +59 -1
- package/dist/reference-field-map.d.ts.map +1 -1
- package/dist/reference-field-map.js +200 -34
- package/dist/release/payload-digest.d.ts +2 -1
- package/dist/release/payload-digest.d.ts.map +1 -1
- package/dist/release/payload-digest.js +2 -1
- package/dist/resolve-ref-sentinels.d.ts.map +1 -1
- package/dist/resolve-ref-sentinels.js +8 -5
- package/dist/resolve-throws-union.d.ts +25 -4
- package/dist/resolve-throws-union.d.ts.map +1 -1
- package/dist/resolve-throws-union.js +62 -32
- package/dist/resolve-zone-requirements.d.ts.map +1 -1
- package/dist/resolve-zone-requirements.js +2 -1
- package/dist/rewrite-synthetic-origins.d.ts +6 -1
- package/dist/rewrite-synthetic-origins.d.ts.map +1 -1
- package/dist/rewrite-synthetic-origins.js +107 -13
- package/dist/schema-compat.d.ts.map +1 -1
- package/dist/schema-compat.js +18 -5
- package/dist/schema-walk.d.ts +47 -13
- package/dist/schema-walk.d.ts.map +1 -1
- package/dist/schema-walk.js +150 -30
- package/dist/scope-declarations.d.ts +59 -0
- package/dist/scope-declarations.d.ts.map +1 -0
- package/dist/scope-declarations.js +45 -0
- package/dist/source-entries.d.ts +119 -0
- package/dist/source-entries.d.ts.map +1 -0
- package/dist/source-entries.js +349 -0
- package/dist/step-bodies.d.ts +24 -0
- package/dist/step-bodies.d.ts.map +1 -0
- package/dist/step-bodies.js +28 -0
- package/dist/telo-version.d.ts +1 -1
- package/dist/telo-version.js +1 -1
- package/dist/validate-cel-context.d.ts.map +1 -1
- package/dist/validate-cel-context.js +3 -2
- package/dist/validate-module-artifact.d.ts +4 -2
- package/dist/validate-module-artifact.d.ts.map +1 -1
- package/dist/validate-module-artifact.js +43 -4
- package/dist/validate-native-entries.d.ts +15 -0
- package/dist/validate-native-entries.d.ts.map +1 -0
- package/dist/validate-native-entries.js +103 -0
- package/dist/validate-observed-state.d.ts +7 -1
- package/dist/validate-observed-state.d.ts.map +1 -1
- package/dist/validate-observed-state.js +24 -6
- package/dist/validate-reference-forms.d.ts.map +1 -1
- package/dist/validate-reference-forms.js +2 -2
- package/dist/validate-references.d.ts.map +1 -1
- package/dist/validate-references.js +11 -5
- package/dist/validate-scope-reach.d.ts +31 -0
- package/dist/validate-scope-reach.d.ts.map +1 -0
- package/dist/validate-scope-reach.js +180 -0
- package/dist/validate-source-entries.d.ts +16 -0
- package/dist/validate-source-entries.d.ts.map +1 -0
- package/dist/validate-source-entries.js +90 -0
- package/dist/validate-throws-coverage.d.ts.map +1 -1
- package/dist/validate-throws-coverage.js +21 -39
- package/dist/value-type-keyword.d.ts +22 -5
- package/dist/value-type-keyword.d.ts.map +1 -1
- package/dist/value-type-keyword.js +16 -7
- package/package.json +3 -3
- package/src/analyzer.ts +33 -9
- package/src/artifact-axes.ts +24 -0
- package/src/artifact-layer-index.ts +9 -6
- package/src/artifact-selector.ts +110 -35
- package/src/builtins.ts +75 -16
- package/src/call-graph.ts +30 -0
- package/src/catch-scope.ts +1 -1
- package/src/forwarded-declaration.ts +32 -0
- package/src/index.ts +36 -1
- package/src/kernel-globals.ts +28 -5
- package/src/migrations/CLAUDE.md +35 -0
- package/src/module-alias-scope.ts +17 -0
- package/src/module-file-claims.ts +63 -4
- package/src/module-named-files.ts +162 -0
- package/src/native-entries.ts +227 -0
- package/src/normalize-inline-resources.ts +326 -70
- package/src/reference-field-map.ts +257 -52
- package/src/release/CLAUDE.md +32 -0
- package/src/release/payload-digest.ts +2 -1
- package/src/resolve-ref-sentinels.ts +7 -6
- package/src/resolve-throws-union.ts +87 -32
- package/src/resolve-zone-requirements.ts +2 -1
- package/src/rewrite-synthetic-origins.ts +107 -16
- package/src/schema-compat.ts +18 -4
- package/src/schema-walk.ts +162 -34
- package/src/scope-declarations.ts +98 -0
- package/src/source-entries.ts +502 -0
- package/src/step-bodies.ts +55 -0
- package/src/telo-version.ts +1 -1
- package/src/validate-cel-context.ts +3 -2
- package/src/validate-module-artifact.ts +46 -3
- package/src/validate-native-entries.ts +147 -0
- package/src/validate-observed-state.ts +36 -7
- package/src/validate-reference-forms.ts +2 -3
- package/src/validate-references.ts +10 -6
- package/src/validate-scope-reach.ts +213 -0
- package/src/validate-source-entries.ts +120 -0
- package/src/validate-throws-coverage.ts +24 -31
- package/src/value-type-keyword.ts +35 -9
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { inlineStepTargetName } from "@telorun/sdk";
|
|
2
|
+
import { isTaggedSentinel } from "@telorun/templating";
|
|
3
|
+
import { controllerBearingAncestor, hasOwnControllerOrTemplate, } from "./extends-resolution.js";
|
|
4
|
+
import { isForwardedDeclaration } from "./forwarded-declaration.js";
|
|
5
|
+
import { definitionInScope } from "./module-alias-scope.js";
|
|
6
|
+
import { isInlineResource, isRefEntry } from "./reference-field-map.js";
|
|
7
|
+
import { gatherPropertySchemas } from "./schema-walk.js";
|
|
8
|
+
import { declaredScopes, outsideScopesOf, scopeEncloses, scopeMembers, } from "./scope-declarations.js";
|
|
9
|
+
import { forEachStep, stepBodiesOf } from "./step-bodies.js";
|
|
10
|
+
import { readStepSlot } from "./step-slot.js";
|
|
2
11
|
const SYSTEM_KINDS = new Set([
|
|
3
12
|
"Telo.Definition",
|
|
4
13
|
"Telo.Application",
|
|
@@ -44,95 +53,266 @@ function cloneForMutation(value) {
|
|
|
44
53
|
/**
|
|
45
54
|
* Phase 2 — Inline resource normalization.
|
|
46
55
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* the inline value in-place with `{kind, name}`. Newly extracted resources are enqueued
|
|
51
|
-
* so nested inlines are resolved in the same pass.
|
|
56
|
+
* Every inline declaration (a `{kind, …config}` with no `name`) is extracted as a
|
|
57
|
+
* first-class manifest under a deterministic name and replaced in place with
|
|
58
|
+
* `{kind, name}`. Two kinds of slot carry one:
|
|
52
59
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
60
|
+
* - a REFERENCE slot, found through the kind's field map, named
|
|
61
|
+
* `{parentName}_{pathSegment}[_{itemName|index}]_{fieldName}`
|
|
62
|
+
* (`TestBasicAddition_steps_AddTwoNumbers_invoke`);
|
|
63
|
+
* - a STEP's dispatch target, at any nesting depth of a step body, named by
|
|
64
|
+
* `inlineStepTargetName` — the name the step engine has always registered it
|
|
65
|
+
* under, which is durable identity and so must not move with the extraction.
|
|
66
|
+
*
|
|
67
|
+
* Step slots are found through the kind's step-body annotation and walked with
|
|
68
|
+
* `walkStepArray`, never through the field map: that map is the kernel's Phase-5
|
|
69
|
+
* injection surface, and a step's target resolves at dispatch.
|
|
70
|
+
*
|
|
71
|
+
* Every extracted manifest is queued in turn, so an inline declaration nested in
|
|
72
|
+
* another's slots — a handler inside an inline step target — is extracted too.
|
|
73
|
+
* So is every member of an `x-telo-scope` array, which is a declaration of its
|
|
74
|
+
* own.
|
|
75
|
+
*
|
|
76
|
+
* WHERE an extraction is created:
|
|
77
|
+
*
|
|
78
|
+
* - a reference slot lying in a region of a scope its owner declares (a
|
|
79
|
+
* sequence's `targets:`) resolves against that scope, so its declaration
|
|
80
|
+
* joins the scope's array and is created per scope run;
|
|
81
|
+
* - a step target is created where its owner is — the module's top level, or
|
|
82
|
+
* the scope array holding a scope member — and never in a scope the owner
|
|
83
|
+
* declares, because that would make every step target of a sequence with a
|
|
84
|
+
* `with:` block a scoped resource and move its durable identity;
|
|
85
|
+
* - any other extraction is created where its owner is.
|
|
86
|
+
*
|
|
87
|
+
* A declaration written inside a scope's region and created outside it records
|
|
88
|
+
* the scope (`xTeloOrigin.outsideScopes`), and `validateScopedNameReach` reports
|
|
89
|
+
* a reference from it to a name that scope declares.
|
|
90
|
+
*
|
|
91
|
+
* An extraction out of a dependency's forwarded manifest is that dependency's
|
|
92
|
+
* code: it is stamped `forwardedInternal` (see `isForwardedDeclaration`) and
|
|
93
|
+
* carries the declaring module's `moduleGlobals`, as its parent does.
|
|
57
94
|
*
|
|
58
95
|
* Returns a new array of deep-cloned manifests (the rewrites land on the clones)
|
|
59
|
-
* plus
|
|
60
|
-
* never mutated; this is the analyzer's immutability boundary.
|
|
96
|
+
* plus every top-level extraction. The caller's manifests — array and elements —
|
|
97
|
+
* are never mutated; this is the analyzer's immutability boundary.
|
|
61
98
|
*/
|
|
62
99
|
export function normalizeInlineResources(resources, registry, aliases, aliasesByModule) {
|
|
63
100
|
// Deep-clone the input so this pass — and `resolveRefSentinels`, which runs on
|
|
64
|
-
// this output — never mutate caller-owned manifests.
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
// reference form). The clone is the analyzer's immutability boundary.
|
|
101
|
+
// this output — never mutate caller-owned manifests. The extractions rewrite
|
|
102
|
+
// slots in place, so without cloning we'd corrupt shared state such as the
|
|
103
|
+
// editor's `LoadedFile.manifests` parse cache (a reused sentinel would be
|
|
104
|
+
// rewritten to `{kind, name}`, later misread as an authored reference form).
|
|
69
105
|
const result = resources.map(cloneForMutation);
|
|
70
|
-
// Queue: all non-system resources with a name. Extracted resources are appended.
|
|
71
|
-
// Filter the CLONES (not the originals) so traversal mutates copies.
|
|
72
106
|
// System kinds join the queue too: their inline-accepting slots are filtered
|
|
73
107
|
// per entry below, so a system document is walked but only its opted-in slots
|
|
74
108
|
// are extracted from.
|
|
75
|
-
const queue = result
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
109
|
+
const queue = result
|
|
110
|
+
.filter((r) => typeof r.metadata?.name === "string" && !!r.kind)
|
|
111
|
+
.map((manifest) => ({
|
|
112
|
+
manifest,
|
|
113
|
+
home: undefined,
|
|
114
|
+
outside: outsideScopesOf(manifest),
|
|
115
|
+
...provenanceOf(manifest, undefined),
|
|
116
|
+
}));
|
|
117
|
+
const place = (manifest, into, module) => {
|
|
118
|
+
if (into)
|
|
119
|
+
into.push(manifest);
|
|
120
|
+
else
|
|
121
|
+
result.push(manifest);
|
|
122
|
+
queue.push({
|
|
123
|
+
manifest: manifest,
|
|
124
|
+
home: into,
|
|
125
|
+
outside: outsideScopesOf(manifest),
|
|
126
|
+
...provenanceOf(manifest, module),
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
for (let i = 0; i < queue.length; i++) {
|
|
130
|
+
const current = queue[i];
|
|
131
|
+
const { manifest: resource, home, outside } = current;
|
|
132
|
+
// The registry reads a kind's alias table off `metadata.module`; a scope
|
|
133
|
+
// member is looked up through a view carrying its owner's.
|
|
134
|
+
const view = current.module !== undefined && moduleOf(resource) === undefined
|
|
135
|
+
? { ...resource, metadata: { ...resource.metadata, module: current.module } }
|
|
136
|
+
: resource;
|
|
79
137
|
// When aliasesByModule is available, use the expanded map so inline refs
|
|
80
138
|
// hidden behind an x-telo-schema-from indirection (e.g. an encoder inside
|
|
81
139
|
// an HttpDispatch.Outcomes/$defs/Returns sub-schema) reach extraction.
|
|
82
140
|
const fieldMap = aliases && aliasesByModule
|
|
83
|
-
? registry.expandedFieldMapForResource(
|
|
141
|
+
? registry.expandedFieldMapForResource(view, aliases, aliasesByModule)
|
|
84
142
|
: registry.getFieldMapForKind(resource.kind, aliases);
|
|
85
143
|
if (!fieldMap)
|
|
86
144
|
continue;
|
|
87
145
|
const parentName = resource.metadata.name;
|
|
88
|
-
const parentModule =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
146
|
+
const parentModule = moduleOf(view);
|
|
147
|
+
const inherit = {
|
|
148
|
+
module: parentModule,
|
|
149
|
+
forwarded: current.forwarded,
|
|
150
|
+
moduleGlobals: current.moduleGlobals,
|
|
151
|
+
};
|
|
152
|
+
const scopes = declaredScopes(resource, fieldMap);
|
|
153
|
+
// Queued BEFORE anything is extracted into these arrays: an extraction
|
|
154
|
+
// queues itself, and must not be walked twice. A member is created inside
|
|
155
|
+
// this resource's scope, which is itself created where this resource is.
|
|
156
|
+
for (const scope of scopes) {
|
|
157
|
+
for (const member of scopeMembers(scope)) {
|
|
158
|
+
queue.push({ manifest: member, home: scope.declarations, outside, ...inherit });
|
|
97
159
|
}
|
|
98
160
|
}
|
|
161
|
+
const outsideAt = (slotPath, createdIn) => [
|
|
162
|
+
...outside,
|
|
163
|
+
...scopes
|
|
164
|
+
.filter((scope) => scope !== createdIn && scopeEncloses(scope, slotPath))
|
|
165
|
+
.map((scope) => ({
|
|
166
|
+
ownerKind: resource.kind,
|
|
167
|
+
ownerName: parentName,
|
|
168
|
+
field: scope.path,
|
|
169
|
+
names: scopeMembers(scope).map((member) => member.metadata.name),
|
|
170
|
+
}))
|
|
171
|
+
.filter((scope) => scope.names.length > 0),
|
|
172
|
+
];
|
|
99
173
|
for (const [fieldPath, entry] of fieldMap) {
|
|
100
174
|
if (!isRefEntry(entry))
|
|
101
175
|
continue;
|
|
102
176
|
if (!acceptsInline(resource.kind, entry))
|
|
103
177
|
continue;
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const invocationContext = isRefEntry(entry) ? entry.context : undefined;
|
|
108
|
-
const extracted = extractInlinesAtPath(resource, fieldPath, parentName, resource.kind, parentModule, invocationContext);
|
|
109
|
-
for (const manifest of extracted) {
|
|
110
|
-
result.push(manifest);
|
|
111
|
-
queue.push(manifest);
|
|
112
|
-
// TODO Phase 5: when inScope, add to parent's scope array instead of outer set
|
|
113
|
-
void inScope;
|
|
178
|
+
const scope = scopes.find((s) => scopeEncloses(s, fieldPath));
|
|
179
|
+
for (const manifest of extractInlinesAtPath(resource, fieldPath, parentName, resource.kind, inherit, outsideAt(fieldPath, scope), entry.context)) {
|
|
180
|
+
place(manifest, scope?.declarations ?? home, parentModule);
|
|
114
181
|
}
|
|
115
182
|
}
|
|
183
|
+
if (SYSTEM_KINDS.has(resource.kind))
|
|
184
|
+
continue;
|
|
185
|
+
extractStepTargets(resource, view, registry, aliases, aliasesByModule, inherit, outsideAt, (m) => place(m, home, parentModule));
|
|
116
186
|
}
|
|
117
187
|
return result;
|
|
118
188
|
}
|
|
189
|
+
const moduleOf = (manifest) => {
|
|
190
|
+
const module = manifest.metadata?.module;
|
|
191
|
+
return typeof module === "string" ? module : undefined;
|
|
192
|
+
};
|
|
193
|
+
function provenanceOf(manifest, module) {
|
|
194
|
+
return {
|
|
195
|
+
module: moduleOf(manifest) ?? module,
|
|
196
|
+
forwarded: isForwardedDeclaration(manifest),
|
|
197
|
+
moduleGlobals: manifest.metadata?.moduleGlobals,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Extract every inline dispatch target of every step in `resource`'s step
|
|
202
|
+
* bodies, at any nesting depth, into a named manifest.
|
|
203
|
+
*
|
|
204
|
+
* The name is the step engine's, so it names what the RUNTIME owner passes it:
|
|
205
|
+
*
|
|
206
|
+
* - the owner kind is the kind whose CONTROLLER runs the body — the kind
|
|
207
|
+
* itself, or for an `extends` child that inherits its controller, the
|
|
208
|
+
* ancestor that supplies it;
|
|
209
|
+
* - the path's first segment is the field the controller reads its body from.
|
|
210
|
+
* For a `base:`-form child that is the PARENT's field the body is mapped onto,
|
|
211
|
+
* which is taken from a pure `self.<field>` mapping; a body `base:` reshapes any
|
|
212
|
+
* other way is left inline, for the runtime to name exactly as it always has;
|
|
213
|
+
* - an inline declaration stating its own `metadata.name` keeps it, as
|
|
214
|
+
* `ensureKindRef` always has.
|
|
215
|
+
*/
|
|
216
|
+
function extractStepTargets(resource, view, registry, aliases, aliasesByModule, inherit, outsideAt, emit) {
|
|
217
|
+
const definition = definitionInScope(registry, view.kind, view.metadata, aliases, aliasesByModule);
|
|
218
|
+
if (!definition)
|
|
219
|
+
return;
|
|
220
|
+
const schema = registry.effectiveSchemaOf(definition);
|
|
221
|
+
if (!schema)
|
|
222
|
+
return;
|
|
223
|
+
const resolveDef = (kind, from) => definitionInScope(registry, kind, from?.metadata, aliases, aliasesByModule);
|
|
224
|
+
const runner = hasOwnControllerOrTemplate(definition)
|
|
225
|
+
? definition
|
|
226
|
+
: (controllerBearingAncestor(definition, resolveDef) ?? definition);
|
|
227
|
+
const owner = { kind: runner.metadata.name, resourceName: resource.metadata.name };
|
|
228
|
+
const base = runner !== definition ? definition.base : undefined;
|
|
229
|
+
for (const body of stepBodiesOf(resource, schema)) {
|
|
230
|
+
const root = base === undefined ? body.field : mappedStepField(base, body.field, runner, registry);
|
|
231
|
+
if (root === undefined)
|
|
232
|
+
continue;
|
|
233
|
+
const outsideScopes = outsideAt(body.field);
|
|
234
|
+
forEachStep(body, schema, (step, stepPath) => {
|
|
235
|
+
const target = step[body.invokeField];
|
|
236
|
+
if (!target || typeof target !== "object" || Array.isArray(target))
|
|
237
|
+
return;
|
|
238
|
+
if (!isInlineResource(target))
|
|
239
|
+
return;
|
|
240
|
+
// The step grammar requires a name, and a target is named after it; a step
|
|
241
|
+
// without one is reported by schema validation and left as written.
|
|
242
|
+
if (typeof step.name !== "string")
|
|
243
|
+
return;
|
|
244
|
+
const inline = target;
|
|
245
|
+
const declared = inline.metadata?.name;
|
|
246
|
+
const name = typeof declared === "string"
|
|
247
|
+
? declared
|
|
248
|
+
: inlineStepTargetName(owner, [root, ...stepPathSegments(stepPath).slice(1)], step.name);
|
|
249
|
+
step[body.invokeField] = { kind: inline.kind, name };
|
|
250
|
+
emit(buildManifest(inline, name, {
|
|
251
|
+
parentKind: resource.kind,
|
|
252
|
+
parentName: resource.metadata.name,
|
|
253
|
+
pathFromParent: `${stepPath}.${body.invokeField}`,
|
|
254
|
+
stepTarget: true,
|
|
255
|
+
...(outsideScopes.length > 0 ? { outsideScopes } : {}),
|
|
256
|
+
}, inherit));
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/** The runner's step field a `base:` mapping forwards `field` into, when it does
|
|
261
|
+
* so verbatim (`steps: !cel "self.<field>"`); undefined otherwise. */
|
|
262
|
+
function mappedStepField(base, field, runner, registry) {
|
|
263
|
+
if (!base || typeof base !== "object" || Array.isArray(base))
|
|
264
|
+
return undefined;
|
|
265
|
+
const runnerSchema = registry.effectiveSchemaOf(runner);
|
|
266
|
+
if (!runnerSchema)
|
|
267
|
+
return undefined;
|
|
268
|
+
const runnerSteps = new Set(gatherPropertySchemas(runnerSchema)
|
|
269
|
+
.filter(([, schema]) => readStepSlot(schema) !== undefined)
|
|
270
|
+
.map(([key]) => key));
|
|
271
|
+
for (const [target, value] of Object.entries(base)) {
|
|
272
|
+
if (runnerSteps.has(target) && pureSelfField(value) === field)
|
|
273
|
+
return target;
|
|
274
|
+
}
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
/** `f` for a CEL value that is exactly `self.f`, in any spelling it arrives in. */
|
|
278
|
+
function pureSelfField(value) {
|
|
279
|
+
let source;
|
|
280
|
+
if (isTaggedSentinel(value)) {
|
|
281
|
+
if (value.engine === "cel")
|
|
282
|
+
source = value.source;
|
|
283
|
+
}
|
|
284
|
+
else if (value && typeof value === "object" && value.__compiled) {
|
|
285
|
+
const compiled = value.source;
|
|
286
|
+
if (typeof compiled === "string")
|
|
287
|
+
source = compiled;
|
|
288
|
+
}
|
|
289
|
+
else if (typeof value === "string") {
|
|
290
|
+
source = /^\s*\$\{\{([\s\S]*)\}\}\s*$/.exec(value)?.[1];
|
|
291
|
+
}
|
|
292
|
+
return source === undefined ? undefined : /^self\.([A-Za-z_$][\w$]*)$/.exec(source.trim())?.[1];
|
|
293
|
+
}
|
|
294
|
+
/** `steps[1].cases.a[0]` → `["steps", "1", "cases", "a", "0"]`. Exact even for a
|
|
295
|
+
* case key holding punctuation: the name keeps only alphanumeric runs, so
|
|
296
|
+
* splitting inside a key cannot change it. */
|
|
297
|
+
function stepPathSegments(path) {
|
|
298
|
+
return path.split(/[.[\]]/).filter((segment) => segment.length > 0);
|
|
299
|
+
}
|
|
119
300
|
/**
|
|
120
301
|
* Walks `resource` following `fieldPath` (dot notation, `[]` = array traversal).
|
|
121
302
|
* Mutates the resource in-place: replaces each inline value with `{kind, name}`.
|
|
122
303
|
* Returns the extracted manifests.
|
|
123
|
-
*
|
|
124
|
-
* Each extracted manifest carries `metadata.xTeloOrigin` so downstream
|
|
125
|
-
* diagnostics can be rerouted back to the parent doc's YAML position:
|
|
126
|
-
* - `parentKind` / `parentName` — the resource that owned the inline slot
|
|
127
|
-
* - `pathFromParent` — concrete dotted path with `[N]` indices, matching
|
|
128
|
-
* `buildPositionIndex` keys (e.g. `routes[0].handler`)
|
|
129
304
|
*/
|
|
130
|
-
function extractInlinesAtPath(resource, fieldPath, parentName, parentKind,
|
|
305
|
+
function extractInlinesAtPath(resource, fieldPath, parentName, parentKind, inherit, outsideScopes, invocationContext) {
|
|
131
306
|
const extracted = [];
|
|
132
307
|
const parts = fieldPath.split(".");
|
|
133
308
|
function emit(inline, nameSegments, concretePath) {
|
|
134
309
|
const name = sanitizeName([parentName, ...nameSegments].join("_"));
|
|
135
|
-
extracted.push(buildManifest(inline, name,
|
|
310
|
+
extracted.push(buildManifest(inline, name, {
|
|
311
|
+
parentKind,
|
|
312
|
+
parentName,
|
|
313
|
+
pathFromParent: concretePath,
|
|
314
|
+
...(outsideScopes.length > 0 ? { outsideScopes } : {}),
|
|
315
|
+
}, inherit, invocationContext));
|
|
136
316
|
return name;
|
|
137
317
|
}
|
|
138
318
|
function traverse(obj, partsLeft, nameParts, pathSoFar) {
|
|
@@ -207,7 +387,7 @@ function extractInlinesAtPath(resource, fieldPath, parentName, parentKind, paren
|
|
|
207
387
|
traverse(resource, parts, [], "");
|
|
208
388
|
return extracted;
|
|
209
389
|
}
|
|
210
|
-
function buildManifest(inline, name,
|
|
390
|
+
function buildManifest(inline, name, origin, inherit, invocationContext) {
|
|
211
391
|
const existingMeta = inline.metadata && typeof inline.metadata === "object"
|
|
212
392
|
? inline.metadata
|
|
213
393
|
: {};
|
|
@@ -217,9 +397,11 @@ function buildManifest(inline, name, parentKind, parentName, pathFromParent, par
|
|
|
217
397
|
...existingMeta,
|
|
218
398
|
name,
|
|
219
399
|
// Inherit parent module only if the inline doesn't already declare one
|
|
220
|
-
...(
|
|
400
|
+
...(inherit.module && !existingMeta.module ? { module: inherit.module } : {}),
|
|
401
|
+
...(inherit.forwarded ? { forwardedInternal: true } : {}),
|
|
402
|
+
...(inherit.moduleGlobals !== undefined ? { moduleGlobals: inherit.moduleGlobals } : {}),
|
|
221
403
|
...(invocationContext ? { xTeloInvocationContext: invocationContext } : {}),
|
|
222
|
-
xTeloOrigin:
|
|
404
|
+
xTeloOrigin: origin,
|
|
223
405
|
},
|
|
224
406
|
};
|
|
225
407
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type RefUse, type RefUseCases } from "./ref-slot.js";
|
|
1
|
+
import { type RefSlot, type RefUse, type RefUseCases } from "./ref-slot.js";
|
|
2
|
+
import { type StepSlot } from "./step-slot.js";
|
|
2
3
|
export { readRefSlot, isRefSlot, hasDeclaredUse } from "./ref-slot.js";
|
|
3
4
|
export type { RefSlot, RefUse, RefUseCases } from "./ref-slot.js";
|
|
4
5
|
/** An entry for a field that carries one or more x-telo-ref constraints. */
|
|
@@ -36,6 +37,39 @@ export interface RefFieldEntry {
|
|
|
36
37
|
* an unconditional opt-in would rewrite the value into a valid shape before
|
|
37
38
|
* the schema ever saw it. */
|
|
38
39
|
inline?: boolean;
|
|
40
|
+
/** See {@link RefSlot.throwsThrough}. */
|
|
41
|
+
throwsThrough?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** The slot an entry records, as `readRefSlot` read it. */
|
|
44
|
+
export declare function refSlotOfEntry(entry: RefFieldEntry): RefSlot;
|
|
45
|
+
/** Everything a driven-slot map records at one field path. */
|
|
46
|
+
export interface DrivenPath {
|
|
47
|
+
/** Every reference slot declared here, by any branch. Kept apart rather than
|
|
48
|
+
* merged into one slot and read as a union: a branch that does not apply to a
|
|
49
|
+
* resource can only ADD what counts — more coverage demanded, never less — and
|
|
50
|
+
* one merged slot could not hold two case-map selectors or a branch that
|
|
51
|
+
* declares no use. */
|
|
52
|
+
refs: RefFieldEntry[];
|
|
53
|
+
/** Every step body declared here, by any branch. */
|
|
54
|
+
steps: StepSlot[];
|
|
55
|
+
/** Back-edges of a recursive schema: the schema here is also the one entered
|
|
56
|
+
* at each of these paths, so everything below them applies again below this
|
|
57
|
+
* one, as deep as a resource's data goes. Recorded BESIDE `refs`, never in
|
|
58
|
+
* place of them — a `!ref` here resolves as a reference, an inline object
|
|
59
|
+
* recurses. */
|
|
60
|
+
recurse: string[];
|
|
61
|
+
}
|
|
62
|
+
/** See {@link buildDrivenSlotMap}. */
|
|
63
|
+
export interface DrivenSlots {
|
|
64
|
+
paths: Map<string, DrivenPath>;
|
|
65
|
+
/** Per `{}` field path, the keys JSON Schema does NOT apply that
|
|
66
|
+
* `additionalProperties` to: those the same schema declares under
|
|
67
|
+
* `properties`, plus the resource envelope at the root. Where several schemas
|
|
68
|
+
* meet at one `{}` path, only keys every one of them declares are skipped. */
|
|
69
|
+
declaredKeys: Map<string, Set<string>>;
|
|
70
|
+
/** True when some path holds a step or reference slot. A map of back-edges
|
|
71
|
+
* alone drives nothing, so a walk over it is skipped. */
|
|
72
|
+
drives: boolean;
|
|
39
73
|
}
|
|
40
74
|
/** An entry for a field that declares an execution scope (x-telo-scope). */
|
|
41
75
|
export interface ScopeFieldEntry {
|
|
@@ -139,4 +173,28 @@ export declare function collectRefs(node: Record<string, any>): string[];
|
|
|
139
173
|
* inline normalization and Phase 5 injection see slots that the local field map
|
|
140
174
|
* hid behind the schema-from indirection. */
|
|
141
175
|
export declare function buildFieldMapAtPath(schema: Record<string, any>, pathPrefix: string): ReferenceFieldMap;
|
|
176
|
+
/**
|
|
177
|
+
* Every slot through which a resource of this schema DRIVES another — the
|
|
178
|
+
* reference field map's own traversal, plus what a dispatch analysis needs and
|
|
179
|
+
* the injection surface must not have:
|
|
180
|
+
*
|
|
181
|
+
* - local `$ref` is followed, resolved against the root. The injection map
|
|
182
|
+
* stops there so a step's `invoke` never becomes an injection site; this map
|
|
183
|
+
* stops AT a step body instead, which removes that reason. A reference back
|
|
184
|
+
* to a node already on the descent is recorded as a back-edge rather than
|
|
185
|
+
* unrolled, so a recursive shape stays finite here and is followed as deep as
|
|
186
|
+
* the data goes by `forEachDrivenSlot`;
|
|
187
|
+
* - a step body is recorded and not descended — the step traversal owns
|
|
188
|
+
* everything below it;
|
|
189
|
+
* - the root's own variant branches and `additionalProperties` are walked, not
|
|
190
|
+
* only its `properties`;
|
|
191
|
+
* - a path keeps EVERY slot any branch declares there, where the injection map
|
|
192
|
+
* keeps the last one written (see {@link DrivenPath.refs});
|
|
193
|
+
* - each `{}` path records the keys its `additionalProperties` does not cover.
|
|
194
|
+
*
|
|
195
|
+
* Shared by every throws question (a kind's `inherit` union, a scope list's
|
|
196
|
+
* denominator, catch-scope enclosure, and whether `inherit` is legal at all),
|
|
197
|
+
* so none can reach a slot another cannot. Memoized per schema object.
|
|
198
|
+
*/
|
|
199
|
+
export declare function buildDrivenSlotMap(schema: Record<string, any>): DrivenSlots;
|
|
142
200
|
//# sourceMappingURL=reference-field-map.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference-field-map.d.ts","sourceRoot":"","sources":["../src/reference-field-map.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reference-field-map.d.ts","sourceRoot":"","sources":["../src/reference-field-map.ts"],"names":[],"mappings":"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"}
|