@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
package/dist/zone-slot.js CHANGED
@@ -10,6 +10,13 @@
10
10
  *
11
11
  * x-telo-provides-zone: true # uncorrelated — the zone is the kind
12
12
  * x-telo-provides-zone: /connection # correlation-key pointer (own field)
13
+ * x-telo-provides-zone: # correlation key + zone attributes
14
+ * key: /connection
15
+ * atomic: a rollback erases writes a journal recorded as done
16
+ * noSuspend: the transaction holds a connection a parked run would lose
17
+ *
18
+ * x-telo-violates-zone: # what this kind cannot honour
19
+ * noSuspend: this waits for a delivery that may be days away
13
20
  *
14
21
  * x-telo-requires-zone: Self.Transaction # uncorrelated string form
15
22
  * x-telo-requires-zone: # object form
@@ -17,8 +24,10 @@
17
24
  * key: [/connection, /transaction/connection] # ordered, first hit wins
18
25
  * reason: the statement would execute outside any transaction
19
26
  */
27
+ import { ZONE_ATTRIBUTES } from "@telorun/sdk";
20
28
  const PROVIDES = "x-telo-provides-zone";
21
29
  const REQUIRES = "x-telo-requires-zone";
30
+ const VIOLATES = "x-telo-violates-zone";
22
31
  /** A self-relative JSON Pointer — the only correlation-key spelling the
23
32
  * analyzer and the kernel read identically. Applied to BOTH the scalar and the
24
33
  * list form: the kernel's walk splits on `/` and drops empty segments, so a
@@ -33,10 +42,38 @@ function isPointer(value) {
33
42
  export function readProvidesZone(node) {
34
43
  const raw = node?.[PROVIDES];
35
44
  if (raw === true)
36
- return {};
45
+ return { attributes: {} };
37
46
  if (isPointer(raw))
38
- return { key: raw };
39
- return undefined;
47
+ return { key: raw, attributes: {} };
48
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
49
+ return undefined;
50
+ const obj = raw;
51
+ // A `key` that is present but unreadable makes the object form MEAN something
52
+ // different to the two halves — the correlation the author wrote is dropped
53
+ // here while the kernel's walk still resolves a bare name — so the whole
54
+ // annotation is refused rather than read as uncorrelated. Absent `key` is the
55
+ // legitimate uncorrelated case.
56
+ if (obj.key !== undefined && !isPointer(obj.key))
57
+ return undefined;
58
+ const attributes = {};
59
+ for (const [name, value] of Object.entries(obj)) {
60
+ if (name === "key")
61
+ continue;
62
+ // Unknown names and wrong-shaped values are reported by
63
+ // `validate-zone-slots`; skipped here so a typo degrades to an attribute
64
+ // this zone does not declare rather than to a consumer reading a name that
65
+ // means nothing to it.
66
+ if (!ZONE_ATTRIBUTES.has(name) || typeof value !== "string" || !value)
67
+ continue;
68
+ attributes[name] = value;
69
+ }
70
+ return { ...(isPointer(obj.key) ? { key: obj.key } : {}), attributes: attributes };
71
+ }
72
+ /** The attributes the zone a slot provides declares, or an empty record when the
73
+ * node provides no zone. The shape every containment consumer wants, so none of
74
+ * them repeats the `readProvidesZone(...)?.attributes ?? {}` dance. */
75
+ export function providedZoneAttributes(node) {
76
+ return readProvidesZone(node)?.attributes ?? {};
40
77
  }
41
78
  /** True when the node carries `x-telo-provides-zone` in any shape, valid or not
42
79
  * — the recognition test validation needs before it judges the value. */
