@telorun/analyzer 0.73.0 → 0.74.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 (138) hide show
  1. package/dist/analyzer.d.ts.map +1 -1
  2. package/dist/analyzer.js +26 -7
  3. package/dist/artifact-axes.d.ts +14 -0
  4. package/dist/artifact-axes.d.ts.map +1 -0
  5. package/dist/artifact-axes.js +12 -0
  6. package/dist/artifact-layer-index.d.ts +2 -2
  7. package/dist/artifact-layer-index.d.ts.map +1 -1
  8. package/dist/artifact-layer-index.js +9 -4
  9. package/dist/artifact-selector.d.ts +47 -21
  10. package/dist/artifact-selector.d.ts.map +1 -1
  11. package/dist/artifact-selector.js +85 -16
  12. package/dist/builtins.d.ts.map +1 -1
  13. package/dist/builtins.js +73 -16
  14. package/dist/call-graph.d.ts +12 -1
  15. package/dist/call-graph.d.ts.map +1 -1
  16. package/dist/call-graph.js +22 -0
  17. package/dist/catch-scope.js +1 -1
  18. package/dist/forwarded-declaration.d.ts +26 -0
  19. package/dist/forwarded-declaration.d.ts.map +1 -0
  20. package/dist/forwarded-declaration.js +31 -0
  21. package/dist/index.d.ts +9 -3
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +4 -1
  24. package/dist/kernel-globals.d.ts.map +1 -1
  25. package/dist/kernel-globals.js +21 -5
  26. package/dist/module-alias-scope.d.ts +11 -0
  27. package/dist/module-alias-scope.d.ts.map +1 -1
  28. package/dist/module-alias-scope.js +10 -0
  29. package/dist/module-file-claims.d.ts +17 -1
  30. package/dist/module-file-claims.d.ts.map +1 -1
  31. package/dist/module-file-claims.js +38 -3
  32. package/dist/module-named-files.d.ts +72 -0
  33. package/dist/module-named-files.d.ts.map +1 -0
  34. package/dist/module-named-files.js +115 -0
  35. package/dist/native-entries.d.ts +83 -0
  36. package/dist/native-entries.d.ts.map +1 -0
  37. package/dist/native-entries.js +169 -0
  38. package/dist/normalize-inline-resources.d.ts +41 -13
  39. package/dist/normalize-inline-resources.d.ts.map +1 -1
  40. package/dist/normalize-inline-resources.js +236 -54
  41. package/dist/reference-field-map.d.ts +59 -1
  42. package/dist/reference-field-map.d.ts.map +1 -1
  43. package/dist/reference-field-map.js +200 -34
  44. package/dist/release/payload-digest.d.ts +2 -1
  45. package/dist/release/payload-digest.d.ts.map +1 -1
  46. package/dist/release/payload-digest.js +2 -1
  47. package/dist/resolve-ref-sentinels.d.ts.map +1 -1
  48. package/dist/resolve-ref-sentinels.js +8 -5
  49. package/dist/resolve-throws-union.d.ts +25 -4
  50. package/dist/resolve-throws-union.d.ts.map +1 -1
  51. package/dist/resolve-throws-union.js +62 -32
  52. package/dist/resolve-zone-requirements.d.ts.map +1 -1
  53. package/dist/resolve-zone-requirements.js +2 -1
  54. package/dist/rewrite-synthetic-origins.d.ts +6 -1
  55. package/dist/rewrite-synthetic-origins.d.ts.map +1 -1
  56. package/dist/rewrite-synthetic-origins.js +107 -13
  57. package/dist/schema-compat.d.ts.map +1 -1
  58. package/dist/schema-compat.js +18 -5
  59. package/dist/schema-walk.d.ts +47 -13
  60. package/dist/schema-walk.d.ts.map +1 -1
  61. package/dist/schema-walk.js +150 -30
  62. package/dist/scope-declarations.d.ts +59 -0
  63. package/dist/scope-declarations.d.ts.map +1 -0
  64. package/dist/scope-declarations.js +45 -0
  65. package/dist/source-entries.d.ts +119 -0
  66. package/dist/source-entries.d.ts.map +1 -0
  67. package/dist/source-entries.js +349 -0
  68. package/dist/step-bodies.d.ts +24 -0
  69. package/dist/step-bodies.d.ts.map +1 -0
  70. package/dist/step-bodies.js +28 -0
  71. package/dist/telo-version.d.ts +1 -1
  72. package/dist/telo-version.js +1 -1
  73. package/dist/validate-cel-context.d.ts.map +1 -1
  74. package/dist/validate-cel-context.js +3 -2
  75. package/dist/validate-module-artifact.d.ts +4 -2
  76. package/dist/validate-module-artifact.d.ts.map +1 -1
  77. package/dist/validate-module-artifact.js +43 -4
  78. package/dist/validate-native-entries.d.ts +15 -0
  79. package/dist/validate-native-entries.d.ts.map +1 -0
  80. package/dist/validate-native-entries.js +103 -0
  81. package/dist/validate-observed-state.d.ts +7 -1
  82. package/dist/validate-observed-state.d.ts.map +1 -1
  83. package/dist/validate-observed-state.js +24 -6
  84. package/dist/validate-reference-forms.d.ts.map +1 -1
  85. package/dist/validate-reference-forms.js +2 -2
  86. package/dist/validate-references.d.ts.map +1 -1
  87. package/dist/validate-references.js +11 -5
  88. package/dist/validate-scope-reach.d.ts +31 -0
  89. package/dist/validate-scope-reach.d.ts.map +1 -0
  90. package/dist/validate-scope-reach.js +180 -0
  91. package/dist/validate-source-entries.d.ts +16 -0
  92. package/dist/validate-source-entries.d.ts.map +1 -0
  93. package/dist/validate-source-entries.js +90 -0
  94. package/dist/validate-throws-coverage.d.ts.map +1 -1
  95. package/dist/validate-throws-coverage.js +21 -39
  96. package/dist/value-type-keyword.d.ts +22 -5
  97. package/dist/value-type-keyword.d.ts.map +1 -1
  98. package/dist/value-type-keyword.js +16 -7
  99. package/package.json +3 -3
  100. package/src/analyzer.ts +33 -9
  101. package/src/artifact-axes.ts +24 -0
  102. package/src/artifact-layer-index.ts +9 -6
  103. package/src/artifact-selector.ts +110 -35
  104. package/src/builtins.ts +75 -16
  105. package/src/call-graph.ts +30 -0
  106. package/src/catch-scope.ts +1 -1
  107. package/src/forwarded-declaration.ts +32 -0
  108. package/src/index.ts +36 -1
  109. package/src/kernel-globals.ts +28 -5
  110. package/src/migrations/CLAUDE.md +35 -0
  111. package/src/module-alias-scope.ts +17 -0
  112. package/src/module-file-claims.ts +63 -4
  113. package/src/module-named-files.ts +162 -0
  114. package/src/native-entries.ts +227 -0
  115. package/src/normalize-inline-resources.ts +326 -70
  116. package/src/reference-field-map.ts +257 -52
  117. package/src/release/CLAUDE.md +32 -0
  118. package/src/release/payload-digest.ts +2 -1
  119. package/src/resolve-ref-sentinels.ts +7 -6
  120. package/src/resolve-throws-union.ts +87 -32
  121. package/src/resolve-zone-requirements.ts +2 -1
  122. package/src/rewrite-synthetic-origins.ts +107 -16
  123. package/src/schema-compat.ts +18 -4
  124. package/src/schema-walk.ts +162 -34
  125. package/src/scope-declarations.ts +98 -0
  126. package/src/source-entries.ts +502 -0
  127. package/src/step-bodies.ts +55 -0
  128. package/src/telo-version.ts +1 -1
  129. package/src/validate-cel-context.ts +3 -2
  130. package/src/validate-module-artifact.ts +46 -3
  131. package/src/validate-native-entries.ts +147 -0
  132. package/src/validate-observed-state.ts +36 -7
  133. package/src/validate-reference-forms.ts +2 -3
  134. package/src/validate-references.ts +10 -6
  135. package/src/validate-scope-reach.ts +213 -0
  136. package/src/validate-source-entries.ts +120 -0
  137. package/src/validate-throws-coverage.ts +24 -31
  138. package/src/value-type-keyword.ts +35 -9
