@telorun/analyzer 0.53.0 → 0.55.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 (76) hide show
  1. package/dist/analysis-registry.d.ts +20 -0
  2. package/dist/analysis-registry.d.ts.map +1 -1
  3. package/dist/analysis-registry.js +36 -3
  4. package/dist/analyzer.d.ts +3 -2
  5. package/dist/analyzer.d.ts.map +1 -1
  6. package/dist/analyzer.js +188 -26
  7. package/dist/builtins.d.ts.map +1 -1
  8. package/dist/builtins.js +32 -12
  9. package/dist/call-graph.d.ts +189 -0
  10. package/dist/call-graph.d.ts.map +1 -0
  11. package/dist/call-graph.js +617 -0
  12. package/dist/dependency-graph.d.ts +17 -7
  13. package/dist/dependency-graph.d.ts.map +1 -1
  14. package/dist/dependency-graph.js +36 -65
  15. package/dist/flatten-for-analyzer.d.ts +8 -0
  16. package/dist/flatten-for-analyzer.d.ts.map +1 -1
  17. package/dist/flatten-for-analyzer.js +32 -0
  18. package/dist/index.d.ts +14 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +7 -1
  21. package/dist/manifest-navigation.d.ts +32 -0
  22. package/dist/manifest-navigation.d.ts.map +1 -0
  23. package/dist/manifest-navigation.js +91 -0
  24. package/dist/manifest-visitor.js +1 -1
  25. package/dist/ref-slot.d.ts +125 -0
  26. package/dist/ref-slot.d.ts.map +1 -0
  27. package/dist/ref-slot.js +226 -0
  28. package/dist/reference-field-map.d.ts +15 -1
  29. package/dist/reference-field-map.d.ts.map +1 -1
  30. package/dist/reference-field-map.js +29 -35
  31. package/dist/resolve-schema-ref-kinds.d.ts +4 -0
  32. package/dist/resolve-schema-ref-kinds.d.ts.map +1 -1
  33. package/dist/resolve-schema-ref-kinds.js +31 -8
  34. package/dist/resolve-zone-requirements.d.ts +110 -0
  35. package/dist/resolve-zone-requirements.d.ts.map +1 -0
  36. package/dist/resolve-zone-requirements.js +541 -0
  37. package/dist/types.d.ts +8 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/validate-observed-state.d.ts +14 -13
  40. package/dist/validate-observed-state.d.ts.map +1 -1
  41. package/dist/validate-observed-state.js +21 -88
  42. package/dist/validate-ref-slots.d.ts +48 -0
  43. package/dist/validate-ref-slots.d.ts.map +1 -0
  44. package/dist/validate-ref-slots.js +219 -0
  45. package/dist/validate-references.d.ts.map +1 -1
  46. package/dist/validate-references.js +8 -1
  47. package/dist/validate-zone-slots.d.ts +39 -0
  48. package/dist/validate-zone-slots.d.ts.map +1 -0
  49. package/dist/validate-zone-slots.js +114 -0
  50. package/dist/zone-module-documents.d.ts +27 -0
  51. package/dist/zone-module-documents.d.ts.map +1 -0
  52. package/dist/zone-module-documents.js +1 -0
  53. package/dist/zone-slot.d.ts +61 -0
  54. package/dist/zone-slot.d.ts.map +1 -0
  55. package/dist/zone-slot.js +91 -0
  56. package/package.json +3 -3
  57. package/src/analysis-registry.ts +36 -2
  58. package/src/analyzer.ts +206 -24
  59. package/src/builtins.ts +32 -12
  60. package/src/call-graph.ts +827 -0
  61. package/src/dependency-graph.ts +34 -68
  62. package/src/flatten-for-analyzer.ts +32 -0
  63. package/src/index.ts +47 -0
  64. package/src/manifest-navigation.ts +91 -0
  65. package/src/manifest-visitor.ts +1 -1
  66. package/src/ref-slot.ts +273 -0
  67. package/src/reference-field-map.ts +39 -36
  68. package/src/resolve-schema-ref-kinds.ts +34 -7
  69. package/src/resolve-zone-requirements.ts +781 -0
  70. package/src/types.ts +8 -0
  71. package/src/validate-observed-state.ts +26 -92
  72. package/src/validate-ref-slots.ts +293 -0
  73. package/src/validate-references.ts +8 -1
  74. package/src/validate-zone-slots.ts +175 -0
  75. package/src/zone-module-documents.ts +27 -0
  76. package/src/zone-slot.ts +116 -0