@@ -48,7 +85,7 @@ export function hasProvidesZone(node) {
48
85
  export function readRequiresZone(node) {
49
86
  const raw = node?.[REQUIRES];
50
87
  if (typeof raw === "string" && raw)
51
- return { zone: raw, key: [] };
88
+ return { zone: raw, key: [], attributes: [] };
52
89
  if (!raw || typeof raw !== "object" || Array.isArray(raw))
53
90
  return undefined;
54
91
  const obj = raw;
@@ -56,11 +93,55 @@ export function readRequiresZone(node) {
56
93
  return undefined;
57
94
  // One filter for both spellings — see `isPointer`.
58
95
  const key = (Array.isArray(obj.key) ? obj.key : [obj.key]).filter(isPointer);
59
- const slot = { zone: obj.zone, key };
96
+ // Unknown names are dropped here and reported by `validate-zone-slots`, the
97
+ // lenient-reader / strict-validator split this file has throughout: a typo
98
+ // degrades to a guarantee this requirement does not ask for, never to a
99
+ // consumer matching against a name that means nothing.
100
+ const attributes = (Array.isArray(obj.attributes) ? obj.attributes : []).filter((a) => typeof a === "string" && ZONE_ATTRIBUTES.has(a));
101
+ const slot = { zone: obj.zone, key, attributes };
60
102
  if (typeof obj.reason === "string")
61
103
  slot.reason = obj.reason;
62
104
  return slot;
63
105
  }
106
+ /**
107
+ * What this kind CANNOT honour about a region it is placed inside.
108
+ *
109
+ * The third relation, and the one the other two cannot express. `provides`
110
+ * declares what a region guarantees about its contents; `requires` declares what
111
+ * a resource needs of the region around it. Neither says *this resource breaks
112
+ * that guarantee* — and without it a zone attribute has a promise and no way to
113
+ * name what falsifies it: `noSuspend` would be enforced only when a parking kind
114
+ * happened to reach its runtime check, and `Durable.Sleep` would be
115
+ * indistinguishable from `Durable.Value`, which needs the same journal and parks
116
+ * nothing.
117
+ *
118
+ * Declared at the kind's SCHEMA ROOT, because it is a property of the kind
119
+ * rather than of one of its slots — a kind that suspends suspends however it is
120
+ * configured.
121
+ *
122
+ * Values are the author's REASON, exactly as on `provides`: a diagnostic prints
123
+ * the region's promise and this resource's rebuttal side by side, and both are
124
+ * their own authors' words.
125
+ */
126
+ export function readViolatesZone(node) {
127
+ const raw = node?.[VIOLATES];
128
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
129
+ return {};
130
+ const out = {};
131
+ for (const [name, value] of Object.entries(raw)) {
132
+ // Lenient, like every reader here: `validate-zone-slots` reports a typo, and
133
+ // dropping it degrades to a violation nobody declared rather than to a
134
+ // consumer matching a name that means nothing.
135
+ if (!ZONE_ATTRIBUTES.has(name) || typeof value !== "string" || !value)
136
+ continue;
137
+ out[name] = value;
138
+ }
139
+ return out;
140
+ }
141
+ /** True when the node carries `x-telo-violates-zone` in any shape, valid or not. */
142
+ export function hasViolatesZone(node) {
143
+ return node?.[VIOLATES] !== undefined;
144
+ }
64
145
  /** True when the node carries `x-telo-requires-zone` in any shape. */
65
146
  export function hasRequiresZone(node) {
66
147
  return node?.[REQUIRES] !== undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telorun/analyzer",
3
- "version": "0.62.1",
3
+ "version": "0.64.0",
4
4
  "description": "Telo Analyzer - Static manifest validator for Telo manifests.",
5
5
  "keywords": [
6
6
  "telo",
@@ -49,7 +49,7 @@
49
49
  "@types/node": "^20.0.0",
50
50
  "typescript": "^5.0.0",
51
51
  "vitest": "^2.1.8",
52
- "@telorun/sdk": "0.77.0"
52
+ "@telorun/sdk": "0.80.0"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@telorun/sdk": "*"
@@ -1,6 +1,7 @@
1
1
  import type { ResourceDefinition, ResourceManifest } from "@telorun/sdk";
2
2
  import { AliasResolver } from "./alias-resolver.js";
3
3
  import { KERNEL_BUILTINS } from "./builtins.js";
4
+ import { ManifestAnalysis } from "./manifest-analysis.js";
4
5
  import { DefinitionRegistry } from "./definition-registry.js";
5
6
  import { computeSuggestKind, computeValidUserFacingKinds } from "./kind-suggest.js";
6
7
  import { visitManifest as runVisitManifest, type ManifestVisitor } from "./manifest-visitor.js";
@@ -174,6 +175,12 @@ export class AnalysisRegistry {
174
175
  ): Record<string, unknown> | undefined {
175
176
  const def = this.resolveDefinition(kind);
176
177
  if (!def) return undefined;
178
+ // A KIND-level query: there is no instance, so a DECLARATION-derived slot
179
+ // (`x-telo-schema-projection-from`) has no reference to project from and is
180
+ // left as the kind declared it. That is the honest answer here — the
181
+ // projected shape is a property of one instance, not of the kind — and it is
182
+ // why passing no manifest cannot silently drop a projection: the per-resource
183
+ // analysis pass is what resolves and reports them.
177
184
  return resolveContract(direction, undefined, def, {
178
185
  resolveDefinition: this.scopedDefResolver(),
179
186
  typeManifestsFor: () => [],
@@ -236,6 +243,42 @@ export class AnalysisRegistry {
236
243
  });
237
244
  }
238
245
 
246
+ /**
247
+ * Resolves an `x-telo-schema-from` annotation to the schema node it derives,
248
+ * in the scope of the kind that DECLARED it — anchors are alias-qualified, and
249
+ * the declaring definition's module is where those aliases mean something.
250
+ *
251
+ * The seam an IDE walks a schema through: a slot shaped entirely by this
252
+ * annotation (an `Http.Api` route's `request:`) carries no `properties` of its
253
+ * own, so a walker that only reads `properties` finds nothing there and
254
+ * silently offers no keys and no hover — a whole field of the standard library
255
+ * looking like an unknown one.
256
+ */
257
+ resolveSchemaFrom(schemaFrom: string, declaringKind: string): Record<string, any> | undefined {
258
+ const def = this.resolveDefinition(declaringKind);
259
+ const ownerModule = (def?.metadata as { module?: string } | undefined)?.module;
260
+ const scope = (ownerModule ? this.aliasesByModule.get(ownerModule) : undefined) ?? this.aliases;
261
+ return this.defs.resolveSchemaFromNode(schemaFrom, scope);
262
+ }
263
+
264
+ /**
265
+ * The queries that need this registry AND a manifest set: what CEL sees at a
266
+ * site, where a binding was declared, what a reference's contract is.
267
+ *
268
+ * The seam an IDE reaches all of them through, and one object rather than a
269
+ * factory per question — each answer has to be the one the analysis pass
270
+ * computed, or a completion list stops being a claim about what `telo check`
271
+ * accepts. Built per analysis, not per keystroke: the indices behind it are a
272
+ * function of the whole manifest set.
273
+ */
274
+ analysisOf(manifests: ResourceManifest[]): ManifestAnalysis {
275
+ return new ManifestAnalysis(manifests, {
276
+ defs: this.defs,
277
+ aliases: this.aliases,
278
+ aliasesByModule: this.aliasesByModule,
279
+ });
280
+ }
281
+
239
282
  /**
240
283
  * Returns the built-in kernel definitions. The underlying DefinitionRegistry already
241
284
  * seeds these on construction; this method exposes them so callers (e.g. the kernel's