@telorun/language-server 0.102.0 → 0.103.1
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/language-server.mjs +1174 -1015
- package/package.json +5 -5
package/dist/language-server.mjs
CHANGED
|
@@ -17440,8 +17440,8 @@ function normalizePath(path) {
|
|
|
17440
17440
|
function splitSource(source) {
|
|
17441
17441
|
const match = SCHEME.exec(source);
|
|
17442
17442
|
if (match) return { prefix: `${match[1]}://${match[2]}`, path: match[3] || "/" };
|
|
17443
|
-
const
|
|
17444
|
-
if (
|
|
17443
|
+
const root = /^(\/\/[^/]+|\/[A-Za-z]:(?=\/|$))(.*)$/.exec(source);
|
|
17444
|
+
if (root) return { prefix: root[1], path: root[2] || "/" };
|
|
17445
17445
|
return { prefix: "", path: source };
|
|
17446
17446
|
}
|
|
17447
17447
|
function dirnameOf(source) {
|
|
@@ -17478,7 +17478,7 @@ function resolveAgainst(base, relative) {
|
|
|
17478
17478
|
}
|
|
17479
17479
|
|
|
17480
17480
|
// src/engine-version.ts
|
|
17481
|
-
var TELO_ENGINE_VERSION = "0.
|
|
17481
|
+
var TELO_ENGINE_VERSION = "0.103.1";
|
|
17482
17482
|
|
|
17483
17483
|
// src/engine-port.ts
|
|
17484
17484
|
var import_browser = __toESM(require_main3(), 1);
|
|
@@ -38699,21 +38699,22 @@ function createAjv() {
|
|
|
38699
38699
|
}
|
|
38700
38700
|
var ajv = createAjv();
|
|
38701
38701
|
var compiledSchemaValidators = /* @__PURE__ */ new WeakMap();
|
|
38702
|
+
var DEFAULT_ROLES = { source: "source", target: "target" };
|
|
38702
38703
|
function unionBranches(schema4) {
|
|
38703
38704
|
const branches = schema4.anyOf ?? schema4.oneOf;
|
|
38704
38705
|
if (!Array.isArray(branches) || branches.length === 0) return void 0;
|
|
38705
38706
|
return branches.filter((b) => b && typeof b === "object");
|
|
38706
38707
|
}
|
|
38707
|
-
function checkSchemaCompatibility(source, target, resolveRef2) {
|
|
38708
|
+
function checkSchemaCompatibility(source, target, resolveRef2, roles = DEFAULT_ROLES) {
|
|
38708
38709
|
const issues = [];
|
|
38709
|
-
compare(source, target, "", issues, resolveRef2, /* @__PURE__ */ new Set());
|
|
38710
|
+
compare(source, target, "", issues, resolveRef2, /* @__PURE__ */ new Set(), roles);
|
|
38710
38711
|
return { compatible: issues.length === 0, issues };
|
|
38711
38712
|
}
|
|
38712
38713
|
function deref(schema4, resolveRef2) {
|
|
38713
38714
|
if (!resolveRef2 || typeof schema4.$ref !== "string") return schema4;
|
|
38714
38715
|
return resolveRef2(schema4.$ref) ?? schema4;
|
|
38715
38716
|
}
|
|
38716
|
-
function compare(rawSource, rawTarget, path, issues, resolveRef2, seen) {
|
|
38717
|
+
function compare(rawSource, rawTarget, path, issues, resolveRef2, seen, roles) {
|
|
38717
38718
|
if (!rawSource || !rawTarget || typeof rawSource !== "object" || typeof rawTarget !== "object") {
|
|
38718
38719
|
return;
|
|
38719
38720
|
}
|
|
@@ -38734,7 +38735,7 @@ function compare(rawSource, rawTarget, path, issues, resolveRef2, seen) {
|
|
|
38734
38735
|
for (const left of lefts) {
|
|
38735
38736
|
for (const right of rights) {
|
|
38736
38737
|
const probe = [];
|
|
38737
|
-
compare(left, right, path, probe, resolveRef2, new Set(seen));
|
|
38738
|
+
compare(left, right, path, probe, resolveRef2, new Set(seen), roles);
|
|
38738
38739
|
if (probe.length === 0) return;
|
|
38739
38740
|
reasons.push(...probe);
|
|
38740
38741
|
}
|
|
@@ -38749,7 +38750,7 @@ function compare(rawSource, rawTarget, path, issues, resolveRef2, seen) {
|
|
|
38749
38750
|
if (sourceType && targetType) {
|
|
38750
38751
|
if (sourceType.name !== targetType.name) {
|
|
38751
38752
|
issues.push(
|
|
38752
|
-
`${path || "/"}: value type mismatch \u2014 source is '${sourceType.name}', target expects '${targetType.name}'`
|
|
38753
|
+
`${path || "/"}: value type mismatch \u2014 ${roles.source} is '${sourceType.name}', ${roles.target} expects '${targetType.name}'`
|
|
38753
38754
|
);
|
|
38754
38755
|
return;
|
|
38755
38756
|
}
|
|
@@ -38762,7 +38763,8 @@ function compare(rawSource, rawTarget, path, issues, resolveRef2, seen) {
|
|
|
38762
38763
|
`${path}<${argument}>`,
|
|
38763
38764
|
issues,
|
|
38764
38765
|
resolveRef2,
|
|
38765
|
-
seen
|
|
38766
|
+
seen,
|
|
38767
|
+
roles
|
|
38766
38768
|
);
|
|
38767
38769
|
}
|
|
38768
38770
|
return;
|
|
@@ -38772,7 +38774,7 @@ function compare(rawSource, rawTarget, path, issues, resolveRef2, seen) {
|
|
|
38772
38774
|
const other = sourceType ? target : source;
|
|
38773
38775
|
if (targetType?.entry?.fromHost !== void 0 && (source.type !== void 0 || source.const !== void 0 || source.enum !== void 0)) {
|
|
38774
38776
|
issues.push(
|
|
38775
|
-
`${path || "/"}: value type mismatch \u2014 target expects '${targetType.name}', source is a plain value`
|
|
38777
|
+
`${path || "/"}: value type mismatch \u2014 ${roles.target} expects '${targetType.name}', ${roles.source} is a plain value`
|
|
38776
38778
|
);
|
|
38777
38779
|
return;
|
|
38778
38780
|
}
|
|
@@ -38781,7 +38783,7 @@ function compare(rawSource, rawTarget, path, issues, resolveRef2, seen) {
|
|
|
38781
38783
|
const asJson = base === void 0 ? void 0 : declared.entry.base;
|
|
38782
38784
|
if (asJson !== other.type) {
|
|
38783
38785
|
issues.push(
|
|
38784
|
-
`${path || "/"}: value type mismatch \u2014 ${sourceType ?
|
|
38786
|
+
`${path || "/"}: value type mismatch \u2014 ${sourceType ? `${roles.source} is` : `${roles.target} expects`} '${declared.name}', ${sourceType ? `${roles.target} expects` : `${roles.source} is`} '${other.type}'`
|
|
38785
38787
|
);
|
|
38786
38788
|
return;
|
|
38787
38789
|
}
|
|
@@ -38789,7 +38791,7 @@ function compare(rawSource, rawTarget, path, issues, resolveRef2, seen) {
|
|
|
38789
38791
|
}
|
|
38790
38792
|
if (typeof source.type === "string" && typeof target.type === "string" && source.type !== target.type) {
|
|
38791
38793
|
issues.push(
|
|
38792
|
-
`${path || "/"}: type mismatch \u2014 source is '${source.type}', target expects '${target.type}'`
|
|
38794
|
+
`${path || "/"}: type mismatch \u2014 ${roles.source} is '${source.type}', ${roles.target} expects '${target.type}'`
|
|
38793
38795
|
);
|
|
38794
38796
|
return;
|
|
38795
38797
|
}
|
|
@@ -38800,7 +38802,8 @@ function compare(rawSource, rawTarget, path, issues, resolveRef2, seen) {
|
|
|
38800
38802
|
`${path}[]`,
|
|
38801
38803
|
issues,
|
|
38802
38804
|
resolveRef2,
|
|
38803
|
-
seen
|
|
38805
|
+
seen,
|
|
38806
|
+
roles
|
|
38804
38807
|
);
|
|
38805
38808
|
}
|
|
38806
38809
|
const targetRequired = Array.isArray(target.required) ? target.required : [];
|
|
@@ -38809,13 +38812,13 @@ function compare(rawSource, rawTarget, path, issues, resolveRef2, seen) {
|
|
|
38809
38812
|
for (const field of targetRequired) {
|
|
38810
38813
|
if (!(field in sourceProps)) {
|
|
38811
38814
|
if (source.properties === void 0) continue;
|
|
38812
|
-
issues.push(`${path}/${field}: required by target but missing from source`);
|
|
38815
|
+
issues.push(`${path}/${field}: required by ${roles.target} but missing from ${roles.source}`);
|
|
38813
38816
|
continue;
|
|
38814
38817
|
}
|
|
38815
38818
|
const srcProp = sourceProps[field];
|
|
38816
38819
|
const tgtProp = targetProps[field];
|
|
38817
38820
|
if (tgtProp && srcProp) {
|
|
38818
|
-
compare(srcProp, tgtProp, `${path}/${field}`, issues, resolveRef2, seen);
|
|
38821
|
+
compare(srcProp, tgtProp, `${path}/${field}`, issues, resolveRef2, seen, roles);
|
|
38819
38822
|
}
|
|
38820
38823
|
}
|
|
38821
38824
|
}
|
|
@@ -39914,6 +39917,7 @@ function readRefSlot(node) {
|
|
|
39914
39917
|
let useCases;
|
|
39915
39918
|
let inputs;
|
|
39916
39919
|
let throwsThrough = false;
|
|
39920
|
+
let outputType;
|
|
39917
39921
|
for (const carrier of nodes) {
|
|
39918
39922
|
const annotation = carrier["x-telo-ref"];
|
|
39919
39923
|
for (const kind of readKinds(annotation)) {
|
|
@@ -39925,6 +39929,7 @@ function readRefSlot(node) {
|
|
|
39925
39929
|
useCases ??= readUseCases(obj.use);
|
|
39926
39930
|
if (typeof obj.inputs === "string") inputs ??= obj.inputs;
|
|
39927
39931
|
if (obj.throwsThrough === true) throwsThrough = true;
|
|
39932
|
+
if (isSchemaObject(obj.outputType)) outputType ??= obj.outputType;
|
|
39928
39933
|
}
|
|
39929
39934
|
const slot = {
|
|
39930
39935
|
kinds,
|
|
@@ -39935,8 +39940,12 @@ function readRefSlot(node) {
|
|
|
39935
39940
|
if (useCases) slot.useCases = useCases;
|
|
39936
39941
|
if (inputs !== void 0) slot.inputs = inputs;
|
|
39937
39942
|
if (throwsThrough) slot.throwsThrough = true;
|
|
39943
|
+
if (outputType) slot.outputType = outputType;
|
|
39938
39944
|
return slot;
|
|
39939
39945
|
}
|
|
39946
|
+
function isSchemaObject(value) {
|
|
39947
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
39948
|
+
}
|
|
39940
39949
|
function isRefSlot(node) {
|
|
39941
39950
|
return annotationNodes(node).length > 0;
|
|
39942
39951
|
}
|
|
@@ -39949,6 +39958,7 @@ function refSlotAnnotation(slot) {
|
|
|
39949
39958
|
else if (slot.uses.length > 1) annotation.use = slot.uses;
|
|
39950
39959
|
if (slot.inputs !== void 0) annotation.inputs = slot.inputs;
|
|
39951
39960
|
if (slot.throwsThrough) annotation.throwsThrough = true;
|
|
39961
|
+
if (slot.outputType) annotation.outputType = slot.outputType;
|
|
39952
39962
|
return annotation;
|
|
39953
39963
|
}
|
|
39954
39964
|
function rewriteRefSlotKinds(annotationHolder, map3) {
|
|
@@ -41990,6 +42000,7 @@ function refSlotOfEntry(entry) {
|
|
|
41990
42000
|
if (entry.useCases) slot.useCases = entry.useCases;
|
|
41991
42001
|
if (entry.inputs !== void 0) slot.inputs = entry.inputs;
|
|
41992
42002
|
if (entry.throwsThrough) slot.throwsThrough = true;
|
|
42003
|
+
if (entry.outputType) slot.outputType = entry.outputType;
|
|
41993
42004
|
return slot;
|
|
41994
42005
|
}
|
|
41995
42006
|
function isRefEntry(entry) {
|
|
@@ -42197,6 +42208,7 @@ function traverseNode(node, path, sink, root, onStack = /* @__PURE__ */ new Map(
|
|
|
42197
42208
|
if (node["x-telo-context"]) entry.context = node["x-telo-context"];
|
|
42198
42209
|
if (slot.inline) entry.inline = true;
|
|
42199
42210
|
if (slot.throwsThrough) entry.throwsThrough = true;
|
|
42211
|
+
if (slot.outputType) entry.outputType = slot.outputType;
|
|
42200
42212
|
sink.ref(path, entry, node);
|
|
42201
42213
|
for (const variantKey2 of ["oneOf", "anyOf", "allOf"]) {
|
|
42202
42214
|
const variants = node[variantKey2];
|
|
@@ -46153,690 +46165,195 @@ function dataEdges(node, manifest, fromModule, resolveName, rowIdByPath, rowsByO
|
|
|
46153
46165
|
return out;
|
|
46154
46166
|
}
|
|
46155
46167
|
|
|
46156
|
-
// ../../analyzer/nodejs/src/
|
|
46157
|
-
|
|
46158
|
-
|
|
46159
|
-
|
|
46160
|
-
|
|
46161
|
-
|
|
46162
|
-
|
|
46163
|
-
|
|
46164
|
-
}
|
|
46165
|
-
|
|
46166
|
-
|
|
46167
|
-
|
|
46168
|
-
|
|
46169
|
-
|
|
46170
|
-
|
|
46171
|
-
|
|
46172
|
-
|
|
46173
|
-
|
|
46174
|
-
get celScope() {
|
|
46175
|
-
return this.celScopeQuery ??= new CelScopeQuery(this.manifests, this.ctx);
|
|
46176
|
-
}
|
|
46177
|
-
/** What calls what. Built on first use and kept, so the projection and any
|
|
46178
|
-
* other consumer over this set share one. */
|
|
46179
|
-
get callGraph() {
|
|
46180
|
-
return this.callGraphMemo ??= buildCallGraph(this.manifests, this.ctx.defs, {
|
|
46181
|
-
aliases: this.ctx.aliases,
|
|
46182
|
-
aliasesByModule: this.ctx.aliasesByModule
|
|
46183
|
-
});
|
|
46184
|
-
}
|
|
46185
|
-
/**
|
|
46186
|
-
* The module graph: boxes, ordered rows and classed edges — the projection an
|
|
46187
|
-
* editor draws.
|
|
46188
|
-
*
|
|
46189
|
-
* Here rather than on the registry because it is the registry AND a manifest
|
|
46190
|
-
* set, which is the pairing this class exists to name; a fifth
|
|
46191
|
-
* `registry.x(manifests, …)` factory is the accretion naming it stopped. It
|
|
46192
|
-
* shares this analysis's call graph rather than building one of its own.
|
|
46193
|
-
*
|
|
46194
|
-
* `deps` is supplied by the registry, which owns capability resolution — this
|
|
46195
|
-
* class holds the manifests, not the rules for reading a kind.
|
|
46196
|
-
*/
|
|
46197
|
-
moduleGraph(deps, options = {}) {
|
|
46198
|
-
return this.moduleGraphMemo ??= buildModuleGraph(
|
|
46199
|
-
this.manifests,
|
|
46200
|
-
this.callGraph,
|
|
46201
|
-
deps,
|
|
46202
|
-
options
|
|
46203
|
-
);
|
|
46204
|
-
}
|
|
46205
|
-
/** Whether a resource's name denotes a type or a value — the rule the naming
|
|
46206
|
-
* check applies to it, so a rename proposes only a name `telo check` accepts. */
|
|
46207
|
-
nameLevel(manifest) {
|
|
46208
|
-
const resolveDef = moduleScopedDefResolver(this.ctx.defs, this.ctx.aliases, this.scopes);
|
|
46209
|
-
return levelFor(manifest, resolveDef, manifest.metadata?.module);
|
|
46210
|
-
}
|
|
46211
|
-
/** The manifest a `(kind, name)` pair addresses. */
|
|
46212
|
-
resourceFor(kind, name) {
|
|
46213
|
-
return findManifest(this.manifests, kind, name);
|
|
46214
|
-
}
|
|
46215
|
-
/**
|
|
46216
|
-
* The invocation contract of the resource a reference names.
|
|
46217
|
-
*
|
|
46218
|
-
* The shared resolver, so an editor offering a target's input keys is offering
|
|
46219
|
-
* exactly what `telo check` validates that call site against and what the
|
|
46220
|
-
* kernel binds at dispatch. Layered instance-first: a resource declaring its
|
|
46221
|
-
* own `inputType:` narrows the kind's, which is the common case for a
|
|
46222
|
-
* `Run.Sequence` used as a handler.
|
|
46223
|
-
*/
|
|
46224
|
-
contractFor(ref, direction) {
|
|
46225
|
-
const target = this.resolveRef(ref);
|
|
46226
|
-
const definition = ref.kind ? this.definitionFor(ref.kind) : void 0;
|
|
46227
|
-
if (!target && !definition) return void 0;
|
|
46228
|
-
return resolveContract(
|
|
46229
|
-
direction,
|
|
46230
|
-
target,
|
|
46231
|
-
definition,
|
|
46232
|
-
analyzerContractScope(
|
|
46233
|
-
this.ctx.defs,
|
|
46234
|
-
this.ctx.aliases,
|
|
46235
|
-
this.scopes,
|
|
46236
|
-
this.manifests
|
|
46237
|
-
)
|
|
46238
|
-
)?.schema;
|
|
46239
|
-
}
|
|
46240
|
-
/**
|
|
46241
|
-
* The manifest a reference names.
|
|
46242
|
-
*
|
|
46243
|
-
* An ALIAS narrows before the name does: a flattened set carries every
|
|
46244
|
-
* imported library's exported instances, so two libraries exporting a `store`
|
|
46245
|
-
* are two manifests with one name. Matching the alias to its target module
|
|
46246
|
-
* picks the right one; where the alias resolves to nothing the name alone is
|
|
46247
|
-
* used, which is what a local reference needs anyway.
|
|
46248
|
-
*/
|
|
46249
|
-
resolveRef(ref) {
|
|
46250
|
-
if (!ref.name) return void 0;
|
|
46251
|
-
const byName = this.manifests.filter(
|
|
46252
|
-
(m) => m.metadata?.name === ref.name
|
|
46253
|
-
);
|
|
46254
|
-
if (byName.length === 0) return void 0;
|
|
46255
|
-
if (byName.length === 1) return byName[0];
|
|
46256
|
-
const targetModule = ref.alias ? this.ctx.aliases.moduleForAlias?.(ref.alias) : void 0;
|
|
46257
|
-
if (targetModule) {
|
|
46258
|
-
const scoped = byName.find(
|
|
46259
|
-
(m) => m.metadata?.module === targetModule
|
|
46260
|
-
);
|
|
46261
|
-
if (scoped) return scoped;
|
|
46168
|
+
// ../../analyzer/nodejs/src/plain-literal-decoding.ts
|
|
46169
|
+
function decodePlainLiterals(value, schema4, external, rootSchema = schema4) {
|
|
46170
|
+
return mapTextLeaves(value, schema4, decodePlainText, external, rootSchema);
|
|
46171
|
+
}
|
|
46172
|
+
function mapTextLeaves(value, schema4, leaf, external, rootSchema = schema4, visit4) {
|
|
46173
|
+
const walk4 = (node, raw, base, pointer) => {
|
|
46174
|
+
const entered = resolveRefIn(raw, base, external);
|
|
46175
|
+
const selected = selectUnionBranch(entered.schema, node, entered.root, external);
|
|
46176
|
+
const { schema: here, root } = resolveRefIn(selected, entered.root, external);
|
|
46177
|
+
visit4?.(here, node, pointer);
|
|
46178
|
+
if (typeof node === "string") return leaf(here, node, pointer);
|
|
46179
|
+
if (!node || typeof node !== "object") return node;
|
|
46180
|
+
if (here["x-telo-ref"] !== void 0) return node;
|
|
46181
|
+
if (isCompiledValue(node) || isTaggedSentinel(node)) return node;
|
|
46182
|
+
if (Array.isArray(node)) {
|
|
46183
|
+
const item = resolveRefIn(here.items ?? {}, root, external);
|
|
46184
|
+
for (let i = 0; i < node.length; i++) node[i] = walk4(node[i], item.schema, item.root, `${pointer}/${i}`);
|
|
46185
|
+
return node;
|
|
46262
46186
|
}
|
|
46263
|
-
|
|
46264
|
-
|
|
46265
|
-
|
|
46266
|
-
const
|
|
46267
|
-
|
|
46268
|
-
|
|
46269
|
-
|
|
46270
|
-
|
|
46271
|
-
|
|
46272
|
-
|
|
46273
|
-
if (isCompiledValue(value) || isTaggedSentinel(value)) {
|
|
46274
|
-
return typeof value.source === "string" ? value.source : "";
|
|
46275
|
-
}
|
|
46276
|
-
if (Array.isArray(value)) return value.map(schemaWithTagsAsText);
|
|
46277
|
-
if (value && typeof value === "object") {
|
|
46278
|
-
const out = {};
|
|
46279
|
-
for (const [k, v] of Object.entries(value)) {
|
|
46280
|
-
out[k] = schemaWithTagsAsText(v);
|
|
46187
|
+
const proto = Object.getPrototypeOf(node);
|
|
46188
|
+
if (proto !== Object.prototype && proto !== null) return node;
|
|
46189
|
+
const properties = collectProperties(here);
|
|
46190
|
+
const additional = here.additionalProperties && typeof here.additionalProperties === "object" ? here.additionalProperties : void 0;
|
|
46191
|
+
const record = node;
|
|
46192
|
+
for (const key of Object.keys(record)) {
|
|
46193
|
+
const child = properties[key] ?? additional;
|
|
46194
|
+
if (child) {
|
|
46195
|
+
record[key] = walk4(record[key], child, root, `${pointer}/${key.replace(/~/g, "~0").replace(/\//g, "~1")}`);
|
|
46196
|
+
}
|
|
46281
46197
|
}
|
|
46282
|
-
return
|
|
46198
|
+
return node;
|
|
46199
|
+
};
|
|
46200
|
+
return walk4(value, schema4, rootSchema, "");
|
|
46201
|
+
}
|
|
46202
|
+
function substituteDecodedCelFields(data, schema4, rootSchema, options = {}) {
|
|
46203
|
+
const decoded = decodePlainLiterals(
|
|
46204
|
+
copyPlainContainers(data),
|
|
46205
|
+
schema4,
|
|
46206
|
+
options.external,
|
|
46207
|
+
rootSchema ?? schema4
|
|
46208
|
+
);
|
|
46209
|
+
return substituteCelFields(decoded, schema4, rootSchema, options);
|
|
46210
|
+
}
|
|
46211
|
+
function copyPlainContainers(value) {
|
|
46212
|
+
if (Array.isArray(value)) return value.map(copyPlainContainers);
|
|
46213
|
+
if (!value || typeof value !== "object" || isCompiledValue(value) || isTaggedSentinel(value)) {
|
|
46214
|
+
return value;
|
|
46283
46215
|
}
|
|
46284
|
-
|
|
46216
|
+
const proto = Object.getPrototypeOf(value);
|
|
46217
|
+
if (proto !== Object.prototype && proto !== null) return value;
|
|
46218
|
+
return Object.fromEntries(
|
|
46219
|
+
Object.entries(value).map(([key, item]) => [
|
|
46220
|
+
key,
|
|
46221
|
+
copyPlainContainers(item)
|
|
46222
|
+
])
|
|
46223
|
+
);
|
|
46285
46224
|
}
|
|
46286
46225
|
|
|
46287
|
-
// ../../analyzer/nodejs/src/
|
|
46288
|
-
var
|
|
46289
|
-
|
|
46290
|
-
|
|
46291
|
-
|
|
46292
|
-
|
|
46293
|
-
|
|
46294
|
-
|
|
46295
|
-
|
|
46296
|
-
registeredSchemaIds = /* @__PURE__ */ new Set();
|
|
46297
|
-
compiledValidators = /* @__PURE__ */ new WeakMap();
|
|
46298
|
-
/** The subset of `registeredSchemaIds` claimed by a kind's schema. Kinds and
|
|
46299
|
-
* named `Telo.Type`s share one `telo://<module>/<Name>` id space, so this is
|
|
46300
|
-
* what lets a colliding type name be reported instead of silently dropped. */
|
|
46301
|
-
definitionSchemaIds = /* @__PURE__ */ new Set();
|
|
46302
|
-
defs = /* @__PURE__ */ new Map();
|
|
46303
|
-
fieldMaps = /* @__PURE__ */ new Map();
|
|
46304
|
-
/** Reverse inheritance index: parent kind → direct child kinds. */
|
|
46305
|
-
extendedBy = /* @__PURE__ */ new Map();
|
|
46306
|
-
/** Memoized inheritance-resolved schemas. `null` records "resolved to
|
|
46307
|
-
* nothing", so a kind with no schema is not re-walked on every resource. */
|
|
46308
|
-
effectiveSchemas = /* @__PURE__ */ new Map();
|
|
46309
|
-
/** DEPRECATED module identity table: identity string → canonical module name
|
|
46310
|
-
* ("std/pipeline" → "pipeline"). Serves only the legacy
|
|
46311
|
-
* `<namespace>/<module>#<Kind>` form of `x-telo-ref`, kept resolvable for
|
|
46312
|
-
* module versions published before constraints named their target by import
|
|
46313
|
-
* alias. Fed by `metadata.namespace`, which nothing else reads. */
|
|
46314
|
-
identityMap = /* @__PURE__ */ new Map();
|
|
46315
|
-
register(definition) {
|
|
46316
|
-
this.add(definition, false);
|
|
46317
|
-
}
|
|
46318
|
-
/** `trustedSchema` skips meta-validating the schema — only for the built-ins,
|
|
46319
|
-
* whose validity a test asserts once. */
|
|
46320
|
-
add(definition, trustedSchema) {
|
|
46321
|
-
const { name, module: mod } = definition.metadata;
|
|
46322
|
-
const key = mod ? `${mod}.${name}` : name;
|
|
46323
|
-
this.defs.set(key, definition);
|
|
46324
|
-
this.fieldMaps.clear();
|
|
46325
|
-
this.effectiveSchemas.clear();
|
|
46326
|
-
if (definition.capability) {
|
|
46327
|
-
this.addExtendedBy(definition.capability, key);
|
|
46226
|
+
// ../../analyzer/nodejs/src/resolve-schema-type-refs.ts
|
|
46227
|
+
var SCHEMA_FIELDS = ["schema", "inputType", "outputType"];
|
|
46228
|
+
var SIGNATURE_FIELDS = ["params", "returns"];
|
|
46229
|
+
function resolveSchemaTypeRefs(resources, aliases, aliasesByModule) {
|
|
46230
|
+
const walk4 = (value, resolveAuthority, ownModule, isSlotRoot) => {
|
|
46231
|
+
if (value === null || typeof value !== "object") return;
|
|
46232
|
+
if (Array.isArray(value)) {
|
|
46233
|
+
for (const item of value) walk4(item, resolveAuthority, ownModule, false);
|
|
46234
|
+
return;
|
|
46328
46235
|
}
|
|
46329
|
-
|
|
46330
|
-
|
|
46236
|
+
const obj = value;
|
|
46237
|
+
const parsed = parseTeloTypeRef(obj.$ref);
|
|
46238
|
+
if (parsed) {
|
|
46239
|
+
const module = resolveAuthority(parsed.authority);
|
|
46240
|
+
if (module) obj.$ref = canonicalTypeSchemaId(module, parsed.typeName);
|
|
46331
46241
|
}
|
|
46332
|
-
|
|
46333
|
-
|
|
46242
|
+
const named = resolvedRefInSchema(obj);
|
|
46243
|
+
if (named) {
|
|
46244
|
+
const module = named.alias === void 0 ? ownModule : resolveAuthority(named.alias);
|
|
46245
|
+
if (module) {
|
|
46246
|
+
const canonical = canonicalTypeSchemaId(module, named.name);
|
|
46247
|
+
if (isSlotRoot) {
|
|
46248
|
+
obj.$ref = canonical;
|
|
46249
|
+
} else {
|
|
46250
|
+
delete obj.kind;
|
|
46251
|
+
delete obj.name;
|
|
46252
|
+
delete obj.alias;
|
|
46253
|
+
obj.$ref = canonical;
|
|
46254
|
+
}
|
|
46255
|
+
}
|
|
46334
46256
|
}
|
|
46335
|
-
|
|
46336
|
-
|
|
46337
|
-
|
|
46338
|
-
|
|
46339
|
-
|
|
46340
|
-
|
|
46341
|
-
|
|
46257
|
+
for (const key of Object.keys(obj)) walk4(obj[key], resolveAuthority, ownModule, false);
|
|
46258
|
+
};
|
|
46259
|
+
for (const r of resources) {
|
|
46260
|
+
const ownModule = r.metadata?.module;
|
|
46261
|
+
const resolver = moduleAliasScope(r.metadata, aliases, aliasesByModule);
|
|
46262
|
+
const resolveAuthority = (authority) => authority === "Self" ? ownModule : resolver?.moduleForAlias(authority);
|
|
46263
|
+
for (const field of SCHEMA_FIELDS) {
|
|
46264
|
+
walk4(r[field], resolveAuthority, ownModule, true);
|
|
46342
46265
|
}
|
|
46343
|
-
|
|
46344
|
-
|
|
46345
|
-
const children = this.extendedBy.get(parent);
|
|
46346
|
-
if (children) {
|
|
46347
|
-
if (!children.includes(child)) children.push(child);
|
|
46348
|
-
} else {
|
|
46349
|
-
this.extendedBy.set(parent, [child]);
|
|
46266
|
+
for (const field of SIGNATURE_FIELDS) {
|
|
46267
|
+
walk4(r[field], resolveAuthority, ownModule, false);
|
|
46350
46268
|
}
|
|
46351
46269
|
}
|
|
46352
|
-
|
|
46353
|
-
|
|
46354
|
-
|
|
46355
|
-
|
|
46356
|
-
|
|
46357
|
-
|
|
46358
|
-
* The "telo" identity is reserved for the built-in module and is populated
|
|
46359
|
-
* automatically when a `Telo.Abstract` registers. A namespace-less module must
|
|
46360
|
-
* not claim it: overwriting the entry would repoint every legacy `telo#…`
|
|
46361
|
-
* constraint at a module that declares no such kind, and the resulting
|
|
46362
|
-
* unresolvable ref reads as partial context rather than an error.
|
|
46363
|
-
*
|
|
46364
|
-
* @param namespace The module's `metadata.namespace`, or null when it declares none.
|
|
46365
|
-
* @param moduleName The module's `metadata.name` (e.g. "pipeline", "http-server"). */
|
|
46366
|
-
registerModuleIdentity(namespace, moduleName2) {
|
|
46367
|
-
if (!namespace || moduleName2 === "Telo") return;
|
|
46368
|
-
this.identityMap.set(`${namespace}/${moduleName2}`, moduleName2);
|
|
46369
|
-
}
|
|
46370
|
-
/** Registers a named `Telo.Type` resource's schema under its canonical
|
|
46371
|
-
* module-scoped URI `$id` (`telo://<module>/<name>`), so a sibling schema's
|
|
46372
|
-
* `$ref: "telo://Self/<name>"` (rewritten to the canonical form by
|
|
46373
|
-
* `resolveSchemaTypeRefs`) resolves during AJV compilation. Mirrors the
|
|
46374
|
-
* kernel type controller's `registerSchema(canonicalTypeSchemaId(...))`.
|
|
46375
|
-
*
|
|
46376
|
-
* Returns `false` when a kind schema in the same module already owns the id —
|
|
46377
|
-
* a name collision between a kind and a named type. Definitions register
|
|
46378
|
-
* first, so the type is the one that would be dropped, and every
|
|
46379
|
-
* `$ref: "telo://<module>/<Name>"` would then silently validate against the
|
|
46380
|
-
* kind's schema instead. The caller reports it; nothing is overwritten. */
|
|
46381
|
-
registerNamedTypeSchema(id, schema4) {
|
|
46382
|
-
if (this.definitionSchemaIds.has(id)) return false;
|
|
46383
|
-
if (this.registeredSchemaIds.has(id) || this.ajv.getSchema(id)) return true;
|
|
46384
|
-
if (!this.tryAddSchema(schema4, id)) return true;
|
|
46385
|
-
this.registeredSchemaIds.add(id);
|
|
46386
|
-
return true;
|
|
46387
|
-
}
|
|
46388
|
-
/**
|
|
46389
|
-
* Register a schema, surviving one AJV refuses.
|
|
46390
|
-
*
|
|
46391
|
-
* `addSchema` META-VALIDATES and THROWS, and a throw here escapes the whole
|
|
46392
|
-
* analyze pass: one author schema with `minimum: "3"` in it aborted the run
|
|
46393
|
-
* with AJV's own unanchored text and took every other diagnostic in the file
|
|
46394
|
-
* down with it — including the anchored one that says exactly which keyword is
|
|
46395
|
-
* wrong. Registration is a lookup table for `$ref` resolution, so failing to
|
|
46396
|
-
* fill one entry costs a reference that could not have resolved anyway.
|
|
46397
|
-
*
|
|
46398
|
-
* Nothing is swallowed: an unregisterable schema is invalid, and the two
|
|
46399
|
-
* checks that report it both run afterwards and both anchor on the offending
|
|
46400
|
-
* line — `SCHEMA_VIOLATION` from the `KindSchema` / `JsonSchema7` fragment the
|
|
46401
|
-
* slot points at, and `SCHEMA_COMPILE_ERROR` from {@link schemaCompileError},
|
|
46402
|
-
* which wraps `compile` for this same reason.
|
|
46403
|
-
*/
|
|
46404
|
-
tryAddSchema(schema4, id, trusted = false) {
|
|
46405
|
-
try {
|
|
46406
|
-
this.ajv.addSchema(schemaWithTagsAsText(schema4), id, void 0, !trusted);
|
|
46407
|
-
return true;
|
|
46408
|
-
} catch {
|
|
46409
|
-
return false;
|
|
46410
|
-
}
|
|
46270
|
+
}
|
|
46271
|
+
function withCanonicalRefSentinels(value, ownModule, resolveModule) {
|
|
46272
|
+
const target = refSentinelTarget(value);
|
|
46273
|
+
if (target) {
|
|
46274
|
+
const module = target.alias === void 0 || target.alias === "Self" ? ownModule : resolveModule(target.alias);
|
|
46275
|
+
return module ? { $ref: canonicalTypeSchemaId(module, target.name) } : value;
|
|
46411
46276
|
}
|
|
46412
|
-
|
|
46413
|
-
|
|
46414
|
-
hasSchemaId(id) {
|
|
46415
|
-
return this.registeredSchemaIds.has(id) || this.ajv.getSchema(id) !== void 0;
|
|
46277
|
+
if (Array.isArray(value)) {
|
|
46278
|
+
return value.map((item) => withCanonicalRefSentinels(item, ownModule, resolveModule));
|
|
46416
46279
|
}
|
|
46417
|
-
|
|
46418
|
-
|
|
46419
|
-
|
|
46420
|
-
|
|
46421
|
-
|
|
46422
|
-
|
|
46423
|
-
* compiling a shape the registry holds but cannot compile throws out of
|
|
46424
|
-
* whichever walk asked. That shape's compile failure is reported where the
|
|
46425
|
-
* shape is validated, not here. */
|
|
46426
|
-
schemaForId(id) {
|
|
46427
|
-
let entry = this.ajv.schemas[id] ?? this.ajv.refs[id];
|
|
46428
|
-
while (typeof entry === "string") entry = this.ajv.schemas[entry] ?? this.ajv.refs[entry];
|
|
46429
|
-
const schema4 = entry ? entry.schema : this.ajv.getSchema(id)?.schema;
|
|
46430
|
-
return schema4 && typeof schema4 === "object" ? schema4 : void 0;
|
|
46280
|
+
if (value === null || typeof value !== "object") return value;
|
|
46281
|
+
const prototype = Object.getPrototypeOf(value);
|
|
46282
|
+
if (prototype !== Object.prototype && prototype !== null) return value;
|
|
46283
|
+
const out = {};
|
|
46284
|
+
for (const [key, child] of Object.entries(value)) {
|
|
46285
|
+
out[key] = withCanonicalRefSentinels(child, ownModule, resolveModule);
|
|
46431
46286
|
}
|
|
46432
|
-
|
|
46433
|
-
|
|
46434
|
-
|
|
46435
|
-
|
|
46436
|
-
|
|
46437
|
-
|
|
46438
|
-
* references a shape declared elsewhere is checked rather than skipped. The
|
|
46439
|
-
* module-level instance this used to run on had none of them registered, so
|
|
46440
|
-
* such a schema failed to compile and the failure was swallowed — a resource
|
|
46441
|
-
* could be arbitrarily wrong and `telo check` reported nothing, while the
|
|
46442
|
-
* kernel (whose validator does resolve the reference) rejected it at boot.
|
|
46443
|
-
* Two AJVs answering one question is what made that possible; there is now
|
|
46444
|
-
* one, and it is the same one `schemaCompileError` reports through.
|
|
46445
|
-
*/
|
|
46446
|
-
validateWithRefs(data, schema4) {
|
|
46447
|
-
const validate2 = this.compiledFor(schema4);
|
|
46448
|
-
if (!validate2 || validate2(data)) return [];
|
|
46449
|
-
return reduceSchemaErrors(explainFormatErrors(validate2.errors, data)).map(formatSingleError);
|
|
46287
|
+
return out;
|
|
46288
|
+
}
|
|
46289
|
+
function resolvedRefInSchema(obj) {
|
|
46290
|
+
if (typeof obj.kind !== "string" || typeof obj.name !== "string") return null;
|
|
46291
|
+
for (const key of Object.keys(obj)) {
|
|
46292
|
+
if (key !== "kind" && key !== "name" && key !== "alias" && key !== "$ref") return null;
|
|
46450
46293
|
}
|
|
46451
|
-
|
|
46452
|
-
|
|
46453
|
-
|
|
46454
|
-
|
|
46455
|
-
|
|
46294
|
+
return typeof obj.alias === "string" ? { name: obj.name, alias: obj.alias } : { name: obj.name };
|
|
46295
|
+
}
|
|
46296
|
+
|
|
46297
|
+
// ../../analyzer/nodejs/src/schema-from-sites.ts
|
|
46298
|
+
function schemaFromSites(resource, fieldPath, schemaFrom, ctx) {
|
|
46299
|
+
const out = [];
|
|
46300
|
+
const label2 = `${resource.kind}/${resource.metadata?.name}`;
|
|
46301
|
+
const isAbsolute = schemaFrom.startsWith("/");
|
|
46302
|
+
const expr = isAbsolute ? schemaFrom.slice(1) : schemaFrom;
|
|
46303
|
+
const slashIdx = expr.indexOf("/");
|
|
46304
|
+
if (slashIdx === -1) {
|
|
46305
|
+
out.push({
|
|
46306
|
+
code: "INVALID_SCHEMA_FROM",
|
|
46307
|
+
message: `${label2}: x-telo-schema-from "${schemaFrom}" must contain at least one "/" to separate anchor from JSON Pointer`,
|
|
46308
|
+
path: fieldPath
|
|
46309
|
+
});
|
|
46310
|
+
return out;
|
|
46456
46311
|
}
|
|
46457
|
-
|
|
46458
|
-
|
|
46459
|
-
|
|
46460
|
-
|
|
46461
|
-
|
|
46462
|
-
const
|
|
46463
|
-
|
|
46464
|
-
|
|
46465
|
-
const
|
|
46466
|
-
|
|
46467
|
-
|
|
46468
|
-
|
|
46469
|
-
|
|
46312
|
+
const anchorName = expr.slice(0, slashIdx);
|
|
46313
|
+
const jsonPointer = "/" + expr.slice(slashIdx + 1);
|
|
46314
|
+
if (!isAbsolute && anchorName.includes(".")) {
|
|
46315
|
+
const resolvedResourceKind = ctx.aliases.resolveKind(resource.kind) ?? resource.kind;
|
|
46316
|
+
const resourceDef = ctx.defs.resolve(resource.kind) ?? ctx.defs.resolve(resolvedResourceKind);
|
|
46317
|
+
const ownerScope = moduleAliasScope(resourceDef?.metadata, ctx.aliases, ctx.aliasesByModule);
|
|
46318
|
+
const targetKind = ownerScope.resolveKind(anchorName);
|
|
46319
|
+
if (!targetKind) {
|
|
46320
|
+
const aliasName = anchorName.slice(0, anchorName.indexOf("."));
|
|
46321
|
+
out.push({
|
|
46322
|
+
code: "SCHEMA_FROM_MISSING_PATH",
|
|
46323
|
+
message: `${label2}: x-telo-schema-from at '${fieldPath}' \u2192 cannot resolve alias '${aliasName}' (in '${anchorName}'). Check the import that declares it.`,
|
|
46324
|
+
path: fieldPath
|
|
46325
|
+
});
|
|
46326
|
+
return out;
|
|
46470
46327
|
}
|
|
46471
|
-
|
|
46472
|
-
|
|
46473
|
-
|
|
46474
|
-
|
|
46475
|
-
|
|
46476
|
-
|
|
46477
|
-
|
|
46478
|
-
|
|
46479
|
-
schemaCompileError(schema4) {
|
|
46480
|
-
try {
|
|
46481
|
-
this.ajv.compile(schemaWithTagsAsText(schema4));
|
|
46482
|
-
return void 0;
|
|
46483
|
-
} catch (err) {
|
|
46484
|
-
return err instanceof Error ? err.message : String(err);
|
|
46328
|
+
const targetDef = ctx.defs.resolve(targetKind);
|
|
46329
|
+
if (!targetDef?.schema) {
|
|
46330
|
+
out.push({
|
|
46331
|
+
code: "SCHEMA_FROM_MISSING_PATH",
|
|
46332
|
+
message: `${label2}: x-telo-schema-from at '${fieldPath}' \u2192 kind '${targetKind}' has no schema`,
|
|
46333
|
+
path: fieldPath
|
|
46334
|
+
});
|
|
46335
|
+
return out;
|
|
46485
46336
|
}
|
|
46486
|
-
|
|
46487
|
-
|
|
46488
|
-
|
|
46489
|
-
|
|
46490
|
-
|
|
46491
|
-
|
|
46492
|
-
|
|
46493
|
-
|
|
46494
|
-
if (this.registeredSchemaIds.has(id)) {
|
|
46495
|
-
this.definitionSchemaIds.add(id);
|
|
46496
|
-
return;
|
|
46337
|
+
const subSchema = navigateJsonPointer(targetDef.schema, jsonPointer);
|
|
46338
|
+
if (subSchema === void 0) {
|
|
46339
|
+
out.push({
|
|
46340
|
+
code: "SCHEMA_FROM_MISSING_PATH",
|
|
46341
|
+
message: `${label2}: x-telo-schema-from at '${fieldPath}' \u2192 kind '${targetKind}' has no schema path '${jsonPointer}'`,
|
|
46342
|
+
path: fieldPath
|
|
46343
|
+
});
|
|
46344
|
+
return out;
|
|
46497
46345
|
}
|
|
46498
|
-
|
|
46499
|
-
|
|
46346
|
+
for (const { value, path } of resolveFieldEntries(resource, fieldPath)) {
|
|
46347
|
+
if (value == null) continue;
|
|
46348
|
+
out.push({
|
|
46349
|
+
path,
|
|
46350
|
+
value,
|
|
46351
|
+
schema: subSchema,
|
|
46352
|
+
source: `${anchorName}${jsonPointer}`,
|
|
46353
|
+
form: "anchored"
|
|
46354
|
+
});
|
|
46500
46355
|
}
|
|
46501
|
-
|
|
46502
|
-
this.registeredSchemaIds.add(id);
|
|
46503
|
-
this.definitionSchemaIds.add(id);
|
|
46504
|
-
}
|
|
46505
|
-
/** Resolves an `x-telo-ref` constraint to a canonical registry kind key.
|
|
46506
|
-
*
|
|
46507
|
-
* The constraint is already canonical `<module>.<Kind>`: alias-form values
|
|
46508
|
-
* (`KvStore.Store`, `Self.Store`, `Telo.Invocable`) are rewritten in the
|
|
46509
|
-
* declaring module's scope by `resolveSchemaRefKinds` before registration, so
|
|
46510
|
-
* no module context is needed here.
|
|
46511
|
-
*
|
|
46512
|
-
* The legacy `<namespace>/<module>#<Kind>` form still resolves through the
|
|
46513
|
-
* identity table for module versions published before the alias form existed:
|
|
46514
|
-
*
|
|
46515
|
-
* "telo#Invocable" → "Telo.Invocable"
|
|
46516
|
-
* "std/http-server#Server" → "http-server.Server"
|
|
46517
|
-
*
|
|
46518
|
-
* Returns undefined when a legacy string is malformed or its identity was
|
|
46519
|
-
* never registered. */
|
|
46520
|
-
resolveRef(xTeloRef) {
|
|
46521
|
-
const hash = xTeloRef.indexOf("#");
|
|
46522
|
-
if (hash === -1) return xTeloRef;
|
|
46523
|
-
if (hash === xTeloRef.length - 1) return void 0;
|
|
46524
|
-
const moduleName2 = this.identityMap.get(xTeloRef.slice(0, hash));
|
|
46525
|
-
if (!moduleName2) return void 0;
|
|
46526
|
-
return `${moduleName2}.${xTeloRef.slice(hash + 1)}`;
|
|
46527
|
-
}
|
|
46528
|
-
resolve(kind) {
|
|
46529
|
-
return this.defs.get(kind);
|
|
46530
|
-
}
|
|
46531
|
-
/**
|
|
46532
|
-
* The kind's AUTHOR-FACING schema — its own merged with everything it
|
|
46533
|
-
* inherits along `extends` — memoized per kind.
|
|
46534
|
-
*
|
|
46535
|
-
* This is what every consumer reading a kind's schema to interpret an
|
|
46536
|
-
* INSTANCE must use, because that is the schema the instance was authored
|
|
46537
|
-
* against and the one the kernel stamps at definition registration. Reading
|
|
46538
|
-
* `resolve(kind).schema` instead sees only what the leaf declared, so an
|
|
46539
|
-
* annotation on a parent — a CEL context region, a step body, an error
|
|
46540
|
-
* context — is invisible on every child, silently and per consumer. Sharing
|
|
46541
|
-
* one memo is what keeps those consumers from drifting apart.
|
|
46542
|
-
*
|
|
46543
|
-
* Lazy for the same reason `getFieldMap` is: a child registered before its
|
|
46544
|
-
* parent still sees the inherited half once both are present.
|
|
46545
|
-
*/
|
|
46546
|
-
effectiveSchema(kind) {
|
|
46547
|
-
const cached = this.effectiveSchemas.get(kind);
|
|
46548
|
-
if (cached !== void 0) return cached ?? void 0;
|
|
46549
|
-
const def = this.defs.get(kind);
|
|
46550
|
-
if (!def) return void 0;
|
|
46551
|
-
const schema4 = effectiveAuthorSchema(def, (k) => this.resolve(k));
|
|
46552
|
-
this.effectiveSchemas.set(kind, schema4 ?? null);
|
|
46553
|
-
return schema4;
|
|
46554
|
-
}
|
|
46555
|
-
/** The effective schema for a definition, by the kind it is registered under.
|
|
46556
|
-
* Falls back to the definition's own schema when it is not in this registry
|
|
46557
|
-
* (a synthesized or not-yet-registered kind), which is the pre-inheritance
|
|
46558
|
-
* behaviour and the safe direction: it types less, never wrongly. */
|
|
46559
|
-
effectiveSchemaOf(definition) {
|
|
46560
|
-
if (!definition) return void 0;
|
|
46561
|
-
const { name, module: mod } = definition.metadata;
|
|
46562
|
-
const resolved = this.effectiveSchema(mod ? `${mod}.${name}` : name);
|
|
46563
|
-
return resolved ?? definition.schema;
|
|
46564
|
-
}
|
|
46565
|
-
/** Returns the reference field map for the given kind, computed lazily from the
|
|
46566
|
-
* kind's AUTHOR-FACING (inheritance-resolved) schema and memoized. Lazy so a
|
|
46567
|
-
* child registered before its parent still sees the parent's inherited ref
|
|
46568
|
-
* slots once both are present. */
|
|
46569
|
-
getFieldMap(kind) {
|
|
46570
|
-
const cached = this.fieldMaps.get(kind);
|
|
46571
|
-
if (cached) return cached;
|
|
46572
|
-
const def = this.defs.get(kind);
|
|
46573
|
-
if (!def) return void 0;
|
|
46574
|
-
const schema4 = effectiveAuthorSchema(def, (k) => this.resolve(k));
|
|
46575
|
-
const map3 = buildReferenceFieldMap(schema4 ?? {});
|
|
46576
|
-
this.fieldMaps.set(kind, map3);
|
|
46577
|
-
return map3;
|
|
46578
|
-
}
|
|
46579
|
-
/** Returns the field map for `kind`, falling back to the alias-resolved kind when not found. */
|
|
46580
|
-
getFieldMapForKind(kind, aliases) {
|
|
46581
|
-
const fm = this.getFieldMap(kind);
|
|
46582
|
-
if (fm) return fm;
|
|
46583
|
-
const resolved = aliases?.resolveKind(kind);
|
|
46584
|
-
return resolved ? this.getFieldMap(resolved) : void 0;
|
|
46585
|
-
}
|
|
46586
|
-
/** Returns the field map for `resource.kind` with x-telo-schema-from entries replaced
|
|
46587
|
-
* by their nested ref/scope slots — so Phase 2 inline normalization and Phase 5
|
|
46588
|
-
* injection see encoders nested behind a schema-from indirection (e.g.
|
|
46589
|
-
* http-server `Server.notFoundHandler.returns[].content[mime].encoder`).
|
|
46590
|
-
*
|
|
46591
|
-
* Only static absolute schema-from paths with a dotted alias anchor are expanded
|
|
46592
|
-
* (e.g. "HttpDispatch.Outcomes/$defs/Returns"). Relative and unqualified absolute
|
|
46593
|
-
* anchors depend on a sibling property at runtime and stay unexpanded; the
|
|
46594
|
-
* analyzer's reference validation phase already flags the cases that matter. */
|
|
46595
|
-
expandedFieldMapForResource(resource, aliases, aliasesByModule) {
|
|
46596
|
-
const moduleScope = moduleAliasScope(resource.metadata, aliases, aliasesByModule);
|
|
46597
|
-
const baseMap = this.getFieldMapForKind(resource.kind, moduleScope);
|
|
46598
|
-
if (!baseMap) return void 0;
|
|
46599
|
-
const resolvedKind = moduleScope.resolveKind(resource.kind) ?? resource.kind;
|
|
46600
|
-
const def = this.resolve(resource.kind) ?? this.resolve(resolvedKind);
|
|
46601
|
-
const ownerScope = moduleAliasScope(def?.metadata, aliases, aliasesByModule);
|
|
46602
|
-
const expanded = /* @__PURE__ */ new Map();
|
|
46603
|
-
for (const [path, entry] of baseMap) {
|
|
46604
|
-
if (!isSchemaFromEntry(entry)) {
|
|
46605
|
-
expanded.set(path, entry);
|
|
46606
|
-
continue;
|
|
46607
|
-
}
|
|
46608
|
-
const sub = this.resolveSchemaFromSubMap(entry.schemaFrom, path, ownerScope);
|
|
46609
|
-
if (!sub) continue;
|
|
46610
|
-
for (const [subPath, subEntry] of sub) expanded.set(subPath, subEntry);
|
|
46611
|
-
}
|
|
46612
|
-
return expanded;
|
|
46613
|
-
}
|
|
46614
|
-
/**
|
|
46615
|
-
* The schema an `x-telo-schema-from` slot derives its shape from.
|
|
46616
|
-
*
|
|
46617
|
-
* Only the STATIC form resolves: an anchor that is a dotted alias-qualified
|
|
46618
|
-
* kind (`HttpDispatch.Request/$defs/Matcher`). The polymorphic forms — a
|
|
46619
|
-
* relative anchor, or a single-segment absolute one — name a sibling property
|
|
46620
|
-
* whose value is known per resource, so a definition-level lookup would be
|
|
46621
|
-
* guessing at one instance's shape.
|
|
46622
|
-
*
|
|
46623
|
-
* Its own method because a schema-from slot is otherwise INVISIBLE to anything
|
|
46624
|
-
* reading `properties`: the field map needs the nested ref slots, and an IDE
|
|
46625
|
-
* needs the very same node to offer a key or describe one. Two resolutions of
|
|
46626
|
-
* one annotation would eventually disagree about which anchors are static.
|
|
46627
|
-
*/
|
|
46628
|
-
resolveSchemaFromNode(schemaFrom, ownerScope) {
|
|
46629
|
-
const isAbsolute = schemaFrom.startsWith("/");
|
|
46630
|
-
const expr = isAbsolute ? schemaFrom.slice(1) : schemaFrom;
|
|
46631
|
-
const slashIdx = expr.indexOf("/");
|
|
46632
|
-
if (slashIdx === -1) return void 0;
|
|
46633
|
-
const anchorName = expr.slice(0, slashIdx);
|
|
46634
|
-
const jsonPointer = "/" + expr.slice(slashIdx + 1);
|
|
46635
|
-
if (!anchorName.includes(".")) return void 0;
|
|
46636
|
-
const targetKind = ownerScope.resolveKind(anchorName);
|
|
46637
|
-
if (!targetKind) return void 0;
|
|
46638
|
-
const targetDef = this.resolve(targetKind);
|
|
46639
|
-
if (!targetDef?.schema) return void 0;
|
|
46640
|
-
const subSchema = navigateJsonPointer(
|
|
46641
|
-
targetDef.schema,
|
|
46642
|
-
jsonPointer
|
|
46643
|
-
);
|
|
46644
|
-
if (!subSchema || typeof subSchema !== "object") return void 0;
|
|
46645
|
-
return subSchema;
|
|
46646
|
-
}
|
|
46647
|
-
resolveSchemaFromSubMap(schemaFrom, fieldPath, ownerScope) {
|
|
46648
|
-
const subSchema = this.resolveSchemaFromNode(schemaFrom, ownerScope);
|
|
46649
|
-
if (!subSchema) return null;
|
|
46650
|
-
return buildFieldMapAtPath(subSchema, fieldPath);
|
|
46651
|
-
}
|
|
46652
|
-
/** The kinds a definition descends from DIRECTLY — the same two edges
|
|
46653
|
-
* `register` feeds into `extendedBy`, read the other way.
|
|
46654
|
-
*
|
|
46655
|
-
* Both spellings, because either can carry the edge that satisfies a slot:
|
|
46656
|
-
* `capability:` is the legacy implements-this form, `extends:` the canonical
|
|
46657
|
-
* one. A consumer walking these by hand would be a second reading of what an
|
|
46658
|
-
* inheritance edge IS, and the downward index and the upward walk have to
|
|
46659
|
-
* agree about that forever. */
|
|
46660
|
-
parentsOf(kind) {
|
|
46661
|
-
const def = this.defs.get(kind);
|
|
46662
|
-
if (!def) return [];
|
|
46663
|
-
return [def.capability, def.extends].filter(
|
|
46664
|
-
(parent) => typeof parent === "string" && parent.length > 0
|
|
46665
|
-
);
|
|
46666
|
-
}
|
|
46667
|
-
/** Whether every kind this one descends from is registered.
|
|
46668
|
-
*
|
|
46669
|
-
* When it is, what the kind implements is FULLY KNOWN: a target it does not
|
|
46670
|
-
* reach is one it genuinely does not implement, so a mismatch is a verdict.
|
|
46671
|
-
* When a hop is missing — an unimported abstract, an alias the declaring file
|
|
46672
|
-
* could not resolve — a mismatch cannot be told from a missing dependency,
|
|
46673
|
-
* which is the partial context every reference check stays lenient in. */
|
|
46674
|
-
ancestryResolved(kind) {
|
|
46675
|
-
const queue = [kind];
|
|
46676
|
-
const seen = /* @__PURE__ */ new Set();
|
|
46677
|
-
while (queue.length > 0) {
|
|
46678
|
-
const current = queue.shift();
|
|
46679
|
-
if (seen.has(current)) continue;
|
|
46680
|
-
seen.add(current);
|
|
46681
|
-
if (!this.defs.has(current)) return false;
|
|
46682
|
-
queue.push(...this.parentsOf(current));
|
|
46683
|
-
}
|
|
46684
|
-
return true;
|
|
46685
|
-
}
|
|
46686
|
-
/** Returns all definitions that transitively extend the given abstract kind.
|
|
46687
|
-
* Follows the capability chain to any depth (equivalent to instanceof in OOP).
|
|
46688
|
-
* Definitions are included regardless of registration order. */
|
|
46689
|
-
getByExtends(abstractKind) {
|
|
46690
|
-
const result = [];
|
|
46691
|
-
const queue = [abstractKind];
|
|
46692
|
-
while (queue.length > 0) {
|
|
46693
|
-
const parent = queue.shift();
|
|
46694
|
-
const children = this.extendedBy.get(parent);
|
|
46695
|
-
if (!children) continue;
|
|
46696
|
-
for (const child of children) {
|
|
46697
|
-
const def = this.defs.get(child);
|
|
46698
|
-
if (def) result.push(def);
|
|
46699
|
-
queue.push(child);
|
|
46700
|
-
}
|
|
46701
|
-
}
|
|
46702
|
-
return result;
|
|
46703
|
-
}
|
|
46704
|
-
kinds() {
|
|
46705
|
-
return Array.from(this.defs.keys());
|
|
46706
|
-
}
|
|
46707
|
-
};
|
|
46708
|
-
|
|
46709
|
-
// ../../analyzer/nodejs/src/resolve-schema-type-refs.ts
|
|
46710
|
-
var SCHEMA_FIELDS = ["schema", "inputType", "outputType"];
|
|
46711
|
-
var SIGNATURE_FIELDS = ["params", "returns"];
|
|
46712
|
-
function resolveSchemaTypeRefs(resources, aliases, aliasesByModule) {
|
|
46713
|
-
const walk4 = (value, resolveAuthority, ownModule, isSlotRoot) => {
|
|
46714
|
-
if (value === null || typeof value !== "object") return;
|
|
46715
|
-
if (Array.isArray(value)) {
|
|
46716
|
-
for (const item of value) walk4(item, resolveAuthority, ownModule, false);
|
|
46717
|
-
return;
|
|
46718
|
-
}
|
|
46719
|
-
const obj = value;
|
|
46720
|
-
const parsed = parseTeloTypeRef(obj.$ref);
|
|
46721
|
-
if (parsed) {
|
|
46722
|
-
const module = resolveAuthority(parsed.authority);
|
|
46723
|
-
if (module) obj.$ref = canonicalTypeSchemaId(module, parsed.typeName);
|
|
46724
|
-
}
|
|
46725
|
-
const named = resolvedRefInSchema(obj);
|
|
46726
|
-
if (named) {
|
|
46727
|
-
const module = named.alias === void 0 ? ownModule : resolveAuthority(named.alias);
|
|
46728
|
-
if (module) {
|
|
46729
|
-
const canonical = canonicalTypeSchemaId(module, named.name);
|
|
46730
|
-
if (isSlotRoot) {
|
|
46731
|
-
obj.$ref = canonical;
|
|
46732
|
-
} else {
|
|
46733
|
-
delete obj.kind;
|
|
46734
|
-
delete obj.name;
|
|
46735
|
-
delete obj.alias;
|
|
46736
|
-
obj.$ref = canonical;
|
|
46737
|
-
}
|
|
46738
|
-
}
|
|
46739
|
-
}
|
|
46740
|
-
for (const key of Object.keys(obj)) walk4(obj[key], resolveAuthority, ownModule, false);
|
|
46741
|
-
};
|
|
46742
|
-
for (const r of resources) {
|
|
46743
|
-
const ownModule = r.metadata?.module;
|
|
46744
|
-
const resolver = moduleAliasScope(r.metadata, aliases, aliasesByModule);
|
|
46745
|
-
const resolveAuthority = (authority) => authority === "Self" ? ownModule : resolver?.moduleForAlias(authority);
|
|
46746
|
-
for (const field of SCHEMA_FIELDS) {
|
|
46747
|
-
walk4(r[field], resolveAuthority, ownModule, true);
|
|
46748
|
-
}
|
|
46749
|
-
for (const field of SIGNATURE_FIELDS) {
|
|
46750
|
-
walk4(r[field], resolveAuthority, ownModule, false);
|
|
46751
|
-
}
|
|
46752
|
-
}
|
|
46753
|
-
}
|
|
46754
|
-
function withCanonicalRefSentinels(value, ownModule, resolveModule) {
|
|
46755
|
-
const target = refSentinelTarget(value);
|
|
46756
|
-
if (target) {
|
|
46757
|
-
const module = target.alias === void 0 || target.alias === "Self" ? ownModule : resolveModule(target.alias);
|
|
46758
|
-
return module ? { $ref: canonicalTypeSchemaId(module, target.name) } : value;
|
|
46759
|
-
}
|
|
46760
|
-
if (Array.isArray(value)) {
|
|
46761
|
-
return value.map((item) => withCanonicalRefSentinels(item, ownModule, resolveModule));
|
|
46762
|
-
}
|
|
46763
|
-
if (value === null || typeof value !== "object") return value;
|
|
46764
|
-
const prototype = Object.getPrototypeOf(value);
|
|
46765
|
-
if (prototype !== Object.prototype && prototype !== null) return value;
|
|
46766
|
-
const out = {};
|
|
46767
|
-
for (const [key, child] of Object.entries(value)) {
|
|
46768
|
-
out[key] = withCanonicalRefSentinels(child, ownModule, resolveModule);
|
|
46769
|
-
}
|
|
46770
|
-
return out;
|
|
46771
|
-
}
|
|
46772
|
-
function resolvedRefInSchema(obj) {
|
|
46773
|
-
if (typeof obj.kind !== "string" || typeof obj.name !== "string") return null;
|
|
46774
|
-
for (const key of Object.keys(obj)) {
|
|
46775
|
-
if (key !== "kind" && key !== "name" && key !== "alias" && key !== "$ref") return null;
|
|
46776
|
-
}
|
|
46777
|
-
return typeof obj.alias === "string" ? { name: obj.name, alias: obj.alias } : { name: obj.name };
|
|
46778
|
-
}
|
|
46779
|
-
|
|
46780
|
-
// ../../analyzer/nodejs/src/schema-from-sites.ts
|
|
46781
|
-
function schemaFromSites(resource, fieldPath, schemaFrom, ctx) {
|
|
46782
|
-
const out = [];
|
|
46783
|
-
const label2 = `${resource.kind}/${resource.metadata?.name}`;
|
|
46784
|
-
const isAbsolute = schemaFrom.startsWith("/");
|
|
46785
|
-
const expr = isAbsolute ? schemaFrom.slice(1) : schemaFrom;
|
|
46786
|
-
const slashIdx = expr.indexOf("/");
|
|
46787
|
-
if (slashIdx === -1) {
|
|
46788
|
-
out.push({
|
|
46789
|
-
code: "INVALID_SCHEMA_FROM",
|
|
46790
|
-
message: `${label2}: x-telo-schema-from "${schemaFrom}" must contain at least one "/" to separate anchor from JSON Pointer`,
|
|
46791
|
-
path: fieldPath
|
|
46792
|
-
});
|
|
46793
|
-
return out;
|
|
46794
|
-
}
|
|
46795
|
-
const anchorName = expr.slice(0, slashIdx);
|
|
46796
|
-
const jsonPointer = "/" + expr.slice(slashIdx + 1);
|
|
46797
|
-
if (!isAbsolute && anchorName.includes(".")) {
|
|
46798
|
-
const resolvedResourceKind = ctx.aliases.resolveKind(resource.kind) ?? resource.kind;
|
|
46799
|
-
const resourceDef = ctx.defs.resolve(resource.kind) ?? ctx.defs.resolve(resolvedResourceKind);
|
|
46800
|
-
const ownerScope = moduleAliasScope(resourceDef?.metadata, ctx.aliases, ctx.aliasesByModule);
|
|
46801
|
-
const targetKind = ownerScope.resolveKind(anchorName);
|
|
46802
|
-
if (!targetKind) {
|
|
46803
|
-
const aliasName = anchorName.slice(0, anchorName.indexOf("."));
|
|
46804
|
-
out.push({
|
|
46805
|
-
code: "SCHEMA_FROM_MISSING_PATH",
|
|
46806
|
-
message: `${label2}: x-telo-schema-from at '${fieldPath}' \u2192 cannot resolve alias '${aliasName}' (in '${anchorName}'). Check the import that declares it.`,
|
|
46807
|
-
path: fieldPath
|
|
46808
|
-
});
|
|
46809
|
-
return out;
|
|
46810
|
-
}
|
|
46811
|
-
const targetDef = ctx.defs.resolve(targetKind);
|
|
46812
|
-
if (!targetDef?.schema) {
|
|
46813
|
-
out.push({
|
|
46814
|
-
code: "SCHEMA_FROM_MISSING_PATH",
|
|
46815
|
-
message: `${label2}: x-telo-schema-from at '${fieldPath}' \u2192 kind '${targetKind}' has no schema`,
|
|
46816
|
-
path: fieldPath
|
|
46817
|
-
});
|
|
46818
|
-
return out;
|
|
46819
|
-
}
|
|
46820
|
-
const subSchema = navigateJsonPointer(targetDef.schema, jsonPointer);
|
|
46821
|
-
if (subSchema === void 0) {
|
|
46822
|
-
out.push({
|
|
46823
|
-
code: "SCHEMA_FROM_MISSING_PATH",
|
|
46824
|
-
message: `${label2}: x-telo-schema-from at '${fieldPath}' \u2192 kind '${targetKind}' has no schema path '${jsonPointer}'`,
|
|
46825
|
-
path: fieldPath
|
|
46826
|
-
});
|
|
46827
|
-
return out;
|
|
46828
|
-
}
|
|
46829
|
-
for (const { value, path } of resolveFieldEntries(resource, fieldPath)) {
|
|
46830
|
-
if (value == null) continue;
|
|
46831
|
-
out.push({
|
|
46832
|
-
path,
|
|
46833
|
-
value,
|
|
46834
|
-
schema: subSchema,
|
|
46835
|
-
source: `${anchorName}${jsonPointer}`,
|
|
46836
|
-
form: "anchored"
|
|
46837
|
-
});
|
|
46838
|
-
}
|
|
46839
|
-
return out;
|
|
46356
|
+
return out;
|
|
46840
46357
|
}
|
|
46841
46358
|
let anchorPath;
|
|
46842
46359
|
if (isAbsolute) {
|
|
@@ -46958,132 +46475,913 @@ function stepCallSites(manifest, defSchema, ctx) {
|
|
|
46958
46475
|
);
|
|
46959
46476
|
});
|
|
46960
46477
|
}
|
|
46961
|
-
return out;
|
|
46962
|
-
}
|
|
46963
|
-
function slotCallSites(manifest, fieldMap, ctx) {
|
|
46964
|
-
const out = [];
|
|
46965
|
-
if (!fieldMap) return out;
|
|
46966
|
-
for (const [fieldPath, entry] of fieldMap) {
|
|
46967
|
-
if (!isRefEntry(entry) || !entry.inputs) continue;
|
|
46968
|
-
const pointer = pointerSegments(entry.inputs);
|
|
46969
|
-
if (!pointer) continue;
|
|
46970
|
-
for (const { value: invoke, path: slotPath } of resolveFieldEntries(manifest, fieldPath)) {
|
|
46971
|
-
if (!invoke || typeof invoke !== "object" || Array.isArray(invoke)) continue;
|
|
46972
|
-
const enclosing = slotPath.slice(0, Math.max(0, slotPath.lastIndexOf(".")));
|
|
46973
|
-
const inputsPath = [enclosing, ...pointer].filter(Boolean).join(".");
|
|
46974
|
-
const values = navigateConcretePath2(manifest, inputsPath);
|
|
46975
|
-
if (!values || typeof values !== "object" || Array.isArray(values)) continue;
|
|
46976
|
-
out.push(
|
|
46977
|
-
callSite("slot", inputsPath, values, invoke, manifest, ctx)
|
|
46978
|
-
);
|
|
46979
|
-
}
|
|
46478
|
+
return out;
|
|
46479
|
+
}
|
|
46480
|
+
function slotCallSites(manifest, fieldMap, ctx) {
|
|
46481
|
+
const out = [];
|
|
46482
|
+
if (!fieldMap) return out;
|
|
46483
|
+
for (const [fieldPath, entry] of fieldMap) {
|
|
46484
|
+
if (!isRefEntry(entry) || !entry.inputs) continue;
|
|
46485
|
+
const pointer = pointerSegments(entry.inputs);
|
|
46486
|
+
if (!pointer) continue;
|
|
46487
|
+
for (const { value: invoke, path: slotPath } of resolveFieldEntries(manifest, fieldPath)) {
|
|
46488
|
+
if (!invoke || typeof invoke !== "object" || Array.isArray(invoke)) continue;
|
|
46489
|
+
const enclosing = slotPath.slice(0, Math.max(0, slotPath.lastIndexOf(".")));
|
|
46490
|
+
const inputsPath = [enclosing, ...pointer].filter(Boolean).join(".");
|
|
46491
|
+
const values = navigateConcretePath2(manifest, inputsPath);
|
|
46492
|
+
if (!values || typeof values !== "object" || Array.isArray(values)) continue;
|
|
46493
|
+
out.push(
|
|
46494
|
+
callSite("slot", inputsPath, values, invoke, manifest, ctx)
|
|
46495
|
+
);
|
|
46496
|
+
}
|
|
46497
|
+
}
|
|
46498
|
+
return out;
|
|
46499
|
+
}
|
|
46500
|
+
function pointerSegments(pointer) {
|
|
46501
|
+
if (!pointer.startsWith("/")) return void 0;
|
|
46502
|
+
const segments = pointer.slice(1).split("/").map((s) => s.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
46503
|
+
return segments.every((s) => s.length > 0 && !/^\d+$/.test(s)) ? segments : void 0;
|
|
46504
|
+
}
|
|
46505
|
+
function templateCallSite(manifest, ctx) {
|
|
46506
|
+
if (manifest.kind !== "Telo.Definition") return void 0;
|
|
46507
|
+
const values = manifest.inputs;
|
|
46508
|
+
if (!values || typeof values !== "object" || Array.isArray(values)) return void 0;
|
|
46509
|
+
const scope = contractScopeOf(ctx);
|
|
46510
|
+
const module = manifest.metadata?.module;
|
|
46511
|
+
for (const slot of ["invoke", "provide"]) {
|
|
46512
|
+
const target = dispatchTargetOf(manifest, slot);
|
|
46513
|
+
if (!target) continue;
|
|
46514
|
+
const definition2 = scope.resolveIn(target.kind, module);
|
|
46515
|
+
const aliases = moduleAliasScope(manifest.metadata, ctx.aliases, ctx.aliasesByModule);
|
|
46516
|
+
const entry = target.entry && {
|
|
46517
|
+
...target.entry,
|
|
46518
|
+
inputType: withCanonicalRefSentinels(
|
|
46519
|
+
target.entry.inputType,
|
|
46520
|
+
module,
|
|
46521
|
+
(alias) => aliases?.moduleForAlias(alias)
|
|
46522
|
+
)
|
|
46523
|
+
};
|
|
46524
|
+
return {
|
|
46525
|
+
origin: "template",
|
|
46526
|
+
path: "inputs",
|
|
46527
|
+
values,
|
|
46528
|
+
invoke: { kind: target.kind, name: target.name },
|
|
46529
|
+
invokedManifest: entry,
|
|
46530
|
+
invokedDefinition: definition2,
|
|
46531
|
+
contract: resolveContract("inputType", entry, definition2, scope)
|
|
46532
|
+
};
|
|
46533
|
+
}
|
|
46534
|
+
const dispatch = [manifest.invoke, manifest.provide].find(
|
|
46535
|
+
(d) => d && typeof d === "object" && !Array.isArray(d) && typeof d.kind === "string"
|
|
46536
|
+
);
|
|
46537
|
+
if (!dispatch) return void 0;
|
|
46538
|
+
const definition = scope.resolveIn(dispatch.kind, module);
|
|
46539
|
+
return {
|
|
46540
|
+
origin: "template",
|
|
46541
|
+
path: "inputs",
|
|
46542
|
+
values,
|
|
46543
|
+
invoke: { kind: dispatch.kind },
|
|
46544
|
+
invokedManifest: void 0,
|
|
46545
|
+
invokedDefinition: definition,
|
|
46546
|
+
contract: resolveContract("inputType", void 0, definition, scope)
|
|
46547
|
+
};
|
|
46548
|
+
}
|
|
46549
|
+
function valueSchemaSites(manifest, defSchema, ctx) {
|
|
46550
|
+
if (!defSchema) return [];
|
|
46551
|
+
const out = [];
|
|
46552
|
+
for (const { scope, from } of valueSchemaSlots(defSchema)) {
|
|
46553
|
+
const schema4 = resolveTypeFieldToSchema(manifest[from], ctx.typeManifests);
|
|
46554
|
+
if (!schema4 || typeof schema4 !== "object") continue;
|
|
46555
|
+
for (const { path, value } of resolveScopeValues(manifest, scope)) {
|
|
46556
|
+
out.push({ path, value, schema: schema4, from });
|
|
46557
|
+
}
|
|
46558
|
+
}
|
|
46559
|
+
return out;
|
|
46560
|
+
}
|
|
46561
|
+
function derivedSlotsOf(resource, ctx) {
|
|
46562
|
+
const manifest = resource;
|
|
46563
|
+
const moduleScope = moduleAliasScope(resource.metadata, ctx.aliases, ctx.aliasesByModule);
|
|
46564
|
+
const resolvedKind = moduleScope.resolveKind(resource.kind);
|
|
46565
|
+
const definition = ctx.defs.resolve(resource.kind) ?? (resolvedKind ? ctx.defs.resolve(resolvedKind) : void 0);
|
|
46566
|
+
const schema4 = ctx.defs.effectiveSchemaOf(definition);
|
|
46567
|
+
const out = [];
|
|
46568
|
+
const at2 = (path, value, schema5) => out.push({ path, value, schema: schema5, replace: (next) => assignConcretePath(manifest, path, next) });
|
|
46569
|
+
const calls = [
|
|
46570
|
+
...schema4 ? stepCallSites(manifest, schema4, ctx) : [],
|
|
46571
|
+
...slotCallSites(
|
|
46572
|
+
manifest,
|
|
46573
|
+
ctx.defs.expandedFieldMapForResource(resource, ctx.aliases, ctx.aliasesByModule),
|
|
46574
|
+
ctx
|
|
46575
|
+
)
|
|
46576
|
+
];
|
|
46577
|
+
const template = templateCallSite(manifest, ctx);
|
|
46578
|
+
if (template) calls.push(template);
|
|
46579
|
+
for (const call of calls) {
|
|
46580
|
+
if (call.contract) at2(call.path, call.values, call.contract.schema);
|
|
46581
|
+
}
|
|
46582
|
+
for (const site of valueSchemaSites(manifest, schema4, ctx)) {
|
|
46583
|
+
at2(site.path, site.value, site.schema);
|
|
46584
|
+
}
|
|
46585
|
+
visitManifest(
|
|
46586
|
+
[resource],
|
|
46587
|
+
ctx.defs,
|
|
46588
|
+
{
|
|
46589
|
+
onSchemaFrom: (e) => {
|
|
46590
|
+
for (const site of schemaFromSites(manifest, e.fieldPath, e.entry.schemaFrom, ctx)) {
|
|
46591
|
+
if (isSchemaFromSite(site)) at2(site.path, site.value, site.schema);
|
|
46592
|
+
}
|
|
46593
|
+
}
|
|
46594
|
+
},
|
|
46595
|
+
{
|
|
46596
|
+
aliases: ctx.aliases,
|
|
46597
|
+
aliasesByModule: ctx.aliasesByModule,
|
|
46598
|
+
skipKinds: REF_VALIDATION_SKIP_KINDS,
|
|
46599
|
+
expand: false
|
|
46600
|
+
}
|
|
46601
|
+
);
|
|
46602
|
+
return out;
|
|
46603
|
+
}
|
|
46604
|
+
|
|
46605
|
+
// ../../analyzer/nodejs/src/validate-step-inputs.ts
|
|
46606
|
+
var missingRequired = (issue) => /is missing required property/.test(issue.message);
|
|
46607
|
+
function containerOf(path) {
|
|
46608
|
+
const dot = path.lastIndexOf(".");
|
|
46609
|
+
return dot === -1 ? "" : path.slice(0, dot);
|
|
46610
|
+
}
|
|
46611
|
+
var declarationsByName = /* @__PURE__ */ new WeakMap();
|
|
46612
|
+
function byNameOf(allManifests) {
|
|
46613
|
+
let byName = declarationsByName.get(allManifests);
|
|
46614
|
+
if (!byName) {
|
|
46615
|
+
byName = /* @__PURE__ */ new Map();
|
|
46616
|
+
for (const m of allManifests) {
|
|
46617
|
+
const name = m.metadata?.name;
|
|
46618
|
+
if (typeof name !== "string" || m.kind === "Telo.Import") continue;
|
|
46619
|
+
const list2 = byName.get(name);
|
|
46620
|
+
if (list2) list2.push(m);
|
|
46621
|
+
else byName.set(name, [m]);
|
|
46622
|
+
}
|
|
46623
|
+
declarationsByName.set(allManifests, byName);
|
|
46624
|
+
}
|
|
46625
|
+
return byName;
|
|
46626
|
+
}
|
|
46627
|
+
function callSiteContext(manifest, allManifests, defs, aliases, scopes) {
|
|
46628
|
+
const fromModule = manifest.metadata?.module;
|
|
46629
|
+
const scope = moduleAliasScope({ module: fromModule }, aliases, scopes.aliasesByModule);
|
|
46630
|
+
return {
|
|
46631
|
+
defs,
|
|
46632
|
+
aliases,
|
|
46633
|
+
aliasesByModule: scopes.aliasesByModule,
|
|
46634
|
+
rootModules: scopes.rootModules,
|
|
46635
|
+
typeManifests: allManifests,
|
|
46636
|
+
resolveTarget: (ref) => typeof ref.name === "string" ? resolveReferenceTarget(
|
|
46637
|
+
byNameOf(allManifests),
|
|
46638
|
+
{ name: ref.name, ...typeof ref.alias === "string" ? { alias: ref.alias } : {} },
|
|
46639
|
+
fromModule,
|
|
46640
|
+
(alias) => scope.moduleForAlias(alias)
|
|
46641
|
+
) : void 0
|
|
46642
|
+
};
|
|
46643
|
+
}
|
|
46644
|
+
function collectStepInputIssues(manifest, defSchema, allManifests, defs, aliases, scopes, stepContext) {
|
|
46645
|
+
const ctx = callSiteContext(manifest, allManifests, defs, aliases, scopes);
|
|
46646
|
+
return stepCallSites(manifest, defSchema, ctx).flatMap(
|
|
46647
|
+
(site) => checkCallSite(site, manifest, allManifests, defs, aliases, scopes, stepContext)
|
|
46648
|
+
);
|
|
46649
|
+
}
|
|
46650
|
+
function collectRefInputIssues(manifest, fieldMap, allManifests, defs, aliases, scopes) {
|
|
46651
|
+
const ctx = callSiteContext(manifest, allManifests, defs, aliases, scopes);
|
|
46652
|
+
return slotCallSites(manifest, fieldMap, ctx).flatMap(
|
|
46653
|
+
(site) => checkCallSite(site, manifest, allManifests, defs, aliases, scopes)
|
|
46654
|
+
);
|
|
46655
|
+
}
|
|
46656
|
+
function checkCallSite(site, manifest, allManifests, defs, aliases, scopes, stepContext) {
|
|
46657
|
+
const out = [];
|
|
46658
|
+
const { contract, values, invoke, invokedManifest, invokedDefinition } = site;
|
|
46659
|
+
if (!contract) return out;
|
|
46660
|
+
const targetLabel2 = invoke.name ?? invoke.kind ?? "the invoked resource";
|
|
46661
|
+
const contractScope = analyzerContractScope(defs, aliases, scopes, allManifests);
|
|
46662
|
+
const readingModule = manifest.metadata?.module;
|
|
46663
|
+
const celPaths = /* @__PURE__ */ new Set();
|
|
46664
|
+
const substituted = substituteDecodedCelFields(values, contract.schema, void 0, {
|
|
46665
|
+
onSubstitute: (p) => celPaths.add(p),
|
|
46666
|
+
// A contract may name a shape declared elsewhere. Both halves need the
|
|
46667
|
+
// resolver or they disagree about the same slot.
|
|
46668
|
+
external: (ref) => defs.schemaForId(ref)
|
|
46669
|
+
});
|
|
46670
|
+
const roots = [];
|
|
46671
|
+
if (stepContext) roots.push(["steps.", stepContext]);
|
|
46672
|
+
const ownContract = resolveContract(
|
|
46673
|
+
"inputType",
|
|
46674
|
+
manifest,
|
|
46675
|
+
contractScope.resolveIn(manifest.kind, readingModule),
|
|
46676
|
+
contractScope
|
|
46677
|
+
);
|
|
46678
|
+
if (ownContract) roots.push(["inputs.", ownContract.schema]);
|
|
46679
|
+
if (roots.length > 0) {
|
|
46680
|
+
for (const [inputName, inputValue] of Object.entries(values)) {
|
|
46681
|
+
const chain = plainChainOf(inputValue);
|
|
46682
|
+
const root = chain ? roots.find(([prefix]) => chain.startsWith(prefix)) : void 0;
|
|
46683
|
+
if (!chain || !root) continue;
|
|
46684
|
+
const produced = navigateSchemaToExprPath(root[1], chain.slice(root[0].length));
|
|
46685
|
+
const slotSchema = contract.schema.properties?.[inputName];
|
|
46686
|
+
if (!produced || !slotSchema) continue;
|
|
46687
|
+
if (isLiveSlot(produced)) {
|
|
46688
|
+
const retry = site.step ? declaredRetry(site.step.value, site.step.schema, invokedManifest, invokedDefinition) : void 0;
|
|
46689
|
+
if (retry !== void 0) {
|
|
46690
|
+
out.push({
|
|
46691
|
+
path: `${site.path}.${inputName}`,
|
|
46692
|
+
targetLabel: targetLabel2,
|
|
46693
|
+
message: `'${inputName}' is a live value, which is consumed by reading and so exists once \u2014 but ${retry} re-attempts the dispatch, and a re-attempt would pass nothing. Collect it to a value first, or chunk the work so each attempt carries its own replayable piece.`,
|
|
46694
|
+
code: "LIVE_VALUE_RETRIED"
|
|
46695
|
+
});
|
|
46696
|
+
continue;
|
|
46697
|
+
}
|
|
46698
|
+
}
|
|
46699
|
+
if (!valueTypeOf(produced) || !valueTypeOf(slotSchema)) continue;
|
|
46700
|
+
const { compatible, issues } = checkSchemaCompatibility(
|
|
46701
|
+
produced,
|
|
46702
|
+
slotSchema,
|
|
46703
|
+
(ref) => defs.schemaForId(ref)
|
|
46704
|
+
);
|
|
46705
|
+
if (compatible) continue;
|
|
46706
|
+
out.push({
|
|
46707
|
+
path: `${site.path}.${inputName}`,
|
|
46708
|
+
targetLabel: targetLabel2,
|
|
46709
|
+
message: issues.join("; "),
|
|
46710
|
+
code: "CEL_TYPE_ARGUMENT_MISMATCH"
|
|
46711
|
+
});
|
|
46712
|
+
}
|
|
46713
|
+
}
|
|
46714
|
+
for (const issue of defs.validateResourceConfig(substituted, contract.schema)) {
|
|
46715
|
+
if (celPaths.has(issue.path)) continue;
|
|
46716
|
+
const anchor = missingRequired(issue) ? containerOf(issue.path) : issue.path;
|
|
46717
|
+
out.push({
|
|
46718
|
+
path: anchor ? `${site.path}.${anchor}` : site.path,
|
|
46719
|
+
targetLabel: targetLabel2,
|
|
46720
|
+
message: issue.message
|
|
46721
|
+
});
|
|
46722
|
+
}
|
|
46723
|
+
return out;
|
|
46724
|
+
}
|
|
46725
|
+
function declaredRetry(step, stepItemSchema, invokedManifest, invokedDef) {
|
|
46726
|
+
for (const [field, budget] of retryFields(stepItemSchema)) {
|
|
46727
|
+
if (budget(step?.[field]) > 0) return `the step's \`${field}\``;
|
|
46728
|
+
}
|
|
46729
|
+
for (const [field, budget] of retryFields(invokedDef?.schema)) {
|
|
46730
|
+
if (budget(invokedManifest?.[field]) > 0) return `the target's \`${field}\``;
|
|
46731
|
+
}
|
|
46732
|
+
return void 0;
|
|
46733
|
+
}
|
|
46734
|
+
var RETRY_BUDGET = {
|
|
46735
|
+
RetryPolicy: (value) => {
|
|
46736
|
+
if (!value || typeof value !== "object") return 0;
|
|
46737
|
+
const attempts = value.attempts;
|
|
46738
|
+
return typeof attempts === "number" ? attempts : 0;
|
|
46739
|
+
},
|
|
46740
|
+
RetryAttempts: (value) => typeof value === "number" ? value : 0
|
|
46741
|
+
};
|
|
46742
|
+
function retryFields(schema4) {
|
|
46743
|
+
if (!schema4) return [];
|
|
46744
|
+
const out = [];
|
|
46745
|
+
for (const [key, sub] of gatherPropertySchemas(schema4)) {
|
|
46746
|
+
const budget = RETRY_BUDGET[manifestFragmentOf(sub) ?? ""];
|
|
46747
|
+
if (budget) out.push([key, budget]);
|
|
46748
|
+
}
|
|
46749
|
+
return out;
|
|
46750
|
+
}
|
|
46751
|
+
|
|
46752
|
+
// ../../analyzer/nodejs/src/validate-reference-output.ts
|
|
46753
|
+
function producedOutputContract(target, definition, scope, defs) {
|
|
46754
|
+
return resolveContract("outputType", target, definition, scope)?.schema ?? valueDerivedContract(
|
|
46755
|
+
target,
|
|
46756
|
+
defs.effectiveSchemaOf(definition),
|
|
46757
|
+
"outputType"
|
|
46758
|
+
);
|
|
46759
|
+
}
|
|
46760
|
+
var OUTPUT_ROLES = { source: "the target's output", target: "this slot" };
|
|
46761
|
+
function referenceOutputRefusal(slot, produced, defs) {
|
|
46762
|
+
if (!slot.outputType || !produced) return [];
|
|
46763
|
+
const { compatible, issues } = checkSchemaCompatibility(
|
|
46764
|
+
produced,
|
|
46765
|
+
slot.outputType,
|
|
46766
|
+
(id) => defs.schemaForId(id),
|
|
46767
|
+
OUTPUT_ROLES
|
|
46768
|
+
);
|
|
46769
|
+
return compatible ? [] : issues;
|
|
46770
|
+
}
|
|
46771
|
+
function targetLabel(target) {
|
|
46772
|
+
const metadata = target.metadata;
|
|
46773
|
+
if (metadata?.xTeloOrigin !== void 0 || typeof metadata?.name !== "string") {
|
|
46774
|
+
return `the inline ${String(target.kind)}`;
|
|
46775
|
+
}
|
|
46776
|
+
return `${String(target.kind)} '${metadata.name}'`;
|
|
46777
|
+
}
|
|
46778
|
+
function collectReferenceOutputIssues(manifest, fieldMap, allManifests, defs, aliases, scopes) {
|
|
46779
|
+
const out = [];
|
|
46780
|
+
if (!fieldMap) return out;
|
|
46781
|
+
const ctx = callSiteContext(manifest, allManifests, defs, aliases, scopes);
|
|
46782
|
+
const contractScope = analyzerContractScope(defs, aliases, scopes, allManifests);
|
|
46783
|
+
const readingModule = manifest.metadata?.module;
|
|
46784
|
+
for (const [fieldPath, entry] of fieldMap) {
|
|
46785
|
+
if (!isRefEntry(entry) || !entry.outputType) continue;
|
|
46786
|
+
const slot = refSlotOfEntry(entry);
|
|
46787
|
+
for (const { value: ref, path } of resolveFieldEntries(manifest, fieldPath)) {
|
|
46788
|
+
if (!ref || typeof ref !== "object" || Array.isArray(ref)) continue;
|
|
46789
|
+
const reference = ref;
|
|
46790
|
+
if (typeof reference.kind !== "string") continue;
|
|
46791
|
+
const target = typeof reference.name === "string" ? ctx.resolveTarget(reference) : reference;
|
|
46792
|
+
if (!target) continue;
|
|
46793
|
+
const definition = contractScope.resolveIn(reference.kind, readingModule);
|
|
46794
|
+
const issues = referenceOutputRefusal(
|
|
46795
|
+
slot,
|
|
46796
|
+
producedOutputContract(target, definition, contractScope, defs),
|
|
46797
|
+
defs
|
|
46798
|
+
);
|
|
46799
|
+
if (issues.length === 0) continue;
|
|
46800
|
+
out.push({
|
|
46801
|
+
path,
|
|
46802
|
+
message: `${targetLabel(target)} does not return what this slot reads from it. The slot requires an output of ${JSON.stringify(slot.outputType)}; its declared output contract disagrees: ${issues.join("; ")}.`
|
|
46803
|
+
});
|
|
46804
|
+
}
|
|
46805
|
+
}
|
|
46806
|
+
return out;
|
|
46807
|
+
}
|
|
46808
|
+
|
|
46809
|
+
// ../../analyzer/nodejs/src/manifest-analysis.ts
|
|
46810
|
+
var ManifestAnalysis = class {
|
|
46811
|
+
constructor(manifests, ctx) {
|
|
46812
|
+
this.manifests = manifests;
|
|
46813
|
+
this.ctx = ctx;
|
|
46814
|
+
const rootModules = /* @__PURE__ */ new Set();
|
|
46815
|
+
for (const m of manifests) {
|
|
46816
|
+
if (isModuleKind(m.kind) && m.metadata?.name) rootModules.add(m.metadata.name);
|
|
46817
|
+
}
|
|
46818
|
+
this.scopes = { aliasesByModule: ctx.aliasesByModule, rootModules };
|
|
46819
|
+
}
|
|
46820
|
+
scopes;
|
|
46821
|
+
celScopeQuery;
|
|
46822
|
+
callGraphMemo;
|
|
46823
|
+
moduleGraphMemo;
|
|
46824
|
+
/** What CEL sees, per site. Built on first use — its indices are a function of
|
|
46825
|
+
* the whole set, and a host that never opens a CEL body should not pay for
|
|
46826
|
+
* them. */
|
|
46827
|
+
get celScope() {
|
|
46828
|
+
return this.celScopeQuery ??= new CelScopeQuery(this.manifests, this.ctx);
|
|
46829
|
+
}
|
|
46830
|
+
/** What calls what. Built on first use and kept, so the projection and any
|
|
46831
|
+
* other consumer over this set share one. */
|
|
46832
|
+
get callGraph() {
|
|
46833
|
+
return this.callGraphMemo ??= buildCallGraph(this.manifests, this.ctx.defs, {
|
|
46834
|
+
aliases: this.ctx.aliases,
|
|
46835
|
+
aliasesByModule: this.ctx.aliasesByModule
|
|
46836
|
+
});
|
|
46837
|
+
}
|
|
46838
|
+
/**
|
|
46839
|
+
* The module graph: boxes, ordered rows and classed edges — the projection an
|
|
46840
|
+
* editor draws.
|
|
46841
|
+
*
|
|
46842
|
+
* Here rather than on the registry because it is the registry AND a manifest
|
|
46843
|
+
* set, which is the pairing this class exists to name; a fifth
|
|
46844
|
+
* `registry.x(manifests, …)` factory is the accretion naming it stopped. It
|
|
46845
|
+
* shares this analysis's call graph rather than building one of its own.
|
|
46846
|
+
*
|
|
46847
|
+
* `deps` is supplied by the registry, which owns capability resolution — this
|
|
46848
|
+
* class holds the manifests, not the rules for reading a kind.
|
|
46849
|
+
*/
|
|
46850
|
+
moduleGraph(deps, options = {}) {
|
|
46851
|
+
return this.moduleGraphMemo ??= buildModuleGraph(
|
|
46852
|
+
this.manifests,
|
|
46853
|
+
this.callGraph,
|
|
46854
|
+
deps,
|
|
46855
|
+
options
|
|
46856
|
+
);
|
|
46857
|
+
}
|
|
46858
|
+
/** Whether a resource's name denotes a type or a value — the rule the naming
|
|
46859
|
+
* check applies to it, so a rename proposes only a name `telo check` accepts. */
|
|
46860
|
+
nameLevel(manifest) {
|
|
46861
|
+
const resolveDef = moduleScopedDefResolver(this.ctx.defs, this.ctx.aliases, this.scopes);
|
|
46862
|
+
return levelFor(manifest, resolveDef, manifest.metadata?.module);
|
|
46863
|
+
}
|
|
46864
|
+
/** The manifest a `(kind, name)` pair addresses. */
|
|
46865
|
+
resourceFor(kind, name) {
|
|
46866
|
+
return findManifest(this.manifests, kind, name);
|
|
46867
|
+
}
|
|
46868
|
+
/**
|
|
46869
|
+
* The invocation contract of the resource a reference names.
|
|
46870
|
+
*
|
|
46871
|
+
* The shared resolver, so an editor offering a target's input keys is offering
|
|
46872
|
+
* exactly what `telo check` validates that call site against and what the
|
|
46873
|
+
* kernel binds at dispatch. Layered instance-first: a resource declaring its
|
|
46874
|
+
* own `inputType:` narrows the kind's, which is the common case for a
|
|
46875
|
+
* `Run.Sequence` used as a handler.
|
|
46876
|
+
*/
|
|
46877
|
+
contractFor(ref, direction) {
|
|
46878
|
+
const target = this.resolveRef(ref);
|
|
46879
|
+
const definition = ref.kind ? this.definitionFor(ref.kind) : void 0;
|
|
46880
|
+
if (!target && !definition) return void 0;
|
|
46881
|
+
return resolveContract(
|
|
46882
|
+
direction,
|
|
46883
|
+
target,
|
|
46884
|
+
definition,
|
|
46885
|
+
analyzerContractScope(
|
|
46886
|
+
this.ctx.defs,
|
|
46887
|
+
this.ctx.aliases,
|
|
46888
|
+
this.scopes,
|
|
46889
|
+
this.manifests
|
|
46890
|
+
)
|
|
46891
|
+
)?.schema;
|
|
46892
|
+
}
|
|
46893
|
+
/**
|
|
46894
|
+
* Why the resource `ref` names cannot fill `slot`, by what it RETURNS — one
|
|
46895
|
+
* line per definite mismatch against the slot's `x-telo-ref` `outputType`,
|
|
46896
|
+
* empty when it can. The verdict `telo check` reports as
|
|
46897
|
+
* `REFERENCE_OUTPUT_MISMATCH`, so an editor never offers a target the checker
|
|
46898
|
+
* then refuses.
|
|
46899
|
+
*/
|
|
46900
|
+
outputRefusal(slot, ref) {
|
|
46901
|
+
if (!slot.outputType) return [];
|
|
46902
|
+
const target = this.resolveRef(ref);
|
|
46903
|
+
const definition = ref.kind ? this.definitionFor(ref.kind) : void 0;
|
|
46904
|
+
if (!target && !definition) return [];
|
|
46905
|
+
const scope = analyzerContractScope(
|
|
46906
|
+
this.ctx.defs,
|
|
46907
|
+
this.ctx.aliases,
|
|
46908
|
+
this.scopes,
|
|
46909
|
+
this.manifests
|
|
46910
|
+
);
|
|
46911
|
+
return referenceOutputRefusal(
|
|
46912
|
+
slot,
|
|
46913
|
+
producedOutputContract(target, definition, scope, this.ctx.defs),
|
|
46914
|
+
this.ctx.defs
|
|
46915
|
+
);
|
|
46916
|
+
}
|
|
46917
|
+
/**
|
|
46918
|
+
* The manifest a reference names.
|
|
46919
|
+
*
|
|
46920
|
+
* An ALIAS narrows before the name does: a flattened set carries every
|
|
46921
|
+
* imported library's exported instances, so two libraries exporting a `store`
|
|
46922
|
+
* are two manifests with one name. Matching the alias to its target module
|
|
46923
|
+
* picks the right one; where the alias resolves to nothing the name alone is
|
|
46924
|
+
* used, which is what a local reference needs anyway.
|
|
46925
|
+
*/
|
|
46926
|
+
resolveRef(ref) {
|
|
46927
|
+
if (!ref.name) return void 0;
|
|
46928
|
+
const byName = this.manifests.filter(
|
|
46929
|
+
(m) => m.metadata?.name === ref.name
|
|
46930
|
+
);
|
|
46931
|
+
if (byName.length === 0) return void 0;
|
|
46932
|
+
if (byName.length === 1) return byName[0];
|
|
46933
|
+
const targetModule = ref.alias ? this.ctx.aliases.moduleForAlias?.(ref.alias) : void 0;
|
|
46934
|
+
if (targetModule) {
|
|
46935
|
+
const scoped = byName.find(
|
|
46936
|
+
(m) => m.metadata?.module === targetModule
|
|
46937
|
+
);
|
|
46938
|
+
if (scoped) return scoped;
|
|
46939
|
+
}
|
|
46940
|
+
return ref.kind ? byName.find((m) => m.kind === ref.kind) : void 0;
|
|
46941
|
+
}
|
|
46942
|
+
definitionFor(kind) {
|
|
46943
|
+
const canonical = this.ctx.aliases.resolveKind(kind);
|
|
46944
|
+
return this.ctx.defs.resolve(kind) ?? (canonical ? this.ctx.defs.resolve(canonical) : void 0);
|
|
46945
|
+
}
|
|
46946
|
+
};
|
|
46947
|
+
|
|
46948
|
+
// ../../analyzer/nodejs/src/schema-tag-text.ts
|
|
46949
|
+
function schemaWithTagsAsText(value) {
|
|
46950
|
+
if (isCompiledValue(value) || isTaggedSentinel(value)) {
|
|
46951
|
+
return typeof value.source === "string" ? value.source : "";
|
|
46952
|
+
}
|
|
46953
|
+
if (Array.isArray(value)) return value.map(schemaWithTagsAsText);
|
|
46954
|
+
if (value && typeof value === "object") {
|
|
46955
|
+
const out = {};
|
|
46956
|
+
for (const [k, v] of Object.entries(value)) {
|
|
46957
|
+
out[k] = schemaWithTagsAsText(v);
|
|
46958
|
+
}
|
|
46959
|
+
return out;
|
|
46960
|
+
}
|
|
46961
|
+
return value;
|
|
46962
|
+
}
|
|
46963
|
+
|
|
46964
|
+
// ../../analyzer/nodejs/src/definition-registry.ts
|
|
46965
|
+
var DefinitionRegistry = class {
|
|
46966
|
+
constructor() {
|
|
46967
|
+
for (const def of KERNEL_BUILTINS) this.add(def, true);
|
|
46968
|
+
}
|
|
46969
|
+
/** Per-instance AJV for cross-module $ref resolution. Isolated so each registry
|
|
46970
|
+
* (and thus each AnalysisContext) has its own schema store — no stale schemas
|
|
46971
|
+
* across analyze() calls and no unbounded growth across the process lifetime. */
|
|
46972
|
+
ajv = createAjv();
|
|
46973
|
+
registeredSchemaIds = /* @__PURE__ */ new Set();
|
|
46974
|
+
compiledValidators = /* @__PURE__ */ new WeakMap();
|
|
46975
|
+
/** The subset of `registeredSchemaIds` claimed by a kind's schema. Kinds and
|
|
46976
|
+
* named `Telo.Type`s share one `telo://<module>/<Name>` id space, so this is
|
|
46977
|
+
* what lets a colliding type name be reported instead of silently dropped. */
|
|
46978
|
+
definitionSchemaIds = /* @__PURE__ */ new Set();
|
|
46979
|
+
defs = /* @__PURE__ */ new Map();
|
|
46980
|
+
fieldMaps = /* @__PURE__ */ new Map();
|
|
46981
|
+
/** Reverse inheritance index: parent kind → direct child kinds. */
|
|
46982
|
+
extendedBy = /* @__PURE__ */ new Map();
|
|
46983
|
+
/** Memoized inheritance-resolved schemas. `null` records "resolved to
|
|
46984
|
+
* nothing", so a kind with no schema is not re-walked on every resource. */
|
|
46985
|
+
effectiveSchemas = /* @__PURE__ */ new Map();
|
|
46986
|
+
/** DEPRECATED module identity table: identity string → canonical module name
|
|
46987
|
+
* ("std/pipeline" → "pipeline"). Serves only the legacy
|
|
46988
|
+
* `<namespace>/<module>#<Kind>` form of `x-telo-ref`, kept resolvable for
|
|
46989
|
+
* module versions published before constraints named their target by import
|
|
46990
|
+
* alias. Fed by `metadata.namespace`, which nothing else reads. */
|
|
46991
|
+
identityMap = /* @__PURE__ */ new Map();
|
|
46992
|
+
register(definition) {
|
|
46993
|
+
this.add(definition, false);
|
|
46994
|
+
}
|
|
46995
|
+
/** `trustedSchema` skips meta-validating the schema — only for the built-ins,
|
|
46996
|
+
* whose validity a test asserts once. */
|
|
46997
|
+
add(definition, trustedSchema) {
|
|
46998
|
+
const { name, module: mod } = definition.metadata;
|
|
46999
|
+
const key = mod ? `${mod}.${name}` : name;
|
|
47000
|
+
this.defs.set(key, definition);
|
|
47001
|
+
this.fieldMaps.clear();
|
|
47002
|
+
this.effectiveSchemas.clear();
|
|
47003
|
+
if (definition.capability) {
|
|
47004
|
+
this.addExtendedBy(definition.capability, key);
|
|
47005
|
+
}
|
|
47006
|
+
if (definition.extends) {
|
|
47007
|
+
this.addExtendedBy(definition.extends, key);
|
|
47008
|
+
}
|
|
47009
|
+
if (definition.kind === "Telo.Abstract" && mod === "Telo") {
|
|
47010
|
+
this.identityMap.set("telo", "Telo");
|
|
47011
|
+
}
|
|
47012
|
+
if (mod && definition.schema) {
|
|
47013
|
+
this.tryRegisterSchema(
|
|
47014
|
+
mod,
|
|
47015
|
+
name,
|
|
47016
|
+
definition.schema,
|
|
47017
|
+
trustedSchema
|
|
47018
|
+
);
|
|
47019
|
+
}
|
|
47020
|
+
}
|
|
47021
|
+
addExtendedBy(parent, child) {
|
|
47022
|
+
const children = this.extendedBy.get(parent);
|
|
47023
|
+
if (children) {
|
|
47024
|
+
if (!children.includes(child)) children.push(child);
|
|
47025
|
+
} else {
|
|
47026
|
+
this.extendedBy.set(parent, [child]);
|
|
47027
|
+
}
|
|
47028
|
+
}
|
|
47029
|
+
/** DEPRECATED. Register a module identity so the legacy
|
|
47030
|
+
* `<namespace>/<module>#<Kind>` form of `x-telo-ref` still resolves for module
|
|
47031
|
+
* versions published before constraints named their target by import alias.
|
|
47032
|
+
* New manifests declare no namespace and need no identity — their constraints
|
|
47033
|
+
* are canonicalized to `<module>.<Kind>` before registration.
|
|
47034
|
+
*
|
|
47035
|
+
* The "telo" identity is reserved for the built-in module and is populated
|
|
47036
|
+
* automatically when a `Telo.Abstract` registers. A namespace-less module must
|
|
47037
|
+
* not claim it: overwriting the entry would repoint every legacy `telo#…`
|
|
47038
|
+
* constraint at a module that declares no such kind, and the resulting
|
|
47039
|
+
* unresolvable ref reads as partial context rather than an error.
|
|
47040
|
+
*
|
|
47041
|
+
* @param namespace The module's `metadata.namespace`, or null when it declares none.
|
|
47042
|
+
* @param moduleName The module's `metadata.name` (e.g. "pipeline", "http-server"). */
|
|
47043
|
+
registerModuleIdentity(namespace, moduleName2) {
|
|
47044
|
+
if (!namespace || moduleName2 === "Telo") return;
|
|
47045
|
+
this.identityMap.set(`${namespace}/${moduleName2}`, moduleName2);
|
|
47046
|
+
}
|
|
47047
|
+
/** Registers a named `Telo.Type` resource's schema under its canonical
|
|
47048
|
+
* module-scoped URI `$id` (`telo://<module>/<name>`), so a sibling schema's
|
|
47049
|
+
* `$ref: "telo://Self/<name>"` (rewritten to the canonical form by
|
|
47050
|
+
* `resolveSchemaTypeRefs`) resolves during AJV compilation. Mirrors the
|
|
47051
|
+
* kernel type controller's `registerSchema(canonicalTypeSchemaId(...))`.
|
|
47052
|
+
*
|
|
47053
|
+
* Returns `false` when a kind schema in the same module already owns the id —
|
|
47054
|
+
* a name collision between a kind and a named type. Definitions register
|
|
47055
|
+
* first, so the type is the one that would be dropped, and every
|
|
47056
|
+
* `$ref: "telo://<module>/<Name>"` would then silently validate against the
|
|
47057
|
+
* kind's schema instead. The caller reports it; nothing is overwritten. */
|
|
47058
|
+
registerNamedTypeSchema(id, schema4) {
|
|
47059
|
+
if (this.definitionSchemaIds.has(id)) return false;
|
|
47060
|
+
if (this.registeredSchemaIds.has(id) || this.ajv.getSchema(id)) return true;
|
|
47061
|
+
if (!this.tryAddSchema(schema4, id)) return true;
|
|
47062
|
+
this.registeredSchemaIds.add(id);
|
|
47063
|
+
return true;
|
|
47064
|
+
}
|
|
47065
|
+
/**
|
|
47066
|
+
* Register a schema, surviving one AJV refuses.
|
|
47067
|
+
*
|
|
47068
|
+
* `addSchema` META-VALIDATES and THROWS, and a throw here escapes the whole
|
|
47069
|
+
* analyze pass: one author schema with `minimum: "3"` in it aborted the run
|
|
47070
|
+
* with AJV's own unanchored text and took every other diagnostic in the file
|
|
47071
|
+
* down with it — including the anchored one that says exactly which keyword is
|
|
47072
|
+
* wrong. Registration is a lookup table for `$ref` resolution, so failing to
|
|
47073
|
+
* fill one entry costs a reference that could not have resolved anyway.
|
|
47074
|
+
*
|
|
47075
|
+
* Nothing is swallowed: an unregisterable schema is invalid, and the two
|
|
47076
|
+
* checks that report it both run afterwards and both anchor on the offending
|
|
47077
|
+
* line — `SCHEMA_VIOLATION` from the `KindSchema` / `JsonSchema7` fragment the
|
|
47078
|
+
* slot points at, and `SCHEMA_COMPILE_ERROR` from {@link schemaCompileError},
|
|
47079
|
+
* which wraps `compile` for this same reason.
|
|
47080
|
+
*/
|
|
47081
|
+
tryAddSchema(schema4, id, trusted = false) {
|
|
47082
|
+
try {
|
|
47083
|
+
this.ajv.addSchema(schemaWithTagsAsText(schema4), id, void 0, !trusted);
|
|
47084
|
+
return true;
|
|
47085
|
+
} catch {
|
|
47086
|
+
return false;
|
|
47087
|
+
}
|
|
47088
|
+
}
|
|
47089
|
+
/** True when a schema is registered under `id` (a canonical `telo://` type id
|
|
47090
|
+
* or a definition `$id`). Used to flag schema `$ref`s that resolve to nothing. */
|
|
47091
|
+
hasSchemaId(id) {
|
|
47092
|
+
return this.registeredSchemaIds.has(id) || this.ajv.getSchema(id) !== void 0;
|
|
47093
|
+
}
|
|
47094
|
+
/** The schema registered under `id`, for a structural comparison that must see
|
|
47095
|
+
* THROUGH a named shape. Declaring a shape once and referencing it is the
|
|
47096
|
+
* sanctioned way to reuse one, so a comparator that cannot follow the
|
|
47097
|
+
* reference judges two opaque nodes and learns nothing.
|
|
47098
|
+
*
|
|
47099
|
+
* A registered id is READ, never compiled: this is a structural lookup, and
|
|
47100
|
+
* compiling a shape the registry holds but cannot compile throws out of
|
|
47101
|
+
* whichever walk asked. That shape's compile failure is reported where the
|
|
47102
|
+
* shape is validated, not here. */
|
|
47103
|
+
schemaForId(id) {
|
|
47104
|
+
let entry = this.ajv.schemas[id] ?? this.ajv.refs[id];
|
|
47105
|
+
while (typeof entry === "string") entry = this.ajv.schemas[entry] ?? this.ajv.refs[entry];
|
|
47106
|
+
const schema4 = entry ? entry.schema : this.ajv.getSchema(id)?.schema;
|
|
47107
|
+
return schema4 && typeof schema4 === "object" ? schema4 : void 0;
|
|
47108
|
+
}
|
|
47109
|
+
/**
|
|
47110
|
+
* Validates a resource's configuration against its kind's schema, with the
|
|
47111
|
+
* offending field's path — what a `SCHEMA_VIOLATION` diagnostic is built from.
|
|
47112
|
+
*
|
|
47113
|
+
* On THIS registry's AJV, which is the point: it holds every registered
|
|
47114
|
+
* definition schema and every named `Telo.Type`, so a kind whose schema
|
|
47115
|
+
* references a shape declared elsewhere is checked rather than skipped. The
|
|
47116
|
+
* module-level instance this used to run on had none of them registered, so
|
|
47117
|
+
* such a schema failed to compile and the failure was swallowed — a resource
|
|
47118
|
+
* could be arbitrarily wrong and `telo check` reported nothing, while the
|
|
47119
|
+
* kernel (whose validator does resolve the reference) rejected it at boot.
|
|
47120
|
+
* Two AJVs answering one question is what made that possible; there is now
|
|
47121
|
+
* one, and it is the same one `schemaCompileError` reports through.
|
|
47122
|
+
*/
|
|
47123
|
+
validateWithRefs(data, schema4) {
|
|
47124
|
+
const validate2 = this.compiledFor(schema4);
|
|
47125
|
+
if (!validate2 || validate2(data)) return [];
|
|
47126
|
+
return reduceSchemaErrors(explainFormatErrors(validate2.errors, data)).map(formatSingleError);
|
|
47127
|
+
}
|
|
47128
|
+
/** {@link validateWithRefs}, with the path each issue is anchored at. */
|
|
47129
|
+
validateResourceConfig(data, schema4) {
|
|
47130
|
+
const validate2 = this.compiledFor(schema4);
|
|
47131
|
+
if (!validate2 || validate2(data)) return [];
|
|
47132
|
+
return schemaIssues(validate2.errors, data);
|
|
47133
|
+
}
|
|
47134
|
+
/** Memoized per schema OBJECT — the analyzer validates every resource of a
|
|
47135
|
+
* kind against the same one, and this runs at keystroke time in an editor.
|
|
47136
|
+
* A schema AJV refuses compiles to `undefined`; that is reported once,
|
|
47137
|
+
* anchored on the owning definition, by `schemaCompileError`. */
|
|
47138
|
+
compiledFor(schema4) {
|
|
47139
|
+
const cached = this.compiledValidators.get(schema4);
|
|
47140
|
+
if (cached) return cached;
|
|
47141
|
+
try {
|
|
47142
|
+
const validate2 = this.ajv.compile(schemaWithTagsAsText(schema4));
|
|
47143
|
+
this.compiledValidators.set(schema4, validate2);
|
|
47144
|
+
return validate2;
|
|
47145
|
+
} catch {
|
|
47146
|
+
return void 0;
|
|
47147
|
+
}
|
|
47148
|
+
}
|
|
47149
|
+
/** Returns the AJV compile error for `schema`, or `undefined` when it compiles.
|
|
47150
|
+
* Compiles on this registry's instance, which has every loaded module schema
|
|
47151
|
+
* plus the manifest root registered, so local `#/$defs`, `telo://manifest`,
|
|
47152
|
+
* and cross-module `$ref`s all resolve. Used to fail loud on a definition
|
|
47153
|
+
* schema that AJV cannot compile — otherwise `validateAgainstSchema` /
|
|
47154
|
+
* `validateWithRefs` would swallow the failure and silently skip every
|
|
47155
|
+
* resource of that kind. */
|
|
47156
|
+
schemaCompileError(schema4) {
|
|
47157
|
+
try {
|
|
47158
|
+
this.ajv.compile(schemaWithTagsAsText(schema4));
|
|
47159
|
+
return void 0;
|
|
47160
|
+
} catch (err) {
|
|
47161
|
+
return err instanceof Error ? err.message : String(err);
|
|
47162
|
+
}
|
|
47163
|
+
}
|
|
47164
|
+
/** Registers a definition schema under the same module-scoped `telo://` id a
|
|
47165
|
+
* named `Telo.Type` uses, so a kind schema and a type schema are addressable
|
|
47166
|
+
* the same way and a `$ref` between them resolves at AJV compile time. One id
|
|
47167
|
+
* space per module: a kind and a named type may not share a name, which
|
|
47168
|
+
* `registerNamedTypeSchema` reports rather than resolving silently. */
|
|
47169
|
+
tryRegisterSchema(moduleName2, typeName2, schema4, trusted) {
|
|
47170
|
+
const id = canonicalTypeSchemaId(moduleName2, typeName2);
|
|
47171
|
+
if (this.registeredSchemaIds.has(id)) {
|
|
47172
|
+
this.definitionSchemaIds.add(id);
|
|
47173
|
+
return;
|
|
47174
|
+
}
|
|
47175
|
+
if (this.ajv.getSchema(id)) {
|
|
47176
|
+
throw new Error(`Duplicate definition schema $id: "${id}" is already registered`);
|
|
47177
|
+
}
|
|
47178
|
+
this.tryAddSchema(schema4, id, trusted);
|
|
47179
|
+
this.registeredSchemaIds.add(id);
|
|
47180
|
+
this.definitionSchemaIds.add(id);
|
|
47181
|
+
}
|
|
47182
|
+
/** Resolves an `x-telo-ref` constraint to a canonical registry kind key.
|
|
47183
|
+
*
|
|
47184
|
+
* The constraint is already canonical `<module>.<Kind>`: alias-form values
|
|
47185
|
+
* (`KvStore.Store`, `Self.Store`, `Telo.Invocable`) are rewritten in the
|
|
47186
|
+
* declaring module's scope by `resolveSchemaRefKinds` before registration, so
|
|
47187
|
+
* no module context is needed here.
|
|
47188
|
+
*
|
|
47189
|
+
* The legacy `<namespace>/<module>#<Kind>` form still resolves through the
|
|
47190
|
+
* identity table for module versions published before the alias form existed:
|
|
47191
|
+
*
|
|
47192
|
+
* "telo#Invocable" → "Telo.Invocable"
|
|
47193
|
+
* "std/http-server#Server" → "http-server.Server"
|
|
47194
|
+
*
|
|
47195
|
+
* Returns undefined when a legacy string is malformed or its identity was
|
|
47196
|
+
* never registered. */
|
|
47197
|
+
resolveRef(xTeloRef) {
|
|
47198
|
+
const hash = xTeloRef.indexOf("#");
|
|
47199
|
+
if (hash === -1) return xTeloRef;
|
|
47200
|
+
if (hash === xTeloRef.length - 1) return void 0;
|
|
47201
|
+
const moduleName2 = this.identityMap.get(xTeloRef.slice(0, hash));
|
|
47202
|
+
if (!moduleName2) return void 0;
|
|
47203
|
+
return `${moduleName2}.${xTeloRef.slice(hash + 1)}`;
|
|
47204
|
+
}
|
|
47205
|
+
resolve(kind) {
|
|
47206
|
+
return this.defs.get(kind);
|
|
47207
|
+
}
|
|
47208
|
+
/**
|
|
47209
|
+
* The kind's AUTHOR-FACING schema — its own merged with everything it
|
|
47210
|
+
* inherits along `extends` — memoized per kind.
|
|
47211
|
+
*
|
|
47212
|
+
* This is what every consumer reading a kind's schema to interpret an
|
|
47213
|
+
* INSTANCE must use, because that is the schema the instance was authored
|
|
47214
|
+
* against and the one the kernel stamps at definition registration. Reading
|
|
47215
|
+
* `resolve(kind).schema` instead sees only what the leaf declared, so an
|
|
47216
|
+
* annotation on a parent — a CEL context region, a step body, an error
|
|
47217
|
+
* context — is invisible on every child, silently and per consumer. Sharing
|
|
47218
|
+
* one memo is what keeps those consumers from drifting apart.
|
|
47219
|
+
*
|
|
47220
|
+
* Lazy for the same reason `getFieldMap` is: a child registered before its
|
|
47221
|
+
* parent still sees the inherited half once both are present.
|
|
47222
|
+
*/
|
|
47223
|
+
effectiveSchema(kind) {
|
|
47224
|
+
const cached = this.effectiveSchemas.get(kind);
|
|
47225
|
+
if (cached !== void 0) return cached ?? void 0;
|
|
47226
|
+
const def = this.defs.get(kind);
|
|
47227
|
+
if (!def) return void 0;
|
|
47228
|
+
const schema4 = effectiveAuthorSchema(def, (k) => this.resolve(k));
|
|
47229
|
+
this.effectiveSchemas.set(kind, schema4 ?? null);
|
|
47230
|
+
return schema4;
|
|
47231
|
+
}
|
|
47232
|
+
/** The effective schema for a definition, by the kind it is registered under.
|
|
47233
|
+
* Falls back to the definition's own schema when it is not in this registry
|
|
47234
|
+
* (a synthesized or not-yet-registered kind), which is the pre-inheritance
|
|
47235
|
+
* behaviour and the safe direction: it types less, never wrongly. */
|
|
47236
|
+
effectiveSchemaOf(definition) {
|
|
47237
|
+
if (!definition) return void 0;
|
|
47238
|
+
const { name, module: mod } = definition.metadata;
|
|
47239
|
+
const resolved = this.effectiveSchema(mod ? `${mod}.${name}` : name);
|
|
47240
|
+
return resolved ?? definition.schema;
|
|
46980
47241
|
}
|
|
46981
|
-
|
|
46982
|
-
|
|
46983
|
-
|
|
46984
|
-
|
|
46985
|
-
|
|
46986
|
-
|
|
46987
|
-
|
|
46988
|
-
|
|
46989
|
-
|
|
46990
|
-
|
|
46991
|
-
|
|
46992
|
-
|
|
46993
|
-
|
|
46994
|
-
for (const slot of ["invoke", "provide"]) {
|
|
46995
|
-
const target = dispatchTargetOf(manifest, slot);
|
|
46996
|
-
if (!target) continue;
|
|
46997
|
-
const definition2 = scope.resolveIn(target.kind, module);
|
|
46998
|
-
const aliases = moduleAliasScope(manifest.metadata, ctx.aliases, ctx.aliasesByModule);
|
|
46999
|
-
const entry = target.entry && {
|
|
47000
|
-
...target.entry,
|
|
47001
|
-
inputType: withCanonicalRefSentinels(
|
|
47002
|
-
target.entry.inputType,
|
|
47003
|
-
module,
|
|
47004
|
-
(alias) => aliases?.moduleForAlias(alias)
|
|
47005
|
-
)
|
|
47006
|
-
};
|
|
47007
|
-
return {
|
|
47008
|
-
origin: "template",
|
|
47009
|
-
path: "inputs",
|
|
47010
|
-
values,
|
|
47011
|
-
invoke: { kind: target.kind, name: target.name },
|
|
47012
|
-
invokedManifest: entry,
|
|
47013
|
-
invokedDefinition: definition2,
|
|
47014
|
-
contract: resolveContract("inputType", entry, definition2, scope)
|
|
47015
|
-
};
|
|
47242
|
+
/** Returns the reference field map for the given kind, computed lazily from the
|
|
47243
|
+
* kind's AUTHOR-FACING (inheritance-resolved) schema and memoized. Lazy so a
|
|
47244
|
+
* child registered before its parent still sees the parent's inherited ref
|
|
47245
|
+
* slots once both are present. */
|
|
47246
|
+
getFieldMap(kind) {
|
|
47247
|
+
const cached = this.fieldMaps.get(kind);
|
|
47248
|
+
if (cached) return cached;
|
|
47249
|
+
const def = this.defs.get(kind);
|
|
47250
|
+
if (!def) return void 0;
|
|
47251
|
+
const schema4 = effectiveAuthorSchema(def, (k) => this.resolve(k));
|
|
47252
|
+
const map3 = buildReferenceFieldMap(schema4 ?? {});
|
|
47253
|
+
this.fieldMaps.set(kind, map3);
|
|
47254
|
+
return map3;
|
|
47016
47255
|
}
|
|
47017
|
-
|
|
47018
|
-
|
|
47019
|
-
|
|
47020
|
-
|
|
47021
|
-
|
|
47022
|
-
|
|
47023
|
-
|
|
47024
|
-
|
|
47025
|
-
|
|
47026
|
-
|
|
47027
|
-
|
|
47028
|
-
|
|
47029
|
-
|
|
47030
|
-
|
|
47031
|
-
|
|
47032
|
-
|
|
47033
|
-
|
|
47034
|
-
|
|
47035
|
-
|
|
47036
|
-
|
|
47037
|
-
|
|
47038
|
-
|
|
47039
|
-
|
|
47256
|
+
/** Returns the field map for `kind`, falling back to the alias-resolved kind when not found. */
|
|
47257
|
+
getFieldMapForKind(kind, aliases) {
|
|
47258
|
+
const fm = this.getFieldMap(kind);
|
|
47259
|
+
if (fm) return fm;
|
|
47260
|
+
const resolved = aliases?.resolveKind(kind);
|
|
47261
|
+
return resolved ? this.getFieldMap(resolved) : void 0;
|
|
47262
|
+
}
|
|
47263
|
+
/** Returns the field map for `resource.kind` with x-telo-schema-from entries replaced
|
|
47264
|
+
* by their nested ref/scope slots — so Phase 2 inline normalization and Phase 5
|
|
47265
|
+
* injection see encoders nested behind a schema-from indirection (e.g.
|
|
47266
|
+
* http-server `Server.notFoundHandler.returns[].content[mime].encoder`).
|
|
47267
|
+
*
|
|
47268
|
+
* Only static absolute schema-from paths with a dotted alias anchor are expanded
|
|
47269
|
+
* (e.g. "HttpDispatch.Outcomes/$defs/Returns"). Relative and unqualified absolute
|
|
47270
|
+
* anchors depend on a sibling property at runtime and stay unexpanded; the
|
|
47271
|
+
* analyzer's reference validation phase already flags the cases that matter. */
|
|
47272
|
+
expandedFieldMapForResource(resource, aliases, aliasesByModule) {
|
|
47273
|
+
const moduleScope = moduleAliasScope(resource.metadata, aliases, aliasesByModule);
|
|
47274
|
+
const baseMap = this.getFieldMapForKind(resource.kind, moduleScope);
|
|
47275
|
+
if (!baseMap) return void 0;
|
|
47276
|
+
const resolvedKind = moduleScope.resolveKind(resource.kind) ?? resource.kind;
|
|
47277
|
+
const def = this.resolve(resource.kind) ?? this.resolve(resolvedKind);
|
|
47278
|
+
const ownerScope = moduleAliasScope(def?.metadata, aliases, aliasesByModule);
|
|
47279
|
+
const expanded = /* @__PURE__ */ new Map();
|
|
47280
|
+
for (const [path, entry] of baseMap) {
|
|
47281
|
+
if (!isSchemaFromEntry(entry)) {
|
|
47282
|
+
expanded.set(path, entry);
|
|
47283
|
+
continue;
|
|
47284
|
+
}
|
|
47285
|
+
const sub = this.resolveSchemaFromSubMap(entry.schemaFrom, path, ownerScope);
|
|
47286
|
+
if (!sub) continue;
|
|
47287
|
+
for (const [subPath, subEntry] of sub) expanded.set(subPath, subEntry);
|
|
47040
47288
|
}
|
|
47289
|
+
return expanded;
|
|
47041
47290
|
}
|
|
47042
|
-
|
|
47043
|
-
|
|
47044
|
-
|
|
47045
|
-
|
|
47046
|
-
|
|
47047
|
-
|
|
47048
|
-
|
|
47049
|
-
|
|
47050
|
-
|
|
47051
|
-
|
|
47052
|
-
|
|
47053
|
-
|
|
47054
|
-
|
|
47055
|
-
|
|
47056
|
-
|
|
47057
|
-
|
|
47058
|
-
)
|
|
47059
|
-
|
|
47060
|
-
|
|
47061
|
-
|
|
47062
|
-
|
|
47063
|
-
if (
|
|
47291
|
+
/**
|
|
47292
|
+
* The schema an `x-telo-schema-from` slot derives its shape from.
|
|
47293
|
+
*
|
|
47294
|
+
* Only the STATIC form resolves: an anchor that is a dotted alias-qualified
|
|
47295
|
+
* kind (`HttpDispatch.Request/$defs/Matcher`). The polymorphic forms — a
|
|
47296
|
+
* relative anchor, or a single-segment absolute one — name a sibling property
|
|
47297
|
+
* whose value is known per resource, so a definition-level lookup would be
|
|
47298
|
+
* guessing at one instance's shape.
|
|
47299
|
+
*
|
|
47300
|
+
* Its own method because a schema-from slot is otherwise INVISIBLE to anything
|
|
47301
|
+
* reading `properties`: the field map needs the nested ref slots, and an IDE
|
|
47302
|
+
* needs the very same node to offer a key or describe one. Two resolutions of
|
|
47303
|
+
* one annotation would eventually disagree about which anchors are static.
|
|
47304
|
+
*/
|
|
47305
|
+
resolveSchemaFromNode(schemaFrom, ownerScope) {
|
|
47306
|
+
const isAbsolute = schemaFrom.startsWith("/");
|
|
47307
|
+
const expr = isAbsolute ? schemaFrom.slice(1) : schemaFrom;
|
|
47308
|
+
const slashIdx = expr.indexOf("/");
|
|
47309
|
+
if (slashIdx === -1) return void 0;
|
|
47310
|
+
const anchorName = expr.slice(0, slashIdx);
|
|
47311
|
+
const jsonPointer = "/" + expr.slice(slashIdx + 1);
|
|
47312
|
+
if (!anchorName.includes(".")) return void 0;
|
|
47313
|
+
const targetKind = ownerScope.resolveKind(anchorName);
|
|
47314
|
+
if (!targetKind) return void 0;
|
|
47315
|
+
const targetDef = this.resolve(targetKind);
|
|
47316
|
+
if (!targetDef?.schema) return void 0;
|
|
47317
|
+
const subSchema = navigateJsonPointer(
|
|
47318
|
+
targetDef.schema,
|
|
47319
|
+
jsonPointer
|
|
47320
|
+
);
|
|
47321
|
+
if (!subSchema || typeof subSchema !== "object") return void 0;
|
|
47322
|
+
return subSchema;
|
|
47064
47323
|
}
|
|
47065
|
-
|
|
47066
|
-
|
|
47324
|
+
resolveSchemaFromSubMap(schemaFrom, fieldPath, ownerScope) {
|
|
47325
|
+
const subSchema = this.resolveSchemaFromNode(schemaFrom, ownerScope);
|
|
47326
|
+
if (!subSchema) return null;
|
|
47327
|
+
return buildFieldMapAtPath(subSchema, fieldPath);
|
|
47067
47328
|
}
|
|
47068
|
-
|
|
47069
|
-
|
|
47070
|
-
|
|
47071
|
-
|
|
47072
|
-
|
|
47073
|
-
|
|
47074
|
-
|
|
47075
|
-
|
|
47329
|
+
/** The kinds a definition descends from DIRECTLY — the same two edges
|
|
47330
|
+
* `register` feeds into `extendedBy`, read the other way.
|
|
47331
|
+
*
|
|
47332
|
+
* Both spellings, because either can carry the edge that satisfies a slot:
|
|
47333
|
+
* `capability:` is the legacy implements-this form, `extends:` the canonical
|
|
47334
|
+
* one. A consumer walking these by hand would be a second reading of what an
|
|
47335
|
+
* inheritance edge IS, and the downward index and the upward walk have to
|
|
47336
|
+
* agree about that forever. */
|
|
47337
|
+
parentsOf(kind) {
|
|
47338
|
+
const def = this.defs.get(kind);
|
|
47339
|
+
if (!def) return [];
|
|
47340
|
+
return [def.capability, def.extends].filter(
|
|
47341
|
+
(parent) => typeof parent === "string" && parent.length > 0
|
|
47342
|
+
);
|
|
47343
|
+
}
|
|
47344
|
+
/** Whether every kind this one descends from is registered.
|
|
47345
|
+
*
|
|
47346
|
+
* When it is, what the kind implements is FULLY KNOWN: a target it does not
|
|
47347
|
+
* reach is one it genuinely does not implement, so a mismatch is a verdict.
|
|
47348
|
+
* When a hop is missing — an unimported abstract, an alias the declaring file
|
|
47349
|
+
* could not resolve — a mismatch cannot be told from a missing dependency,
|
|
47350
|
+
* which is the partial context every reference check stays lenient in. */
|
|
47351
|
+
ancestryResolved(kind) {
|
|
47352
|
+
const queue = [kind];
|
|
47353
|
+
const seen = /* @__PURE__ */ new Set();
|
|
47354
|
+
while (queue.length > 0) {
|
|
47355
|
+
const current = queue.shift();
|
|
47356
|
+
if (seen.has(current)) continue;
|
|
47357
|
+
seen.add(current);
|
|
47358
|
+
if (!this.defs.has(current)) return false;
|
|
47359
|
+
queue.push(...this.parentsOf(current));
|
|
47360
|
+
}
|
|
47361
|
+
return true;
|
|
47362
|
+
}
|
|
47363
|
+
/** Returns all definitions that transitively extend the given abstract kind.
|
|
47364
|
+
* Follows the capability chain to any depth (equivalent to instanceof in OOP).
|
|
47365
|
+
* Definitions are included regardless of registration order. */
|
|
47366
|
+
getByExtends(abstractKind) {
|
|
47367
|
+
const result = [];
|
|
47368
|
+
const queue = [abstractKind];
|
|
47369
|
+
while (queue.length > 0) {
|
|
47370
|
+
const parent = queue.shift();
|
|
47371
|
+
const children = this.extendedBy.get(parent);
|
|
47372
|
+
if (!children) continue;
|
|
47373
|
+
for (const child of children) {
|
|
47374
|
+
const def = this.defs.get(child);
|
|
47375
|
+
if (def) result.push(def);
|
|
47376
|
+
queue.push(child);
|
|
47076
47377
|
}
|
|
47077
|
-
},
|
|
47078
|
-
{
|
|
47079
|
-
aliases: ctx.aliases,
|
|
47080
|
-
aliasesByModule: ctx.aliasesByModule,
|
|
47081
|
-
skipKinds: REF_VALIDATION_SKIP_KINDS,
|
|
47082
|
-
expand: false
|
|
47083
47378
|
}
|
|
47084
|
-
|
|
47085
|
-
|
|
47086
|
-
|
|
47379
|
+
return result;
|
|
47380
|
+
}
|
|
47381
|
+
kinds() {
|
|
47382
|
+
return Array.from(this.defs.keys());
|
|
47383
|
+
}
|
|
47384
|
+
};
|
|
47087
47385
|
|
|
47088
47386
|
// ../../analyzer/nodejs/src/instantiable-kind.ts
|
|
47089
47387
|
function isInstantiableDefinition(def) {
|
|
@@ -47782,6 +48080,32 @@ var AnalysisRegistry = class _AnalysisRegistry {
|
|
|
47782
48080
|
typeManifestsFor: () => []
|
|
47783
48081
|
})?.schema;
|
|
47784
48082
|
}
|
|
48083
|
+
/**
|
|
48084
|
+
* Why a resource of `candidate.kind` — configured as `candidate.config`, when
|
|
48085
|
+
* the caller holds its configuration — cannot fill `slot`, by what it RETURNS:
|
|
48086
|
+
* one line per definite mismatch against the slot's `x-telo-ref`
|
|
48087
|
+
* `outputType`, empty when it can. The same derivation and comparator
|
|
48088
|
+
* `telo check`'s `REFERENCE_OUTPUT_MISMATCH` runs, for a host that has a kind
|
|
48089
|
+
* (and perhaps its fields) but not the analyzed manifest set. A named shape an
|
|
48090
|
+
* instance's own `outputType` points at resolves through no manifest here, so
|
|
48091
|
+
* that layer gives no verdict and the kind's contract decides.
|
|
48092
|
+
*/
|
|
48093
|
+
outputRefusal(slot, candidate) {
|
|
48094
|
+
if (!slot.outputType) return [];
|
|
48095
|
+
const definition = this.resolveDefinition(candidate.kind);
|
|
48096
|
+
if (!definition) return [];
|
|
48097
|
+
const target = candidate.config ? { kind: candidate.kind, ...candidate.config } : void 0;
|
|
48098
|
+
return referenceOutputRefusal(
|
|
48099
|
+
slot,
|
|
48100
|
+
producedOutputContract(
|
|
48101
|
+
target,
|
|
48102
|
+
definition,
|
|
48103
|
+
{ resolveDefinition: this.scopedDefResolver(), typeManifestsFor: () => [] },
|
|
48104
|
+
this.defs
|
|
48105
|
+
),
|
|
48106
|
+
this.defs
|
|
48107
|
+
);
|
|
48108
|
+
}
|
|
47785
48109
|
/** A resolver that re-scopes at every hop of an `extends` chain: each kind is
|
|
47786
48110
|
* resolved in the module that DECLARED the definition it was read off, since
|
|
47787
48111
|
* `extends` aliases are lexical. `resolveParent` always passes that definition
|
|
@@ -51237,6 +51561,14 @@ function checkAnnotation(annotation, manifest, path, issues) {
|
|
|
51237
51561
|
message: `x-telo-ref at '${path}' declares 'throwsThrough: ${JSON.stringify(obj.throwsThrough)}', which is not a boolean. Only 'true' declares that throws from this slot's target surface through the declaring resource; anything else reads as absent, which silently stops its catch list from enclosing what it holds.`
|
|
51238
51562
|
});
|
|
51239
51563
|
}
|
|
51564
|
+
if (obj.outputType !== void 0 && (!obj.outputType || typeof obj.outputType !== "object" || Array.isArray(obj.outputType))) {
|
|
51565
|
+
issues.push({
|
|
51566
|
+
code: "X_TELO_REF_INVALID_OUTPUT_TYPE",
|
|
51567
|
+
manifest,
|
|
51568
|
+
path,
|
|
51569
|
+
message: `x-telo-ref at '${path}' declares 'outputType: ${JSON.stringify(obj.outputType)}', which is not a JSON Schema object. It names the shape the target's output must have (e.g. '{ type: object, required: [output] }'); anything else reads as absent, so the slot would accept a target returning anything.`
|
|
51570
|
+
});
|
|
51571
|
+
}
|
|
51240
51572
|
for (const key of Object.keys(obj)) {
|
|
51241
51573
|
if (REF_ANNOTATION_KEYS.has(key)) continue;
|
|
51242
51574
|
issues.push({
|
|
@@ -51248,7 +51580,7 @@ function checkAnnotation(annotation, manifest, path, issues) {
|
|
|
51248
51580
|
}
|
|
51249
51581
|
return declaredUses(use);
|
|
51250
51582
|
}
|
|
51251
|
-
var REF_ANNOTATION_KEYS = /* @__PURE__ */ new Set(["kind", "use", "inputs", "throwsThrough"]);
|
|
51583
|
+
var REF_ANNOTATION_KEYS = /* @__PURE__ */ new Set(["kind", "use", "inputs", "throwsThrough", "outputType"]);
|
|
51252
51584
|
function carriesRefAnnotation(obj) {
|
|
51253
51585
|
if (obj["x-telo-ref"] !== void 0) return true;
|
|
51254
51586
|
for (const key of ["anyOf", "oneOf"]) {
|
|
@@ -51705,64 +52037,6 @@ function formatSegments(segments) {
|
|
|
51705
52037
|
return out;
|
|
51706
52038
|
}
|
|
51707
52039
|
|
|
51708
|
-
// ../../analyzer/nodejs/src/plain-literal-decoding.ts
|
|
51709
|
-
function decodePlainLiterals(value, schema4, external, rootSchema = schema4) {
|
|
51710
|
-
return mapTextLeaves(value, schema4, decodePlainText, external, rootSchema);
|
|
51711
|
-
}
|
|
51712
|
-
function mapTextLeaves(value, schema4, leaf, external, rootSchema = schema4, visit4) {
|
|
51713
|
-
const walk4 = (node, raw, base, pointer) => {
|
|
51714
|
-
const entered = resolveRefIn(raw, base, external);
|
|
51715
|
-
const selected = selectUnionBranch(entered.schema, node, entered.root, external);
|
|
51716
|
-
const { schema: here, root } = resolveRefIn(selected, entered.root, external);
|
|
51717
|
-
visit4?.(here, node, pointer);
|
|
51718
|
-
if (typeof node === "string") return leaf(here, node, pointer);
|
|
51719
|
-
if (!node || typeof node !== "object") return node;
|
|
51720
|
-
if (here["x-telo-ref"] !== void 0) return node;
|
|
51721
|
-
if (isCompiledValue(node) || isTaggedSentinel(node)) return node;
|
|
51722
|
-
if (Array.isArray(node)) {
|
|
51723
|
-
const item = resolveRefIn(here.items ?? {}, root, external);
|
|
51724
|
-
for (let i = 0; i < node.length; i++) node[i] = walk4(node[i], item.schema, item.root, `${pointer}/${i}`);
|
|
51725
|
-
return node;
|
|
51726
|
-
}
|
|
51727
|
-
const proto = Object.getPrototypeOf(node);
|
|
51728
|
-
if (proto !== Object.prototype && proto !== null) return node;
|
|
51729
|
-
const properties = collectProperties(here);
|
|
51730
|
-
const additional = here.additionalProperties && typeof here.additionalProperties === "object" ? here.additionalProperties : void 0;
|
|
51731
|
-
const record = node;
|
|
51732
|
-
for (const key of Object.keys(record)) {
|
|
51733
|
-
const child = properties[key] ?? additional;
|
|
51734
|
-
if (child) {
|
|
51735
|
-
record[key] = walk4(record[key], child, root, `${pointer}/${key.replace(/~/g, "~0").replace(/\//g, "~1")}`);
|
|
51736
|
-
}
|
|
51737
|
-
}
|
|
51738
|
-
return node;
|
|
51739
|
-
};
|
|
51740
|
-
return walk4(value, schema4, rootSchema, "");
|
|
51741
|
-
}
|
|
51742
|
-
function substituteDecodedCelFields(data, schema4, rootSchema, options = {}) {
|
|
51743
|
-
const decoded = decodePlainLiterals(
|
|
51744
|
-
copyPlainContainers(data),
|
|
51745
|
-
schema4,
|
|
51746
|
-
options.external,
|
|
51747
|
-
rootSchema ?? schema4
|
|
51748
|
-
);
|
|
51749
|
-
return substituteCelFields(decoded, schema4, rootSchema, options);
|
|
51750
|
-
}
|
|
51751
|
-
function copyPlainContainers(value) {
|
|
51752
|
-
if (Array.isArray(value)) return value.map(copyPlainContainers);
|
|
51753
|
-
if (!value || typeof value !== "object" || isCompiledValue(value) || isTaggedSentinel(value)) {
|
|
51754
|
-
return value;
|
|
51755
|
-
}
|
|
51756
|
-
const proto = Object.getPrototypeOf(value);
|
|
51757
|
-
if (proto !== Object.prototype && proto !== null) return value;
|
|
51758
|
-
return Object.fromEntries(
|
|
51759
|
-
Object.entries(value).map(([key, item]) => [
|
|
51760
|
-
key,
|
|
51761
|
-
copyPlainContainers(item)
|
|
51762
|
-
])
|
|
51763
|
-
);
|
|
51764
|
-
}
|
|
51765
|
-
|
|
51766
52040
|
// ../../analyzer/nodejs/src/validate-value-schema.ts
|
|
51767
52041
|
function collectValueSchemaIssues(manifest, defSchema, allManifests, validator) {
|
|
51768
52042
|
const issues = [];
|
|
@@ -58704,7 +58978,7 @@ function describe3(value) {
|
|
|
58704
58978
|
}
|
|
58705
58979
|
|
|
58706
58980
|
// ../../analyzer/nodejs/src/telo-version.ts
|
|
58707
|
-
var TELO_SURFACE_VERSION = "0.
|
|
58981
|
+
var TELO_SURFACE_VERSION = "0.103.1";
|
|
58708
58982
|
|
|
58709
58983
|
// ../../analyzer/nodejs/src/validate-requires.ts
|
|
58710
58984
|
var SOURCE19 = "telo-analyzer";
|
|
@@ -59259,153 +59533,6 @@ function findInModule(manifests, name, module) {
|
|
|
59259
59533
|
return byName.length === 1 ? byName[0] : void 0;
|
|
59260
59534
|
}
|
|
59261
59535
|
|
|
59262
|
-
// ../../analyzer/nodejs/src/validate-step-inputs.ts
|
|
59263
|
-
var missingRequired = (issue) => /is missing required property/.test(issue.message);
|
|
59264
|
-
function containerOf(path) {
|
|
59265
|
-
const dot = path.lastIndexOf(".");
|
|
59266
|
-
return dot === -1 ? "" : path.slice(0, dot);
|
|
59267
|
-
}
|
|
59268
|
-
var declarationsByName = /* @__PURE__ */ new WeakMap();
|
|
59269
|
-
function byNameOf(allManifests) {
|
|
59270
|
-
let byName = declarationsByName.get(allManifests);
|
|
59271
|
-
if (!byName) {
|
|
59272
|
-
byName = /* @__PURE__ */ new Map();
|
|
59273
|
-
for (const m of allManifests) {
|
|
59274
|
-
const name = m.metadata?.name;
|
|
59275
|
-
if (typeof name !== "string" || m.kind === "Telo.Import") continue;
|
|
59276
|
-
const list2 = byName.get(name);
|
|
59277
|
-
if (list2) list2.push(m);
|
|
59278
|
-
else byName.set(name, [m]);
|
|
59279
|
-
}
|
|
59280
|
-
declarationsByName.set(allManifests, byName);
|
|
59281
|
-
}
|
|
59282
|
-
return byName;
|
|
59283
|
-
}
|
|
59284
|
-
function callSiteContext(manifest, allManifests, defs, aliases, scopes) {
|
|
59285
|
-
const fromModule = manifest.metadata?.module;
|
|
59286
|
-
const scope = moduleAliasScope({ module: fromModule }, aliases, scopes.aliasesByModule);
|
|
59287
|
-
return {
|
|
59288
|
-
defs,
|
|
59289
|
-
aliases,
|
|
59290
|
-
aliasesByModule: scopes.aliasesByModule,
|
|
59291
|
-
rootModules: scopes.rootModules,
|
|
59292
|
-
typeManifests: allManifests,
|
|
59293
|
-
resolveTarget: (ref) => typeof ref.name === "string" ? resolveReferenceTarget(
|
|
59294
|
-
byNameOf(allManifests),
|
|
59295
|
-
{ name: ref.name, ...typeof ref.alias === "string" ? { alias: ref.alias } : {} },
|
|
59296
|
-
fromModule,
|
|
59297
|
-
(alias) => scope.moduleForAlias(alias)
|
|
59298
|
-
) : void 0
|
|
59299
|
-
};
|
|
59300
|
-
}
|
|
59301
|
-
function collectStepInputIssues(manifest, defSchema, allManifests, defs, aliases, scopes, stepContext) {
|
|
59302
|
-
const ctx = callSiteContext(manifest, allManifests, defs, aliases, scopes);
|
|
59303
|
-
return stepCallSites(manifest, defSchema, ctx).flatMap(
|
|
59304
|
-
(site) => checkCallSite(site, manifest, allManifests, defs, aliases, scopes, stepContext)
|
|
59305
|
-
);
|
|
59306
|
-
}
|
|
59307
|
-
function collectRefInputIssues(manifest, fieldMap, allManifests, defs, aliases, scopes) {
|
|
59308
|
-
const ctx = callSiteContext(manifest, allManifests, defs, aliases, scopes);
|
|
59309
|
-
return slotCallSites(manifest, fieldMap, ctx).flatMap(
|
|
59310
|
-
(site) => checkCallSite(site, manifest, allManifests, defs, aliases, scopes)
|
|
59311
|
-
);
|
|
59312
|
-
}
|
|
59313
|
-
function checkCallSite(site, manifest, allManifests, defs, aliases, scopes, stepContext) {
|
|
59314
|
-
const out = [];
|
|
59315
|
-
const { contract, values, invoke, invokedManifest, invokedDefinition } = site;
|
|
59316
|
-
if (!contract) return out;
|
|
59317
|
-
const targetLabel = invoke.name ?? invoke.kind ?? "the invoked resource";
|
|
59318
|
-
const contractScope = analyzerContractScope(defs, aliases, scopes, allManifests);
|
|
59319
|
-
const readingModule = manifest.metadata?.module;
|
|
59320
|
-
const celPaths = /* @__PURE__ */ new Set();
|
|
59321
|
-
const substituted = substituteDecodedCelFields(values, contract.schema, void 0, {
|
|
59322
|
-
onSubstitute: (p) => celPaths.add(p),
|
|
59323
|
-
// A contract may name a shape declared elsewhere. Both halves need the
|
|
59324
|
-
// resolver or they disagree about the same slot.
|
|
59325
|
-
external: (ref) => defs.schemaForId(ref)
|
|
59326
|
-
});
|
|
59327
|
-
const roots = [];
|
|
59328
|
-
if (stepContext) roots.push(["steps.", stepContext]);
|
|
59329
|
-
const ownContract = resolveContract(
|
|
59330
|
-
"inputType",
|
|
59331
|
-
manifest,
|
|
59332
|
-
contractScope.resolveIn(manifest.kind, readingModule),
|
|
59333
|
-
contractScope
|
|
59334
|
-
);
|
|
59335
|
-
if (ownContract) roots.push(["inputs.", ownContract.schema]);
|
|
59336
|
-
if (roots.length > 0) {
|
|
59337
|
-
for (const [inputName, inputValue] of Object.entries(values)) {
|
|
59338
|
-
const chain = plainChainOf(inputValue);
|
|
59339
|
-
const root = chain ? roots.find(([prefix]) => chain.startsWith(prefix)) : void 0;
|
|
59340
|
-
if (!chain || !root) continue;
|
|
59341
|
-
const produced = navigateSchemaToExprPath(root[1], chain.slice(root[0].length));
|
|
59342
|
-
const slotSchema = contract.schema.properties?.[inputName];
|
|
59343
|
-
if (!produced || !slotSchema) continue;
|
|
59344
|
-
if (isLiveSlot(produced)) {
|
|
59345
|
-
const retry = site.step ? declaredRetry(site.step.value, site.step.schema, invokedManifest, invokedDefinition) : void 0;
|
|
59346
|
-
if (retry !== void 0) {
|
|
59347
|
-
out.push({
|
|
59348
|
-
path: `${site.path}.${inputName}`,
|
|
59349
|
-
targetLabel,
|
|
59350
|
-
message: `'${inputName}' is a live value, which is consumed by reading and so exists once \u2014 but ${retry} re-attempts the dispatch, and a re-attempt would pass nothing. Collect it to a value first, or chunk the work so each attempt carries its own replayable piece.`,
|
|
59351
|
-
code: "LIVE_VALUE_RETRIED"
|
|
59352
|
-
});
|
|
59353
|
-
continue;
|
|
59354
|
-
}
|
|
59355
|
-
}
|
|
59356
|
-
if (!valueTypeOf(produced) || !valueTypeOf(slotSchema)) continue;
|
|
59357
|
-
const { compatible, issues } = checkSchemaCompatibility(
|
|
59358
|
-
produced,
|
|
59359
|
-
slotSchema,
|
|
59360
|
-
(ref) => defs.schemaForId(ref)
|
|
59361
|
-
);
|
|
59362
|
-
if (compatible) continue;
|
|
59363
|
-
out.push({
|
|
59364
|
-
path: `${site.path}.${inputName}`,
|
|
59365
|
-
targetLabel,
|
|
59366
|
-
message: issues.join("; "),
|
|
59367
|
-
code: "CEL_TYPE_ARGUMENT_MISMATCH"
|
|
59368
|
-
});
|
|
59369
|
-
}
|
|
59370
|
-
}
|
|
59371
|
-
for (const issue of defs.validateResourceConfig(substituted, contract.schema)) {
|
|
59372
|
-
if (celPaths.has(issue.path)) continue;
|
|
59373
|
-
const anchor = missingRequired(issue) ? containerOf(issue.path) : issue.path;
|
|
59374
|
-
out.push({
|
|
59375
|
-
path: anchor ? `${site.path}.${anchor}` : site.path,
|
|
59376
|
-
targetLabel,
|
|
59377
|
-
message: issue.message
|
|
59378
|
-
});
|
|
59379
|
-
}
|
|
59380
|
-
return out;
|
|
59381
|
-
}
|
|
59382
|
-
function declaredRetry(step, stepItemSchema, invokedManifest, invokedDef) {
|
|
59383
|
-
for (const [field, budget] of retryFields(stepItemSchema)) {
|
|
59384
|
-
if (budget(step?.[field]) > 0) return `the step's \`${field}\``;
|
|
59385
|
-
}
|
|
59386
|
-
for (const [field, budget] of retryFields(invokedDef?.schema)) {
|
|
59387
|
-
if (budget(invokedManifest?.[field]) > 0) return `the target's \`${field}\``;
|
|
59388
|
-
}
|
|
59389
|
-
return void 0;
|
|
59390
|
-
}
|
|
59391
|
-
var RETRY_BUDGET = {
|
|
59392
|
-
RetryPolicy: (value) => {
|
|
59393
|
-
if (!value || typeof value !== "object") return 0;
|
|
59394
|
-
const attempts = value.attempts;
|
|
59395
|
-
return typeof attempts === "number" ? attempts : 0;
|
|
59396
|
-
},
|
|
59397
|
-
RetryAttempts: (value) => typeof value === "number" ? value : 0
|
|
59398
|
-
};
|
|
59399
|
-
function retryFields(schema4) {
|
|
59400
|
-
if (!schema4) return [];
|
|
59401
|
-
const out = [];
|
|
59402
|
-
for (const [key, sub] of gatherPropertySchemas(schema4)) {
|
|
59403
|
-
const budget = RETRY_BUDGET[manifestFragmentOf(sub) ?? ""];
|
|
59404
|
-
if (budget) out.push([key, budget]);
|
|
59405
|
-
}
|
|
59406
|
-
return out;
|
|
59407
|
-
}
|
|
59408
|
-
|
|
59409
59536
|
// ../../analyzer/nodejs/src/validate-nested-inline.ts
|
|
59410
59537
|
var SOURCE22 = "telo-analyzer";
|
|
59411
59538
|
function validateNestedInlineResources(manifest, rootSchema, lookupDefinition, allManifests, validator, implementationsOf) {
|
|
@@ -63448,10 +63575,31 @@ var StaticAnalyzer = class {
|
|
|
63448
63575
|
if (effectiveSchema) {
|
|
63449
63576
|
const stepName = m.metadata?.name;
|
|
63450
63577
|
const stepFile = m.metadata?.source;
|
|
63578
|
+
const expandedFieldMap = defs.expandedFieldMapForResource(m, aliases, aliasesByModule);
|
|
63579
|
+
for (const issue of collectReferenceOutputIssues(
|
|
63580
|
+
m,
|
|
63581
|
+
expandedFieldMap,
|
|
63582
|
+
allManifests,
|
|
63583
|
+
defs,
|
|
63584
|
+
aliases,
|
|
63585
|
+
{ aliasesByModule, rootModules }
|
|
63586
|
+
)) {
|
|
63587
|
+
diagnostics.push({
|
|
63588
|
+
severity: DiagnosticSeverity2.Error,
|
|
63589
|
+
code: "REFERENCE_OUTPUT_MISMATCH",
|
|
63590
|
+
source: SOURCE35,
|
|
63591
|
+
message: `${m.kind}/${stepName}: at '${issue.path}', ${issue.message}`,
|
|
63592
|
+
data: {
|
|
63593
|
+
resource: { kind: m.kind, name: stepName ?? "" },
|
|
63594
|
+
filePath: stepFile,
|
|
63595
|
+
path: issue.path
|
|
63596
|
+
}
|
|
63597
|
+
});
|
|
63598
|
+
}
|
|
63451
63599
|
const inputIssues = [
|
|
63452
63600
|
...collectRefInputIssues(
|
|
63453
63601
|
m,
|
|
63454
|
-
|
|
63602
|
+
expandedFieldMap,
|
|
63455
63603
|
allManifests,
|
|
63456
63604
|
defs,
|
|
63457
63605
|
aliases,
|
|
@@ -67160,9 +67308,11 @@ function unionLeaves(parent, leaves) {
|
|
|
67160
67308
|
return out;
|
|
67161
67309
|
}
|
|
67162
67310
|
function lookupRefConstraints(definitionSchema, yamlPath, schemaFrom) {
|
|
67311
|
+
return lookupRefSlot(definitionSchema, yamlPath, schemaFrom)?.kinds ?? [];
|
|
67312
|
+
}
|
|
67313
|
+
function lookupRefSlot(definitionSchema, yamlPath, schemaFrom) {
|
|
67163
67314
|
const node = navigateSchema2(definitionSchema, yamlPath, schemaFrom);
|
|
67164
|
-
|
|
67165
|
-
return readRefSlot(node)?.kinds ?? [];
|
|
67315
|
+
return node ? readRefSlot(node) : void 0;
|
|
67166
67316
|
}
|
|
67167
67317
|
function detectContext(text, line, character, docs) {
|
|
67168
67318
|
const resolved = resolveNodeAtPosition(text, docs ?? parseToAst(text), line, character);
|
|
@@ -67905,8 +68055,9 @@ function extractInFileResources(docs) {
|
|
|
67905
68055
|
}
|
|
67906
68056
|
return out;
|
|
67907
68057
|
}
|
|
67908
|
-
function refNameCompletions(docs, refKind,
|
|
68058
|
+
function refNameCompletions(docs, refKind, slot, registry, analysis, replaceRange) {
|
|
67909
68059
|
const resources = extractInFileResources(docs);
|
|
68060
|
+
const refConstraints = slot?.kinds ?? [];
|
|
67910
68061
|
let acceptable;
|
|
67911
68062
|
if (refKind) {
|
|
67912
68063
|
acceptable = /* @__PURE__ */ new Set([refKind]);
|
|
@@ -67920,6 +68071,7 @@ function refNameCompletions(docs, refKind, refConstraints, registry, replaceRang
|
|
|
67920
68071
|
const out = [];
|
|
67921
68072
|
for (const r of resources) {
|
|
67922
68073
|
if (acceptable && !acceptable.has(r.kind)) continue;
|
|
68074
|
+
if (slot && outputRefused(slot, r, registry, analysis)) continue;
|
|
67923
68075
|
if (seen.has(r.name)) continue;
|
|
67924
68076
|
seen.add(r.name);
|
|
67925
68077
|
out.push({
|
|
@@ -67933,18 +68085,25 @@ function refNameCompletions(docs, refKind, refConstraints, registry, replaceRang
|
|
|
67933
68085
|
}
|
|
67934
68086
|
return out;
|
|
67935
68087
|
}
|
|
68088
|
+
function outputRefused(slot, candidate, registry, analysis) {
|
|
68089
|
+
if (!slot.outputType) return false;
|
|
68090
|
+
const refusal = analysis ? analysis.outputRefusal(slot, { kind: candidate.kind, name: candidate.name }) : registry?.outputRefusal(slot, { kind: candidate.kind }) ?? [];
|
|
68091
|
+
return refusal.length > 0;
|
|
68092
|
+
}
|
|
67936
68093
|
function refConstrainedKinds(registry, parentDocKind, parentYamlPath) {
|
|
67937
68094
|
const definition = registry.resolveDefinition(parentDocKind);
|
|
67938
68095
|
if (!definition?.schema) return void 0;
|
|
67939
|
-
const
|
|
68096
|
+
const slot = lookupRefSlot(
|
|
67940
68097
|
definition.schema,
|
|
67941
68098
|
parentYamlPath,
|
|
67942
68099
|
(from) => registry.resolveSchemaFrom(from, parentDocKind)
|
|
67943
68100
|
);
|
|
67944
|
-
if (
|
|
67945
|
-
const resolved =
|
|
68101
|
+
if (!slot || slot.kinds.length === 0) return void 0;
|
|
68102
|
+
const resolved = slot.kinds.map((c) => registry.userFacingKindsForRef(c));
|
|
67946
68103
|
if (!resolved.some(Boolean)) return void 0;
|
|
67947
|
-
return [...new Set(resolved.flatMap((kinds) => kinds ?? []))]
|
|
68104
|
+
return [...new Set(resolved.flatMap((kinds) => kinds ?? []))].filter(
|
|
68105
|
+
(kind) => !outputRefused(slot, { kind }, registry, void 0)
|
|
68106
|
+
);
|
|
67948
68107
|
}
|
|
67949
68108
|
function kindCompletions(registry, docKind, yamlPath, replaceRange) {
|
|
67950
68109
|
let kinds;
|
|
@@ -68019,12 +68178,12 @@ async function buildCompletions(text, line, character, registry, adapter, docs,
|
|
|
68019
68178
|
}
|
|
68020
68179
|
if (ctx.type === "ref-name") {
|
|
68021
68180
|
const definition = registry?.resolveDefinition(ctx.docKind);
|
|
68022
|
-
const
|
|
68181
|
+
const slot = registry && definition?.schema ? lookupRefSlot(
|
|
68023
68182
|
definition.schema,
|
|
68024
68183
|
ctx.yamlPath,
|
|
68025
68184
|
(from) => registry.resolveSchemaFrom(from, ctx.docKind)
|
|
68026
|
-
) :
|
|
68027
|
-
return refNameCompletions(astDocs, ctx.refKind,
|
|
68185
|
+
) : void 0;
|
|
68186
|
+
return refNameCompletions(astDocs, ctx.refKind, slot, registry, analysis, ctx.replaceRange);
|
|
68028
68187
|
}
|
|
68029
68188
|
if (ctx.type === "field-value") {
|
|
68030
68189
|
if (ctx.field === "import-source") {
|