diff options
author | 2023-07-11 19:14:34 -0700 | |
---|---|---|
committer | 2023-07-11 19:14:34 -0700 | |
commit | cbb88672f217a90db1aa1eb29cd92d5d9035b22b (patch) | |
tree | 43a00501f3cde495967e116f0b660777051551f8 /src/js/builtins/ImportMetaObject.ts | |
parent | 1f900cff453700b19bca2acadfe26da4468c1282 (diff) | |
parent | 34b0e7a2bbd8bf8097341cdb0075d0908283e834 (diff) | |
download | bun-jarred/esm-conditions.tar.gz bun-jarred/esm-conditions.tar.zst bun-jarred/esm-conditions.zip |
Merge branch 'main' into jarred/esm-conditionsjarred/esm-conditions
Diffstat (limited to '')
-rw-r--r-- | src/js/builtins/ImportMetaObject.ts | 214 |
1 files changed, 86 insertions, 128 deletions
diff --git a/src/js/builtins/ImportMetaObject.ts b/src/js/builtins/ImportMetaObject.ts index 7fc8b5fe8..934a37881 100644 --- a/src/js/builtins/ImportMetaObject.ts +++ b/src/js/builtins/ImportMetaObject.ts @@ -8,9 +8,9 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) { // we need to explicitly check because state could be $ModuleFetch // it will throw this error if we do not: // $throwTypeError("Requested module is already fetched."); - var entry = loader.registry.$get(key); + var entry = loader.registry.$get(key)!; - if (!entry || !entry.state || entry.state <= $ModuleFetch) { + if ((entry?.state ?? 0) <= $ModuleFetch) { $fulfillModuleSync(key); entry = loader.registry.$get(key)!; } @@ -24,14 +24,14 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) { // so we just pull it out of the promise here once again // But, this time we do it a little more carefully because this is a JSC function call and not bun source code var moduleRecordPromise = loader.parseModule(key, sourceCodeObject); - var module = entry.module; - if (!module && moduleRecordPromise && $isPromise(moduleRecordPromise)) { + var mod = entry.module; + if (moduleRecordPromise && $isPromise(moduleRecordPromise)) { var reactionsOrResult = $getPromiseInternalField(moduleRecordPromise, $promiseFieldReactionsOrResult); var flags = $getPromiseInternalField(moduleRecordPromise, $promiseFieldFlags); var state = flags & $promiseStateMask; // this branch should never happen, but just to be safe if (state === $promiseStatePending || (reactionsOrResult && $isPromise(reactionsOrResult))) { - throw new TypeError(`require() async module "${key}" is unsupported`); + throw new TypeError(`require() async module "${key}" is unsupported. use "await import()" instead.`); } else if (state === $promiseStateRejected) { if (!reactionsOrResult?.message) { throw new TypeError( @@ -43,15 +43,15 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) { throw reactionsOrResult; } - entry.module = module = reactionsOrResult; - } else if (moduleRecordPromise && !module) { - entry.module = module = moduleRecordPromise as LoaderModule; + entry.module = mod = reactionsOrResult; + } else if (moduleRecordPromise && !mod) { + entry.module = mod = moduleRecordPromise as LoaderModule; } // This is very similar to "requestInstantiate" in ModuleLoader.js in JavaScriptCore. $setStateToMax(entry, $ModuleLink); - var dependenciesMap = module.dependenciesMap; - var requestedModules = loader.requestedModules(module); + var dependenciesMap = mod.dependenciesMap; + var requestedModules = loader.requestedModules(mod); var dependencies = $newArrayWithSize<string>(requestedModules.length); for (var i = 0, length = requestedModules.length; i < length; ++i) { var depName = requestedModules[i]; @@ -59,6 +59,7 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) { // we don't need to run the resolver a 2nd time var depKey = depName[0] === "/" ? depName : loader.resolve(depName, key); var depEntry = loader.ensureRegistered(depKey); + if (depEntry.state < $ModuleLink) { queue.push(depKey); } @@ -81,7 +82,9 @@ export function loadCJS2ESM(this: ImportMetaObject, resolvedSpecifier: string) { if (linkAndEvaluateResult && $isPromise(linkAndEvaluateResult)) { // if you use top-level await, or any dependencies use top-level await, then we throw here // this means the module will still actually load eventually, but that's okay. - throw new TypeError(`require() async module \"${resolvedSpecifier}\" is unsupported`); + throw new TypeError( + `require() async module \"${resolvedSpecifier}\" is unsupported. use "await import()" instead.`, + ); } return loader.registry.$get(resolvedSpecifier); @@ -104,158 +107,113 @@ export function requireESM(this: ImportMetaObject, resolved) { return; } - var commonJS = exports.default; - var cjs = commonJS?.[$commonJSSymbol]; - if (cjs === 0) { - return commonJS; - } else if (cjs && $isCallable(commonJS)) { - return commonJS(); - } - return exports; } -export function internalRequire(this: ImportMetaObject, resolved) { - var cached = $requireMap.$get(resolved); - const last5 = resolved.substring(resolved.length - 5); +export function internalRequire(this: ImportMetaObject, id) { + var cached = $requireMap.$get(id); + const last5 = id.substring(id.length - 5); if (cached) { - if (last5 === ".node") { - return cached.exports; - } - return cached; + return cached.exports; } // TODO: remove this hardcoding if (last5 === ".json") { var fs = (globalThis[Symbol.for("_fs")] ||= Bun.fs()); - var exports = JSON.parse(fs.readFileSync(resolved, "utf8")); - $requireMap.$set(resolved, exports); + var exports = JSON.parse(fs.readFileSync(id, "utf8")); + $requireMap.$set(id, $createCommonJSModule(id, exports, true)); return exports; } else if (last5 === ".node") { - var module = { exports: {} }; - process.dlopen(module, resolved); - $requireMap.$set(resolved, module); + const module = $createCommonJSModule(id, {}, true); + process.dlopen(module, id); + $requireMap.$set(id, module); return module.exports; } else if (last5 === ".toml") { var fs = (globalThis[Symbol.for("_fs")] ||= Bun.fs()); - var exports = Bun.TOML.parse(fs.readFileSync(resolved, "utf8")); - $requireMap.$set(resolved, exports); + var exports = Bun.TOML.parse(fs.readFileSync(id, "utf8")); + $requireMap.$set(id, $createCommonJSModule(id, exports, true)); return exports; } else { - var exports = $requireESM(resolved); - const cachedExports = $requireMap.$get(resolved); - if (cachedExports) { - return cachedExports; + var exports = $requireESM(id); + const cachedModule = $requireMap.$get(id); + if (cachedModule) { + return cachedModule.exports; } - - $requireMap.$set(resolved, exports); + var defaultExport = exports?.default; + if (defaultExport?.[$commonJSSymbol] === 0) { + exports = defaultExport; + } + $requireMap.$set(id, $createCommonJSModule(id, exports, true)); return exports; } } export function createRequireCache() { - class Module { - id; - parent; - filename; - children = []; - paths = []; - - constructor(filename) { - this.id = filename; - // TODO: windows - const lastSlash = filename.lastIndexOf("/"); - if (lastSlash !== -1 && filename.length > lastSlash + 1) { - this.filename = filename.substring(lastSlash + 1); - } else { - this.filename = filename; + var moduleMap = new Map(); + var inner = {}; + return new Proxy(inner, { + get(target, key: string) { + const entry = $requireMap.$get(key); + if (entry) return entry; + + const esm = Loader.registry.$get(key); + if (esm?.evaluated) { + const namespace = Loader.getModuleNamespaceObject(esm.module); + const exports = + namespace[$commonJSSymbol] === 0 || namespace.default?.[$commonJSSymbol] ? namespace.default : namespace; + const mod = $createCommonJSModule(key, exports, true); + $requireMap.$set(key, mod); + return mod; } - } - get loaded() { + return inner[key]; + }, + set(target, key: string, value) { + $requireMap.$set(key, value); return true; - } - - require(path) { - return $internalRequire($resolveSync(path, this.id)); - } - - get exports() { - return $requireMap.$get(this.id) ?? {}; - } + }, - set exports(value) { - $requireMap.$set(this.id, value); - } - } + has(target, key: string) { + return $requireMap.$has(key) || Loader.registry.$has(key); + }, - var moduleMap = new Map(); + deleteProperty(target, key: string) { + moduleMap.$delete(key); + $requireMap.$delete(key); + Loader.registry.$delete(key); + return true; + }, - return new Proxy( - {}, - { - get(target, key: string) { - const entry = $requireMap.$get(key); - if (entry) { - var mod = moduleMap.$get(key); - if (!mod) { - mod = new Module(key); - moduleMap.$set(key, mod); - } - return mod; - } - }, - set(target, key: string, value) { - if (!moduleMap.$has(key)) { - moduleMap.$set(key, new Module(key)); + ownKeys(target) { + var array = [...$requireMap.$keys()]; + const registryKeys = [...Loader.registry.$keys()]; + for (const key of registryKeys) { + if (!array.includes(key)) { + $arrayPush(array, key); } + } - $requireMap.$set(key, value?.exports); - - return true; - }, - - has(target, key: string) { - return $requireMap.$has(key); - }, - - deleteProperty(target, key: string) { - moduleMap.$delete(key); - $requireMap.$delete(key); - Loader.registry.$delete(key); - return true; - }, - - ownKeys(target) { - return [...$requireMap.$keys()]; - }, + return array; + }, - // In Node, require.cache has a null prototype - getPrototypeOf(target) { - return null; - }, + // In Node, require.cache has a null prototype + getPrototypeOf(target) { + return null; + }, - getOwnPropertyDescriptor(target, key: string) { - if ($requireMap.$has(key)) { - return { - configurable: true, - enumerable: true, - }; - } - }, + getOwnPropertyDescriptor(target, key: string) { + if ($requireMap.$has(key) || Loader.registry.$has(key)) { + return { + configurable: true, + enumerable: true, + }; + } }, - ); + }); } -$sloppy; -export function require(this: ImportMetaObject, name) { - var from = this?.path ?? arguments.callee.path; - - if (typeof name !== "string") { - throw new TypeError("require(name) must be a string"); - } - - return $internalRequire($resolveSync(name, from)); +export function require(this: string, name) { + return $internalRequire($resolveSync(name, $toString(this), false)); } $getter; |