@@ -0,0 +1,226 @@
1
+ /**
2
+ * The single reader of the `x-telo-ref` annotation.
3
+ *
4
+ * A reference slot is *recognised* here and nowhere else. Four surfaces ask what
5
+ * a slot accepts — the analyzer's reference checks, the kernel's Phase-5
6
+ * injection, the GUI editor's reference picker, and `ide-support`'s completions
7
+ * / hover / go-to-definition — and before this module each recognised the
8
+ * annotation by pattern-matching its shape (`typeof node["x-telo-ref"] ===
9
+ * "string"`, plus a hand-rolled `anyOf` peel in three of them, and no peel at all
10
+ * in hover). That is why the shape could not change without silently turning
11
+ * every ref slot in the GUI into a free-text field.
12
+ *
13
+ * Browser-safe by construction: no Node built-ins, so the editor and
14
+ * `ide-support` import it directly and the kernel re-imports it rather than
15
+ * carrying a second reader — the split already used for the invocation-contract
16
+ * resolver, the eval-path matcher and the redaction path parser.
17
+ *
18
+ * Two annotation shapes are accepted during the migration:
19
+ *
20
+ * x-telo-ref: Telo.Invocable # bare string, no declared use
21
+ * x-telo-ref: # structured
22
+ * kind: [Telo.Invocable, Telo.Runnable]
23
+ * use: call
24
+ * inputs: /inputs
25
+ */
26
+ export const REF_USES = [
27
+ "schema",
28
+ "dependency",
29
+ "call",
30
+ "detached",
31
+ "trigger.inbound",
32
+ "trigger.consumer",
33
+ ];
34
+ export function isRefUse(value) {
35
+ return typeof value === "string" && REF_USES.includes(value);
36
+ }
37
+ /** True for a use that transfers control to the target at some point. Everything
38
+ * but `schema` and `dependency`. */
39
+ export function transfersControl(use) {
40
+ return use !== "schema" && use !== "dependency";
41
+ }
42
+ /** Every use a slot can take, flattening a case map. The conservative reading
43
+ * for a consumer that does not resolve the selector. */
44
+ export function possibleUses(slot) {
45
+ if (!slot.useCases)
46
+ return slot.uses;
47
+ const out = new Set(slot.uses);
48
+ for (const uses of Object.values(slot.useCases.cases)) {
49
+ for (const use of uses)
50
+ out.add(use);
51
+ }
52
+ return [...out];
53
+ }
54
+ /** True when the slot states what the declaring resource does with the target.
55
+ * False only for the legacy bare-string form. */
56
+ export function hasDeclaredUse(slot) {
57
+ return slot.uses.length > 0 || slot.useCases !== undefined;
58
+ }
59
+ function normalizeUses(raw) {
60
+ if (isRefUse(raw))
61
+ return [raw];
62
+ if (Array.isArray(raw))
63
+ return raw.filter(isRefUse);
64
+ return [];
65
+ }
66
+ function readUseCases(raw) {
67
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
68
+ return undefined;
69
+ const obj = raw;
70
+ if (typeof obj.by !== "string")
71
+ return undefined;
72
+ const rawCases = obj.cases;
73
+ if (!rawCases || typeof rawCases !== "object" || Array.isArray(rawCases))
74
+ return undefined;
75
+ const cases = {};
76
+ for (const [key, value] of Object.entries(rawCases)) {
77
+ cases[key] = normalizeUses(value);
78
+ }
79
+ return { by: obj.by, cases };
80
+ }
81
+ /** Kind names declared by one annotation value, in either shape. */
82
+ function readKinds(annotation) {
83
+ if (typeof annotation === "string")
84
+ return annotation ? [annotation] : [];
85
+ if (!annotation || typeof annotation !== "object" || Array.isArray(annotation))
86
+ return [];
87
+ const kind = annotation.kind;
88
+ if (typeof kind === "string")
89
+ return kind ? [kind] : [];
90
+ if (Array.isArray(kind))
91
+ return kind.filter((k) => typeof k === "string" && !!k);
92
+ return [];
93
+ }
94
+ /** The nodes carrying an `x-telo-ref` for this slot: the node itself plus any
95
+ * `anyOf` / `oneOf` branch. The multi-kind shape the `kind:` list replaces.
96
+ *
97
+ * `oneOf` is peeled because the editor's picker always did and the analyzer
98
+ * never did — unifying on the wider reading is the point of a single accessor.
99
+ * The no-op claim is scoped to THIS repo: no schema here puts an `x-telo-ref`
100
+ * under `oneOf`, so for the standard library this cannot add a field-map entry
101
+ * (and hence a Phase-5 injection site) that did not exist before. An
102
+ * already-published third-party module that does use that spelling gains an
103
+ * injection site on upgrade — behavior its author most plausibly intended (the
104
+ * editor already treated the slot as a reference), but a change of behavior
105
+ * nonetheless, and part of this release's contract. */
106
+ function annotationNodes(node) {
107
+ if (!node || typeof node !== "object")
108
+ return [];
109
+ const out = [];
110
+ if (node["x-telo-ref"] !== undefined)
111
+ out.push(node);
112
+ for (const key of ["anyOf", "oneOf"]) {
113
+ const branches = node[key];
114
+ if (!Array.isArray(branches))
115
+ continue;
116
+ for (const branch of branches) {
117
+ if (branch && typeof branch === "object" && branch["x-telo-ref"] !== undefined) {
118
+ out.push(branch);
119
+ }
120
+ }
121
+ }
122
+ return out;
123
+ }
124
+ /**
125
+ * Reads a schema node as a reference slot, or `undefined` when it declares none.
126
+ *
127
+ * Unions the accepted kinds across the `kind:` list and across `anyOf` branches,
128
+ * which is the model the analyzer has always had internally — `RefFieldEntry`
129
+ * has carried a flat `refs: string[]` since before the structured form existed.
130
+ * A `use` declared on more than one branch is taken once; a *disagreement*
131
+ * between branches is left visible in the returned set rather than silently
132
+ * resolved here, so `validate-ref-slots.ts` reports it against the authored
133
+ * node (`X_TELO_REF_USE_CONFLICT`) — the same split that keeps this reader
134
+ * lenient about unrecognized `use` tokens while that pass rejects them.
135
+ */
136
+ export function readRefSlot(node) {
137
+ const nodes = annotationNodes(node);
138
+ if (nodes.length === 0)
139
+ return undefined;
140
+ const kinds = [];
141
+ const uses = new Set();
142
+ let useCases;
143
+ let inputs;
144
+ for (const carrier of nodes) {
145
+ const annotation = carrier["x-telo-ref"];
146
+ for (const kind of readKinds(annotation)) {
147
+ if (!kinds.includes(kind))
148
+ kinds.push(kind);
149
+ }
150
+ if (!annotation || typeof annotation !== "object" || Array.isArray(annotation))
151
+ continue;
152
+ const obj = annotation;
153
+ for (const use of normalizeUses(obj.use))
154
+ uses.add(use);
155
+ useCases ??= readUseCases(obj.use);
156
+ if (typeof obj.inputs === "string")
157
+ inputs ??= obj.inputs;
158
+ }
159
+ const slot = {
160
+ kinds,
161
+ uses: [...uses],
162
+ inline: node?.["x-telo-inline"] === true || nodes.some((n) => n["x-telo-inline"] === true),
163
+ };
164
+ if (useCases)
165
+ slot.useCases = useCases;
166
+ if (inputs !== undefined)
167
+ slot.inputs = inputs;
168
+ return slot;
169
+ }
170
+ /** True when the node declares a reference slot in any accepted shape. The
171
+ * recognition test every surface used to spell for itself. */
172
+ export function isRefSlot(node) {
173
+ return annotationNodes(node).length > 0;
174
+ }
175
+ /**
176
+ * Re-emits a slot as a canonical structured annotation value.
177
+ *
178
+ * For a consumer that has to *synthesize* a schema node and keep its reference
179
+ * slot intact — `ide-support` merges `anyOf` branches into one node for
180
+ * completion, and the merged node would otherwise carry no constraint at all,
181
+ * because the branches that held it are gone.
182
+ */
183
+ export function refSlotAnnotation(slot) {
184
+ const annotation = {
185
+ kind: slot.kinds.length === 1 ? slot.kinds[0] : slot.kinds,
186
+ };
187
+ if (slot.useCases)
188
+ annotation.use = slot.useCases;
189
+ else if (slot.uses.length === 1)
190
+ annotation.use = slot.uses[0];
191
+ else if (slot.uses.length > 1)
192
+ annotation.use = slot.uses;
193
+ if (slot.inputs !== undefined)
194
+ annotation.inputs = slot.inputs;
195
+ return annotation;
196
+ }
197
+ /**
198
+ * Rewrites every kind name an annotation declares, in place, in whichever shape
199
+ * it is written. `map` returns the replacement, or `undefined` to leave the name
200
+ * untouched (which is what keeps `resolveSchemaRefKinds` idempotent and lets it
201
+ * report an unresolvable constraint while quoting what the author wrote).
202
+ *
203
+ * Lives here rather than in the caller so that adding an annotation shape is a
204
+ * one-file change on the write side as well as the read side.
205
+ */
206
+ export function rewriteRefSlotKinds(annotationHolder, map) {
207
+ const annotation = annotationHolder["x-telo-ref"];
208
+ if (typeof annotation === "string") {
209
+ const next = map(annotation);
210
+ if (next !== undefined)
211
+ annotationHolder["x-telo-ref"] = next;
212
+ return;
213
+ }
214
+ if (!annotation || typeof annotation !== "object" || Array.isArray(annotation))
215
+ return;
216
+ const obj = annotation;
217
+ if (typeof obj.kind === "string") {
218
+ const next = map(obj.kind);
219
+ if (next !== undefined)
220
+ obj.kind = next;
221
+ return;
222
+ }
223
+ if (Array.isArray(obj.kind)) {
224
+ obj.kind = obj.kind.map((k) => (typeof k === "string" ? (map(k) ?? k) : k));
225
+ }
226
+ }
@@ -1,9 +1,20 @@
1
+ import { type RefUse, type RefUseCases } from "./ref-slot.js";
2
+ export { readRefSlot, isRefSlot, hasDeclaredUse } from "./ref-slot.js";
3
+ export type { RefSlot, RefUse, RefUseCases } from "./ref-slot.js";
1
4
  /** An entry for a field that carries one or more x-telo-ref constraints. */
