@telorun/analyzer 0.1.4 → 0.2.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.
Files changed (64) hide show
  1. package/README.md +3 -3
  2. package/dist/analyzer.d.ts +6 -0
  3. package/dist/analyzer.d.ts.map +1 -1
  4. package/dist/analyzer.js +45 -25
  5. package/dist/builtins.d.ts.map +1 -1
  6. package/dist/builtins.js +52 -24
  7. package/dist/cel-environment.d.ts +12 -5
  8. package/dist/cel-environment.d.ts.map +1 -1
  9. package/dist/cel-environment.js +31 -17
  10. package/dist/definition-registry.d.ts +5 -5
  11. package/dist/definition-registry.d.ts.map +1 -1
  12. package/dist/definition-registry.js +10 -10
  13. package/dist/dependency-graph.d.ts.map +1 -1
  14. package/dist/dependency-graph.js +9 -2
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +1 -0
  18. package/dist/kernel-globals.d.ts +6 -2
  19. package/dist/kernel-globals.d.ts.map +1 -1
  20. package/dist/kernel-globals.js +14 -8
  21. package/dist/manifest-loader.d.ts +1 -0
  22. package/dist/manifest-loader.d.ts.map +1 -1
  23. package/dist/manifest-loader.js +36 -14
  24. package/dist/module-kinds.d.ts +4 -0
  25. package/dist/module-kinds.d.ts.map +1 -0
  26. package/dist/module-kinds.js +4 -0
  27. package/dist/normalize-inline-resources.d.ts.map +1 -1
  28. package/dist/normalize-inline-resources.js +6 -1
  29. package/dist/precompile.d.ts +3 -2
  30. package/dist/precompile.d.ts.map +1 -1
  31. package/dist/precompile.js +13 -11
  32. package/dist/reference-field-map.d.ts +1 -1
  33. package/dist/resolve-throws-union.d.ts +30 -0
  34. package/dist/resolve-throws-union.d.ts.map +1 -0
  35. package/dist/resolve-throws-union.js +252 -0
  36. package/dist/types.d.ts +3 -0
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/validate-cel-context.js +1 -1
  39. package/dist/validate-references.d.ts.map +1 -1
  40. package/dist/validate-references.js +19 -12
  41. package/dist/validate-throws-coverage.d.ts +8 -0
  42. package/dist/validate-throws-coverage.d.ts.map +1 -0
  43. package/dist/validate-throws-coverage.js +461 -0
  44. package/package.json +2 -2
  45. package/src/analyzer.ts +60 -26
  46. package/src/builtins.ts +52 -24
  47. package/src/cel-environment.ts +40 -17
  48. package/src/definition-registry.ts +10 -10
  49. package/src/dependency-graph.ts +9 -2
  50. package/src/index.ts +2 -0
  51. package/src/kernel-globals.ts +19 -10
  52. package/src/manifest-loader.ts +40 -14
  53. package/src/module-kinds.ts +6 -0
  54. package/src/normalize-inline-resources.ts +6 -1
  55. package/src/precompile.ts +14 -11
  56. package/src/reference-field-map.ts +1 -1
  57. package/src/resolve-throws-union.ts +345 -0
  58. package/src/types.ts +3 -0
  59. package/src/validate-cel-context.ts +1 -1
  60. package/src/validate-references.ts +19 -12
  61. package/src/validate-throws-coverage.ts +565 -0
  62. package/dist/adapters/node-adapter.d.ts +0 -17
  63. package/dist/adapters/node-adapter.d.ts.map +0 -1
  64. package/dist/adapters/node-adapter.js +0 -71
@@ -6,7 +6,7 @@ import type { ResourceManifest } from "@telorun/sdk";
6
6
  * must stay in sync with this list.
7
7
  *
8
8
  * Note: `env` is only available in the root module context. Child modules
9
- * loaded via Kernel.Import do not receive host environment variables.
9
+ * loaded via Telo.Import do not receive host environment variables.
10
10
  * There is no `imports` namespace at runtime — import snapshots are stored
11
11
  * under `resources.<alias>`.
12
12
  */
