@descryy/runtime-identity-grounding 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/element-identity.d.ts +41 -78
- package/dist/element-identity.d.ts.map +1 -1
- package/dist/element-identity.js +69 -64
- package/dist/element-identity.js.map +1 -1
- package/dist/fiber-probe.d.ts +25 -45
- package/dist/fiber-probe.d.ts.map +1 -1
- package/dist/fiber-probe.js +45 -84
- package/dist/fiber-probe.js.map +1 -1
- package/dist/framework-aware-grounder.d.ts +35 -0
- package/dist/framework-aware-grounder.d.ts.map +1 -0
- package/dist/framework-aware-grounder.js +58 -0
- package/dist/framework-aware-grounder.js.map +1 -0
- package/dist/framework-detector.d.ts +46 -0
- package/dist/framework-detector.d.ts.map +1 -0
- package/dist/framework-detector.js +89 -0
- package/dist/framework-detector.js.map +1 -0
- package/dist/graph-join.d.ts +18 -49
- package/dist/graph-join.d.ts.map +1 -1
- package/dist/graph-join.js +17 -42
- package/dist/graph-join.js.map +1 -1
- package/dist/identity-grounder.d.ts +12 -31
- package/dist/identity-grounder.d.ts.map +1 -1
- package/dist/identity-grounder.js +13 -26
- package/dist/identity-grounder.js.map +1 -1
- package/dist/identity-grounding.d.ts +20 -39
- package/dist/identity-grounding.d.ts.map +1 -1
- package/dist/identity-grounding.js +27 -44
- package/dist/identity-grounding.js.map +1 -1
- package/dist/index.d.ts +11 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -6
- package/dist/index.js.map +1 -1
- package/dist/owner-stack.d.ts +36 -65
- package/dist/owner-stack.d.ts.map +1 -1
- package/dist/owner-stack.js +33 -62
- package/dist/owner-stack.js.map +1 -1
- package/dist/vue-identity-grounder.d.ts +23 -0
- package/dist/vue-identity-grounder.d.ts.map +1 -0
- package/dist/vue-identity-grounder.js +28 -0
- package/dist/vue-identity-grounder.js.map +1 -0
- package/dist/vue-identity-grounding.d.ts +16 -0
- package/dist/vue-identity-grounding.d.ts.map +1 -0
- package/dist/vue-identity-grounding.js +110 -0
- package/dist/vue-identity-grounding.js.map +1 -0
- package/dist/vue-probe.d.ts +49 -0
- package/dist/vue-probe.d.ts.map +1 -0
- package/dist/vue-probe.js +95 -0
- package/dist/vue-probe.js.map +1 -0
- package/package.json +5 -5
package/dist/fiber-probe.js
CHANGED
|
@@ -2,58 +2,38 @@
|
|
|
2
2
|
* The page-side half: reads React's fiber bookkeeping off a real DOM node
|
|
3
3
|
* and returns **raw facts only**.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Read-only, unlike `frontend-initiator-capture.ts` which concedes it
|
|
6
|
+
* wraps `window.fetch`. This module defines one function on `window` and
|
|
7
|
+
* reads properties React already put on DOM nodes and fiber objects —
|
|
8
|
+
* nothing wrapped, nothing patched, no application code path changes shape
|
|
9
|
+
* (same observation-only guarantee `Collector` states for attach mode).
|
|
6
10
|
*
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* objects. Nothing is wrapped, nothing is patched, no application code path
|
|
14
|
-
* changes shape because Descry is attached. That is the same
|
|
15
|
-
* observation-only guarantee `Collector` states for attach mode
|
|
16
|
-
* (`ATTACH_MODE_SCOPE_DISCLOSURE`), and it holds here without needing an
|
|
17
|
-
* exception.
|
|
11
|
+
* Injected via `page.addInitScript` with a string body, the same mechanism
|
|
12
|
+
* `frontend-initiator-capture.ts` uses — no transpilation step needed. A
|
|
13
|
+
* string rather than a typed function because this repo's
|
|
14
|
+
* `tsconfig.base.json` has no DOM library, so `document`/`window` don't
|
|
15
|
+
* exist as types here; it keeps the "runs here" vs "runs there" boundary
|
|
16
|
+
* visible.
|
|
18
17
|
*
|
|
19
|
-
*
|
|
18
|
+
* `addInitScript` doesn't reach an already-loaded document — call
|
|
19
|
+
* `install()` before navigating, or a page reports `probe-not-installed`.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* function because this repo's `tsconfig.base.json` compiles with `lib:
|
|
26
|
-
* ["ES2023"]` and no DOM library at all, so `document` and `window` do not
|
|
27
|
-
* exist as types in this package. Writing the page code as a string is not
|
|
28
|
-
* a shortcut around that; it is the same choice the sibling module made,
|
|
29
|
-
* and it keeps the boundary between "runs here" and "runs there" visible.
|
|
30
|
-
*
|
|
31
|
-
* `addInitScript` does not reach a document that has already loaded. Call
|
|
32
|
-
* `install()` before navigating, like every other collector in
|
|
33
|
-
* `@descryy/runtime-browser` — a page navigated first reports
|
|
34
|
-
* `probe-not-installed`, by name, rather than silently returning nothing.
|
|
35
|
-
*
|
|
36
|
-
* ## Raw facts only — no decisions
|
|
37
|
-
*
|
|
38
|
-
* Everything this returns is a JSON-serialisable transcript of what was on
|
|
39
|
-
* the fiber. Deciding what it *means* (is this a production build? does
|
|
40
|
-
* this owner stack point at authored source?) happens in Node, in
|
|
41
|
-
* `identity-grounding.ts`, where it can be unit-tested without a browser
|
|
42
|
-
* and where the source-map machinery this repo already owns is reachable.
|
|
43
|
-
* The page-side script cannot resolve a source map and must not try.
|
|
21
|
+
* Raw facts only, no decisions: everything returned is a JSON-serialisable
|
|
22
|
+
* transcript. Deciding what it *means* happens in Node
|
|
23
|
+
* (`identity-grounding.ts`), unit-testable without a browser. The
|
|
24
|
+
* page-side script cannot resolve a source map and must not try.
|
|
44
25
|
*/
|
|
45
26
|
/** The single global this installs. One name, one function, no other footprint on the page. */
|
|
46
27
|
export const IDENTITY_GROUNDING_BINDING = "__descryIdentityGrounding";
|
|
47
28
|
/**
|
|
48
29
|
* The two key prefixes React has used to hang a fiber off a host DOM node:
|
|
49
|
-
* `__reactFiber$` since React 17, `__reactInternalInstance$` before
|
|
50
|
-
*
|
|
51
|
-
*
|
|
30
|
+
* `__reactFiber$` since React 17, `__reactInternalInstance$` before. Both
|
|
31
|
+
* checked because both are cheap and a wrong "not React" on a React 16 page
|
|
32
|
+
* would be a silent, permanent blind spot.
|
|
52
33
|
*
|
|
53
|
-
* Measured present as `__reactFiber$<random>` on React 18.3.1 and 19.2.8
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* here rather than implied by the code.
|
|
34
|
+
* Measured present as `__reactFiber$<random>` on React 18.3.1 and 19.2.8;
|
|
35
|
+
* `__reactInternalInstance$` matches React 16's documented shape but is
|
|
36
|
+
* NOT covered by this repo's fixtures.
|
|
57
37
|
*/
|
|
58
38
|
export const FIBER_KEY_PREFIXES = ["__reactFiber$", "__reactInternalInstance$"];
|
|
59
39
|
export function createIdentityGroundingProbe() {
|
|
@@ -67,22 +47,15 @@ export function createIdentityGroundingProbe() {
|
|
|
67
47
|
};
|
|
68
48
|
}
|
|
69
49
|
/**
|
|
70
|
-
* The call side, also a string —
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* alongside a string body returned `undefined` here rather than calling the
|
|
76
|
-
* function expression with it. A self-invoking expression has one
|
|
77
|
-
* unambiguous meaning in both directions, and `JSON.stringify` on the
|
|
78
|
-
* selector is the same escaping this file already uses for the binding
|
|
79
|
-
* name, so a selector containing quotes cannot break out of the string.
|
|
50
|
+
* The call side, also a string — **self-invoking**, with the selector
|
|
51
|
+
* serialised into it rather than passed as an `evaluate` argument. Measured,
|
|
52
|
+
* not stylistic: a separate `arg` alongside a string body returned
|
|
53
|
+
* `undefined` here instead of calling the expression with it.
|
|
54
|
+
* `JSON.stringify` on the selector prevents a quote from breaking out.
|
|
80
55
|
*
|
|
81
|
-
* The `probe-not-installed` branch lives here
|
|
82
|
-
* script
|
|
83
|
-
*
|
|
84
|
-
* and drawing it is what keeps "Descry was not attached to this document"
|
|
85
|
-
* from being reported as "this page is not React".
|
|
56
|
+
* The `probe-not-installed` branch lives here, not in the injected script —
|
|
57
|
+
* a script that never ran can't report that it never ran. This is the only
|
|
58
|
+
* place that distinction can be drawn.
|
|
86
59
|
*/
|
|
87
60
|
function probeCallSource(selector) {
|
|
88
61
|
return `(() => {
|
|
@@ -93,34 +66,23 @@ function probeCallSource(selector) {
|
|
|
93
66
|
return grounding.probe(${JSON.stringify(selector)});
|
|
94
67
|
})()`;
|
|
95
68
|
}
|
|
96
|
-
/** Cap on the key list carried by a `no-fiber` result
|
|
69
|
+
/** Cap on the key list carried by a `no-fiber` result — a pathological element shouldn't become an unbounded payload. */
|
|
97
70
|
const MAX_REPORTED_OWN_KEYS = 32;
|
|
98
71
|
/**
|
|
99
72
|
* The injected reader.
|
|
100
73
|
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* React does not fail loudly — it silently classifies a real component as
|
|
110
|
-
* "not a component" and the answer degrades to a refusal nobody can
|
|
111
|
-
* explain.
|
|
112
|
-
*
|
|
113
|
-
* `fiber.type` is far more stable and is directly observable: a string is a
|
|
114
|
-
* host element, a function is a function or class component, an object with
|
|
115
|
-
* a `render` is a `forwardRef`, an object with a `type` is a `memo`. That
|
|
116
|
-
* is what is used. `tag` is still reported, verbatim, for audit.
|
|
117
|
-
*
|
|
118
|
-
* ## Everything degrades to null, nothing throws
|
|
74
|
+
* Component detection reads the *type shape*, not `fiber.tag` — the
|
|
75
|
+
* obvious numeric-tag table (`0 = FunctionComponent`, ...) is a private
|
|
76
|
+
* React implementation detail with no cross-major guarantee, and a table
|
|
77
|
+
* wrong on some future React silently misclassifies a component as "not a
|
|
78
|
+
* component" rather than failing loudly. `fiber.type` is stable and
|
|
79
|
+
* observable instead: a string is a host element, a function a
|
|
80
|
+
* function/class component, an object with `render` a `forwardRef`, an
|
|
81
|
+
* object with `type` a `memo`. `tag` is still reported verbatim for audit.
|
|
119
82
|
*
|
|
120
|
-
*
|
|
121
|
-
* whole probe body is wrapped so
|
|
122
|
-
*
|
|
123
|
-
* then have to survive.
|
|
83
|
+
* Everything degrades to null, nothing throws — an unexpected shape yields
|
|
84
|
+
* `null`, and the whole probe body is wrapped so a read-only observation
|
|
85
|
+
* can't become a page error the app has to survive.
|
|
124
86
|
*/
|
|
125
87
|
function probeScriptSource() {
|
|
126
88
|
return `(() => {
|
|
@@ -214,9 +176,8 @@ function probeScriptSource() {
|
|
|
214
176
|
try {
|
|
215
177
|
element = document.querySelector(selector);
|
|
216
178
|
} catch (_error) {
|
|
217
|
-
// An invalid selector is the caller's mistake,
|
|
218
|
-
//
|
|
219
|
-
// what actually happened here.
|
|
179
|
+
// An invalid selector is the caller's mistake, not a statement
|
|
180
|
+
// about the page — reported as "matched nothing".
|
|
220
181
|
return { status: "element-not-found", selector: selector };
|
|
221
182
|
}
|
|
222
183
|
if (element === null) return { status: "element-not-found", selector: selector };
|
package/dist/fiber-probe.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fiber-probe.js","sourceRoot":"","sources":["../src/fiber-probe.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fiber-probe.js","sourceRoot":"","sources":["../src/fiber-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAMH,+FAA+F;AAC/F,MAAM,CAAC,MAAM,0BAA0B,GAAG,2BAA2B,CAAC;AAEtE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,eAAe,EAAE,0BAA0B,CAAU,CAAC;AAuDzF,MAAM,UAAU,4BAA4B;IAC1C,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,IAAU;YACtB,MAAM,IAAI,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,KAAK,CAAC,IAAU,EAAE,QAAgB;YAChC,OAAO,IAAI,CAAC,QAAQ,CAAgB,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;QACjE,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,eAAe,CAAC,QAAgB;IACvC,OAAO;6BACoB,IAAI,CAAC,SAAS,CAAC,0BAA0B,CAAC;;;;2BAI5C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;KAC9C,CAAC;AACN,CAAC;AAED,yHAAyH;AACzH,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAEjC;;;;;;;;;;;;;;;GAeG;AACH,SAAS,iBAAiB;IACxB,OAAO;+BACsB,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAoFtD,IAAI,CAAC,SAAS,CAAC,0BAA0B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDA4BF,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2BlE,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect, then ground with the matching framework's grounder -- the single
|
|
3
|
+
* seam both surfaces (`descry-core`'s `playwright-driver.ts`, the desktop's
|
|
4
|
+
* `browser-drive.ts`) are meant to call instead of hardcoding
|
|
5
|
+
* `createIdentityGrounder` (React). Composes `createFrameworkDetector`
|
|
6
|
+
* (`framework-detector.ts`) with `createIdentityGrounder` (React,
|
|
7
|
+
* `identity-grounder.ts`) and `createVueIdentityGrounder` (Vue,
|
|
8
|
+
* `vue-identity-grounder.ts`); never defaults to either when detection
|
|
9
|
+
* fails.
|
|
10
|
+
*
|
|
11
|
+
* `install()` installs all three page-side probes -- the detector's and
|
|
12
|
+
* both frameworks' -- before first navigation, required by
|
|
13
|
+
* `page.addInitScript`'s contract regardless of which framework the page
|
|
14
|
+
* turns out to be, since detection cannot run until the document is live.
|
|
15
|
+
* Installing a probe that never fires costs nothing beyond the one
|
|
16
|
+
* `addInitScript` registration.
|
|
17
|
+
*
|
|
18
|
+
* `ground()` re-detects on every call rather than caching the framework
|
|
19
|
+
* after the first success: a session's page can navigate to a different
|
|
20
|
+
* app mid-session (a browser session's grounder is created once and reused
|
|
21
|
+
* across the whole session, both in `playwright-driver.ts`'s long-lived
|
|
22
|
+
* session and in the desktop's drive), and a framework cached from page 1
|
|
23
|
+
* would silently misground page 2 rather than re-deciding honestly.
|
|
24
|
+
*/
|
|
25
|
+
import type { Page } from "playwright-core";
|
|
26
|
+
import type { ElementIdentity } from "./element-identity.ts";
|
|
27
|
+
import { type IdentityGrounderOptions } from "./identity-grounder.ts";
|
|
28
|
+
export interface FrameworkAwareGrounder {
|
|
29
|
+
/** Installs every page-side probe (detection, React, Vue) into every document this page loads from now on. Call before navigating -- same `addInitScript` contract every probe in this package carries. */
|
|
30
|
+
install(page: Page): Promise<void>;
|
|
31
|
+
/** Detects the page's framework, then resolves one on-screen element through that framework's own grounder. Refuses by name (`framework-not-detected`) rather than guessing when neither framework's marker is present. */
|
|
32
|
+
ground(page: Page, selector: string): Promise<ElementIdentity>;
|
|
33
|
+
}
|
|
34
|
+
export declare function createFrameworkAwareGrounder(options?: IdentityGrounderOptions): FrameworkAwareGrounder;
|
|
35
|
+
//# sourceMappingURL=framework-aware-grounder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework-aware-grounder.d.ts","sourceRoot":"","sources":["../src/framework-aware-grounder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7D,OAAO,EAAiD,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAGrH,MAAM,WAAW,sBAAsB;IACrC,2MAA2M;IAC3M,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,2NAA2N;IAC3N,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAChE;AAED,wBAAgB,4BAA4B,CAAC,OAAO,GAAE,uBAA4B,GAAG,sBAAsB,CA6B1G"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect, then ground with the matching framework's grounder -- the single
|
|
3
|
+
* seam both surfaces (`descry-core`'s `playwright-driver.ts`, the desktop's
|
|
4
|
+
* `browser-drive.ts`) are meant to call instead of hardcoding
|
|
5
|
+
* `createIdentityGrounder` (React). Composes `createFrameworkDetector`
|
|
6
|
+
* (`framework-detector.ts`) with `createIdentityGrounder` (React,
|
|
7
|
+
* `identity-grounder.ts`) and `createVueIdentityGrounder` (Vue,
|
|
8
|
+
* `vue-identity-grounder.ts`); never defaults to either when detection
|
|
9
|
+
* fails.
|
|
10
|
+
*
|
|
11
|
+
* `install()` installs all three page-side probes -- the detector's and
|
|
12
|
+
* both frameworks' -- before first navigation, required by
|
|
13
|
+
* `page.addInitScript`'s contract regardless of which framework the page
|
|
14
|
+
* turns out to be, since detection cannot run until the document is live.
|
|
15
|
+
* Installing a probe that never fires costs nothing beyond the one
|
|
16
|
+
* `addInitScript` registration.
|
|
17
|
+
*
|
|
18
|
+
* `ground()` re-detects on every call rather than caching the framework
|
|
19
|
+
* after the first success: a session's page can navigate to a different
|
|
20
|
+
* app mid-session (a browser session's grounder is created once and reused
|
|
21
|
+
* across the whole session, both in `playwright-driver.ts`'s long-lived
|
|
22
|
+
* session and in the desktop's drive), and a framework cached from page 1
|
|
23
|
+
* would silently misground page 2 rather than re-deciding honestly.
|
|
24
|
+
*/
|
|
25
|
+
import { capabilityFor } from "./element-identity.js";
|
|
26
|
+
import { createFrameworkDetector } from "./framework-detector.js";
|
|
27
|
+
import { createIdentityGrounder } from "./identity-grounder.js";
|
|
28
|
+
import { createVueIdentityGrounder } from "./vue-identity-grounder.js";
|
|
29
|
+
export function createFrameworkAwareGrounder(options = {}) {
|
|
30
|
+
const detector = createFrameworkDetector();
|
|
31
|
+
const reactGrounder = createIdentityGrounder(options);
|
|
32
|
+
const vueGrounder = createVueIdentityGrounder();
|
|
33
|
+
return {
|
|
34
|
+
async install(page) {
|
|
35
|
+
// Order doesn't matter -- addInitScript registrations are independent
|
|
36
|
+
// and all three must land before the first navigation.
|
|
37
|
+
await detector.install(page);
|
|
38
|
+
await reactGrounder.install(page);
|
|
39
|
+
await vueGrounder.install(page);
|
|
40
|
+
},
|
|
41
|
+
async ground(page, selector) {
|
|
42
|
+
const result = await detector.detect(page);
|
|
43
|
+
if (result.outcome === "detected") {
|
|
44
|
+
return result.framework === "react" ? reactGrounder.ground(page, selector) : vueGrounder.ground(page, selector);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
selector,
|
|
48
|
+
fiberDistance: 0,
|
|
49
|
+
outcome: "refused",
|
|
50
|
+
refusal: "framework-not-detected",
|
|
51
|
+
reason: result.reason,
|
|
52
|
+
capability: capabilityFor("unavailable", result.reason),
|
|
53
|
+
observedTypeName: null,
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=framework-aware-grounder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework-aware-grounder.js","sourceRoot":"","sources":["../src/framework-aware-grounder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAiC,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAE,sBAAsB,EAAuD,MAAM,wBAAwB,CAAC;AACrH,OAAO,EAAE,yBAAyB,EAA4B,MAAM,4BAA4B,CAAC;AASjG,MAAM,UAAU,4BAA4B,CAAC,UAAmC,EAAE;IAChF,MAAM,QAAQ,GAAG,uBAAuB,EAAE,CAAC;IAC3C,MAAM,aAAa,GAAqB,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACxE,MAAM,WAAW,GAAwB,yBAAyB,EAAE,CAAC;IAErE,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,IAAU;YACtB,sEAAsE;YACtE,uDAAuD;YACvD,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,IAAU,EAAE,QAAgB;YACvC,MAAM,MAAM,GAA6B,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACrE,IAAI,MAAM,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;gBAClC,OAAO,MAAM,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAClH,CAAC;YACD,OAAO;gBACL,QAAQ;gBACR,aAAa,EAAE,CAAC;gBAChB,OAAO,EAAE,SAAS;gBAClB,OAAO,EAAE,wBAAwB;gBACjC,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,UAAU,EAAE,aAAa,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC;gBACvD,gBAAgB,EAAE,IAAI;aACvB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which framework rendered this page, decided by scanning the live document
|
|
3
|
+
* for the marker each framework's own probe already reads: React's fiber
|
|
4
|
+
* key (`fiber-probe.ts`'s `FIBER_KEY_PREFIXES`), then Vue's
|
|
5
|
+
* `__vueParentComponent` (`vue-probe.ts`). Neither found is a named
|
|
6
|
+
* refusal -- never a default to React.
|
|
7
|
+
*
|
|
8
|
+
* This is the one place both surfaces (`descry-core`'s
|
|
9
|
+
* `packages/mcp/src/browser/playwright-driver.ts` and `descry-desktop`'s
|
|
10
|
+
* `packages/session/src/pipeline/browser-drive.ts`) are meant to call, so
|
|
11
|
+
* detection is decided once and the two cannot drift on how they decide.
|
|
12
|
+
* See `framework-aware-grounder.ts` for the composed grounder that uses
|
|
13
|
+
* this to pick between `createIdentityGrounder` (React) and
|
|
14
|
+
* `createVueIdentityGrounder` (Vue).
|
|
15
|
+
*
|
|
16
|
+
* Page-wide, not selector-scoped, deliberately: the element a caller wants
|
|
17
|
+
* grounded may sit outside the framework's own mount root (a static
|
|
18
|
+
* wrapper around an app), and a selector-scoped scan would misreport "not
|
|
19
|
+
* React" for a real React page just because the queried node happens to sit
|
|
20
|
+
* outside it. Scanning the whole document answers the honest, broader
|
|
21
|
+
* question -- "did this framework render anything on this page at all" --
|
|
22
|
+
* which is what deciding *which grounder to use* needs; the per-selector
|
|
23
|
+
* probes answer the narrower one ("did it render *this* element") once a
|
|
24
|
+
* grounder has already been chosen.
|
|
25
|
+
*/
|
|
26
|
+
import type { Page } from "playwright-core";
|
|
27
|
+
/** The single global this installs. One name, one function, no other footprint on the page -- same discipline as `fiber-probe.ts`'s and `vue-probe.ts`'s own bindings. */
|
|
28
|
+
export declare const FRAMEWORK_DETECTION_BINDING = "__descryFrameworkDetection";
|
|
29
|
+
/** Checked in this order, always: React's fiber marker, then Vue's component marker. Never the reverse, and never a default. */
|
|
30
|
+
export declare const DETECTABLE_FRAMEWORKS: readonly ["react", "vue"];
|
|
31
|
+
export type DetectableFramework = (typeof DETECTABLE_FRAMEWORKS)[number];
|
|
32
|
+
export type FrameworkDetectionResult = {
|
|
33
|
+
readonly outcome: "detected";
|
|
34
|
+
readonly framework: DetectableFramework;
|
|
35
|
+
} | {
|
|
36
|
+
readonly outcome: "refused";
|
|
37
|
+
readonly reason: string;
|
|
38
|
+
};
|
|
39
|
+
export interface FrameworkDetector {
|
|
40
|
+
/** Installs the page-side reader into every document this page loads from now on. Call before navigating -- a page navigated first reports a `probe-not-installed`-shaped refusal, same contract `fiber-probe.ts`'s `install` documents. */
|
|
41
|
+
install(page: Page): Promise<void>;
|
|
42
|
+
/** Scans the page's current document and names which framework rendered it, or refuses by name. Never throws for a routine unavailability. */
|
|
43
|
+
detect(page: Page): Promise<FrameworkDetectionResult>;
|
|
44
|
+
}
|
|
45
|
+
export declare function createFrameworkDetector(): FrameworkDetector;
|
|
46
|
+
//# sourceMappingURL=framework-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework-detector.d.ts","sourceRoot":"","sources":["../src/framework-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAI5C,0KAA0K;AAC1K,eAAO,MAAM,2BAA2B,+BAA+B,CAAC;AAExE,gIAAgI;AAChI,eAAO,MAAM,qBAAqB,2BAA4B,CAAC;AAC/D,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzE,MAAM,MAAM,wBAAwB,GAChC;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAA;CAAE,GACzE;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D,MAAM,WAAW,iBAAiB;IAChC,4OAA4O;IAC5O,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,8IAA8I;IAC9I,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACvD;AAED,wBAAgB,uBAAuB,IAAI,iBAAiB,CAS3D"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which framework rendered this page, decided by scanning the live document
|
|
3
|
+
* for the marker each framework's own probe already reads: React's fiber
|
|
4
|
+
* key (`fiber-probe.ts`'s `FIBER_KEY_PREFIXES`), then Vue's
|
|
5
|
+
* `__vueParentComponent` (`vue-probe.ts`). Neither found is a named
|
|
6
|
+
* refusal -- never a default to React.
|
|
7
|
+
*
|
|
8
|
+
* This is the one place both surfaces (`descry-core`'s
|
|
9
|
+
* `packages/mcp/src/browser/playwright-driver.ts` and `descry-desktop`'s
|
|
10
|
+
* `packages/session/src/pipeline/browser-drive.ts`) are meant to call, so
|
|
11
|
+
* detection is decided once and the two cannot drift on how they decide.
|
|
12
|
+
* See `framework-aware-grounder.ts` for the composed grounder that uses
|
|
13
|
+
* this to pick between `createIdentityGrounder` (React) and
|
|
14
|
+
* `createVueIdentityGrounder` (Vue).
|
|
15
|
+
*
|
|
16
|
+
* Page-wide, not selector-scoped, deliberately: the element a caller wants
|
|
17
|
+
* grounded may sit outside the framework's own mount root (a static
|
|
18
|
+
* wrapper around an app), and a selector-scoped scan would misreport "not
|
|
19
|
+
* React" for a real React page just because the queried node happens to sit
|
|
20
|
+
* outside it. Scanning the whole document answers the honest, broader
|
|
21
|
+
* question -- "did this framework render anything on this page at all" --
|
|
22
|
+
* which is what deciding *which grounder to use* needs; the per-selector
|
|
23
|
+
* probes answer the narrower one ("did it render *this* element") once a
|
|
24
|
+
* grounder has already been chosen.
|
|
25
|
+
*/
|
|
26
|
+
import { FIBER_KEY_PREFIXES } from "./fiber-probe.js";
|
|
27
|
+
/** The single global this installs. One name, one function, no other footprint on the page -- same discipline as `fiber-probe.ts`'s and `vue-probe.ts`'s own bindings. */
|
|
28
|
+
export const FRAMEWORK_DETECTION_BINDING = "__descryFrameworkDetection";
|
|
29
|
+
/** Checked in this order, always: React's fiber marker, then Vue's component marker. Never the reverse, and never a default. */
|
|
30
|
+
export const DETECTABLE_FRAMEWORKS = ["react", "vue"];
|
|
31
|
+
export function createFrameworkDetector() {
|
|
32
|
+
return {
|
|
33
|
+
async install(page) {
|
|
34
|
+
await page.addInitScript({ content: probeScriptSource() });
|
|
35
|
+
},
|
|
36
|
+
detect(page) {
|
|
37
|
+
return page.evaluate(callSource());
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Self-invoking, no arguments needed -- unlike the per-element probes there is no selector to serialise in. The `probe-not-installed` branch lives here, not in the injected script, for the same reason `fiber-probe.ts`'s `probeCallSource` gives: a script that never ran cannot report that it never ran. */
|
|
42
|
+
function callSource() {
|
|
43
|
+
return `(() => {
|
|
44
|
+
const detection = window[${JSON.stringify(FRAMEWORK_DETECTION_BINDING)}];
|
|
45
|
+
if (detection === undefined || typeof detection.detect !== "function") {
|
|
46
|
+
return {
|
|
47
|
+
outcome: "refused",
|
|
48
|
+
reason: "the framework-detection probe was never installed (install() must run before the page's first navigation)",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return detection.detect();
|
|
52
|
+
})()`;
|
|
53
|
+
}
|
|
54
|
+
function probeScriptSource() {
|
|
55
|
+
return `(() => {
|
|
56
|
+
const FIBER_KEY_PREFIXES = ${JSON.stringify(FIBER_KEY_PREFIXES)};
|
|
57
|
+
|
|
58
|
+
function hasReactFiberKey(element) {
|
|
59
|
+
const keys = Object.keys(element);
|
|
60
|
+
for (let i = 0; i < keys.length; i++) {
|
|
61
|
+
for (let p = 0; p < FIBER_KEY_PREFIXES.length; p++) {
|
|
62
|
+
if (keys[i].indexOf(FIBER_KEY_PREFIXES[p]) === 0) return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function hasVueMarker(element) {
|
|
69
|
+
return element.__vueParentComponent !== undefined && element.__vueParentComponent !== null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
window[${JSON.stringify(FRAMEWORK_DETECTION_BINDING)}] = {
|
|
73
|
+
detect: function () {
|
|
74
|
+
const all = document.querySelectorAll("*");
|
|
75
|
+
for (let i = 0; i < all.length; i++) {
|
|
76
|
+
if (hasReactFiberKey(all[i])) return { outcome: "detected", framework: "react" };
|
|
77
|
+
}
|
|
78
|
+
for (let i = 0; i < all.length; i++) {
|
|
79
|
+
if (hasVueMarker(all[i])) return { outcome: "detected", framework: "vue" };
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
outcome: "refused",
|
|
83
|
+
reason: "neither a React fiber key nor a Vue __vueParentComponent marker was found anywhere in the document",
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
})();`;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=framework-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework-detector.js","sourceRoot":"","sources":["../src/framework-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,0KAA0K;AAC1K,MAAM,CAAC,MAAM,2BAA2B,GAAG,4BAA4B,CAAC;AAExE,gIAAgI;AAChI,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,KAAK,CAAU,CAAC;AAc/D,MAAM,UAAU,uBAAuB;IACrC,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,IAAU;YACtB,MAAM,IAAI,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,CAAC,IAAU;YACf,OAAO,IAAI,CAAC,QAAQ,CAA2B,UAAU,EAAE,CAAC,CAAC;QAC/D,CAAC;KACF,CAAC;AACJ,CAAC;AAED,kTAAkT;AAClT,SAAS,UAAU;IACjB,OAAO;6BACoB,IAAI,CAAC,SAAS,CAAC,2BAA2B,CAAC;;;;;;;;KAQnE,CAAC;AACN,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO;+BACsB,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;;;;;;;;;;;;;;;;WAgBtD,IAAI,CAAC,SAAS,CAAC,2BAA2B,CAAC;;;;;;;;;;;;;;;MAehD,CAAC;AACP,CAAC"}
|
package/dist/graph-join.d.ts
CHANGED
|
@@ -1,61 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The join to `descry-core`'s graph —
|
|
3
|
-
* resolver.
|
|
2
|
+
* The join to `descry-core`'s graph — a **hand-off**, not a second
|
|
3
|
+
* resolver. `resolveSymbolNode` already does the whole job of turning
|
|
4
|
+
* `{ file, symbolName, line }` into a `FUNCTION`/`CLASS` node — refusing
|
|
5
|
+
* ambiguity, checking the line against the node's range, translating path
|
|
6
|
+
* languages, requiring `repo` since there's no honest default. This
|
|
7
|
+
* function's entire contract: hand it exactly that input, or hand it
|
|
8
|
+
* nothing.
|
|
4
9
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* function must not duplicate: refusing ambiguity instead of ranking
|
|
9
|
-
* candidates, checking the claimed line against the node's own range and
|
|
10
|
-
* reporting `line-mismatch` distinctly, translating between the absolute /
|
|
11
|
-
* repo-relative / relative-to-launch-cwd path languages, and requiring
|
|
12
|
-
* `repo` because `FUNCTION` is repo-scoped and there is no honest default.
|
|
13
|
-
* A copy of any of that here would be a copy that drifts.
|
|
10
|
+
* No new node type, no new edge type — resolves to a `FUNCTION`/`CLASS`
|
|
11
|
+
* node an adapter already produced. `descry-core`'s frozen 15/15 vocabulary
|
|
12
|
+
* is untouched.
|
|
14
13
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* already produced — `descry-core`'s frozen 15 node types and 15 edge types
|
|
22
|
-
* are untouched. There is no `COMPONENT_INSTANCE`, no `RENDERS` edge, and
|
|
23
|
-
* nothing here asks for one. (`COMPONENT` is already one of the 15, and a
|
|
24
|
-
* React component that an adapter emitted as one is found by the same
|
|
25
|
-
* name+file lookup.)
|
|
26
|
-
*
|
|
27
|
-
* ## Why a compiled location is withheld rather than passed through
|
|
28
|
-
*
|
|
29
|
-
* `resolveSymbolNode` would take a bundle path quite happily and report
|
|
30
|
-
* `not-found` for it, which reads to a consumer as *"that component is not
|
|
31
|
-
* in the graph"* — the exact misleading refusal `symbol.ts`'s own header
|
|
32
|
-
* describes and fixed for absolute paths. A React 19 answer with
|
|
33
|
-
* `authoredSource: false` names `dist/dev.js`, a file no adapter ever
|
|
34
|
-
* indexed and never will. Withholding it keeps the honest statement —
|
|
35
|
-
* *"we know the component, we could not reach authored source"* — inside
|
|
36
|
-
* `ElementIdentity`, where the capability status explains it, instead of
|
|
37
|
-
* laundering it into a graph miss.
|
|
14
|
+
* A compiled location is withheld rather than passed through:
|
|
15
|
+
* `resolveSymbolNode` would report `not-found` for a bundle path, reading
|
|
16
|
+
* as "not in the graph" — the exact misleading refusal `symbol.ts` fixed
|
|
17
|
+
* for absolute paths. Withholding it keeps the honest statement ("we know
|
|
18
|
+
* the component, couldn't reach authored source") inside `ElementIdentity`,
|
|
19
|
+
* not laundered into a graph miss.
|
|
38
20
|
*/
|
|
39
21
|
import type { ElementIdentity } from "./element-identity.ts";
|
|
40
|
-
/**
|
|
41
|
-
* Structurally `resolveSymbolNode`'s own `location` parameter. Deliberately
|
|
42
|
-
* declared with `line` optional rather than nullable, because that is the
|
|
43
|
-
* shape that function accepts; `graph-join.test.ts` asserts the
|
|
44
|
-
* compatibility against the real signature at compile time, so a change on
|
|
45
|
-
* either side breaks the build rather than being discovered at runtime.
|
|
46
|
-
*/
|
|
22
|
+
/** Structurally `resolveSymbolNode`'s own `location` parameter — `line` optional, not nullable, matching that function's shape. `graph-join.test.ts` asserts the compatibility at compile time. */
|
|
47
23
|
export interface GraphSymbolLocation {
|
|
48
24
|
readonly file: string;
|
|
49
25
|
readonly symbolName: string;
|
|
50
26
|
readonly line?: number;
|
|
51
27
|
}
|
|
52
|
-
/**
|
|
53
|
-
* The graph lookup this identity supports, or `null` when it supports none.
|
|
54
|
-
*
|
|
55
|
-
* `null` for every outcome except a `grounded` one that reached authored
|
|
56
|
-
* source with a real file — including `component-only`, which knows the
|
|
57
|
-
* component's name and nothing about where it lives, and including a
|
|
58
|
-
* `grounded` answer whose location is compiled output.
|
|
59
|
-
*/
|
|
28
|
+
/** The graph lookup this identity supports, or `null` when it supports none — only a `grounded` outcome with authored source and a real file. */
|
|
60
29
|
export declare function symbolLocationForGraph(identity: ElementIdentity): GraphSymbolLocation | null;
|
|
61
30
|
//# sourceMappingURL=graph-join.d.ts.map
|
package/dist/graph-join.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-join.d.ts","sourceRoot":"","sources":["../src/graph-join.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"graph-join.d.ts","sourceRoot":"","sources":["../src/graph-join.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,mMAAmM;AACnM,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,iJAAiJ;AACjJ,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,eAAe,GAAG,mBAAmB,GAAG,IAAI,CAU5F"}
|
package/dist/graph-join.js
CHANGED
|
@@ -1,49 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The join to `descry-core`'s graph —
|
|
3
|
-
* resolver.
|
|
2
|
+
* The join to `descry-core`'s graph — a **hand-off**, not a second
|
|
3
|
+
* resolver. `resolveSymbolNode` already does the whole job of turning
|
|
4
|
+
* `{ file, symbolName, line }` into a `FUNCTION`/`CLASS` node — refusing
|
|
5
|
+
* ambiguity, checking the line against the node's range, translating path
|
|
6
|
+
* languages, requiring `repo` since there's no honest default. This
|
|
7
|
+
* function's entire contract: hand it exactly that input, or hand it
|
|
8
|
+
* nothing.
|
|
4
9
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* function must not duplicate: refusing ambiguity instead of ranking
|
|
9
|
-
* candidates, checking the claimed line against the node's own range and
|
|
10
|
-
* reporting `line-mismatch` distinctly, translating between the absolute /
|
|
11
|
-
* repo-relative / relative-to-launch-cwd path languages, and requiring
|
|
12
|
-
* `repo` because `FUNCTION` is repo-scoped and there is no honest default.
|
|
13
|
-
* A copy of any of that here would be a copy that drifts.
|
|
10
|
+
* No new node type, no new edge type — resolves to a `FUNCTION`/`CLASS`
|
|
11
|
+
* node an adapter already produced. `descry-core`'s frozen 15/15 vocabulary
|
|
12
|
+
* is untouched.
|
|
14
13
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* already produced — `descry-core`'s frozen 15 node types and 15 edge types
|
|
22
|
-
* are untouched. There is no `COMPONENT_INSTANCE`, no `RENDERS` edge, and
|
|
23
|
-
* nothing here asks for one. (`COMPONENT` is already one of the 15, and a
|
|
24
|
-
* React component that an adapter emitted as one is found by the same
|
|
25
|
-
* name+file lookup.)
|
|
26
|
-
*
|
|
27
|
-
* ## Why a compiled location is withheld rather than passed through
|
|
28
|
-
*
|
|
29
|
-
* `resolveSymbolNode` would take a bundle path quite happily and report
|
|
30
|
-
* `not-found` for it, which reads to a consumer as *"that component is not
|
|
31
|
-
* in the graph"* — the exact misleading refusal `symbol.ts`'s own header
|
|
32
|
-
* describes and fixed for absolute paths. A React 19 answer with
|
|
33
|
-
* `authoredSource: false` names `dist/dev.js`, a file no adapter ever
|
|
34
|
-
* indexed and never will. Withholding it keeps the honest statement —
|
|
35
|
-
* *"we know the component, we could not reach authored source"* — inside
|
|
36
|
-
* `ElementIdentity`, where the capability status explains it, instead of
|
|
37
|
-
* laundering it into a graph miss.
|
|
38
|
-
*/
|
|
39
|
-
/**
|
|
40
|
-
* The graph lookup this identity supports, or `null` when it supports none.
|
|
41
|
-
*
|
|
42
|
-
* `null` for every outcome except a `grounded` one that reached authored
|
|
43
|
-
* source with a real file — including `component-only`, which knows the
|
|
44
|
-
* component's name and nothing about where it lives, and including a
|
|
45
|
-
* `grounded` answer whose location is compiled output.
|
|
14
|
+
* A compiled location is withheld rather than passed through:
|
|
15
|
+
* `resolveSymbolNode` would report `not-found` for a bundle path, reading
|
|
16
|
+
* as "not in the graph" — the exact misleading refusal `symbol.ts` fixed
|
|
17
|
+
* for absolute paths. Withholding it keeps the honest statement ("we know
|
|
18
|
+
* the component, couldn't reach authored source") inside `ElementIdentity`,
|
|
19
|
+
* not laundered into a graph miss.
|
|
46
20
|
*/
|
|
21
|
+
/** The graph lookup this identity supports, or `null` when it supports none — only a `grounded` outcome with authored source and a real file. */
|
|
47
22
|
export function symbolLocationForGraph(identity) {
|
|
48
23
|
if (identity.outcome !== "grounded")
|
|
49
24
|
return null;
|
package/dist/graph-join.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-join.js","sourceRoot":"","sources":["../src/graph-join.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"graph-join.js","sourceRoot":"","sources":["../src/graph-join.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAWH,iJAAiJ;AACjJ,MAAM,UAAU,sBAAsB,CAAC,QAAyB;IAC9D,IAAI,QAAQ,CAAC,OAAO,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,CAAC,QAAQ,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IAE1C,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC;IAC/C,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE/B,OAAO,IAAI,KAAK,IAAI;QAClB,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE;QAC/C,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;AAC1D,CAAC"}
|