@component-compass/reference-graph 0.1.24 → 0.1.26
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/engine/binding.d.ts +96 -0
- package/dist/engine/binding.js +405 -0
- package/dist/engine/binding.js.map +1 -0
- package/dist/engine/component-shape.d.ts +26 -2
- package/dist/engine/component-shape.js +74 -11
- package/dist/engine/component-shape.js.map +1 -1
- package/dist/engine/denotation.d.ts +7 -0
- package/dist/engine/denotation.js +15 -0
- package/dist/engine/denotation.js.map +1 -1
- package/dist/engine/helper-callers.d.ts +0 -7
- package/dist/engine/helper-callers.js +2 -23
- package/dist/engine/helper-callers.js.map +1 -1
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/index.js +259 -308
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/member-identity.d.ts +7 -19
- package/dist/engine/member-identity.js +13 -19
- package/dist/engine/member-identity.js.map +1 -1
- package/dist/engine/re-export-chain.d.ts +1 -1
- package/dist/engine/re-export-chain.js +6 -6
- package/dist/engine/re-export-chain.js.map +1 -1
- package/dist/engine/registry.d.ts +52 -13
- package/dist/engine/registry.js +73 -58
- package/dist/engine/registry.js.map +1 -1
- package/dist/engine/resolve-reference.d.ts +2 -21
- package/dist/engine/resolve-reference.js +4 -178
- package/dist/engine/resolve-reference.js.map +1 -1
- package/dist/engine/resolve-type.d.ts +7 -7
- package/dist/engine/resolve-type.js +23 -29
- package/dist/engine/resolve-type.js.map +1 -1
- package/dist/engine/wrapper-folding.d.ts +18 -22
- package/dist/engine/wrapper-folding.js +147 -282
- package/dist/engine/wrapper-folding.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { resolveType, resolveToFunctions, resolveDynamicImportTarget, DYNAMIC_MEMBER_KEY } from "./resolve-type.js";
|
|
2
2
|
import { argumentRefKey, boundArgument } from "./argument-map.js";
|
|
3
3
|
import { createCycleGuard } from "./cycle-detection.js";
|
|
4
|
-
import {
|
|
4
|
+
import { resolveReference } from "./resolve-reference.js";
|
|
5
|
+
import { bindingIdentity, pinUnparsed, resolveBinding, resolveModuleExport } from "./binding.js";
|
|
5
6
|
import { packageNameFromSpecifier } from "./specifier.js";
|
|
6
|
-
import {
|
|
7
|
-
import { unparsedMemberDefinition, effectiveExportName, residualMemberChain, compoundExportName } from "./member-identity.js";
|
|
8
|
-
import { evalKind, isImportBackedLeaf } from "./component-shape.js";
|
|
7
|
+
import { containsDynamicImport, evalKind, isImportBackedLeaf, nonComponentProduct } from "./component-shape.js";
|
|
9
8
|
import { HOOK_NAME } from "./host-element.js";
|
|
10
9
|
import { assertNever } from "./assert-never.js";
|
|
11
|
-
import { creditedTerminals, matchDenotation } from "./denotation.js";
|
|
12
|
-
import { libraryExportFor } from "./library-stubs.js";
|
|
10
|
+
import { creditedTerminals, isCallable, matchDenotation } from "./denotation.js";
|
|
13
11
|
/** True when a `ReturnTypeOf`'s callee is a data-method render
|
|
14
12
|
* call (`items.map(render)`) rather than a wrapper taking a component as a
|
|
15
13
|
* prop — the exact structural condition `component-shape.ts`'s rule (ii)
|
|
@@ -19,6 +17,49 @@ import { libraryExportFor } from "./library-stubs.js";
|
|
|
19
17
|
function isDataMethodRenderCall(type, graph, fileGraph, guard) {
|
|
20
18
|
return type.callee.kind === "MemberOf" && !isImportBackedLeaf(type.callee, graph, fileGraph, guard);
|
|
21
19
|
}
|
|
20
|
+
/** True when a value is a loader: a function whose body holds an `import()`,
|
|
21
|
+
* inline, or reached from a reference through a chain of aliases, or held by
|
|
22
|
+
* a static member of an object literal (by every member, for a dynamic one)
|
|
23
|
+
* that the value names directly or through such a chain. Each reference
|
|
24
|
+
* resolves in its own file. Anything else, a `lazy()` holder or a wrapper
|
|
25
|
+
* product included, is not. */
|
|
26
|
+
function isLoader(value, graph, fileGraph, guard) {
|
|
27
|
+
if (value.kind === "Function")
|
|
28
|
+
return containsDynamicImport(value, { graph, fileGraph });
|
|
29
|
+
if (value.kind !== "TypeOf" && value.kind !== "MemberOf")
|
|
30
|
+
return false;
|
|
31
|
+
if (guard.pushNode(value) === "cycle")
|
|
32
|
+
return false;
|
|
33
|
+
try {
|
|
34
|
+
if (value.kind === "TypeOf")
|
|
35
|
+
return isLoader(resolveReference(graph, fileGraph, value.ref, guard), graph, fileGraph, guard);
|
|
36
|
+
const holder = objectLiteralOf(value.obj, graph, fileGraph, guard);
|
|
37
|
+
if (holder === null)
|
|
38
|
+
return false;
|
|
39
|
+
if (value.member !== DYNAMIC_MEMBER_KEY) {
|
|
40
|
+
const held = holder.props[value.member];
|
|
41
|
+
return held !== undefined && isLoader(held, graph, fileGraph, guard);
|
|
42
|
+
}
|
|
43
|
+
const all = Object.values(holder.props);
|
|
44
|
+
return all.length > 0 && all.every((v) => isLoader(v, graph, fileGraph, guard));
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
guard.popNode(value);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** The object literal a value is, directly or through a chain of aliases. */
|
|
51
|
+
function objectLiteralOf(value, graph, fileGraph, guard) {
|
|
52
|
+
if (value.kind === "Object")
|
|
53
|
+
return value;
|
|
54
|
+
if (value.kind !== "TypeOf" || guard.pushNode(value) === "cycle")
|
|
55
|
+
return null;
|
|
56
|
+
try {
|
|
57
|
+
return objectLiteralOf(resolveReference(graph, fileGraph, value.ref, guard), graph, fileGraph, guard);
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
guard.popNode(value);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
22
63
|
/** The denotation of a branch the walk learned nothing about. */
|
|
23
64
|
const INDETERMINATE = { kind: "indeterminate" };
|
|
24
65
|
function withSemantics(t, semantics) {
|
|
@@ -47,6 +88,7 @@ const CAME_TO_NOTHING = {
|
|
|
47
88
|
"late-bound": () => true,
|
|
48
89
|
data: () => false,
|
|
49
90
|
indeterminate: () => true,
|
|
91
|
+
callable: () => false,
|
|
50
92
|
};
|
|
51
93
|
function cameToNothing(t) {
|
|
52
94
|
return matchDenotation(t, CAME_TO_NOTHING);
|
|
@@ -59,6 +101,7 @@ const IS_LATE_BOUND = {
|
|
|
59
101
|
"late-bound": () => true,
|
|
60
102
|
data: () => false,
|
|
61
103
|
indeterminate: () => false,
|
|
104
|
+
callable: () => false,
|
|
62
105
|
};
|
|
63
106
|
/**
|
|
64
107
|
* Rename a branch that came to nothing, keeping its identity and viaTrail
|
|
@@ -95,6 +138,7 @@ const AS_RETURNED_VALUE = {
|
|
|
95
138
|
"late-bound": () => INDETERMINATE,
|
|
96
139
|
data: (d) => d,
|
|
97
140
|
indeterminate: (d) => d,
|
|
141
|
+
callable: (d) => d,
|
|
98
142
|
};
|
|
99
143
|
function returnedValue(t) {
|
|
100
144
|
const denotation = matchDenotation(t, AS_RETURNED_VALUE);
|
|
@@ -223,8 +267,8 @@ function foldToWrappedArg(inner, via) {
|
|
|
223
267
|
* is seeded at its site), so the two name a binding identically.
|
|
224
268
|
* Never re-derive `{ specifier, import }` for an argument elsewhere.
|
|
225
269
|
*/
|
|
226
|
-
export function argumentProvenance(type, arg, fileGraph) {
|
|
227
|
-
const importRecord = findImportForLastArg(arg, fileGraph);
|
|
270
|
+
export function argumentProvenance(graph, type, arg, fileGraph) {
|
|
271
|
+
const importRecord = findImportForLastArg(graph, arg, fileGraph);
|
|
228
272
|
const resolved = importRecord
|
|
229
273
|
? { specifier: importRecord.specifier, import: importRecord.imported }
|
|
230
274
|
: resolveAnonymousLastArg(arg, fileGraph);
|
|
@@ -236,8 +280,8 @@ export function argumentProvenance(type, arg, fileGraph) {
|
|
|
236
280
|
* the opaque HOC fallback (step 4) so all three paths attribute composition
|
|
237
281
|
* identically; the binding is named through `argumentProvenance`.
|
|
238
282
|
*/
|
|
239
|
-
function buildHocVia(type, lastArg, fileGraph) {
|
|
240
|
-
const { callee, specifier, import: imported } = argumentProvenance(type, lastArg, fileGraph);
|
|
283
|
+
function buildHocVia(graph, type, lastArg, fileGraph) {
|
|
284
|
+
const { callee, specifier, import: imported } = argumentProvenance(graph, type, lastArg, fileGraph);
|
|
241
285
|
return { kind: "hoc-wrapper", hocCallee: callee, specifier, import: imported };
|
|
242
286
|
}
|
|
243
287
|
/**
|
|
@@ -254,7 +298,7 @@ export function foldedArgument(graph, fileGraph, call, jsx, argMap) {
|
|
|
254
298
|
const arg = call.args[index];
|
|
255
299
|
if (arg === undefined || jsx.length === 0)
|
|
256
300
|
return null;
|
|
257
|
-
const via = buildHocVia(call, arg, fileGraph);
|
|
301
|
+
const via = buildHocVia(graph, call, arg, fileGraph);
|
|
258
302
|
return jsx.every((t) => t.viaTrail[0] !== undefined && sameHocVia(t.viaTrail[0], via)) ? { arg, via } : null;
|
|
259
303
|
}
|
|
260
304
|
/** Two `hoc-wrapper` vias naming the same wrapper call and the same binding. */
|
|
@@ -304,14 +348,21 @@ function isPassThroughWrapper(algResult, inner) {
|
|
|
304
348
|
* (pure algebra) and computes identity from the input type's leaf TypeOf
|
|
305
349
|
* when one can be confidently identified.
|
|
306
350
|
*/
|
|
307
|
-
export function walkWithFolding(graph, fileGraph, type, argMap, guard = createCycleGuard(), identityFallback) {
|
|
308
|
-
return atLeastOne(walkInner(graph, fileGraph, type, argMap, guard, identityFallback).map(published));
|
|
351
|
+
export function walkWithFolding(graph, fileGraph, type, argMap, guard = createCycleGuard(), identityFallback, position = "value") {
|
|
352
|
+
return atLeastOne(walkInner(graph, fileGraph, type, argMap, guard, identityFallback, position).map(published));
|
|
309
353
|
}
|
|
310
354
|
/**
|
|
311
355
|
* The walk itself. Returns exactly what each arm produced, empty included:
|
|
312
356
|
* inside the walk an empty result means "this branch contributed nothing",
|
|
313
357
|
* which `walkTypeOf`'s vacuous `every` and `foldToWrappedArg`'s rescue both
|
|
314
358
|
* read. Only the exported boundary above may substitute a terminal for it.
|
|
359
|
+
*
|
|
360
|
+
* `position` says whether `type` is what a tag renders. At a `tag`, a
|
|
361
|
+
* function is one `callable` terminal and its body is not walked; the
|
|
362
|
+
* position carries through the value hops (a reference, a union branch, a
|
|
363
|
+
* static or dynamic member, a call's folded argument, a lazy target, a
|
|
364
|
+
* dispatcher's returns) and nowhere else. In `value` position a function is
|
|
365
|
+
* walked into its returns.
|
|
315
366
|
*/
|
|
316
367
|
function walkInner(graph, fileGraph, type, argMap, guard,
|
|
317
368
|
// The identity `foldTerminals` falls back to when a terminal
|
|
@@ -325,39 +376,44 @@ function walkInner(graph, fileGraph, type, argMap, guard,
|
|
|
325
376
|
// that happens to sit in `foldTerminals`' fallback slot. Per-branch
|
|
326
377
|
// identity from a fanout `source` (Union([TypeOf A, TypeOf B])) is
|
|
327
378
|
// untouched: `source` is checked BEFORE this fallback in `foldTerminals`.
|
|
328
|
-
identityFallback) {
|
|
379
|
+
identityFallback, position) {
|
|
329
380
|
const fallback = identityFallback ?? type;
|
|
330
381
|
switch (type.kind) {
|
|
331
382
|
case "ReturnTypeOf":
|
|
332
|
-
return walkReturnTypeOf(graph, fileGraph, type, argMap, guard);
|
|
383
|
+
return walkReturnTypeOf(graph, fileGraph, type, argMap, guard, position);
|
|
333
384
|
case "MemberOf":
|
|
334
385
|
if (type.member === DYNAMIC_MEMBER_KEY) {
|
|
335
|
-
return walkDynamicMember(graph, fileGraph, type, argMap, guard);
|
|
386
|
+
return walkDynamicMember(graph, fileGraph, type, argMap, guard, position);
|
|
336
387
|
}
|
|
337
|
-
return walkStaticMember(graph, fileGraph, type, argMap, guard, fallback);
|
|
388
|
+
return walkStaticMember(graph, fileGraph, type, argMap, guard, fallback, position);
|
|
338
389
|
case "Function":
|
|
339
|
-
//
|
|
390
|
+
// At a tag the function is what JSX renders: one `callable` terminal
|
|
391
|
+
// with no identity of its own, and the body is not walked.
|
|
392
|
+
//
|
|
393
|
+
// In value position a component's own returns can contain a nested
|
|
340
394
|
// ReturnTypeOf/MemberOf (`List = ({items}) => items.map(render)`) that
|
|
341
395
|
// needs wrapper-folding's steps (the opaque-callee / dynamic-map
|
|
342
396
|
// handling below), not `resolveType`'s plain algebra — `resolveType`'s
|
|
343
397
|
// own "Function" case recurses via plain `resolveType`, which never
|
|
344
|
-
// re-enters this walk, so a
|
|
345
|
-
//
|
|
398
|
+
// re-enters this walk, so a value resolving to such a Function would
|
|
399
|
+
// silently produce zero terminals.
|
|
346
400
|
// Mirrors `resolveType`'s "Function" case, one level up. Pass THIS
|
|
347
401
|
// Function as the identity fallback for every return — a
|
|
348
402
|
// Function is never TypeOf/DynamicImport, so `deriveIdentity` on it
|
|
349
403
|
// is always null.
|
|
404
|
+
if (position === "tag")
|
|
405
|
+
return [{ denotation: { kind: "callable" }, identity: null, viaTrail: [] }];
|
|
350
406
|
return type.returns
|
|
351
|
-
.flatMap((r) => walkInner(graph, fileGraph, r, argMap, guard, type))
|
|
407
|
+
.flatMap((r) => walkInner(graph, fileGraph, r, argMap, guard, type, "value"))
|
|
352
408
|
.map(returnedValue);
|
|
353
409
|
case "TypeOf":
|
|
354
|
-
return walkTypeOf(graph, fileGraph, type, argMap, guard, fallback);
|
|
410
|
+
return walkTypeOf(graph, fileGraph, type, argMap, guard, fallback, position);
|
|
355
411
|
case "Union":
|
|
356
412
|
// Structural re-entry: each branch walks through the walker so
|
|
357
413
|
// a TypeOf branch reaches `walkTypeOf` and decides its own identity
|
|
358
414
|
// (per-branch attribution) while a bare JSX branch — a lowered
|
|
359
415
|
// ternary/logical render body — derives from the outer fallback.
|
|
360
|
-
return type.types.flatMap((branch) => walkInner(graph, fileGraph, branch, argMap, guard, fallback));
|
|
416
|
+
return type.types.flatMap((branch) => walkInner(graph, fileGraph, branch, argMap, guard, fallback, position));
|
|
361
417
|
case "ParameterOf":
|
|
362
418
|
return walkParameter(graph, fileGraph, type, argMap, guard, fallback);
|
|
363
419
|
case "DynamicImport":
|
|
@@ -420,28 +476,13 @@ export function fileGraphForDynamicImport(graph, di, fallback) {
|
|
|
420
476
|
return graph.files.get(di.originFile) ?? fallback;
|
|
421
477
|
}
|
|
422
478
|
/**
|
|
423
|
-
* The identity
|
|
424
|
-
*
|
|
425
|
-
* `resolvedFile` is the specifier canonicalised through the module resolver, so
|
|
426
|
-
* two spellings of one target — `./x` from one file, `../x` from another —
|
|
427
|
-
* carry the same `resolvedFile` and collapse to a single componentId
|
|
428
|
-
* downstream instead of minting a phantom each. A chain that resolves into the
|
|
429
|
-
* graph (workspace sibling, relative import, or unparsed workspace member)
|
|
430
|
-
* promotes to `local`, hashing to the same id as the local-index seed;
|
|
431
|
-
* everything else stays `imported`.
|
|
479
|
+
* The identity of a lazy target: the binding its specifier's projected export
|
|
480
|
+
* names from the file that contains the `import()`.
|
|
432
481
|
*/
|
|
433
482
|
export function dynamicImportIdentity(graph, fileGraph, di) {
|
|
434
483
|
const origin = fileGraphForDynamicImport(graph, di, fileGraph);
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
return (workspaceSiblingIdentity(graph, origin, di.specifier, importedName) ??
|
|
438
|
-
relativeChainLocalIdentity(graph, origin, di.specifier, importedName) ??
|
|
439
|
-
memberLocalIdentity(graph, origin, di.specifier, importedName) ?? {
|
|
440
|
-
kind: "imported",
|
|
441
|
-
specifier: di.specifier,
|
|
442
|
-
imported: importedName,
|
|
443
|
-
resolvedFile,
|
|
444
|
-
});
|
|
484
|
+
const binding = resolveModuleExport(graph, origin.filePath, di.specifier, di.projection[0] ?? "default", []);
|
|
485
|
+
return bindingIdentity(pinUnparsed(graph, binding));
|
|
445
486
|
}
|
|
446
487
|
/**
|
|
447
488
|
* Structural re-entry for a reference. Resolves ONE
|
|
@@ -454,9 +495,13 @@ export function dynamicImportIdentity(graph, fileGraph, di) {
|
|
|
454
495
|
* Identity: a terminal that comes back with no identity of its own is
|
|
455
496
|
* stamped with THIS reference's identity only when the reference names a
|
|
456
497
|
* component-shaped value — `evalKind === "component"`, the one component-
|
|
457
|
-
* shape seam, called not re-derived
|
|
458
|
-
*
|
|
459
|
-
*
|
|
498
|
+
* shape seam, called not re-derived — or, at a tag, when the walk came back
|
|
499
|
+
* with an identity-less `callable`: a reference to a function, or to a
|
|
500
|
+
* wrapper call over an anonymous one, names what the tag renders, whatever
|
|
501
|
+
* it returns. A reference to a JSX value (`return priceElement`) or to a
|
|
502
|
+
* parameter binding stays null so the outer fallback wins, by construction
|
|
503
|
+
* rather than by special case. A stamp naming a declaration with no member
|
|
504
|
+
* chain carries that declaration (`bindingIdentity`).
|
|
460
505
|
*
|
|
461
506
|
* An import the graph cannot see (`resolved` is Unknown) is NOT re-entered:
|
|
462
507
|
* it is the identity-bearing leaf `foldLeaf` synthesises from, and
|
|
@@ -470,7 +515,7 @@ export function dynamicImportIdentity(graph, fileGraph, di) {
|
|
|
470
515
|
* Cycle guard: mirrors `resolveType`'s node guard. `const A = B; const B = A`
|
|
471
516
|
* is legal JS and would otherwise re-enter forever.
|
|
472
517
|
*/
|
|
473
|
-
function walkTypeOf(graph, fileGraph, type, argMap, guard, fallback) {
|
|
518
|
+
function walkTypeOf(graph, fileGraph, type, argMap, guard, fallback, position) {
|
|
474
519
|
if (guard.pushNode(type) === "cycle") {
|
|
475
520
|
return [indeterminateTerminal()];
|
|
476
521
|
}
|
|
@@ -486,13 +531,14 @@ function walkTypeOf(graph, fileGraph, type, argMap, guard, fallback) {
|
|
|
486
531
|
return foldLeaf(graph, fileGraph, type, argMap, guard, fallback);
|
|
487
532
|
}
|
|
488
533
|
const innerGraph = resolved.kind === "Function" ? fileGraphForFunction(graph, fileGraph, resolved) : fileGraph;
|
|
489
|
-
const inner = walkInner(graph, innerGraph, resolved, argMap, guard, fallback);
|
|
534
|
+
const inner = walkInner(graph, innerGraph, resolved, argMap, guard, fallback, position);
|
|
490
535
|
if (inner.every((t) => t.identity !== null))
|
|
491
536
|
return inner;
|
|
492
|
-
const
|
|
537
|
+
const derived = (position === "tag" && inner.some((t) => t.identity === null && isCallable(t))) ||
|
|
538
|
+
(resolved.kind !== "ParameterOf" && evalKind(resolved, graph, innerGraph, argMap) === "component")
|
|
493
539
|
? deriveIdentity(type, fileGraph, graph)
|
|
494
540
|
: null;
|
|
495
|
-
const stamp =
|
|
541
|
+
const stamp = derived ?? deriveIdentity(fallback, fileGraph, graph);
|
|
496
542
|
// Carries the product mark: a reference to a context IS that context.
|
|
497
543
|
return inner.map((t) => t.identity === null ? { denotation: t.denotation, viaTrail: t.viaTrail, identity: stamp, semantics: t.semantics } : t);
|
|
498
544
|
}
|
|
@@ -514,7 +560,7 @@ function walkTypeOf(graph, fileGraph, type, argMap, guard, fallback) {
|
|
|
514
560
|
* re-enters this arm forever without it — `resolveType` pops every node it
|
|
515
561
|
* pushes, so nothing on such a cycle stays on the guard's path otherwise.
|
|
516
562
|
*/
|
|
517
|
-
function walkStaticMember(graph, fileGraph, type, argMap, guard, fallback) {
|
|
563
|
+
function walkStaticMember(graph, fileGraph, type, argMap, guard, fallback, position) {
|
|
518
564
|
if (guard.pushNode(type) === "cycle") {
|
|
519
565
|
return [indeterminateTerminal()];
|
|
520
566
|
}
|
|
@@ -537,7 +583,7 @@ function walkStaticMember(graph, fileGraph, type, argMap, guard, fallback) {
|
|
|
537
583
|
// and any member of a non-component product is that product. ONE walk
|
|
538
584
|
// answers both, and only once the member came to nothing, so a member
|
|
539
585
|
// that resolved is never re-walked.
|
|
540
|
-
const object = walkInner(graph, fileGraph, type.obj, argMap, guard);
|
|
586
|
+
const object = walkInner(graph, fileGraph, type.obj, argMap, guard, undefined, "value");
|
|
541
587
|
const semantics = markedProduct(object);
|
|
542
588
|
if (semantics !== null)
|
|
543
589
|
return leaf.map((t) => withSemantics(t, semantics));
|
|
@@ -548,7 +594,7 @@ function walkStaticMember(graph, fileGraph, type, argMap, guard, fallback) {
|
|
|
548
594
|
const value = obj.props[type.member];
|
|
549
595
|
if (value === undefined)
|
|
550
596
|
continue;
|
|
551
|
-
out.push(...walkInner(graph, fileGraph, value, argMap, guard, fallback));
|
|
597
|
+
out.push(...walkInner(graph, fileGraph, value, argMap, guard, fallback, position));
|
|
552
598
|
}
|
|
553
599
|
return out.length > 0 ? out : [indeterminateTerminal()];
|
|
554
600
|
}
|
|
@@ -557,59 +603,33 @@ function walkStaticMember(graph, fileGraph, type, argMap, guard, fallback) {
|
|
|
557
603
|
}
|
|
558
604
|
}
|
|
559
605
|
/**
|
|
560
|
-
* A call.
|
|
561
|
-
*
|
|
562
|
-
*
|
|
606
|
+
* A call. A call of an export the stub table names a non-component product
|
|
607
|
+
* IS that product, before any fold runs: its arguments are values the product
|
|
608
|
+
* holds (a context's default), never a wrapped component, so none of them is
|
|
609
|
+
* walked or credited.
|
|
610
|
+
*
|
|
611
|
+
* Every other call runs the folding rules first (`foldCall`). The call's own
|
|
612
|
+
* shape gets a name only when all of them declined: no argument credited and no
|
|
613
|
+
* algebra result. A call of a hook the graph cannot see returns a value
|
|
563
614
|
* bound at render time by the hook's own implementation, so it is late-bound
|
|
564
615
|
* rather than unknown. The predicate is React's `HOOK_NAME` over a callee
|
|
565
616
|
* `isImportBackedLeaf` says the graph cannot resolve; it runs after the folds,
|
|
566
617
|
* so `const X = useStyled(Base)` keeps the credit its fold gave it.
|
|
567
618
|
*
|
|
568
|
-
* A call of an export the stub table names a non-component product carries
|
|
569
|
-
* that product's mark on the terminals the folds produced, and only when the
|
|
570
|
-
* folds credited nothing.
|
|
571
|
-
*
|
|
572
619
|
* ORDER IS LOAD-BEARING: `returnedValue` runs on the fold's results before
|
|
573
620
|
* `late-bound{hook-result}` is minted for the call itself.
|
|
574
621
|
*/
|
|
575
|
-
function walkReturnTypeOf(graph, fileGraph, type, argMap, guard) {
|
|
576
|
-
const
|
|
577
|
-
if (
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
return returns.map((t) => withSemantics(t, semantics));
|
|
581
|
-
}
|
|
622
|
+
function walkReturnTypeOf(graph, fileGraph, type, argMap, guard, position) {
|
|
623
|
+
const semantics = nonComponentProduct(graph, fileGraph, type.callee, guard);
|
|
624
|
+
if (semantics !== null)
|
|
625
|
+
return [withSemantics(indeterminateTerminal(), semantics)];
|
|
626
|
+
const returns = foldCall(graph, fileGraph, type, argMap, guard, position).map(returnedValue);
|
|
582
627
|
if (!(returns.length > 0 && returns.every(cameToNothing)))
|
|
583
628
|
return returns;
|
|
584
629
|
const unseenHook = HOOK_NAME.test(deriveHocCallee(type.callee)) && isImportBackedLeaf(type.callee, graph, fileGraph, guard);
|
|
585
630
|
return unseenHook ? returns.map(asLateBound("hook-result")) : returns;
|
|
586
631
|
}
|
|
587
|
-
|
|
588
|
-
* The semantics of the non-component value a call produces: the stub table's
|
|
589
|
-
* entry for the callee's export, when the callee is an import the graph cannot
|
|
590
|
-
* see (`isImportBackedLeaf`, the same predicate the unseen-hook rule uses).
|
|
591
|
-
* Null for every other call.
|
|
592
|
-
*
|
|
593
|
-
* The callee's spelling is read through `libraryExportFor`, the one table
|
|
594
|
-
* `libraryStubFor` reads: a reference (a named import, or a default /
|
|
595
|
-
* namespace import carrying the member on the ref) or a member access on one
|
|
596
|
-
* (`React.createContext`).
|
|
597
|
-
*/
|
|
598
|
-
function nonComponentProduct(graph, fileGraph, callee, guard) {
|
|
599
|
-
const ref = callee.kind === "TypeOf"
|
|
600
|
-
? callee.ref
|
|
601
|
-
: callee.kind === "MemberOf" && callee.obj.kind === "TypeOf"
|
|
602
|
-
? { ...callee.obj.ref, memberChain: [callee.member] }
|
|
603
|
-
: null;
|
|
604
|
-
if (ref === null)
|
|
605
|
-
return null;
|
|
606
|
-
const imp = fileGraphForRef(graph, ref, fileGraph).importsByLocal.get(ref.symbol);
|
|
607
|
-
const entry = imp === undefined ? null : libraryExportFor(imp, ref);
|
|
608
|
-
if (entry === null || entry.kind !== "non-component-product")
|
|
609
|
-
return null;
|
|
610
|
-
return isImportBackedLeaf(callee, graph, fileGraph, guard) ? entry.semantics : null;
|
|
611
|
-
}
|
|
612
|
-
function foldCall(graph, fileGraph, type, argMap, guard) {
|
|
632
|
+
function foldCall(graph, fileGraph, type, argMap, guard, position) {
|
|
613
633
|
// (1) lazy-import shape: any arg's subtree contains a DynamicImport
|
|
614
634
|
// (with one-ref-deep peek into local-file bindings to catch the async-await form).
|
|
615
635
|
const lazyShape = findLazyImportArg(type.args, fileGraph);
|
|
@@ -628,10 +648,10 @@ function foldCall(graph, fileGraph, type, argMap, guard) {
|
|
|
628
648
|
}
|
|
629
649
|
let inner;
|
|
630
650
|
try {
|
|
631
|
-
const target = resolveDynamicImportTarget(graph, fileGraph, syntheticDI
|
|
651
|
+
const target = resolveDynamicImportTarget(graph, fileGraph, syntheticDI);
|
|
632
652
|
inner = target
|
|
633
|
-
? walkInner(graph, target.targetFileGraph, target.value, argMap, guard)
|
|
634
|
-
: walkInner(graph, fileGraph, syntheticDI, argMap, guard);
|
|
653
|
+
? walkInner(graph, target.targetFileGraph, target.value, argMap, guard, undefined, position)
|
|
654
|
+
: walkInner(graph, fileGraph, syntheticDI, argMap, guard, undefined, position);
|
|
635
655
|
}
|
|
636
656
|
finally {
|
|
637
657
|
guard.pop(syntheticDI.originFile, guardKey);
|
|
@@ -670,7 +690,7 @@ function foldCall(graph, fileGraph, type, argMap, guard) {
|
|
|
670
690
|
// walkDynamicMember rule fire and surfaces the dynamic-map via in the chain
|
|
671
691
|
// — without it, cross-module dispatcher patterns would lose the via even
|
|
672
692
|
// though identity attribution worked.
|
|
673
|
-
const dispatcherResult = walkDispatcherReturns(graph, fileGraph, type, argMap, guard);
|
|
693
|
+
const dispatcherResult = walkDispatcherReturns(graph, fileGraph, type, argMap, guard, position);
|
|
674
694
|
if (dispatcherResult)
|
|
675
695
|
return dispatcherResult;
|
|
676
696
|
// (2b) Structural pass-through. When every Function
|
|
@@ -686,8 +706,8 @@ function foldCall(graph, fileGraph, type, argMap, guard) {
|
|
|
686
706
|
if (passThroughIndex !== null) {
|
|
687
707
|
const wrapped = type.args[passThroughIndex];
|
|
688
708
|
if (wrapped !== undefined) {
|
|
689
|
-
const inner = walkInner(graph, fileGraph, wrapped, argMap, guard);
|
|
690
|
-
return foldToWrappedArg(inner, buildHocVia(type, wrapped, fileGraph));
|
|
709
|
+
const inner = walkInner(graph, fileGraph, wrapped, argMap, guard, undefined, position);
|
|
710
|
+
return foldToWrappedArg(inner, buildHocVia(graph, type, wrapped, fileGraph));
|
|
691
711
|
}
|
|
692
712
|
}
|
|
693
713
|
// (3) Pure algebra walk. Per-leaf identity uses each terminal's source
|
|
@@ -711,9 +731,9 @@ function foldCall(graph, fileGraph, type, argMap, guard) {
|
|
|
711
731
|
// stands with no via.
|
|
712
732
|
const lastArg = type.args.at(-1);
|
|
713
733
|
if (lastArg !== undefined) {
|
|
714
|
-
const inner = walkInner(graph, fileGraph, lastArg, argMap, guard);
|
|
734
|
+
const inner = walkInner(graph, fileGraph, lastArg, argMap, guard, undefined, position);
|
|
715
735
|
if (isPassThroughWrapper(algResult, inner)) {
|
|
716
|
-
const via = buildHocVia(type, lastArg, fileGraph);
|
|
736
|
+
const via = buildHocVia(graph, type, lastArg, fileGraph);
|
|
717
737
|
return inner
|
|
718
738
|
.filter((t) => !cameToNothing(t))
|
|
719
739
|
.map((t) => ({ denotation: t.denotation, viaTrail: [via, ...t.viaTrail], identity: t.identity }));
|
|
@@ -726,7 +746,11 @@ function foldCall(graph, fileGraph, type, argMap, guard) {
|
|
|
726
746
|
if (lastArg === undefined) {
|
|
727
747
|
return [indeterminateTerminal()];
|
|
728
748
|
}
|
|
729
|
-
|
|
749
|
+
// A data-method callback and a loader holding an `import()` the lazy arm
|
|
750
|
+
// declined are called, not rendered, so they walk in value position.
|
|
751
|
+
const dataMethod = isDataMethodRenderCall(type, graph, fileGraph, guard);
|
|
752
|
+
const called = dataMethod || isLoader(lastArg, graph, fileGraph, guard);
|
|
753
|
+
const inner = walkInner(graph, fileGraph, lastArg, argMap, guard, undefined, called ? "value" : position);
|
|
730
754
|
// A data-method render call (`items.map(render)`) is not a
|
|
731
755
|
// wrapper — its result IS the callback's rendered JSX, not a component
|
|
732
756
|
// received as a prop. Return the callback's terminals AS-IS: no
|
|
@@ -734,14 +758,14 @@ function foldCall(graph, fileGraph, type, argMap, guard) {
|
|
|
734
758
|
// (the declaration being walked, e.g. `List`) wins rather than whatever
|
|
735
759
|
// the callback itself happened to resolve to. Import-backed MemberOf
|
|
736
760
|
// callees (`Sentry.withProfiler`) fall through to the fold+hop below.
|
|
737
|
-
if (
|
|
761
|
+
if (dataMethod) {
|
|
738
762
|
const nonUnknown = inner.filter((t) => !cameToNothing(t));
|
|
739
763
|
if (nonUnknown.length > 0) {
|
|
740
764
|
return nonUnknown.map((t) => ({ denotation: t.denotation, viaTrail: t.viaTrail, identity: null }));
|
|
741
765
|
}
|
|
742
766
|
return [indeterminateTerminal()];
|
|
743
767
|
}
|
|
744
|
-
return foldToWrappedArg(inner, buildHocVia(type, lastArg, fileGraph));
|
|
768
|
+
return foldToWrappedArg(inner, buildHocVia(graph, type, lastArg, fileGraph));
|
|
745
769
|
}
|
|
746
770
|
/**
|
|
747
771
|
* Index of the argument an identity-preserving wrapper returns, or null when
|
|
@@ -792,7 +816,7 @@ function passThroughParameterIndex(graph, fileGraph, type, argMap, guard) {
|
|
|
792
816
|
* `enclosingBinding.file`). Returns null when no callee matches the shape so
|
|
793
817
|
* the caller falls through to the pure algebra path.
|
|
794
818
|
*/
|
|
795
|
-
function walkDispatcherReturns(graph, fileGraph, type, argMap, guard) {
|
|
819
|
+
function walkDispatcherReturns(graph, fileGraph, type, argMap, guard, position) {
|
|
796
820
|
const calleeFns = resolveToFunctions(graph, fileGraph, type.callee, argMap, guard);
|
|
797
821
|
const hasDispatcher = calleeFns.some(({ fn }) => fn.kind === "Function" && fn.returns.some(isDynamicMemberReturn));
|
|
798
822
|
if (!hasDispatcher)
|
|
@@ -806,7 +830,7 @@ function walkDispatcherReturns(graph, fileGraph, type, argMap, guard) {
|
|
|
806
830
|
argMap.bind(bindingRef, type.args);
|
|
807
831
|
try {
|
|
808
832
|
for (const ret of fn.returns) {
|
|
809
|
-
folded.push(...walkInner(graph, fnFileGraph, ret, argMap, guard));
|
|
833
|
+
folded.push(...walkInner(graph, fnFileGraph, ret, argMap, guard, undefined, position));
|
|
810
834
|
}
|
|
811
835
|
}
|
|
812
836
|
finally {
|
|
@@ -886,7 +910,7 @@ function findFirstDynamicImport(t, fileGraph, depthBudget) {
|
|
|
886
910
|
* reached through `MAP[k]` re-enters this arm forever without it. No
|
|
887
911
|
* `foldLeaf` path here, so no early pop is needed.
|
|
888
912
|
*/
|
|
889
|
-
function walkDynamicMember(graph, fileGraph, type, argMap, guard) {
|
|
913
|
+
function walkDynamicMember(graph, fileGraph, type, argMap, guard, position) {
|
|
890
914
|
if (guard.pushNode(type) === "cycle") {
|
|
891
915
|
return [indeterminateTerminal()];
|
|
892
916
|
}
|
|
@@ -906,7 +930,7 @@ function walkDynamicMember(graph, fileGraph, type, argMap, guard) {
|
|
|
906
930
|
for (const propValue of Object.values(obj.props)) {
|
|
907
931
|
// Recurse via walkInner so identity is derived from each branch's
|
|
908
932
|
// leaf TypeOf (Foo/Bar resolve to their respective bindings).
|
|
909
|
-
const inner = walkInner(graph, fileGraph, propValue, argMap, guard);
|
|
933
|
+
const inner = walkInner(graph, fileGraph, propValue, argMap, guard, undefined, position);
|
|
910
934
|
const via = { kind: "dynamic-map", mapName, mapLoc };
|
|
911
935
|
for (const t of inner) {
|
|
912
936
|
if (cameToNothing(t))
|
|
@@ -954,16 +978,22 @@ function deriveHocCallee(callee) {
|
|
|
954
978
|
}
|
|
955
979
|
/**
|
|
956
980
|
* Find an import record that the last arg's outermost TypeOf points at.
|
|
957
|
-
* Returns null when the last arg isn't a TypeOf
|
|
981
|
+
* Returns null when the last arg isn't a TypeOf, isn't an imported binding,
|
|
982
|
+
* or binds to a declaration in this file's scope that shadows the import.
|
|
958
983
|
*/
|
|
959
|
-
function findImportForLastArg(lastArg, fileGraph) {
|
|
984
|
+
function findImportForLastArg(graph, lastArg, fileGraph) {
|
|
960
985
|
let cur = lastArg;
|
|
961
986
|
while (cur.kind === "ReturnTypeOf")
|
|
962
987
|
cur = cur.callee;
|
|
963
988
|
if (cur.kind !== "TypeOf")
|
|
964
989
|
return null;
|
|
965
990
|
const imp = fileGraph.importsByLocal.get(cur.ref.symbol);
|
|
966
|
-
|
|
991
|
+
if (!imp)
|
|
992
|
+
return null;
|
|
993
|
+
const binding = resolveBinding(graph, fileGraph, cur.ref);
|
|
994
|
+
if (binding.kind === "declaration" && binding.inScope && binding.file === fileGraph.filePath)
|
|
995
|
+
return null;
|
|
996
|
+
return { specifier: imp.specifier, imported: imp.imported };
|
|
967
997
|
}
|
|
968
998
|
/**
|
|
969
999
|
* Resolve an anonymous lastArg (no leaf TypeOf, no import record) to a
|
|
@@ -1030,185 +1060,20 @@ function typeContainsRef(haystack, needle) {
|
|
|
1030
1060
|
}
|
|
1031
1061
|
}
|
|
1032
1062
|
/**
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1035
|
-
*
|
|
1036
|
-
* callers fall back to the raw specifier in those cases.
|
|
1037
|
-
*
|
|
1038
|
-
* When `imported` is provided, follows re-export chains (both
|
|
1039
|
-
* `{kind: "named", from, fromImported}` and `{kind: "star", from}`) to the
|
|
1040
|
-
* canonical source file via `followReExportChain` (star re-exports are
|
|
1041
|
-
* first-wins). Mirrors what `resolveExport` in resolve-reference.ts
|
|
1042
|
-
* does for value-flow purposes,
|
|
1043
|
-
* applied here at identity-stamping time. So `import { X } from './barrel'`
|
|
1044
|
-
* where `./barrel` re-exports X from `./source` attributes the component's
|
|
1045
|
-
* identity to `./source.tsx`, not `./barrel.tsx`.
|
|
1046
|
-
*
|
|
1047
|
-
* Used by `deriveIdentity` so `TerminalIdentity.resolvedFile` carries the
|
|
1048
|
-
* canonical repo-relative path. Downstream `componentIdFromIdentity` uses
|
|
1049
|
-
* that canonical path so `'./page'` and `'../page'` from different callers
|
|
1050
|
-
* collapse to the same identity.
|
|
1051
|
-
*/
|
|
1052
|
-
function resolveImportedFile(graph, fileGraph, specifier, imported) {
|
|
1053
|
-
const abs = graph.moduleResolver(fileGraph.filePath, specifier);
|
|
1054
|
-
if (!abs)
|
|
1055
|
-
return null;
|
|
1056
|
-
const key = graph.resolveToGraphKey ? graph.resolveToGraphKey(abs) : abs;
|
|
1057
|
-
if (!key || !imported)
|
|
1058
|
-
return key;
|
|
1059
|
-
return followReExportChain(graph, key, imported)?.file ?? key;
|
|
1060
|
-
}
|
|
1061
|
-
/**
|
|
1062
|
-
* When a relative-spec import resolves into the parsed graph (possibly via a
|
|
1063
|
-
* re-export chain) AND the canonical source file has a local declaration for
|
|
1064
|
-
* the exported name, promote the identity to `kind: "local"` directly. This
|
|
1065
|
-
* matches what the local-index seeds emit (keyed on `{filePath, exportName}`)
|
|
1066
|
-
* so the engine occurrence hashes to the same componentId as the seed —
|
|
1067
|
-
* preventing the barrel-vs-source phantom split.
|
|
1068
|
-
*
|
|
1069
|
-
* Symmetric with `workspaceSiblingIdentity` but for relative imports.
|
|
1070
|
-
*/
|
|
1071
|
-
function relativeChainLocalIdentity(graph, fileGraph, specifier, imported) {
|
|
1072
|
-
if (!graph)
|
|
1073
|
-
return null;
|
|
1074
|
-
if (packageNameFromSpecifier(specifier))
|
|
1075
|
-
return null; // bare package — workspace-sibling path handles it
|
|
1076
|
-
const abs = graph.moduleResolver(fileGraph.filePath, specifier);
|
|
1077
|
-
if (!abs)
|
|
1078
|
-
return null;
|
|
1079
|
-
const key = graph.resolveToGraphKey ? graph.resolveToGraphKey(abs) : abs;
|
|
1080
|
-
if (!key || !graph.files.has(key))
|
|
1081
|
-
return null;
|
|
1082
|
-
const chained = followReExportChain(graph, key, imported);
|
|
1083
|
-
if (!chained)
|
|
1084
|
-
return null;
|
|
1085
|
-
return { kind: "local", filePath: chained.file, export: chained.localExport };
|
|
1086
|
-
}
|
|
1087
|
-
/**
|
|
1088
|
-
* Workspace-sibling detection. A bare-package import (`@org/foo`) that
|
|
1089
|
-
* resolves to a file inside the parsed graph is a workspace sibling — the
|
|
1090
|
-
* package lives in this repo as a sibling workspace, not as a node_modules
|
|
1091
|
-
* dependency. Treat it as a local identity so JSX edges land on the actual
|
|
1092
|
-
* sibling file rather than a phantom external stub.
|
|
1093
|
-
*
|
|
1094
|
-
* Node_modules entries aren't in `graph.files` (excluded by default scan
|
|
1095
|
-
* globs), so they stay external naturally — no extra check needed.
|
|
1096
|
-
*
|
|
1097
|
-
* The file and export name are the ones `followReExportChain` lands on, so a
|
|
1098
|
-
* barrel that renames (`export { FooImpl as Foo } from "./foo"`) names the
|
|
1099
|
-
* binding `FooImpl` in `./foo`, the same identity the local-index seed hashes.
|
|
1100
|
-
*/
|
|
1101
|
-
function workspaceSiblingIdentity(graph, fileGraph, specifier, imported) {
|
|
1102
|
-
if (!graph)
|
|
1103
|
-
return null;
|
|
1104
|
-
if (!packageNameFromSpecifier(specifier))
|
|
1105
|
-
return null;
|
|
1106
|
-
const abs = graph.moduleResolver(fileGraph.filePath, specifier);
|
|
1107
|
-
const key = abs && (graph.resolveToGraphKey ? graph.resolveToGraphKey(abs) : abs);
|
|
1108
|
-
if (!key)
|
|
1109
|
-
return null;
|
|
1110
|
-
const chained = followReExportChain(graph, key, imported);
|
|
1111
|
-
const file = chained?.file ?? key;
|
|
1112
|
-
if (!graph.files.has(file))
|
|
1113
|
-
return null;
|
|
1114
|
-
return { kind: "local", filePath: file, export: chained?.localExport ?? imported };
|
|
1115
|
-
}
|
|
1116
|
-
/**
|
|
1117
|
-
* Membership fallback for composition-path identity. When a specifier
|
|
1118
|
-
* resolves to an absolute target that is NOT in the parsed graph (outside
|
|
1119
|
-
* the scan globs, or reached through an unrealpathed node_modules symlink)
|
|
1120
|
-
* but IS owned by a workspace member, promote to a LOCAL identity pinned via
|
|
1121
|
-
* the shared unparsed-member seam — mirroring the direct-import branch in
|
|
1122
|
-
* engine/index.ts so both paths mint the SAME identity. The absolute
|
|
1123
|
-
* filePath is normalised downstream (CLI `normaliseEngineLocalId`). Runs
|
|
1124
|
-
* after the in-graph promotions (workspaceSiblingIdentity /
|
|
1125
|
-
* relativeChainLocalIdentity), so parsed targets never reach it with a
|
|
1126
|
-
* different answer.
|
|
1127
|
-
*/
|
|
1128
|
-
function memberLocalIdentity(graph, fileGraph, specifier, imported) {
|
|
1129
|
-
if (graph?.workspaceMembership === undefined)
|
|
1130
|
-
return null;
|
|
1131
|
-
const abs = graph.moduleResolver(fileGraph.filePath, specifier);
|
|
1132
|
-
if (!abs)
|
|
1133
|
-
return null;
|
|
1134
|
-
const key = graph.resolveToGraphKey ? graph.resolveToGraphKey(abs) : abs;
|
|
1135
|
-
if (key !== null && graph.files.has(key))
|
|
1136
|
-
return null;
|
|
1137
|
-
const member = unparsedMemberDefinition(graph, abs, imported);
|
|
1138
|
-
if (member === null)
|
|
1139
|
-
return null;
|
|
1140
|
-
return { kind: "local", filePath: member.absFile, export: member.exportName };
|
|
1141
|
-
}
|
|
1142
|
-
/** Append a residual member chain to a derived identity's export name. */
|
|
1143
|
-
function withResidual(identity, residual) {
|
|
1144
|
-
if (identity === null || residual.length === 0)
|
|
1145
|
-
return identity;
|
|
1146
|
-
return identity.kind === "local"
|
|
1147
|
-
? { ...identity, export: compoundExportName(identity.export, residual) }
|
|
1148
|
-
: { ...identity, imported: compoundExportName(identity.imported, residual) };
|
|
1149
|
-
}
|
|
1150
|
-
/**
|
|
1151
|
-
* Resolve the input type's leaf TypeOf ref (or DynamicImport) to either an
|
|
1152
|
-
* imported or a local identity. Any other shape — a `ReturnTypeOf` included —
|
|
1063
|
+
* The identity of the binding a `TypeOf` reference or a `DynamicImport` names
|
|
1064
|
+
* (`bindingIdentity`), with a directly reached workspace member pinned to its
|
|
1065
|
+
* definition (`pinUnparsed`). Any other shape — a `ReturnTypeOf` included —
|
|
1153
1066
|
* has no identity of its own and yields null.
|
|
1154
|
-
*
|
|
1155
|
-
* Switches FileGraph context via `ref.originFile` when set, so refs that have
|
|
1156
|
-
* travelled across module boundaries (e.g. cross-module function returns) are
|
|
1157
|
-
* derived in their authoring file — where the import / declaration tables
|
|
1158
|
-
* that match the ref actually live.
|
|
1159
1067
|
*/
|
|
1160
1068
|
export function deriveIdentity(type, fileGraph, graph) {
|
|
1161
1069
|
// A ReturnTypeOf never derives identity from its callee:
|
|
1162
1070
|
// a resolvable factory call's identity is the declaration holding the call,
|
|
1163
1071
|
// which every engine push site already supplies as its fallback. Returning
|
|
1164
1072
|
// null here is what makes that fallback win.
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
if (cur.kind === "TypeOf") {
|
|
1170
|
-
const symbol = cur.ref.symbol;
|
|
1171
|
-
const lookup = graph ? fileGraphForRef(graph, cur.ref, fileGraph) : fileGraph;
|
|
1172
|
-
const imp = lookup.importsByLocal.get(symbol);
|
|
1173
|
-
if (imp) {
|
|
1174
|
-
// Namespace-import members canonicalise to the member name,
|
|
1175
|
-
// matching the direct-import path's `effectiveImported`
|
|
1176
|
-
// (engine/index.ts) so both paths mint the same identity. The residual chain
|
|
1177
|
-
// is appended AFTER every root lookup, so `Dialog.Popup` on an unparsed
|
|
1178
|
-
// package and `NS.Inline` on a workspace member both mirror the direct
|
|
1179
|
-
// path.
|
|
1180
|
-
const imported = effectiveExportName(imp.imported, cur.ref.memberChain);
|
|
1181
|
-
const residual = residualMemberChain(imp.imported, cur.ref.memberChain);
|
|
1182
|
-
const resolvedFile = graph ? resolveImportedFile(graph, lookup, imp.specifier, imported) : null;
|
|
1183
|
-
const workspaceLocal = workspaceSiblingIdentity(graph, lookup, imp.specifier, imported);
|
|
1184
|
-
if (workspaceLocal)
|
|
1185
|
-
return withResidual(workspaceLocal, residual);
|
|
1186
|
-
const relativeLocal = relativeChainLocalIdentity(graph, lookup, imp.specifier, imported);
|
|
1187
|
-
if (relativeLocal)
|
|
1188
|
-
return withResidual(relativeLocal, residual);
|
|
1189
|
-
const memberLocal = memberLocalIdentity(graph, lookup, imp.specifier, imported);
|
|
1190
|
-
if (memberLocal)
|
|
1191
|
-
return withResidual(memberLocal, residual);
|
|
1192
|
-
return withResidual({
|
|
1193
|
-
kind: "imported",
|
|
1194
|
-
specifier: imp.specifier,
|
|
1195
|
-
imported,
|
|
1196
|
-
resolvedFile,
|
|
1197
|
-
}, residual);
|
|
1198
|
-
}
|
|
1199
|
-
// Check local declarations. A same-file symbol is never a namespace
|
|
1200
|
-
// import, so the whole member chain is residual (mirror of
|
|
1201
|
-
// `pushLocalOccurrence`'s fallback) — an empty chain is a no-op.
|
|
1202
|
-
for (const [, decl] of lookup.declarations) {
|
|
1203
|
-
if (decl && decl.symbol === symbol) {
|
|
1204
|
-
return withResidual({
|
|
1205
|
-
kind: "local",
|
|
1206
|
-
filePath: lookup.filePath,
|
|
1207
|
-
export: decl.exportedAs ?? symbol,
|
|
1208
|
-
}, cur.ref.memberChain);
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1073
|
+
if (type.kind === "DynamicImport")
|
|
1074
|
+
return dynamicImportIdentity(graph, fileGraph, type);
|
|
1075
|
+
if (type.kind === "TypeOf")
|
|
1076
|
+
return bindingIdentity(pinUnparsed(graph, resolveBinding(graph, fileGraph, type.ref)));
|
|
1212
1077
|
return null;
|
|
1213
1078
|
}
|
|
1214
1079
|
//# sourceMappingURL=wrapper-folding.js.map
|