Skip to content

Commit c3b74c3

Browse files
committed
fix: update near-membrane-dom to use ShadowRealm
1 parent e4d17f5 commit c3b74c3

3 files changed

Lines changed: 5 additions & 186 deletions

File tree

packages/near-membrane-dom/src/browser-realm.ts

Lines changed: 5 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -12,140 +12,11 @@ import {
1212

1313
import { getCachedBlueReferences, linkUnforgeables, tameDOM } from './window';
1414

15-
const IFRAME_SANDBOX_ATTRIBUTE_VALUE = 'allow-same-origin allow-scripts';
16-
17-
const emptyArray: [] = [];
18-
const {
19-
close: DocumentProtoClose,
20-
createElement: DocumentProtoCreateElement,
21-
open: DocumentProtoOpen,
22-
} = document;
23-
const { remove: ElementProtoRemove, setAttribute: ElementProtoSetAttribute } = Element.prototype;
24-
const { appendChild: NodeProtoAppendChild } = Node.prototype;
2515
const { assign: ObjectAssign } = Object;
26-
const {
27-
// eslint-disable-next-line @typescript-eslint/naming-convention
28-
__lookupGetter__: ObjectProto__lookupGetter__,
29-
hasOwnProperty: ObjectProtoHasOwnProperty,
30-
} = Object.prototype as any;
31-
const { apply: ReflectApply } = Reflect;
32-
33-
function ObjectLookupOwnGetter(obj: object, key: PropertyKey): Function | undefined {
34-
// Since this function is only used internally, and would not otherwise be
35-
// reachable by user code, istanbul can ignore test coverage for the
36-
// following condition.
37-
// istanbul ignore next
38-
// eslint-disable-next-line @typescript-eslint/no-use-before-define
39-
if (obj === null || obj === undefined || !ReflectApply(ObjectProtoHasOwnProperty, obj, [key])) {
40-
return undefined;
41-
}
42-
// eslint-disable-next-line @typescript-eslint/no-use-before-define
43-
return ReflectApply(ObjectProto__lookupGetter__, obj, [key]);
44-
}
45-
46-
const DocumentProtoBodyGetter = ObjectLookupOwnGetter(Document.prototype, 'body')!;
47-
const HTMLElementProtoStyleGetter = ObjectLookupOwnGetter(HTMLElement.prototype, 'style')!;
48-
const HTMLIFrameElementProtoContentWindowGetter = ObjectLookupOwnGetter(
49-
HTMLIFrameElement.prototype,
50-
'contentWindow'
51-
)!;
52-
const NodeProtoIsConnectedGetter = ObjectLookupOwnGetter(Node.prototype, 'isConnected')!;
53-
const NodeProtoLastChildGetter = ObjectLookupOwnGetter(Node.prototype, 'lastChild')!;
54-
55-
function DocumentBody(doc: Document): typeof Document.prototype.body {
56-
return ReflectApply(DocumentProtoBodyGetter, doc, emptyArray);
57-
}
58-
59-
function DocumentClose(doc: Document): ReturnType<typeof Document.prototype.close> {
60-
return ReflectApply(DocumentProtoClose, doc, emptyArray);
61-
}
62-
63-
function DocumentCreateElement(
64-
doc: Document,
65-
tagName: string
66-
): ReturnType<typeof Document.prototype.createElement> {
67-
return ReflectApply(DocumentProtoCreateElement, doc, [tagName]);
68-
}
69-
70-
function DocumentOpen(doc: Document): ReturnType<typeof Document.prototype.open> {
71-
return ReflectApply(DocumentProtoOpen, doc, emptyArray);
72-
}
73-
74-
function ElementSetAttribute(
75-
el: Element,
76-
name: string,
77-
value: string
78-
): ReturnType<typeof Element.prototype.setAttribute> {
79-
return ReflectApply(ElementProtoSetAttribute, el, [name, value]);
80-
}
81-
82-
function ElementRemove(element: Element): Element {
83-
return ReflectApply(ElementProtoRemove, element, emptyArray);
84-
}
85-
86-
function HTMLElementStyleGetter(el: HTMLElement): typeof HTMLElement.prototype.style {
87-
return ReflectApply(HTMLElementProtoStyleGetter, el, emptyArray);
88-
}
89-
90-
function HTMLIFrameElementContentWindowGetter(
91-
iframe: HTMLIFrameElement
92-
): typeof HTMLIFrameElement.prototype.contentWindow {
93-
return ReflectApply(HTMLIFrameElementProtoContentWindowGetter, iframe, emptyArray);
94-
}
95-
96-
function NodeAppendChild(parent: Node, child: ChildNode): ChildNode {
97-
return ReflectApply(NodeProtoAppendChild, parent, [child]);
98-
}
99-
100-
// It's impossible to test whether NodeLastChild(document) is reached
101-
// in a normal Karma test environment, because the document will always
102-
// have a body element. Ignore this in coverage reporting to
103-
// avoid a penalty.
104-
// istanbul ignore next
105-
function NodeLastChild(node: Node): typeof Node.prototype.lastChild {
106-
return ReflectApply(NodeProtoLastChildGetter, node, emptyArray);
107-
}
108-
109-
function NodeIsConnected(node: Node): boolean {
110-
return ReflectApply(NodeProtoIsConnectedGetter, node, emptyArray);
111-
}
112-
113-
function createDetachableIframe(): HTMLIFrameElement {
114-
// @ts-ignore document global ref - in browsers
115-
const iframe = DocumentCreateElement(document, 'iframe') as HTMLIFrameElement;
116-
// It's impossible to test whether NodeLastChild(document) is reached
117-
// in a normal Karma test environment. (See explanation above,
118-
// at NodeLastChild definition.)
119-
const parent = DocumentBody(document) || /* istanbul ignore next */ NodeLastChild(document);
120-
const style = HTMLElementStyleGetter(iframe);
121-
style.display = 'none';
122-
ElementSetAttribute(iframe, 'sandbox', IFRAME_SANDBOX_ATTRIBUTE_VALUE);
123-
NodeAppendChild(parent, iframe);
124-
return iframe;
125-
}
126-
127-
function removeIframe(iframe: HTMLIFrameElement) {
128-
// In Chrome debugger statements will be ignored when the iframe is removed
129-
// from the document. Other browsers like Firefox and Safari work as expected.
130-
// https://bugs.chromium.org/p/chromium/issues/detail?id=1015462
131-
132-
// Because the detachable iframe is created, and then optionally removed, all
133-
// within the execution of createVirtualEnvironment, there is no point in which
134-
// test code can interfere with iframe element, or its prototype chain, in
135-
// order to remove it from the DOM, or stub the isConnected accessor
136-
// (the latter is already too late before createVirtualEnvironment is ever called).
137-
// For this reason, ignore the lack of `else` path coverage.
138-
//
139-
// istanbul ignore else
140-
if (NodeIsConnected(iframe)) {
141-
ElementRemove(iframe);
142-
}
143-
}
14416

14517
interface BrowserEnvironmentOptions {
14618
distortionCallback?: DistortionCallback;
14719
endowments?: object;
148-
keepAlive?: boolean;
14920
support?: SupportFlagsObject;
15021
instrumentation?: InstrumentationHooks;
15122
}
@@ -165,17 +36,16 @@ export default function createVirtualEnvironment(
16536
const options = ObjectAssign(
16637
{
16738
__proto__: null,
168-
keepAlive: false,
16939
},
17040
providedOptions
17141
);
17242
// eslint-disable-next-line prefer-object-spread
173-
const { distortionCallback, endowments = {}, keepAlive, support, instrumentation } = options;
174-
const iframe = createDetachableIframe();
175-
const redWindow = HTMLIFrameElementContentWindowGetter(iframe)!.window;
176-
const { document: redDocument } = redWindow;
43+
const { distortionCallback, endowments = {}, support, instrumentation } = options;
44+
// @ts-ignore: TypeScript doesn't know what a ShadowRealm is yet.
45+
const shadowRealm = new ShadowRealm();
46+
const shadowRealmEval = shadowRealm.evaluate.bind(shadowRealm);
17747
const blueConnector = createHooksCallback;
178-
const redConnector = createConnector(redWindow.eval);
48+
const redConnector = createConnector(shadowRealmEval);
17949
// Extract the global references and descriptors before any interference.
18050
const blueRefs = getCachedBlueReferences(globalObjectVirtualizationTarget);
18151
// Create a new environment.
@@ -190,15 +60,5 @@ export default function createVirtualEnvironment(
19060
linkIntrinsics(env, globalObjectVirtualizationTarget);
19161
linkUnforgeables(env, globalObjectVirtualizationTarget);
19262
tameDOM(env, blueRefs, getResolvedShapeDescriptors(globalObjectShape, endowments));
193-
// Once we get the iframe info ready, and all mapped, we can proceed
194-
// to detach the iframe only if the keepAlive option isn't true.
195-
if (keepAlive !== true) {
196-
removeIframe(iframe);
197-
} else {
198-
// TODO: Temporary hack to preserve the document reference in Firefox.
199-
// https://bugzilla.mozilla.org/show_bug.cgi?id=543435
200-
DocumentOpen(redDocument);
201-
DocumentClose(redDocument);
202-
}
20363
return env;
20464
}

test/dom/ffbug.spec.js

Lines changed: 0 additions & 31 deletions
This file was deleted.

test/environment/createvirtualenvironment.spec.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,6 @@ describe('createVirtualEnvironment', () => {
2828
const env = createVirtualEnvironment(window, window, { endowments: {} });
2929
expect(() => env.evaluate('')).not.toThrow();
3030
});
31-
it('options object has keepAlive: true', () => {
32-
const count = window.frames.length;
33-
const env = createVirtualEnvironment(window, window, { keepAlive: true });
34-
expect(window.frames.length).toBe(count + 1);
35-
expect(() => env.evaluate('')).not.toThrow();
36-
});
37-
it('options object has keepAlive: false', () => {
38-
const env = createVirtualEnvironment(window, window, { keepAlive: false });
39-
expect(() => env.evaluate('')).not.toThrow();
40-
});
4131
});
4232
});
4333
});

0 commit comments

Comments
 (0)