@telorun/analyzer 0.53.0 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis-registry.d.ts +20 -0
- package/dist/analysis-registry.d.ts.map +1 -1
- package/dist/analysis-registry.js +36 -3
- package/dist/analyzer.d.ts +3 -2
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +188 -26
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +32 -12
- package/dist/call-graph.d.ts +189 -0
- package/dist/call-graph.d.ts.map +1 -0
- package/dist/call-graph.js +617 -0
- package/dist/dependency-graph.d.ts +17 -7
- package/dist/dependency-graph.d.ts.map +1 -1
- package/dist/dependency-graph.js +36 -65
- package/dist/flatten-for-analyzer.d.ts +8 -0
- package/dist/flatten-for-analyzer.d.ts.map +1 -1
- package/dist/flatten-for-analyzer.js +32 -0
- package/dist/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/manifest-navigation.d.ts +32 -0
- package/dist/manifest-navigation.d.ts.map +1 -0
- package/dist/manifest-navigation.js +91 -0
- package/dist/manifest-visitor.js +1 -1
- package/dist/ref-slot.d.ts +125 -0
- package/dist/ref-slot.d.ts.map +1 -0
- package/dist/ref-slot.js +226 -0
- package/dist/reference-field-map.d.ts +15 -1
- package/dist/reference-field-map.d.ts.map +1 -1
- package/dist/reference-field-map.js +29 -35
- package/dist/resolve-schema-ref-kinds.d.ts +4 -0
- package/dist/resolve-schema-ref-kinds.d.ts.map +1 -1
- package/dist/resolve-schema-ref-kinds.js +31 -8
- package/dist/resolve-zone-requirements.d.ts +110 -0
- package/dist/resolve-zone-requirements.d.ts.map +1 -0
- package/dist/resolve-zone-requirements.js +541 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validate-observed-state.d.ts +14 -13
- package/dist/validate-observed-state.d.ts.map +1 -1
- package/dist/validate-observed-state.js +21 -88
- package/dist/validate-ref-slots.d.ts +48 -0
- package/dist/validate-ref-slots.d.ts.map +1 -0
- package/dist/validate-ref-slots.js +219 -0
- package/dist/validate-references.d.ts.map +1 -1
- package/dist/validate-references.js +8 -1
- package/dist/validate-zone-slots.d.ts +39 -0
- package/dist/validate-zone-slots.d.ts.map +1 -0
- package/dist/validate-zone-slots.js +114 -0
- package/dist/zone-module-documents.d.ts +27 -0
- package/dist/zone-module-documents.d.ts.map +1 -0
- package/dist/zone-module-documents.js +1 -0
- package/dist/zone-slot.d.ts +61 -0
- package/dist/zone-slot.d.ts.map +1 -0
- package/dist/zone-slot.js +91 -0
- package/package.json +3 -3
- package/src/analysis-registry.ts +36 -2
- package/src/analyzer.ts +206 -24
- package/src/builtins.ts +32 -12
- package/src/call-graph.ts +827 -0
- package/src/dependency-graph.ts +34 -68
- package/src/flatten-for-analyzer.ts +32 -0
- package/src/index.ts +47 -0
- package/src/manifest-navigation.ts +91 -0
- package/src/manifest-visitor.ts +1 -1
- package/src/ref-slot.ts +273 -0
- package/src/reference-field-map.ts +39 -36
- package/src/resolve-schema-ref-kinds.ts +34 -7
- package/src/resolve-zone-requirements.ts +781 -0
- package/src/types.ts +8 -0
- package/src/validate-observed-state.ts +26 -92
- package/src/validate-ref-slots.ts +293 -0
- package/src/validate-references.ts +8 -1
- package/src/validate-zone-slots.ts +175 -0
- package/src/zone-module-documents.ts +27 -0
- package/src/zone-slot.ts +116 -0
|
@@ -1,9 +1,22 @@
|
|
|
1
|
+
import { type RefSlot, type RefUse, type RefUseCases, readRefSlot } from "./ref-slot.js";
|
|
2
|
+
|
|
3
|
+
export { readRefSlot, isRefSlot, hasDeclaredUse } from "./ref-slot.js";
|
|
4
|
+
export type { RefSlot, RefUse, RefUseCases } from "./ref-slot.js";
|
|
5
|
+
|
|
1
6
|
/** An entry for a field that carries one or more x-telo-ref constraints. */
|
|
2
7
|
export interface RefFieldEntry {
|
|
3
8
|
/** One or more canonical kind keys ("<module>.<Kind>"), or the deprecated
|
|
4
9
|
* identity form ("<namespace>/<module>#<Kind>") for a legacy published module.
|
|
5
|
-
* Multiple entries arise from anyOf branches. */
|
|
10
|
+
* Multiple entries arise from a `kind:` list or from anyOf branches. */
|
|
6
11
|
refs: string[];
|
|
12
|
+
/** What the declaring resource does with the target — see {@link RefUse}.
|
|
13
|
+
* Empty for a slot still on the bare-string form. */
|
|
14
|
+
uses: RefUse[];
|
|
15
|
+
/** Set when the use is selected by a sibling config field. */
|
|
16
|
+
useCases?: RefUseCases;
|
|
17
|
+
/** JSON Pointer (relative to the object enclosing the slot) naming the field
|
|
18
|
+
* carrying this call's arguments. */
|
|
19
|
+
inputs?: string;
|
|
7
20
|
/** True when the field path traversed through at least one array (path contains "[]"). */
|
|
8
21
|
isArray: boolean;
|
|
9
22
|
/** x-telo-context schema declared on this ref slot, if any. Describes the CEL invocation
|
|
@@ -161,26 +174,11 @@ export function buildReferenceFieldMap(schema: Record<string, any>): ReferenceFi
|
|
|
161
174
|
return map;
|
|
162
175
|
}
|
|
163
176
|
|
|
164
|
-
/**
|
|
165
|
-
*
|
|
166
|
-
|
|
167
|
-
if (!Array.isArray(node.anyOf)) return false;
|
|
168
|
-
return node.anyOf.some((branch: Record<string, any>) => branch?.["x-telo-inline"] === true);
|
|
169
|
-
}
|
|
170
|
-
|
|
177
|
+
/** The accepted kinds a node declares, unioned across a `kind:` list and across
|
|
178
|
+
* `anyOf` branches. Thin wrapper over {@link readRefSlot} — kept because
|
|
179
|
+
* several passes want only the kind set. */
|
|
171
180
|
export function collectRefs(node: Record<string, any>): string[] {
|
|
172
|
-
|
|
173
|
-
if (typeof node["x-telo-ref"] === "string") {
|
|
174
|
-
refs.push(node["x-telo-ref"]);
|
|
175
|
-
}
|
|
176
|
-
if (Array.isArray(node.anyOf)) {
|
|
177
|
-
for (const branch of node.anyOf) {
|
|
178
|
-
if (branch && typeof branch["x-telo-ref"] === "string") {
|
|
179
|
-
refs.push(branch["x-telo-ref"]);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return refs;
|
|
181
|
+
return readRefSlot(node)?.kinds ?? [];
|
|
184
182
|
}
|
|
185
183
|
|
|
186
184
|
/** Traverses an arbitrary JSON Schema starting at the given path prefix. Used to
|
|
@@ -203,17 +201,16 @@ function traverseNode(
|
|
|
203
201
|
root?: Record<string, any>,
|
|
204
202
|
visitedRefs: Set<string> = new Set(),
|
|
205
203
|
): void {
|
|
206
|
-
// Local `$ref` is intentionally NOT followed.
|
|
207
|
-
// `$defs` (notably
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
// the
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
// signature; turning the descent back on is a single-branch change.
|
|
204
|
+
// Local `$ref` is intentionally NOT followed. This map is the kernel's
|
|
205
|
+
// Phase-5 injection surface: descending into shared `$defs` (notably
|
|
206
|
+
// `Run.Sequence`'s `step` definition) would make every step's `invoke` an
|
|
207
|
+
// injection site, and step slots resolve at dispatch — injecting there is
|
|
208
|
+
// unwanted regardless of tracing (the original dispatcher-bypass blocker
|
|
209
|
+
// has since shipped via the `REF_IDENTITY` stamp). Static analysis is NOT
|
|
210
|
+
// limited by this stop: the call graph (`call-graph.ts`) reads step slots
|
|
211
|
+
// from the item schema itself and scans the value tree, so it sees what
|
|
212
|
+
// this map deliberately hides. `visitedRefs` stays as a parameter so the
|
|
213
|
+
// recursive calls below thread the right signature.
|
|
217
214
|
if (typeof node?.$ref === "string") return;
|
|
218
215
|
// Scope slot — record and stop; do not recurse into scope contents
|
|
219
216
|
if ("x-telo-scope" in node) {
|
|
@@ -227,12 +224,18 @@ function traverseNode(
|
|
|
227
224
|
return;
|
|
228
225
|
}
|
|
229
226
|
|
|
230
|
-
// Reference slot (direct or via anyOf)
|
|
231
|
-
const
|
|
232
|
-
if (
|
|
233
|
-
const entry: RefFieldEntry = {
|
|
227
|
+
// Reference slot (direct, via a `kind:` list, or via anyOf)
|
|
228
|
+
const slot = readRefSlot(node);
|
|
229
|
+
if (slot && slot.kinds.length > 0) {
|
|
230
|
+
const entry: RefFieldEntry = {
|
|
231
|
+
refs: slot.kinds,
|
|
232
|
+
uses: slot.uses,
|
|
233
|
+
isArray: path.includes("[]"),
|
|
234
|
+
};
|
|
235
|
+
if (slot.useCases) entry.useCases = slot.useCases;
|
|
236
|
+
if (slot.inputs !== undefined) entry.inputs = slot.inputs;
|
|
234
237
|
if (node["x-telo-context"]) entry.context = node["x-telo-context"] as Record<string, any>;
|
|
235
|
-
if (
|
|
238
|
+
if (slot.inline) entry.inline = true;
|
|
236
239
|
map.set(path, entry);
|
|
237
240
|
// A node can mix item-level ref branches (a bare string / `{kind, name}`)
|
|
238
241
|
// with object branches that carry their OWN nested refs — e.g. Application
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ResourceManifest } from "@telorun/sdk";
|
|
2
2
|
import type { AliasResolver } from "./alias-resolver.js";
|
|
3
|
+
import { rewriteRefSlotKinds } from "./ref-slot.js";
|
|
4
|
+
import { hasRequiresZone, rewriteRequiresZoneKind } from "./zone-slot.js";
|
|
3
5
|
|
|
4
6
|
const REF_ANNOTATION = "x-telo-ref";
|
|
5
7
|
|
|
@@ -24,6 +26,10 @@ export interface RefConstraintIssue {
|
|
|
24
26
|
/** The `Telo.Definition` / `Telo.Abstract` doc that declares the slot. */
|
|
25
27
|
manifest: ResourceManifest;
|
|
26
28
|
reason: RefConstraintReason;
|
|
29
|
+
/** Which annotation carried the unresolved name: an `x-telo-ref` constraint
|
|
30
|
+
* (the default) or an `x-telo-requires-zone` provider kind — the caller
|
|
31
|
+
* reports the latter as ZONE_PROVIDER_UNRESOLVED. */
|
|
32
|
+
annotation?: "ref" | "zone";
|
|
27
33
|
/** For `gated`: the target module and the kinds it does export. */
|
|
28
34
|
gate?: { module: string; exported: string[] };
|
|
29
35
|
/** Aliases the declaring scope does know — the "did you mean" material for
|
|
@@ -69,9 +75,9 @@ export function resolveSchemaRefKinds(
|
|
|
69
75
|
): RefConstraintIssue[] {
|
|
70
76
|
const issues: RefConstraintIssue[] = [];
|
|
71
77
|
|
|
72
|
-
const record = (ref: string, path: string): void => {
|
|
78
|
+
const record = (ref: string, path: string, annotation: "ref" | "zone" = "ref"): void => {
|
|
73
79
|
if (isLegacyRefIdentity(ref)) {
|
|
74
|
-
issues.push({ ref, path, manifest: definition, reason: "legacy" });
|
|
80
|
+
issues.push({ ref, path, manifest: definition, reason: "legacy", annotation });
|
|
75
81
|
return;
|
|
76
82
|
}
|
|
77
83
|
const result = resolver.resolveKindResult(ref);
|
|
@@ -83,6 +89,7 @@ export function resolveSchemaRefKinds(
|
|
|
83
89
|
path,
|
|
84
90
|
manifest: definition,
|
|
85
91
|
reason: "gated",
|
|
92
|
+
annotation,
|
|
86
93
|
gate: { module: result.module, exported: result.exported },
|
|
87
94
|
}
|
|
88
95
|
: {
|
|
@@ -90,6 +97,7 @@ export function resolveSchemaRefKinds(
|
|
|
90
97
|
path,
|
|
91
98
|
manifest: definition,
|
|
92
99
|
reason: "unknown",
|
|
100
|
+
annotation,
|
|
93
101
|
knownAliases: resolver.knownAliases(),
|
|
94
102
|
},
|
|
95
103
|
);
|
|
@@ -102,11 +110,30 @@ export function resolveSchemaRefKinds(
|
|
|
102
110
|
return;
|
|
103
111
|
}
|
|
104
112
|
const obj = value as Record<string, unknown>;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
if (obj[REF_ANNOTATION] !== undefined) {
|
|
114
|
+
// Shape knowledge stays in `ref-slot.ts`: this pass states only the
|
|
115
|
+
// alias→canonical rule and what to report when it does not apply.
|
|
116
|
+
rewriteRefSlotKinds(obj, (ref) => {
|
|
117
|
+
const result = isLegacyRefIdentity(ref) ? null : resolver.resolveKindResult(ref);
|
|
118
|
+
if (result?.status === "ok") return result.kind;
|
|
119
|
+
record(ref, path);
|
|
120
|
+
return undefined;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
if (hasRequiresZone(obj)) {
|
|
124
|
+
// A zone requirement names its provider kind through the identical
|
|
125
|
+
// alias-qualified grammar, resolved in the same declaring scope — one
|
|
126
|
+
// walk canonicalizes both, so the kernel's `requireZone` and the zone
|
|
127
|
+
// projection never see an alias. An unresolved name is reported like an
|
|
128
|
+
// unresolved ref constraint (the caller maps it to
|
|
129
|
+
// ZONE_PROVIDER_UNRESOLVED); the legacy identity form is not accepted
|
|
130
|
+
// here — the annotation postdates its removal.
|
|
131
|
+
rewriteRequiresZoneKind(obj, (zone) => {
|
|
132
|
+
const result = resolver.resolveKindResult(zone);
|
|
133
|
+
if (result.status === "ok") return result.kind;
|
|
134
|
+
record(zone, `${path}.x-telo-requires-zone`, "zone");
|
|
135
|
+
return undefined;
|
|
136
|
+
});
|
|
110
137
|
}
|
|
111
138
|
for (const key of Object.keys(obj)) {
|
|
112
139
|
walk(obj[key], path ? `${path}.${key}` : key);
|