@telorun/analyzer 0.67.0 → 0.69.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 +12 -0
- package/dist/analysis-registry.d.ts.map +1 -1
- package/dist/analysis-registry.js +26 -0
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +23 -0
- package/dist/call-graph.d.ts +80 -1
- package/dist/call-graph.d.ts.map +1 -1
- package/dist/call-graph.js +145 -12
- package/dist/extends-resolution.d.ts +20 -0
- package/dist/extends-resolution.d.ts.map +1 -1
- package/dist/extends-resolution.js +29 -0
- package/dist/import-resolution-diagnostics.d.ts.map +1 -1
- package/dist/import-resolution-diagnostics.js +22 -8
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/invocation-contract.d.ts +20 -0
- package/dist/invocation-contract.d.ts.map +1 -1
- package/dist/invocation-contract.js +74 -0
- package/dist/loaded-types.d.ts +4 -4
- package/dist/loaded-types.d.ts.map +1 -1
- package/dist/manifest-analysis.d.ts +19 -0
- package/dist/manifest-analysis.d.ts.map +1 -1
- package/dist/manifest-analysis.js +27 -0
- package/dist/manifest-loader.d.ts +3 -4
- package/dist/manifest-loader.d.ts.map +1 -1
- package/dist/manifest-loader.js +4 -5
- package/dist/manifest-schemas.d.ts +2 -0
- package/dist/manifest-schemas.d.ts.map +1 -1
- package/dist/manifest-schemas.js +4 -0
- package/dist/module-graph.d.ts +500 -0
- package/dist/module-graph.d.ts.map +1 -0
- package/dist/module-graph.js +1411 -0
- package/dist/reconcile-module-versions.d.ts.map +1 -1
- package/dist/reconcile-module-versions.js +10 -11
- package/dist/release/release-plan.d.ts +1 -1
- package/dist/resolve-zone-containment.d.ts +9 -1
- package/dist/resolve-zone-containment.d.ts.map +1 -1
- package/dist/resolve-zone-containment.js +34 -6
- package/dist/resolve-zone-requirements.d.ts.map +1 -1
- package/dist/resolve-zone-requirements.js +4 -2
- package/dist/schema-keywords.d.ts +16 -1
- package/dist/schema-keywords.d.ts.map +1 -1
- package/dist/schema-keywords.js +20 -0
- package/dist/sources/default-sources.d.ts +6 -6
- package/dist/sources/default-sources.d.ts.map +1 -1
- package/dist/sources/default-sources.js +7 -8
- package/dist/sources/integrity.d.ts +3 -2
- package/dist/sources/integrity.d.ts.map +1 -1
- package/dist/sources/integrity.js +26 -3
- package/dist/sources/versioned-ref.d.ts +17 -12
- package/dist/sources/versioned-ref.d.ts.map +1 -1
- package/dist/sources/versioned-ref.js +22 -24
- package/dist/telo-version.d.ts +1 -1
- package/dist/telo-version.js +1 -1
- package/dist/validate-extends.d.ts.map +1 -1
- package/dist/validate-extends.js +42 -1
- package/dist/validate-sensitive-slots.d.ts +28 -0
- package/dist/validate-sensitive-slots.d.ts.map +1 -0
- package/dist/validate-sensitive-slots.js +75 -0
- package/dist/value-type-keyword.d.ts +1 -1
- package/dist/value-type-keyword.d.ts.map +1 -1
- package/dist/value-type-keyword.js +1 -0
- package/package.json +1 -1
- package/src/analysis-registry.ts +37 -0
- package/src/analyzer.ts +26 -0
- package/src/call-graph.ts +207 -14
- package/src/extends-resolution.ts +33 -0
- package/src/import-resolution-diagnostics.ts +24 -7
- package/src/index.ts +42 -5
- package/src/invocation-contract.ts +71 -0
- package/src/loaded-types.ts +4 -4
- package/src/manifest-analysis.ts +39 -0
- package/src/manifest-loader.ts +4 -5
- package/src/manifest-schemas.ts +4 -0
- package/src/module-graph.ts +2005 -0
- package/src/reconcile-module-versions.ts +10 -11
- package/src/release/release-plan.ts +1 -1
- package/src/resolve-zone-containment.ts +49 -9
- package/src/resolve-zone-requirements.ts +7 -2
- package/src/schema-keywords.ts +33 -1
- package/src/sources/default-sources.ts +7 -8
- package/src/sources/integrity.ts +28 -3
- package/src/sources/versioned-ref.ts +26 -28
- package/src/telo-version.ts +1 -1
- package/src/validate-extends.ts +51 -1
- package/src/validate-sensitive-slots.ts +109 -0
- package/src/value-type-keyword.ts +1 -0
- package/dist/sources/module-ref.d.ts +0 -21
- package/dist/sources/module-ref.d.ts.map +0 -1
- package/dist/sources/module-ref.js +0 -36
- package/dist/sources/registry-source.d.ts +0 -14
- package/dist/sources/registry-source.d.ts.map +0 -1
- package/dist/sources/registry-source.js +0 -45
- package/src/sources/module-ref.ts +0 -49
- package/src/sources/registry-source.ts +0 -52
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ResourceDefinition, ResourceManifest } from "@telorun/sdk";
|
|
2
|
+
import type { BuildModuleGraphOptions, ModuleGraphDeps } from "./module-graph.js";
|
|
2
3
|
import { ManifestAnalysis } from "./manifest-analysis.js";
|
|
3
4
|
import { type ManifestVisitor } from "./manifest-visitor.js";
|
|
4
5
|
import type { AnalysisContext } from "./types.js";
|
|
@@ -138,6 +139,17 @@ export declare class AnalysisRegistry {
|
|
|
138
139
|
* function of the whole manifest set.
|
|
139
140
|
*/
|
|
140
141
|
analysisOf(manifests: ResourceManifest[]): ManifestAnalysis;
|
|
142
|
+
/**
|
|
143
|
+
* What the projection needs that only this registry knows: how a kind
|
|
144
|
+
* resolves, what its reference slots are, which capabilities they target, and
|
|
145
|
+
* what a resource can raise.
|
|
146
|
+
*
|
|
147
|
+
* The GRAPH itself is built by `ManifestAnalysis.moduleGraph`, which is the
|
|
148
|
+
* pairing of a registry with a manifest set — a fifth
|
|
149
|
+
* `registry.x(manifests, …)` factory is the accretion naming that class
|
|
150
|
+
* stopped. This is the half the registry owns.
|
|
151
|
+
*/
|
|
152
|
+
moduleGraphDeps(manifests: ResourceManifest[], options?: BuildModuleGraphOptions): ModuleGraphDeps;
|
|
141
153
|
/**
|
|
142
154
|
* Returns the built-in kernel definitions. The underlying DefinitionRegistry already
|
|
143
155
|
* seeds these on construction; this method exposes them so callers (e.g. the kernel's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analysis-registry.d.ts","sourceRoot":"","sources":["../src/analysis-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAG1D,OAAO,EAAqC,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"analysis-registry.d.ts","sourceRoot":"","sources":["../src/analysis-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { DefinitionRegistry } from "./definition-registry.js";
|
|
|
5
5
|
import { computeSuggestKind, computeValidUserFacingKinds } from "./kind-suggest.js";
|
|
6
6
|
import { visitManifest as runVisitManifest } from "./manifest-visitor.js";
|
|
7
7
|
import { resolveContract } from "./invocation-contract.js";
|
|
8
|
+
import { createResolveCtx, resolveThrowsUnion } from "./resolve-throws-union.js";
|
|
8
9
|
import { isRefEntry, isScopeEntry } from "./reference-field-map.js";
|
|
9
10
|
import { resolveSchemaTypeRefs as resolveSchemaTypeRefsIn } from "./resolve-schema-type-refs.js";
|
|
10
11
|
/**
|
|
@@ -226,6 +227,31 @@ export class AnalysisRegistry {
|
|
|
226
227
|
aliasesByModule: this.aliasesByModule,
|
|
227
228
|
});
|
|
228
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* What the projection needs that only this registry knows: how a kind
|
|
232
|
+
* resolves, what its reference slots are, which capabilities they target, and
|
|
233
|
+
* what a resource can raise.
|
|
234
|
+
*
|
|
235
|
+
* The GRAPH itself is built by `ManifestAnalysis.moduleGraph`, which is the
|
|
236
|
+
* pairing of a registry with a manifest set — a fifth
|
|
237
|
+
* `registry.x(manifests, …)` factory is the accretion naming that class
|
|
238
|
+
* stopped. This is the half the registry owns.
|
|
239
|
+
*/
|
|
240
|
+
moduleGraphDeps(manifests, options = {}) {
|
|
241
|
+
// The error contract is resolved through the SAME resolver `telo check`
|
|
242
|
+
// uses, memoized across the whole graph — so what a box says it can raise
|
|
243
|
+
// is what a route's `catches:` is validated against.
|
|
244
|
+
const throwsCtx = createResolveCtx(manifests, this.defs, this.aliases, this.aliasesByModule, new Set(options.entryModule ? [options.entryModule] : []));
|
|
245
|
+
return {
|
|
246
|
+
refFields: (resource) => this.refFieldsForResource(resource),
|
|
247
|
+
definition: (kind, module) => this.resolveDefinitionIn(kind, module),
|
|
248
|
+
aliasesForModule: (module) => this.aliases.aliasesFor(module),
|
|
249
|
+
throwsOf: (resource) => {
|
|
250
|
+
const union = resolveThrowsUnion(resource, throwsCtx);
|
|
251
|
+
return { codes: [...union.codes.keys()], unbounded: union.unbounded };
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
}
|
|
229
255
|
/**
|
|
230
256
|
* Returns the built-in kernel definitions. The underlying DefinitionRegistry already
|
|
231
257
|
* seeds these on construction; this method exposes them so callers (e.g. the kernel's
|
package/dist/analyzer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAiBzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AA8B9B,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAWvF,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAiBzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AA8B9B,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAWvF,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AA4DjE,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAkG/F;0CAC0C;AAC1C,eAAO,MAAM,eAAe,GAAI,OAAO;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,KAAG,OACT,CAAC;AAErD;8EAC8E;AAC9E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhD;AAqUD,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACtC;AA6DD,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAkFD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;gBAEzB,OAAO,GAAE,qBAA0B;IAI/C;;;;;;;;;;;;;;OAcG;IACH,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,EAC3B,eAAe,CAAC,EAAE,eAAe,GAChC,kBAAkB,EAAE;IAq8DvB,aAAa,CACX,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,EAC3B,eAAe,CAAC,EAAE,eAAe,GAChC,kBAAkB,EAAE;IAMvB,SAAS,CACP,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,EAI1B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,GACtC,gBAAgB,EAAE;IAyBrB,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,GACzB;QAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;CAsB5F"}
|
package/dist/analyzer.js
CHANGED
|
@@ -37,6 +37,7 @@ import { analyzerPeerBinder, analyzerPeersTarget } from "./peer-binding.js";
|
|
|
37
37
|
import { describeProjectionFailure, manifestListScope, resolveSchemaProjections, } from "./schema-projection.js";
|
|
38
38
|
import { validateDynamicSelectors, validateRefSlotDeclarations, } from "./validate-ref-slots.js";
|
|
39
39
|
import { validateValueTypeSlots, } from "./validate-value-type-slots.js";
|
|
40
|
+
import { validateSensitiveSlots, } from "./validate-sensitive-slots.js";
|
|
40
41
|
import { resolveSchemaTypeRefs } from "./resolve-schema-type-refs.js";
|
|
41
42
|
import { validateSchemaTypeRefs } from "./validate-schema-type-refs.js";
|
|
42
43
|
import { rewriteSyntheticOrigins } from "./rewrite-synthetic-origins.js";
|
|
@@ -800,10 +801,16 @@ export class StaticAnalyzer {
|
|
|
800
801
|
// definition's `schema:` does. Same scoping as every other schema issue —
|
|
801
802
|
// the entry's own modules, since a dependency is not the consumer's to fix.
|
|
802
803
|
const valueTypeSlotIssues = [];
|
|
804
|
+
// `x-telo-sensitive` rides the same walk and the same scoping. It is read by
|
|
805
|
+
// ONE consumer — the kernel, off a bound contract — so an occurrence outside
|
|
806
|
+
// `inputType` / `outputType` is inert; for a security control, inert-and-
|
|
807
|
+
// silent is the failure worth reporting.
|
|
808
|
+
const sensitiveSlotIssues = [];
|
|
803
809
|
for (const m of manifests) {
|
|
804
810
|
const declaringModule = m.metadata?.module;
|
|
805
811
|
if (!declaringModule || rootModules.has(declaringModule)) {
|
|
806
812
|
valueTypeSlotIssues.push(...validateValueTypeSlots(m));
|
|
813
|
+
sensitiveSlotIssues.push(...validateSensitiveSlots(m));
|
|
807
814
|
}
|
|
808
815
|
}
|
|
809
816
|
for (const m of manifests) {
|
|
@@ -1020,6 +1027,22 @@ export class StaticAnalyzer {
|
|
|
1020
1027
|
},
|
|
1021
1028
|
});
|
|
1022
1029
|
}
|
|
1030
|
+
for (const issue of sensitiveSlotIssues) {
|
|
1031
|
+
diagnostics.push({
|
|
1032
|
+
severity: DiagnosticSeverity.Error,
|
|
1033
|
+
code: issue.code,
|
|
1034
|
+
source: SOURCE,
|
|
1035
|
+
message: issue.message,
|
|
1036
|
+
data: {
|
|
1037
|
+
resource: {
|
|
1038
|
+
kind: issue.manifest.kind,
|
|
1039
|
+
name: issue.manifest.metadata?.name,
|
|
1040
|
+
},
|
|
1041
|
+
filePath: issue.manifest.metadata?.source,
|
|
1042
|
+
path: issue.path,
|
|
1043
|
+
},
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1023
1046
|
// Same split for the two zone annotations. Unreadable ones fail in
|
|
1024
1047
|
// OPPOSITE directions — a dropped requirement is silently unenforced, a
|
|
1025
1048
|
// dropped provision invents failures — so neither can be left to
|
package/dist/call-graph.d.ts
CHANGED
|
@@ -74,6 +74,47 @@ export interface StepGraphNode {
|
|
|
74
74
|
index: number;
|
|
75
75
|
/** The step value as written. */
|
|
76
76
|
step: Record<string, unknown>;
|
|
77
|
+
/**
|
|
78
|
+
* Which branch of the step grammar this step IS — the branch's own title
|
|
79
|
+
* (`invoke`, `if/then/else`, `while/do`, `switch/cases/default`,
|
|
80
|
+
* `try/catch/finally`, `throw`, `value`).
|
|
81
|
+
*
|
|
82
|
+
* Matched on the branch's REQUIRED keys, and IS those keys — sorted and
|
|
83
|
+
* joined (`if+then`, `invoke`, `do+while`). A machine identity, so a consumer
|
|
84
|
+
* may branch on it; it was the branch's `title`, which is prose an author may
|
|
85
|
+
* reword at any time, and a view was splitting it on `/` to recover a keyword.
|
|
86
|
+
* Absent for a step matching no branch — one just added, and still empty.
|
|
87
|
+
*/
|
|
88
|
+
variant?: string;
|
|
89
|
+
/** The branch's `title` as its author wrote it, for a view to render verbatim.
|
|
90
|
+
* Never parsed: it is a label, and the moment anything reads its SHAPE it
|
|
91
|
+
* becomes a vocabulary the author cannot change. */
|
|
92
|
+
variantLabel?: string;
|
|
93
|
+
/**
|
|
94
|
+
* The expression that decides whether or how this step runs, as written: an
|
|
95
|
+
* `if:`, a `while:`, a `switch:`, or the `when:` guard on a dispatch.
|
|
96
|
+
*
|
|
97
|
+
* Found through `x-telo-topology-role`, never by keyword, so a third-party
|
|
98
|
+
* composer annotating its own predicate is read the same way.
|
|
99
|
+
*/
|
|
100
|
+
predicate?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Every reference slot this step's grammar declares — filled, empty, or
|
|
103
|
+
* holding a declaration written at the site.
|
|
104
|
+
*
|
|
105
|
+
* Recorded here because this is the one place a step's item schema and its
|
|
106
|
+
* value are both in hand: a step array's items sit behind a local `$ref`, so
|
|
107
|
+
* the reference field map deliberately never reaches them, and a consumer
|
|
108
|
+
* asking "what may this step dispatch to, and where is that written" has
|
|
109
|
+
* nowhere else to look. An EMPTY slot is listed for exactly that reason — it
|
|
110
|
+
* is a site an editor can offer to fill, and an edge says nothing about one.
|
|
111
|
+
*/
|
|
112
|
+
refSlots?: {
|
|
113
|
+
key: string;
|
|
114
|
+
path: string;
|
|
115
|
+
kinds: string[];
|
|
116
|
+
inline?: boolean;
|
|
117
|
+
}[];
|
|
77
118
|
}
|
|
78
119
|
export type CallGraphNode = ResourceGraphNode | StepGraphNode;
|
|
79
120
|
export interface CallGraphEdge {
|
|
@@ -133,7 +174,15 @@ export interface CallGraph {
|
|
|
133
174
|
/** Edges arriving at a resource node. */
|
|
134
175
|
edgesTo(id: string): CallGraphEdge[];
|
|
135
176
|
resource(kind: string, name: string): ResourceGraphNode | undefined;
|
|
136
|
-
|
|
177
|
+
/**
|
|
178
|
+
* The resource a bare name addresses, read from `fromModule`'s scope.
|
|
179
|
+
*
|
|
180
|
+
* A name is module-scoped, so the module is how two declarations of one name
|
|
181
|
+
* are told apart — see {@link resolveScopedName}. Omitting it answers for a
|
|
182
|
+
* name declared once and, where several modules declare it, declines rather
|
|
183
|
+
* than taking whichever came first.
|
|
184
|
+
*/
|
|
185
|
+
resourceByName(name: string, fromModule?: string): ResourceGraphNode | undefined;
|
|
137
186
|
/** Step nodes declared by a resource, in lexical order. */
|
|
138
187
|
steps(resourceId: string): StepGraphNode[];
|
|
139
188
|
/** Every edge whose `use` includes at least one control transfer, plus every
|
|
@@ -141,6 +190,36 @@ export interface CallGraph {
|
|
|
141
190
|
controlEdges(): CallGraphEdge[];
|
|
142
191
|
}
|
|
143
192
|
export declare const resourceId: (kind: string, name: string) => string;
|
|
193
|
+
/**
|
|
194
|
+
* The id a manifest's node is keyed by.
|
|
195
|
+
*
|
|
196
|
+
* **A resource name is MODULE-SCOPED**, so `(kind, name)` is unique inside one
|
|
197
|
+
* module and not across a flattened set: two libraries each exporting an
|
|
198
|
+
* `Http.Api` named `routes` are two declarations, and keying both as
|
|
199
|
+
* `http.Api\0routes` silently made them one — the second overwrote the first,
|
|
200
|
+
* taking its edges and its steps with it. The module is part of the identity
|
|
201
|
+
* wherever the loader stamped one; a manifest with no stamp keeps the bare form,
|
|
202
|
+
* so nothing that never crossed a module boundary moves.
|
|
203
|
+
*/
|
|
204
|
+
export declare function nodeIdFor(manifest: ResourceManifest): string;
|
|
205
|
+
/**
|
|
206
|
+
* A bare `<name>` read from a resource declared in `fromModule`.
|
|
207
|
+
*
|
|
208
|
+
* **Same module first**, because that is what a bare name MEANS: it is resolved
|
|
209
|
+
* in the scope it was written in, and a cross-module reference is written with
|
|
210
|
+
* an alias. A name declared in exactly one module resolves to it whatever the
|
|
211
|
+
* reader's scope — which is what keeps an unstamped manifest set (every
|
|
212
|
+
* fixture, every single-module load) behaving as it did. A name declared in
|
|
213
|
+
* SEVERAL other modules and none of the reader's resolves to NOTHING: guessing
|
|
214
|
+
* between them attributes a reference to a resource the author never named, and
|
|
215
|
+
* some other pass reports the dangling name honestly.
|
|
216
|
+
*
|
|
217
|
+
* Exported because more than one pass resolves a bare name — the call graph's
|
|
218
|
+
* own sites, and the projection's inline declarations and CEL state reads. Two
|
|
219
|
+
* spellings of this rule is how a fix in one leaves a first-wins lookup in the
|
|
220
|
+
* other, which is exactly the collision it exists to prevent.
|
|
221
|
+
*/
|
|
222
|
+
export declare function resolveScopedName<T>(candidates: readonly T[] | undefined, moduleOf: (item: T) => string | undefined, fromModule: string | undefined): T | undefined;
|
|
144
223
|
export interface BuildCallGraphOptions {
|
|
145
224
|
aliases?: AliasResolver;
|
|
146
225
|
aliasesByModule?: Map<string, AliasResolver>;
|
package/dist/call-graph.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-graph.d.ts","sourceRoot":"","sources":["../src/call-graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAOnE,OAAO,EAIL,KAAK,MAAM,EACX,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"call-graph.d.ts","sourceRoot":"","sources":["../src/call-graph.ts"],"names":[],"mappings":"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"}
|
package/dist/call-graph.js
CHANGED
|
@@ -3,9 +3,52 @@ import { enclosingOf, propertySchemas, resolveLocalRef, } from "./manifest-navig
|
|
|
3
3
|
import { visitManifest } from "./manifest-visitor.js";
|
|
4
4
|
import { possibleUses, readRefSlot, transfersControl, } from "./ref-slot.js";
|
|
5
5
|
import { isStepSlot } from "./step-slot.js";
|
|
6
|
-
import { isRefEntry, resolveFieldEntries } from "./reference-field-map.js";
|
|
6
|
+
import { isInlineResource, isRefEntry, resolveFieldEntries, } from "./reference-field-map.js";
|
|
7
7
|
import { DEPENDENCY_GRAPH_SKIP_KINDS as SYSTEM_KINDS } from "./system-kinds.js";
|
|
8
8
|
export const resourceId = (kind, name) => `${kind}\0${name}`;
|
|
9
|
+
/**
|
|
10
|
+
* The id a manifest's node is keyed by.
|
|
11
|
+
*
|
|
12
|
+
* **A resource name is MODULE-SCOPED**, so `(kind, name)` is unique inside one
|
|
13
|
+
* module and not across a flattened set: two libraries each exporting an
|
|
14
|
+
* `Http.Api` named `routes` are two declarations, and keying both as
|
|
15
|
+
* `http.Api\0routes` silently made them one — the second overwrote the first,
|
|
16
|
+
* taking its edges and its steps with it. The module is part of the identity
|
|
17
|
+
* wherever the loader stamped one; a manifest with no stamp keeps the bare form,
|
|
18
|
+
* so nothing that never crossed a module boundary moves.
|
|
19
|
+
*/
|
|
20
|
+
export function nodeIdFor(manifest) {
|
|
21
|
+
const kind = manifest.kind;
|
|
22
|
+
const name = manifest.metadata?.name;
|
|
23
|
+
const module = manifest.metadata?.module;
|
|
24
|
+
return module ? `${module}\0${resourceId(kind, name)}` : resourceId(kind, name);
|
|
25
|
+
}
|
|
26
|
+
/** The module a manifest was declared in, when the loader stamped one. */
|
|
27
|
+
const declaringModule = (manifest) => manifest.metadata?.module;
|
|
28
|
+
/**
|
|
29
|
+
* A bare `<name>` read from a resource declared in `fromModule`.
|
|
30
|
+
*
|
|
31
|
+
* **Same module first**, because that is what a bare name MEANS: it is resolved
|
|
32
|
+
* in the scope it was written in, and a cross-module reference is written with
|
|
33
|
+
* an alias. A name declared in exactly one module resolves to it whatever the
|
|
34
|
+
* reader's scope — which is what keeps an unstamped manifest set (every
|
|
35
|
+
* fixture, every single-module load) behaving as it did. A name declared in
|
|
36
|
+
* SEVERAL other modules and none of the reader's resolves to NOTHING: guessing
|
|
37
|
+
* between them attributes a reference to a resource the author never named, and
|
|
38
|
+
* some other pass reports the dangling name honestly.
|
|
39
|
+
*
|
|
40
|
+
* Exported because more than one pass resolves a bare name — the call graph's
|
|
41
|
+
* own sites, and the projection's inline declarations and CEL state reads. Two
|
|
42
|
+
* spellings of this rule is how a fix in one leaves a first-wins lookup in the
|
|
43
|
+
* other, which is exactly the collision it exists to prevent.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveScopedName(candidates, moduleOf, fromModule) {
|
|
46
|
+
if (!candidates || candidates.length === 0)
|
|
47
|
+
return undefined;
|
|
48
|
+
if (candidates.length === 1)
|
|
49
|
+
return candidates[0];
|
|
50
|
+
return candidates.find((candidate) => moduleOf(candidate) === fromModule);
|
|
51
|
+
}
|
|
9
52
|
/**
|
|
10
53
|
* Does control reach this edge's target?
|
|
11
54
|
*
|
|
@@ -141,6 +184,64 @@ function isPlainRefValue(value) {
|
|
|
141
184
|
return false;
|
|
142
185
|
return Object.keys(value).every((k) => k === "kind" || k === "name" || k === "alias" || k === "__ref");
|
|
143
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* What a step IS, and what decides whether it runs.
|
|
189
|
+
*
|
|
190
|
+
* Both come off the schema rather than off a keyword list: the variant is the
|
|
191
|
+
* `oneOf` branch whose REQUIRED keys the step carries, and the predicate is the
|
|
192
|
+
* field annotated as one. A composer that declares a step body of its own is
|
|
193
|
+
* therefore described in its own words, and nothing here knows that `while`
|
|
194
|
+
* exists.
|
|
195
|
+
*
|
|
196
|
+
* A step matching several branches takes the FIRST — the grammar is a `oneOf`,
|
|
197
|
+
* so more than one match is a manifest the checker rejects, and guessing among
|
|
198
|
+
* them would be a second opinion on a question the checker already answers.
|
|
199
|
+
*/
|
|
200
|
+
function classifyStep(step, itemSchema, rootSchema) {
|
|
201
|
+
if (!itemSchema)
|
|
202
|
+
return {};
|
|
203
|
+
const branches = Array.isArray(itemSchema.oneOf) ? itemSchema.oneOf : [];
|
|
204
|
+
let variant;
|
|
205
|
+
let variantLabel;
|
|
206
|
+
for (const raw of branches) {
|
|
207
|
+
const branch = resolveLocalRef(raw, rootSchema);
|
|
208
|
+
const required = Array.isArray(branch?.required) ? branch.required : [];
|
|
209
|
+
if (required.length === 0 || !required.every((key) => step[key] !== undefined))
|
|
210
|
+
continue;
|
|
211
|
+
// The keys are what the branch IS; the title is what it is called.
|
|
212
|
+
variant = [...required].sort().join("+");
|
|
213
|
+
if (typeof branch?.title === "string")
|
|
214
|
+
variantLabel = branch.title;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
let predicate;
|
|
218
|
+
for (const [key, propSchema] of propertySchemas(itemSchema)) {
|
|
219
|
+
const role = propSchema?.["x-telo-topology-role"];
|
|
220
|
+
if (role !== "predicate" && role !== "discriminator")
|
|
221
|
+
continue;
|
|
222
|
+
const written = expressionSource(step[key]);
|
|
223
|
+
if (written !== undefined) {
|
|
224
|
+
predicate = written;
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
...(variant ? { variant } : {}),
|
|
230
|
+
...(variantLabel ? { variantLabel } : {}),
|
|
231
|
+
...(predicate ? { predicate } : {}),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
/** A predicate as the author wrote it. A CEL value reaches here as a tagged
|
|
235
|
+
* sentinel or as an already-compiled node, and the SOURCE is the only part of
|
|
236
|
+
* either worth showing. */
|
|
237
|
+
function expressionSource(value) {
|
|
238
|
+
if (typeof value === "string")
|
|
239
|
+
return value;
|
|
240
|
+
if (value === null || typeof value !== "object")
|
|
241
|
+
return undefined;
|
|
242
|
+
const record = value;
|
|
243
|
+
return typeof record.source === "string" ? record.source : undefined;
|
|
244
|
+
}
|
|
144
245
|
/**
|
|
145
246
|
* Emit the edges a single step's own ref slots declare.
|
|
146
247
|
*
|
|
@@ -158,7 +259,20 @@ function emitStepEdges(node, ctx) {
|
|
|
158
259
|
const slot = readRefSlot(propSchema);
|
|
159
260
|
if (!slot || slot.kinds.length === 0)
|
|
160
261
|
continue;
|
|
161
|
-
const
|
|
262
|
+
const written = node.step[key];
|
|
263
|
+
const inline = written !== null &&
|
|
264
|
+
typeof written === "object" &&
|
|
265
|
+
!Array.isArray(written) &&
|
|
266
|
+
isInlineResource(written);
|
|
267
|
+
// Every declared slot is recorded, whatever is in it: an empty one is a
|
|
268
|
+
// site an editor can fill, and a declaration written at the site is a real
|
|
269
|
+
// dispatch that emits no edge — which is what made an inline step read
|
|
270
|
+
// exactly like one that dispatches nothing.
|
|
271
|
+
node.refSlots = [
|
|
272
|
+
...(node.refSlots ?? []),
|
|
273
|
+
{ key, path: `${node.path}.${key}`, kinds: slot.kinds, ...(inline ? { inline: true } : {}) },
|
|
274
|
+
];
|
|
275
|
+
const targetName = refTargetName(written);
|
|
162
276
|
if (targetName === undefined)
|
|
163
277
|
continue;
|
|
164
278
|
const entry = {
|
|
@@ -252,6 +366,13 @@ function walkSteps(steps, arrayPath, parent, ctx) {
|
|
|
252
366
|
};
|
|
253
367
|
if (typeof value.name === "string")
|
|
254
368
|
node.name = value.name;
|
|
369
|
+
const { variant, variantLabel, predicate } = classifyStep(value, ctx.itemSchema, ctx.rootSchema);
|
|
370
|
+
if (variant)
|
|
371
|
+
node.variant = variant;
|
|
372
|
+
if (variantLabel)
|
|
373
|
+
node.variantLabel = variantLabel;
|
|
374
|
+
if (predicate)
|
|
375
|
+
node.predicate = predicate;
|
|
255
376
|
if (parent)
|
|
256
377
|
node.parent = parent;
|
|
257
378
|
ctx.nodes.set(id, node);
|
|
@@ -296,6 +417,8 @@ function ownerStepOf(steps, concretePath) {
|
|
|
296
417
|
export function buildCallGraph(resources, registry, options = {}) {
|
|
297
418
|
const nodes = new Map();
|
|
298
419
|
const edges = [];
|
|
420
|
+
/** Every declaration of a bare name, in declaration order — a name may be
|
|
421
|
+
* declared once per module, so this is a list rather than one node. */
|
|
299
422
|
const byName = new Map();
|
|
300
423
|
const stepsByOwner = new Map();
|
|
301
424
|
const stepEdgesByPath = new Map();
|
|
@@ -325,14 +448,17 @@ export function buildCallGraph(resources, registry, options = {}) {
|
|
|
325
448
|
continue;
|
|
326
449
|
const node = {
|
|
327
450
|
type: "resource",
|
|
328
|
-
id:
|
|
451
|
+
id: nodeIdFor(manifest),
|
|
329
452
|
kind: manifest.kind,
|
|
330
453
|
name: name,
|
|
331
454
|
manifest,
|
|
332
455
|
};
|
|
456
|
+
if (nodes.has(node.id))
|
|
457
|
+
continue;
|
|
333
458
|
nodes.set(node.id, node);
|
|
334
|
-
byName.set(node.name, node);
|
|
459
|
+
byName.set(node.name, [...(byName.get(node.name) ?? []), node]);
|
|
335
460
|
}
|
|
461
|
+
const resolveByName = (name, fromModule) => resolveScopedName(byName.get(name), (node) => declaringModule(node.manifest), fromModule);
|
|
336
462
|
// --- step nodes ---
|
|
337
463
|
const collectStepsFor = (node, resolveName) => {
|
|
338
464
|
const definition = definitionFor(node.manifest);
|
|
@@ -362,7 +488,7 @@ export function buildCallGraph(resources, registry, options = {}) {
|
|
|
362
488
|
stepsByOwner.set(node.id, collected);
|
|
363
489
|
};
|
|
364
490
|
for (const node of [...nodes.values()]) {
|
|
365
|
-
collectStepsFor(node, (name) =>
|
|
491
|
+
collectStepsFor(node, (name) => resolveByName(name, declaringModule(node.manifest)));
|
|
366
492
|
}
|
|
367
493
|
// --- edges ---
|
|
368
494
|
// Scope-local nodes of the CURRENT resource. The visitor fires `onScope`
|
|
@@ -386,7 +512,7 @@ export function buildCallGraph(resources, registry, options = {}) {
|
|
|
386
512
|
const ownerName = event.source.metadata?.name;
|
|
387
513
|
if (!ownerName || !event.source.kind)
|
|
388
514
|
return;
|
|
389
|
-
const ownerId =
|
|
515
|
+
const ownerId = nodeIdFor(event.source);
|
|
390
516
|
// Inline declarations inside `x-telo-scope` arrays become nodes of
|
|
391
517
|
// their own, keyed by their scope site — the declaration-site identity
|
|
392
518
|
// the zones plan correlates on. They are excluded from init ordering
|
|
@@ -413,7 +539,8 @@ export function buildCallGraph(resources, registry, options = {}) {
|
|
|
413
539
|
}
|
|
414
540
|
if (scopeLocal.size === 0)
|
|
415
541
|
return;
|
|
416
|
-
const
|
|
542
|
+
const ownerModule = declaringModule(event.source);
|
|
543
|
+
const resolveScoped = (name) => scopeLocal.get(name) ?? resolveByName(name, ownerModule);
|
|
417
544
|
// The owner's own step edges were emitted before this scope was seen
|
|
418
545
|
// (step collection precedes the visit), so their names resolved
|
|
419
546
|
// module-level. Re-resolve them now that the scope exists: scope-local
|
|
@@ -474,7 +601,7 @@ export function buildCallGraph(resources, registry, options = {}) {
|
|
|
474
601
|
const sourceName = event.source.metadata?.name;
|
|
475
602
|
if (!sourceName || !event.source.kind)
|
|
476
603
|
return;
|
|
477
|
-
const sourceId =
|
|
604
|
+
const sourceId = nodeIdFor(event.source);
|
|
478
605
|
if (!nodes.has(sourceId))
|
|
479
606
|
return;
|
|
480
607
|
// A site inside a step was already emitted by the step walk, which
|
|
@@ -507,9 +634,10 @@ export function buildCallGraph(resources, registry, options = {}) {
|
|
|
507
634
|
path: event.concretePath,
|
|
508
635
|
use,
|
|
509
636
|
};
|
|
637
|
+
const sourceModule = declaringModule(event.source);
|
|
510
638
|
const target = scopedNames.has(targetName)
|
|
511
|
-
? (scopeLocal.get(targetName) ??
|
|
512
|
-
:
|
|
639
|
+
? (scopeLocal.get(targetName) ?? resolveByName(targetName, sourceModule))
|
|
640
|
+
: resolveByName(targetName, sourceModule);
|
|
513
641
|
if (target)
|
|
514
642
|
edge.to = target.id;
|
|
515
643
|
if (unresolved)
|
|
@@ -552,8 +680,13 @@ export function buildCallGraph(resources, registry, options = {}) {
|
|
|
552
680
|
edges,
|
|
553
681
|
edgesFrom: (id) => fromIndex.get(id) ?? [],
|
|
554
682
|
edgesTo: (id) => toIndex.get(id) ?? [],
|
|
555
|
-
|
|
556
|
-
|
|
683
|
+
// Both accessors take a name with no module, so both answer for the one
|
|
684
|
+
// declaration that name has — and, where a flattened set has several, the
|
|
685
|
+
// first in declaration order. A caller that must tell two apart holds a
|
|
686
|
+
// node id, which carries the module.
|
|
687
|
+
resource: (kind, name) => nodes.get(resourceId(kind, name)) ??
|
|
688
|
+
byName.get(name)?.find((n) => n.kind === kind),
|
|
689
|
+
resourceByName: (name, fromModule) => resolveScopedName(byName.get(name), (node) => declaringModule(node.manifest), fromModule),
|
|
557
690
|
steps: (ownerId) => stepsByOwner.get(ownerId) ?? [],
|
|
558
691
|
controlEdges: () => edges.filter(reachesTarget),
|
|
559
692
|
};
|
|
@@ -36,6 +36,26 @@ export declare function inheritedCapability(def: ResourceDefinition | undefined,
|
|
|
36
36
|
* `mergeTypeSchemas` that `Type.JsonSchema.extends` uses.
|
|
37
37
|
* - no `extends` → the own schema unchanged. */
|
|
38
38
|
export declare function effectiveAuthorSchema(def: ResourceDefinition | undefined, resolve: DefResolver): Record<string, any>;
|
|
39
|
+
/**
|
|
40
|
+
* The fields a merge-form inheriting child publishes over its parent's reading.
|
|
41
|
+
*
|
|
42
|
+
* A child that inherits its controller by delegation and declares no `base:` IS
|
|
43
|
+
* the parent instance, so `resources.<child>` is the parent's `snapshot()` — and
|
|
44
|
+
* a field the parent has never heard of would be readable from nowhere. These
|
|
45
|
+
* are exactly those fields: the ones the effective (merged) schema declares that
|
|
46
|
+
* the controller-bearing ancestor's does not.
|
|
47
|
+
*
|
|
48
|
+
* A REDECLARED name is deliberately excluded. Narrowing an inherited field (a
|
|
49
|
+
* description, a pattern, a widget hint) is ordinary in an additive extension and
|
|
50
|
+
* says nothing about publication, while the parent's `snapshot()` is the sole
|
|
51
|
+
* authority on what a parent instance publishes — its normalizations, its
|
|
52
|
+
* deliberate omissions, and its redactions. Republishing such a field from raw
|
|
53
|
+
* config would silently undo a provider's decision to keep it out.
|
|
54
|
+
*
|
|
55
|
+
* Empty for the `base:` form, whose fields are construction inputs consumed by
|
|
56
|
+
* the mapping, and for a child with its own controller, which publishes itself.
|
|
57
|
+
*/
|
|
58
|
+
export declare function publishedOwnFields(def: ResourceDefinition | undefined, resolve: DefResolver): string[];
|
|
39
59
|
/** The two directions of a kind's invocation contract. `inputType` is what a
|
|
40
60
|
* caller sends to `invoke()`; `outputType` is what `invoke()` / `provide()`
|
|
41
61
|
* returns. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extends-resolution.d.ts","sourceRoot":"","sources":["../src/extends-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvD;;;;;;;2DAO2D;AAC3D,MAAM,MAAM,WAAW,GAAG,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,kBAAkB,KACtB,kBAAkB,GAAG,SAAS,CAAC;AA0BpC;sDACsD;AACtD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAIhC;AAED;6EAC6E;AAC7E,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,EAAE,CAUtB;AAED;iFACiF;AACjF,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAUvF;AAED;;mFAEmF;AACnF,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAMhC;AAED;;sCAEsC;AACtC,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,OAAO,CAGT;AAED;2EAC2E;AAC3E,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;;iDAMiD;AACjD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAOrB;AAED;;eAEe;AACf,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,YAAY,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAQT;AAED;;;6BAG6B;AAC7B,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,kBAAkB,GAAG,SAAS,CAShC;AAED;;;;;8CAK8C;AAC9C,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAKT;AAED;;8EAE8E;AAC9E,wBAAgB,eAAe,CAAC,SAAS,EAAE,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,CAEjF;AAED;;;;;;;;;gDASgD;AAChD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CASjC"}
|
|
1
|
+
{"version":3,"file":"extends-resolution.d.ts","sourceRoot":"","sources":["../src/extends-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvD;;;;;;;2DAO2D;AAC3D,MAAM,MAAM,WAAW,GAAG,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,kBAAkB,KACtB,kBAAkB,GAAG,SAAS,CAAC;AA0BpC;sDACsD;AACtD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAIhC;AAED;6EAC6E;AAC7E,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,EAAE,CAUtB;AAED;iFACiF;AACjF,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAUvF;AAED;;mFAEmF;AACnF,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAMhC;AAED;;sCAEsC;AACtC,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,OAAO,CAGT;AAED;2EAC2E;AAC3E,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;;iDAMiD;AACjD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAOrB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,EAAE,CASV;AAED;;eAEe;AACf,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,YAAY,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAQT;AAED;;;6BAG6B;AAC7B,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,kBAAkB,GAAG,SAAS,CAShC;AAED;;;;;8CAK8C;AAC9C,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAKT;AAED;;8EAE8E;AAC9E,wBAAgB,eAAe,CAAC,SAAS,EAAE,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,CAEjF;AAED;;;;;;;;;gDASgD;AAChD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CASjC"}
|
|
@@ -80,6 +80,35 @@ export function effectiveAuthorSchema(def, resolve) {
|
|
|
80
80
|
const parentSchema = effectiveAuthorSchema(parent, resolve);
|
|
81
81
|
return mergeTypeSchemas([parentSchema, own]);
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* The fields a merge-form inheriting child publishes over its parent's reading.
|
|
85
|
+
*
|
|
86
|
+
* A child that inherits its controller by delegation and declares no `base:` IS
|
|
87
|
+
* the parent instance, so `resources.<child>` is the parent's `snapshot()` — and
|
|
88
|
+
* a field the parent has never heard of would be readable from nowhere. These
|
|
89
|
+
* are exactly those fields: the ones the effective (merged) schema declares that
|
|
90
|
+
* the controller-bearing ancestor's does not.
|
|
91
|
+
*
|
|
92
|
+
* A REDECLARED name is deliberately excluded. Narrowing an inherited field (a
|
|
93
|
+
* description, a pattern, a widget hint) is ordinary in an additive extension and
|
|
94
|
+
* says nothing about publication, while the parent's `snapshot()` is the sole
|
|
95
|
+
* authority on what a parent instance publishes — its normalizations, its
|
|
96
|
+
* deliberate omissions, and its redactions. Republishing such a field from raw
|
|
97
|
+
* config would silently undo a provider's decision to keep it out.
|
|
98
|
+
*
|
|
99
|
+
* Empty for the `base:` form, whose fields are construction inputs consumed by
|
|
100
|
+
* the mapping, and for a child with its own controller, which publishes itself.
|
|
101
|
+
*/
|
|
102
|
+
export function publishedOwnFields(def, resolve) {
|
|
103
|
+
if (body(def).base || !isInheritedDelegation(def, resolve))
|
|
104
|
+
return [];
|
|
105
|
+
const ancestor = controllerBearingAncestor(def, resolve);
|
|
106
|
+
if (!ancestor)
|
|
107
|
+
return [];
|
|
108
|
+
const inherited = new Set(Object.keys((effectiveAuthorSchema(ancestor, resolve).properties ?? {})));
|
|
109
|
+
const own = (effectiveAuthorSchema(def, resolve).properties ?? {});
|
|
110
|
+
return Object.keys(own).filter((name) => !inherited.has(name));
|
|
111
|
+
}
|
|
83
112
|
/**
|
|
84
113
|
* The **nearest declaration** of an invocation contract along the `extends`
|
|
85
114
|
* chain, self first — the raw type-field value, still to be resolved to a schema
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-resolution-diagnostics.d.ts","sourceRoot":"","sources":["../src/import-resolution-diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"import-resolution-diagnostics.d.ts","sourceRoot":"","sources":["../src/import-resolution-diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrE,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA2DzE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,WAAW,GAAG,kBAAkB,EAAE,CAepF"}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { isLocalPathSource } from "./sources/local-path-ref.js";
|
|
2
|
-
import { isRegistryRef } from "./sources/module-ref.js";
|
|
3
2
|
import { isOciRef } from "./sources/oci-ref.js";
|
|
4
3
|
import { DiagnosticSeverity } from "./types.js";
|
|
5
4
|
const SOURCE = "telo-analyzer";
|
|
6
|
-
/** True when `source` is a shape some transport claims —
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
/** True when `source` is a shape some transport claims — an OCI ref, an HTTP(S)
|
|
6
|
+
* URL, or a relative/absolute path. A source matching none of these is
|
|
7
|
+
* malformed (no transport can ever resolve it), which we report differently
|
|
8
|
+
* from a well-formed ref that simply failed to fetch. */
|
|
10
9
|
function isRecognizedSourceShape(source) {
|
|
11
|
-
return (
|
|
12
|
-
isOciRef(source) ||
|
|
10
|
+
return (isOciRef(source) ||
|
|
13
11
|
source.startsWith("http://") ||
|
|
14
12
|
source.startsWith("https://") ||
|
|
15
13
|
isLocalPathSource(source));
|
|
@@ -21,12 +19,28 @@ function classify(e) {
|
|
|
21
19
|
return "INVALID_IMPORT_TARGET";
|
|
22
20
|
return isRecognizedSourceShape(e.source ?? e.url) ? "IMPORT_UNRESOLVED" : "INVALID_IMPORT_SOURCE";
|
|
23
21
|
}
|
|
22
|
+
/** The removed bare `<namespace>/<name>@<version>` ref: no scheme, not a path,
|
|
23
|
+
* carrying both a `/` and an `@`. Recognised only to explain itself — no
|
|
24
|
+
* migration can rewrite it, because the OCI host it moved to is not derivable
|
|
25
|
+
* from the ref, and the failing line is frequently inside a dependency the
|
|
26
|
+
* consumer cannot edit. The message is the whole remedy available to them. */
|
|
27
|
+
function isRemovedBareRef(source) {
|
|
28
|
+
return (!source.includes("://") &&
|
|
29
|
+
!source.startsWith("/") &&
|
|
30
|
+
!source.startsWith(".") &&
|
|
31
|
+
source.includes("@") &&
|
|
32
|
+
source.includes("/"));
|
|
33
|
+
}
|
|
24
34
|
function messageFor(e, code) {
|
|
25
35
|
const authored = e.source ?? e.url;
|
|
26
36
|
const via = e.alias ? `import '${e.alias}' → '${authored}'` : `'${authored}'`;
|
|
27
37
|
if (code === "INVALID_IMPORT_SOURCE") {
|
|
38
|
+
const removedForm = isRemovedBareRef(authored)
|
|
39
|
+
? ` The bare '<namespace>/<name>@<version>' form was removed — rewrite it to the ` +
|
|
40
|
+
`module's 'oci://' ref (\`telo search <name>\` reports it).`
|
|
41
|
+
: "";
|
|
28
42
|
return (`Cannot resolve ${via}: not a recognized module reference. Expected ` +
|
|
29
|
-
`'
|
|
43
|
+
`'oci://host/repo@tag', 'https://…', or a relative path.${removedForm}`);
|
|
30
44
|
}
|
|
31
45
|
// The target WAS obtained, so "cannot resolve" would name the wrong problem —
|
|
32
46
|
// and the wrong person to fix it. The loader's message already says what was
|