@telorun/analyzer 0.62.1 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/dist/analysis-registry.d.ts +24 -0
  2. package/dist/analysis-registry.d.ts.map +1 -1
  3. package/dist/analysis-registry.js +41 -0
  4. package/dist/analyzer.d.ts +3 -37
  5. package/dist/analyzer.d.ts.map +1 -1
  6. package/dist/analyzer.js +396 -476
  7. package/dist/call-graph.d.ts.map +1 -1
  8. package/dist/call-graph.js +2 -7
  9. package/dist/cel-scope-query.d.ts +109 -0
  10. package/dist/cel-scope-query.d.ts.map +1 -0
  11. package/dist/cel-scope-query.js +270 -0
  12. package/dist/cel-scope.d.ts +166 -0
  13. package/dist/cel-scope.d.ts.map +1 -0
  14. package/dist/cel-scope.js +377 -0
  15. package/dist/definition-registry.d.ts +15 -0
  16. package/dist/definition-registry.d.ts.map +1 -1
  17. package/dist/definition-registry.js +25 -9
  18. package/dist/find-manifest.d.ts +10 -0
  19. package/dist/find-manifest.d.ts.map +1 -0
  20. package/dist/find-manifest.js +12 -0
  21. package/dist/flatten-for-analyzer.js +1 -1
  22. package/dist/import-resolution-diagnostics.d.ts +9 -2
  23. package/dist/import-resolution-diagnostics.d.ts.map +1 -1
  24. package/dist/import-resolution-diagnostics.js +26 -7
  25. package/dist/index.d.ts +22 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +22 -1
  28. package/dist/invocation-contract.d.ts +17 -1
  29. package/dist/invocation-contract.d.ts.map +1 -1
  30. package/dist/invocation-contract.js +42 -4
  31. package/dist/loaded-types.d.ts +12 -3
  32. package/dist/loaded-types.d.ts.map +1 -1
  33. package/dist/manifest-analysis.d.ts +73 -0
  34. package/dist/manifest-analysis.d.ts.map +1 -0
  35. package/dist/manifest-analysis.js +78 -0
  36. package/dist/manifest-loader.d.ts +0 -1
  37. package/dist/manifest-loader.d.ts.map +1 -1
  38. package/dist/manifest-loader.js +62 -41
  39. package/dist/manifest-path.d.ts +18 -0
  40. package/dist/manifest-path.d.ts.map +1 -0
  41. package/dist/manifest-path.js +37 -0
  42. package/dist/manifest-schemas.d.ts +699 -0
  43. package/dist/manifest-schemas.d.ts.map +1 -1
  44. package/dist/manifest-schemas.js +306 -14
  45. package/dist/module-compatibility.d.ts +40 -0
  46. package/dist/module-compatibility.d.ts.map +1 -0
  47. package/dist/module-compatibility.js +52 -0
  48. package/dist/ref-slot-reading.d.ts +30 -0
  49. package/dist/ref-slot-reading.d.ts.map +1 -0
  50. package/dist/ref-slot-reading.js +139 -0
  51. package/dist/referrer-rule.d.ts +67 -0
  52. package/dist/referrer-rule.d.ts.map +1 -0
  53. package/dist/referrer-rule.js +96 -0
  54. package/dist/release/index.d.ts +1 -1
  55. package/dist/release/index.d.ts.map +1 -1
  56. package/dist/release/index.js +1 -1
  57. package/dist/release/version-stamp.d.ts +16 -0
  58. package/dist/release/version-stamp.d.ts.map +1 -1
  59. package/dist/release/version-stamp.js +52 -0
  60. package/dist/release/workspace-config.d.ts +10 -6
  61. package/dist/release/workspace-config.d.ts.map +1 -1
  62. package/dist/release/workspace-config.js +10 -6
  63. package/dist/resolve-schema-ref-kinds.d.ts +4 -3
  64. package/dist/resolve-schema-ref-kinds.d.ts.map +1 -1
  65. package/dist/resolve-schema-ref-kinds.js +16 -0
  66. package/dist/resolve-throws-union.d.ts.map +1 -1
  67. package/dist/resolve-throws-union.js +4 -3
  68. package/dist/resolve-zone-containment.d.ts +99 -0
  69. package/dist/resolve-zone-containment.d.ts.map +1 -0
  70. package/dist/resolve-zone-containment.js +212 -0
  71. package/dist/resolve-zone-requirements.d.ts +5 -0
  72. package/dist/resolve-zone-requirements.d.ts.map +1 -1
  73. package/dist/resolve-zone-requirements.js +48 -7
  74. package/dist/resource-rule.d.ts +106 -0
  75. package/dist/resource-rule.d.ts.map +1 -0
  76. package/dist/resource-rule.js +236 -0
  77. package/dist/rule-condition.d.ts +50 -0
  78. package/dist/rule-condition.d.ts.map +1 -0
  79. package/dist/rule-condition.js +108 -0
  80. package/dist/schema-keywords.d.ts.map +1 -1
  81. package/dist/schema-keywords.js +20 -0
  82. package/dist/schema-projection.d.ts +171 -0
  83. package/dist/schema-projection.d.ts.map +1 -0
  84. package/dist/schema-projection.js +317 -0
  85. package/dist/schema-walk.d.ts +25 -0
  86. package/dist/schema-walk.d.ts.map +1 -0
  87. package/dist/schema-walk.js +126 -0
  88. package/dist/step-slot.d.ts +39 -0
  89. package/dist/step-slot.d.ts.map +1 -0
  90. package/dist/step-slot.js +49 -0
  91. package/dist/telo-version.d.ts +1 -1
  92. package/dist/telo-version.js +1 -1
  93. package/dist/validate-cel-context.d.ts.map +1 -1
  94. package/dist/validate-cel-context.js +17 -3
  95. package/dist/validate-durable-regions.d.ts +15 -0
  96. package/dist/validate-durable-regions.d.ts.map +1 -0
  97. package/dist/validate-durable-regions.js +336 -0
  98. package/dist/validate-references.d.ts.map +1 -1
  99. package/dist/validate-references.js +44 -2
  100. package/dist/validate-referrer-rules.d.ts +120 -0
  101. package/dist/validate-referrer-rules.d.ts.map +1 -0
  102. package/dist/validate-referrer-rules.js +255 -0
  103. package/dist/validate-resource-rules.d.ts +114 -0
  104. package/dist/validate-resource-rules.d.ts.map +1 -0
  105. package/dist/validate-resource-rules.js +283 -0
  106. package/dist/validate-schema-projection.d.ts +32 -0
  107. package/dist/validate-schema-projection.d.ts.map +1 -0
  108. package/dist/validate-schema-projection.js +110 -0
  109. package/dist/validate-step-inputs.d.ts +19 -1
  110. package/dist/validate-step-inputs.d.ts.map +1 -1
  111. package/dist/validate-step-inputs.js +102 -9
  112. package/dist/validate-throws-coverage.d.ts.map +1 -1
  113. package/dist/validate-throws-coverage.js +11 -5
  114. package/dist/validate-zone-slots.d.ts +2 -2
  115. package/dist/validate-zone-slots.d.ts.map +1 -1
  116. package/dist/validate-zone-slots.js +202 -6
  117. package/dist/validate-zone-violations.d.ts +12 -0
  118. package/dist/validate-zone-violations.d.ts.map +1 -0
  119. package/dist/validate-zone-violations.js +169 -0
  120. package/dist/value-type-keyword.d.ts +1 -1
  121. package/dist/value-type-keyword.d.ts.map +1 -1
  122. package/dist/value-type-keyword.js +4 -0
  123. package/dist/zone-slot.d.ts +61 -0
  124. package/dist/zone-slot.d.ts.map +1 -1
  125. package/dist/zone-slot.js +86 -5
  126. package/package.json +2 -2
  127. package/src/analysis-registry.ts +43 -0
  128. package/src/analyzer.ts +452 -595
  129. package/src/call-graph.ts +2 -8
  130. package/src/cel-scope-query.ts +337 -0
  131. package/src/cel-scope.ts +570 -0
  132. package/src/definition-registry.ts +31 -13
  133. package/src/find-manifest.ts +19 -0
  134. package/src/flatten-for-analyzer.ts +1 -1
  135. package/src/import-resolution-diagnostics.ts +25 -7
  136. package/src/index.ts +86 -0
  137. package/src/invocation-contract.ts +67 -2
  138. package/src/loaded-types.ts +12 -3
  139. package/src/manifest-analysis.ts +132 -0
  140. package/src/manifest-loader.ts +87 -55
  141. package/src/manifest-path.ts +34 -0
  142. package/src/manifest-schemas.ts +328 -14
  143. package/src/module-compatibility.ts +72 -0
  144. package/src/ref-slot-reading.ts +156 -0
  145. package/src/referrer-rule.ts +116 -0
  146. package/src/release/index.ts +1 -0
  147. package/src/release/version-stamp.ts +58 -0
  148. package/src/release/workspace-config.ts +10 -6
  149. package/src/resolve-schema-ref-kinds.ts +28 -4
  150. package/src/resolve-throws-union.ts +4 -3
  151. package/src/resolve-zone-containment.ts +329 -0
  152. package/src/resolve-zone-requirements.ts +67 -7
  153. package/src/resource-rule.ts +252 -0
  154. package/src/rule-condition.ts +126 -0
  155. package/src/schema-keywords.ts +24 -0
  156. package/src/schema-projection.ts +403 -0
  157. package/src/schema-walk.ts +144 -0
  158. package/src/step-slot.ts +64 -0
  159. package/src/telo-version.ts +1 -1
  160. package/src/validate-cel-context.ts +17 -3
  161. package/src/validate-durable-regions.ts +401 -0
  162. package/src/validate-references.ts +57 -2
  163. package/src/validate-referrer-rules.ts +373 -0
  164. package/src/validate-resource-rules.ts +401 -0
  165. package/src/validate-schema-projection.ts +184 -0
  166. package/src/validate-step-inputs.ts +148 -10
  167. package/src/validate-throws-coverage.ts +12 -5
  168. package/src/validate-zone-slots.ts +192 -8
  169. package/src/validate-zone-violations.ts +190 -0
  170. package/src/value-type-keyword.ts +4 -0
  171. package/src/zone-slot.ts +114 -5
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Static validation of the schema-projection annotations themselves — the
3
+ * strict half of the accessor split, mirroring `validate-ref-slots.ts` and
4
+ * `validate-zone-slots.ts`.
5
+ *
6
+ * `readSchemaProjection` / `readSchemaMap` are deliberately lenient: anything
7
+ * they cannot read reads as absent. Without this pass that leniency is silent in
8
+ * the direction that matters — a projection nothing can read does not fail, it
9
+ * simply stops typing the consumers that were counting on it, so a misspelled
10
+ * column reaches the database instead of `telo check`. The whole point of the
11
+ * projection is to move that failure earlier; an unreported malformed
12
+ * declaration puts it back.
13
+ *
14
+ * A map that is merely INCOMPLETE is the same failure per value: a declared type
15
+ * with no entry projects to nothing, so a column of that type silently vanishes
16
+ * from every consumer's view of the row.
17
+ *
18
+ * Scoping follows `X_TELO_REF_UNRESOLVED`: reported only for definitions in the
19
+ * entry's own modules — a published dependency's annotation is not the
20
+ * consumer's to fix.
21
+ *
22
+ * Browser-safe: no Node built-ins.
23
+ */
24
+ import type { ResourceManifest } from "@telorun/sdk";
25
+ export interface SchemaProjectionIssue {
26
+ code: "SCHEMA_PROJECTION_INVALID" | "SCHEMA_MAP_INCOMPLETE";
27
+ manifest: ResourceManifest;
28
+ path: string;
29
+ message: string;
30
+ }
31
+ export declare function validateSchemaProjection(manifest: ResourceManifest): SchemaProjectionIssue[];
32
+ //# sourceMappingURL=validate-schema-projection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-schema-projection.d.ts","sourceRoot":"","sources":["../src/validate-schema-projection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAQrD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,2BAA2B,GAAG,uBAAuB,CAAC;IAC5D,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAQD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,qBAAqB,EAAE,CA2G5F"}
@@ -0,0 +1,110 @@
1
+ import { projectionKeyMap, rawSchemaProjection, readSchemaProjection, schemaProjectionIsMisplaced, } from "./schema-projection.js";
2
+ const PROJECTION = "x-telo-schema-projection";
3
+ function isObject(value) {
4
+ return !!value && typeof value === "object" && !Array.isArray(value);
5
+ }
6
+ export function validateSchemaProjection(manifest) {
7
+ const doc = manifest;
8
+ const raw = rawSchemaProjection(doc);
9
+ if (raw === undefined)
10
+ return [];
11
+ const misplaced = schemaProjectionIsMisplaced(doc);
12
+ const base = misplaced ? `schema.${PROJECTION}` : PROJECTION;
13
+ const issue = (code, path, message) => ({ code, manifest, path, message });
14
+ const issues = [];
15
+ // Read from both positions so a misplaced annotation still WORKS, and
16
+ // reported so it does not stay misplaced. The alternative — reading only the
17
+ // document — makes the inner spelling silently inert, and the resulting
18
+ // failure surfaces on a consumer's slot as "this kind declares no projection",
19
+ // which blames an author who wrote the annotation correctly enough to mean it.
20
+ if (misplaced) {
21
+ issues.push(issue("SCHEMA_PROJECTION_INVALID", base, `'${PROJECTION}' belongs on the kind DOCUMENT, beside 'schema:', not inside it — ` +
22
+ `it describes the whole declaration rather than one field. It is read from here ` +
23
+ `too, so nothing is broken; move it up a level.`));
24
+ }
25
+ if (!isObject(raw)) {
26
+ return [
27
+ ...issues,
28
+ issue("SCHEMA_PROJECTION_INVALID", base, `'${PROJECTION}' must be an object naming the entry collection and the field that keys it.`),
29
+ ];
30
+ }
31
+ const missing = ["entries", "key"].filter((field) => typeof raw[field] !== "string");
32
+ if (missing.length > 0) {
33
+ return [
34
+ ...issues,
35
+ issue("SCHEMA_PROJECTION_INVALID", base, `'${PROJECTION}' is missing ${missing.map((f) => `'${f}'`).join(" and ")}. ` +
36
+ `'entries' is a JSON Pointer to the collection, 'key' the entry field whose value ` +
37
+ `selects an 'x-telo-schema-map' entry.`),
38
+ ];
39
+ }
40
+ const projection = readSchemaProjection(doc);
41
+ const schema = doc.schema;
42
+ // An ARRAY-shaped collection has no key to name its entries by, so without
43
+ // `name` every entry projects to nothing and the whole projection is an object
44
+ // schema with no properties and `additionalProperties: false` — one that
45
+ // rejects every value. A keyed map needs no `name`: the map key IS the
46
+ // identity.
47
+ if (collectionIsArray(schema, projection.entries) && !projection.nameField) {
48
+ return [
49
+ ...issues,
50
+ issue("SCHEMA_PROJECTION_INVALID", base, `'${PROJECTION}' names '${projection.entries}', which is an array, but declares no ` +
51
+ `'name'. An array's entries have no key, so 'name' must say which field holds an ` +
52
+ `entry's identity — without it the projection yields a schema that rejects every value.`),
53
+ ];
54
+ }
55
+ const map = projectionKeyMap(schema, projection);
56
+ if (!map) {
57
+ return [
58
+ ...issues,
59
+ issue("SCHEMA_PROJECTION_INVALID", base, `'${PROJECTION}' names '${projection.entries}' keyed on '${projection.key}', but that ` +
60
+ `field carries no 'x-telo-schema-map'. The map declares the JSON Schema each of its ` +
61
+ `values means, and without it the projection types nothing.`),
62
+ ];
63
+ }
64
+ // An `enum` on the keyed field is the kind's own closed vocabulary, so every
65
+ // member of it is a value the map has to answer for. Only an enum is checked:
66
+ // an open string field has no set to be complete against.
67
+ const keyField = keySchema(schema, projection.entries, projection.key);
68
+ const values = Array.isArray(keyField?.enum) ? keyField.enum : [];
69
+ const unmapped = values.filter((value) => typeof value === "string" && !(value in map));
70
+ if (unmapped.length === 0)
71
+ return issues;
72
+ return [
73
+ ...issues,
74
+ issue("SCHEMA_MAP_INCOMPLETE", base, `'x-telo-schema-map' has no entry for ${unmapped.map((v) => `'${v}'`).join(", ")}. ` +
75
+ `An entry declaring an unmapped value projects to nothing, so it disappears from every ` +
76
+ `consumer's view of the shape.`),
77
+ ];
78
+ }
79
+ function collectionIsArray(schema, entries) {
80
+ let node = schema;
81
+ for (const segment of entries.split("/")) {
82
+ if (segment === "")
83
+ continue;
84
+ if (!isObject(node) || !isObject(node.properties))
85
+ return false;
86
+ node = node.properties[segment];
87
+ }
88
+ return isObject(node) && isObject(node.items);
89
+ }
90
+ function keySchema(schema, entries, key) {
91
+ let node = schema;
92
+ for (const segment of entries.split("/")) {
93
+ if (segment === "")
94
+ continue;
95
+ if (!isObject(node) || !isObject(node.properties))
96
+ return undefined;
97
+ node = node.properties[segment];
98
+ }
99
+ if (!isObject(node))
100
+ return undefined;
101
+ const entry = isObject(node.additionalProperties)
102
+ ? node.additionalProperties
103
+ : isObject(node.items)
104
+ ? node.items
105
+ : undefined;
106
+ if (!isObject(entry) || !isObject(entry.properties))
107
+ return undefined;
108
+ const field = entry.properties[key];
109
+ return isObject(field) ? field : undefined;
110
+ }
@@ -1,5 +1,6 @@
1
1
  import type { AliasResolver, ModuleScopes } from "./alias-resolver.js";
