@braidlabs/core 0.1.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/README.md +123 -0
- package/package.json +37 -0
- package/src/adapters/adapter.d.ts +75 -0
- package/src/adapters/adapter.js +35 -0
- package/src/adapters/adapter.js.map +1 -0
- package/src/adapters/compat-adapter.d.ts +27 -0
- package/src/adapters/compat-adapter.js +113 -0
- package/src/adapters/compat-adapter.js.map +1 -0
- package/src/adapters/custom-element-adapter.d.ts +21 -0
- package/src/adapters/custom-element-adapter.js +91 -0
- package/src/adapters/custom-element-adapter.js.map +1 -0
- package/src/compat/born-inert-scripts.d.ts +30 -0
- package/src/compat/born-inert-scripts.js +85 -0
- package/src/compat/born-inert-scripts.js.map +1 -0
- package/src/compat/document-facade.d.ts +44 -0
- package/src/compat/document-facade.js +104 -0
- package/src/compat/document-facade.js.map +1 -0
- package/src/compat/document-member-classification.d.ts +30 -0
- package/src/compat/document-member-classification.js +64 -0
- package/src/compat/document-member-classification.js.map +1 -0
- package/src/compat/document-overrides.d.ts +44 -0
- package/src/compat/document-overrides.js +225 -0
- package/src/compat/document-overrides.js.map +1 -0
- package/src/compat/document-surface.generated.d.ts +21 -0
- package/src/compat/document-surface.generated.js +292 -0
- package/src/compat/document-surface.generated.js.map +1 -0
- package/src/compat/fragment-boundary.d.ts +14 -0
- package/src/compat/fragment-boundary.js +335 -0
- package/src/compat/fragment-boundary.js.map +1 -0
- package/src/compat/metadata.d.ts +15 -0
- package/src/compat/metadata.js +21 -0
- package/src/compat/metadata.js.map +1 -0
- package/src/compat/navigation-bus.d.ts +29 -0
- package/src/compat/navigation-bus.js +92 -0
- package/src/compat/navigation-bus.js.map +1 -0
- package/src/compat/realm-patches.d.ts +21 -0
- package/src/compat/realm-patches.js +573 -0
- package/src/compat/realm-patches.js.map +1 -0
- package/src/compat/register-worker.d.ts +45 -0
- package/src/compat/register-worker.js +57 -0
- package/src/compat/register-worker.js.map +1 -0
- package/src/compat/script-execution.d.ts +65 -0
- package/src/compat/script-execution.js +361 -0
- package/src/compat/script-execution.js.map +1 -0
- package/src/compat/service-worker.d.ts +22 -0
- package/src/compat/service-worker.js +104 -0
- package/src/compat/service-worker.js.map +1 -0
- package/src/config.d.ts +37 -0
- package/src/config.js +26 -0
- package/src/config.js.map +1 -0
- package/src/context/context-bus.d.ts +67 -0
- package/src/context/context-bus.js +117 -0
- package/src/context/context-bus.js.map +1 -0
- package/src/elements/fragment-slot.d.ts +39 -0
- package/src/elements/fragment-slot.js +281 -0
- package/src/elements/fragment-slot.js.map +1 -0
- package/src/env/create-env.d.ts +31 -0
- package/src/env/create-env.js +91 -0
- package/src/env/create-env.js.map +1 -0
- package/src/env/fragment-env.d.ts +56 -0
- package/src/env/fragment-env.js +14 -0
- package/src/env/fragment-env.js.map +1 -0
- package/src/errors.d.ts +21 -0
- package/src/errors.js +21 -0
- package/src/errors.js.map +1 -0
- package/src/index.d.ts +36 -0
- package/src/index.js +40 -0
- package/src/index.js.map +1 -0
- package/src/protocol.d.ts +38 -0
- package/src/protocol.js +45 -0
- package/src/protocol.js.map +1 -0
- package/src/realm/realm-manager.d.ts +60 -0
- package/src/realm/realm-manager.js +296 -0
- package/src/realm/realm-manager.js.map +1 -0
- package/src/utils/assert.d.ts +7 -0
- package/src/utils/assert.js +10 -0
- package/src/utils/assert.js.map +1 -0
- package/src/utils/selector-helpers.d.ts +10 -0
- package/src/utils/selector-helpers.js +13 -0
- package/src/utils/selector-helpers.js.map +1 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Born-inert scripts.
|
|
3
|
+
*
|
|
4
|
+
* Every script element created by fragment code (via the document facade's
|
|
5
|
+
* `createElement`/`createElementNS`) is neutralized at creation: its `type` attribute is set to
|
|
6
|
+
* `inert` before fragment code can attach content or insert it. This guarantees that no script
|
|
7
|
+
* reachable by fragment code can ever execute in the main JS context, no matter how it is
|
|
8
|
+
* inserted — even through code paths the boundary does not intercept synchronously.
|
|
9
|
+
*
|
|
10
|
+
* So that fragment code doesn't observe the neutralization, the script's `type` property and its
|
|
11
|
+
* `getAttribute`/`setAttribute` methods are shadowed to read and write the real type from/to the
|
|
12
|
+
* `data-script-type` attribute (the same attribute the gateway uses when neutralizing SSR
|
|
13
|
+
* content). The shadowing own-properties are removed before the script is activated.
|
|
14
|
+
*/
|
|
15
|
+
const nativeSetAttribute = Element.prototype.setAttribute;
|
|
16
|
+
const nativeGetAttribute = Element.prototype.getAttribute;
|
|
17
|
+
const nativeRemoveAttribute = Element.prototype.removeAttribute;
|
|
18
|
+
const bornInertScripts = new WeakSet();
|
|
19
|
+
export function makeScriptBornInert(script) {
|
|
20
|
+
nativeSetAttribute.call(script, 'type', 'inert');
|
|
21
|
+
bornInertScripts.add(script);
|
|
22
|
+
Object.defineProperties(script, {
|
|
23
|
+
type: {
|
|
24
|
+
configurable: true,
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get() {
|
|
27
|
+
return nativeGetAttribute.call(this, 'data-script-type') ?? '';
|
|
28
|
+
},
|
|
29
|
+
set(value) {
|
|
30
|
+
nativeSetAttribute.call(this, 'data-script-type', String(value));
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
setAttribute: {
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: function setAttribute(name, value) {
|
|
37
|
+
return nativeSetAttribute.call(this, String(name).toLowerCase() === 'type' ? 'data-script-type' : name, value);
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
getAttribute: {
|
|
41
|
+
configurable: true,
|
|
42
|
+
writable: true,
|
|
43
|
+
value: function getAttribute(name) {
|
|
44
|
+
return nativeGetAttribute.call(this, String(name).toLowerCase() === 'type' ? 'data-script-type' : name);
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
export function isBornInertScript(script) {
|
|
50
|
+
return bornInertScripts.has(script);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Removes the type-shadowing own-properties, leaving the script in the standard inert form
|
|
54
|
+
* (`type="inert"` plus the real type in `data-script-type`) that the script execution machinery
|
|
55
|
+
* understands. Used on the asynchronous (boundary observer) activation path, where the script is
|
|
56
|
+
* already attached to the fragment's DOM in inert form.
|
|
57
|
+
*/
|
|
58
|
+
export function removeBornInertShadowing(script) {
|
|
59
|
+
if (!bornInertScripts.has(script))
|
|
60
|
+
return;
|
|
61
|
+
delete script.type;
|
|
62
|
+
delete script.setAttribute;
|
|
63
|
+
delete script.getAttribute;
|
|
64
|
+
bornInertScripts.delete(script);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Fully reverts a born-inert script to the live form the application intended (real `type`
|
|
68
|
+
* attribute, no `data-script-type`). Used on the synchronous (stamped insertion) activation
|
|
69
|
+
* path, which re-neutralizes the script itself before performing the actual DOM insertion — the
|
|
70
|
+
* script is never attached to the DOM in live form.
|
|
71
|
+
*/
|
|
72
|
+
export function unwrapBornInertScriptToLive(script) {
|
|
73
|
+
if (!bornInertScripts.has(script))
|
|
74
|
+
return;
|
|
75
|
+
removeBornInertShadowing(script);
|
|
76
|
+
const realType = nativeGetAttribute.call(script, 'data-script-type');
|
|
77
|
+
nativeRemoveAttribute.call(script, 'data-script-type');
|
|
78
|
+
if (realType) {
|
|
79
|
+
nativeSetAttribute.call(script, 'type', realType);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
nativeRemoveAttribute.call(script, 'type');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=born-inert-scripts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"born-inert-scripts.js","sourceRoot":"","sources":["../../../../../libs/core/src/compat/born-inert-scripts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,kBAAkB,GAAG,OAAO,CAAC,SAAS,CAAC,YAAY,CAAC;AAC1D,MAAM,kBAAkB,GAAG,OAAO,CAAC,SAAS,CAAC,YAAY,CAAC;AAC1D,MAAM,qBAAqB,GAAG,OAAO,CAAC,SAAS,CAAC,eAAe,CAAC;AAEhE,MAAM,gBAAgB,GAAG,IAAI,OAAO,EAAqB,CAAC;AAE1D,MAAM,UAAU,mBAAmB,CAAC,MAAyB;IAC3D,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACjD,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAE7B,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE;QAC9B,IAAI,EAAE;YACJ,YAAY,EAAE,IAAI;YAClB,UAAU,EAAE,IAAI;YAChB,GAAG;gBACD,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC,IAAI,EAAE,CAAC;YACjE,CAAC;YACD,GAAG,CAAC,KAAa;gBACf,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACnE,CAAC;SACF;QACD,YAAY,EAAE;YACZ,YAAY,EAAE,IAAI;YAClB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,SAAS,YAAY,CAAC,IAAY,EAAE,KAAa;gBACtD,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACjH,CAAC;SACF;QACD,YAAY,EAAE;YACZ,YAAY,EAAE,IAAI;YAClB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,SAAS,YAAY,CAAC,IAAY;gBACvC,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC1G,CAAC;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAyB;IACzD,OAAO,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAyB;IAChE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO;IAC1C,OAAQ,MAAc,CAAC,IAAI,CAAC;IAC5B,OAAQ,MAAc,CAAC,YAAY,CAAC;IACpC,OAAQ,MAAc,CAAC,YAAY,CAAC;IACpC,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAClC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,MAAyB;IACnE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO;IAC1C,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACrE,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACvD,IAAI,QAAQ,EAAE,CAAC;QACb,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A facade override for a single Document member, mirroring the shape of a property descriptor:
|
|
3
|
+
* either an accessor (`get`, optionally with `set`) or a data member (`value`, typically a method).
|
|
4
|
+
*/
|
|
5
|
+
export type FacadeOverride = {
|
|
6
|
+
get: () => unknown;
|
|
7
|
+
set?: (value: any) => void;
|
|
8
|
+
value?: never;
|
|
9
|
+
} | {
|
|
10
|
+
value: unknown;
|
|
11
|
+
get?: never;
|
|
12
|
+
set?: never;
|
|
13
|
+
};
|
|
14
|
+
export type FacadeOverrides = Record<string, FacadeOverride>;
|
|
15
|
+
/**
|
|
16
|
+
* Installs a virtualizing facade over the given realm document by splicing a Proxy into its
|
|
17
|
+
* prototype chain.
|
|
18
|
+
*
|
|
19
|
+
* The proxy classifies every property access on the document:
|
|
20
|
+
*
|
|
21
|
+
* - members with an override (classified `'virtualized'`) are redirected to the override, which
|
|
22
|
+
* operates on the fragment's DOM in the main document,
|
|
23
|
+
* - members classified `'native'` pass through to the realm document's native behavior,
|
|
24
|
+
* - spec-defined Document members that are not classified also pass through, but log a one-time
|
|
25
|
+
* dev-mode diagnostic so that unaudited API usage by fragments surfaces during development
|
|
26
|
+
* instead of silently misbehaving,
|
|
27
|
+
* - anything else (application-defined expandos, symbols) passes through silently.
|
|
28
|
+
*
|
|
29
|
+
* Unlike patching individual properties, the proxy guarantees that *every* property access is
|
|
30
|
+
* observed, which turns "we forgot to patch X" from a silent wrong-document bug into an
|
|
31
|
+
* actionable diagnostic.
|
|
32
|
+
*
|
|
33
|
+
* Note that unlike `window` (whose prototype is immutable per the HTML spec), a Document
|
|
34
|
+
* instance has an ordinary, mutable [[Prototype]] slot, so splicing is safe cross-browser. Own
|
|
35
|
+
* properties of the document instance (e.g. the [LegacyUnforgeable] `location`) are unaffected.
|
|
36
|
+
*
|
|
37
|
+
* This patches the fragment's own realm document only — never the host
|
|
38
|
+
* page's document.
|
|
39
|
+
*
|
|
40
|
+
* @param realmDocument the fragment's realm iframe document to install the facade on
|
|
41
|
+
* @param overrides the virtualized member implementations (see `createDocumentOverrides`)
|
|
42
|
+
* @returns a function that uninstalls the facade and restores the original prototype chain
|
|
43
|
+
*/
|
|
44
|
+
export declare function installDocumentFacade(realmDocument: Document, overrides: FacadeOverrides): () => void;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { documentSurface } from './document-surface.generated.js';
|
|
2
|
+
import { documentMemberClassification } from './document-member-classification.js';
|
|
3
|
+
import { isDevMode } from '../config.js';
|
|
4
|
+
/**
|
|
5
|
+
* Members inherited by Document from these interfaces always pass through to the realm document
|
|
6
|
+
* silently. DOM tree traversal and event dispatch are virtualized at other layers (the fragment
|
|
7
|
+
* boundary and the event system patches in `realm-patches.ts`).
|
|
8
|
+
*/
|
|
9
|
+
const inheritedInterfaces = new Set(['Node', 'EventTarget']);
|
|
10
|
+
let lazyUnauditedDocumentMembers;
|
|
11
|
+
/**
|
|
12
|
+
* Returns whether the given member is a spec-defined Document member that has not been audited
|
|
13
|
+
* for compat fragment contexts yet. Access to such members falls through to the realm document
|
|
14
|
+
* and triggers a dev-mode diagnostic.
|
|
15
|
+
*/
|
|
16
|
+
function isUnauditedDocumentMember(name) {
|
|
17
|
+
lazyUnauditedDocumentMembers ??= new Set(Object.keys(documentSurface).filter((member) => !(member in documentMemberClassification) && !inheritedInterfaces.has(documentSurface[member].from)));
|
|
18
|
+
return lazyUnauditedDocumentMembers.has(name);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Installs a virtualizing facade over the given realm document by splicing a Proxy into its
|
|
22
|
+
* prototype chain.
|
|
23
|
+
*
|
|
24
|
+
* The proxy classifies every property access on the document:
|
|
25
|
+
*
|
|
26
|
+
* - members with an override (classified `'virtualized'`) are redirected to the override, which
|
|
27
|
+
* operates on the fragment's DOM in the main document,
|
|
28
|
+
* - members classified `'native'` pass through to the realm document's native behavior,
|
|
29
|
+
* - spec-defined Document members that are not classified also pass through, but log a one-time
|
|
30
|
+
* dev-mode diagnostic so that unaudited API usage by fragments surfaces during development
|
|
31
|
+
* instead of silently misbehaving,
|
|
32
|
+
* - anything else (application-defined expandos, symbols) passes through silently.
|
|
33
|
+
*
|
|
34
|
+
* Unlike patching individual properties, the proxy guarantees that *every* property access is
|
|
35
|
+
* observed, which turns "we forgot to patch X" from a silent wrong-document bug into an
|
|
36
|
+
* actionable diagnostic.
|
|
37
|
+
*
|
|
38
|
+
* Note that unlike `window` (whose prototype is immutable per the HTML spec), a Document
|
|
39
|
+
* instance has an ordinary, mutable [[Prototype]] slot, so splicing is safe cross-browser. Own
|
|
40
|
+
* properties of the document instance (e.g. the [LegacyUnforgeable] `location`) are unaffected.
|
|
41
|
+
*
|
|
42
|
+
* This patches the fragment's own realm document only — never the host
|
|
43
|
+
* page's document.
|
|
44
|
+
*
|
|
45
|
+
* @param realmDocument the fragment's realm iframe document to install the facade on
|
|
46
|
+
* @param overrides the virtualized member implementations (see `createDocumentOverrides`)
|
|
47
|
+
* @returns a function that uninstalls the facade and restores the original prototype chain
|
|
48
|
+
*/
|
|
49
|
+
export function installDocumentFacade(realmDocument, overrides) {
|
|
50
|
+
const originalPrototype = Object.getPrototypeOf(realmDocument);
|
|
51
|
+
const overrideMap = new Map(Object.entries(overrides));
|
|
52
|
+
const warnedMembers = new Set();
|
|
53
|
+
if (isDevMode()) {
|
|
54
|
+
for (const overriddenMember of overrideMap.keys()) {
|
|
55
|
+
if (documentMemberClassification[overriddenMember] !== 'virtualized') {
|
|
56
|
+
console.warn(`Braid compat: document facade override '${overriddenMember}' is not classified as 'virtualized' in document-member-classification.ts! Please classify it to keep the audit trail consistent.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function warnIfUnaudited(propertyName) {
|
|
61
|
+
if (isUnauditedDocumentMember(propertyName) && !warnedMembers.has(propertyName)) {
|
|
62
|
+
warnedMembers.add(propertyName);
|
|
63
|
+
console.warn(`Braid compat: a fragment accessed 'document.${propertyName}', which has not been audited for compat fragment contexts yet and falls through to the fragment's hidden realm document.\n` +
|
|
64
|
+
`If the fragment misbehaves in a way related to this API, please report it at https://github.com/braidjs/braid/issues`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const facadeProxy = new Proxy(originalPrototype, {
|
|
68
|
+
get(target, property, receiver) {
|
|
69
|
+
if (typeof property === 'string') {
|
|
70
|
+
const override = overrideMap.get(property);
|
|
71
|
+
if (override) {
|
|
72
|
+
return override.get ? override.get() : override.value;
|
|
73
|
+
}
|
|
74
|
+
if (isDevMode()) {
|
|
75
|
+
warnIfUnaudited(property);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return Reflect.get(target, property, receiver);
|
|
79
|
+
},
|
|
80
|
+
set(target, property, value, receiver) {
|
|
81
|
+
if (typeof property === 'string') {
|
|
82
|
+
const override = overrideMap.get(property);
|
|
83
|
+
if (override) {
|
|
84
|
+
if (override.set) {
|
|
85
|
+
override.set(value);
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
// read-only virtualized member: fail the assignment just like an assignment to a
|
|
89
|
+
// non-writable property would (throws in strict mode, silently ignored otherwise)
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
if (isDevMode()) {
|
|
93
|
+
warnIfUnaudited(property);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return Reflect.set(target, property, value, receiver);
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
Object.setPrototypeOf(realmDocument, facadeProxy);
|
|
100
|
+
return function uninstallDocumentFacade() {
|
|
101
|
+
Object.setPrototypeOf(realmDocument, originalPrototype);
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=document-facade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-facade.js","sourceRoot":"","sources":["../../../../../libs/core/src/compat/document-facade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAYzC;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;AAE7D,IAAI,4BAAqD,CAAC;AAE1D;;;;GAIG;AACH,SAAS,yBAAyB,CAAC,IAAY;IAC7C,4BAA4B,KAAK,IAAI,GAAG,CACtC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,MAAM,CACjC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,4BAA4B,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAChH,CACF,CAAC;IACF,OAAO,4BAA4B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,qBAAqB,CAAC,aAAuB,EAAE,SAA0B;IACvF,MAAM,iBAAiB,GAAG,MAAM,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;IAC/D,MAAM,WAAW,GAAG,IAAI,GAAG,CAAyB,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAC/E,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;IAExC,IAAI,SAAS,EAAE,EAAE,CAAC;QAChB,KAAK,MAAM,gBAAgB,IAAI,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC;YAClD,IAAI,4BAA4B,CAAC,gBAAgB,CAAC,KAAK,aAAa,EAAE,CAAC;gBACrE,OAAO,CAAC,IAAI,CACV,2CAA2C,gBAAgB,mIAAmI,CAC/L,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,eAAe,CAAC,YAAoB;QAC3C,IAAI,yBAAyB,CAAC,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YAChF,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAChC,OAAO,CAAC,IAAI,CACV,+CAA+C,YAAY,6HAA6H;gBACtL,sHAAsH,CACzH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,KAAK,CAAC,iBAAiB,EAAE;QAC/C,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ;YAC5B,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACjC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAC3C,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;gBACxD,CAAC;gBACD,IAAI,SAAS,EAAE,EAAE,CAAC;oBAChB,eAAe,CAAC,QAAQ,CAAC,CAAC;gBAC5B,CAAC;YACH,CAAC;YACD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACjD,CAAC;QAED,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ;YACnC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACjC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAC3C,IAAI,QAAQ,EAAE,CAAC;oBACb,IAAI,QAAQ,CAAC,GAAG,EAAE,CAAC;wBACjB,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;wBACpB,OAAO,IAAI,CAAC;oBACd,CAAC;oBACD,iFAAiF;oBACjF,kFAAkF;oBAClF,OAAO,KAAK,CAAC;gBACf,CAAC;gBACD,IAAI,SAAS,EAAE,EAAE,CAAC;oBAChB,eAAe,CAAC,QAAQ,CAAC,CAAC;gBAC5B,CAAC;YACH,CAAC;YACD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QACxD,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAElD,OAAO,SAAS,uBAAuB;QACrC,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;IAC1D,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classification of the Document API surface for compat fragment contexts (the WebIDL audit
|
|
3
|
+
* manifest for the document facade).
|
|
4
|
+
*
|
|
5
|
+
* Every entry records the result of auditing a Document member for use by application code
|
|
6
|
+
* running inside a compat fragment:
|
|
7
|
+
*
|
|
8
|
+
* - `'virtualized'` — the member is reimplemented by the document facade (see
|
|
9
|
+
* `document-overrides.ts`) so that it operates on the fragment's DOM in the main document
|
|
10
|
+
* (shadow root / `<braid-document>`) instead of the fragment's hidden realm iframe document.
|
|
11
|
+
*
|
|
12
|
+
* - `'native'` — the member was audited and the realm document's native behavior is the desired
|
|
13
|
+
* behavior for fragments, so it intentionally passes through the facade untouched.
|
|
14
|
+
*
|
|
15
|
+
* Spec-defined Document members absent from this map have not been audited yet. They pass
|
|
16
|
+
* through to the realm document's native behavior, and the facade logs a dev-mode diagnostic
|
|
17
|
+
* when a fragment uses them, so unaudited API usage surfaces during development instead of
|
|
18
|
+
* failing silently — and feeds the compat fidelity telemetry the architecture calls for.
|
|
19
|
+
*
|
|
20
|
+
* Members inherited from Node and EventTarget always pass through silently — DOM tree traversal
|
|
21
|
+
* and event dispatch are virtualized at other layers (the fragment boundary and the event
|
|
22
|
+
* system patches in `realm-patches.ts`).
|
|
23
|
+
*
|
|
24
|
+
* Note: `location` is a [LegacyUnforgeable] own property of the document instance and can never
|
|
25
|
+
* be intercepted via the prototype chain, so it is intentionally not classified here. The compat
|
|
26
|
+
* realm iframe's `src` is set to the fragment's url, which makes the realm's native
|
|
27
|
+
* `document.location` correct for fragments.
|
|
28
|
+
*/
|
|
29
|
+
export type DocumentMemberClassification = 'virtualized' | 'native';
|
|
30
|
+
export declare const documentMemberClassification: Readonly<Record<string, DocumentMemberClassification>>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export const documentMemberClassification = {
|
|
2
|
+
// --- virtualized: reimplemented against the fragment's DOM in the main document ---
|
|
3
|
+
// document metadata and state
|
|
4
|
+
title: 'virtualized',
|
|
5
|
+
readyState: 'virtualized',
|
|
6
|
+
currentScript: 'virtualized',
|
|
7
|
+
activeElement: 'virtualized',
|
|
8
|
+
// styles
|
|
9
|
+
styleSheets: 'virtualized',
|
|
10
|
+
adoptedStyleSheets: 'virtualized',
|
|
11
|
+
// document tree accessors (html/head/body are represented by braid-html/braid-head/braid-body custom elements)
|
|
12
|
+
documentElement: 'virtualized',
|
|
13
|
+
head: 'virtualized',
|
|
14
|
+
body: 'virtualized',
|
|
15
|
+
children: 'virtualized',
|
|
16
|
+
childElementCount: 'virtualized',
|
|
17
|
+
firstElementChild: 'virtualized',
|
|
18
|
+
lastElementChild: 'virtualized',
|
|
19
|
+
firstChild: 'virtualized',
|
|
20
|
+
lastChild: 'virtualized',
|
|
21
|
+
hasChildNodes: 'virtualized',
|
|
22
|
+
// querying
|
|
23
|
+
querySelector: 'virtualized',
|
|
24
|
+
querySelectorAll: 'virtualized',
|
|
25
|
+
getElementById: 'virtualized',
|
|
26
|
+
getElementsByClassName: 'virtualized',
|
|
27
|
+
getElementsByName: 'virtualized',
|
|
28
|
+
getElementsByTagName: 'virtualized',
|
|
29
|
+
getElementsByTagNameNS: 'virtualized',
|
|
30
|
+
// event dispatch (listeners registered via addEventListener are retargeted by the event system patches)
|
|
31
|
+
dispatchEvent: 'virtualized',
|
|
32
|
+
// node creation (nodes must be created in the main document so they can be attached to the fragment's DOM)
|
|
33
|
+
createElement: 'virtualized',
|
|
34
|
+
createElementNS: 'virtualized',
|
|
35
|
+
createAttributeNS: 'virtualized',
|
|
36
|
+
createCDATASection: 'virtualized',
|
|
37
|
+
createComment: 'virtualized',
|
|
38
|
+
createDocumentFragment: 'virtualized',
|
|
39
|
+
createEvent: 'virtualized',
|
|
40
|
+
createExpression: 'virtualized',
|
|
41
|
+
createNSResolver: 'virtualized',
|
|
42
|
+
createNodeIterator: 'virtualized',
|
|
43
|
+
createProcessingInstruction: 'virtualized',
|
|
44
|
+
createRange: 'virtualized',
|
|
45
|
+
createTextNode: 'virtualized',
|
|
46
|
+
createTreeWalker: 'virtualized',
|
|
47
|
+
// --- native: audited, the realm document's native behavior is correct for fragments ---
|
|
48
|
+
// the compat realm iframe is same-origin with the main document, so it shares the cookie jar
|
|
49
|
+
cookie: 'native',
|
|
50
|
+
// fragments must see the fragment's window (the realm iframe's window), not the main window
|
|
51
|
+
defaultView: 'native',
|
|
52
|
+
// the realm iframe's src is set to the fragment's url, so url-related members are correct natively
|
|
53
|
+
URL: 'native',
|
|
54
|
+
documentURI: 'native',
|
|
55
|
+
// document encoding/mode metadata of the realm document matches a standard html document
|
|
56
|
+
compatMode: 'native',
|
|
57
|
+
characterSet: 'native',
|
|
58
|
+
charset: 'native',
|
|
59
|
+
inputEncoding: 'native',
|
|
60
|
+
contentType: 'native',
|
|
61
|
+
// importNode deliberately creates nodes in the fragment's realm (used by the script execution machinery)
|
|
62
|
+
importNode: 'native',
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=document-member-classification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-member-classification.js","sourceRoot":"","sources":["../../../../../libs/core/src/compat/document-member-classification.ts"],"names":[],"mappings":"AA8BA,MAAM,CAAC,MAAM,4BAA4B,GAA2D;IAClG,qFAAqF;IAErF,8BAA8B;IAC9B,KAAK,EAAE,aAAa;IACpB,UAAU,EAAE,aAAa;IACzB,aAAa,EAAE,aAAa;IAC5B,aAAa,EAAE,aAAa;IAE5B,SAAS;IACT,WAAW,EAAE,aAAa;IAC1B,kBAAkB,EAAE,aAAa;IAEjC,+GAA+G;IAC/G,eAAe,EAAE,aAAa;IAC9B,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE,aAAa;IACnB,QAAQ,EAAE,aAAa;IACvB,iBAAiB,EAAE,aAAa;IAChC,iBAAiB,EAAE,aAAa;IAChC,gBAAgB,EAAE,aAAa;IAC/B,UAAU,EAAE,aAAa;IACzB,SAAS,EAAE,aAAa;IACxB,aAAa,EAAE,aAAa;IAE5B,WAAW;IACX,aAAa,EAAE,aAAa;IAC5B,gBAAgB,EAAE,aAAa;IAC/B,cAAc,EAAE,aAAa;IAC7B,sBAAsB,EAAE,aAAa;IACrC,iBAAiB,EAAE,aAAa;IAChC,oBAAoB,EAAE,aAAa;IACnC,sBAAsB,EAAE,aAAa;IAErC,wGAAwG;IACxG,aAAa,EAAE,aAAa;IAE5B,2GAA2G;IAC3G,aAAa,EAAE,aAAa;IAC5B,eAAe,EAAE,aAAa;IAC9B,iBAAiB,EAAE,aAAa;IAChC,kBAAkB,EAAE,aAAa;IACjC,aAAa,EAAE,aAAa;IAC5B,sBAAsB,EAAE,aAAa;IACrC,WAAW,EAAE,aAAa;IAC1B,gBAAgB,EAAE,aAAa;IAC/B,gBAAgB,EAAE,aAAa;IAC/B,kBAAkB,EAAE,aAAa;IACjC,2BAA2B,EAAE,aAAa;IAC1C,WAAW,EAAE,aAAa;IAC1B,cAAc,EAAE,aAAa;IAC7B,gBAAgB,EAAE,aAAa;IAE/B,yFAAyF;IAEzF,6FAA6F;IAC7F,MAAM,EAAE,QAAQ;IAEhB,4FAA4F;IAC5F,WAAW,EAAE,QAAQ;IAErB,mGAAmG;IACnG,GAAG,EAAE,QAAQ;IACb,WAAW,EAAE,QAAQ;IAErB,yFAAyF;IACzF,UAAU,EAAE,QAAQ;IACpB,YAAY,EAAE,QAAQ;IACtB,OAAO,EAAE,QAAQ;IACjB,aAAa,EAAE,QAAQ;IACvB,WAAW,EAAE,QAAQ;IAErB,yGAAyG;IACzG,UAAU,EAAE,QAAQ;CACrB,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { FacadeOverrides } from './document-facade.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hooks provided by the fragment boundary. Nodes created via the facade are stamped with the
|
|
4
|
+
* fragment's boundary prototype, and scripts are neutralized at creation ("born inert").
|
|
5
|
+
*/
|
|
6
|
+
export interface DocumentBoundaryHooks {
|
|
7
|
+
stampNode(node: Node): void;
|
|
8
|
+
makeScriptBornInert(script: HTMLScriptElement): void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Everything the document overrides need from the surrounding compat context.
|
|
12
|
+
*
|
|
13
|
+
* All dependencies are injected so that this module stays free of imports with side effects and
|
|
14
|
+
* can be exercised by unit tests outside of a browser.
|
|
15
|
+
*/
|
|
16
|
+
export interface DocumentOverridesContext {
|
|
17
|
+
/** The document of the fragment's hidden realm iframe. */
|
|
18
|
+
realmDocument: Document;
|
|
19
|
+
/** The main frame's document which owns the fragment's DOM. */
|
|
20
|
+
mainDocument: Document;
|
|
21
|
+
/** The `<braid-document>` element that acts as the fragment's virtual document element in the main DOM. */
|
|
22
|
+
braidDocumentElement: HTMLElement;
|
|
23
|
+
/** The shadow root of the `<fragment-slot>` element that contains the fragment's DOM. */
|
|
24
|
+
fragmentShadowRoot: ShadowRoot;
|
|
25
|
+
/** Whether the fragment's navigation is bound to the main window's navigation. */
|
|
26
|
+
boundNavigation: boolean;
|
|
27
|
+
/** Returns the virtualized readyState of the fragment's document. */
|
|
28
|
+
getRealmDocumentReadyState: () => DocumentReadyState;
|
|
29
|
+
/** Returns the inert clone (in the main DOM) of the script currently executing in the fragment's realm. */
|
|
30
|
+
getCurrentScript: () => HTMLScriptElement | undefined;
|
|
31
|
+
/** Boundary hooks; absent only in unit tests that exercise the overrides in isolation. */
|
|
32
|
+
boundary?: DocumentBoundaryHooks;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates the facade overrides that virtualize the Document API surface for a compat fragment.
|
|
36
|
+
*
|
|
37
|
+
* Each override redirects a Document member to operate on the fragment's DOM in the main
|
|
38
|
+
* document (the shadow root of `<fragment-slot>` and its `<braid-document>` element) instead of
|
|
39
|
+
* the hidden realm's document.
|
|
40
|
+
*
|
|
41
|
+
* Every member overridden here must be classified as `'virtualized'` in
|
|
42
|
+
* `document-member-classification.ts`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createDocumentOverrides(ctx: DocumentOverridesContext): FacadeOverrides;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { rewriteQuerySelector } from '../utils/selector-helpers.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates the facade overrides that virtualize the Document API surface for a compat fragment.
|
|
4
|
+
*
|
|
5
|
+
* Each override redirects a Document member to operate on the fragment's DOM in the main
|
|
6
|
+
* document (the shadow root of `<fragment-slot>` and its `<braid-document>` element) instead of
|
|
7
|
+
* the hidden realm's document.
|
|
8
|
+
*
|
|
9
|
+
* Every member overridden here must be classified as `'virtualized'` in
|
|
10
|
+
* `document-member-classification.ts`.
|
|
11
|
+
*/
|
|
12
|
+
export function createDocumentOverrides(ctx) {
|
|
13
|
+
const { realmDocument, mainDocument, braidDocumentElement, fragmentShadowRoot, boundNavigation } = ctx;
|
|
14
|
+
/**
|
|
15
|
+
* Elements created via the facade enter the fragment boundary at birth: scripts are
|
|
16
|
+
* neutralized before fragment code can arm them, and every created element is stamped so that
|
|
17
|
+
* operations on it are intercepted at the boundary rather than via global patches.
|
|
18
|
+
*/
|
|
19
|
+
function admitCreatedElement(element) {
|
|
20
|
+
if (ctx.boundary) {
|
|
21
|
+
if (element instanceof HTMLScriptElement) {
|
|
22
|
+
ctx.boundary.makeScriptBornInert(element);
|
|
23
|
+
}
|
|
24
|
+
ctx.boundary.stampNode(element);
|
|
25
|
+
}
|
|
26
|
+
return element;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
title: {
|
|
30
|
+
get: function () {
|
|
31
|
+
return (
|
|
32
|
+
// https://html.spec.whatwg.org/multipage/dom.html#document.title
|
|
33
|
+
braidDocumentElement.querySelector('title')?.textContent?.trim() ?? '[braid fragment document]');
|
|
34
|
+
},
|
|
35
|
+
set: function (newTitle) {
|
|
36
|
+
const titleElement = braidDocumentElement.querySelector('title');
|
|
37
|
+
if (titleElement) {
|
|
38
|
+
titleElement.textContent = newTitle;
|
|
39
|
+
}
|
|
40
|
+
if (boundNavigation) {
|
|
41
|
+
mainDocument.title = newTitle;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
readyState: {
|
|
46
|
+
get() {
|
|
47
|
+
return ctx.getRealmDocumentReadyState();
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
currentScript: {
|
|
51
|
+
get() {
|
|
52
|
+
return ctx.getCurrentScript();
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
// redirect getElementById to be a scoped braidDocumentElement.querySelector query
|
|
56
|
+
getElementById: {
|
|
57
|
+
value(id) {
|
|
58
|
+
return braidDocumentElement.querySelector(`[id="${id}"]`);
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
getElementsByClassName: {
|
|
62
|
+
value(names) {
|
|
63
|
+
return braidDocumentElement.getElementsByClassName(names);
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
getElementsByName: {
|
|
67
|
+
value(name) {
|
|
68
|
+
return braidDocumentElement.querySelector(`[name="${name}"]`);
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
getElementsByTagNameNS: {
|
|
72
|
+
value(namespaceURI, name) {
|
|
73
|
+
return braidDocumentElement.getElementsByTagNameNS(namespaceURI, name);
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
// redirect to mainDocument
|
|
77
|
+
activeElement: {
|
|
78
|
+
get: () => {
|
|
79
|
+
return (fragmentShadowRoot.activeElement ??
|
|
80
|
+
(mainDocument.activeElement === mainDocument.body ? realmDocument.body : null));
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
styleSheets: {
|
|
84
|
+
get: () => {
|
|
85
|
+
return fragmentShadowRoot.styleSheets;
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
adoptedStyleSheets: {
|
|
89
|
+
get() {
|
|
90
|
+
return fragmentShadowRoot.adoptedStyleSheets;
|
|
91
|
+
},
|
|
92
|
+
set(value) {
|
|
93
|
+
fragmentShadowRoot.adoptedStyleSheets = value;
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
dispatchEvent: {
|
|
97
|
+
value(event) {
|
|
98
|
+
return braidDocumentElement.dispatchEvent(event);
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
childElementCount: {
|
|
102
|
+
get() {
|
|
103
|
+
return braidDocumentElement.childElementCount;
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
hasChildNodes: {
|
|
107
|
+
value() {
|
|
108
|
+
return braidDocumentElement.hasChildNodes();
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
children: {
|
|
112
|
+
get() {
|
|
113
|
+
return braidDocumentElement.children;
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
firstElementChild: {
|
|
117
|
+
get() {
|
|
118
|
+
return braidDocumentElement.firstElementChild;
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
firstChild: {
|
|
122
|
+
get() {
|
|
123
|
+
return braidDocumentElement.firstChild;
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
lastElementChild: {
|
|
127
|
+
get() {
|
|
128
|
+
return braidDocumentElement.lastElementChild;
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
lastChild: {
|
|
132
|
+
get() {
|
|
133
|
+
return braidDocumentElement.lastChild;
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
/**
|
|
137
|
+
* The following properties are references to special elements in a Document (html, head,
|
|
138
|
+
* body). The browser does not allow multiple instances of these elements within a Document,
|
|
139
|
+
* so we cannot render true <html>, <head>, <body> elements within the shadow root of a
|
|
140
|
+
* fragment.
|
|
141
|
+
*
|
|
142
|
+
* Instead, render custom elements (braid-html, braid-head, braid-body) that act like the
|
|
143
|
+
* html, head, and body. The tagName and nodeName properties of these custom elements are
|
|
144
|
+
* then patched to return "HTML", "HEAD", and "BODY", respectively.
|
|
145
|
+
*
|
|
146
|
+
* CSS selector queries that contain html/head/body tag selectors are rewritten to the
|
|
147
|
+
* custom elements.
|
|
148
|
+
*/
|
|
149
|
+
querySelector: {
|
|
150
|
+
value(selector) {
|
|
151
|
+
return braidDocumentElement.querySelector(rewriteQuerySelector(selector));
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
querySelectorAll: {
|
|
155
|
+
value(selector) {
|
|
156
|
+
return braidDocumentElement.querySelectorAll(rewriteQuerySelector(selector));
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
getElementsByTagName: {
|
|
160
|
+
value(tagName) {
|
|
161
|
+
// The shadowRoot node itself does not have a getElementsByTagName method.
|
|
162
|
+
// For html, head, and body, rely on the rewritten querySelectorAll query.
|
|
163
|
+
// This will return a NodeList instead of an HTMLCollection, which will suffice for most use cases.
|
|
164
|
+
return braidDocumentElement.querySelectorAll(rewriteQuerySelector(tagName));
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
documentElement: {
|
|
168
|
+
get() {
|
|
169
|
+
return braidDocumentElement.querySelector('braid-html') ?? braidDocumentElement.firstElementChild;
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
head: {
|
|
173
|
+
get() {
|
|
174
|
+
return braidDocumentElement.querySelector('braid-head') ?? braidDocumentElement.firstElementChild;
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
body: {
|
|
178
|
+
get() {
|
|
179
|
+
return braidDocumentElement.querySelector('braid-body') ?? braidDocumentElement.firstElementChild;
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
// document.createElement & friends overrides: nodes must be created in the main document
|
|
183
|
+
// so that they can be attached to the fragment's DOM without adoption
|
|
184
|
+
...Object.fromEntries([
|
|
185
|
+
'createAttributeNS',
|
|
186
|
+
'createCDATASection',
|
|
187
|
+
'createComment',
|
|
188
|
+
'createDocumentFragment',
|
|
189
|
+
'createEvent',
|
|
190
|
+
'createExpression',
|
|
191
|
+
'createNSResolver',
|
|
192
|
+
'createNodeIterator',
|
|
193
|
+
'createProcessingInstruction',
|
|
194
|
+
'createRange',
|
|
195
|
+
'createTextNode',
|
|
196
|
+
'createTreeWalker',
|
|
197
|
+
].map((createProperty) => [
|
|
198
|
+
createProperty,
|
|
199
|
+
{
|
|
200
|
+
value: function compatCreateFn(...args) {
|
|
201
|
+
return mainDocument[createProperty].apply(mainDocument, args);
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
])),
|
|
205
|
+
createElement: {
|
|
206
|
+
value: function createElement(...[tagName, ...rest]) {
|
|
207
|
+
const element = Document.prototype.createElement.apply(
|
|
208
|
+
// create the element within the realm document if it contains a dash as it could be a
|
|
209
|
+
// custom element defined only in the fragment's realm
|
|
210
|
+
tagName.includes('-') ? realmDocument : mainDocument, [tagName, ...rest]);
|
|
211
|
+
return admitCreatedElement(element);
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
createElementNS: {
|
|
215
|
+
value: function createElementNS(...[namespaceURI, tagName, ...rest]) {
|
|
216
|
+
const element = Document.prototype.createElementNS.apply(
|
|
217
|
+
// create the element within the realm document if it contains a dash as it could be a
|
|
218
|
+
// custom element defined only in the fragment's realm
|
|
219
|
+
namespaceURI === 'http://www.w3.org/1999/xhtml' && tagName.includes('-') ? realmDocument : mainDocument, [namespaceURI, tagName, ...rest]);
|
|
220
|
+
return admitCreatedElement(element);
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=document-overrides.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-overrides.js","sourceRoot":"","sources":["../../../../../libs/core/src/compat/document-overrides.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GENERATED FILE — DO NOT EDIT!
|
|
3
|
+
*
|
|
4
|
+
* Generated by scripts/generate-document-surface.mjs from @webref/idl@3.82.1 in the
|
|
5
|
+
* Jefftopia/web-fragments fork and ported into Braid verbatim. To regenerate, run the fork's
|
|
6
|
+
* `pnpm generate:document-surface` and copy the result here.
|
|
7
|
+
*
|
|
8
|
+
* Enumerates the spec-defined API surface of the Document interface (including partials and mixins such as
|
|
9
|
+
* FontFaceSource, GeometryUtils, NonElementParentNode, DocumentOrShadowRoot, ParentNode, XPathEvaluatorBase, GlobalEventHandlers, ARIANotifyMixin)
|
|
10
|
+
* as well as the inherited Node and EventTarget interfaces.
|
|
11
|
+
*/
|
|
12
|
+
export interface DocumentSurfaceMember {
|
|
13
|
+
/** Whether the member is declared as a WebIDL attribute or operation. */
|
|
14
|
+
kind: 'attribute' | 'operation';
|
|
15
|
+
/** The interface or mixin that declares the member. */
|
|
16
|
+
from: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* All named properties that browsers expose on a Document instance per the current browser specifications.
|
|
20
|
+
*/
|
|
21
|
+
export declare const documentSurface: Readonly<Record<string, DocumentSurfaceMember>>;
|