@component-compass/reference-graph 0.0.0-pr-114-393daf6-20260518195554
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/builder.d.ts +40 -0
- package/dist/builder.js +80 -0
- package/dist/builder.js.map +1 -0
- package/dist/engine/argument-map.d.ts +14 -0
- package/dist/engine/argument-map.js +30 -0
- package/dist/engine/argument-map.js.map +1 -0
- package/dist/engine/cycle-detection.d.ts +10 -0
- package/dist/engine/cycle-detection.js +25 -0
- package/dist/engine/cycle-detection.js.map +1 -0
- package/dist/engine/index.d.ts +43 -0
- package/dist/engine/index.js +241 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/resolve-reference.d.ts +9 -0
- package/dist/engine/resolve-reference.js +125 -0
- package/dist/engine/resolve-reference.js.map +1 -0
- package/dist/engine/resolve-type.d.ts +11 -0
- package/dist/engine/resolve-type.js +154 -0
- package/dist/engine/resolve-type.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/types/file-graph.d.ts +81 -0
- package/dist/types/file-graph.js +2 -0
- package/dist/types/file-graph.js.map +1 -0
- package/dist/types/inferred-type.d.ts +44 -0
- package/dist/types/inferred-type.js +2 -0
- package/dist/types/inferred-type.js.map +1 -0
- package/dist/types/reference.d.ts +20 -0
- package/dist/types/reference.js +2 -0
- package/dist/types/reference.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ResolveImport } from "@component-compass/plugin-core";
|
|
2
|
+
import type { BindingDecl, ExportRecord, Graph, ImportRecord, Reference, ScopeId } from "./index.js";
|
|
3
|
+
export interface FileBuilder {
|
|
4
|
+
pushScope(): ScopeId;
|
|
5
|
+
popScope(): void;
|
|
6
|
+
currentScope(): ScopeId;
|
|
7
|
+
addImport(record: Omit<ImportRecord, "scope"> & {
|
|
8
|
+
scope?: ScopeId;
|
|
9
|
+
}): void;
|
|
10
|
+
addDeclaration(decl: Omit<BindingDecl, "scope"> & {
|
|
11
|
+
scope?: ScopeId;
|
|
12
|
+
}): void;
|
|
13
|
+
addExport(record: ExportRecord): void;
|
|
14
|
+
addJsxUsage(usage: {
|
|
15
|
+
ref: Omit<Reference, "scope"> & {
|
|
16
|
+
scope?: ScopeId;
|
|
17
|
+
};
|
|
18
|
+
loc: {
|
|
19
|
+
line: number;
|
|
20
|
+
column: number;
|
|
21
|
+
};
|
|
22
|
+
props: unknown[];
|
|
23
|
+
}): void;
|
|
24
|
+
/** Wire the owner of the last-emitted JsxUsage. */
|
|
25
|
+
setOwner(ownerSymbolRef: Reference | null): void;
|
|
26
|
+
}
|
|
27
|
+
export interface GraphBuilder {
|
|
28
|
+
beginFile(filePath: string): FileBuilder;
|
|
29
|
+
build(): Graph;
|
|
30
|
+
}
|
|
31
|
+
export type CreateGraphBuilderOptions = {
|
|
32
|
+
moduleResolver: ResolveImport;
|
|
33
|
+
/**
|
|
34
|
+
* Optional absolute repo root. When provided, the built Graph gains a
|
|
35
|
+
* `resolveToGraphKey` helper that normalises absolute paths returned by
|
|
36
|
+
* `moduleResolver` into repo-relative POSIX keys matching `Graph.files`.
|
|
37
|
+
*/
|
|
38
|
+
repoRoot?: string;
|
|
39
|
+
};
|
|
40
|
+
export declare function createGraphBuilder(opts: CreateGraphBuilderOptions): GraphBuilder;
|
package/dist/builder.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// API surface validated against two emitters (paper-sketch + implementation):
|
|
2
|
+
// - parser-react: full implementation (Phase 6)
|
|
3
|
+
// - parser-vue: paper sketch (Task 0.2, see plan doc)
|
|
4
|
+
// Members not justified by either should not be added speculatively.
|
|
5
|
+
import { isAbsolute, relative } from "node:path";
|
|
6
|
+
import { MODULE_SCOPE } from "./index.js";
|
|
7
|
+
export function createGraphBuilder(opts) {
|
|
8
|
+
const files = new Map();
|
|
9
|
+
return {
|
|
10
|
+
beginFile(filePath) {
|
|
11
|
+
const scopes = new Map([[MODULE_SCOPE, { parent: null }]]);
|
|
12
|
+
const declarations = new Map();
|
|
13
|
+
const imports = [];
|
|
14
|
+
const exports = [];
|
|
15
|
+
const jsxUsages = [];
|
|
16
|
+
const ownership = [];
|
|
17
|
+
const scopeStack = [MODULE_SCOPE];
|
|
18
|
+
let nextScopeId = 1;
|
|
19
|
+
const fg = { filePath, scopes, declarations, imports, exports, jsxUsages, ownership };
|
|
20
|
+
files.set(filePath, fg);
|
|
21
|
+
return {
|
|
22
|
+
pushScope() {
|
|
23
|
+
const id = nextScopeId++;
|
|
24
|
+
scopes.set(id, { parent: scopeStack[scopeStack.length - 1] ?? null });
|
|
25
|
+
scopeStack.push(id);
|
|
26
|
+
return id;
|
|
27
|
+
},
|
|
28
|
+
popScope() {
|
|
29
|
+
if (scopeStack.length <= 1)
|
|
30
|
+
throw new Error("popScope at module-scope root");
|
|
31
|
+
scopeStack.pop();
|
|
32
|
+
},
|
|
33
|
+
currentScope() {
|
|
34
|
+
return scopeStack[scopeStack.length - 1] ?? MODULE_SCOPE;
|
|
35
|
+
},
|
|
36
|
+
addImport(record) {
|
|
37
|
+
const scope = record.scope ?? scopeStack[scopeStack.length - 1] ?? MODULE_SCOPE;
|
|
38
|
+
imports.push({ ...record, scope });
|
|
39
|
+
},
|
|
40
|
+
addDeclaration(decl) {
|
|
41
|
+
const scope = decl.scope ?? scopeStack[scopeStack.length - 1] ?? MODULE_SCOPE;
|
|
42
|
+
declarations.set(`${scope}::${decl.symbol}`, { ...decl, scope });
|
|
43
|
+
},
|
|
44
|
+
addExport(record) {
|
|
45
|
+
exports.push(record);
|
|
46
|
+
},
|
|
47
|
+
addJsxUsage(usage) {
|
|
48
|
+
const scope = usage.ref.scope ?? scopeStack[scopeStack.length - 1] ?? MODULE_SCOPE;
|
|
49
|
+
jsxUsages.push({
|
|
50
|
+
ref: { ...usage.ref, scope },
|
|
51
|
+
loc: usage.loc,
|
|
52
|
+
props: usage.props,
|
|
53
|
+
});
|
|
54
|
+
ownership.push({ usageIdx: jsxUsages.length - 1, ownerSymbolRef: null });
|
|
55
|
+
},
|
|
56
|
+
setOwner(ownerSymbolRef) {
|
|
57
|
+
if (ownership.length === 0)
|
|
58
|
+
return;
|
|
59
|
+
const last = ownership[ownership.length - 1];
|
|
60
|
+
if (last)
|
|
61
|
+
last.ownerSymbolRef = ownerSymbolRef;
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
build() {
|
|
66
|
+
if (opts.repoRoot) {
|
|
67
|
+
const repoRoot = opts.repoRoot;
|
|
68
|
+
const resolveToGraphKey = (absPath) => {
|
|
69
|
+
if (!isAbsolute(absPath))
|
|
70
|
+
return null;
|
|
71
|
+
const rel = relative(repoRoot, absPath).replace(/\\/g, "/");
|
|
72
|
+
return files.has(rel) ? rel : null;
|
|
73
|
+
};
|
|
74
|
+
return { files, moduleResolver: opts.moduleResolver, resolveToGraphKey };
|
|
75
|
+
}
|
|
76
|
+
return { files, moduleResolver: opts.moduleResolver };
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { InferredType, Reference } from "../index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Argument map: substitution table for ParameterOf nodes.
|
|
4
|
+
*
|
|
5
|
+
* When `resolveType` walks `ReturnTypeOf(callee, args)`, it binds `args` to
|
|
6
|
+
* the callee function's parameters. Any `ParameterOf(fn, i)` encountered
|
|
7
|
+
* during resolution of the function's return type substitutes via this map.
|
|
8
|
+
*/
|
|
9
|
+
export interface ArgumentMap {
|
|
10
|
+
bind(fn: Reference, args: InferredType[]): void;
|
|
11
|
+
unbind(fn: Reference): void;
|
|
12
|
+
lookup(fn: Reference, index: number): InferredType | undefined;
|
|
13
|
+
}
|
|
14
|
+
export declare function createArgumentMap(): ArgumentMap;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function refKey(ref) {
|
|
2
|
+
return `${ref.symbol}::${ref.scope}`;
|
|
3
|
+
}
|
|
4
|
+
export function createArgumentMap() {
|
|
5
|
+
const stack = [];
|
|
6
|
+
return {
|
|
7
|
+
bind(fn, args) {
|
|
8
|
+
stack.push({ key: refKey(fn), args });
|
|
9
|
+
},
|
|
10
|
+
unbind(fn) {
|
|
11
|
+
const key = refKey(fn);
|
|
12
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
13
|
+
if (stack[i]?.key === key) {
|
|
14
|
+
stack.splice(i, 1);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
lookup(fn, index) {
|
|
20
|
+
const key = refKey(fn);
|
|
21
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
22
|
+
const frame = stack[i];
|
|
23
|
+
if (frame?.key === key)
|
|
24
|
+
return frame.args[index];
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=argument-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"argument-map.js","sourceRoot":"","sources":["../../src/engine/argument-map.ts"],"names":[],"mappings":"AAeA,SAAS,MAAM,CAAC,GAAc;IAC5B,OAAO,GAAG,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,MAAM,KAAK,GAAiD,EAAE,CAAC;IAC/D,OAAO;QACL,IAAI,CAAC,EAAE,EAAE,IAAI;YACX,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,CAAC;QACD,MAAM,CAAC,EAAE;YACP,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;YACvB,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,GAAG,EAAE,CAAC;oBAC1B,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBACnB,OAAO;gBACT,CAAC;YACH,CAAC;QACH,CAAC;QACD,MAAM,CAAC,EAAE,EAAE,KAAK;YACd,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;YACvB,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACvB,IAAI,KAAK,EAAE,GAAG,KAAK,GAAG;oBAAE,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnD,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Max barrel-walk depth, matches LazyResolver's MAX_REEXPORT_HOPS budget. */
|
|
2
|
+
export declare const MAX_REFERENCE_DEPTH = 32;
|
|
3
|
+
export type CycleGuard = {
|
|
4
|
+
visited: Set<string>;
|
|
5
|
+
depth: number;
|
|
6
|
+
/** Cheap key: file + symbol identity for cycle detection. */
|
|
7
|
+
push(file: string, symbol: string): "ok" | "cycle" | "too-deep";
|
|
8
|
+
pop(file: string, symbol: string): void;
|
|
9
|
+
};
|
|
10
|
+
export declare function createCycleGuard(): CycleGuard;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Max barrel-walk depth, matches LazyResolver's MAX_REEXPORT_HOPS budget. */
|
|
2
|
+
export const MAX_REFERENCE_DEPTH = 32;
|
|
3
|
+
export function createCycleGuard() {
|
|
4
|
+
const visited = new Set();
|
|
5
|
+
let depth = 0;
|
|
6
|
+
return {
|
|
7
|
+
visited,
|
|
8
|
+
get depth() { return depth; },
|
|
9
|
+
push(file, symbol) {
|
|
10
|
+
const key = `${file}::${symbol}`;
|
|
11
|
+
if (visited.has(key))
|
|
12
|
+
return "cycle";
|
|
13
|
+
if (depth >= MAX_REFERENCE_DEPTH)
|
|
14
|
+
return "too-deep";
|
|
15
|
+
visited.add(key);
|
|
16
|
+
depth++;
|
|
17
|
+
return "ok";
|
|
18
|
+
},
|
|
19
|
+
pop(file, symbol) {
|
|
20
|
+
visited.delete(`${file}::${symbol}`);
|
|
21
|
+
depth--;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=cycle-detection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cycle-detection.js","sourceRoot":"","sources":["../../src/engine/cycle-detection.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAUtC,MAAM,UAAU,gBAAgB;IAC9B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO;QACL,OAAO;QACP,IAAI,KAAK,KAAK,OAAO,KAAK,CAAC,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI,EAAE,MAAM;YACf,MAAM,GAAG,GAAG,GAAG,IAAI,KAAK,MAAM,EAAE,CAAC;YACjC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,OAAO,OAAO,CAAC;YACrC,IAAI,KAAK,IAAI,mBAAmB;gBAAE,OAAO,UAAU,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACjB,KAAK,EAAE,CAAC;YACR,OAAO,IAAI,CAAC;QACd,CAAC;QACD,GAAG,CAAC,IAAI,EAAE,MAAM;YACd,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC;YACrC,KAAK,EAAE,CAAC;QACV,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Graph } from "../index.js";
|
|
2
|
+
import type { OccurrenceVia, ComponentId } from "@component-compass/plugin-core";
|
|
3
|
+
/** Full occurrence shape produced by the engine.
|
|
4
|
+
*
|
|
5
|
+
* `rawComponentId` carries the structured `ComponentId` (same type as in
|
|
6
|
+
* plugin-core scan-types) so scan.ts can pass it through
|
|
7
|
+
* `computeStableIdFromComponentId` (cli/src/identity.ts) and produce the
|
|
8
|
+
* final short-hash string that lands on `OutputOccurrence.componentId`. The
|
|
9
|
+
* engine stays self-contained and avoids duplicating the sha1 logic.
|
|
10
|
+
*
|
|
11
|
+
* `occurrenceId` is a provisional hash keyed on `serialiseComponentId(...)` +
|
|
12
|
+
* location; scan.ts re-derives it after hashing.
|
|
13
|
+
*/
|
|
14
|
+
export type EngineOccurrence = {
|
|
15
|
+
/** Raw structured component identity (pre-hash). Scan.ts converts to string. */
|
|
16
|
+
rawComponentId: ComponentId;
|
|
17
|
+
filePath: string;
|
|
18
|
+
line: number;
|
|
19
|
+
column: number;
|
|
20
|
+
/** Outermost access pattern (alias for viaChain[0]). */
|
|
21
|
+
via: OccurrenceVia;
|
|
22
|
+
/** Full provenance chain, outermost-first. Single-element for direct imports. */
|
|
23
|
+
viaChain: OccurrenceVia[];
|
|
24
|
+
props: Record<string, unknown>;
|
|
25
|
+
/** Provisional stable id (keyed on serialised componentId + location).
|
|
26
|
+
* Scan.ts re-derives using the final hashed componentId string. */
|
|
27
|
+
occurrenceId: string;
|
|
28
|
+
/** Composition depth — 0 for now; deferred to a follow-up task. */
|
|
29
|
+
depth: number;
|
|
30
|
+
/** Declaration position for local-scope identities. */
|
|
31
|
+
definition?: {
|
|
32
|
+
line: number;
|
|
33
|
+
column: number;
|
|
34
|
+
};
|
|
35
|
+
/** Raw owner component identity (pre-hash). Scan.ts converts to ownerComponentId string. */
|
|
36
|
+
rawOwnerComponentId?: ComponentId;
|
|
37
|
+
/** Stable id of enclosing component definition. Absent when deferred. */
|
|
38
|
+
ownerComponentId?: string;
|
|
39
|
+
};
|
|
40
|
+
export type ResolvedGraph = {
|
|
41
|
+
occurrences: EngineOccurrence[];
|
|
42
|
+
};
|
|
43
|
+
export declare function resolve(graph: Graph): ResolvedGraph;
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { MODULE_SCOPE } from "../index.js";
|
|
2
|
+
import { computeOccurrenceId, serialiseComponentId } from "@component-compass/plugin-core";
|
|
3
|
+
import { createArgumentMap } from "./argument-map.js";
|
|
4
|
+
import { resolveReference } from "./resolve-reference.js";
|
|
5
|
+
import { resolveType } from "./resolve-type.js";
|
|
6
|
+
/** Extract the npm package name from a module specifier.
|
|
7
|
+
* - `react` → `react`
|
|
8
|
+
* - `@org/pkg` → `@org/pkg`
|
|
9
|
+
* - `@org/pkg/sub/path` → `@org/pkg`
|
|
10
|
+
* - `./foo` / `../bar` → null (relative — local file, skip)
|
|
11
|
+
* - `/abs/path` → null (absolute — local file, skip)
|
|
12
|
+
*/
|
|
13
|
+
function packageNameFromSpecifier(specifier) {
|
|
14
|
+
if (specifier.startsWith(".") || specifier.startsWith("/"))
|
|
15
|
+
return null;
|
|
16
|
+
const parts = specifier.split("/");
|
|
17
|
+
if (parts[0]?.startsWith("@")) {
|
|
18
|
+
if (parts.length < 2)
|
|
19
|
+
return null;
|
|
20
|
+
return `${parts[0]}/${parts[1]}`;
|
|
21
|
+
}
|
|
22
|
+
return parts[0] ?? null;
|
|
23
|
+
}
|
|
24
|
+
export function resolve(graph) {
|
|
25
|
+
const occurrences = [];
|
|
26
|
+
const argMap = createArgumentMap();
|
|
27
|
+
for (const [filePath, fileGraph] of graph.files) {
|
|
28
|
+
for (let usageIdx = 0; usageIdx < fileGraph.jsxUsages.length; usageIdx++) {
|
|
29
|
+
const usage = fileGraph.jsxUsages[usageIdx];
|
|
30
|
+
if (!usage)
|
|
31
|
+
continue;
|
|
32
|
+
// Resolve owner symbol ref for this usage (for composition attribution).
|
|
33
|
+
const ownerRef = fileGraph.ownership[usageIdx]?.ownerSymbolRef ?? null;
|
|
34
|
+
// Find the import record that introduced the root symbol at module scope.
|
|
35
|
+
// We check usage.ref.symbol (the root binding name), not member-chain
|
|
36
|
+
// segments, because ImportRecord.local binds the top-level name.
|
|
37
|
+
const matchedImport = fileGraph.imports.find((i) => i.local === usage.ref.symbol);
|
|
38
|
+
if (!matchedImport) {
|
|
39
|
+
// Symbol is locally declared (no import) — emit local identity.
|
|
40
|
+
const decl = findLocalDeclaration(fileGraph, usage.ref);
|
|
41
|
+
if (!decl)
|
|
42
|
+
continue;
|
|
43
|
+
// Resolve to check JSX type.
|
|
44
|
+
const refType = resolveReference(graph, fileGraph, usage.ref);
|
|
45
|
+
const terminals = resolveType(graph, fileGraph, refType, argMap);
|
|
46
|
+
if (!terminals.some((t) => t.kind === "JSX"))
|
|
47
|
+
continue;
|
|
48
|
+
const rawOwnerComponentId = ownerRef
|
|
49
|
+
? makeLocalComponentId(fileGraph.filePath, ownerRef.symbol)
|
|
50
|
+
: undefined;
|
|
51
|
+
pushLocalOccurrence(occurrences, filePath, usage, decl, rawOwnerComponentId);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const packageName = packageNameFromSpecifier(matchedImport.specifier);
|
|
55
|
+
if (!packageName) {
|
|
56
|
+
// Relative / absolute specifier — always a local file reference.
|
|
57
|
+
// Resolve the target path; normalize absolute → graph-relative if possible.
|
|
58
|
+
const resolvedAbsTarget = graph.moduleResolver(filePath, matchedImport.specifier);
|
|
59
|
+
if (!resolvedAbsTarget)
|
|
60
|
+
continue;
|
|
61
|
+
const resolvedTarget = graph.resolveToGraphKey
|
|
62
|
+
? (graph.resolveToGraphKey(resolvedAbsTarget) ?? resolvedAbsTarget)
|
|
63
|
+
: resolvedAbsTarget;
|
|
64
|
+
// Resolve the type to confirm it's a JSX component. Cross-file resolution
|
|
65
|
+
// works when resolveToGraphKey is present (graph keys are repo-relative).
|
|
66
|
+
const refType = resolveReference(graph, fileGraph, usage.ref);
|
|
67
|
+
const terminals = resolveType(graph, fileGraph, refType, argMap);
|
|
68
|
+
const jsxTerminals = terminals.filter((t) => t.kind === "JSX");
|
|
69
|
+
if (jsxTerminals.length === 0)
|
|
70
|
+
continue;
|
|
71
|
+
// Determine the actual export name used in the target file.
|
|
72
|
+
// When the target is in the graph, look up the export record to find
|
|
73
|
+
// the local symbol name (e.g. "Button" rather than "default").
|
|
74
|
+
// This ensures the componentId hash matches the local-index seed.
|
|
75
|
+
const targetGraph = graph.files.get(resolvedTarget);
|
|
76
|
+
let exportName = matchedImport.imported;
|
|
77
|
+
if (targetGraph && matchedImport.imported === "default") {
|
|
78
|
+
const defaultExp = targetGraph.exports.find((e) => e.kind === "default");
|
|
79
|
+
if (defaultExp && "local" in defaultExp) {
|
|
80
|
+
exportName = defaultExp.local;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else if (targetGraph) {
|
|
84
|
+
// Named import: find the local name for the exported binding.
|
|
85
|
+
const namedExp = targetGraph.exports.find((e) => e.kind === "named" && "exportedAs" in e && e.exportedAs === matchedImport.imported && "local" in e);
|
|
86
|
+
if (namedExp && "local" in namedExp) {
|
|
87
|
+
exportName = namedExp.local;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const rawOwnerComponentId = ownerRef
|
|
91
|
+
? makeLocalComponentId(fileGraph.filePath, ownerRef.symbol)
|
|
92
|
+
: undefined;
|
|
93
|
+
const via = {
|
|
94
|
+
kind: "direct-import",
|
|
95
|
+
specifier: matchedImport.specifier,
|
|
96
|
+
import: matchedImport.imported,
|
|
97
|
+
};
|
|
98
|
+
const rawComponentId = {
|
|
99
|
+
kind: "react-component",
|
|
100
|
+
export: exportName,
|
|
101
|
+
source: { type: "local", filePath: resolvedTarget },
|
|
102
|
+
};
|
|
103
|
+
const provisionalId = serialiseComponentId(rawComponentId);
|
|
104
|
+
const occurrenceId = computeOccurrenceId(provisionalId, filePath, usage.loc.line, usage.loc.column);
|
|
105
|
+
occurrences.push({
|
|
106
|
+
rawComponentId,
|
|
107
|
+
filePath,
|
|
108
|
+
line: usage.loc.line,
|
|
109
|
+
column: usage.loc.column,
|
|
110
|
+
via,
|
|
111
|
+
viaChain: [via],
|
|
112
|
+
props: {},
|
|
113
|
+
occurrenceId,
|
|
114
|
+
depth: 0,
|
|
115
|
+
...(rawOwnerComponentId !== undefined ? { rawOwnerComponentId } : {}),
|
|
116
|
+
});
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
// Check whether the import resolves to a local file that IS in the graph.
|
|
120
|
+
// If it does, resolve properly to avoid false positives (e.g. importing a
|
|
121
|
+
// utility function that happens to be named with a capital letter from a
|
|
122
|
+
// workspace sibling). For imports whose target is outside the graph
|
|
123
|
+
// (external packages in node_modules), trust the JSX call site directly.
|
|
124
|
+
const resolvedAbsTarget = graph.moduleResolver(filePath, matchedImport.specifier);
|
|
125
|
+
// Normalize absolute path → repo-relative graph key when possible.
|
|
126
|
+
const resolvedNormTarget = resolvedAbsTarget !== null && graph.resolveToGraphKey
|
|
127
|
+
? (graph.resolveToGraphKey(resolvedAbsTarget) ?? resolvedAbsTarget)
|
|
128
|
+
: resolvedAbsTarget;
|
|
129
|
+
const targetInGraph = resolvedNormTarget !== null && graph.files.has(resolvedNormTarget);
|
|
130
|
+
const rawOwnerComponentId = ownerRef
|
|
131
|
+
? makeLocalComponentId(fileGraph.filePath, ownerRef.symbol)
|
|
132
|
+
: undefined;
|
|
133
|
+
if (targetInGraph) {
|
|
134
|
+
// Target file is in graph — resolve to check JSX type, and fan out
|
|
135
|
+
// per JSX terminal (handles dynamic-map fanout within workspace siblings).
|
|
136
|
+
const refType = resolveReference(graph, fileGraph, usage.ref);
|
|
137
|
+
const terminals = resolveType(graph, fileGraph, refType, argMap);
|
|
138
|
+
const jsxTerminals = terminals.filter((t) => t.kind === "JSX");
|
|
139
|
+
if (jsxTerminals.length === 0)
|
|
140
|
+
continue;
|
|
141
|
+
for (const _terminal of jsxTerminals) {
|
|
142
|
+
pushOccurrence(occurrences, filePath, usage, matchedImport, packageName, rawOwnerComponentId);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Target not in graph (external package or unresolvable specifier).
|
|
147
|
+
// Trust the JSX call site — emit one occurrence.
|
|
148
|
+
pushOccurrence(occurrences, filePath, usage, matchedImport, packageName, rawOwnerComponentId);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { occurrences };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Walk the scope chain for `ref.symbol` in `fileGraph.declarations` and
|
|
156
|
+
* return the first matching BindingDecl, or null if not found.
|
|
157
|
+
*/
|
|
158
|
+
function findLocalDeclaration(fileGraph, ref) {
|
|
159
|
+
let scope = ref.scope;
|
|
160
|
+
while (true) {
|
|
161
|
+
const decl = fileGraph.declarations.get(`${scope}::${ref.symbol}`);
|
|
162
|
+
if (decl)
|
|
163
|
+
return decl;
|
|
164
|
+
if (scope === MODULE_SCOPE)
|
|
165
|
+
return null;
|
|
166
|
+
const parent = fileGraph.scopes.get(scope)?.parent;
|
|
167
|
+
if (parent === null || parent === undefined)
|
|
168
|
+
return null;
|
|
169
|
+
scope = parent;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Build a local-scope ComponentId for a symbol declared in `filePath`.
|
|
174
|
+
* Used for both the occurrence's own identity and for owner attribution.
|
|
175
|
+
*/
|
|
176
|
+
function makeLocalComponentId(filePath, symbol) {
|
|
177
|
+
return {
|
|
178
|
+
kind: "react-component",
|
|
179
|
+
export: symbol,
|
|
180
|
+
source: { type: "local", filePath },
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function pushOccurrence(occurrences, filePath, usage, matchedImport, packageName, rawOwnerComponentId) {
|
|
184
|
+
const rawComponentId = {
|
|
185
|
+
kind: "react-component",
|
|
186
|
+
export: matchedImport.imported,
|
|
187
|
+
source: {
|
|
188
|
+
type: "external",
|
|
189
|
+
package: packageName,
|
|
190
|
+
// modulePath: proper resolution via graph.moduleResolver deferred
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
const via = {
|
|
194
|
+
kind: "direct-import",
|
|
195
|
+
specifier: matchedImport.specifier,
|
|
196
|
+
import: matchedImport.imported,
|
|
197
|
+
};
|
|
198
|
+
// Provisional occurrenceId keyed on the serialised (human-readable) form.
|
|
199
|
+
// Scan.ts re-derives the final occurrenceId using the hashed componentId.
|
|
200
|
+
const provisionalId = serialiseComponentId(rawComponentId);
|
|
201
|
+
const occurrenceId = computeOccurrenceId(provisionalId, filePath, usage.loc.line, usage.loc.column);
|
|
202
|
+
occurrences.push({
|
|
203
|
+
rawComponentId,
|
|
204
|
+
filePath,
|
|
205
|
+
line: usage.loc.line,
|
|
206
|
+
column: usage.loc.column,
|
|
207
|
+
via,
|
|
208
|
+
viaChain: [via],
|
|
209
|
+
props: {},
|
|
210
|
+
occurrenceId,
|
|
211
|
+
depth: 0,
|
|
212
|
+
...(rawOwnerComponentId !== undefined ? { rawOwnerComponentId } : {}),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Push a local-scope occurrence for a symbol declared in the same file (no import).
|
|
217
|
+
*/
|
|
218
|
+
function pushLocalOccurrence(occurrences, filePath, usage, decl, rawOwnerComponentId) {
|
|
219
|
+
const rawComponentId = {
|
|
220
|
+
kind: "react-component",
|
|
221
|
+
export: usage.ref.symbol,
|
|
222
|
+
source: { type: "local", filePath },
|
|
223
|
+
};
|
|
224
|
+
const via = { kind: "local-component" };
|
|
225
|
+
const provisionalId = serialiseComponentId(rawComponentId);
|
|
226
|
+
const occurrenceId = computeOccurrenceId(provisionalId, filePath, usage.loc.line, usage.loc.column);
|
|
227
|
+
occurrences.push({
|
|
228
|
+
rawComponentId,
|
|
229
|
+
filePath,
|
|
230
|
+
line: usage.loc.line,
|
|
231
|
+
column: usage.loc.column,
|
|
232
|
+
via,
|
|
233
|
+
viaChain: [via],
|
|
234
|
+
props: {},
|
|
235
|
+
occurrenceId,
|
|
236
|
+
depth: 0,
|
|
237
|
+
definition: { line: decl.loc.line, column: decl.loc.column },
|
|
238
|
+
...(rawOwnerComponentId !== undefined ? { rawOwnerComponentId } : {}),
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FileGraph, Graph, InferredType, Reference } from "../index.js";
|
|
2
|
+
import { type CycleGuard } from "./cycle-detection.js";
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a Reference to an InferredType by walking the scope chain in
|
|
5
|
+
* its FileGraph, falling through to imports at module scope, and following
|
|
6
|
+
* cross-file resolution through exports. Returns InferredType::Unknown for
|
|
7
|
+
* unresolved symbols and cycles.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveReference(graph: Graph, fileGraph: FileGraph, ref: Reference, guard?: CycleGuard): InferredType;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { MODULE_SCOPE } from "../index.js";
|
|
2
|
+
import { createCycleGuard } from "./cycle-detection.js";
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a Reference to an InferredType by walking the scope chain in
|
|
5
|
+
* its FileGraph, falling through to imports at module scope, and following
|
|
6
|
+
* cross-file resolution through exports. Returns InferredType::Unknown for
|
|
7
|
+
* unresolved symbols and cycles.
|
|
8
|
+
*/
|
|
9
|
+
export function resolveReference(graph, fileGraph, ref, guard = createCycleGuard()) {
|
|
10
|
+
// Walk up the scope chain.
|
|
11
|
+
let scope = ref.scope;
|
|
12
|
+
while (true) {
|
|
13
|
+
const decl = fileGraph.declarations.get(`${scope}::${ref.symbol}`);
|
|
14
|
+
if (decl) {
|
|
15
|
+
// Apply member chain via MemberOf wrap.
|
|
16
|
+
return wrapWithMemberChain(decl.value, ref.memberChain);
|
|
17
|
+
}
|
|
18
|
+
if (scope === MODULE_SCOPE)
|
|
19
|
+
break;
|
|
20
|
+
const parent = fileGraph.scopes.get(scope)?.parent;
|
|
21
|
+
if (parent === null || parent === undefined)
|
|
22
|
+
break;
|
|
23
|
+
scope = parent;
|
|
24
|
+
}
|
|
25
|
+
// At module scope — check imports.
|
|
26
|
+
const imp = fileGraph.imports.find((i) => i.local === ref.symbol);
|
|
27
|
+
if (!imp)
|
|
28
|
+
return { kind: "Unknown" };
|
|
29
|
+
const resolvedFile = graph.moduleResolver(fileGraph.filePath, imp.specifier);
|
|
30
|
+
if (!resolvedFile)
|
|
31
|
+
return { kind: "Unknown" };
|
|
32
|
+
// Normalize the resolved path to the graph key format (repo-relative POSIX).
|
|
33
|
+
// `moduleResolver` may return absolute paths; `resolveToGraphKey` maps them
|
|
34
|
+
// to relative keys matching `graph.files`.
|
|
35
|
+
const targetFile = graph.resolveToGraphKey
|
|
36
|
+
? (graph.resolveToGraphKey(resolvedFile) ?? resolvedFile)
|
|
37
|
+
: resolvedFile;
|
|
38
|
+
const targetGraph = graph.files.get(targetFile);
|
|
39
|
+
if (!targetGraph)
|
|
40
|
+
return { kind: "Unknown" };
|
|
41
|
+
// Look up the export with the imported name in the target file.
|
|
42
|
+
const exp = findExport(targetGraph.exports, imp.imported);
|
|
43
|
+
if (!exp)
|
|
44
|
+
return { kind: "Unknown" };
|
|
45
|
+
return resolveExport(graph, targetGraph, exp, ref.memberChain, guard);
|
|
46
|
+
}
|
|
47
|
+
function findExport(exports, imported) {
|
|
48
|
+
for (const exp of exports) {
|
|
49
|
+
if (exp.kind === "named" && exp.exportedAs === imported)
|
|
50
|
+
return exp;
|
|
51
|
+
if (exp.kind === "default" && imported === "default")
|
|
52
|
+
return exp;
|
|
53
|
+
}
|
|
54
|
+
// Star re-exports — fall through to first match (simplified for v1).
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
function resolveExport(graph, fileGraph, exp, memberChain, guard) {
|
|
58
|
+
if (exp.kind === "named" && "local" in exp) {
|
|
59
|
+
const guardResult = guard.push(fileGraph.filePath, exp.local);
|
|
60
|
+
if (guardResult !== "ok")
|
|
61
|
+
return { kind: "Unknown" };
|
|
62
|
+
try {
|
|
63
|
+
const localRef = {
|
|
64
|
+
symbol: exp.local,
|
|
65
|
+
scope: MODULE_SCOPE,
|
|
66
|
+
memberChain,
|
|
67
|
+
loc: { line: 0, column: 0 },
|
|
68
|
+
};
|
|
69
|
+
return resolveReference(graph, fileGraph, localRef, guard);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
guard.pop(fileGraph.filePath, exp.local);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (exp.kind === "named" && "from" in exp) {
|
|
76
|
+
// Re-export: resolve to the source module's binding.
|
|
77
|
+
const resolvedFrom = graph.moduleResolver(fileGraph.filePath, exp.from);
|
|
78
|
+
if (!resolvedFrom)
|
|
79
|
+
return { kind: "Unknown" };
|
|
80
|
+
const targetFile = graph.resolveToGraphKey
|
|
81
|
+
? (graph.resolveToGraphKey(resolvedFrom) ?? resolvedFrom)
|
|
82
|
+
: resolvedFrom;
|
|
83
|
+
const targetGraph = graph.files.get(targetFile);
|
|
84
|
+
if (!targetGraph)
|
|
85
|
+
return { kind: "Unknown" };
|
|
86
|
+
const innerExp = findExport(targetGraph.exports, exp.fromImported);
|
|
87
|
+
if (!innerExp)
|
|
88
|
+
return { kind: "Unknown" };
|
|
89
|
+
const guardResult = guard.push(fileGraph.filePath, exp.exportedAs);
|
|
90
|
+
if (guardResult !== "ok")
|
|
91
|
+
return { kind: "Unknown" };
|
|
92
|
+
try {
|
|
93
|
+
return resolveExport(graph, targetGraph, innerExp, memberChain, guard);
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
guard.pop(fileGraph.filePath, exp.exportedAs);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (exp.kind === "default" && "local" in exp) {
|
|
100
|
+
const guardResult = guard.push(fileGraph.filePath, exp.local);
|
|
101
|
+
if (guardResult !== "ok")
|
|
102
|
+
return { kind: "Unknown" };
|
|
103
|
+
try {
|
|
104
|
+
const localRef = {
|
|
105
|
+
symbol: exp.local,
|
|
106
|
+
scope: MODULE_SCOPE,
|
|
107
|
+
memberChain,
|
|
108
|
+
loc: { line: 0, column: 0 },
|
|
109
|
+
};
|
|
110
|
+
return resolveReference(graph, fileGraph, localRef, guard);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
guard.pop(fileGraph.filePath, exp.local);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return { kind: "Unknown" };
|
|
117
|
+
}
|
|
118
|
+
function wrapWithMemberChain(t, chain) {
|
|
119
|
+
let result = t;
|
|
120
|
+
for (const member of chain) {
|
|
121
|
+
result = { kind: "MemberOf", obj: result, member };
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=resolve-reference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-reference.js","sourceRoot":"","sources":["../../src/engine/resolve-reference.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FileGraph, Graph, InferredType } from "../index.js";
|
|
2
|
+
import type { ArgumentMap } from "./argument-map.js";
|
|
3
|
+
import { type CycleGuard } from "./cycle-detection.js";
|
|
4
|
+
/** Sentinel for dynamic member access (`obj[expr]` where expr isn't a literal). */
|
|
5
|
+
export declare const DYNAMIC_MEMBER_KEY = "";
|
|
6
|
+
/**
|
|
7
|
+
* Walk an InferredType to its terminal types (JSX, Str, Unknown, or
|
|
8
|
+
* concrete TypeOf/ParameterOf leaves that can't be reduced further).
|
|
9
|
+
* Returns one or more results — multi-result for Union and fanout cases.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveType(graph: Graph, fileGraph: FileGraph, type: InferredType, argMap: ArgumentMap, guard?: CycleGuard): InferredType[];
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { resolveReference } from "./resolve-reference.js";
|
|
2
|
+
import { createCycleGuard } from "./cycle-detection.js";
|
|
3
|
+
/** Sentinel for dynamic member access (`obj[expr]` where expr isn't a literal). */
|
|
4
|
+
export const DYNAMIC_MEMBER_KEY = "";
|
|
5
|
+
/**
|
|
6
|
+
* Walk an InferredType to its terminal types (JSX, Str, Unknown, or
|
|
7
|
+
* concrete TypeOf/ParameterOf leaves that can't be reduced further).
|
|
8
|
+
* Returns one or more results — multi-result for Union and fanout cases.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveType(graph, fileGraph, type, argMap, guard = createCycleGuard()) {
|
|
11
|
+
switch (type.kind) {
|
|
12
|
+
case "JSX":
|
|
13
|
+
case "Str":
|
|
14
|
+
case "Unknown":
|
|
15
|
+
return [type];
|
|
16
|
+
case "TypeOf": {
|
|
17
|
+
const resolved = resolveReference(graph, fileGraph, type.ref, guard);
|
|
18
|
+
return resolveType(graph, fileGraph, resolved, argMap, guard);
|
|
19
|
+
}
|
|
20
|
+
case "Function":
|
|
21
|
+
return type.returns.flatMap((r) => resolveType(graph, fileGraph, r, argMap, guard));
|
|
22
|
+
case "ReturnTypeOf": {
|
|
23
|
+
// Resolve the callee to its bare Function node(s) without expanding
|
|
24
|
+
// their returns — if we went through resolveType the Function case would
|
|
25
|
+
// prematurely walk returns before args are bound.
|
|
26
|
+
// Each entry carries a bindingRef: the Reference that ParameterOf nodes
|
|
27
|
+
// inside the function use as their fn key. For a TypeOf callee this is
|
|
28
|
+
// the callee ref; for a nested ReturnTypeOf chain it's propagated up.
|
|
29
|
+
const calleeFns = resolveToFunctions(graph, fileGraph, type.callee, argMap, guard);
|
|
30
|
+
const results = [];
|
|
31
|
+
for (const { fn, bindingRef } of calleeFns) {
|
|
32
|
+
if (fn.kind !== "Function") {
|
|
33
|
+
results.push({ kind: "Unknown" });
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (bindingRef)
|
|
37
|
+
argMap.bind(bindingRef, type.args);
|
|
38
|
+
try {
|
|
39
|
+
for (const ret of fn.returns) {
|
|
40
|
+
results.push(...resolveType(graph, fileGraph, ret, argMap, guard));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
if (bindingRef)
|
|
45
|
+
argMap.unbind(bindingRef);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return results;
|
|
49
|
+
}
|
|
50
|
+
case "ParameterOf": {
|
|
51
|
+
const subbed = argMap.lookup(type.fn, type.index);
|
|
52
|
+
if (!subbed)
|
|
53
|
+
return [{ kind: "Unknown" }];
|
|
54
|
+
return resolveType(graph, fileGraph, subbed, argMap, guard);
|
|
55
|
+
}
|
|
56
|
+
case "MemberOf": {
|
|
57
|
+
const objTypes = resolveType(graph, fileGraph, type.obj, argMap, guard);
|
|
58
|
+
const results = [];
|
|
59
|
+
for (const obj of objTypes) {
|
|
60
|
+
if (obj.kind === "Object") {
|
|
61
|
+
if (type.member === DYNAMIC_MEMBER_KEY) {
|
|
62
|
+
for (const v of Object.values(obj.props)) {
|
|
63
|
+
results.push(...resolveType(graph, fileGraph, v, argMap, guard));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const v = obj.props[type.member];
|
|
68
|
+
if (v)
|
|
69
|
+
results.push(...resolveType(graph, fileGraph, v, argMap, guard));
|
|
70
|
+
else
|
|
71
|
+
results.push({ kind: "Unknown" });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else if (obj.kind === "Array") {
|
|
75
|
+
for (const el of obj.elements) {
|
|
76
|
+
results.push(...resolveType(graph, fileGraph, el, argMap, guard));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
results.push({ kind: "Unknown" });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return results;
|
|
84
|
+
}
|
|
85
|
+
case "Union":
|
|
86
|
+
return type.types.flatMap((t) => resolveType(graph, fileGraph, t, argMap, guard));
|
|
87
|
+
case "Object":
|
|
88
|
+
case "Array":
|
|
89
|
+
return [type];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Resolve a type down to its bare Function node(s) without expanding their
|
|
94
|
+
* returns[]. Used by ReturnTypeOf so that args can be bound before the
|
|
95
|
+
* function body is walked.
|
|
96
|
+
*
|
|
97
|
+
* Each entry carries a `bindingRef` — the Reference that `ParameterOf` nodes
|
|
98
|
+
* inside the function use as their `fn` key. For `TypeOf` callees this is the
|
|
99
|
+
* referenced symbol; for nested `ReturnTypeOf` chains it is propagated from
|
|
100
|
+
* the innermost `TypeOf` that started the chain, because `ParameterOf` nodes
|
|
101
|
+
* are authored with that outer ref (e.g. `id()(Foo)` where the inner
|
|
102
|
+
* function's body has `ParameterOf(idRef, 0)` and the outer invocation
|
|
103
|
+
* supplies `Foo`).
|
|
104
|
+
*
|
|
105
|
+
* Follows: TypeOf (via resolveReference), Union fanout, and nested
|
|
106
|
+
* ReturnTypeOf chains. Returns `{fn: Unknown}` when the chain doesn't bottom
|
|
107
|
+
* out at Function.
|
|
108
|
+
*/
|
|
109
|
+
function resolveToFunctions(graph, fileGraph, type, argMap, guard) {
|
|
110
|
+
switch (type.kind) {
|
|
111
|
+
case "Function":
|
|
112
|
+
return [{ fn: type, bindingRef: null }];
|
|
113
|
+
case "TypeOf": {
|
|
114
|
+
const resolved = resolveReference(graph, fileGraph, type.ref, guard);
|
|
115
|
+
// Carry the TypeOf ref through so the caller can bind args to it.
|
|
116
|
+
const inner = resolveToFunctions(graph, fileGraph, resolved, argMap, guard);
|
|
117
|
+
return inner.map((e) => ({ fn: e.fn, bindingRef: e.bindingRef ?? type.ref }));
|
|
118
|
+
}
|
|
119
|
+
case "Union":
|
|
120
|
+
return type.types.flatMap((t) => resolveToFunctions(graph, fileGraph, t, argMap, guard));
|
|
121
|
+
case "ReturnTypeOf": {
|
|
122
|
+
// Recursively resolve the inner callee to Function entries, then walk
|
|
123
|
+
// each function's returns to find Functions one level deeper.
|
|
124
|
+
const innerFns = resolveToFunctions(graph, fileGraph, type.callee, argMap, guard);
|
|
125
|
+
const results = [];
|
|
126
|
+
for (const { fn, bindingRef } of innerFns) {
|
|
127
|
+
if (fn.kind !== "Function") {
|
|
128
|
+
results.push({ fn: { kind: "Unknown" }, bindingRef: null });
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (bindingRef)
|
|
132
|
+
argMap.bind(bindingRef, type.args);
|
|
133
|
+
try {
|
|
134
|
+
for (const ret of fn.returns) {
|
|
135
|
+
const deeper = resolveToFunctions(graph, fileGraph, ret, argMap, guard);
|
|
136
|
+
// Propagate bindingRef so the outer call can bind to the same ref.
|
|
137
|
+
results.push(...deeper.map((e) => ({
|
|
138
|
+
fn: e.fn,
|
|
139
|
+
bindingRef: e.bindingRef ?? bindingRef,
|
|
140
|
+
})));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
if (bindingRef)
|
|
145
|
+
argMap.unbind(bindingRef);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return results;
|
|
149
|
+
}
|
|
150
|
+
default:
|
|
151
|
+
return [{ fn: { kind: "Unknown" }, bindingRef: null }];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=resolve-type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-type.js","sourceRoot":"","sources":["../../src/engine/resolve-type.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAmB,MAAM,sBAAsB,CAAC;AAEzE,mFAAmF;AACnF,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAErC;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,KAAY,EACZ,SAAoB,EACpB,IAAkB,EAClB,MAAmB,EACnB,QAAoB,gBAAgB,EAAE;IAEtC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,KAAK,CAAC;QACX,KAAK,KAAK,CAAC;QACX,KAAK,SAAS;YACZ,OAAO,CAAC,IAAI,CAAC,CAAC;QAEhB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACrE,OAAO,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QAChE,CAAC;QAED,KAAK,UAAU;YACb,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QAEtF,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,oEAAoE;YACpE,yEAAyE;YACzE,kDAAkD;YAClD,wEAAwE;YACxE,uEAAuE;YACvE,sEAAsE;YACtE,MAAM,SAAS,GAAG,kBAAkB,CAClC,KAAK,EACL,SAAS,EACT,IAAI,CAAC,MAAM,EACX,MAAM,EACN,KAAK,CACN,CAAC;YAEF,MAAM,OAAO,GAAmB,EAAE,CAAC;YACnC,KAAK,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,SAAS,EAAE,CAAC;gBAC3C,IAAI,EAAE,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;oBAC3B,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;oBAClC,SAAS;gBACX,CAAC;gBACD,IAAI,UAAU;oBAAE,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBACnD,IAAI,CAAC;oBACH,KAAK,MAAM,GAAG,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;wBAC7B,OAAO,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;oBACrE,CAAC;gBACH,CAAC;wBAAS,CAAC;oBACT,IAAI,UAAU;wBAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAClD,IAAI,CAAC,MAAM;gBAAE,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;YAC1C,OAAO,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QAC9D,CAAC;QAED,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;YACxE,MAAM,OAAO,GAAmB,EAAE,CAAC;YACnC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC3B,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC1B,IAAI,IAAI,CAAC,MAAM,KAAK,kBAAkB,EAAE,CAAC;wBACvC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;4BACzC,OAAO,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;wBACnE,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;wBACjC,IAAI,CAAC;4BAAE,OAAO,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;;4BACnE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;oBACzC,CAAC;gBACH,CAAC;qBAAM,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAChC,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;wBAC9B,OAAO,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;oBACpE,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,KAAK,OAAO;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QAEpF,KAAK,QAAQ,CAAC;QACd,KAAK,OAAO;YACV,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,SAAS,kBAAkB,CACzB,KAAY,EACZ,SAAoB,EACpB,IAAkB,EAClB,MAAmB,EACnB,KAAiB;IAEjB,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,UAAU;YACb,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1C,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACrE,kEAAkE;YAClE,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;YAC5E,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAChF,CAAC;QAED,KAAK,OAAO;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9B,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CACvD,CAAC;QAEJ,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,sEAAsE;YACtE,8DAA8D;YAC9D,MAAM,QAAQ,GAAG,kBAAkB,CACjC,KAAK,EACL,SAAS,EACT,IAAI,CAAC,MAAM,EACX,MAAM,EACN,KAAK,CACN,CAAC;YACF,MAAM,OAAO,GAAc,EAAE,CAAC;YAC9B,KAAK,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAC1C,IAAI,EAAE,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;oBAC3B,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;oBAC5D,SAAS;gBACX,CAAC;gBACD,IAAI,UAAU;oBAAE,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBACnD,IAAI,CAAC;oBACH,KAAK,MAAM,GAAG,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;wBAC7B,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;wBACxE,mEAAmE;wBACnE,OAAO,CAAC,IAAI,CACV,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;4BACpB,EAAE,EAAE,CAAC,CAAC,EAAE;4BACR,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,UAAU;yBACvC,CAAC,CAAC,CACJ,CAAC;oBACJ,CAAC;gBACH,CAAC;wBAAS,CAAC;oBACT,IAAI,UAAU;wBAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED;YACE,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type { Reference, ScopeId } from "./types/reference.js";
|
|
2
|
+
export { MODULE_SCOPE } from "./types/reference.js";
|
|
3
|
+
export type { InferredType } from "./types/inferred-type.js";
|
|
4
|
+
export type { BindingDecl, ExportRecord, FileGraph, Graph, ImportRecord, JsxUsage, } from "./types/file-graph.js";
|
|
5
|
+
export { createGraphBuilder } from "./builder.js";
|
|
6
|
+
export type { GraphBuilder, FileBuilder, CreateGraphBuilderOptions } from "./builder.js";
|
|
7
|
+
export { resolveType, DYNAMIC_MEMBER_KEY } from "./engine/resolve-type.js";
|
|
8
|
+
export { createArgumentMap } from "./engine/argument-map.js";
|
|
9
|
+
export type { ArgumentMap } from "./engine/argument-map.js";
|
|
10
|
+
export { resolve } from "./engine/index.js";
|
|
11
|
+
export type { ResolvedGraph, EngineOccurrence } from "./engine/index.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Public API surface for @component-compass/reference-graph.
|
|
2
|
+
// Types and builders re-exported below as they're implemented.
|
|
3
|
+
export { MODULE_SCOPE } from "./types/reference.js";
|
|
4
|
+
export { createGraphBuilder } from "./builder.js";
|
|
5
|
+
export { resolveType, DYNAMIC_MEMBER_KEY } from "./engine/resolve-type.js";
|
|
6
|
+
export { createArgumentMap } from "./engine/argument-map.js";
|
|
7
|
+
export { resolve } from "./engine/index.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,+DAA+D;AAG/D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAWpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGlD,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { ResolveImport } from "@component-compass/plugin-core";
|
|
2
|
+
import type { InferredType } from "./inferred-type.js";
|
|
3
|
+
import type { Reference, ScopeId } from "./reference.js";
|
|
4
|
+
/** A binding declared in a file (variable, function, class, import alias). */
|
|
5
|
+
export type BindingDecl = {
|
|
6
|
+
scope: ScopeId;
|
|
7
|
+
symbol: string;
|
|
8
|
+
value: InferredType;
|
|
9
|
+
loc: {
|
|
10
|
+
line: number;
|
|
11
|
+
column: number;
|
|
12
|
+
};
|
|
13
|
+
isExported: boolean;
|
|
14
|
+
/** When `export { local as exported }`, the public name differs from the local. */
|
|
15
|
+
exportedAs?: string;
|
|
16
|
+
};
|
|
17
|
+
export type ImportRecord = {
|
|
18
|
+
specifier: string;
|
|
19
|
+
/** `"default"` | exported name | `"*"` (namespace). */
|
|
20
|
+
imported: string;
|
|
21
|
+
local: string;
|
|
22
|
+
scope: ScopeId;
|
|
23
|
+
loc: {
|
|
24
|
+
line: number;
|
|
25
|
+
column: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export type ExportRecord = {
|
|
29
|
+
kind: "named";
|
|
30
|
+
exportedAs: string;
|
|
31
|
+
local: string;
|
|
32
|
+
} | {
|
|
33
|
+
kind: "named";
|
|
34
|
+
exportedAs: string;
|
|
35
|
+
from: string;
|
|
36
|
+
fromImported: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: "star";
|
|
39
|
+
from: string;
|
|
40
|
+
} | {
|
|
41
|
+
kind: "default";
|
|
42
|
+
local: string;
|
|
43
|
+
};
|
|
44
|
+
/** A JSX element opening — becomes one or more Occurrences post-resolution. */
|
|
45
|
+
export type JsxUsage = {
|
|
46
|
+
ref: Reference;
|
|
47
|
+
loc: {
|
|
48
|
+
line: number;
|
|
49
|
+
column: number;
|
|
50
|
+
};
|
|
51
|
+
/** Per-occurrence prop usage; existing PropUsage shape from plugin-core. */
|
|
52
|
+
props: unknown[];
|
|
53
|
+
};
|
|
54
|
+
export type FileGraph = {
|
|
55
|
+
/** Repo-relative POSIX path. */
|
|
56
|
+
filePath: string;
|
|
57
|
+
scopes: Map<ScopeId, {
|
|
58
|
+
parent: ScopeId | null;
|
|
59
|
+
}>;
|
|
60
|
+
/** Keyed by `${scopeId}::${symbol}` for O(1) scope-aware lookup. */
|
|
61
|
+
declarations: Map<string, BindingDecl>;
|
|
62
|
+
imports: ImportRecord[];
|
|
63
|
+
exports: ExportRecord[];
|
|
64
|
+
jsxUsages: JsxUsage[];
|
|
65
|
+
/** Per-JSX-usage owner attribution. usageIdx aligns with jsxUsages[i]. */
|
|
66
|
+
ownership: Array<{
|
|
67
|
+
usageIdx: number;
|
|
68
|
+
ownerSymbolRef: Reference | null;
|
|
69
|
+
}>;
|
|
70
|
+
};
|
|
71
|
+
export type Graph = {
|
|
72
|
+
files: Map<string, FileGraph>;
|
|
73
|
+
moduleResolver: ResolveImport;
|
|
74
|
+
/**
|
|
75
|
+
* Optional function that normalises an absolute path returned by
|
|
76
|
+
* `moduleResolver` into the repo-relative POSIX key used by `files`.
|
|
77
|
+
* When provided, enables cross-file resolution for relative-specifier
|
|
78
|
+
* imports where `moduleResolver` returns absolute paths.
|
|
79
|
+
*/
|
|
80
|
+
resolveToGraphKey?: (absPath: string) => string | null;
|
|
81
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-graph.js","sourceRoot":"","sources":["../../src/types/file-graph.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Reference } from "./reference.js";
|
|
2
|
+
/**
|
|
3
|
+
* Typed value-flow algebra. Every binding's value is described by an
|
|
4
|
+
* InferredType expression. The resolution engine walks these expressions
|
|
5
|
+
* across module boundaries, threading concrete component identities
|
|
6
|
+
* through arbitrary call chains.
|
|
7
|
+
*
|
|
8
|
+
* 11 variants — adapted from Omlet's analyzer. See spec §5.
|
|
9
|
+
*/
|
|
10
|
+
export type InferredType = {
|
|
11
|
+
kind: "TypeOf";
|
|
12
|
+
ref: Reference;
|
|
13
|
+
} | {
|
|
14
|
+
kind: "Function";
|
|
15
|
+
returns: InferredType[];
|
|
16
|
+
} | {
|
|
17
|
+
kind: "ReturnTypeOf";
|
|
18
|
+
callee: InferredType;
|
|
19
|
+
args: InferredType[];
|
|
20
|
+
} | {
|
|
21
|
+
kind: "ParameterOf";
|
|
22
|
+
fn: Reference;
|
|
23
|
+
index: number;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "MemberOf";
|
|
26
|
+
obj: InferredType;
|
|
27
|
+
member: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "Union";
|
|
30
|
+
types: InferredType[];
|
|
31
|
+
} | {
|
|
32
|
+
kind: "Object";
|
|
33
|
+
props: Record<string, InferredType>;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "Array";
|
|
36
|
+
elements: InferredType[];
|
|
37
|
+
} | {
|
|
38
|
+
kind: "JSX";
|
|
39
|
+
} | {
|
|
40
|
+
kind: "Str";
|
|
41
|
+
value: string;
|
|
42
|
+
} | {
|
|
43
|
+
kind: "Unknown";
|
|
44
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inferred-type.js","sourceRoot":"","sources":["../../src/types/inferred-type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A scope id is opaque per-FileGraph. Sequential ints assigned by
|
|
3
|
+
* GraphBuilder.pushScope(); module scope is always 0.
|
|
4
|
+
*/
|
|
5
|
+
export type ScopeId = number;
|
|
6
|
+
export declare const MODULE_SCOPE: ScopeId;
|
|
7
|
+
/**
|
|
8
|
+
* A Reference is what a parser emits when it sees an identifier in code.
|
|
9
|
+
* Captures the identifier as written, the scope it resolves in, and any
|
|
10
|
+
* member access chain (`<Foo.Bar.Baz />` produces memberChain ["Bar", "Baz"]).
|
|
11
|
+
*/
|
|
12
|
+
export type Reference = {
|
|
13
|
+
symbol: string;
|
|
14
|
+
scope: ScopeId;
|
|
15
|
+
memberChain: string[];
|
|
16
|
+
loc: {
|
|
17
|
+
line: number;
|
|
18
|
+
column: number;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../../src/types/reference.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,YAAY,GAAY,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@component-compass/reference-graph",
|
|
3
|
+
"version": "0.0.0-pr-114-393daf6-20260518195554",
|
|
4
|
+
"description": "Project-wide reference graph + cross-module resolution engine for component-compass parsers.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.json",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"lint": "biome lint src tests",
|
|
24
|
+
"clean": "rm -rf dist .turbo"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@component-compass/plugin-core": "workspace:^"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^24.0.0",
|
|
31
|
+
"typescript": "^5.9.0",
|
|
32
|
+
"vitest": "^4.0.0"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=24"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
}
|
|
40
|
+
}
|