@@ -17,7 +17,11 @@ export declare const KERNEL_GLOBAL_NAMES: readonly ["variables", "secrets", "res
17
17
  * chain-access validation recognises kernel globals without module authors
18
18
  * having to re-declare them.
19
19
  *
20
- * - `variables` / `secrets`: typed from the `Kernel.Module` declaration
20
+ * - `variables` / `secrets`: typed from the root module doc — prefer
21
+ * Telo.Application when present, otherwise fall back to Telo.Library.
22
+ * Applications are the root whose variables/secrets contract governs CEL
23
+ * in the outer module; Libraries are only relevant when the caller scoped
24
+ * the manifest list to a single library's file.
21
25
  * - `resources`: enumerates all non-system resource names
22
26
  * - `env`: dynamic (runtime env vars, root module only)
23
27
  */
@@ -1 +1 @@
1
- {"version":3,"file":"kernel-globals.d.ts","sourceRoot":"","sources":["../src/kernel-globals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,uDAAwD,CAAC;AAQzF;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA6BrB;AA2BD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CASrB"}
1
+ {"version":3,"file":"kernel-globals.d.ts","sourceRoot":"","sources":["../src/kernel-globals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,uDAAwD,CAAC;AASzF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAiCrB;AA2BD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CASrB"}
@@ -5,15 +5,16 @@
5
5
  * must stay in sync with this list.
6
6
  *
7
7
  * Note: `env` is only available in the root module context. Child modules
8
- * loaded via Kernel.Import do not receive host environment variables.
8
+ * loaded via Telo.Import do not receive host environment variables.
9
9
  * There is no `imports` namespace at runtime — import snapshots are stored
10
10
  * under `resources.<alias>`.
11
11
  */
12
12
  export const KERNEL_GLOBAL_NAMES = ["variables", "secrets", "resources", "env"];
13
13
  const SYSTEM_KINDS = new Set([
14
- "Kernel.Definition",
15
- "Kernel.Module",
16
- "Kernel.Abstract",
14
+ "Telo.Definition",
15
+ "Telo.Application",
16
+ "Telo.Library",
17
+ "Telo.Abstract",
17
18
  ]);
18
19
  /**
19
20
  * Build a typed JSON Schema describing the kernel globals available in the
@@ -21,18 +22,23 @@ const SYSTEM_KINDS = new Set([
21
22
  * chain-access validation recognises kernel globals without module authors
22
23
  * having to re-declare them.
23
24
  *
24
- * - `variables` / `secrets`: typed from the `Kernel.Module` declaration
25
+ * - `variables` / `secrets`: typed from the root module doc — prefer
26
+ * Telo.Application when present, otherwise fall back to Telo.Library.
27
+ * Applications are the root whose variables/secrets contract governs CEL
28
+ * in the outer module; Libraries are only relevant when the caller scoped
29
+ * the manifest list to a single library's file.
25
30
  * - `resources`: enumerates all non-system resource names
26
31
  * - `env`: dynamic (runtime env vars, root module only)
27
32
  */
28
33
  export function buildKernelGlobalsSchema(manifests) {
29
- const moduleManifest = manifests.find((m) => m.kind === "Kernel.Module");
34
+ const moduleManifest = manifests.find((m) => m.kind === "Telo.Application") ??
35
+ manifests.find((m) => m.kind === "Telo.Library");
30
36
  const resourceProps = {};
31
37
  for (const m of manifests) {
32
38
  const name = m.metadata?.name;
33
39
  if (!name || !m.kind)
34
40
  continue;
35
- // Kernel.Import snapshots are stored under resources.<alias> at runtime,
41
+ // Telo.Import snapshots are stored under resources.<alias> at runtime,
36
42
  // so they appear here alongside regular resources.
37
43
  if (!SYSTEM_KINDS.has(m.kind)) {
38
44
  resourceProps[name] = { type: "object", additionalProperties: true };
@@ -52,7 +58,7 @@ export function buildKernelGlobalsSchema(manifests) {
52
58
  },
53
59
  };
54
60
  }
55
- /** Wrap a JSON Schema property map (like `Kernel.Module.variables`) into a
61
+ /** Wrap a JSON Schema property map (like `Telo.Application.variables`) into a
56
62
  * closed object schema suitable for chain-access validation. Falls back to
57
63
  * an open map when the module declares no variables/secrets. */
58
64
  function buildSchemaMapSchema(schemaMap) {
@@ -3,6 +3,7 @@ import { type LoadOptions, type LoaderInitOptions, type ManifestAdapter } from "
3
3
  export declare class Loader {
4
4
  private static readonly moduleCache;
5
5
  protected adapters: ManifestAdapter[];
6
+ private readonly celEnv;
6
7
  constructor(extraAdaptersOrOptions?: ManifestAdapter[] | LoaderInitOptions);
7
8
  register(adapter: ManifestAdapter): this;
8
9
  private pick;
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../src/manifest-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKtE,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EAGrB,MAAM,YAAY,CAAC;AAIpB,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAG/B;IAEJ,SAAS,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;gBAE1B,sBAAsB,GAAE,eAAe,EAAE,GAAG,iBAAsB;IAiB9E,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAKxC,OAAO,CAAC,IAAI;IAMN,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK/C,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAmGnE,eAAe;YAoBf,eAAe;IAgEvB,iBAAiB,CACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,gBAAgB,EAAE,CAAC;QAC9B,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;KAClD,GAAG,IAAI,CAAC;IAiCH,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,GAC5C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAsCrC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAoDnE"}
1
+ {"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../src/manifest-loader.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAOtE,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EAGrB,MAAM,YAAY,CAAC;AASpB,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAG/B;IAEJ,SAAS,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;gBAEzB,sBAAsB,GAAE,eAAe,EAAE,GAAG,iBAAsB;IAmB9E,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAKxC,OAAO,CAAC,IAAI;IAMN,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK/C,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAqGnE,eAAe;YAoBf,eAAe;IAgEvB,iBAAiB,CACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,gBAAgB,EAAE,CAAC;QAC9B,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;KAClD,GAAG,IAAI,CAAC;IAiCH,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,GAC5C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAsCrC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAiEnE"}
@@ -2,12 +2,20 @@ import { isCompiledValue } from "@telorun/sdk";
2
2
  import { isMap, isPair, isScalar, isSeq, parseAllDocuments } from "yaml";
3
3
  import { HttpAdapter } from "./adapters/http-adapter.js";
4
4
  import { RegistryAdapter } from "./adapters/registry-adapter.js";
5
+ import { buildCelEnvironment } from "./cel-environment.js";
6
+ import { isModuleKind } from "./module-kinds.js";
5
7
  import { precompileDoc } from "./precompile.js";
6
8
  import { DEFAULT_MANIFEST_FILENAME, } from "./types.js";
7
- const SYSTEM_KINDS = new Set(["Kernel.Module", "Kernel.Import", "Kernel.Definition"]);
9
+ const SYSTEM_KINDS = new Set([
10
+ "Telo.Application",
11
+ "Telo.Library",
12
+ "Telo.Import",
13
+ "Telo.Definition",
14
+ ]);
8
15
  export class Loader {
9
16
  static moduleCache = new Map();
10
17
  adapters;
18
+ celEnv;
11
19
  constructor(extraAdaptersOrOptions = []) {
12
20
  const options = Array.isArray(extraAdaptersOrOptions)
13
21
  ? { extraAdapters: extraAdaptersOrOptions }
@@ -22,6 +30,7 @@ export class Loader {
22
30
  if (options.extraAdapters?.length) {
23
31
  this.adapters.unshift(...options.extraAdapters);
24
32
  }
33
+ this.celEnv = buildCelEnvironment(options.celHandlers);
25
34
  }
26
35
  register(adapter) {
27
36
  this.adapters.unshift(adapter);
@@ -59,7 +68,7 @@ export class Loader {
59
68
  let compiledDocs;
60
69
  if (options?.compile) {
61
70
  try {
62
- const result = precompileDoc(rawDoc);
71
+ const result = precompileDoc(rawDoc, this.celEnv);
63
72
  compiledDocs = Array.isArray(result) ? result : [result];
64
73
  }
65
74
  catch (error) {
@@ -85,15 +94,17 @@ export class Loader {
85
94
  resolved.push({ ...manifest, metadata });
86
95
  }
87
96
  }
88
- const moduleManifests = resolved.filter((m) => m.kind === "Kernel.Module");
97
+ const moduleManifests = resolved.filter((m) => isModuleKind(m.kind));
89
98
  if (moduleManifests.length > 1) {
90
- throw new Error(`File '${source}' contains ${moduleManifests.length} Kernel.Module declarations. Maximum one is allowed.`);
99
+ const kinds = moduleManifests.map((m) => m.kind).join(", ");
100
+ throw new Error(`File '${source}' contains ${moduleManifests.length} module declarations (${kinds}). ` +
101
+ `A file may declare at most one Telo.Application or Telo.Library.`);
91
102
  }
92
103
  const moduleManifest = moduleManifests[0];
93
104
  const moduleName = moduleManifest?.metadata?.name;
94
105
  if (moduleName) {
95
106
  for (const manifest of resolved) {
96
- if (manifest.kind !== "Kernel.Module" && !manifest.metadata?.module) {
107
+ if (!isModuleKind(manifest.kind) && !manifest.metadata?.module) {
97
108
  const pi = manifest.metadata?.positionIndex;
98
109
  manifest.metadata = { ...manifest.metadata, module: moduleName };
99
110
  if (pi) {
@@ -163,7 +174,7 @@ export class Loader {
163
174
  let compiledDocs;
164
175
  if (options?.compile) {
165
176
  try {
166
- const result = precompileDoc(rawDoc);
177
+ const result = precompileDoc(rawDoc, this.celEnv);
167
178
  compiledDocs = Array.isArray(result) ? result : [result];
168
179
  }
169
180
  catch (error) {
@@ -197,10 +208,10 @@ export class Loader {
197
208
  async loadModuleForFile(fileUrl) {
198
209
  // Try loading as a regular module first (it might be a telo.yaml itself).
199
210
  // Use loadManifests (not loadModule) so imported definitions are included —
200
- // otherwise the analyzer won't know about kinds from Kernel.Import sources.
211
+ // otherwise the analyzer won't know about kinds from Telo.Import sources.
201
212
  try {
202
213
  const docs = await this.loadModule(fileUrl);
203
- const hasModule = docs.some((d) => d.kind === "Kernel.Module");
214
+ const hasModule = docs.some((d) => isModuleKind(d.kind));
204
215
  if (hasModule) {
205
216
  const { source } = await this.pick(fileUrl).read(fileUrl);
206
217
  const manifests = await this.loadManifests(fileUrl);
@@ -235,7 +246,7 @@ export class Loader {
235
246
  const queue = [...entry];
236
247
  while (queue.length > 0) {
237
248
  const m = queue.shift();
238
- if (m.kind !== "Kernel.Import")
249
+ if (m.kind !== "Telo.Import")
239
250
  continue;
240
251
  const importSource = m.source;
241
252
  if (!importSource)
@@ -258,7 +269,7 @@ export class Loader {
258
269
  }
259
270
  result.set(importUrl, imported);
260
271
  for (const im of imported) {
261
- if (im.kind === "Kernel.Import")
272
+ if (im.kind === "Telo.Import")
262
273
  queue.push(im);
263
274
  }
264
275
  }
@@ -271,7 +282,7 @@ export class Loader {
271
282
  const queue = [...entry];
272
283
  while (queue.length > 0) {
273
284
  const m = queue.shift();
274
- if (m.kind !== "Kernel.Import")
285
+ if (m.kind !== "Telo.Import")
275
286
  continue;
276
287
  const importSource = m.source;
277
288
  if (!importSource)
@@ -292,7 +303,18 @@ export class Loader {
292
303
  e.sourceLine = m.metadata?.sourceLine ?? 0;
293
304
  throw e;
294
305
  }
295
- const importedModule = imported.find((im) => im.kind === "Kernel.Module");
306
+ // Import target must be a Telo.Library. Check the Library branch
307
+ // explicitly rather than "anything that's a module kind" so that a
308
+ // future third kind can't silently slip past as a valid import target.
309
+ const importedLibrary = imported.find((im) => im.kind === "Telo.Library");
310
+ const importedApplication = imported.find((im) => im.kind === "Telo.Application");
311
+ if (importedApplication) {
312
+ const e = new Error(`Telo.Import target '${importSource}' is a Telo.Application. ` +
313
+ `Only Telo.Library modules may be imported. Applications are run directly, not imported.`);
314
+ e.sourceLine = m.metadata?.sourceLine ?? 0;
315
+ throw e;
316
+ }
317
+ const importedModule = importedLibrary;
296
318
  if (importedModule?.metadata?.name) {
297
319
  const pi = m.metadata?.positionIndex;
298
320
  m.metadata = {
@@ -310,9 +332,9 @@ export class Loader {
310
332
  }
311
333
  }
312
334
  for (const im of imported) {
313
- if (im.kind === "Kernel.Definition")
335
+ if (im.kind === "Telo.Definition")
314
336
  importedDefs.push(im);
315
- if (im.kind === "Kernel.Import")
337
+ if (im.kind === "Telo.Import")
316
338
  queue.push(im);
317
339
  }
318
340
  }
@@ -0,0 +1,4 @@
1
+ export declare const MODULE_KINDS: readonly ["Telo.Application", "Telo.Library"];
2
+ export type ModuleKind = (typeof MODULE_KINDS)[number];
3
+ export declare function isModuleKind(kind: string | undefined): kind is ModuleKind;
4
+ //# sourceMappingURL=module-kinds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-kinds.d.ts","sourceRoot":"","sources":["../src/module-kinds.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,+CAAgD,CAAC;AAC1E,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,IAAI,UAAU,CAEzE"}
@@ -0,0 +1,4 @@
1
+ export const MODULE_KINDS = ["Telo.Application", "Telo.Library"];
2
+ export function isModuleKind(kind) {
3
+ return kind === "Telo.Application" || kind === "Telo.Library";
4
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-inline-resources.d.ts","sourceRoot":"","sources":["../src/normalize-inline-resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AASzD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE,aAAa,GACtB,gBAAgB,EAAE,CAkDpB"}
1
+ {"version":3,"file":"normalize-inline-resources.d.ts","sourceRoot":"","sources":["../src/normalize-inline-resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAczD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE,aAAa,GACtB,gBAAgB,EAAE,CAkDpB"}
@@ -1,5 +1,10 @@
1
1
  import { isRefEntry, isScopeEntry, isInlineResource } from "./reference-field-map.js";
2
- const SYSTEM_KINDS = new Set(["Kernel.Definition", "Kernel.Module", "Kernel.Import"]);
2
+ const SYSTEM_KINDS = new Set([
3
+ "Telo.Definition",
4
+ "Telo.Application",
5
+ "Telo.Library",
6
+ "Telo.Import",
7
+ ]);
3
8
  /** Replaces characters outside [a-zA-Z0-9_] with underscores. */
4
9
  function sanitizeName(raw) {
5
10
  return raw.replace(/[^a-zA-Z0-9_]/g, "_");
@@ -1,9 +1,10 @@
1
+ import type { Environment } from "@marcbachmann/cel-js";
1
2
  /**
2
3
  * Walks a raw YAML document and replaces all "${{ expr }}" strings with
3
4
  * CompiledValue wrappers. Throws on CEL syntax errors.
4
5
  * Intended to be called once per document at load time.
5
- * Kernel.Definition documents are returned unchanged — their schema fields
6
+ * Telo.Definition documents are returned unchanged — their schema fields
6
7
  * are static metadata and must not be treated as CEL templates.
7
8
  */
8
- export declare function precompileDoc(doc: unknown): unknown;
9
+ export declare function precompileDoc(doc: unknown, env: Environment): unknown;
9
10
  //# sourceMappingURL=precompile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"precompile.d.ts","sourceRoot":"","sources":["../src/precompile.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAanD"}
1
+ {"version":3,"file":"precompile.d.ts","sourceRoot":"","sources":["../src/precompile.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAKxD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAarE"}
@@ -1,36 +1,36 @@
1
- import { celEnvironment } from "./cel-environment.js";
2
1
  const TEMPLATE_REGEX = /\$\{\{\s*([^}]+?)\s*\}\}/g;
3
2
  const EXACT_TEMPLATE_REGEX = /^\s*\$\{\{\s*([^}]+?)\s*\}\}\s*$/;
4
3
  /**
5
4
  * Walks a raw YAML document and replaces all "${{ expr }}" strings with
6
5
  * CompiledValue wrappers. Throws on CEL syntax errors.
7
6
  * Intended to be called once per document at load time.
8
- * Kernel.Definition documents are returned unchanged — their schema fields
7
+ * Telo.Definition documents are returned unchanged — their schema fields
9
8
  * are static metadata and must not be treated as CEL templates.
10
9
  */
11
- export function precompileDoc(doc) {
10
+ export function precompileDoc(doc, env) {
12
11
  if (typeof doc === "string")
13
- return compileString(doc);
12
+ return compileString(doc, env);
14
13
  if (Array.isArray(doc))
15
- return doc.map(precompileDoc);
14
+ return doc.map((item) => precompileDoc(item, env));
16
15
  // Only recurse into plain objects. Class instances (ResourceInstance, ScopeHandle, etc.)
17
16
  // are returned as-is — their prototype methods must not be lost by object reconstruction.
18
17
  if (doc !== null && typeof doc === "object" && Object.getPrototypeOf(doc) === Object.prototype) {
19
18
  const result = {};
20
19
  for (const [k, v] of Object.entries(doc)) {
21
- result[k] = precompileDoc(v);
20
+ result[k] = precompileDoc(v, env);
22
21
  }
23
22
  return result;
24
23
  }
25
24
  return doc;
26
25
  }
27
- function compileString(s) {
26
+ function compileString(s, env) {
28
27
  if (!s.includes("${{"))
29
28
  return s;
30
29
  const exact = s.match(EXACT_TEMPLATE_REGEX);
31
30
  if (exact) {
32
- const fn = celEnvironment.parse(exact[1].trim());
33
- return { __compiled: true, call: (ctx) => fn(ctx) };
31
+ const expr = exact[1].trim();
32
+ const fn = env.parse(expr);
33
+ return { __compiled: true, source: expr, call: (ctx) => fn(ctx) };
34
34
  }
35
35
  // Interpolated template — collect literal parts + compiled sub-expressions
36
36
  const parts = [];
@@ -38,14 +38,16 @@ function compileString(s) {
38
38
  for (const m of s.matchAll(TEMPLATE_REGEX)) {
39
39
  if (m.index > last)
40
40
  parts.push(s.slice(last, m.index));
41
- const fn = celEnvironment.parse(m[1].trim());
42
- parts.push({ __compiled: true, call: (ctx) => fn(ctx) });
41
+ const expr = m[1].trim();
42
+ const fn = env.parse(expr);
43
+ parts.push({ __compiled: true, source: expr, call: (ctx) => fn(ctx) });
43
44
  last = m.index + m[0].length;
44
45
  }
45
46
  if (last < s.length)
46
47
  parts.push(s.slice(last));
47
48
  return {
48
49
  __compiled: true,
50
+ source: s,
49
51
  call: (ctx) => parts.map((p) => (typeof p === "string" ? p : String(p.call(ctx) ?? ""))).join(""),
50
52
  };
51
53
  }
@@ -1,6 +1,6 @@
1
1
  /** An entry for a field that carries one or more x-telo-ref constraints. */
2
2
  export interface RefFieldEntry {
3
- /** One or more canonical ref strings ("namespace/module#TypeName" or "kernel#TypeName").
3
+ /** One or more canonical ref strings ("namespace/module#TypeName" or "telo#TypeName").
4
4
  * Multiple entries arise from anyOf branches. */
5
5
  refs: string[];
6
6
  /** True when the field path traversed through at least one array (path contains "[]"). */
@@ -0,0 +1,30 @@
1
+ import type { ResourceManifest } from "@telorun/sdk";
2
+ import type { AliasResolver } from "./alias-resolver.js";
3
+ import type { DefinitionRegistry } from "./definition-registry.js";
4
+ export interface ThrowsCodeMeta {
5
+ data?: Record<string, any>;
6
+ }
7
+ export interface ThrowsUnion {
8
+ /** Code → per-code metadata (data schema, etc). Keys are the declared codes. */
9
+ codes: Map<string, ThrowsCodeMeta>;
10
+ /** True when the union cannot be fully resolved statically — e.g. a
11
+ * `passthrough` call site uses a CEL expression the analyzer can't narrow,
12
+ * an unknown kind was encountered, or a cycle short-circuited resolution.
13
+ * Callers must treat unbounded unions as requiring a catch-all entry. */
14
+ unbounded: boolean;
15
+ }
16
+ export interface ResolveCtx {
17
+ allManifests: ResourceManifest[];
18
+ defs: DefinitionRegistry;
19
+ aliases: AliasResolver;
20
+ memo: Map<string, ThrowsUnion>;
21
+ inProgress: Set<string>;
22
+ }
23
+ export declare function createResolveCtx(allManifests: ResourceManifest[], defs: DefinitionRegistry, aliases: AliasResolver): ResolveCtx;
24
+ /** Resolve the effective throw union for a named manifest. The result combines
25
+ * explicit `throws.codes`, `throws.inherit: true` dataflow (step-context
26
+ * traversal with try/catch subtraction), and unbounded markers for
27
+ * unresolvable passthrough call sites. Cycles short-circuit to an empty
28
+ * result so resolution always terminates. */
29
+ export declare function resolveThrowsUnion(manifest: ResourceManifest, ctx: ResolveCtx): ThrowsUnion;
30
+ //# sourceMappingURL=resolve-throws-union.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-throws-union.d.ts","sourceRoot":"","sources":["../src/resolve-throws-union.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACnC;;;8EAG0E;IAC1E,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,IAAI,EAAE,kBAAkB,CAAC;IACzB,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC/B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB;AAED,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,gBAAgB,EAAE,EAChC,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,aAAa,GACrB,UAAU,CAQZ;AA+BD;;;;8CAI8C;AAC9C,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,gBAAgB,EAC1B,GAAG,EAAE,UAAU,GACd,WAAW,CA+Cb"}
@@ -0,0 +1,252 @@
1
+ export function createResolveCtx(allManifests, defs, aliases) {
2
+ return {
3
+ allManifests,
4
+ defs,
5
+ aliases,
6
+ memo: new Map(),
7
+ inProgress: new Set(),
8
+ };
9
+ }
10
+ function emptyUnion() {
11
+ return { codes: new Map(), unbounded: false };
12
+ }
13
+ function unionInto(target, src) {
14
+ for (const [code, meta] of src.codes) {
15
+ if (!target.codes.has(code))
16
+ target.codes.set(code, meta);
17
+ }
18
+ if (src.unbounded)
19
+ target.unbounded = true;
20
+ }
21
+ function definitionFor(kind, defs, aliases) {
22
+ const resolved = aliases.resolveKind(kind);
23
+ return defs.resolve(kind) ?? (resolved ? defs.resolve(resolved) : undefined);
24
+ }
25
+ function codesFromDefinition(definition) {
26
+ const out = new Map();
27
+ const raw = definition.throws?.codes ?? {};
28
+ for (const [code, meta] of Object.entries(raw)) {
29
+ out.set(code, { data: meta.data });
30
+ }
31
+ return out;
32
+ }
33
+ /** Resolve the effective throw union for a named manifest. The result combines
34
+ * explicit `throws.codes`, `throws.inherit: true` dataflow (step-context
35
+ * traversal with try/catch subtraction), and unbounded markers for
36
+ * unresolvable passthrough call sites. Cycles short-circuit to an empty
37
+ * result so resolution always terminates. */
38
+ export function resolveThrowsUnion(manifest, ctx) {
39
+ const name = manifest.metadata?.name;
40
+ if (name) {
41
+ const cached = ctx.memo.get(name);
42
+ if (cached)
43
+ return cached;
44
+ if (ctx.inProgress.has(name))
45
+ return emptyUnion();
46
+ }
47
+ const definition = definitionFor(manifest.kind, ctx.defs, ctx.aliases);
48
+ if (!definition) {
49
+ const u = { codes: new Map(), unbounded: true };
50
+ if (name)
51
+ ctx.memo.set(name, u);
52
+ return u;
53
+ }
54
+ const throws = definition.throws;
55
+ if (!throws) {
56
+ const u = emptyUnion();
57
+ if (name)
58
+ ctx.memo.set(name, u);
59
+ return u;
60
+ }
61
+ if (name)
62
+ ctx.inProgress.add(name);
63
+ try {
64
+ const result = { codes: new Map(), unbounded: false };
65
+ for (const [code, meta] of codesFromDefinition(definition)) {
66
+ result.codes.set(code, meta);
67
+ }
68
+ if (throws.passthrough) {
69
+ // Definition-level passthrough can't be resolved without a call site.
70
+ // resolveStepInvokeThrows handles passthrough call sites directly.
71
+ result.unbounded = true;
72
+ }
73
+ if (throws.inherit) {
74
+ const inherited = resolveInherited(manifest, definition, ctx);
75
+ unionInto(result, inherited);
76
+ }
77
+ if (name)
78
+ ctx.memo.set(name, result);
79
+ return result;
80
+ }
81
+ finally {
82
+ if (name)
83
+ ctx.inProgress.delete(name);
84
+ }
85
+ }
86
+ function resolveInherited(manifest, definition, ctx) {
87
+ const result = { codes: new Map(), unbounded: false };
88
+ const props = definition.schema?.properties;
89
+ if (!props)
90
+ return result;
91
+ for (const [fieldName, fieldSchema] of Object.entries(props)) {
92
+ const stepCtx = fieldSchema["x-telo-step-context"];
93
+ if (!stepCtx?.invoke)
94
+ continue;
95
+ const steps = manifest[fieldName];
96
+ if (!Array.isArray(steps))
97
+ continue;
98
+ unionInto(result, collectStepArrayThrows(steps, stepCtx.invoke, undefined, ctx));
99
+ }
100
+ return result;
101
+ }
102
+ function collectStepArrayThrows(steps, invokeField, enclosingTryCodes, ctx) {
103
+ const result = emptyUnion();
104
+ for (const step of steps) {
105
+ if (!step || typeof step !== "object")
106
+ continue;
107
+ unionInto(result, collectStepThrows(step, invokeField, enclosingTryCodes, ctx));
108
+ }
109
+ return result;
110
+ }
111
+ /** Walk one step, dispatching by shape. Generic for any Run.Sequence-style
112
+ * composer: the step keys it recognises (`try` / `catch` / `finally` / `then`
113
+ * / `else` / `elseif` / `do` / `cases` / `default`) are the same set already
114
+ * traversed by the analyzer's `x-telo-step-context` schema builder, so future
115
+ * composers that reuse those shape conventions work without changes here. */
116
+ function collectStepThrows(step, invokeField, enclosingTryCodes, ctx) {
117
+ if (step[invokeField]) {
118
+ return resolveStepInvokeThrows(step, invokeField, enclosingTryCodes, ctx);
119
+ }
120
+ if (step.throw && typeof step.throw === "object") {
121
+ return resolveThrowStepCode(step.throw, enclosingTryCodes);
122
+ }
123
+ if (Array.isArray(step.try)) {
124
+ const tryUnion = collectStepArrayThrows(step.try, invokeField, enclosingTryCodes, ctx);
125
+ let propagated;
126
+ if (Array.isArray(step.catch)) {
127
+ // Catch absorbs the try block's codes; the catch's own throws propagate
128
+ // out instead. Sequence-specific subtraction — the plan explicitly
129
+ // anchors this to Run.Sequence's try/catch schema shape.
130
+ const tryCodes = new Set(tryUnion.codes.keys());
131
+ propagated = collectStepArrayThrows(step.catch, invokeField, tryCodes, ctx);
132
+ // Unbounded in the try block still signals the caller to expect
133
+ // arbitrary codes to flow through the catch (e.g. via passthrough).
134
+ if (tryUnion.unbounded)
135
+ propagated.unbounded = true;
136
+ }
137
+ else {
138
+ propagated = cloneUnion(tryUnion);
139
+ }
140
+ if (Array.isArray(step.finally)) {
141
+ unionInto(propagated, collectStepArrayThrows(step.finally, invokeField, enclosingTryCodes, ctx));
142
+ }
143
+ return propagated;
144
+ }
145
+ if (Array.isArray(step.then)) {
146
+ const result = emptyUnion();
147
+ unionInto(result, collectStepArrayThrows(step.then, invokeField, enclosingTryCodes, ctx));
148
+ if (Array.isArray(step.else)) {
149
+ unionInto(result, collectStepArrayThrows(step.else, invokeField, enclosingTryCodes, ctx));
150
+ }
151
+ if (Array.isArray(step.elseif)) {
152
+ for (const branch of step.elseif) {
153
+ if (Array.isArray(branch?.then)) {
154
+ unionInto(result, collectStepArrayThrows(branch.then, invokeField, enclosingTryCodes, ctx));
155
+ }
156
+ }
157
+ }
158
+ return result;
159
+ }
160
+ if (Array.isArray(step.do)) {
161
+ return collectStepArrayThrows(step.do, invokeField, enclosingTryCodes, ctx);
162
+ }
163
+ if (step.cases && typeof step.cases === "object") {
164
+ const result = emptyUnion();
165
+ for (const arr of Object.values(step.cases)) {
166
+ if (Array.isArray(arr)) {
167
+ unionInto(result, collectStepArrayThrows(arr, invokeField, enclosingTryCodes, ctx));
168
+ }
169
+ }
170
+ if (Array.isArray(step.default)) {
171
+ unionInto(result, collectStepArrayThrows(step.default, invokeField, enclosingTryCodes, ctx));
172
+ }
173
+ return result;
174
+ }
175
+ return emptyUnion();
176
+ }
177
+ function cloneUnion(u) {
178
+ const out = emptyUnion();
179
+ for (const [c, m] of u.codes)
180
+ out.codes.set(c, m);
181
+ out.unbounded = u.unbounded;
182
+ return out;
183
+ }
184
+ function resolveStepInvokeThrows(step, invokeField, enclosingTryCodes, ctx) {
185
+ const invokeRef = step[invokeField];
186
+ if (!invokeRef || typeof invokeRef !== "object")
187
+ return emptyUnion();
188
+ const invokedKind = invokeRef.kind;
189
+ if (!invokedKind)
190
+ return emptyUnion();
191
+ const definition = definitionFor(invokedKind, ctx.defs, ctx.aliases);
192
+ if (!definition)
193
+ return { codes: new Map(), unbounded: true };
194
+ if (definition.throws?.passthrough) {
195
+ return resolvePassthroughAtCallSite(step, enclosingTryCodes);
196
+ }
197
+ // Named manifest: resolve the full chain (covers transitive inherit).
198
+ const invokeName = invokeRef.name;
199
+ if (invokeName) {
200
+ const target = ctx.allManifests.find((m) => m.metadata?.name === invokeName &&
201
+ (m.kind === invokedKind ||
202
+ ctx.aliases.resolveKind(m.kind) === invokedKind ||
203
+ m.kind === ctx.aliases.resolveKind(invokedKind)));
204
+ if (target)
205
+ return resolveThrowsUnion(target, ctx);
206
+ }
207
+ // Fall back to the definition's own explicit codes. Mark unbounded when the
208
+ // definition depends on call-site or transitive resolution we couldn't
209
+ // perform (no specific target manifest to recurse into).
210
+ const codes = codesFromDefinition(definition);
211
+ const unbounded = definition.throws?.inherit === true || definition.throws?.passthrough === true;
212
+ return { codes, unbounded };
213
+ }
214
+ /** Resolve a passthrough-style invocable at a specific call site. Recognised forms
215
+ * (see "passthrough: true" in the plan):
216
+ * - constant literal (no template) → `{ <literal> }`
217
+ * - `${{ 'FOO' }}` constant expression → `{ FOO }`
218
+ * - `${{ error.code }}` inside a catch → enclosing try's propagated union
219
+ * Anything else is unbounded; the analyzer flags it downstream. */
220
+ function resolvePassthroughAtCallSite(step, enclosingTryCodes) {
221
+ return resolveCodeExpression(step.inputs?.code, enclosingTryCodes);
222
+ }
223
+ /** Resolve the `code:` of a `throw:` step to a throws union. Uses the same
224
+ * recognised forms as passthrough call sites. */
225
+ function resolveThrowStepCode(throwSpec, enclosingTryCodes) {
226
+ return resolveCodeExpression(throwSpec.code, enclosingTryCodes);
227
+ }
228
+ function resolveCodeExpression(codeInput, enclosingTryCodes) {
229
+ if (typeof codeInput !== "string" || codeInput.length === 0) {
230
+ return { codes: new Map(), unbounded: true };
231
+ }
232
+ const match = codeInput.match(/^\s*\$\{\{\s*([\s\S]+?)\s*\}\}\s*$/);
233
+ if (!match) {
234
+ return { codes: new Map([[codeInput, {}]]), unbounded: false };
235
+ }
236
+ const expr = match[1].trim();
237
+ const litMatch = expr.match(/^'([^']+)'$|^"([^"]+)"$/);
238
+ if (litMatch) {
239
+ const code = litMatch[1] ?? litMatch[2];
240
+ return { codes: new Map([[code, {}]]), unbounded: false };
241
+ }
242
+ if (expr === "error.code") {
243
+ if (enclosingTryCodes) {
244
+ const codes = new Map();
245
+ for (const c of enclosingTryCodes)
246
+ codes.set(c, {});
247
+ return { codes, unbounded: false };
248
+ }
249
+ return { codes: new Map(), unbounded: true };
250
+ }
251
+ return { codes: new Map(), unbounded: true };
252
+ }