@masknet/compartment
Advanced tools
Comparing version 0.2.1 to 0.2.2
@@ -10,4 +10,5 @@ import type { CompartmentInstance, CompartmentOptions } from './types.js'; | ||
import(fullSpec: string): Promise<object>; | ||
static _: any; | ||
constructor(options: CompartmentOptions); | ||
} | ||
//# sourceMappingURL=compartment.d.ts.map |
import { makeBorrowedGlobalThis, makeGlobalThis } from './utils/makeGlobalThis.js'; | ||
import { StaticModuleRecord } from './StaticModuleRecord.js'; | ||
import { normalizeModuleDescriptor } from './utils/normalize.js'; | ||
@@ -9,2 +8,3 @@ import { internalError, unreachable } from './utils/assert.js'; | ||
import { PromiseCapability } from './utils/spec.js'; | ||
import { ModuleSource } from './ModuleSource.js'; | ||
/** @internal */ | ||
@@ -28,6 +28,16 @@ export let brandCheck_Compartment; | ||
// implementation | ||
static { | ||
brandCheck_Compartment = (compartment) => #globalThis in compartment; | ||
// Safari: static init block | ||
static _ = (() => { | ||
// Safari: private in | ||
brandCheck_Compartment = (compartment) => { | ||
try { | ||
compartment.#globalThis; | ||
return true; | ||
} | ||
catch { | ||
return false; | ||
} | ||
}; | ||
internalSlot_Compartment_globalThis_get = (compartment) => compartment.#globalThis; | ||
} | ||
})(); | ||
#opts; | ||
@@ -145,4 +155,4 @@ #incubatorCompartment; | ||
} | ||
else if (desc.record instanceof StaticModuleRecord) { | ||
throw new TypeError('StaticModuleRecord is not supported.'); | ||
else if (desc.record instanceof ModuleSource) { | ||
throw new TypeError('ModuleSource is not supported.'); | ||
} | ||
@@ -172,3 +182,3 @@ else { | ||
else if (module.type === 'record') { | ||
const { initialize, bindings = [], needsImport, needsImportMeta } = module.module; | ||
const { execute, bindings = [], needsImport, needsImportMeta } = module.module; | ||
const { imports, moduleEnvironmentProxy, setters, init } = makeModuleEnvironmentProxy(bindings, this.#globalThis); | ||
@@ -185,3 +195,3 @@ return [ | ||
return { | ||
execute: () => initialize?.(moduleEnvironmentProxy, _context), | ||
execute: () => execute?.(moduleEnvironmentProxy, _context), | ||
setters, | ||
@@ -196,2 +206,3 @@ }; | ||
} | ||
delete Compartment._; | ||
function makeModuleEnvironmentProxy(bindings, globalThis) { | ||
@@ -198,0 +209,0 @@ const systemImports = []; |
@@ -1,4 +0,3 @@ | ||
export type { Binding, ImportBinding, ExportBinding, CompartmentOptions, ModuleDescriptor, ModuleDescriptor_Source, ModuleDescriptor_ModuleInstance, ModuleDescriptor_FullSpecReference, ModuleDescriptor_StaticModuleRecord, ModuleNamespace, SyntheticModuleRecord, SyntheticModuleRecordInitializeContext, } from './types.js'; | ||
export type { Binding, ImportBinding, ExportBinding, CompartmentOptions, ModuleDescriptor, ModuleDescriptor_Source, ModuleDescriptor_ModuleInstance, ModuleDescriptor_FullSpecReference, ModuleDescriptor_StaticModuleRecord, ModuleNamespace, VirtualModuleRecord, VirtualModuleRecordExecuteContext, } from './types.js'; | ||
export { Compartment } from './compartment.js'; | ||
export { StaticModuleRecord } from './StaticModuleRecord.js'; | ||
export { ModuleSource } from './ModuleSource.js'; | ||
@@ -5,0 +4,0 @@ export { Evaluators } from './Evaluators.js'; |
export { Compartment } from './compartment.js'; | ||
export { StaticModuleRecord } from './StaticModuleRecord.js'; | ||
export { ModuleSource } from './ModuleSource.js'; | ||
@@ -4,0 +3,0 @@ export { Evaluators } from './Evaluators.js'; |
import type { ModuleSource } from './ModuleSource.js'; | ||
import type { ModuleNamespace, SyntheticModuleRecord } from './types.js'; | ||
export declare type ImportHook = (importSpecifier: string, importMeta: object) => PromiseLike<Module | null>; | ||
import type { ModuleNamespace, VirtualModuleRecord } from './types.js'; | ||
export declare type ImportHook = (importSpecifier: string, importMeta: object) => PromiseLike<Module | null> | Module | null; | ||
export declare let imports: (specifier: Module, options?: ImportCallOptions) => Promise<ModuleNamespace>; | ||
export interface ModuleConstructorOptions { | ||
importHook?: ImportHook | undefined; | ||
importMeta?: object | undefined; | ||
} | ||
export declare class Module { | ||
#private; | ||
constructor(source: ModuleSource | SyntheticModuleRecord, importHook: ImportHook, importMeta: object); | ||
constructor(source: ModuleSource | VirtualModuleRecord, options?: ModuleConstructorOptions); | ||
get source(): ModuleSource | VirtualModuleRecord | null; | ||
} | ||
//# sourceMappingURL=Module.d.ts.map |
import { all, ambiguous, empty, namespace, PromiseCapability, } from './utils/spec.js'; | ||
import { normalizeBindingsToSpecRecord, normalizeSyntheticModuleRecord } from './utils/normalize.js'; | ||
import { normalizeBindingsToSpecRecord, normalizeVirtualModuleRecord } from './utils/normalize.js'; | ||
import { assert, internalError, opaqueProxy } from './utils/assert.js'; | ||
@@ -10,3 +10,4 @@ export let imports; | ||
// https://tc39.es/ecma262/#sec-parsemodule | ||
constructor(source, importHook, importMeta) { | ||
constructor(source, options = {}) { | ||
const { importHook, importMeta } = options; | ||
if (typeof importHook !== 'function') | ||
@@ -18,5 +19,5 @@ throw new TypeError('importHook must be a function'); | ||
source = source; | ||
const module = normalizeSyntheticModuleRecord(source); | ||
this.#InitializeThisValue = source; | ||
this.#Initialize = module.initialize; | ||
const module = normalizeVirtualModuleRecord(source); | ||
this.#Source = source; | ||
this.#Execute = module.execute; | ||
this.#NeedsImport = module.needsImport; | ||
@@ -34,5 +35,8 @@ this.#NeedsImportMeta = module.needsImportMeta; | ||
} | ||
get source() { | ||
return this.#Source; | ||
} | ||
//#region ModuleRecord fields https://tc39.es/ecma262/#table-module-record-fields | ||
// #Realm: unknown | ||
/** first argument of initialize() */ | ||
/** first argument of execute() */ | ||
#Environment; | ||
@@ -43,6 +47,6 @@ /** result of await import(mod) */ | ||
//#endregion | ||
// #region SyntheticModuleRecord fields | ||
// *this value* when calling #Initialize. | ||
#InitializeThisValue; | ||
#Initialize; | ||
// #region VirtualModuleRecord fields | ||
// *this value* when calling #Execute. | ||
#Source; | ||
#Execute; | ||
#NeedsImportMeta; | ||
@@ -67,3 +71,3 @@ #NeedsImport; | ||
//#endregion | ||
//#region SyntheticModuleRecord methods | ||
//#region VirtualModuleRecord methods | ||
//#endregion | ||
@@ -262,5 +266,3 @@ //#region ModuleRecord methods https://tc39.es/ecma262/#table-abstract-methods-of-module-records | ||
assert(module); | ||
module.#Link(); | ||
await module.#Evaluate(); | ||
return Module.#GetModuleNamespace(module); | ||
return Module.#DynamicImportModule(module); | ||
}; | ||
@@ -272,4 +274,4 @@ } | ||
assert(!promise); | ||
if (this.#Initialize) { | ||
Reflect.apply(this.#Initialize, this.#InitializeThisValue, [env, this.#ContextObjectProxy]); | ||
if (this.#Execute) { | ||
Reflect.apply(this.#Execute, this.#Source, [env, this.#ContextObjectProxy]); | ||
} | ||
@@ -279,8 +281,7 @@ } | ||
assert(promise); | ||
if (this.#Initialize) { | ||
Promise.resolve(Reflect.apply(this.#Initialize, this.#InitializeThisValue, [env, this.#ContextObjectProxy])).then(promise.Resolve, promise.Reject); | ||
if (this.#Execute) { | ||
Promise.resolve(Reflect.apply(this.#Execute, this.#Source, [env, this.#ContextObjectProxy])).then(promise.Resolve, promise.Reject); | ||
} | ||
} | ||
this.#Initialize = undefined; | ||
this.#InitializeThisValue = undefined; | ||
this.#Execute = undefined; | ||
} | ||
@@ -602,3 +603,16 @@ // https://tc39.es/ecma262/#sec-moduledeclarationlinking | ||
//#endregion | ||
//#region Our host hook | ||
//#region Our functions / host hooks | ||
static async #DynamicImportModule(module) { | ||
if (module.#Status === ModuleStatus.evaluated) | ||
return this.#GetModuleNamespace(module); | ||
if (module.#Status === ModuleStatus.evaluatingAsync) { | ||
assert(module.#TopLevelCapability); | ||
await module.#TopLevelCapability.Promise; | ||
return Module.#GetModuleNamespace(module); | ||
} | ||
await this.#HostResolveModules(module, module.#RequestedModules); | ||
module.#Link(); | ||
await module.#Evaluate(); | ||
return Module.#GetModuleNamespace(module); | ||
} | ||
static #HostResolveModulesInner(module, spec) { | ||
@@ -611,10 +625,9 @@ const capability = PromiseCapability(); | ||
throw new SyntaxError(`Failed to resolve module '${spec}'`); | ||
if (!(#HasTLA in module)) | ||
throw new TypeError('ImportHook must return a Module instance'); | ||
// Safari: private in | ||
module.#HasTLA; | ||
// if (!(#HasTLA in module)) throw new TypeError('ImportHook must return a Module instance') | ||
await this.#HostResolveModules(module, module.#RequestedModules); | ||
return module; | ||
}, (error) => { | ||
throw new SyntaxError(`Failed to import module '${spec}'`, | ||
// @ts-expect-error | ||
{ cause: error }); | ||
throw new SyntaxError(`Failed to import module '${spec}'`, { cause: error }); | ||
}) | ||
@@ -644,8 +657,7 @@ .then(capability.Resolve, capability.Reject); | ||
//#endregion | ||
static { | ||
// Safari: static init block | ||
/** @internal */ | ||
static _ = (() => { | ||
imports = async (module, options) => { | ||
await this.#HostResolveModules(module, module.#RequestedModules); | ||
module.#Link(); | ||
await module.#Evaluate(); | ||
return Module.#GetModuleNamespace(module); | ||
return Module.#DynamicImportModule(module); | ||
}; | ||
@@ -655,4 +667,8 @@ createModuleSubclass = (globalThis, upper_importHook, upper_importMeta) => { | ||
const SubModule = class Module extends Parent { | ||
constructor(source, importHook, importMeta) { | ||
super(source, importHook ?? upper_importHook, importMeta ?? upper_importMeta); | ||
constructor(source, options = {}) { | ||
const { importHook, importMeta } = options; | ||
super(source, { | ||
importHook: importHook ?? upper_importHook, | ||
importMeta: importMeta ?? upper_importMeta, | ||
}); | ||
this.#GlobalThis = globalThis; | ||
@@ -663,4 +679,5 @@ } | ||
}; | ||
} | ||
})(); | ||
} | ||
delete Module._; | ||
var ModuleStatus; | ||
@@ -737,14 +754,41 @@ (function (ModuleStatus) { | ||
const moduleEnvExoticMethods = { | ||
getOwnPropertyDescriptor: internalError, | ||
defineProperty: internalError, | ||
deleteProperty: internalError, | ||
getPrototypeOf: internalError, | ||
has: internalError, | ||
isExtensible: internalError, | ||
ownKeys: internalError, | ||
preventExtensions: internalError, | ||
setPrototypeOf: internalError, | ||
apply: internalError, | ||
construct: internalError, | ||
set(target, p, value) { | ||
const ownDesc = Reflect.getOwnPropertyDescriptor(target, p); | ||
if (ownDesc) { | ||
// import binding | ||
if (!ownDesc.writable) | ||
return false; | ||
if (!ownDesc.set) | ||
return false; | ||
// export binding | ||
ownDesc.set(value); | ||
return true; | ||
} | ||
else { | ||
// global binding | ||
const global = Object.getPrototypeOf(target); | ||
if (!Object.hasOwn(global, p)) | ||
return false; | ||
return Reflect.set(global, p, value); | ||
} | ||
}, | ||
getOwnPropertyDescriptor: () => undefined, | ||
defineProperty() { | ||
// TODO: | ||
internalError(); | ||
}, | ||
deleteProperty() { | ||
return false; | ||
}, | ||
has() { | ||
return false; | ||
}, | ||
ownKeys() { | ||
return []; | ||
}, | ||
isExtensible: () => false, | ||
preventExtensions: () => true, | ||
getPrototypeOf: () => null, | ||
setPrototypeOf: (_, v) => v === null, | ||
}; | ||
//# sourceMappingURL=Module.js.map |
import type { Compartment } from './compartment.js'; | ||
import type { StaticModuleRecord } from './StaticModuleRecord.js'; | ||
import type { ModuleSource } from './ModuleSource.js'; | ||
export declare type Binding = ImportBinding | ExportBinding | ImportAllBinding | ExportAllBinding; | ||
@@ -36,5 +36,5 @@ /** | ||
} | ||
export interface SyntheticModuleRecord { | ||
export interface VirtualModuleRecord { | ||
bindings?: Array<Binding>; | ||
initialize?(environment: object, context?: SyntheticModuleRecordInitializeContext): void | Promise<void>; | ||
execute?(environment: any, context?: VirtualModuleRecordExecuteContext): void | Promise<void>; | ||
needsImportMeta?: boolean | undefined; | ||
@@ -45,3 +45,3 @@ needsImport?: boolean | undefined; | ||
export declare type ModuleNamespace = Record<string, unknown>; | ||
export interface SyntheticModuleRecordInitializeContext { | ||
export interface VirtualModuleRecordExecuteContext { | ||
importMeta?: object; | ||
@@ -59,3 +59,3 @@ import?(spec: string, options?: ImportCallOptions): Promise<ModuleNamespace>; | ||
export interface ModuleDescriptor_StaticModuleRecord { | ||
record: StaticModuleRecord | SyntheticModuleRecord | string; | ||
record: ModuleSource | VirtualModuleRecord | string; | ||
importMeta?: object | undefined; | ||
@@ -62,0 +62,0 @@ } |
@@ -1,8 +0,8 @@ | ||
import type { Binding, ModuleDescriptor, ModuleDescriptor_FullSpecReference, ModuleNamespace, SyntheticModuleRecord } from '../types.js'; | ||
import type { Binding, ModuleDescriptor, ModuleDescriptor_FullSpecReference, ModuleNamespace, VirtualModuleRecord } from '../types.js'; | ||
export declare function createModuleCache(): { | ||
moduleMap: Record<string, ModuleDescriptor>; | ||
addNamespace: (fullSpec: string, namespace: ModuleNamespace, bindings?: Binding[]) => void; | ||
addModuleRecord: (fullSpec: string, record: SyntheticModuleRecord, extraImportMeta?: object) => void; | ||
addModuleRecord: (fullSpec: string, record: VirtualModuleRecord, extraImportMeta?: object) => void; | ||
addAlias: (fullSpec: string, alias: ModuleDescriptor_FullSpecReference) => void; | ||
}; | ||
//# sourceMappingURL=createModuleCache.d.ts.map |
@@ -7,3 +7,3 @@ export function createModuleCache() { | ||
record: { | ||
initialize(env) { | ||
execute(env) { | ||
for (const [key, val] of Object.entries(namespace)) { | ||
@@ -10,0 +10,0 @@ env[key] = val; |
import { brandCheck_Compartment } from '../compartment.js'; | ||
import { StaticModuleRecord } from '../StaticModuleRecord.js'; | ||
import { ModuleSource } from '../ModuleSource.js'; | ||
import { unreachable } from './assert.js'; | ||
@@ -25,9 +25,9 @@ import { hasFromField, isExportAllBinding, isExportBinding, isImportAllBinding, isImportBinding, isModuleDescriptor_FullSpecReference, isModuleDescriptor_ModuleInstance, isModuleDescriptor_Source, isModuleDescriptor_StaticModuleRecord, } from './shapeCheck.js'; | ||
else if (typeof record !== 'object' || record === null) { | ||
throw new TypeError('ModuleDescriptor must be either a string, StaticModuleRecord or SyntheticModuleRecord'); | ||
throw new TypeError('ModuleDescriptor must be either a string, StaticModuleRecord or VirtualModuleRecord'); | ||
} | ||
else if (record instanceof StaticModuleRecord) { | ||
throw new TypeError('StaticModuleRecord is not supported'); | ||
else if (record instanceof ModuleSource) { | ||
throw new TypeError('ModuleSource is not supported'); | ||
} | ||
else { | ||
normalizedRecord = normalizeSyntheticModuleRecord(record); | ||
normalizedRecord = normalizeVirtualModuleRecord(record); | ||
} | ||
@@ -57,9 +57,9 @@ const copy = { | ||
/** @internal */ | ||
export function normalizeSyntheticModuleRecord(module) { | ||
const { initialize, bindings, needsImport, needsImportMeta, isAsync } = module; | ||
if (initialize !== undefined && initialize !== null && typeof initialize !== 'function') { | ||
throw new TypeError('SyntheticModuleRecord.initialize must be a function'); | ||
export function normalizeVirtualModuleRecord(module) { | ||
const { execute, bindings, needsImport, needsImportMeta, isAsync } = module; | ||
if (execute !== undefined && execute !== null && typeof execute !== 'function') { | ||
throw new TypeError('VirtualModuleRecord.execute must be a function'); | ||
} | ||
return { | ||
initialize, | ||
execute, | ||
needsImportMeta: Boolean(needsImportMeta), | ||
@@ -66,0 +66,0 @@ needsImport: Boolean(needsImport), |
{ | ||
"name": "@masknet/compartment", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"type": "module", | ||
@@ -9,5 +9,5 @@ "main": "./dist/index.js", | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": {}, | ||
"peerDependencies": {}, | ||
"devDependencies": { | ||
"@swc/core": "^1.2.222" | ||
}, | ||
"files": [ | ||
@@ -17,7 +17,3 @@ "dist", | ||
], | ||
"scripts": { | ||
"install-system.js": "node --experimental-fetch ./addSystemJS.mjs", | ||
"play": "node ./test/index.js", | ||
"build": "echo 'No build command'" | ||
} | ||
"scripts": {} | ||
} |
import { makeBorrowedGlobalThis, makeGlobalThis } from './utils/makeGlobalThis.js' | ||
import { StaticModuleRecord } from './StaticModuleRecord.js' | ||
import type { | ||
@@ -9,3 +8,3 @@ Binding, | ||
ModuleDescriptor, | ||
SyntheticModuleRecordInitializeContext, | ||
VirtualModuleRecordExecuteContext, | ||
} from './types.js' | ||
@@ -29,2 +28,3 @@ import { normalizeModuleDescriptor } from './utils/normalize.js' | ||
import { PromiseCapability } from './utils/spec.js' | ||
import { ModuleSource } from './ModuleSource.js' | ||
@@ -51,6 +51,15 @@ /** @internal */ | ||
// implementation | ||
static { | ||
brandCheck_Compartment = (compartment: Compartment) => #globalThis in compartment | ||
// Safari: static init block | ||
static _: any = (() => { | ||
// Safari: private in | ||
brandCheck_Compartment = (compartment: Compartment) => { | ||
try { | ||
compartment.#globalThis | ||
return true | ||
} catch { | ||
return false | ||
} | ||
} | ||
internalSlot_Compartment_globalThis_get = (compartment: Compartment) => compartment.#globalThis | ||
} | ||
})() | ||
#opts: CompartmentOptions | ||
@@ -168,4 +177,4 @@ #incubatorCompartment?: Compartment | ||
return this.#incubatorCompartment.#loadModuleDescriptor(desc.record) | ||
} else if (desc.record instanceof StaticModuleRecord) { | ||
throw new TypeError('StaticModuleRecord is not supported.') | ||
} else if (desc.record instanceof ModuleSource) { | ||
throw new TypeError('ModuleSource is not supported.') | ||
} else { | ||
@@ -191,3 +200,3 @@ return { type: 'record', module: desc.record, extraImportMeta: desc.importMeta } | ||
} else if (module.type === 'record') { | ||
const { initialize, bindings = [], needsImport, needsImportMeta } = module.module | ||
const { execute, bindings = [], needsImport, needsImportMeta } = module.module | ||
@@ -202,3 +211,3 @@ const { imports, moduleEnvironmentProxy, setters, init } = makeModuleEnvironmentProxy( | ||
(_export, _context) => { | ||
const context: SyntheticModuleRecordInitializeContext | undefined = | ||
const context: VirtualModuleRecordExecuteContext | undefined = | ||
needsImport || needsImportMeta ? {} : undefined | ||
@@ -210,3 +219,3 @@ if (needsImport) context!.import = _context.import | ||
return { | ||
execute: () => initialize?.(moduleEnvironmentProxy, _context), | ||
execute: () => execute?.(moduleEnvironmentProxy, _context), | ||
setters, | ||
@@ -219,2 +228,3 @@ } | ||
} | ||
delete Compartment._ | ||
@@ -221,0 +231,0 @@ function makeModuleEnvironmentProxy(bindings: readonly Binding[], globalThis: object) { |
@@ -12,7 +12,6 @@ export type { | ||
ModuleNamespace, | ||
SyntheticModuleRecord, | ||
SyntheticModuleRecordInitializeContext, | ||
VirtualModuleRecord, | ||
VirtualModuleRecordExecuteContext, | ||
} from './types.js' | ||
export { Compartment } from './compartment.js' | ||
export { StaticModuleRecord } from './StaticModuleRecord.js' | ||
export { ModuleSource } from './ModuleSource.js' | ||
@@ -19,0 +18,0 @@ export { Evaluators } from './Evaluators.js' |
import type { ModuleSource } from './ModuleSource.js' | ||
import type { ModuleNamespace, SyntheticModuleRecord, SyntheticModuleRecordInitializeContext } from './types.js' | ||
import type { ModuleNamespace, VirtualModuleRecord, VirtualModuleRecordExecuteContext } from './types.js' | ||
import { | ||
@@ -12,21 +12,26 @@ all, | ||
} from './utils/spec.js' | ||
import { normalizeBindingsToSpecRecord, normalizeSyntheticModuleRecord } from './utils/normalize.js' | ||
import { normalizeBindingsToSpecRecord, normalizeVirtualModuleRecord } from './utils/normalize.js' | ||
import { assert, internalError, opaqueProxy } from './utils/assert.js' | ||
export type ImportHook = (importSpecifier: string, importMeta: object) => PromiseLike<Module | null> | ||
export type ImportHook = (importSpecifier: string, importMeta: object) => PromiseLike<Module | null> | Module | null | ||
export let imports: (specifier: Module, options?: ImportCallOptions) => Promise<ModuleNamespace> | ||
/** @internal */ | ||
export let createModuleSubclass: (globalThis: object, importHook?: ImportHook, importMeta?: ImportMeta) => typeof Module | ||
export interface ModuleConstructorOptions { | ||
importHook?: ImportHook | undefined | ||
importMeta?: object | undefined | ||
} | ||
export class Module { | ||
// The constructor is equivalent to ParseModule in SourceTextModuleRecord | ||
// https://tc39.es/ecma262/#sec-parsemodule | ||
constructor(source: ModuleSource | SyntheticModuleRecord, importHook: ImportHook, importMeta: object) { | ||
constructor(source: ModuleSource | VirtualModuleRecord, options: ModuleConstructorOptions = {}) { | ||
const { importHook, importMeta } = options | ||
if (typeof importHook !== 'function') throw new TypeError('importHook must be a function') | ||
if (typeof importMeta !== 'object') throw new TypeError('importMeta must be an object') | ||
// impossible to create a ModuleSource instance | ||
source = source as SyntheticModuleRecord | ||
source = source as VirtualModuleRecord | ||
const module = normalizeSyntheticModuleRecord(source) | ||
this.#InitializeThisValue = source | ||
this.#Initialize = module.initialize | ||
const module = normalizeVirtualModuleRecord(source) | ||
this.#Source = source | ||
this.#Execute = module.execute | ||
this.#NeedsImport = module.needsImport | ||
@@ -47,5 +52,8 @@ this.#NeedsImportMeta = module.needsImportMeta | ||
} | ||
get source(): ModuleSource | VirtualModuleRecord | null { | ||
return this.#Source | ||
} | ||
//#region ModuleRecord fields https://tc39.es/ecma262/#table-module-record-fields | ||
// #Realm: unknown | ||
/** first argument of initialize() */ | ||
/** first argument of execute() */ | ||
#Environment: object | undefined | ||
@@ -57,10 +65,10 @@ /** result of await import(mod) */ | ||
// #region SyntheticModuleRecord fields | ||
// *this value* when calling #Initialize. | ||
#InitializeThisValue: unknown | ||
#Initialize: SyntheticModuleRecord['initialize'] | ||
// #region VirtualModuleRecord fields | ||
// *this value* when calling #Execute. | ||
#Source: VirtualModuleRecord | ||
#Execute: VirtualModuleRecord['execute'] | ||
#NeedsImportMeta: boolean | undefined | ||
#NeedsImport: boolean | undefined | ||
#ContextObject: SyntheticModuleRecordInitializeContext | undefined | ||
#ContextObjectProxy: SyntheticModuleRecordInitializeContext | undefined | ||
#ContextObject: VirtualModuleRecordExecuteContext | undefined | ||
#ContextObjectProxy: VirtualModuleRecordExecuteContext | undefined | ||
#ImportHook: ImportHook | ||
@@ -82,3 +90,3 @@ #AssignedImportMeta: object | ||
//#region SyntheticModuleRecord methods | ||
//#region VirtualModuleRecord methods | ||
//#endregion | ||
@@ -284,5 +292,3 @@ | ||
assert(module) | ||
module.#Link() | ||
await module.#Evaluate() | ||
return Module.#GetModuleNamespace(module) | ||
return Module.#DynamicImportModule(module) | ||
} | ||
@@ -296,15 +302,15 @@ } | ||
assert(!promise) | ||
if (this.#Initialize) { | ||
Reflect.apply(this.#Initialize, this.#InitializeThisValue, [env, this.#ContextObjectProxy]) | ||
if (this.#Execute) { | ||
Reflect.apply(this.#Execute, this.#Source, [env, this.#ContextObjectProxy]) | ||
} | ||
} else { | ||
assert(promise) | ||
if (this.#Initialize) { | ||
Promise.resolve( | ||
Reflect.apply(this.#Initialize, this.#InitializeThisValue, [env, this.#ContextObjectProxy]), | ||
).then(promise.Resolve, promise.Reject) | ||
if (this.#Execute) { | ||
Promise.resolve(Reflect.apply(this.#Execute, this.#Source, [env, this.#ContextObjectProxy])).then( | ||
promise.Resolve, | ||
promise.Reject, | ||
) | ||
} | ||
} | ||
this.#Initialize = undefined! | ||
this.#InitializeThisValue = undefined | ||
this.#Execute = undefined! | ||
} | ||
@@ -640,3 +646,16 @@ // https://tc39.es/ecma262/#sec-moduledeclarationlinking | ||
//#region Our host hook | ||
//#region Our functions / host hooks | ||
static async #DynamicImportModule(module: Module) { | ||
if (module.#Status === ModuleStatus.evaluated) return this.#GetModuleNamespace(module) | ||
if (module.#Status === ModuleStatus.evaluatingAsync) { | ||
assert(module.#TopLevelCapability) | ||
await module.#TopLevelCapability.Promise | ||
return Module.#GetModuleNamespace(module) | ||
} | ||
await this.#HostResolveModules(module, module.#RequestedModules) | ||
module.#Link() | ||
await module.#Evaluate() | ||
return Module.#GetModuleNamespace(module) | ||
} | ||
static #HostResolveModulesInner(module: Module, spec: string) { | ||
@@ -650,3 +669,5 @@ const capability = PromiseCapability<Module>() | ||
throw new SyntaxError(`Failed to resolve module '${spec}'`) | ||
if (!(#HasTLA in module)) throw new TypeError('ImportHook must return a Module instance') | ||
// Safari: private in | ||
module.#HasTLA | ||
// if (!(#HasTLA in module)) throw new TypeError('ImportHook must return a Module instance') | ||
await this.#HostResolveModules(module, module.#RequestedModules) | ||
@@ -656,7 +677,3 @@ return module | ||
(error) => { | ||
throw new SyntaxError( | ||
`Failed to import module '${spec}'`, | ||
// @ts-expect-error | ||
{ cause: error }, | ||
) | ||
throw new SyntaxError(`Failed to import module '${spec}'`, { cause: error }) | ||
}, | ||
@@ -684,8 +701,7 @@ ) | ||
//#endregion | ||
static { | ||
// Safari: static init block | ||
/** @internal */ | ||
static _: any = (() => { | ||
imports = async (module, options) => { | ||
await this.#HostResolveModules(module, module.#RequestedModules) | ||
module.#Link() | ||
await module.#Evaluate() | ||
return Module.#GetModuleNamespace(module) | ||
return Module.#DynamicImportModule(module) | ||
} | ||
@@ -695,4 +711,8 @@ createModuleSubclass = (globalThis, upper_importHook, upper_importMeta) => { | ||
const SubModule = class Module extends Parent { | ||
constructor(source: ModuleSource | SyntheticModuleRecord, importHook: ImportHook, importMeta: object) { | ||
super(source, importHook ?? upper_importHook, importMeta ?? upper_importMeta) | ||
constructor(source: ModuleSource | VirtualModuleRecord, options: ModuleConstructorOptions = {}) { | ||
const { importHook, importMeta } = options | ||
super(source, { | ||
importHook: importHook ?? upper_importHook, | ||
importMeta: importMeta ?? upper_importMeta, | ||
}) | ||
this.#GlobalThis = globalThis | ||
@@ -703,4 +723,5 @@ } | ||
} | ||
} | ||
})() | ||
} | ||
delete Module._ | ||
@@ -772,13 +793,36 @@ const enum ModuleStatus { | ||
const moduleEnvExoticMethods: ProxyHandler<any> = { | ||
getOwnPropertyDescriptor: internalError, | ||
defineProperty: internalError, | ||
deleteProperty: internalError, | ||
getPrototypeOf: internalError, | ||
has: internalError, | ||
isExtensible: internalError, | ||
ownKeys: internalError, | ||
preventExtensions: internalError, | ||
setPrototypeOf: internalError, | ||
apply: internalError, | ||
construct: internalError, | ||
set(target, p, value) { | ||
const ownDesc = Reflect.getOwnPropertyDescriptor(target, p) | ||
if (ownDesc) { | ||
// import binding | ||
if (!ownDesc.writable) return false | ||
if (!ownDesc.set) return false | ||
// export binding | ||
ownDesc.set(value) | ||
return true | ||
} else { | ||
// global binding | ||
const global = Object.getPrototypeOf(target) | ||
if (!Object.hasOwn(global, p)) return false | ||
return Reflect.set(global, p, value) | ||
} | ||
}, | ||
getOwnPropertyDescriptor: () => undefined, | ||
defineProperty() { | ||
// TODO: | ||
internalError() | ||
}, | ||
deleteProperty() { | ||
return false | ||
}, | ||
has() { | ||
return false | ||
}, | ||
ownKeys() { | ||
return [] | ||
}, | ||
isExtensible: () => false, | ||
preventExtensions: () => true, | ||
getPrototypeOf: () => null, | ||
setPrototypeOf: (_, v) => v === null, | ||
} |
// https://github.com/tc39/proposal-compartments/blob/775024d93830ee6464363b4b373d9353425a0776/README.md | ||
import type { Compartment } from './compartment.js' | ||
import type { StaticModuleRecord } from './StaticModuleRecord.js' | ||
import type { ModuleSource } from './ModuleSource.js' | ||
@@ -38,5 +38,5 @@ export type Binding = ImportBinding | ExportBinding | ImportAllBinding | ExportAllBinding | ||
} | ||
export interface SyntheticModuleRecord { | ||
export interface VirtualModuleRecord { | ||
bindings?: Array<Binding> | ||
initialize?(environment: object, context?: SyntheticModuleRecordInitializeContext): void | Promise<void> | ||
execute?(environment: any, context?: VirtualModuleRecordExecuteContext): void | Promise<void> | ||
needsImportMeta?: boolean | undefined | ||
@@ -48,3 +48,3 @@ needsImport?: boolean | undefined | ||
export type ModuleNamespace = Record<string, unknown> | ||
export interface SyntheticModuleRecordInitializeContext { | ||
export interface VirtualModuleRecordExecuteContext { | ||
importMeta?: object | ||
@@ -69,3 +69,3 @@ import?(spec: string, options?: ImportCallOptions): Promise<ModuleNamespace> | ||
export interface ModuleDescriptor_StaticModuleRecord { | ||
record: StaticModuleRecord | SyntheticModuleRecord | string | ||
record: ModuleSource | VirtualModuleRecord | string | ||
importMeta?: object | undefined | ||
@@ -106,2 +106,2 @@ } | ||
| { type: 'instance'; moduleInstance: ModuleNamespace } | ||
| { type: 'record'; module: SyntheticModuleRecord; extraImportMeta: object | null | undefined } | ||
| { type: 'record'; module: VirtualModuleRecord; extraImportMeta: object | null | undefined } |
@@ -6,3 +6,3 @@ import type { | ||
ModuleNamespace, | ||
SyntheticModuleRecord, | ||
VirtualModuleRecord, | ||
} from '../types.js' | ||
@@ -17,3 +17,3 @@ | ||
record: { | ||
initialize(env: any) { | ||
execute(env: any) { | ||
for (const [key, val] of Object.entries(namespace)) { | ||
@@ -30,3 +30,3 @@ env[key] = val | ||
} | ||
function addModuleRecord(fullSpec: string, record: SyntheticModuleRecord, extraImportMeta?: object) { | ||
function addModuleRecord(fullSpec: string, record: VirtualModuleRecord, extraImportMeta?: object) { | ||
moduleMap[fullSpec] = { record, importMeta: extraImportMeta } | ||
@@ -33,0 +33,0 @@ } |
import { brandCheck_Compartment } from '../compartment.js' | ||
import { StaticModuleRecord } from '../StaticModuleRecord.js' | ||
import { ModuleSource } from '../ModuleSource.js' | ||
import type { | ||
@@ -7,3 +7,3 @@ ModuleDescriptor, | ||
ModuleDescriptor_StaticModuleRecord, | ||
SyntheticModuleRecord, | ||
VirtualModuleRecord, | ||
ModuleDescriptor_ModuleInstance, | ||
@@ -44,7 +44,7 @@ Binding, | ||
} else if (typeof record !== 'object' || record === null) { | ||
throw new TypeError('ModuleDescriptor must be either a string, StaticModuleRecord or SyntheticModuleRecord') | ||
} else if (record instanceof StaticModuleRecord) { | ||
throw new TypeError('StaticModuleRecord is not supported') | ||
throw new TypeError('ModuleDescriptor must be either a string, StaticModuleRecord or VirtualModuleRecord') | ||
} else if (record instanceof ModuleSource) { | ||
throw new TypeError('ModuleSource is not supported') | ||
} else { | ||
normalizedRecord = normalizeSyntheticModuleRecord(record) | ||
normalizedRecord = normalizeVirtualModuleRecord(record) | ||
} | ||
@@ -72,9 +72,9 @@ const copy: ModuleDescriptor_StaticModuleRecord = { | ||
/** @internal */ | ||
export function normalizeSyntheticModuleRecord(module: SyntheticModuleRecord): SyntheticModuleRecord { | ||
const { initialize, bindings, needsImport, needsImportMeta, isAsync } = module | ||
if (initialize !== undefined && initialize !== null && typeof initialize !== 'function') { | ||
throw new TypeError('SyntheticModuleRecord.initialize must be a function') | ||
export function normalizeVirtualModuleRecord(module: VirtualModuleRecord): VirtualModuleRecord { | ||
const { execute, bindings, needsImport, needsImportMeta, isAsync } = module | ||
if (execute !== undefined && execute !== null && typeof execute !== 'function') { | ||
throw new TypeError('VirtualModuleRecord.execute must be a function') | ||
} | ||
return { | ||
initialize, | ||
execute, | ||
needsImportMeta: Boolean(needsImportMeta), | ||
@@ -81,0 +81,0 @@ needsImport: Boolean(needsImport), |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
297532
4917
1
79