@@ -1 +1 @@
1
- {"version":3,"file":"rewrite-synthetic-origins.d.ts","sourceRoot":"","sources":["../src/rewrite-synthetic-origins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAsBrD;;;;;0EAK0E;AAC1E,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,kBAAkB,EAAE,EACjC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,kBAAkB,EAAE,CA0CtB"}
1
+ {"version":3,"file":"rewrite-synthetic-origins.d.ts","sourceRoot":"","sources":["../src/rewrite-synthetic-origins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAsBrD;;;;;;;;;;+EAU+E;AAC/E,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,kBAAkB,EAAE,EACjC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,kBAAkB,EAAE,CA0CtB"}
@@ -1,5 +1,5 @@
1
1
  function readOrigin(manifest) {
2
- if (!manifest)
2
+ if (!manifest || typeof manifest !== "object")
3
3
  return undefined;
4
4
  const origin = manifest.metadata?.xTeloOrigin;
5
5
  if (!origin ||
@@ -15,7 +15,12 @@ function readOrigin(manifest) {
15
15
  * `data.resource`, which has no YAML source. Rewrite each such diagnostic
16
16
  * back to the chain root: walk up `metadata.xTeloOrigin` until a manifest
17
17
  * with no origin is reached, and prepend each hop's `pathFromParent` to
18
- * `data.path` so position-index lookups against the root doc resolve. */
18
+ * `data.path` so position-index lookups against the root doc resolve.
19
+ *
20
+ * An extraction from a scope member lives INSIDE the scope array rather than at
21
+ * the top level, so a diagnostic about it names the top-level owner and a path
22
+ * through an array index the author never wrote (`with[3]`). That prefix is
23
+ * unfolded the same way, into the position the declaration was written at. */
19
24
  export function rewriteSyntheticOrigins(diagnostics, manifests) {
20
25
  const byName = new Map();
21
26
  for (const m of manifests) {
@@ -29,27 +34,116 @@ export function rewriteSyntheticOrigins(diagnostics, manifests) {
29
34
  return d;
30
35
  let current = byName.get(data.resource.name);
31
36
  let origin = readOrigin(current);
32
- if (!origin)
33
- return d;
34
- let accumPath = typeof data.path === "string" ? data.path : "";
35
- let rootKind = origin.parentKind;
36
- let rootName = origin.parentName;
37
+ const path = typeof data.path === "string" ? data.path : "";
38
+ let accumPath = path;
39
+ let root = data.resource;
37
40
  while (origin) {
38
41
  accumPath = accumPath ? `${origin.pathFromParent}.${accumPath}` : origin.pathFromParent;
39
- rootKind = origin.parentKind;
40
- rootName = origin.parentName;
42
+ root = { kind: origin.parentKind, name: origin.parentName };
41
43
  current = byName.get(origin.parentName);
42
44
  origin = readOrigin(current);
43
45
  }
44
- const rootFilePath = current?.metadata?.source ?? data.filePath;
46
+ const rerouted = root !== data.resource;
47
+ const unfolded = current ? unfoldScopedOrigins(current, accumPath) : accumPath;
48
+ if (!rerouted && unfolded === path)
49
+ return d;
45
50
  return {
46
51
  ...d,
47
52
  data: {
48
53
  ...data,
49
- resource: { kind: rootKind, name: rootName },
50
- filePath: rootFilePath,
51
- path: accumPath,
54
+ resource: root,
55
+ filePath: rerouted
56
+ ? (current?.metadata?.source ?? data.filePath)
57
+ : data.filePath,
58
+ path: unfolded,
52
59
  },
53
60
  };
54
61
  });
55
62
  }
63
+ /** Replace every scope-array index that holds an extraction with the position
64
+ * the extraction was written at, until none is left. */
65
+ function unfoldScopedOrigins(root, path) {
66
+ let segments = parseSegments(path);
67
+ let unfoldedAny = false;
68
+ // Each unfolding replaces one extraction with its parent, which is strictly
69
+ // closer to what the author wrote, so the chain is as long as the nesting.
70
+ for (let hops = 0; hops <= segments.length + 16; hops++) {
71
+ const next = unfoldOnce(root, segments);
72
+ if (!next)
73
+ break;
74
+ segments = next;
75
+ unfoldedAny = true;
76
+ }
77
+ // Re-formatting is lossy (an empty segment in `entries../x` is dropped), so a
78
+ // path nothing unfolded is returned as written.
79
+ return unfoldedAny ? formatSegments(segments) : path;
80
+ }
81
+ function unfoldOnce(root, segments) {
82
+ let node = root;
83
+ for (let i = 0; i < segments.length; i++) {
84
+ const segment = segments[i];
85
+ const container = node;
86
+ node =
87
+ typeof segment === "number"
88
+ ? Array.isArray(container)
89
+ ? container[segment]
90
+ : undefined
91
+ : container && typeof container === "object" && !Array.isArray(container)
92
+ ? container[segment]
93
+ : undefined;
94
+ if (node === undefined || node === null)
95
+ return undefined;
96
+ if (typeof segment !== "number" || i === 0)
97
+ continue;
98
+ const origin = readOrigin(node);
99
+ if (!origin)
100
+ continue;
101
+ // Its parent is either the resource holding this scope array (a slot of
102
+ // the resource that declares the scope) or a sibling member of the array.
103
+ const holderPath = segments.slice(0, i - 1);
104
+ let parentPath;
105
+ if (nameOf(at(root, holderPath)) === origin.parentName) {
106
+ parentPath = holderPath;
107
+ }
108
+ else {
109
+ const sibling = container.findIndex((m) => nameOf(m) === origin.parentName);
110
+ if (sibling >= 0)
111
+ parentPath = [...segments.slice(0, i), sibling];
112
+ }
113
+ if (!parentPath)
114
+ return undefined;
115
+ return [...parentPath, ...parseSegments(origin.pathFromParent), ...segments.slice(i + 1)];
116
+ }
117
+ return undefined;
118
+ }
119
+ function at(root, segments) {
120
+ let node = root;
121
+ for (const segment of segments) {
122
+ if (!node || typeof node !== "object")
123
+ return undefined;
124
+ node = node[segment];
125
+ }
126
+ return node;
127
+ }
128
+ function nameOf(value) {
129
+ const name = value?.metadata?.name;
130
+ return typeof name === "string" ? name : undefined;
131
+ }
132
+ /** `with[3].steps[0].invoke` → `["with", 3, "steps", 0, "invoke"]`. */
133
+ function parseSegments(path) {
134
+ const out = [];
135
+ for (const match of path.matchAll(/\[(\d+)\]|([^.[\]]+)/g)) {
136
+ out.push(match[1] !== undefined ? Number(match[1]) : match[2]);
137
+ }
138
+ return out;
139
+ }
140
+ function formatSegments(segments) {
141
+ let out = "";
142
+ for (const segment of segments) {
143
+ if (typeof segment === "number")
144
+ out += `[${segment}]`;
145
+ else
146
+ out += out ? `.${segment}` : segment;
147
+ }
148
+ return out;
149
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"schema-compat.d.ts","sourceRoot":"","sources":["../src/schema-compat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema-compat.d.ts","sourceRoot":"","sources":["../src/schema-compat.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import AjvModule from "ajv";
2
2
  import addFormats from "ajv-formats";
3
3
  import { isRefSentinel, isTaggedSentinel, producedTypeOf, } from "@telorun/templating";
4
- import { celBaseOfValueType, celTypeOfValueType, isCompiledValue, readValueTypeSlot, valueBrandBases, valueTypeOf, valueTypePlaceholder, } from "@telorun/sdk";
4
+ import { celBaseOfValueType, celTypeOfValueType, isCompiledValue, readValueTypeSlot, VALUE_TYPE_BINDINGS, valueBrandBases, valueTypeOf, valueTypePlaceholder, } from "@telorun/sdk";
5
5
  import { ManifestRootSchema } from "./manifest-schemas.js";
6
6
  import { schemaIssues } from "./schema-error-report.js";
7
7
  import { registerTeloKeywords } from "./value-type-keyword.js";
@@ -22,8 +22,9 @@ export function createAjv() {
22
22
  // One registration site for every Telo keyword — the annotations as no-ops and
23
23
  // `x-telo-type` as the one that checks. Registered here and in the kernel's
24
24
  // validators from one definition, so a literal at an instance-typed slot is
25
- // rejected statically and at dispatch by the identical rule.
26
- registerTeloKeywords(instance);
25
+ // rejected statically and at dispatch by the identical rule. This instance is
26
+ // static analysis alone, so it also asserts a `live` type: no literal can be one.
27
+ registerTeloKeywords(instance, { assertLive: true });
27
28
  instance.addSchema(ManifestRootSchema);
28
29
  return instance;
29
30
  }
@@ -463,6 +464,18 @@ function foldedConstraints(schema) {
463
464
  }
464
465
  return out;
465
466
  }
467
+ /** The stand-in for a CEL leaf at a `live` slot. Static analysis asserts a live
468
+ * type like any instance type (a literal can never be one), so the leaf's
469
+ * stand-in has to BE one. A live binding declares no factory, and building an
470
+ * instance would mean knowing its constructor's signature; an object on the
471
+ * constructor's prototype satisfies `instanceof` and is never used as one. */
472
+ function liveValuePlaceholder(schema) {
473
+ const entry = readValueTypeSlot(schema)?.entry;
474
+ if (!entry?.live || entry.representation !== "instance")
475
+ return undefined;
476
+ const binding = VALUE_TYPE_BINDINGS[entry.binding];
477
+ return binding ? Object.create(binding.constructor.prototype) : undefined;
478
+ }
466
479
  export function celPlaceholderForSchema(rawSchema) {
467
480
  const schema = foldedConstraints(rawSchema);
468
481
  // An instance-typed slot's placeholder must BE an instance: the same keyword
@@ -471,8 +484,8 @@ export function celPlaceholderForSchema(rawSchema) {
471
484
  // rejected because no YAML literal is a byte buffer, while a value arriving by
472
485
  // reference passes. The stand-in comes from the binding table, so a new
473
486
  // instance type brings its own rather than adding a branch here; a `live` type
474
- // declares none, because nothing validates it.
475
- const placeholder = valueTypePlaceholder(schema);
487
+ // declares none, because nothing validates it at dispatch.
488
+ const placeholder = valueTypePlaceholder(schema) ?? liveValuePlaceholder(schema);
476
489
  if (placeholder !== undefined)
477
490
  return placeholder;
478
491
  if (schema.default !== undefined)
@@ -1,5 +1,5 @@
1
- import { type RefSlot } from "./ref-slot.js";
2
- import { type StepSlot } from "./step-slot.js";
1
+ import type { RefSlot } from "./ref-slot.js";
2
+ import type { StepSlot } from "./step-slot.js";
3
3
  /** Resolve a local `$ref` (only `#/$defs/<name>` form) against the root schema.
4
4
  * Non-refs and unresolved refs pass through unchanged. */
5
5
  export declare function resolveLocalRef(schema: Record<string, any> | undefined, root: Record<string, any>): Record<string, any> | undefined;
@@ -24,29 +24,63 @@ export declare function gatherPropertySchemas(schema: Record<string, any>, root?
24
24
  * hardcoded; recursion is driven entirely by the schema annotations.
25
25
  */
26
26
  export declare function walkStepArray(steps: unknown[], stepItemSchema: Record<string, any> | undefined, rootSchema: Record<string, any>, basePath: string, visit: (step: Record<string, any>, stepPath: string) => void): void;
27
- /** A slot through which a resource drives another. */
27
+ /** A slot a kind's schema declares through which its resources drive another.
28
+ * `path` is the field-map form (`routes[].handler`, `content.{}.encoder`);
29
+ * `slots` holds every slot any branch declares there. */
30
+ export type DeclaredSlot = {
31
+ kind: "step";
32
+ slots: StepSlot[];
33
+ path: string;
34
+ } | {
35
+ kind: "ref";
36
+ slots: RefSlot[];
37
+ path: string;
38
+ };
39
+ /** A reference slot at a site, with the declaration it came from — which is
40
+ * what a case-map selector's schema default is read against. */
41
+ export interface DrivenRef {
42
+ slot: RefSlot;
43
+ fieldPath: string;
44
+ }
45
+ /** The slots at one concrete site of one resource (`routes[0].handler`): every
46
+ * slot any branch or recursion route declares there. A consumer reads them as
47
+ * a union — a branch that does not apply to this resource can only add what
48
+ * counts, never remove it. */
28
49
  export type DrivenSlot = {
29
50
  kind: "step";
30
- slot: StepSlot;
51
+ slots: StepSlot[];
31
52
  data: unknown[];
32
53
  path: string;
33
54
  } | {
34
55
  kind: "ref";
35
- slot: RefSlot;
56
+ slots: DrivenRef[];
36
57
  data: unknown;
37
58
  path: string;
38
59
  };
60
+ /**
61
+ * Every slot a kind's schema declares through which its resources drive
62
+ * another — the schema-only mode of {@link forEachDrivenSlot}, read off the
63
+ * same {@link buildDrivenSlotMap}.
64
+ */
65
+ export declare function forEachDeclaredSlot(schema: unknown, visit: (slot: DeclaredSlot) => void): void;
39
66
  /**
40
67
  * Every slot of one resource through which it drives another, schema and data in
41
68
  * tandem.
42
69
  *
43
- * One traversal with two consumersthe inherited union here, and the catch
44
- * scope enclosure in `validate-throws-coverage.ts` because both ask the same
45
- * structural question and two copies would eventually disagree about where the
46
- * walk stops. It terminates on the manifest's own depth, and it stops AT a step
47
- * slot (that traversal owns everything below it, `try`/`catch` subtraction
48
- * included) and AT a reference slot (a resolved ref is a leaf, `{kind, name}`,
49
- * with nothing beneath it to visit).
70
+ * One traversal for every throws question a kind's `inherit` union, a scope
71
+ * list's denominator, catch-scope enclosure, and whether `inherit` is legal
72
+ * because they ask the same structural question and two copies would eventually
73
+ * disagree about where the walk stops. The slots are the driven-slot map's, so
74
+ * the reach is the reference field map's plus local `$ref`; a step slot is a
75
+ * stop (that traversal owns everything below it, `try`/`catch` subtraction
76
+ * included) and so is a reference slot (a resolved ref is a leaf).
77
+ *
78
+ * Each concrete site is visited once, with every slot that reaches it. A
79
+ * map-value (`additionalProperties`) slot applies only to keys its schema does
80
+ * not declare, and never to the resource envelope at the root, as JSON Schema
81
+ * applies it. A recursive schema's back-edge is followed as deep as the data
82
+ * goes, guarded against data that aliases one of its own ancestors. A schema
83
+ * whose map holds no step or reference slot is not walked at all.
50
84
  */
51
- export declare function forEachDrivenSlot(schema: unknown, data: unknown, visit: (slot: DrivenSlot) => void, path?: string): void;
85
+ export declare function forEachDrivenSlot(schema: unknown, data: unknown, visit: (slot: DrivenSlot) => void): void;
52
86
  //# sourceMappingURL=schema-walk.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-walk.d.ts","sourceRoot":"","sources":["../src/schema-walk.ts"],"names":[],"mappings":"AAWA,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE7D;2DAC2D;AAC3D,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACvC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACxB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAqBjC;AAID;;;;;;;;iDAQiD;AACjD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACzB,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAsBtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,OAAO,EAAE,EAChB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EAC/C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAC3D,IAAI,CAiDN;AACD,sDAAsD;AACtD,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,EACjC,IAAI,SAAK,GACR,IAAI,CA8BN"}
1
+ {"version":3,"file":"schema-walk.d.ts","sourceRoot":"","sources":["../src/schema-walk.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/C;2DAC2D;AAC3D,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACvC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACxB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAqBjC;AAID;;;;;;;;iDAQiD;AACjD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACzB,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAsBtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,OAAO,EAAE,EAChB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EAC/C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAC3D,IAAI,CAiDN;AACD;;0DAE0D;AAC1D,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD;iEACiE;AACjE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;+BAG+B;AAC/B,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,SAAS,EAAE,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI,CAM9F;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,GAChC,IAAI,CAkDN"}
@@ -9,8 +9,7 @@
9
9
  * scope rule is consumed by the IDE, which must not pull the pass in behind it.
10
10
  */
11
11
  import { MANIFEST_SCHEMA_URI, ManifestRootSchema } from "./manifest-schemas.js";
12
- import { readRefSlot } from "./ref-slot.js";
13
- import { readStepSlot } from "./step-slot.js";
12
+ import { buildDrivenSlotMap, refSlotOfEntry } from "./reference-field-map.js";
14
13
  /** Resolve a local `$ref` (only `#/$defs/<name>` form) against the root schema.
15
14
  * Non-refs and unresolved refs pass through unchanged. */
16
15
  export function resolveLocalRef(schema, root) {
@@ -126,45 +125,166 @@ export function walkStepArray(steps, stepItemSchema, rootSchema, basePath, visit
126
125
  }
127
126
  });
128
127
  }
128
+ /**
129
+ * Every slot a kind's schema declares through which its resources drive
130
+ * another — the schema-only mode of {@link forEachDrivenSlot}, read off the
131
+ * same {@link buildDrivenSlotMap}.
132
+ */
133
+ export function forEachDeclaredSlot(schema, visit) {
134
+ if (!schema || typeof schema !== "object")
135
+ return;
136
+ for (const [path, at] of buildDrivenSlotMap(schema).paths) {
137
+ if (at.steps.length > 0)
138
+ visit({ kind: "step", slots: at.steps, path });
139
+ if (at.refs.length > 0)
140
+ visit({ kind: "ref", slots: at.refs.map(refSlotOfEntry), path });
141
+ }
142
+ }
129
143
  /**
130
144
  * Every slot of one resource through which it drives another, schema and data in
131
145
  * tandem.
132
146
  *
133
- * One traversal with two consumersthe inherited union here, and the catch
134
- * scope enclosure in `validate-throws-coverage.ts` because both ask the same
135
- * structural question and two copies would eventually disagree about where the
136
- * walk stops. It terminates on the manifest's own depth, and it stops AT a step
137
- * slot (that traversal owns everything below it, `try`/`catch` subtraction
138
- * included) and AT a reference slot (a resolved ref is a leaf, `{kind, name}`,
139
- * with nothing beneath it to visit).
147
+ * One traversal for every throws question a kind's `inherit` union, a scope
148
+ * list's denominator, catch-scope enclosure, and whether `inherit` is legal
149
+ * because they ask the same structural question and two copies would eventually
150
+ * disagree about where the walk stops. The slots are the driven-slot map's, so
151
+ * the reach is the reference field map's plus local `$ref`; a step slot is a
152
+ * stop (that traversal owns everything below it, `try`/`catch` subtraction
153
+ * included) and so is a reference slot (a resolved ref is a leaf).
154
+ *
155
+ * Each concrete site is visited once, with every slot that reaches it. A
156
+ * map-value (`additionalProperties`) slot applies only to keys its schema does
157
+ * not declare, and never to the resource envelope at the root, as JSON Schema
158
+ * applies it. A recursive schema's back-edge is followed as deep as the data
159
+ * goes, guarded against data that aliases one of its own ancestors. A schema
160
+ * whose map holds no step or reference slot is not walked at all.
140
161
  */
141
- export function forEachDrivenSlot(schema, data, visit, path = "") {
162
+ export function forEachDrivenSlot(schema, data, visit) {
142
163
  if (!schema || typeof schema !== "object" || data === undefined || data === null)
143
164
  return;
144
- const node = schema;
145
- const stepSlot = readStepSlot(node);
146
- if (stepSlot) {
147
- if (Array.isArray(data))
148
- visit({ kind: "step", slot: stepSlot, data, path });
149
- return;
150
- }
151
- const refSlot = readRefSlot(node);
152
- if (refSlot) {
153
- visit({ kind: "ref", slot: refSlot, data, path });
165
+ const driven = buildDrivenSlotMap(schema);
166
+ if (!driven.drives)
154
167
  return;
155
- }
156
- const props = node.properties;
157
- if (props && typeof data === "object" && !Array.isArray(data)) {
158
- const obj = data;
159
- for (const [key, propSchema] of Object.entries(props)) {
160
- if (obj[key] === undefined)
168
+ const sites = new Map();
169
+ const onData = new Set([data]);
170
+ const walk = (prefix, value, base) => {
171
+ for (const [fieldPath, at] of driven.paths) {
172
+ const rel = relativeFieldPath(fieldPath, prefix);
173
+ if (rel === undefined)
161
174
  continue;
162
- forEachDrivenSlot(propSchema, obj[key], visit, path ? `${path}.${key}` : key);
175
+ for (const found of resolveSites(value, rel, prefix, driven)) {
176
+ const path = joinConcrete(base, found.path);
177
+ if (at.steps.length > 0 || at.refs.length > 0) {
178
+ let site = sites.get(path);
179
+ if (!site) {
180
+ site = { data: found.value, steps: [], refs: [], from: new Set() };
181
+ sites.set(path, site);
182
+ }
183
+ for (const step of at.steps) {
184
+ if (site.from.has(step))
185
+ continue;
186
+ site.from.add(step);
187
+ site.steps.push(step);
188
+ }
189
+ for (const entry of at.refs) {
190
+ if (site.from.has(entry))
191
+ continue;
192
+ site.from.add(entry);
193
+ site.refs.push({ slot: refSlotOfEntry(entry), fieldPath });
194
+ }
195
+ }
196
+ if (at.recurse.length === 0)
197
+ continue;
198
+ if (!found.value || typeof found.value !== "object" || onData.has(found.value))
199
+ continue;
200
+ onData.add(found.value);
201
+ for (const to of at.recurse)
202
+ walk(to, found.value, path);
203
+ onData.delete(found.value);
204
+ }
205
+ }
206
+ };
207
+ walk("", data, "");
208
+ for (const [path, site] of sites) {
209
+ if (site.steps.length > 0 && Array.isArray(site.data)) {
210
+ visit({ kind: "step", slots: site.steps, data: site.data, path });
211
+ }
212
+ else if (site.refs.length > 0) {
213
+ visit({ kind: "ref", slots: site.refs, data: site.data, path });
163
214
  }
164
215
  }
165
- if (node.items && Array.isArray(data)) {
166
- for (const [i, item] of data.entries()) {
167
- forEachDrivenSlot(node.items, item, visit, `${path}[${i}]`);
216
+ }
217
+ /** The values at `rel` below `value`, where `rel` is relative to the field path
218
+ * `prefix`. A `{}` segment skips the keys the driven map records as declared
219
+ * for that map path; each `[]` iterates one array level. */
220
+ function resolveSites(value, rel, prefix, driven) {
221
+ let sites = [{ value, path: "" }];
222
+ let field = prefix;
223
+ for (const part of rel.split(".")) {
224
+ const next = [];
225
+ if (part === "{}") {
226
+ field = joinKey(field, "{}");
227
+ const declared = driven.declaredKeys.get(field);
228
+ for (const site of sites) {
229
+ if (!site.value || typeof site.value !== "object" || Array.isArray(site.value))
230
+ continue;
231
+ for (const [key, entry] of Object.entries(site.value)) {
232
+ if (entry == null || declared?.has(key))
233
+ continue;
234
+ next.push({ value: entry, path: joinKey(site.path, key) });
235
+ }
236
+ }
168
237
  }
238
+ else {
239
+ const key = part.replace(/(\[\])+$/, "");
240
+ const depth = (part.length - key.length) / 2;
241
+ field = key ? joinKey(field, part) : `${field}${part}`;
242
+ for (const site of sites) {
243
+ let level;
244
+ if (key) {
245
+ if (!site.value || typeof site.value !== "object")
246
+ continue;
247
+ const entry = site.value[key];
248
+ if (entry == null)
249
+ continue;
250
+ level = [{ value: entry, path: joinKey(site.path, key) }];
251
+ }
252
+ else {
253
+ level = [site];
254
+ }
255
+ for (let d = 0; d < depth; d++) {
256
+ const items = [];
257
+ for (const holder of level) {
258
+ if (!Array.isArray(holder.value))
259
+ continue;
260
+ holder.value.forEach((item, i) => {
261
+ if (item != null)
262
+ items.push({ value: item, path: `${holder.path}[${i}]` });
263
+ });
264
+ }
265
+ level = items;
266
+ }
267
+ next.push(...level);
268
+ }
269
+ }
270
+ sites = next;
169
271
  }
272
+ return sites;
273
+ }
274
+ const joinKey = (path, key) => (path ? `${path}.${key}` : key);
275
+ /** `fieldPath` relative to `prefix`, or undefined when it is not strictly
276
+ * below it. A result starting `[]` iterates the value at `prefix` itself. */
277
+ function relativeFieldPath(fieldPath, prefix) {
278
+ if (prefix === "")
279
+ return fieldPath;
280
+ if (fieldPath.startsWith(`${prefix}.`))
281
+ return fieldPath.slice(prefix.length + 1);
282
+ if (fieldPath.startsWith(`${prefix}[]`))
283
+ return fieldPath.slice(prefix.length);
284
+ return undefined;
285
+ }
286
+ function joinConcrete(base, rel) {
287
+ if (!base)
288
+ return rel;
289
+ return rel.startsWith("[") ? `${base}${rel}` : `${base}.${rel}`;
170
290
  }
@@ -0,0 +1,59 @@
1
+ import type { ResourceManifest } from "@telorun/sdk";
2
+ import { type ReferenceFieldMap } from "./reference-field-map.js";
3
+ /**
4
+ * The execution scopes ONE resource declares — the `x-telo-scope` arrays it
5
+ * holds — read off its kind's field map, which is the analyzer's single
6
+ * definition of "scope" (the same one `resolve-ref-sentinels` and
7
+ * `manifest-visitor` read). Inferring a scope from shape instead would give one
8
+ * to any kind that happens to carry an array of named declarations.
9
+ *
10
+ * Browser-safe.
11
+ */
12
+ /** One declared scope: the array a scope run creates, and where its names resolve. */
13
+ export interface DeclaredScope {
14
+ /** Concrete path of the scope slot on its resource (`with`). */
15
+ path: string;
16
+ /** The declaration array itself — what a scope run registers and tears down. */
17
+ declarations: unknown[];
18
+ /** Dot-form prefixes of every region its names resolve in (`steps`, `targets`). */
19
+ regions: string[];
20
+ }
21
+ export type ScopeMember = ResourceManifest & {
22
+ metadata: {
23
+ name: string;
24
+ };
25
+ };
26
+ /** Every scope `resource` declares, in field-map order. A scope slot left unset
27
+ * declares nothing: no scope run happens, so nothing is created in one. */
28
+ export declare function declaredScopes(resource: Record<string, unknown>, fieldMap: ReferenceFieldMap | undefined): DeclaredScope[];
29
+ /** True when `path` — a field-map path (`steps[].invoke`) or a concrete one
30
+ * (`steps[0].invoke`) — lies inside one of the scope's regions. */
31
+ export declare function scopeEncloses(scope: DeclaredScope, path: string): boolean;
32
+ /** A scope's inline resource declarations. A `!ref` entry is a category error
33
+ * (`SCOPE_ENTRY_NOT_INLINE`), not a member. */
34
+ export declare function scopeMembers(scope: DeclaredScope): ScopeMember[];
35
+ /** True when a scope array entry is an inline resource declaration. */
36
+ export declare function isScopeMember(value: unknown): value is ScopeMember;
37
+ /**
38
+ * A scope an extracted declaration was WRITTEN inside and is NOT created in.
39
+ *
40
+ * An inline declaration is created in the set its owner is declared in, never in
41
+ * a scope its owner declares — moving it there would make every step target of a
42
+ * sequence with a `with:` block a scoped resource, which is a change of durable
43
+ * identity. So a declaration written in `steps:` next to a `with:` block is
44
+ * lexically inside that scope and lives outside it, and the names the scope
45
+ * declares are out of its reach. Recorded at extraction, where both facts are in
46
+ * hand, as `metadata.xTeloOrigin.outsideScopes`.
47
+ */
48
+ export interface OutsideScope {
49
+ /** The resource declaring the scope, as its manifest spells it. */
50
+ ownerKind: string;
51
+ ownerName: string;
52
+ /** The scope slot (`with`). */
53
+ field: string;
54
+ /** Every name the scope declares. */
55
+ names: string[];
56
+ }
57
+ /** The scopes recorded as out of reach for an extracted declaration. */
58
+ export declare function outsideScopesOf(manifest: unknown): OutsideScope[];
59
+ //# sourceMappingURL=scope-declarations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-declarations.d.ts","sourceRoot":"","sources":["../src/scope-declarations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,EAAqC,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAErG;;;;;;;;GAQG;AAEH,sFAAsF;AACtF,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,YAAY,EAAE,OAAO,EAAE,CAAC;IACxB,mFAAmF;IACnF,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,MAAM,WAAW,GAAG,gBAAgB,GAAG;IAAE,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAE5E;4EAC4E;AAC5E,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,GACtC,aAAa,EAAE,CAYjB;AAED;oEACoE;AACpE,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAIzE;AAED;gDACgD;AAChD,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,WAAW,EAAE,CAEhE;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAOlE;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAY;IAC3B,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,YAAY,EAAE,CAMjE"}
@@ -0,0 +1,45 @@
1
+ import { isRefSentinel } from "@telorun/templating";
2
+ import { isScopeEntry, resolveFieldEntries } from "./reference-field-map.js";
3
+ /** Every scope `resource` declares, in field-map order. A scope slot left unset
4
+ * declares nothing: no scope run happens, so nothing is created in one. */
5
+ export function declaredScopes(resource, fieldMap) {
6
+ if (!fieldMap)
7
+ return [];
8
+ const out = [];
9
+ for (const [fieldPath, entry] of fieldMap) {
10
+ if (!isScopeEntry(entry))
11
+ continue;
12
+ const pointers = Array.isArray(entry.scope) ? entry.scope : [entry.scope];
13
+ const regions = pointers.map((p) => p.replace(/^\//, "").replace(/\//g, "."));
14
+ for (const { value, path } of resolveFieldEntries(resource, fieldPath)) {
15
+ if (Array.isArray(value))
16
+ out.push({ path, declarations: value, regions });
17
+ }
18
+ }
19
+ return out;
20
+ }
21
+ /** True when `path` — a field-map path (`steps[].invoke`) or a concrete one
22
+ * (`steps[0].invoke`) — lies inside one of the scope's regions. */
23
+ export function scopeEncloses(scope, path) {
24
+ return scope.regions.some((region) => path === region || path.startsWith(`${region}.`) || path.startsWith(`${region}[`));
25
+ }
26
+ /** A scope's inline resource declarations. A `!ref` entry is a category error
27
+ * (`SCOPE_ENTRY_NOT_INLINE`), not a member. */
28
+ export function scopeMembers(scope) {
29
+ return scope.declarations.filter(isScopeMember);
30
+ }
31
+ /** True when a scope array entry is an inline resource declaration. */
32
+ export function isScopeMember(value) {
33
+ if (!value || typeof value !== "object" || Array.isArray(value) || isRefSentinel(value)) {
34
+ return false;
35
+ }
36
+ const entry = value;
37
+ const name = entry.metadata?.name;
38
+ return typeof entry.kind === "string" && typeof entry.name !== "string" && typeof name === "string";
39
+ }
40
+ /** The scopes recorded as out of reach for an extracted declaration. */
41
+ export function outsideScopesOf(manifest) {
42
+ const origin = (manifest
43
+ ?.metadata?.xTeloOrigin)?.outsideScopes;
44
+ return Array.isArray(origin) ? origin : [];
45
+ }