@telorun/analyzer 0.16.0 → 0.17.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/README.md +7 -14
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +23 -0
- package/dist/flatten-for-analyzer.d.ts +23 -1
- package/dist/flatten-for-analyzer.d.ts.map +1 -1
- package/dist/flatten-for-analyzer.js +45 -28
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/analyzer.ts +22 -0
- package/src/flatten-for-analyzer.ts +53 -33
- package/src/index.ts +5 -1
package/README.md
CHANGED
|
@@ -54,20 +54,13 @@ metadata:
|
|
|
54
54
|
description: |
|
|
55
55
|
A complete feedback collection REST API — no code, pure YAML.
|
|
56
56
|
Persists entries to SQLite and serves them over HTTP.
|
|
57
|
+
imports:
|
|
58
|
+
Http: std/http-server@0.6.1
|
|
59
|
+
Sql: std/sql@0.5.1
|
|
57
60
|
targets:
|
|
58
61
|
- Migrations
|
|
59
62
|
- Server
|
|
60
63
|
---
|
|
61
|
-
kind: Telo.Import
|
|
62
|
-
metadata:
|
|
63
|
-
name: Http
|
|
64
|
-
source: std/http-server@0.5.0
|
|
65
|
-
---
|
|
66
|
-
kind: Telo.Import
|
|
67
|
-
metadata:
|
|
68
|
-
name: Sql
|
|
69
|
-
source: std/sql@0.3.0
|
|
70
|
-
---
|
|
71
64
|
# SQLite database — swap driver/host/database for PostgreSQL with zero YAML changes
|
|
72
65
|
kind: Sql.Connection
|
|
73
66
|
metadata:
|
|
@@ -127,7 +120,7 @@ routes:
|
|
|
127
120
|
minLength: 1
|
|
128
121
|
source:
|
|
129
122
|
type: string
|
|
130
|
-
required: [text]
|
|
123
|
+
required: [ text ]
|
|
131
124
|
handler:
|
|
132
125
|
kind: Sql.Exec
|
|
133
126
|
connection:
|
|
@@ -157,7 +150,7 @@ routes:
|
|
|
157
150
|
kind: Sql.Connection
|
|
158
151
|
name: Db
|
|
159
152
|
from: feedback
|
|
160
|
-
columns: [id, text, source, score, created_at]
|
|
153
|
+
columns: [ id, text, source, score, created_at ]
|
|
161
154
|
orderBy:
|
|
162
155
|
- { column: created_at, direction: desc }
|
|
163
156
|
response:
|
|
@@ -176,14 +169,14 @@ routes:
|
|
|
176
169
|
properties:
|
|
177
170
|
id:
|
|
178
171
|
type: integer
|
|
179
|
-
required: [id]
|
|
172
|
+
required: [ id ]
|
|
180
173
|
handler:
|
|
181
174
|
kind: Sql.Select
|
|
182
175
|
connection:
|
|
183
176
|
kind: Sql.Connection
|
|
184
177
|
name: Db
|
|
185
178
|
from: feedback
|
|
186
|
-
columns: [id, text, source, score, created_at]
|
|
179
|
+
columns: [ id, text, source, score, created_at ]
|
|
187
180
|
where:
|
|
188
181
|
- { column: id, op: "=", value: "${{ request.params.id }}" }
|
|
189
182
|
response:
|
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;AAIzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAiB9B,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAuhB/F,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,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,GAC1B,kBAAkB,EAAE;
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAIzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAiB9B,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAuhB/F,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,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,GAC1B,kBAAkB,EAAE;IAypBvB,aAAa,CACX,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,kBAAkB,EAAE;IAMvB,SAAS,CACP,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,EAI1B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,GACtC,gBAAgB,EAAE;IAqBrB,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
|
@@ -590,6 +590,29 @@ export class StaticAnalyzer {
|
|
|
590
590
|
}
|
|
591
591
|
}
|
|
592
592
|
}
|
|
593
|
+
// Seed `Self` for every module that contributes definitions but whose own
|
|
594
|
+
// Telo.Library doc isn't in this manifest set. `flattenForAnalyzer` forwards an
|
|
595
|
+
// imported library's definitions/abstracts/imports but NOT its module doc, so the
|
|
596
|
+
// module-doc loop above can't register `Self` for imported modules. Without this, a
|
|
597
|
+
// definition's `extends: Self.X` (a kind defined in the same library as the abstract)
|
|
598
|
+
// can't resolve and its `extendedBy` edge mis-keys under the literal "Self.X" — which
|
|
599
|
+
// stays invisible until another module also implements that abstract and flips the
|
|
600
|
+
// reference check from lenient to strict. `Self` always maps a module to its own name.
|
|
601
|
+
for (const m of manifests) {
|
|
602
|
+
if (m.kind !== "Telo.Definition" && m.kind !== "Telo.Abstract")
|
|
603
|
+
continue;
|
|
604
|
+
const ownModule = m.metadata?.module;
|
|
605
|
+
if (!ownModule || rootModules.has(ownModule))
|
|
606
|
+
continue;
|
|
607
|
+
let libResolver = aliasesByModule.get(ownModule);
|
|
608
|
+
if (!libResolver) {
|
|
609
|
+
libResolver = new AliasResolver();
|
|
610
|
+
aliasesByModule.set(ownModule, libResolver);
|
|
611
|
+
}
|
|
612
|
+
if (!libResolver.hasAlias("Self")) {
|
|
613
|
+
libResolver.registerImport("Self", ownModule, []);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
593
616
|
// Register definitions from Telo.Definition AND Telo.Abstract resources.
|
|
594
617
|
// Abstracts declare contracts that implementations target via `extends` (canonical)
|
|
595
618
|
// or `capability: <AbstractKind>` (legacy). Until they're registered, validateReferences
|
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
import type { ResourceManifest } from "@telorun/sdk";
|
|
2
2
|
import type { LoadedGraph, LoadedModule } from "./loaded-types.js";
|
|
3
|
+
/** The import-boundary forwarding rule, shared by `flattenForAnalyzer` (the
|
|
4
|
+
* CLI / kernel loader path) and the telo-editor's workspace projection so the
|
|
5
|
+
* two cannot drift. Given one module's stamped manifests and whether that
|
|
6
|
+
* module is the analysis entry (root), returns the manifests that cross into
|
|
7
|
+
* the consumer's flat analysis list:
|
|
8
|
+
*
|
|
9
|
+
* - **Root module** — every manifest is local; returned unchanged. The root's
|
|
10
|
+
* internals (CEL / schema / refs) are validated in full.
|
|
11
|
+
* - **Imported module** — only `Telo.Definition` / `Telo.Abstract` /
|
|
12
|
+
* `Telo.Import` docs cross unconditionally, plus the instances named in the
|
|
13
|
+
* module's `exports.resources` (stamped `metadata.forwardedExport: true`).
|
|
14
|
+
* The module doc and internal (unexported) instances are dropped — they
|
|
15
|
+
* belong to that module's own analysis pass.
|
|
16
|
+
*
|
|
17
|
+
* `forwardedExport` marks an instance as a cross-module resolution TARGET only
|
|
18
|
+
* (keyed by `metadata.module`), so `resolveRefSentinels` files it under
|
|
19
|
+
* `byModuleName` and `!ref Alias.name` resolves, while `validate-references` /
|
|
20
|
+
* the per-resource validation loop never re-walk or re-validate it against the
|
|
21
|
+
* consumer's scope. A consumer that instead emits every module doc as a peer
|
|
22
|
+
* local manifest silently breaks both. */
|
|
23
|
+
export declare function selectModuleManifestsForAnalysis(moduleManifests: ResourceManifest[], isRoot: boolean): ResourceManifest[];
|
|
3
24
|
/** Produce the flat manifest list `analyze()` consumes today.
|
|
4
25
|
*
|
|
5
26
|
* Combines the entry module's manifests with `Telo.Definition`,
|
|
6
|
-
* `Telo.Abstract`, and `Telo.Import` docs forwarded from imported libraries
|
|
27
|
+
* `Telo.Abstract`, and `Telo.Import` docs forwarded from imported libraries
|
|
28
|
+
* (plus their `exports.resources` instances) via `selectModuleManifestsForAnalysis`.
|
|
7
29
|
* Stamps three flavours of metadata along the way:
|
|
8
30
|
*
|
|
9
31
|
* - `metadata.source` and `metadata.sourceLine` — already on each manifest
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flatten-for-analyzer.d.ts","sourceRoot":"","sources":["../src/flatten-for-analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAc,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG/E
|
|
1
|
+
{"version":3,"file":"flatten-for-analyzer.d.ts","sourceRoot":"","sources":["../src/flatten-for-analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAc,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG/E;;;;;;;;;;;;;;;;;;;2CAmB2C;AAC3C,wBAAgB,gCAAgC,CAC9C,eAAe,EAAE,gBAAgB,EAAE,EACnC,MAAM,EAAE,OAAO,GACd,gBAAgB,EAAE,CAwBpB;AAED;;;;;;;;;;;;;;;;;;;6EAmB6E;AAC7E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,gBAAgB,EAAE,CA+CzE;AAED;;;;;6BAK6B;AAC7B,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,YAAY,GAAG,gBAAgB,EAAE,CAEzE"}
|
|
@@ -1,8 +1,50 @@
|
|
|
1
1
|
import { isModuleKind } from "./module-kinds.js";
|
|
2
|
+
/** The import-boundary forwarding rule, shared by `flattenForAnalyzer` (the
|
|
3
|
+
* CLI / kernel loader path) and the telo-editor's workspace projection so the
|
|
4
|
+
* two cannot drift. Given one module's stamped manifests and whether that
|
|
5
|
+
* module is the analysis entry (root), returns the manifests that cross into
|
|
6
|
+
* the consumer's flat analysis list:
|
|
7
|
+
*
|
|
8
|
+
* - **Root module** — every manifest is local; returned unchanged. The root's
|
|
9
|
+
* internals (CEL / schema / refs) are validated in full.
|
|
10
|
+
* - **Imported module** — only `Telo.Definition` / `Telo.Abstract` /
|
|
11
|
+
* `Telo.Import` docs cross unconditionally, plus the instances named in the
|
|
12
|
+
* module's `exports.resources` (stamped `metadata.forwardedExport: true`).
|
|
13
|
+
* The module doc and internal (unexported) instances are dropped — they
|
|
14
|
+
* belong to that module's own analysis pass.
|
|
15
|
+
*
|
|
16
|
+
* `forwardedExport` marks an instance as a cross-module resolution TARGET only
|
|
17
|
+
* (keyed by `metadata.module`), so `resolveRefSentinels` files it under
|
|
18
|
+
* `byModuleName` and `!ref Alias.name` resolves, while `validate-references` /
|
|
19
|
+
* the per-resource validation loop never re-walk or re-validate it against the
|
|
20
|
+
* consumer's scope. A consumer that instead emits every module doc as a peer
|
|
21
|
+
* local manifest silently breaks both. */
|
|
22
|
+
export function selectModuleManifestsForAnalysis(moduleManifests, isRoot) {
|
|
23
|
+
if (isRoot)
|
|
24
|
+
return moduleManifests;
|
|
25
|
+
const libDoc = moduleManifests.find((m) => isModuleKind(m.kind));
|
|
26
|
+
const exportedResources = new Set(libDoc?.exports?.resources ?? []);
|
|
27
|
+
const out = [];
|
|
28
|
+
for (const m of moduleManifests) {
|
|
29
|
+
if (m.kind === "Telo.Definition" || m.kind === "Telo.Abstract" || m.kind === "Telo.Import") {
|
|
30
|
+
out.push(m);
|
|
31
|
+
}
|
|
32
|
+
else if (!isModuleKind(m.kind) &&
|
|
33
|
+
typeof m.metadata?.name === "string" &&
|
|
34
|
+
exportedResources.has(m.metadata.name)) {
|
|
35
|
+
out.push({
|
|
36
|
+
...m,
|
|
37
|
+
metadata: { ...m.metadata, forwardedExport: true },
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
2
43
|
/** Produce the flat manifest list `analyze()` consumes today.
|
|
3
44
|
*
|
|
4
45
|
* Combines the entry module's manifests with `Telo.Definition`,
|
|
5
|
-
* `Telo.Abstract`, and `Telo.Import` docs forwarded from imported libraries
|
|
46
|
+
* `Telo.Abstract`, and `Telo.Import` docs forwarded from imported libraries
|
|
47
|
+
* (plus their `exports.resources` instances) via `selectModuleManifestsForAnalysis`.
|
|
6
48
|
* Stamps three flavours of metadata along the way:
|
|
7
49
|
*
|
|
8
50
|
* - `metadata.source` and `metadata.sourceLine` — already on each manifest
|
|
@@ -20,8 +62,7 @@ import { isModuleKind } from "./module-kinds.js";
|
|
|
20
62
|
* callers look it up via `findPositions(graph, ...)` on the LoadedGraph. */
|
|
21
63
|
export function flattenForAnalyzer(graph) {
|
|
22
64
|
const result = [];
|
|
23
|
-
|
|
24
|
-
result.push(...stampedEntry);
|
|
65
|
+
result.push(...selectModuleManifestsForAnalysis(collectModuleManifests(graph.entry), true));
|
|
25
66
|
const seen = new Set([graph.rootSource]);
|
|
26
67
|
const queue = [graph.rootSource];
|
|
27
68
|
while (queue.length > 0) {
|
|
@@ -37,31 +78,7 @@ export function flattenForAnalyzer(graph) {
|
|
|
37
78
|
const targetModule = graph.modules.get(edge.targetSource);
|
|
38
79
|
if (!targetModule)
|
|
39
80
|
continue;
|
|
40
|
-
|
|
41
|
-
const libDoc = stamped.find((m) => isModuleKind(m.kind));
|
|
42
|
-
const exportedResources = new Set(libDoc?.exports?.resources ?? []);
|
|
43
|
-
for (const m of stamped) {
|
|
44
|
-
if (m.kind === "Telo.Definition" ||
|
|
45
|
-
m.kind === "Telo.Abstract" ||
|
|
46
|
-
m.kind === "Telo.Import") {
|
|
47
|
-
result.push(m);
|
|
48
|
-
}
|
|
49
|
-
else if (!isModuleKind(m.kind) &&
|
|
50
|
-
typeof m.metadata?.name === "string" &&
|
|
51
|
-
exportedResources.has(m.metadata.name)) {
|
|
52
|
-
// Forward instances listed in the library's `exports.resources` so the
|
|
53
|
-
// consumer's analyzer can resolve, gate, kind-check, and draw topology edges
|
|
54
|
-
// for cross-module `!ref Alias.name`. The gate IS this forwarding — only
|
|
55
|
-
// exported names cross the boundary. `metadata.forwardedExport` marks them as
|
|
56
|
-
// cross-module resolution targets only (keyed by `metadata.module`), so ref
|
|
57
|
-
// resolution / validation treats them as targets, never as local sources to
|
|
58
|
-
// re-validate or walk.
|
|
59
|
-
result.push({
|
|
60
|
-
...m,
|
|
61
|
-
metadata: { ...m.metadata, forwardedExport: true },
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
81
|
+
result.push(...selectModuleManifestsForAnalysis(collectModuleManifests(targetModule), false));
|
|
65
82
|
}
|
|
66
83
|
}
|
|
67
84
|
// Stamp resolved import identity on every Telo.Import in the result by
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { AnalysisRegistry } from "./analysis-registry.js";
|
|
2
2
|
export { StaticAnalyzer } from "./analyzer.js";
|
|
3
3
|
export type { GraphLoadError, ImportEdge, LoadedFile, LoadedGraph, LoadedModule, ParseError, } from "./loaded-types.js";
|
|
4
|
-
export { flattenForAnalyzer, flattenLoadedModule } from "./flatten-for-analyzer.js";
|
|
4
|
+
export { flattenForAnalyzer, flattenLoadedModule, selectModuleManifestsForAnalysis, } from "./flatten-for-analyzer.js";
|
|
5
5
|
export { visitManifest } from "./manifest-visitor.js";
|
|
6
6
|
export type { CelSiteEvent, ManifestVisitor, RefSiteEvent, ResourceEnterEvent, ResourceExitEvent, ScopeBoundaryEvent, SchemaFromSiteEvent, VisitOptions, } from "./manifest-visitor.js";
|
|
7
7
|
export { Loader } from "./manifest-loader.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EACR,cAAc,EACd,UAAU,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,UAAU,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EACR,cAAc,EACd,UAAU,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,UAAU,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,kBAAkB,EAClB,mBAAmB,EACnB,gCAAgC,GACnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,YAAY,EACR,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC/D,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EACH,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,GACtB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC3E,YAAY,EACR,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,aAAa,EACb,KAAK,EACR,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { AnalysisRegistry } from "./analysis-registry.js";
|
|
2
2
|
export { StaticAnalyzer } from "./analyzer.js";
|
|
3
|
-
export { flattenForAnalyzer, flattenLoadedModule } from "./flatten-for-analyzer.js";
|
|
3
|
+
export { flattenForAnalyzer, flattenLoadedModule, selectModuleManifestsForAnalysis, } from "./flatten-for-analyzer.js";
|
|
4
4
|
export { visitManifest } from "./manifest-visitor.js";
|
|
5
5
|
export { Loader } from "./manifest-loader.js";
|
|
6
6
|
export { isModuleKind, MODULE_KINDS } from "./module-kinds.js";
|
package/package.json
CHANGED
package/src/analyzer.ts
CHANGED
|
@@ -716,6 +716,28 @@ export class StaticAnalyzer {
|
|
|
716
716
|
}
|
|
717
717
|
}
|
|
718
718
|
|
|
719
|
+
// Seed `Self` for every module that contributes definitions but whose own
|
|
720
|
+
// Telo.Library doc isn't in this manifest set. `flattenForAnalyzer` forwards an
|
|
721
|
+
// imported library's definitions/abstracts/imports but NOT its module doc, so the
|
|
722
|
+
// module-doc loop above can't register `Self` for imported modules. Without this, a
|
|
723
|
+
// definition's `extends: Self.X` (a kind defined in the same library as the abstract)
|
|
724
|
+
// can't resolve and its `extendedBy` edge mis-keys under the literal "Self.X" — which
|
|
725
|
+
// stays invisible until another module also implements that abstract and flips the
|
|
726
|
+
// reference check from lenient to strict. `Self` always maps a module to its own name.
|
|
727
|
+
for (const m of manifests) {
|
|
728
|
+
if (m.kind !== "Telo.Definition" && m.kind !== "Telo.Abstract") continue;
|
|
729
|
+
const ownModule = (m.metadata as { module?: string } | undefined)?.module;
|
|
730
|
+
if (!ownModule || rootModules.has(ownModule)) continue;
|
|
731
|
+
let libResolver = aliasesByModule.get(ownModule);
|
|
732
|
+
if (!libResolver) {
|
|
733
|
+
libResolver = new AliasResolver();
|
|
734
|
+
aliasesByModule.set(ownModule, libResolver);
|
|
735
|
+
}
|
|
736
|
+
if (!libResolver.hasAlias("Self")) {
|
|
737
|
+
libResolver.registerImport("Self", ownModule, []);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
719
741
|
// Register definitions from Telo.Definition AND Telo.Abstract resources.
|
|
720
742
|
// Abstracts declare contracts that implementations target via `extends` (canonical)
|
|
721
743
|
// or `capability: <AbstractKind>` (legacy). Until they're registered, validateReferences
|
|
@@ -2,10 +2,60 @@ import type { ResourceManifest } from "@telorun/sdk";
|
|
|
2
2
|
import type { LoadedFile, LoadedGraph, LoadedModule } from "./loaded-types.js";
|
|
3
3
|
import { isModuleKind } from "./module-kinds.js";
|
|
4
4
|
|
|
5
|
+
/** The import-boundary forwarding rule, shared by `flattenForAnalyzer` (the
|
|
6
|
+
* CLI / kernel loader path) and the telo-editor's workspace projection so the
|
|
7
|
+
* two cannot drift. Given one module's stamped manifests and whether that
|
|
8
|
+
* module is the analysis entry (root), returns the manifests that cross into
|
|
9
|
+
* the consumer's flat analysis list:
|
|
10
|
+
*
|
|
11
|
+
* - **Root module** — every manifest is local; returned unchanged. The root's
|
|
12
|
+
* internals (CEL / schema / refs) are validated in full.
|
|
13
|
+
* - **Imported module** — only `Telo.Definition` / `Telo.Abstract` /
|
|
14
|
+
* `Telo.Import` docs cross unconditionally, plus the instances named in the
|
|
15
|
+
* module's `exports.resources` (stamped `metadata.forwardedExport: true`).
|
|
16
|
+
* The module doc and internal (unexported) instances are dropped — they
|
|
17
|
+
* belong to that module's own analysis pass.
|
|
18
|
+
*
|
|
19
|
+
* `forwardedExport` marks an instance as a cross-module resolution TARGET only
|
|
20
|
+
* (keyed by `metadata.module`), so `resolveRefSentinels` files it under
|
|
21
|
+
* `byModuleName` and `!ref Alias.name` resolves, while `validate-references` /
|
|
22
|
+
* the per-resource validation loop never re-walk or re-validate it against the
|
|
23
|
+
* consumer's scope. A consumer that instead emits every module doc as a peer
|
|
24
|
+
* local manifest silently breaks both. */
|
|
25
|
+
export function selectModuleManifestsForAnalysis(
|
|
26
|
+
moduleManifests: ResourceManifest[],
|
|
27
|
+
isRoot: boolean,
|
|
28
|
+
): ResourceManifest[] {
|
|
29
|
+
if (isRoot) return moduleManifests;
|
|
30
|
+
|
|
31
|
+
const libDoc = moduleManifests.find((m) => isModuleKind(m.kind));
|
|
32
|
+
const exportedResources = new Set<string>(
|
|
33
|
+
(libDoc as { exports?: { resources?: string[] } } | undefined)?.exports?.resources ?? [],
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const out: ResourceManifest[] = [];
|
|
37
|
+
for (const m of moduleManifests) {
|
|
38
|
+
if (m.kind === "Telo.Definition" || m.kind === "Telo.Abstract" || m.kind === "Telo.Import") {
|
|
39
|
+
out.push(m);
|
|
40
|
+
} else if (
|
|
41
|
+
!isModuleKind(m.kind) &&
|
|
42
|
+
typeof m.metadata?.name === "string" &&
|
|
43
|
+
exportedResources.has(m.metadata.name as string)
|
|
44
|
+
) {
|
|
45
|
+
out.push({
|
|
46
|
+
...m,
|
|
47
|
+
metadata: { ...m.metadata, forwardedExport: true } as ResourceManifest["metadata"],
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
|
|
5
54
|
/** Produce the flat manifest list `analyze()` consumes today.
|
|
6
55
|
*
|
|
7
56
|
* Combines the entry module's manifests with `Telo.Definition`,
|
|
8
|
-
* `Telo.Abstract`, and `Telo.Import` docs forwarded from imported libraries
|
|
57
|
+
* `Telo.Abstract`, and `Telo.Import` docs forwarded from imported libraries
|
|
58
|
+
* (plus their `exports.resources` instances) via `selectModuleManifestsForAnalysis`.
|
|
9
59
|
* Stamps three flavours of metadata along the way:
|
|
10
60
|
*
|
|
11
61
|
* - `metadata.source` and `metadata.sourceLine` — already on each manifest
|
|
@@ -24,8 +74,7 @@ import { isModuleKind } from "./module-kinds.js";
|
|
|
24
74
|
export function flattenForAnalyzer(graph: LoadedGraph): ResourceManifest[] {
|
|
25
75
|
const result: ResourceManifest[] = [];
|
|
26
76
|
|
|
27
|
-
|
|
28
|
-
result.push(...stampedEntry);
|
|
77
|
+
result.push(...selectModuleManifestsForAnalysis(collectModuleManifests(graph.entry), true));
|
|
29
78
|
|
|
30
79
|
const seen = new Set<string>([graph.rootSource]);
|
|
31
80
|
const queue: string[] = [graph.rootSource];
|
|
@@ -43,36 +92,7 @@ export function flattenForAnalyzer(graph: LoadedGraph): ResourceManifest[] {
|
|
|
43
92
|
const targetModule = graph.modules.get(edge.targetSource);
|
|
44
93
|
if (!targetModule) continue;
|
|
45
94
|
|
|
46
|
-
|
|
47
|
-
const libDoc = stamped.find((m) => isModuleKind(m.kind));
|
|
48
|
-
const exportedResources = new Set<string>(
|
|
49
|
-
(libDoc as { exports?: { resources?: string[] } } | undefined)?.exports?.resources ?? [],
|
|
50
|
-
);
|
|
51
|
-
for (const m of stamped) {
|
|
52
|
-
if (
|
|
53
|
-
m.kind === "Telo.Definition" ||
|
|
54
|
-
m.kind === "Telo.Abstract" ||
|
|
55
|
-
m.kind === "Telo.Import"
|
|
56
|
-
) {
|
|
57
|
-
result.push(m);
|
|
58
|
-
} else if (
|
|
59
|
-
!isModuleKind(m.kind) &&
|
|
60
|
-
typeof m.metadata?.name === "string" &&
|
|
61
|
-
exportedResources.has(m.metadata.name as string)
|
|
62
|
-
) {
|
|
63
|
-
// Forward instances listed in the library's `exports.resources` so the
|
|
64
|
-
// consumer's analyzer can resolve, gate, kind-check, and draw topology edges
|
|
65
|
-
// for cross-module `!ref Alias.name`. The gate IS this forwarding — only
|
|
66
|
-
// exported names cross the boundary. `metadata.forwardedExport` marks them as
|
|
67
|
-
// cross-module resolution targets only (keyed by `metadata.module`), so ref
|
|
68
|
-
// resolution / validation treats them as targets, never as local sources to
|
|
69
|
-
// re-validate or walk.
|
|
70
|
-
result.push({
|
|
71
|
-
...m,
|
|
72
|
-
metadata: { ...m.metadata, forwardedExport: true } as ResourceManifest["metadata"],
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
}
|
|
95
|
+
result.push(...selectModuleManifestsForAnalysis(collectModuleManifests(targetModule), false));
|
|
76
96
|
}
|
|
77
97
|
}
|
|
78
98
|
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,11 @@ export type {
|
|
|
8
8
|
LoadedModule,
|
|
9
9
|
ParseError,
|
|
10
10
|
} from "./loaded-types.js";
|
|
11
|
-
export {
|
|
11
|
+
export {
|
|
12
|
+
flattenForAnalyzer,
|
|
13
|
+
flattenLoadedModule,
|
|
14
|
+
selectModuleManifestsForAnalysis,
|
|
15
|
+
} from "./flatten-for-analyzer.js";
|
|
12
16
|
export { visitManifest } from "./manifest-visitor.js";
|
|
13
17
|
export type {
|
|
14
18
|
CelSiteEvent,
|