@descryy/runtime-identity-grounding 0.3.0 → 0.4.1
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 +59 -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/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 +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -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 +7 -7
|
@@ -1,49 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* What identity grounding is allowed to say about one on-screen element.
|
|
3
|
+
* The whole package answers *which component produced this DOM node, and
|
|
4
|
+
* where is that written* — this file fixes the vocabulary so "we couldn't
|
|
5
|
+
* tell" is a first-class named value, not a null a reader has to interpret.
|
|
3
6
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `RuntimeEventType` (`@descryy/runtime-contracts`) gains nothing here, and
|
|
12
|
-
* neither does `descry-core`'s frozen 15/15 graph vocabulary. This follows
|
|
13
|
-
* `@descryy/runtime-browser`'s `dom-evidence.ts` precedent exactly: a DOM
|
|
14
|
-
* fact is naturally *"what did the element this action touched look like"*,
|
|
15
|
-
* not an independent stream, so it rides on the `Evidence.payload` of the
|
|
16
|
-
* action evidence a caller is already emitting. An `ElementIdentity` is a
|
|
17
|
-
* plain, JSON-serialisable object for exactly that reason.
|
|
18
|
-
*
|
|
19
|
-
* The graph side is the same discipline one layer over: this package
|
|
20
|
-
* resolves an element to a **file, a symbol name and a line**, which is
|
|
21
|
-
* precisely `resolveSymbolNode`'s (`@descryy/runtime-graph-correlator`) input.
|
|
22
|
-
* It does not resolve to a node id itself — that resolver already refuses
|
|
23
|
-
* ambiguity, checks the line against the node's range and knows about
|
|
24
|
-
* repo-relative versus absolute path languages, and a second copy of that
|
|
25
|
-
* reasoning here would be a copy that drifts. See `graph-join.ts`.
|
|
7
|
+
* No new event type, no new node type: an `ElementIdentity` rides on the
|
|
8
|
+
* `Evidence.payload` of action evidence a caller is already emitting
|
|
9
|
+
* (`@descryy/runtime-browser`'s `dom-evidence.ts` precedent), so it's a
|
|
10
|
+
* plain JSON-serialisable object. This package resolves to a **file, symbol
|
|
11
|
+
* name and line** — `resolveSymbolNode`'s own input — never to a node id
|
|
12
|
+
* itself, since that resolver already refuses ambiguity and checks path
|
|
13
|
+
* languages; a second copy of that reasoning would drift. See `graph-join.ts`.
|
|
26
14
|
*/
|
|
27
15
|
import type { CapabilityStatus, SourceLocation } from "@descryy/runtime-contracts";
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
*
|
|
31
|
-
* A refusal is not an error and is never thrown — same contract
|
|
32
|
-
* `CollectorStartResult` states for a collector that cannot start: absence
|
|
33
|
-
* has to be representable data the caller can act on.
|
|
34
|
-
*/
|
|
35
|
-
export declare const IDENTITY_REFUSALS: readonly ["probe-not-installed", "element-not-found", "not-react", "react-debug-fields-absent", "no-component-fiber", "anonymous-component"];
|
|
16
|
+
/** Every way this can decline to name a component, as a closed set. A refusal is not an error and is never thrown — absence has to be representable data the caller can act on. */
|
|
17
|
+
export declare const IDENTITY_REFUSALS: readonly ["probe-not-installed", "element-not-found", "not-react", "react-debug-fields-absent", "no-component-fiber", "anonymous-component", "vue-component-marker-absent"];
|
|
36
18
|
export type IdentityRefusal = (typeof IDENTITY_REFUSALS)[number];
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
-
* majors' genuinely different internals, not two implementations of one
|
|
40
|
-
* idea — see `identity-grounding.ts` for the measurements.
|
|
41
|
-
*/
|
|
42
|
-
export declare const GROUNDING_MECHANISMS: readonly ["react-debug-source", "react-owner-stack"];
|
|
19
|
+
/** How a source location was obtained. The two values are the two React majors' genuinely different internals, not two implementations of one idea — see `identity-grounding.ts` for the measurements. */
|
|
20
|
+
export declare const GROUNDING_MECHANISMS: readonly ["react-debug-source", "react-owner-stack", "vue-options-file"];
|
|
43
21
|
export type GroundingMechanism = (typeof GROUNDING_MECHANISMS)[number];
|
|
44
|
-
export declare const COMPONENT_KINDS: readonly ["function", "class", "forward-ref", "memo"];
|
|
22
|
+
export declare const COMPONENT_KINDS: readonly ["function", "class", "forward-ref", "memo", "vue-options"];
|
|
45
23
|
export type ComponentKind = (typeof COMPONENT_KINDS)[number];
|
|
46
|
-
export declare const COMPONENT_NAME_SOURCES: readonly ["displayName", "function-name", "forward-ref-render-name"];
|
|
24
|
+
export declare const COMPONENT_NAME_SOURCES: readonly ["displayName", "function-name", "forward-ref-render-name", "vue-options-name"];
|
|
47
25
|
export type ComponentNameSource = (typeof COMPONENT_NAME_SOURCES)[number];
|
|
48
26
|
export interface ResolvedComponent {
|
|
49
27
|
readonly name: string;
|
|
@@ -52,27 +30,28 @@ export interface ResolvedComponent {
|
|
|
52
30
|
readonly kind: ComponentKind;
|
|
53
31
|
}
|
|
54
32
|
/**
|
|
55
|
-
* Which
|
|
56
|
-
*
|
|
57
|
-
* `
|
|
58
|
-
* this element
|
|
59
|
-
* `_debugSource` and `_debugStack` both describe the *creation* site. The
|
|
60
|
-
* `return` chain answers a different question — which component this
|
|
61
|
-
* element ended up rendered *inside* — and the two differ whenever an
|
|
33
|
+
* Which field the component was read from. `_debugOwner` is React's record
|
|
34
|
+
* of which component's render *created* this element, pairing with the
|
|
35
|
+
* source location. The `return` chain answers a different question — which
|
|
36
|
+
* component this element ended up rendered *inside* — differing whenever an
|
|
62
37
|
* element is created in one component and passed down as `children` to
|
|
63
|
-
* another
|
|
38
|
+
* another (the fixture app renders this case on purpose). `vue-parent-
|
|
39
|
+
* component` is Vue's own read (`el.__vueParentComponent`) and does not
|
|
40
|
+
* carry React's creation-vs-render distinction — Vue's instance tree has no
|
|
41
|
+
* runtime-observable equivalent of `_debugOwner` separate from the nearest
|
|
42
|
+
* owning instance, so `renderedBy` is always `null` on a Vue-grounded
|
|
43
|
+
* identity rather than a guessed second answer.
|
|
64
44
|
*/
|
|
65
|
-
export declare const COMPONENT_SOURCES: readonly ["debug-owner", "return-chain"];
|
|
45
|
+
export declare const COMPONENT_SOURCES: readonly ["debug-owner", "return-chain", "vue-parent-component"];
|
|
66
46
|
export type ComponentSource = (typeof COMPONENT_SOURCES)[number];
|
|
67
47
|
interface ElementIdentityBase {
|
|
68
48
|
readonly selector: string;
|
|
69
49
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* into the answer silently.
|
|
50
|
+
* `parentElement` hops from the queried element to the node that carried
|
|
51
|
+
* a React fiber. `0` is the element itself; greater than zero means the
|
|
52
|
+
* queried node wasn't created by React (e.g. inside
|
|
53
|
+
* `dangerouslySetInnerHTML`), and the answer describes its nearest
|
|
54
|
+
* React-rendered ancestor.
|
|
76
55
|
*/
|
|
77
56
|
readonly fiberDistance: number;
|
|
78
57
|
}
|
|
@@ -84,13 +63,7 @@ export interface ElementIdentityGrounded extends ElementIdentityBase {
|
|
|
84
63
|
/** The nearest component in the `return` chain — where the element was rendered, as opposed to where it was created. Null when there is none above the host fiber. */
|
|
85
64
|
readonly renderedBy: ResolvedComponent | null;
|
|
86
65
|
readonly sourceLocation: SourceLocation;
|
|
87
|
-
/**
|
|
88
|
-
* True when `sourceLocation.file` names authored source. False when it
|
|
89
|
-
* names compiled output because nothing could map it back — a React 19
|
|
90
|
-
* owner stack with no source map beside the bundle. The location is still
|
|
91
|
-
* real and still worth reporting; it just is not the file a developer
|
|
92
|
-
* wrote, and `capability` degrades accordingly.
|
|
93
|
-
*/
|
|
66
|
+
/** True when `sourceLocation.file` names authored source. False when it names compiled output (a React 19 owner stack with no source map beside the bundle) — still real, still worth reporting, just not the file a developer wrote. */
|
|
94
67
|
readonly authoredSource: boolean;
|
|
95
68
|
readonly mechanism: GroundingMechanism;
|
|
96
69
|
readonly capability: CapabilityStatus;
|
|
@@ -110,35 +83,25 @@ export interface ElementIdentityRefused extends ElementIdentityBase {
|
|
|
110
83
|
readonly reason: string;
|
|
111
84
|
readonly capability: CapabilityStatus;
|
|
112
85
|
/**
|
|
113
|
-
* The running page's own `type.name` for the fiber, when there was
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* a human debugging a refusal can see what was actually there. Anything
|
|
119
|
-
* that treats this as an authored name has reintroduced exactly the guess
|
|
120
|
-
* the refusal exists to prevent.
|
|
86
|
+
* The running page's own `type.name` for the fiber, when there was one.
|
|
87
|
+
* NOT a component name, deliberately: on `react-debug-fields-absent` this
|
|
88
|
+
* is a minified identifier, kept so a human debugging a refusal can see
|
|
89
|
+
* what was there. Treating this as authored reintroduces the guess the
|
|
90
|
+
* refusal exists to prevent.
|
|
121
91
|
*/
|
|
122
92
|
readonly observedTypeName: string | null;
|
|
123
93
|
}
|
|
124
94
|
export type ElementIdentity = ElementIdentityGrounded | ElementIdentityComponentOnly | ElementIdentityRefused;
|
|
125
95
|
/**
|
|
126
|
-
* The capability level this answer reports, in `CollectorCapabilities`'s
|
|
127
|
-
* three-value vocabulary
|
|
128
|
-
* one invented here.
|
|
129
|
-
*
|
|
130
|
-
* The mapping, stated once so it cannot drift between call sites:
|
|
96
|
+
* The capability level this answer reports, in `CollectorCapabilities`'s
|
|
97
|
+
* existing three-value vocabulary rather than a fourth one invented here.
|
|
131
98
|
*
|
|
132
99
|
* | outcome | availability | why |
|
|
133
100
|
* | --- | --- | --- |
|
|
134
101
|
* | `grounded`, authored source, not stale | `available` | component and authored file/line, both trustworthy |
|
|
135
|
-
* | `grounded`, compiled or stale location | `degraded` | a real location that
|
|
102
|
+
* | `grounded`, compiled or stale location | `degraded` | a real location that isn't the authored one, or failed a freshness check |
|
|
136
103
|
* | `component-only` | `degraded` | the component is named; no location at all |
|
|
137
104
|
* | `refused` | `unavailable` | nothing was named |
|
|
138
|
-
*
|
|
139
|
-
* `unavailable` is this repo's existing word for what a refusal is; there is
|
|
140
|
-
* no `refused` member of `CapabilityAvailability` and adding one would fork
|
|
141
|
-
* the capability model for one package.
|
|
142
105
|
*/
|
|
143
106
|
export declare function capabilityFor(availability: "available"): CapabilityStatus;
|
|
144
107
|
export declare function capabilityFor(availability: "degraded" | "unavailable", reason: string): CapabilityStatus;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element-identity.d.ts","sourceRoot":"","sources":["../src/element-identity.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"element-identity.d.ts","sourceRoot":"","sources":["../src/element-identity.ts"],"names":[],"mappings":"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"}
|
package/dist/element-identity.js
CHANGED
|
@@ -1,36 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* What identity grounding is allowed to say about one on-screen element.
|
|
3
|
+
* The whole package answers *which component produced this DOM node, and
|
|
4
|
+
* where is that written* — this file fixes the vocabulary so "we couldn't
|
|
5
|
+
* tell" is a first-class named value, not a null a reader has to interpret.
|
|
3
6
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `RuntimeEventType` (`@descryy/runtime-contracts`) gains nothing here, and
|
|
12
|
-
* neither does `descry-core`'s frozen 15/15 graph vocabulary. This follows
|
|
13
|
-
* `@descryy/runtime-browser`'s `dom-evidence.ts` precedent exactly: a DOM
|
|
14
|
-
* fact is naturally *"what did the element this action touched look like"*,
|
|
15
|
-
* not an independent stream, so it rides on the `Evidence.payload` of the
|
|
16
|
-
* action evidence a caller is already emitting. An `ElementIdentity` is a
|
|
17
|
-
* plain, JSON-serialisable object for exactly that reason.
|
|
18
|
-
*
|
|
19
|
-
* The graph side is the same discipline one layer over: this package
|
|
20
|
-
* resolves an element to a **file, a symbol name and a line**, which is
|
|
21
|
-
* precisely `resolveSymbolNode`'s (`@descryy/runtime-graph-correlator`) input.
|
|
22
|
-
* It does not resolve to a node id itself — that resolver already refuses
|
|
23
|
-
* ambiguity, checks the line against the node's range and knows about
|
|
24
|
-
* repo-relative versus absolute path languages, and a second copy of that
|
|
25
|
-
* reasoning here would be a copy that drifts. See `graph-join.ts`.
|
|
26
|
-
*/
|
|
27
|
-
/**
|
|
28
|
-
* Every way this can decline to name a component, as a closed set.
|
|
29
|
-
*
|
|
30
|
-
* A refusal is not an error and is never thrown — same contract
|
|
31
|
-
* `CollectorStartResult` states for a collector that cannot start: absence
|
|
32
|
-
* has to be representable data the caller can act on.
|
|
7
|
+
* No new event type, no new node type: an `ElementIdentity` rides on the
|
|
8
|
+
* `Evidence.payload` of action evidence a caller is already emitting
|
|
9
|
+
* (`@descryy/runtime-browser`'s `dom-evidence.ts` precedent), so it's a
|
|
10
|
+
* plain JSON-serialisable object. This package resolves to a **file, symbol
|
|
11
|
+
* name and line** — `resolveSymbolNode`'s own input — never to a node id
|
|
12
|
+
* itself, since that resolver already refuses ambiguity and checks path
|
|
13
|
+
* languages; a second copy of that reasoning would drift. See `graph-join.ts`.
|
|
33
14
|
*/
|
|
15
|
+
/** Every way this can decline to name a component, as a closed set. A refusal is not an error and is never thrown — absence has to be representable data the caller can act on. */
|
|
34
16
|
export const IDENTITY_REFUSALS = [
|
|
35
17
|
/** `install()` was never called, or was called after the document had already loaded — `page.addInitScript` does not reach a document that is already there. */
|
|
36
18
|
"probe-not-installed",
|
|
@@ -41,58 +23,71 @@ export const IDENTITY_REFUSALS = [
|
|
|
41
23
|
/**
|
|
42
24
|
* A fiber was found and it carries no `_debug*` field of any kind.
|
|
43
25
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* 19.2.8 production bundles: zero `_debug*` keys, and component names
|
|
51
|
-
* mangled in both.
|
|
52
|
-
*
|
|
53
|
-
* So there are two independent losses here, not one: no source location,
|
|
54
|
-
* *and* no trustworthy name. Reporting the mangled name as the component
|
|
55
|
-
* would be a confident wrong answer, which is worse than this refusal.
|
|
56
|
-
* The observed `type.name` still travels on
|
|
57
|
-
* `ElementIdentityRefused.observedTypeName`, labelled as what it is.
|
|
26
|
+
* The production-build refusal, must never soften into a guess. React
|
|
27
|
+
* strips `_debugSource`/`_debugOwner`/`_debugStack` outside dev builds,
|
|
28
|
+
* and a production bundle is minified too, so `type.name` is whatever the
|
|
29
|
+
* minifier left (`U2`, `ap`), not the authored name. Measured against
|
|
30
|
+
* React 18.3.1 and 19.2.8 production bundles: zero `_debug*` keys,
|
|
31
|
+
* mangled names in both.
|
|
58
32
|
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* production build)
|
|
33
|
+
* Two independent losses: no source location, no trustworthy name.
|
|
34
|
+
* Reporting the mangled name would be a confident wrong answer. It still
|
|
35
|
+
* travels on `ElementIdentityRefused.observedTypeName`, labelled as what
|
|
36
|
+
* it is. Named for the evidence (fields absent), not the conclusion
|
|
37
|
+
* (production build), since a React version that stopped exposing
|
|
38
|
+
* `_debug*` in dev too can't be distinguished from here.
|
|
64
39
|
*/
|
|
65
40
|
"react-debug-fields-absent",
|
|
66
41
|
/** A host fiber with no component above it at all — an element rendered directly by the root, with no `_debugOwner` and no component in its `return` chain. */
|
|
67
42
|
"no-component-fiber",
|
|
68
43
|
/** A component fiber was found and it has no resolvable name (an anonymous function or arrow with no `displayName`). Refused rather than reported as a nameless component: `resolveSymbolNode` has nothing to look up, and neither does a reader. */
|
|
69
44
|
"anonymous-component",
|
|
45
|
+
/**
|
|
46
|
+
* Vue's own read (`vue-identity-grounding.ts`): neither the queried element nor any ancestor
|
|
47
|
+
* carries `__vueParentComponent`. Named for the evidence, not the conclusion, for the same
|
|
48
|
+
* reason `react-debug-fields-absent` is — and here it is load-bearing rather than a stylistic
|
|
49
|
+
* choice: Vue 3 attaches this marker only when the app was built in a mode that keeps it
|
|
50
|
+
* (measured: present on an `esbuild --define process.env.NODE_ENV=development` bundle,
|
|
51
|
+
* **absent entirely** on a `minify: true` production bundle with devtools support off — no
|
|
52
|
+
* marker survives to distinguish "not a Vue page" from "a Vue production build" the way
|
|
53
|
+
* React's still-present-but-stripped fiber does). So this single refusal covers both readings
|
|
54
|
+
* honestly, the same way `react-debug-fields-absent` covers "production" vs "a future React
|
|
55
|
+
* that stopped exposing `_debug*` in dev too."
|
|
56
|
+
*/
|
|
57
|
+
"vue-component-marker-absent",
|
|
70
58
|
];
|
|
71
|
-
/**
|
|
72
|
-
* How a source location was obtained. The two values are the two React
|
|
73
|
-
* majors' genuinely different internals, not two implementations of one
|
|
74
|
-
* idea — see `identity-grounding.ts` for the measurements.
|
|
75
|
-
*/
|
|
59
|
+
/** How a source location was obtained. The two values are the two React majors' genuinely different internals, not two implementations of one idea — see `identity-grounding.ts` for the measurements. */
|
|
76
60
|
export const GROUNDING_MECHANISMS = [
|
|
77
61
|
/** React 18 and earlier, development build: `fiber._debugSource`, which names the authored file and line directly. */
|
|
78
62
|
"react-debug-source",
|
|
79
63
|
/** React 19, development build: `fiber._debugStack`, a captured `Error` whose frames point into *compiled* output and must be mapped back. */
|
|
80
64
|
"react-owner-stack",
|
|
65
|
+
/**
|
|
66
|
+
* Vue 3, a dev-mode-retaining build: `instance.type.__file`, the same property
|
|
67
|
+
* `@vitejs/plugin-vue`/`vue-loader` write onto a compiled SFC's options object for its own
|
|
68
|
+
* devtools "open in editor" feature — this package reads that convention rather than
|
|
69
|
+
* inventing one. **File-level only.** Unlike React's `_debugSource`, nothing in Vue's runtime
|
|
70
|
+
* records a creation *line* for an element — there is no owner-stack equivalent to fall back
|
|
71
|
+
* to, so a Vue answer's `sourceLocation.line` is `null` by construction, not a missed case.
|
|
72
|
+
*/
|
|
73
|
+
"vue-options-file",
|
|
81
74
|
];
|
|
82
|
-
export const COMPONENT_KINDS = ["function", "class", "forward-ref", "memo"];
|
|
83
|
-
export const COMPONENT_NAME_SOURCES = ["displayName", "function-name", "forward-ref-render-name"];
|
|
75
|
+
export const COMPONENT_KINDS = ["function", "class", "forward-ref", "memo", "vue-options"];
|
|
76
|
+
export const COMPONENT_NAME_SOURCES = ["displayName", "function-name", "forward-ref-render-name", "vue-options-name"];
|
|
84
77
|
/**
|
|
85
|
-
* Which
|
|
86
|
-
*
|
|
87
|
-
* `
|
|
88
|
-
* this element
|
|
89
|
-
* `_debugSource` and `_debugStack` both describe the *creation* site. The
|
|
90
|
-
* `return` chain answers a different question — which component this
|
|
91
|
-
* element ended up rendered *inside* — and the two differ whenever an
|
|
78
|
+
* Which field the component was read from. `_debugOwner` is React's record
|
|
79
|
+
* of which component's render *created* this element, pairing with the
|
|
80
|
+
* source location. The `return` chain answers a different question — which
|
|
81
|
+
* component this element ended up rendered *inside* — differing whenever an
|
|
92
82
|
* element is created in one component and passed down as `children` to
|
|
93
|
-
* another
|
|
83
|
+
* another (the fixture app renders this case on purpose). `vue-parent-
|
|
84
|
+
* component` is Vue's own read (`el.__vueParentComponent`) and does not
|
|
85
|
+
* carry React's creation-vs-render distinction — Vue's instance tree has no
|
|
86
|
+
* runtime-observable equivalent of `_debugOwner` separate from the nearest
|
|
87
|
+
* owning instance, so `renderedBy` is always `null` on a Vue-grounded
|
|
88
|
+
* identity rather than a guessed second answer.
|
|
94
89
|
*/
|
|
95
|
-
export const COMPONENT_SOURCES = ["debug-owner", "return-chain"];
|
|
90
|
+
export const COMPONENT_SOURCES = ["debug-owner", "return-chain", "vue-parent-component"];
|
|
96
91
|
export function capabilityFor(availability, reason) {
|
|
97
92
|
return availability === "available" ? { availability, reason: null } : { availability, reason: reason ?? "" };
|
|
98
93
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element-identity.js","sourceRoot":"","sources":["../src/element-identity.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"element-identity.js","sourceRoot":"","sources":["../src/element-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,mLAAmL;AACnL,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,gKAAgK;IAChK,qBAAqB;IACrB,gDAAgD;IAChD,mBAAmB;IACnB,8IAA8I;IAC9I,WAAW;IACX;;;;;;;;;;;;;;;;OAgBG;IACH,2BAA2B;IAC3B,+JAA+J;IAC/J,oBAAoB;IACpB,qPAAqP;IACrP,qBAAqB;IACrB;;;;;;;;;;;OAWG;IACH,6BAA6B;CACrB,CAAC;AAGX,0MAA0M;AAC1M,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,sHAAsH;IACtH,oBAAoB;IACpB,8IAA8I;IAC9I,mBAAmB;IACnB;;;;;;;OAOG;IACH,kBAAkB;CACV,CAAC;AAGX,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,CAAU,CAAC;AAGpG,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,aAAa,EAAE,eAAe,EAAE,yBAAyB,EAAE,kBAAkB,CAAU,CAAC;AAU/H;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,aAAa,EAAE,cAAc,EAAE,sBAAsB,CAAU,CAAC;AAqElG,MAAM,UAAU,aAAa,CAAC,YAA8C,EAAE,MAAe;IAC3F,OAAO,YAAY,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC;AAChH,CAAC"}
|
package/dist/fiber-probe.d.ts
CHANGED
|
@@ -2,45 +2,26 @@
|
|
|
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
|
import type { Page } from "playwright-core";
|
|
46
27
|
import type { ComponentKind, ComponentNameSource } from "./element-identity.ts";
|
|
@@ -48,14 +29,13 @@ import type { ComponentKind, ComponentNameSource } from "./element-identity.ts";
|
|
|
48
29
|
export declare const IDENTITY_GROUNDING_BINDING = "__descryIdentityGrounding";
|
|
49
30
|
/**
|
|
50
31
|
* The two key prefixes React has used to hang a fiber off a host DOM node:
|
|
51
|
-
* `__reactFiber$` since React 17, `__reactInternalInstance$` before
|
|
52
|
-
*
|
|
53
|
-
*
|
|
32
|
+
* `__reactFiber$` since React 17, `__reactInternalInstance$` before. Both
|
|
33
|
+
* checked because both are cheap and a wrong "not React" on a React 16 page
|
|
34
|
+
* would be a silent, permanent blind spot.
|
|
54
35
|
*
|
|
55
|
-
* Measured present as `__reactFiber$<random>` on React 18.3.1 and 19.2.8
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* here rather than implied by the code.
|
|
36
|
+
* Measured present as `__reactFiber$<random>` on React 18.3.1 and 19.2.8;
|
|
37
|
+
* `__reactInternalInstance$` matches React 16's documented shape but is
|
|
38
|
+
* NOT covered by this repo's fixtures.
|
|
59
39
|
*/
|
|
60
40
|
export declare const FIBER_KEY_PREFIXES: readonly ["__reactFiber$", "__reactInternalInstance$"];
|
|
61
41
|
export type FiberKeyPrefix = (typeof FIBER_KEY_PREFIXES)[number];
|
|
@@ -78,14 +58,14 @@ export type RawFiberProbe = {
|
|
|
78
58
|
} | {
|
|
79
59
|
readonly status: "no-fiber";
|
|
80
60
|
readonly selector: string;
|
|
81
|
-
/** The element's own enumerable keys, capped — so a "not React" refusal can be argued with
|
|
61
|
+
/** The element's own enumerable keys, capped — so a "not React" refusal can be argued with, not just believed. */
|
|
82
62
|
readonly ownKeys: readonly string[];
|
|
83
63
|
} | {
|
|
84
64
|
readonly status: "fiber";
|
|
85
65
|
readonly selector: string;
|
|
86
66
|
readonly fiberKeyPrefix: FiberKeyPrefix;
|
|
87
67
|
readonly fiberDistance: number;
|
|
88
|
-
/** `fiber.tag`, verbatim, for audit only
|
|
68
|
+
/** `fiber.tag`, verbatim, for audit only — see `describeType` for why the type shape is used instead. */
|
|
89
69
|
readonly hostTag: number | null;
|
|
90
70
|
/** `fiber.type` when it is a string, i.e. the host element's tag name. Null for a non-host fiber. */
|
|
91
71
|
readonly hostTypeName: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fiber-probe.d.ts","sourceRoot":"","sources":["../src/fiber-probe.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fiber-probe.d.ts","sourceRoot":"","sources":["../src/fiber-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,+FAA+F;AAC/F,eAAO,MAAM,0BAA0B,8BAA8B,CAAC;AAEtE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,wDAAyD,CAAC;AACzF,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE,+GAA+G;AAC/G,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAChD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAA;CAAE,GAC1C;IAAE,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACnE;IACE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kHAAkH;IAClH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC,GACD;IACE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,yGAAyG;IACzG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,qGAAqG;IACrG,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,+IAA+I;IAC/I,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,sJAAsJ;IACtJ,QAAQ,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC9C,sFAAsF;IACtF,QAAQ,CAAC,oBAAoB,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC7D,4FAA4F;IAC5F,QAAQ,CAAC,WAAW,EAAE,cAAc,GAAG,IAAI,CAAC;IAC5C,qGAAqG;IACrG,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,wIAAwI;IACxI,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1C,CAAC;AAEN,MAAM,WAAW,sBAAsB;IACrC,6GAA6G;IAC7G,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,2EAA2E;IAC3E,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CAC7D;AAED,wBAAgB,4BAA4B,IAAI,sBAAsB,CASrE"}
|