|
function isObject(value) { |
|
return ( |
|
(value !== null && typeof value === 'object') |
|
|| typeof value === 'function' |
|
); |
|
} |
|
|
|
/** |
|
* We can’t transfer a (non-callable) object across realms. |
|
* But we can transfer a function that applies proxy-trapped operations |
|
* to the object. |
|
*/ |
|
export function wrapLocalValue(value) { |
|
if (isObject(value)) { |
|
return (trapName, ...args) => { |
|
const wrappedArgs = args.map(arg => wrapForeignValue(arg)); |
|
const result = Reflect[trapName](value, ...wrappedArgs); |
|
return wrapLocalValue(result); |
|
}; |
|
} else { |
|
return value; |
|
} |
|
} |
|
|
|
/** |
|
* To use a wrapped object from another realm in the current realm, |
|
* we create a Proxy that feeds the operations it traps to the function. |
|
*/ |
|
export function wrapForeignValue(value) { |
|
if (!isObject(value)) { |
|
return value; |
|
} |
|
|
|
// All handler methods follow the same pattern. |
|
// To avoid repetitive code, we create it via a loop. |
|
const handler = {}; |
|
for (const trapName of Object.getOwnPropertyNames(Reflect)) { |
|
handler[trapName] = (_target, ...args) => { |
|
const wrappedArgs = args.map(arg => wrapLocalValue(arg)); |
|
const result = value(trapName, ...wrappedArgs); |
|
return wrapForeignValue(result); |
|
}; |
|
} |
|
|
|
const target = function () {}; |
|
return new Proxy(target, handler); |
|
} |
|
|
|
export async function createShadowEval(shadowRealm) { |
|
const _getLocallyWrappedEval = await shadowRealm.importValue(import.meta.url, '_getLocallyWrappedEval'); |
|
return wrapForeignValue(_getLocallyWrappedEval()); |
|
} |
|
|
|
export async function createShadowImport(shadowRealm) { |
|
const _getLocallyWrappedImport = await shadowRealm.importValue(import.meta.url, '_getLocallyWrappedImport'); |
|
return wrapForeignValue(_getLocallyWrappedImport()); |
|
} |
|
|
|
export function _getLocallyWrappedEval() { |
|
return wrapLocalValue(globalThis.eval); |
|
} |
|
|
|
export function _getLocallyWrappedImport() { |
|
return wrapLocalValue((moduleSpecifier) => import(moduleSpecifier)); |
|
} |