2
2
  import type { DefinitionRegistry } from "./definition-registry.js";
3
+ import { type ReferenceFieldMap } from "./reference-field-map.js";
3
4
  export interface StepInputIssue {
4
5
  path: string;
5
6
  targetLabel: string;
@@ -20,7 +21,8 @@ export interface StepInputIssue {
20
21
  * CEL leaves are replaced by schema-shaped placeholders first (`substituteCelFields`),
21
22
  * so an expression is never a false positive — only structural disagreement is
22
23
  * reported. Nothing is hardcoded about `Run.Sequence`: the invoke field comes
23
- * from `x-telo-step-context`, and the paired inputs field from whichever sibling
24
+ * from the step slot (the shared grammar, or the legacy `x-telo-step-context`),
25
+ * and the paired inputs field from whichever sibling
24
26
  * property carries `x-telo-topology-role: inputs`.
25
27
  */
26
28
  export declare function collectStepInputIssues(manifest: Record<string, any>, defSchema: Record<string, any>, allManifests: Record<string, any>[], defs: DefinitionRegistry, aliases: AliasResolver, scopes: ModuleScopes,
@@ -28,4 +30,20 @@ export declare function collectStepInputIssues(manifest: Record<string, any>, de
28
30
  * caller because building it is analyzer state; without it the contract check
29
31
  * still runs and only the type-argument comparison is skipped. */
30
32
  stepContext?: Record<string, any>): StepInputIssue[];
33
+ /**
34
+ * Validate the argument map of every call this resource makes through a
35
+ * REFERENCE SLOT, as opposed to a step.
36
+ *
37
+ * A slot that transfers control names its argument slot on its own `x-telo-ref`
38
+ * (`inputs:`, a JSON Pointer relative to the object enclosing the slot). That
39
+ * annotation is the only thing tying an otherwise-open `inputs:` map to the
40
+ * resource it holds arguments for — an HTTP route's `handler:` + `inputs:` pair
41
+ * is exactly this shape, and nothing about it is a step.
42
+ *
43
+ * Discovery is driven by the annotation rather than by any kind's topology, so
44
+ * a composer that names its argument slot gets its call sites checked without
45
+ * the analyzer learning what a route is. It is the same check the step driver
46
+ * runs, because it is the same question.
47
+ */
48
+ export declare function collectRefInputIssues(manifest: Record<string, any>, fieldMap: ReferenceFieldMap | undefined, allManifests: Record<string, any>[], defs: DefinitionRegistry, aliases: AliasResolver, scopes: ModuleScopes): StepInputIssue[];
31
49
  //# sourceMappingURL=validate-step-inputs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate-step-inputs.d.ts","sourceRoot":"","sources":["../src/validate-step-inputs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAqBnE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB;iFAC6E;IAC7E,IAAI,CAAC,EAAE,4BAA4B,GAAG,oBAAoB,CAAC;CAC5D;AAGD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC9B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EACnC,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,YAAY;AACpB;;mEAEmE;AACnE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAChC,cAAc,EAAE,CAsJlB"}
1
+ {"version":3,"file":"validate-step-inputs.d.ts","sourceRoot":"","sources":["../src/validate-step-inputs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAsBnE,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB;iFAC6E;IAC7E,IAAI,CAAC,EAAE,4BAA4B,GAAG,oBAAoB,CAAC;CAC5D;AAGD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC9B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EACnC,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,YAAY;AACpB;;mEAEmE;AACnE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAChC,cAAc,EAAE,CA4DlB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC7B,QAAQ,EAAE,iBAAiB,GAAG,SAAS,EACvC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EACnC,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,YAAY,GACnB,cAAc,EAAE,CAoClB"}
@@ -4,6 +4,9 @@ import { plainChainOf } from "@telorun/templating";
4
4
  import { isLiveSlot, valueTypeOf } from "@telorun/sdk";
5
5
  import { manifestFragmentOf } from "./manifest-schemas.js";
6
6
  import { analyzerContractScope, containerOf, gatherPropertySchemas, missingRequired, resolveLocalRef, walkStepArray, } from "./analyzer.js";
7
+ import { readStepSlot } from "./step-slot.js";
8
+ import { navigateConcretePath } from "./manifest-path.js";
9
+ import { isRefEntry, resolveFieldEntries, } from "./reference-field-map.js";
7
10
  /**
8
11
  * Validate every step's `inputs:` against the invoked target's declared input
9
12
  * contract — the static half of what the kernel enforces at dispatch.
@@ -16,7 +19,8 @@ import { analyzerContractScope, containerOf, gatherPropertySchemas, missingRequi
16
19
  * CEL leaves are replaced by schema-shaped placeholders first (`substituteCelFields`),
17
20
  * so an expression is never a false positive — only structural disagreement is
18
21
  * reported. Nothing is hardcoded about `Run.Sequence`: the invoke field comes
19
- * from `x-telo-step-context`, and the paired inputs field from whichever sibling
22
+ * from the step slot (the shared grammar, or the legacy `x-telo-step-context`),
23
+ * and the paired inputs field from whichever sibling
20
24
  * property carries `x-telo-topology-role: inputs`.
21
25
  */
22
26
  export function collectStepInputIssues(manifest, defSchema, allManifests, defs, aliases, scopes,
@@ -30,9 +34,17 @@ stepContext) {
30
34
  return out;
31
35
  const contractScope = analyzerContractScope(defs, aliases, scopes, allManifests);
32
36
  const readingModule = manifest.metadata?.module;
37
+ const ctx = {
38
+ manifest,
39
+ allManifests,
40
+ defs,
41
+ contractScope,
42
+ readingModule,
43
+ stepContext,
44
+ };
33
45
  for (const [fieldName, fieldSchema] of Object.entries(props)) {
34
- const stepCtx = fieldSchema["x-telo-step-context"];
35
- if (!stepCtx?.invoke)
46
+ const stepCtx = readStepSlot(fieldSchema);
47
+ if (!stepCtx)
36
48
  continue;
37
49
  const steps = manifest[fieldName];
38
50
  if (!Array.isArray(steps))
@@ -56,6 +68,87 @@ stepContext) {
56
68
  return;
57
69
  if (!values || typeof values !== "object" || Array.isArray(values))
58
70
  return;
71
+ out.push(...checkCallSite({
72
+ inputsPath: `${stepPath}.${inputsField}`,
73
+ values: values,
74
+ invoke,
75
+ // Only a step declares a re-attempt policy, so only a step can carry
76
+ // the live-value-retried finding.
77
+ declaredRetryFor: (invokedManifest, invokedDef) => declaredRetry(step, stepItemSchema, invokedManifest, invokedDef),
78
+ }, ctx));
79
+ });
80
+ }
81
+ return out;
82
+ }
83
+ /**
84
+ * Validate the argument map of every call this resource makes through a
85
+ * REFERENCE SLOT, as opposed to a step.
86
+ *
87
+ * A slot that transfers control names its argument slot on its own `x-telo-ref`
88
+ * (`inputs:`, a JSON Pointer relative to the object enclosing the slot). That
89
+ * annotation is the only thing tying an otherwise-open `inputs:` map to the
90
+ * resource it holds arguments for — an HTTP route's `handler:` + `inputs:` pair
91
+ * is exactly this shape, and nothing about it is a step.
92
+ *
93
+ * Discovery is driven by the annotation rather than by any kind's topology, so
94
+ * a composer that names its argument slot gets its call sites checked without
95
+ * the analyzer learning what a route is. It is the same check the step driver
96
+ * runs, because it is the same question.
97
+ */
98
+ export function collectRefInputIssues(manifest, fieldMap, allManifests, defs, aliases, scopes) {
99
+ const out = [];
100
+ if (!fieldMap)
101
+ return out;
102
+ const contractScope = analyzerContractScope(defs, aliases, scopes, allManifests);
103
+ const ctx = {
104
+ manifest,
105
+ allManifests,
106
+ defs,
107
+ contractScope,
108
+ readingModule: manifest.metadata?.module,
109
+ };
110
+ for (const [fieldPath, entry] of fieldMap) {
111
+ if (!isRefEntry(entry) || !entry.inputs)
112
+ continue;
113
+ const pointer = pointerSegments(entry.inputs);
114
+ if (!pointer)
115
+ continue;
116
+ for (const { value: invoke, path: slotPath } of resolveFieldEntries(manifest, fieldPath)) {
117
+ if (!invoke || typeof invoke !== "object" || Array.isArray(invoke))
118
+ continue;
119
+ // Relative to the object ENCLOSING the slot, which is the annotation's
120
+ // documented anchor.
121
+ const enclosing = slotPath.slice(0, Math.max(0, slotPath.lastIndexOf(".")));
122
+ const inputsPath = [enclosing, ...pointer].filter(Boolean).join(".");
123
+ const values = navigateConcretePath(manifest, inputsPath);
124
+ if (!values || typeof values !== "object" || Array.isArray(values))
125
+ continue;
126
+ out.push(...checkCallSite({ inputsPath, values: values, invoke: invoke }, ctx));
127
+ }
128
+ }
129
+ return out;
130
+ }
131
+ /** A JSON Pointer naming a sibling FIELD path. An array index is not a field,
132
+ * so a pointer carrying one names nothing this can resolve. */
133
+ function pointerSegments(pointer) {
134
+ if (!pointer.startsWith("/"))
135
+ return undefined;
136
+ const segments = pointer
137
+ .slice(1)
138
+ .split("/")
139
+ .map((s) => s.replace(/~1/g, "/").replace(/~0/g, "~"));
140
+ return segments.every((s) => s.length > 0 && !/^\d+$/.test(s)) ? segments : undefined;
141
+ }
142
+ /**
143
+ * The check itself, shared by both drivers: the arguments written at a call site
144
+ * against the contract the target declares.
145
+ */
146
+ function checkCallSite(site, ctx) {
147
+ const out = [];
148
+ const { manifest, allManifests, defs, contractScope, readingModule, stepContext } = ctx;
149
+ const { invoke, values } = site;
150
+ {
151
+ {
59
152
  const invokedKind = invoke.kind;
60
153
  const invokedName = invoke.name;
61
154
  const invokedManifest = invokedName
@@ -66,7 +159,7 @@ stepContext) {
66
159
  : undefined;
67
160
  const contract = resolveContract("inputType", invokedManifest, invokedDef, contractScope);
68
161
  if (!contract)
69
- return;
162
+ return out;
70
163
  // Findings AT a substituted path are about a placeholder, not about
71
164
  // anything the author wrote — a `pattern`-constrained string or a `oneOf`
72
165
  // of unrelated shapes cannot be satisfied by any stand-in. Structural
@@ -118,10 +211,10 @@ stepContext) {
118
211
  // already declared: the value's liveness by its value type, and the
119
212
  // re-attempt by the retry policy. No kind is named.
120
213
  if (isLiveSlot(produced)) {
121
- const retry = declaredRetry(step, stepItemSchema, invokedManifest, invokedDef);
214
+ const retry = site.declaredRetryFor?.(invokedManifest, invokedDef);
122
215
  if (retry !== undefined) {
123
216
  out.push({
124
- path: `${stepPath}.${inputsField}.${inputName}`,
217
+ path: `${site.inputsPath}.${inputName}`,
125
218
  targetLabel: invokedName ?? invokedKind ?? "the invoked resource",
126
219
  message: `'${inputName}' is a live value, which is consumed by reading and so exists ` +
127
220
  `once — but ${retry} re-attempts the dispatch, and a re-attempt would pass ` +
@@ -138,7 +231,7 @@ stepContext) {
138
231
  if (compatible)
139
232
  continue;
140
233
  out.push({
141
- path: `${stepPath}.${inputsField}.${inputName}`,
234
+ path: `${site.inputsPath}.${inputName}`,
142
235
  targetLabel: invokedName ?? invokedKind ?? "the invoked resource",
143
236
  message: issues.join("; "),
144
237
  code: "CEL_TYPE_ARGUMENT_MISMATCH",
@@ -154,12 +247,12 @@ stepContext) {
154
247
  // container that should have held it, which does exist.
155
248
  const anchor = missingRequired(issue) ? containerOf(issue.path) : issue.path;
156
249
  out.push({
157
- path: anchor ? `${stepPath}.${inputsField}.${anchor}` : `${stepPath}.${inputsField}`,
250
+ path: anchor ? `${site.inputsPath}.${anchor}` : site.inputsPath,
158
251
  targetLabel: invokedName ?? invokedKind ?? "the invoked resource",
159
252
  message: issue.message,
160
253
  });
161
254
  }
162
- });
255
+ }
163
256
  }
164
257
  return out;
165
258
  }
@@ -1 +1 @@
1
- {"version":3,"file":"validate-throws-coverage.d.ts","sourceRoot":"","sources":["../src/validate-throws-coverage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAOnE,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA+ezE,oDAAoD;AACpD,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,WAAW,EAChB,eAAe,GAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAa,EACvD,WAAW,GAAE,GAAG,CAAC,MAAM,CAAa,GACnC,kBAAkB,EAAE,CAkDtB"}
1
+ {"version":3,"file":"validate-throws-coverage.d.ts","sourceRoot":"","sources":["../src/validate-throws-coverage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAOnE,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAsfzE,oDAAoD;AACpD,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,WAAW,EAChB,eAAe,GAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAa,EACvD,WAAW,GAAE,GAAG,CAAC,MAAM,CAAa,GACnC,kBAAkB,EAAE,CAkDtB"}
@@ -4,6 +4,7 @@ import { scopeResolverForModule } from "./alias-resolver.js";
4
4
  import { createResolveCtx, resolveThrowsUnion, } from "./resolve-throws-union.js";
5
5
  import { DiagnosticSeverity } from "./types.js";
6
6
  import { extractAccessChains, validateChainAgainstSchema } from "./validate-cel-context.js";
7
+ import { isStepSlot } from "./step-slot.js";
7
8
  const SOURCE = "telo-analyzer";
8
9
  const TEMPLATE_REGEX = /\$\{\{\s*([^}]+?)\s*\}\}/g;
9
10
  /** Walk `definition.schema` and `data` in tandem, invoking `onOutcome` each
@@ -366,9 +367,11 @@ function checkCelChainAgainstDataSchema(entry, dataSchema, resource, filePath, e
366
367
  return diagnostics;
367
368
  }
368
369
  /** Rule 8 extension: `inherit: true` only makes sense on a definition whose
369
- * schema contains at least one `x-telo-step-context` array — the annotation
370
- * that drives the resolver's generic step traversal. A definition with
371
- * `inherit: true` and no such array has no invocables to inherit from. */
370
+ * schema declares at least one STEP BODYan array whose items point at the
371
+ * shared grammar, or, for a module published before that fragment existed, one
372
+ * carrying the legacy `x-telo-step-context` annotation. That is what drives the
373
+ * resolver's generic step traversal; a definition with `inherit: true` and no
374
+ * such array has no invocables to inherit from. */
372
375
  function validateThrowsDeclarations(manifests) {
373
376
  const diagnostics = [];
374
377
  for (const m of manifests) {
@@ -386,7 +389,10 @@ function validateThrowsDeclarations(manifests) {
386
389
  severity: DiagnosticSeverity.Error,
387
390
  code: "INHERIT_WITHOUT_STEP_CONTEXT",
388
391
  source: SOURCE,
389
- message: `Telo.Definition '${name}' declares throws.inherit: true but its schema has no field annotated with x-telo-step-context. inherit is only meaningful on definitions that drive invocables via step arrays.`,
392
+ message: `Telo.Definition '${name}' declares throws.inherit: true but its schema declares no step ` +
393
+ `body. inherit is only meaningful on a definition that drives invocables through steps — ` +
394
+ `give an array field 'items: { $ref: "telo://manifest#/$defs/Step" }' (the legacy ` +
395
+ `x-telo-step-context annotation is also recognised).`,
390
396
  data: { resource: { kind: m.kind, name }, filePath, path: "throws.inherit" },
391
397
  });
392
398
  }
@@ -397,7 +403,7 @@ function validateThrowsDeclarations(manifests) {
397
403
  function schemaHasStepContext(schema) {
398
404
  if (!schema || typeof schema !== "object")
399
405
  return false;
400
- if ("x-telo-step-context" in schema)
406
+ if (isStepSlot(schema))
401
407
  return true;
402
408
  const props = schema.properties;
403
409
  if (props && typeof props === "object") {
@@ -26,9 +26,9 @@
26
26
  *
27
27
  * Browser-safe: no Node built-ins.
28
28
  */
29
- import type { ResourceManifest } from "@telorun/sdk";
29
+ import { type ResourceManifest } from "@telorun/sdk";
30
30
  export interface ZoneSlotIssue {
31
- code: "ZONE_ANNOTATION_INVALID";
31
+ code: "ZONE_ANNOTATION_INVALID" | "ZONE_ATTRIBUTE_UNKNOWN" | "ZONE_ATTRIBUTE_INCOMPLETE";
32
32
  manifest: ResourceManifest;
33
33
  /** Schema path of the annotated slot. */
34
34
  path: string;
@@ -1 +1 @@
1
- {"version":3,"file":"validate-zone-slots.d.ts","sourceRoot":"","sources":["../src/validate-zone-slots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,yBAAyB,CAAC;IAChC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAmID,iFAAiF;AACjF,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,gBAAgB,GAAG,aAAa,EAAE,CAM1F"}
1
+ {"version":3,"file":"validate-zone-slots.d.ts","sourceRoot":"","sources":["../src/validate-zone-slots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAuC,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAG1F,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,yBAAyB,GAAG,wBAAwB,GAAG,2BAA2B,CAAC;IACzF,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AA0TD,iFAAiF;AACjF,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,gBAAgB,GAAG,aAAa,EAAE,CAM1F"}