2
5
  export interface RefFieldEntry {
3
6
  /** One or more canonical kind keys ("<module>.<Kind>"), or the deprecated
4
7
  * identity form ("<namespace>/<module>#<Kind>") for a legacy published module.
5
- * Multiple entries arise from anyOf branches. */
8
+ * Multiple entries arise from a `kind:` list or from anyOf branches. */
6
9
  refs: string[];
10
+ /** What the declaring resource does with the target — see {@link RefUse}.
11
+ * Empty for a slot still on the bare-string form. */
12
+ uses: RefUse[];
13
+ /** Set when the use is selected by a sibling config field. */
14
+ useCases?: RefUseCases;
15
+ /** JSON Pointer (relative to the object enclosing the slot) naming the field
16
+ * carrying this call's arguments. */
17
+ inputs?: string;
7
18
  /** True when the field path traversed through at least one array (path contains "[]"). */
8
19
  isArray: boolean;
9
20
  /** x-telo-context schema declared on this ref slot, if any. Describes the CEL invocation
@@ -91,6 +102,9 @@ export declare function resolveFieldValues(obj: unknown, path: string): unknown[
91
102
  * - A node with `properties` → recurse into each property
92
103
  */
93
104
  export declare function buildReferenceFieldMap(schema: Record<string, any>): ReferenceFieldMap;
105
+ /** The accepted kinds a node declares, unioned across a `kind:` list and across
106
+ * `anyOf` branches. Thin wrapper over {@link readRefSlot} — kept because
107
+ * several passes want only the kind set. */
94
108
  export declare function collectRefs(node: Record<string, any>): string[];
95
109
  /** Traverses an arbitrary JSON Schema starting at the given path prefix. Used to
96
110
  * expand x-telo-schema-from sub-schemas into nested ref/scope entries so Phase 2
@@ -1 +1 @@
1
- {"version":3,"file":"reference-field-map.d.ts","sourceRoot":"","sources":["../src/reference-field-map.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B;;sDAEkD;IAClD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,0FAA0F;IAC1F,OAAO,EAAE,OAAO,CAAC;IACjB;8DAC0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B;;;;;;;;;;kCAU8B;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B;2CACuC;IACvC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC1B;AAED;8CAC8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC;;qFAEiF;IACjF,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAEnF;0FAC0F;AAC1F,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE3D,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,aAAa,CAEvE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,eAAe,CAE3E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,oBAAoB,CAErF;AAED,oGAAoG;AACpG,eAAO,MAAM,cAAc,aAAwC,CAAC;AAEpE;;;;;;;;;2EAS2E;AAC3E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAItE;AAED;;;;sEAIsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;wDAUwD;AACxD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAoCpF;AAED;+DAC+D;AAC/D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAExE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,iBAAiB,CAQrF;AASD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAa/D;AAED;;;8CAG8C;AAC9C,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,UAAU,EAAE,MAAM,GACjB,iBAAiB,CAInB"}
1
+ {"version":3,"file":"reference-field-map.d.ts","sourceRoot":"","sources":["../src/reference-field-map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,KAAK,WAAW,EAAe,MAAM,eAAe,CAAC;AAEzF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACvE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAElE,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B;;6EAEyE;IACzE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;0DACsD;IACtD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB;0CACsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,OAAO,EAAE,OAAO,CAAC;IACjB;8DAC0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B;;;;;;;;;;kCAU8B;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B;2CACuC;IACvC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC1B;AAED;8CAC8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC;;qFAEiF;IACjF,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAEnF;0FAC0F;AAC1F,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE3D,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,aAAa,CAEvE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,eAAe,CAE3E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,oBAAoB,CAErF;AAED,oGAAoG;AACpG,eAAO,MAAM,cAAc,aAAwC,CAAC;AAEpE;;;;;;;;;2EAS2E;AAC3E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAItE;AAED;;;;sEAIsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;wDAUwD;AACxD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAoCpF;AAED;+DAC+D;AAC/D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAExE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,iBAAiB,CAQrF;AAED;;6CAE6C;AAC7C,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAE/D;AAED;;;8CAG8C;AAC9C,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,UAAU,EAAE,MAAM,GACjB,iBAAiB,CAInB"}
@@ -1,3 +1,5 @@
1
+ import { readRefSlot } from "./ref-slot.js";
2
+ export { readRefSlot, isRefSlot, hasDeclaredUse } from "./ref-slot.js";
1
3
  export function isRefEntry(entry) {
2
4
  return "refs" in entry;
3
5
  }
@@ -103,26 +105,11 @@ export function buildReferenceFieldMap(schema) {
103
105
  }
104
106
  return map;
105
107
  }
106
- /** `x-telo-inline` declared on any `anyOf` branch marks the whole slot as
107
- * inline-accepting, matching how {@link collectRefs} unions branch refs. */
108
- function collectInlineFlag(node) {
109
- if (!Array.isArray(node.anyOf))
110
- return false;
111
- return node.anyOf.some((branch) => branch?.["x-telo-inline"] === true);
112
- }
108
+ /** The accepted kinds a node declares, unioned across a `kind:` list and across
109
+ * `anyOf` branches. Thin wrapper over {@link readRefSlot} kept because
110
+ * several passes want only the kind set. */
113
111
  export function collectRefs(node) {
114
- const refs = [];
115
- if (typeof node["x-telo-ref"] === "string") {
116
- refs.push(node["x-telo-ref"]);
117
- }
118
- if (Array.isArray(node.anyOf)) {
119
- for (const branch of node.anyOf) {
120
- if (branch && typeof branch["x-telo-ref"] === "string") {
121
- refs.push(branch["x-telo-ref"]);
122
- }
123
- }
124
- }
125
- return refs;
112
+ return readRefSlot(node)?.kinds ?? [];
126
113
  }
127
114
  /** Traverses an arbitrary JSON Schema starting at the given path prefix. Used to
128
115
  * expand x-telo-schema-from sub-schemas into nested ref/scope entries so Phase 2
@@ -134,17 +121,16 @@ export function buildFieldMapAtPath(schema, pathPrefix) {
134
121
  return map;
135
122
  }
136
123
  function traverseNode(node, path, map, root, visitedRefs = new Set()) {
137
- // Local `$ref` is intentionally NOT followed. Descending into shared
138
- // `$defs` (notably `Run.Sequence`'s `step` definition) would surface
139
- // ref slots like `steps[].invoke` that Phase 5 then injects live
140
- // instances into; today's `Run.Sequence` controller calls
141
- // `instance.invoke()` directly when handed an instance, bypassing
142
- // the kernel's `runInvoke` emit-Invoked path. The walker fix and the
143
- // dispatcher fix need to land together see the follow-up in
144
- // [kernel/nodejs/plans/reference-syntax-unification.md] and the
145
- // stopgap in `resource-context.ts:ensureKindRef`. `visitedRefs`
146
- // stays as a parameter so the recursive calls below thread the right
147
- // signature; turning the descent back on is a single-branch change.
124
+ // Local `$ref` is intentionally NOT followed. This map is the kernel's
125
+ // Phase-5 injection surface: descending into shared `$defs` (notably
126
+ // `Run.Sequence`'s `step` definition) would make every step's `invoke` an
127
+ // injection site, and step slots resolve at dispatch — injecting there is
128
+ // unwanted regardless of tracing (the original dispatcher-bypass blocker
129
+ // has since shipped via the `REF_IDENTITY` stamp). Static analysis is NOT
130
+ // limited by this stop: the call graph (`call-graph.ts`) reads step slots
131
+ // from the item schema itself and scans the value tree, so it sees what
132
+ // this map deliberately hides. `visitedRefs` stays as a parameter so the
133
+ // recursive calls below thread the right signature.
148
134
  if (typeof node?.$ref === "string")
149
135
  return;
150
136
  // Scope slot — record and stop; do not recurse into scope contents
@@ -157,13 +143,21 @@ function traverseNode(node, path, map, root, visitedRefs = new Set()) {
157
143
  map.set(path, { schemaFrom: node["x-telo-schema-from"] });
158
144
  return;
159
145
  }
160
- // Reference slot (direct or via anyOf)
161
- const refs = collectRefs(node);
162
- if (refs.length > 0) {
163
- const entry = { refs, isArray: path.includes("[]") };
146
+ // Reference slot (direct, via a `kind:` list, or via anyOf)
147
+ const slot = readRefSlot(node);
148
+ if (slot && slot.kinds.length > 0) {
149
+ const entry = {
150
+ refs: slot.kinds,
151
+ uses: slot.uses,
152
+ isArray: path.includes("[]"),
153
+ };
154
+ if (slot.useCases)
155
+ entry.useCases = slot.useCases;
156
+ if (slot.inputs !== undefined)
157
+ entry.inputs = slot.inputs;
164
158
  if (node["x-telo-context"])
165
159
  entry.context = node["x-telo-context"];
166
- if (node["x-telo-inline"] === true || collectInlineFlag(node))
160
+ if (slot.inline)
167
161
  entry.inline = true;
168
162
  map.set(path, entry);
169
163
  // A node can mix item-level ref branches (a bare string / `{kind, name}`)
@@ -20,6 +20,10 @@ export interface RefConstraintIssue {
20
20
  /** The `Telo.Definition` / `Telo.Abstract` doc that declares the slot. */
21
21
  manifest: ResourceManifest;
22
22
  reason: RefConstraintReason;
23
+ /** Which annotation carried the unresolved name: an `x-telo-ref` constraint
24
+ * (the default) or an `x-telo-requires-zone` provider kind — the caller
25
+ * reports the latter as ZONE_PROVIDER_UNRESOLVED. */
26
+ annotation?: "ref" | "zone";
23
27
  /** For `gated`: the target module and the kinds it does export. */
24
28
  gate?: {
25
29
  module: string;
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-schema-ref-kinds.d.ts","sourceRoot":"","sources":["../src/resolve-schema-ref-kinds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD;;;;;;;;sDAQsD;AACtD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAEjE,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ;sFACkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,mEAAmE;IACnE,IAAI,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC9C;+BAC2B;IAC3B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,sFAAsF;AACtF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,gBAAgB,EAC5B,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,mBAAmB,GAAG,cAAc,CAAC,GAClE,kBAAkB,EAAE,CAiDtB"}
1
+ {"version":3,"file":"resolve-schema-ref-kinds.d.ts","sourceRoot":"","sources":["../src/resolve-schema-ref-kinds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMzD;;;;;;;;sDAQsD;AACtD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAEjE,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ;sFACkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,EAAE,mBAAmB,CAAC;IAC5B;;0DAEsD;IACtD,UAAU,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC5B,mEAAmE;IACnE,IAAI,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC9C;+BAC2B;IAC3B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,sFAAsF;AACtF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,gBAAgB,EAC5B,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,mBAAmB,GAAG,cAAc,CAAC,GAClE,kBAAkB,EAAE,CAsEtB"}
@@ -1,3 +1,5 @@
1
+ import { rewriteRefSlotKinds } from "./ref-slot.js";
2
+ import { hasRequiresZone, rewriteRequiresZoneKind } from "./zone-slot.js";
1
3
  const REF_ANNOTATION = "x-telo-ref";
2
4
  /** True for the legacy identity form, which is split on `#` by the identity table. */
3
5
  export function isLegacyRefIdentity(ref) {
@@ -32,9 +34,9 @@ export function isLegacyRefIdentity(ref) {
32
34
  */
33
35
  export function resolveSchemaRefKinds(definition, resolver) {
34
36
  const issues = [];
35
- const record = (ref, path) => {
37
+ const record = (ref, path, annotation = "ref") => {
36
38
  if (isLegacyRefIdentity(ref)) {
37
- issues.push({ ref, path, manifest: definition, reason: "legacy" });
39
+ issues.push({ ref, path, manifest: definition, reason: "legacy", annotation });
38
40
  return;
39
41
  }
40
42
  const result = resolver.resolveKindResult(ref);
@@ -46,6 +48,7 @@ export function resolveSchemaRefKinds(definition, resolver) {
46
48
  path,
47
49
  manifest: definition,
48
50
  reason: "gated",
51
+ annotation,
49
52
  gate: { module: result.module, exported: result.exported },
50
53
  }
51
54
  : {
@@ -53,6 +56,7 @@ export function resolveSchemaRefKinds(definition, resolver) {
53
56
  path,
54
57
  manifest: definition,
55
58
  reason: "unknown",
59
+ annotation,
56
60
  knownAliases: resolver.knownAliases(),
57
61
  });
58
62
  };
@@ -64,13 +68,32 @@ export function resolveSchemaRefKinds(definition, resolver) {
64
68
  return;
65
69
  }
66
70
  const obj = value;
67
- const ref = obj[REF_ANNOTATION];
68
- if (typeof ref === "string" && ref) {
69
- const result = isLegacyRefIdentity(ref) ? null : resolver.resolveKindResult(ref);
70
- if (result?.status === "ok")
71
- obj[REF_ANNOTATION] = result.kind;
72
- else
71
+ if (obj[REF_ANNOTATION] !== undefined) {
72
+ // Shape knowledge stays in `ref-slot.ts`: this pass states only the
73
+ // alias→canonical rule and what to report when it does not apply.
74
+ rewriteRefSlotKinds(obj, (ref) => {
75
+ const result = isLegacyRefIdentity(ref) ? null : resolver.resolveKindResult(ref);
76
+ if (result?.status === "ok")
77
+ return result.kind;
73
78
  record(ref, path);
79
+ return undefined;
80
+ });
81
+ }
82
+ if (hasRequiresZone(obj)) {
83
+ // A zone requirement names its provider kind through the identical
84
+ // alias-qualified grammar, resolved in the same declaring scope — one
85
+ // walk canonicalizes both, so the kernel's `requireZone` and the zone
86
+ // projection never see an alias. An unresolved name is reported like an
87
+ // unresolved ref constraint (the caller maps it to
88
+ // ZONE_PROVIDER_UNRESOLVED); the legacy identity form is not accepted
89
+ // here — the annotation postdates its removal.
90
+ rewriteRequiresZoneKind(obj, (zone) => {
91
+ const result = resolver.resolveKindResult(zone);
92
+ if (result.status === "ok")
93
+ return result.kind;
94
+ record(zone, `${path}.x-telo-requires-zone`, "zone");
95
+ return undefined;
96
+ });
74
97
  }
75
98
  for (const key of Object.keys(obj)) {
76
99
  walk(obj[key], path ? `${path}.${key}` : key);
@@ -0,0 +1,110 @@
1
+ /**
2
+ * The zone projection — a CONSUMER of the call-graph service, with no traversal
3
+ * of its own (see `plans/execution-zones.md`): it filters the graph's edges by
4
+ * `use`, propagates zone requirements callee→caller along `call` edges,
5
+ * discharges them at providing slots under the correlation rule, and fires at
6
+ * terminating edges and at boot.
7
+ *
8
+ * Polarity: zones UNDER-approximate. A requirement is asserted only where the
9
+ * manifest states it, a correlation only where a key pointer resolves, and an
10
+ * edge whose `use` is unknown neither propagates nor terminates — it warns.
11
+ * The runtime (`requireZone`) stays the enforcement; a path this pass cannot
12
+ * see degrades to the runtime error at the right place, never to silence.
13
+ *
14
+ * Browser-safe: no Node built-ins.
15
+ */
16
+ import type { ResourceManifest } from "@telorun/sdk";
17
+ import type { AliasResolver } from "./alias-resolver.js";
18
+ import { type CallGraph, type ResourceGraphNode } from "./call-graph.js";
19
+ import type { DefinitionRegistry } from "./definition-registry.js";
20
+ import type { ZoneModuleDocuments } from "./zone-module-documents.js";
21
+ import { type AnalysisDiagnostic } from "./types.js";
22
+ /** One open requirement on a library's exported resource — the contract an
23
+ * importer must satisfy. Plain data, so it caches and crosses the
24
+ * per-library derivation boundary. */
25
+ export interface ZoneRequirementSpec {
26
+ /** Canonical `<module>.<Kind>` of the required zone. */
27
+ zone: string;
28
+ /** Correlation identity — the resolved declaration site of the instance the
29
+ * requirement correlates on (see {@link correlationIdOf}). Absent =
30
+ * uncorrelated. */
31
+ correlation?: string;
32
+ /** Human label of the correlation target (`sqlite.Connection 'billingDb'`). */
33
+ correlationLabel?: string;
34
+ /** Bare name of the correlation target — what the export-satisfiability
35
+ * check compares against `exports.resources`. */
36
+ correlationName?: string;
37
+ reason?: string;
38
+ /** Label of the requiring resource (`sql.Command 'charge'`). */
39
+ origin: string;
40
+ /** Resource names on the propagation path so far, origin first. */
41
+ via: string[];
42
+ }
43
+ /** Per-library derived export contracts: export name → open requirements. */
44
+ export type ZoneExportRequirements = Map<string, ZoneRequirementSpec[]>;
45
+ export interface ZoneExportCacheEntry {
46
+ signature: string;
47
+ exports: ZoneExportRequirements;
48
+ }
49
+ /**
50
+ * Host-lifetime cache for per-library export derivation, keyed by the
51
+ * library's source identity with a content signature guarding staleness. The
52
+ * HOST owns it (the editor re-analyzes on every keystroke and must not rebuild
53
+ * every dependency's graph each time); the CLI passes none. It deliberately
54
+ * does not live in `AnalysisRegistry`, which the editor constructs fresh per
55
+ * closure per run — a cache there dies at exactly the boundary it must cross.
56
+ */
57
+ export type ZoneExportCache = Map<string, ZoneExportCacheEntry>;
58
+ interface ProjectionArgs {
59
+ graph: CallGraph;
60
+ defs: DefinitionRegistry;
61
+ aliases: AliasResolver;
62
+ aliasesByModule: Map<string, AliasResolver>;
63
+ /** Modules whose files diagnostics may be reported against (the analysis
64
+ * entry's own modules). Empty = derive-only, report nothing. */
65
+ reportModules: ReadonlySet<string>;
66
+ /** Extra requirements seeded at forwarded export nodes, keyed
67
+ * `${module}\0${name}` — an imported library's derived contracts. */
68
+ seeds?: Map<string, ZoneRequirementSpec[]>;
69
+ /** When set, record every requirement that reaches a module-level resource
70
+ * this returns an export name for. */
71
+ exportOf?: (node: ResourceGraphNode) => string | undefined;
72
+ }
73
+ interface ProjectionResult {
74
+ diagnostics: AnalysisDiagnostic[];
75
+ openExports: ZoneExportRequirements;
76
+ }
77
+ /** Run the projection over one graph. */
78
+ export declare function projectZoneRequirements(args: ProjectionArgs): ProjectionResult;
79
+ /** Content signature over a library's loaded documents — what makes a
80
+ * workspace library invalidate on the keystroke that changed it while a
81
+ * published library (immutable bytes) hits every time. FNV-1a over the JSON
82
+ * projection; collisions only stale a warning-level derivation, and the
83
+ * projection is cheap relative to the graph build it guards. */
84
+ export declare function zoneDocumentsSignature(manifests: readonly ResourceManifest[]): string;
85
+ /**
86
+ * Derive one library's export contracts: build the library-scoped graph from
87
+ * its full documents (which the flattened analysis view no longer holds), run
88
+ * the projection derive-only, and keep what reaches an exported instance.
89
+ */
90
+ export declare function deriveLibraryExportRequirements(docs: ZoneModuleDocuments, defs: DefinitionRegistry, aliases: AliasResolver, aliasesByModule: Map<string, AliasResolver>, cache?: ZoneExportCache): ZoneExportRequirements;
91
+ export interface ZoneAnalysisArgs {
92
+ /** The entry analysis set (post inline-normalization + sentinel resolution). */
93
+ manifests: ResourceManifest[];
94
+ graph: CallGraph;
95
+ defs: DefinitionRegistry;
96
+ aliases: AliasResolver;
97
+ aliasesByModule: Map<string, AliasResolver>;
98
+ rootModules: ReadonlySet<string>;
99
+ moduleDocuments?: readonly ZoneModuleDocuments[];
100
+ cache?: ZoneExportCache;
101
+ }
102
+ /**
103
+ * The zone stage of `analyze()`: per-library export derivation (cached), the
104
+ * entry projection with those contracts seeded, and — when the entry is a
105
+ * library — the export-satisfiability check, at the one desk where it is
106
+ * fixable.
107
+ */
108
+ export declare function runZoneAnalysis(args: ZoneAnalysisArgs): AnalysisDiagnostic[];
109
+ export {};
110
+ //# sourceMappingURL=resolve-zone-requirements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-zone-requirements.d.ts","sourceRoot":"","sources":["../src/resolve-zone-requirements.ts"],"names":[],"mappings":"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"}