mirror of
https://github.com/denoland/deno.git
synced 2024-11-26 16:09:27 -05:00
f57745fe21
- upgrade to v8 12.8 - optimizes DataView bigint methods - fixes global interceptors - includes CPED methods for ALS - fix global resolution - makes global resolution consistent using host_defined_options. originally a separate patch but due to the global interceptor bug it needs to be included in this pr for all tests to pass.
1310 lines
37 KiB
JavaScript
1310 lines
37 KiB
JavaScript
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
|
|
// deno-lint-ignore-file
|
|
|
|
import { core, internals, primordials } from "ext:core/mod.js";
|
|
import {
|
|
op_napi_open,
|
|
op_require_as_file_path,
|
|
op_require_break_on_next_statement,
|
|
op_require_init_paths,
|
|
op_require_is_deno_dir_package,
|
|
op_require_is_request_relative,
|
|
op_require_node_module_paths,
|
|
op_require_package_imports_resolve,
|
|
op_require_path_basename,
|
|
op_require_path_dirname,
|
|
op_require_path_is_absolute,
|
|
op_require_path_resolve,
|
|
op_require_proxy_path,
|
|
op_require_read_closest_package_json,
|
|
op_require_read_file,
|
|
op_require_read_package_scope,
|
|
op_require_real_path,
|
|
op_require_resolve_deno_dir,
|
|
op_require_resolve_exports,
|
|
op_require_resolve_lookup_paths,
|
|
op_require_stat,
|
|
op_require_try_self,
|
|
op_require_try_self_parent_path,
|
|
} from "ext:core/ops";
|
|
const {
|
|
ArrayIsArray,
|
|
ArrayPrototypeIncludes,
|
|
ArrayPrototypeIndexOf,
|
|
ArrayPrototypeJoin,
|
|
ArrayPrototypePush,
|
|
ArrayPrototypeSlice,
|
|
ArrayPrototypeSplice,
|
|
Error,
|
|
JSONParse,
|
|
ObjectCreate,
|
|
ObjectEntries,
|
|
ObjectGetOwnPropertyDescriptor,
|
|
ObjectGetPrototypeOf,
|
|
ObjectHasOwn,
|
|
ObjectKeys,
|
|
ObjectPrototype,
|
|
ObjectSetPrototypeOf,
|
|
Proxy,
|
|
RegExpPrototypeTest,
|
|
SafeArrayIterator,
|
|
SafeMap,
|
|
SafeWeakMap,
|
|
String,
|
|
StringPrototypeCharCodeAt,
|
|
StringPrototypeEndsWith,
|
|
StringPrototypeIncludes,
|
|
StringPrototypeIndexOf,
|
|
StringPrototypeMatch,
|
|
StringPrototypeSlice,
|
|
StringPrototypeSplit,
|
|
StringPrototypeStartsWith,
|
|
TypeError,
|
|
} = primordials;
|
|
|
|
import { nodeGlobals } from "ext:deno_node/00_globals.js";
|
|
|
|
import _httpAgent from "ext:deno_node/_http_agent.mjs";
|
|
import _httpOutgoing from "ext:deno_node/_http_outgoing.ts";
|
|
import _streamDuplex from "ext:deno_node/internal/streams/duplex.mjs";
|
|
import _streamPassthrough from "ext:deno_node/internal/streams/passthrough.mjs";
|
|
import _streamReadable from "ext:deno_node/internal/streams/readable.mjs";
|
|
import _streamTransform from "ext:deno_node/internal/streams/transform.mjs";
|
|
import _streamWritable from "ext:deno_node/internal/streams/writable.mjs";
|
|
import assert from "node:assert";
|
|
import assertStrict from "node:assert/strict";
|
|
import asyncHooks from "node:async_hooks";
|
|
import buffer from "node:buffer";
|
|
import childProcess from "node:child_process";
|
|
import cluster from "node:cluster";
|
|
import console from "node:console";
|
|
import constants from "node:constants";
|
|
import crypto from "node:crypto";
|
|
import dgram from "node:dgram";
|
|
import diagnosticsChannel from "node:diagnostics_channel";
|
|
import dns from "node:dns";
|
|
import dnsPromises from "node:dns/promises";
|
|
import domain from "node:domain";
|
|
import events from "node:events";
|
|
import fs from "node:fs";
|
|
import fsPromises from "node:fs/promises";
|
|
import http from "node:http";
|
|
import http2 from "node:http2";
|
|
import https from "node:https";
|
|
import inspector from "ext:deno_node/inspector.ts";
|
|
import internalCp from "ext:deno_node/internal/child_process.ts";
|
|
import internalCryptoCertificate from "ext:deno_node/internal/crypto/certificate.ts";
|
|
import internalCryptoCipher from "ext:deno_node/internal/crypto/cipher.ts";
|
|
import internalCryptoDiffiehellman from "ext:deno_node/internal/crypto/diffiehellman.ts";
|
|
import internalCryptoHash from "ext:deno_node/internal/crypto/hash.ts";
|
|
import internalCryptoHkdf from "ext:deno_node/internal/crypto/hkdf.ts";
|
|
import internalCryptoKeygen from "ext:deno_node/internal/crypto/keygen.ts";
|
|
import internalCryptoKeys from "ext:deno_node/internal/crypto/keys.ts";
|
|
import internalCryptoPbkdf2 from "ext:deno_node/internal/crypto/pbkdf2.ts";
|
|
import internalCryptoRandom from "ext:deno_node/internal/crypto/random.ts";
|
|
import internalCryptoScrypt from "ext:deno_node/internal/crypto/scrypt.ts";
|
|
import internalCryptoSig from "ext:deno_node/internal/crypto/sig.ts";
|
|
import internalCryptoUtil from "ext:deno_node/internal/crypto/util.ts";
|
|
import internalCryptoX509 from "ext:deno_node/internal/crypto/x509.ts";
|
|
import internalDgram from "ext:deno_node/internal/dgram.ts";
|
|
import internalDnsPromises from "ext:deno_node/internal/dns/promises.ts";
|
|
import internalErrors from "ext:deno_node/internal/errors.ts";
|
|
import internalEventTarget from "ext:deno_node/internal/event_target.mjs";
|
|
import internalFsUtils from "ext:deno_node/internal/fs/utils.mjs";
|
|
import internalHttp from "ext:deno_node/internal/http.ts";
|
|
import internalReadlineUtils from "ext:deno_node/internal/readline/utils.mjs";
|
|
import internalStreamsAddAbortSignal from "ext:deno_node/internal/streams/add-abort-signal.mjs";
|
|
import internalStreamsBufferList from "ext:deno_node/internal/streams/buffer_list.mjs";
|
|
import internalStreamsLazyTransform from "ext:deno_node/internal/streams/lazy_transform.mjs";
|
|
import internalStreamsState from "ext:deno_node/internal/streams/state.mjs";
|
|
import internalTestBinding from "ext:deno_node/internal/test/binding.ts";
|
|
import internalTimers from "ext:deno_node/internal/timers.mjs";
|
|
import internalUtil from "ext:deno_node/internal/util.mjs";
|
|
import internalUtilInspect from "ext:deno_node/internal/util/inspect.mjs";
|
|
import net from "node:net";
|
|
import os from "node:os";
|
|
import pathPosix from "node:path/posix";
|
|
import pathWin32 from "node:path/win32";
|
|
import path from "node:path";
|
|
import perfHooks from "node:perf_hooks";
|
|
import punycode from "node:punycode";
|
|
import process from "node:process";
|
|
import querystring from "node:querystring";
|
|
import readline from "node:readline";
|
|
import readlinePromises from "node:readline/promises";
|
|
import repl from "node:repl";
|
|
import stream from "node:stream";
|
|
import streamConsumers from "node:stream/consumers";
|
|
import streamPromises from "node:stream/promises";
|
|
import streamWeb from "node:stream/web";
|
|
import stringDecoder from "node:string_decoder";
|
|
import sys from "node:sys";
|
|
import test from "node:test";
|
|
import timers from "node:timers";
|
|
import timersPromises from "node:timers/promises";
|
|
import tls from "node:tls";
|
|
import tty from "node:tty";
|
|
import url from "node:url";
|
|
import utilTypes from "node:util/types";
|
|
import util from "node:util";
|
|
import v8 from "node:v8";
|
|
import vm from "node:vm";
|
|
import workerThreads from "node:worker_threads";
|
|
import wasi from "ext:deno_node/wasi.ts";
|
|
import zlib from "node:zlib";
|
|
|
|
const nativeModuleExports = ObjectCreate(null);
|
|
const builtinModules = [];
|
|
|
|
// NOTE(bartlomieju): keep this list in sync with `ext/node/polyfill.rs`
|
|
function setupBuiltinModules() {
|
|
const nodeModules = {
|
|
"_http_agent": _httpAgent,
|
|
"_http_outgoing": _httpOutgoing,
|
|
"_stream_duplex": _streamDuplex,
|
|
"_stream_passthrough": _streamPassthrough,
|
|
"_stream_readable": _streamReadable,
|
|
"_stream_transform": _streamTransform,
|
|
"_stream_writable": _streamWritable,
|
|
assert,
|
|
"assert/strict": assertStrict,
|
|
"async_hooks": asyncHooks,
|
|
buffer,
|
|
crypto,
|
|
console,
|
|
constants,
|
|
child_process: childProcess,
|
|
cluster,
|
|
dgram,
|
|
diagnostics_channel: diagnosticsChannel,
|
|
dns,
|
|
"dns/promises": dnsPromises,
|
|
domain,
|
|
events,
|
|
fs,
|
|
"fs/promises": fsPromises,
|
|
http,
|
|
http2,
|
|
https,
|
|
inspector,
|
|
"internal/child_process": internalCp,
|
|
"internal/crypto/certificate": internalCryptoCertificate,
|
|
"internal/crypto/cipher": internalCryptoCipher,
|
|
"internal/crypto/diffiehellman": internalCryptoDiffiehellman,
|
|
"internal/crypto/hash": internalCryptoHash,
|
|
"internal/crypto/hkdf": internalCryptoHkdf,
|
|
"internal/crypto/keygen": internalCryptoKeygen,
|
|
"internal/crypto/keys": internalCryptoKeys,
|
|
"internal/crypto/pbkdf2": internalCryptoPbkdf2,
|
|
"internal/crypto/random": internalCryptoRandom,
|
|
"internal/crypto/scrypt": internalCryptoScrypt,
|
|
"internal/crypto/sig": internalCryptoSig,
|
|
"internal/crypto/util": internalCryptoUtil,
|
|
"internal/crypto/x509": internalCryptoX509,
|
|
"internal/dgram": internalDgram,
|
|
"internal/dns/promises": internalDnsPromises,
|
|
"internal/errors": internalErrors,
|
|
"internal/event_target": internalEventTarget,
|
|
"internal/fs/utils": internalFsUtils,
|
|
"internal/http": internalHttp,
|
|
"internal/readline/utils": internalReadlineUtils,
|
|
"internal/streams/add-abort-signal": internalStreamsAddAbortSignal,
|
|
"internal/streams/buffer_list": internalStreamsBufferList,
|
|
"internal/streams/lazy_transform": internalStreamsLazyTransform,
|
|
"internal/streams/state": internalStreamsState,
|
|
"internal/test/binding": internalTestBinding,
|
|
"internal/timers": internalTimers,
|
|
"internal/util/inspect": internalUtilInspect,
|
|
"internal/util": internalUtil,
|
|
net,
|
|
module: Module,
|
|
os,
|
|
"path/posix": pathPosix,
|
|
"path/win32": pathWin32,
|
|
path,
|
|
perf_hooks: perfHooks,
|
|
process,
|
|
get punycode() {
|
|
process.emitWarning(
|
|
"The `punycode` module is deprecated. Please use a userland " +
|
|
"alternative instead.",
|
|
"DeprecationWarning",
|
|
"DEP0040",
|
|
);
|
|
return punycode;
|
|
},
|
|
querystring,
|
|
readline,
|
|
"readline/promises": readlinePromises,
|
|
repl,
|
|
stream,
|
|
"stream/consumers": streamConsumers,
|
|
"stream/promises": streamPromises,
|
|
"stream/web": streamWeb,
|
|
string_decoder: stringDecoder,
|
|
sys,
|
|
test,
|
|
timers,
|
|
"timers/promises": timersPromises,
|
|
tls,
|
|
tty,
|
|
url,
|
|
util,
|
|
"util/types": utilTypes,
|
|
v8,
|
|
vm,
|
|
wasi,
|
|
worker_threads: workerThreads,
|
|
zlib,
|
|
};
|
|
for (const [name, moduleExports] of ObjectEntries(nodeModules)) {
|
|
nativeModuleExports[name] = moduleExports;
|
|
ArrayPrototypePush(builtinModules, name);
|
|
}
|
|
}
|
|
setupBuiltinModules();
|
|
|
|
function pathDirname(filepath) {
|
|
if (filepath == null) {
|
|
throw new Error("Empty filepath.");
|
|
} else if (filepath === "") {
|
|
return ".";
|
|
}
|
|
return op_require_path_dirname(filepath);
|
|
}
|
|
|
|
function pathResolve(...args) {
|
|
return op_require_path_resolve(args);
|
|
}
|
|
|
|
const nativeModulePolyfill = new SafeMap();
|
|
|
|
const relativeResolveCache = ObjectCreate(null);
|
|
let requireDepth = 0;
|
|
let statCache = null;
|
|
let mainModule = null;
|
|
let hasBrokenOnInspectBrk = false;
|
|
let hasInspectBrk = false;
|
|
// Are we running with --node-modules-dir flag or byonm?
|
|
let usesLocalNodeModulesDir = false;
|
|
|
|
function stat(filename) {
|
|
// TODO: required only on windows
|
|
// filename = path.toNamespacedPath(filename);
|
|
if (statCache !== null) {
|
|
const result = statCache.get(filename);
|
|
if (result !== undefined) {
|
|
return result;
|
|
}
|
|
}
|
|
const result = op_require_stat(filename);
|
|
if (statCache !== null && result >= 0) {
|
|
statCache.set(filename, result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function updateChildren(parent, child, scan) {
|
|
if (!parent) {
|
|
return;
|
|
}
|
|
|
|
const children = parent.children;
|
|
if (children && !(scan && ArrayPrototypeIncludes(children, child))) {
|
|
ArrayPrototypePush(children, child);
|
|
}
|
|
}
|
|
|
|
function tryFile(requestPath, _isMain) {
|
|
const rc = stat(requestPath);
|
|
if (rc !== 0) return;
|
|
return toRealPath(requestPath);
|
|
}
|
|
|
|
function tryPackage(requestPath, exts, isMain, originalPath) {
|
|
const packageJsonPath = pathResolve(
|
|
requestPath,
|
|
"package.json",
|
|
);
|
|
const pkg = op_require_read_package_scope(packageJsonPath)?.main;
|
|
if (!pkg) {
|
|
return tryExtensions(
|
|
pathResolve(requestPath, "index"),
|
|
exts,
|
|
isMain,
|
|
);
|
|
}
|
|
|
|
const filename = pathResolve(requestPath, pkg);
|
|
let actual = tryFile(filename, isMain) ||
|
|
tryExtensions(filename, exts, isMain) ||
|
|
tryExtensions(
|
|
pathResolve(filename, "index"),
|
|
exts,
|
|
isMain,
|
|
);
|
|
if (actual === false) {
|
|
actual = tryExtensions(
|
|
pathResolve(requestPath, "index"),
|
|
exts,
|
|
isMain,
|
|
);
|
|
if (!actual) {
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
const err = new Error(
|
|
`Cannot find module '${filename}'. ` +
|
|
'Please verify that the package.json has a valid "main" entry',
|
|
);
|
|
err.code = "MODULE_NOT_FOUND";
|
|
err.path = pathResolve(
|
|
requestPath,
|
|
"package.json",
|
|
);
|
|
err.requestPath = originalPath;
|
|
throw err;
|
|
} else {
|
|
process.emitWarning(
|
|
`Invalid 'main' field in '${packageJsonPath}' of '${pkg}'. ` +
|
|
"Please either fix that or report it to the module author",
|
|
"DeprecationWarning",
|
|
"DEP0128",
|
|
);
|
|
}
|
|
}
|
|
return actual;
|
|
}
|
|
|
|
const realpathCache = new SafeMap();
|
|
function toRealPath(requestPath) {
|
|
const maybeCached = realpathCache.get(requestPath);
|
|
if (maybeCached) {
|
|
return maybeCached;
|
|
}
|
|
const rp = op_require_real_path(requestPath);
|
|
realpathCache.set(requestPath, rp);
|
|
return rp;
|
|
}
|
|
|
|
function tryExtensions(p, exts, isMain) {
|
|
for (let i = 0; i < exts.length; i++) {
|
|
const filename = tryFile(p + exts[i], isMain);
|
|
|
|
if (filename) {
|
|
return filename;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Find the longest (possibly multi-dot) extension registered in
|
|
// Module._extensions
|
|
function findLongestRegisteredExtension(filename) {
|
|
const name = op_require_path_basename(filename);
|
|
let currentExtension;
|
|
let index;
|
|
let startIndex = 0;
|
|
while ((index = StringPrototypeIndexOf(name, ".", startIndex)) !== -1) {
|
|
startIndex = index + 1;
|
|
if (index === 0) continue; // Skip dotfiles like .gitignore
|
|
currentExtension = StringPrototypeSlice(name, index);
|
|
if (Module._extensions[currentExtension]) {
|
|
return currentExtension;
|
|
}
|
|
}
|
|
return ".js";
|
|
}
|
|
|
|
function getExportsForCircularRequire(module) {
|
|
if (
|
|
module.exports &&
|
|
ObjectGetPrototypeOf(module.exports) === ObjectPrototype &&
|
|
// Exclude transpiled ES6 modules / TypeScript code because those may
|
|
// employ unusual patterns for accessing 'module.exports'. That should
|
|
// be okay because ES6 modules have a different approach to circular
|
|
// dependencies anyway.
|
|
!module.exports.__esModule
|
|
) {
|
|
// This is later unset once the module is done loading.
|
|
ObjectSetPrototypeOf(
|
|
module.exports,
|
|
CircularRequirePrototypeWarningProxy,
|
|
);
|
|
}
|
|
|
|
return module.exports;
|
|
}
|
|
|
|
function emitCircularRequireWarning(prop) {
|
|
process.emitWarning(
|
|
`Accessing non-existent property '${String(prop)}' of module exports ` +
|
|
"inside circular dependency",
|
|
);
|
|
}
|
|
|
|
// A Proxy that can be used as the prototype of a module.exports object and
|
|
// warns when non-existent properties are accessed.
|
|
const CircularRequirePrototypeWarningProxy = new Proxy({}, {
|
|
get(target, prop) {
|
|
// Allow __esModule access in any case because it is used in the output
|
|
// of transpiled code to determine whether something comes from an
|
|
// ES module, and is not used as a regular key of `module.exports`.
|
|
if (prop in target || prop === "__esModule") return target[prop];
|
|
emitCircularRequireWarning(prop);
|
|
return undefined;
|
|
},
|
|
|
|
getOwnPropertyDescriptor(target, prop) {
|
|
if (
|
|
ObjectHasOwn(target, prop) || prop === "__esModule"
|
|
) {
|
|
return ObjectGetOwnPropertyDescriptor(target, prop);
|
|
}
|
|
emitCircularRequireWarning(prop);
|
|
return undefined;
|
|
},
|
|
});
|
|
|
|
const moduleParentCache = new SafeWeakMap();
|
|
function Module(id = "", parent) {
|
|
this.id = id;
|
|
this.path = pathDirname(id);
|
|
this.exports = {};
|
|
moduleParentCache.set(this, parent);
|
|
updateChildren(parent, this, false);
|
|
this.filename = null;
|
|
this.loaded = false;
|
|
this.parent = parent;
|
|
this.children = [];
|
|
}
|
|
|
|
Module.builtinModules = builtinModules;
|
|
|
|
Module._extensions = ObjectCreate(null);
|
|
Module._cache = ObjectCreate(null);
|
|
Module._pathCache = ObjectCreate(null);
|
|
let modulePaths = [];
|
|
Module.globalPaths = modulePaths;
|
|
|
|
const CHAR_FORWARD_SLASH = 47;
|
|
const TRAILING_SLASH_REGEX = /(?:^|\/)\.?\.$/;
|
|
|
|
// This only applies to requests of a specific form:
|
|
// 1. name/.*
|
|
// 2. @scope/name/.*
|
|
const EXPORTS_PATTERN = /^((?:@[^/\\%]+\/)?[^./\\%][^/\\%]*)(\/.*)?$/;
|
|
function resolveExports(
|
|
modulesPath,
|
|
request,
|
|
parentPath,
|
|
usesLocalNodeModulesDir,
|
|
) {
|
|
// The implementation's behavior is meant to mirror resolution in ESM.
|
|
const [, name, expansion = ""] =
|
|
StringPrototypeMatch(request, EXPORTS_PATTERN) || [];
|
|
if (!name) {
|
|
return;
|
|
}
|
|
|
|
if (!parentPath) {
|
|
return false;
|
|
}
|
|
|
|
return op_require_resolve_exports(
|
|
usesLocalNodeModulesDir,
|
|
modulesPath,
|
|
request,
|
|
name,
|
|
expansion,
|
|
parentPath,
|
|
) ?? false;
|
|
}
|
|
|
|
Module._findPath = function (request, paths, isMain, parentPath) {
|
|
const absoluteRequest = op_require_path_is_absolute(request);
|
|
if (absoluteRequest) {
|
|
paths = [""];
|
|
} else if (!paths || paths.length === 0) {
|
|
return false;
|
|
}
|
|
|
|
const cacheKey = request + "\x00" + ArrayPrototypeJoin(paths, "\x00");
|
|
const entry = Module._pathCache[cacheKey];
|
|
if (entry) {
|
|
return entry;
|
|
}
|
|
|
|
let exts;
|
|
let trailingSlash = request.length > 0 &&
|
|
StringPrototypeCharCodeAt(request, request.length - 1) ===
|
|
CHAR_FORWARD_SLASH;
|
|
if (!trailingSlash) {
|
|
trailingSlash = RegExpPrototypeTest(TRAILING_SLASH_REGEX, request);
|
|
}
|
|
|
|
// For each path
|
|
for (let i = 0; i < paths.length; i++) {
|
|
// Don't search further if path doesn't exist
|
|
const curPath = paths[i];
|
|
if (curPath && stat(curPath) < 1) continue;
|
|
|
|
if (!absoluteRequest) {
|
|
const exportsResolved = resolveExports(
|
|
curPath,
|
|
request,
|
|
parentPath,
|
|
usesLocalNodeModulesDir,
|
|
);
|
|
if (exportsResolved) {
|
|
return exportsResolved;
|
|
}
|
|
}
|
|
|
|
let basePath;
|
|
|
|
if (usesLocalNodeModulesDir) {
|
|
basePath = pathResolve(curPath, request);
|
|
} else {
|
|
const isDenoDirPackage = op_require_is_deno_dir_package(
|
|
curPath,
|
|
);
|
|
const isRelative = op_require_is_request_relative(
|
|
request,
|
|
);
|
|
basePath = (isDenoDirPackage && !isRelative)
|
|
? pathResolve(curPath, packageSpecifierSubPath(request))
|
|
: pathResolve(curPath, request);
|
|
}
|
|
let filename;
|
|
|
|
const rc = stat(basePath);
|
|
if (!trailingSlash) {
|
|
if (rc === 0) { // File.
|
|
filename = toRealPath(basePath);
|
|
}
|
|
|
|
if (!filename) {
|
|
// Try it with each of the extensions
|
|
if (exts === undefined) {
|
|
exts = ObjectKeys(Module._extensions);
|
|
}
|
|
filename = tryExtensions(basePath, exts, isMain);
|
|
}
|
|
}
|
|
|
|
if (!filename && rc === 1) { // Directory.
|
|
// try it with each of the extensions at "index"
|
|
if (exts === undefined) {
|
|
exts = ObjectKeys(Module._extensions);
|
|
}
|
|
filename = tryPackage(basePath, exts, isMain, request);
|
|
}
|
|
|
|
if (filename) {
|
|
Module._pathCache[cacheKey] = filename;
|
|
return filename;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* Get a list of potential module directories
|
|
* @param {string} fromPath The directory name of the module
|
|
* @returns {string[]} List of module directories
|
|
*/
|
|
Module._nodeModulePaths = function (fromPath) {
|
|
return op_require_node_module_paths(fromPath);
|
|
};
|
|
|
|
Module._resolveLookupPaths = function (request, parent) {
|
|
const paths = [];
|
|
|
|
if (op_require_is_request_relative(request)) {
|
|
ArrayPrototypePush(
|
|
paths,
|
|
parent?.filename ? op_require_path_dirname(parent.filename) : ".",
|
|
);
|
|
return paths;
|
|
}
|
|
|
|
if (
|
|
!usesLocalNodeModulesDir && parent?.filename && parent.filename.length > 0
|
|
) {
|
|
const denoDirPath = op_require_resolve_deno_dir(
|
|
request,
|
|
parent.filename,
|
|
);
|
|
if (denoDirPath) {
|
|
ArrayPrototypePush(paths, denoDirPath);
|
|
}
|
|
}
|
|
const lookupPathsResult = op_require_resolve_lookup_paths(
|
|
request,
|
|
parent?.paths,
|
|
parent?.filename ?? "",
|
|
);
|
|
if (lookupPathsResult) {
|
|
ArrayPrototypePush(paths, ...new SafeArrayIterator(lookupPathsResult));
|
|
}
|
|
return paths;
|
|
};
|
|
|
|
Module._load = function (request, parent, isMain) {
|
|
let relResolveCacheIdentifier;
|
|
if (parent) {
|
|
// Fast path for (lazy loaded) modules in the same directory. The indirect
|
|
// caching is required to allow cache invalidation without changing the old
|
|
// cache key names.
|
|
relResolveCacheIdentifier = `${parent.path}\x00${request}`;
|
|
const filename = relativeResolveCache[relResolveCacheIdentifier];
|
|
if (filename !== undefined) {
|
|
const cachedModule = Module._cache[filename];
|
|
if (cachedModule !== undefined) {
|
|
updateChildren(parent, cachedModule, true);
|
|
if (!cachedModule.loaded) {
|
|
return getExportsForCircularRequire(cachedModule);
|
|
}
|
|
return cachedModule.exports;
|
|
}
|
|
delete relativeResolveCache[relResolveCacheIdentifier];
|
|
}
|
|
}
|
|
|
|
const filename = Module._resolveFilename(request, parent, isMain);
|
|
if (StringPrototypeStartsWith(filename, "node:")) {
|
|
// Slice 'node:' prefix
|
|
const id = StringPrototypeSlice(filename, 5);
|
|
|
|
const module = loadNativeModule(id, id);
|
|
if (!module) {
|
|
// TODO:
|
|
// throw new ERR_UNKNOWN_BUILTIN_MODULE(filename);
|
|
throw new Error("Unknown built-in module");
|
|
}
|
|
|
|
return module.exports;
|
|
}
|
|
|
|
const cachedModule = Module._cache[filename];
|
|
if (cachedModule !== undefined) {
|
|
updateChildren(parent, cachedModule, true);
|
|
if (!cachedModule.loaded) {
|
|
return getExportsForCircularRequire(cachedModule);
|
|
}
|
|
return cachedModule.exports;
|
|
}
|
|
|
|
const mod = loadNativeModule(filename, request);
|
|
if (
|
|
mod
|
|
) {
|
|
return mod.exports;
|
|
}
|
|
// Don't call updateChildren(), Module constructor already does.
|
|
const module = cachedModule || new Module(filename, parent);
|
|
|
|
if (isMain) {
|
|
process.mainModule = module;
|
|
mainModule = module;
|
|
module.id = ".";
|
|
}
|
|
|
|
Module._cache[filename] = module;
|
|
if (parent !== undefined) {
|
|
relativeResolveCache[relResolveCacheIdentifier] = filename;
|
|
}
|
|
|
|
let threw = true;
|
|
try {
|
|
module.load(filename);
|
|
threw = false;
|
|
} finally {
|
|
if (threw) {
|
|
delete Module._cache[filename];
|
|
if (parent !== undefined) {
|
|
delete relativeResolveCache[relResolveCacheIdentifier];
|
|
const children = parent?.children;
|
|
if (ArrayIsArray(children)) {
|
|
const index = ArrayPrototypeIndexOf(children, module);
|
|
if (index !== -1) {
|
|
ArrayPrototypeSplice(children, index, 1);
|
|
}
|
|
}
|
|
}
|
|
} else if (
|
|
module.exports &&
|
|
ObjectGetPrototypeOf(module.exports) ===
|
|
CircularRequirePrototypeWarningProxy
|
|
) {
|
|
ObjectSetPrototypeOf(module.exports, ObjectPrototype);
|
|
}
|
|
}
|
|
|
|
return module.exports;
|
|
};
|
|
|
|
Module._resolveFilename = function (
|
|
request,
|
|
parent,
|
|
isMain,
|
|
options,
|
|
) {
|
|
if (
|
|
StringPrototypeStartsWith(request, "node:") ||
|
|
nativeModuleCanBeRequiredByUsers(request)
|
|
) {
|
|
return request;
|
|
}
|
|
|
|
let paths;
|
|
|
|
if (typeof options === "object" && options !== null) {
|
|
if (ArrayIsArray(options.paths)) {
|
|
const isRelative = op_require_is_request_relative(request);
|
|
|
|
if (isRelative) {
|
|
paths = options.paths;
|
|
} else {
|
|
const fakeParent = new Module("", null);
|
|
paths = [];
|
|
|
|
for (let i = 0; i < options.paths.length; i++) {
|
|
const path = options.paths[i];
|
|
fakeParent.paths = Module._nodeModulePaths(path);
|
|
const lookupPaths = Module._resolveLookupPaths(request, fakeParent);
|
|
|
|
for (let j = 0; j < lookupPaths.length; j++) {
|
|
if (!ArrayPrototypeIncludes(paths, lookupPaths[j])) {
|
|
ArrayPrototypePush(paths, lookupPaths[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (options.paths === undefined) {
|
|
paths = Module._resolveLookupPaths(request, parent);
|
|
} else {
|
|
// TODO:
|
|
// throw new ERR_INVALID_ARG_VALUE("options.paths", options.paths);
|
|
throw new Error("Invalid arg value options.paths", options.path);
|
|
}
|
|
} else {
|
|
paths = Module._resolveLookupPaths(request, parent);
|
|
}
|
|
|
|
if (parent?.filename) {
|
|
if (request[0] === "#") {
|
|
const maybeResolved = op_require_package_imports_resolve(
|
|
parent.filename,
|
|
request,
|
|
);
|
|
if (maybeResolved) {
|
|
return maybeResolved;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Try module self resolution first
|
|
const parentPath = op_require_try_self_parent_path(
|
|
!!parent,
|
|
parent?.filename,
|
|
parent?.id,
|
|
);
|
|
const selfResolved = op_require_try_self(parentPath, request);
|
|
if (selfResolved) {
|
|
const cacheKey = request + "\x00" +
|
|
(paths.length === 1 ? paths[0] : ArrayPrototypeJoin(paths, "\x00"));
|
|
Module._pathCache[cacheKey] = selfResolved;
|
|
return selfResolved;
|
|
}
|
|
|
|
// Look up the filename first, since that's the cache key.
|
|
const filename = Module._findPath(
|
|
request,
|
|
paths,
|
|
isMain,
|
|
parentPath,
|
|
);
|
|
if (filename) {
|
|
return op_require_real_path(filename);
|
|
}
|
|
const requireStack = [];
|
|
for (let cursor = parent; cursor; cursor = moduleParentCache.get(cursor)) {
|
|
ArrayPrototypePush(requireStack, cursor.filename || cursor.id);
|
|
}
|
|
let message = `Cannot find module '${request}'`;
|
|
if (requireStack.length > 0) {
|
|
message = message + "\nRequire stack:\n- " +
|
|
ArrayPrototypeJoin(requireStack, "\n- ");
|
|
}
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
const err = new Error(message);
|
|
err.code = "MODULE_NOT_FOUND";
|
|
err.requireStack = requireStack;
|
|
|
|
// fallback and attempt to resolve bare specifiers using
|
|
// the global cache when not using --node-modules-dir
|
|
if (
|
|
!usesLocalNodeModulesDir &&
|
|
ArrayIsArray(options?.paths) &&
|
|
request[0] !== "." &&
|
|
request[0] !== "#" &&
|
|
!request.startsWith("file:///") &&
|
|
!op_require_is_request_relative(request) &&
|
|
!op_require_path_is_absolute(request)
|
|
) {
|
|
try {
|
|
return Module._resolveFilename(request, parent, isMain, {
|
|
...options,
|
|
paths: undefined,
|
|
});
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
// throw the original error
|
|
throw err;
|
|
};
|
|
|
|
/**
|
|
* Internal CommonJS API to always require modules before requiring the actual
|
|
* one when calling `require("my-module")`. This is used by require hooks such
|
|
* as `ts-node/register`.
|
|
* @param {string[]} requests List of modules to preload
|
|
*/
|
|
Module._preloadModules = function (requests) {
|
|
if (!ArrayIsArray(requests) || requests.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const parent = new Module("internal/preload", null);
|
|
// All requested files must be resolved against cwd
|
|
parent.paths = Module._nodeModulePaths(process.cwd());
|
|
for (let i = 0; i < requests.length; i++) {
|
|
parent.require(requests[i]);
|
|
}
|
|
};
|
|
|
|
Module.prototype.load = function (filename) {
|
|
if (this.loaded) {
|
|
throw Error("Module already loaded");
|
|
}
|
|
|
|
// Canonicalize the path so it's not pointing to the symlinked directory
|
|
// in `node_modules` directory of the referrer.
|
|
this.filename = op_require_real_path(filename);
|
|
this.paths = Module._nodeModulePaths(
|
|
pathDirname(this.filename),
|
|
);
|
|
const extension = findLongestRegisteredExtension(filename);
|
|
// allow .mjs to be overridden
|
|
if (
|
|
StringPrototypeEndsWith(filename, ".mjs") && !Module._extensions[".mjs"]
|
|
) {
|
|
throw createRequireEsmError(
|
|
filename,
|
|
moduleParentCache.get(this)?.filename,
|
|
);
|
|
}
|
|
|
|
Module._extensions[extension](this, this.filename);
|
|
this.loaded = true;
|
|
|
|
// TODO: do caching
|
|
};
|
|
|
|
// Loads a module at the given file path. Returns that module's
|
|
// `exports` property.
|
|
Module.prototype.require = function (id) {
|
|
if (typeof id !== "string") {
|
|
// TODO(bartlomieju): it should use different error type
|
|
// ("ERR_INVALID_ARG_VALUE")
|
|
throw new TypeError("Invalid argument type");
|
|
}
|
|
|
|
if (id === "") {
|
|
// TODO(bartlomieju): it should use different error type
|
|
// ("ERR_INVALID_ARG_VALUE")
|
|
throw new TypeError("id must be non empty");
|
|
}
|
|
requireDepth++;
|
|
try {
|
|
return Module._load(id, this, /* isMain */ false);
|
|
} finally {
|
|
requireDepth--;
|
|
}
|
|
};
|
|
|
|
// The module wrapper looks slightly different to Node. Instead of using one
|
|
// wrapper function, we use two. The first one exists to performance optimize
|
|
// access to magic node globals, like `Buffer` or `process`. The second one
|
|
// is the actual wrapper function we run the users code in.
|
|
// The only observable difference is that in Deno `arguments.callee` is not
|
|
// null.
|
|
Module.wrapper = [
|
|
"(function (exports, require, module, __filename, __dirname, Buffer, clearImmediate, clearInterval, clearTimeout, console, global, process, setImmediate, setInterval, setTimeout, performance) { (function (exports, require, module, __filename, __dirname) {",
|
|
"\n}).call(this, exports, require, module, __filename, __dirname); })",
|
|
];
|
|
Module.wrap = function (script) {
|
|
script = script.replace(/^#!.*?\n/, "");
|
|
return `${Module.wrapper[0]}${script}${Module.wrapper[1]}`;
|
|
};
|
|
|
|
function isEsmSyntaxError(error) {
|
|
return error instanceof SyntaxError && (
|
|
StringPrototypeIncludes(
|
|
error.message,
|
|
"Cannot use import statement outside a module",
|
|
) ||
|
|
StringPrototypeIncludes(error.message, "Unexpected token 'export'")
|
|
);
|
|
}
|
|
|
|
function enrichCJSError(error) {
|
|
if (isEsmSyntaxError(error)) {
|
|
console.error(
|
|
'To load an ES module, set "type": "module" in the package.json or use ' +
|
|
"the .mjs extension.",
|
|
);
|
|
}
|
|
}
|
|
|
|
function wrapSafe(
|
|
filename,
|
|
content,
|
|
cjsModuleInstance,
|
|
format,
|
|
) {
|
|
const wrapper = Module.wrap(content);
|
|
const [f, err] = core.evalContext(
|
|
wrapper,
|
|
url.pathToFileURL(filename).toString(),
|
|
[format !== "module"],
|
|
);
|
|
if (err) {
|
|
if (process.mainModule === cjsModuleInstance) {
|
|
enrichCJSError(err.thrown);
|
|
}
|
|
if (isEsmSyntaxError(err.thrown)) {
|
|
throw createRequireEsmError(
|
|
filename,
|
|
moduleParentCache.get(cjsModuleInstance)?.filename,
|
|
);
|
|
} else {
|
|
throw err.thrown;
|
|
}
|
|
}
|
|
return f;
|
|
}
|
|
|
|
Module.prototype._compile = function (content, filename, format) {
|
|
const compiledWrapper = wrapSafe(filename, content, this, format);
|
|
|
|
if (format === "module") {
|
|
// TODO(https://github.com/denoland/deno/issues/24822): implement require esm
|
|
throw createRequireEsmError(
|
|
filename,
|
|
moduleParentCache.get(module)?.filename,
|
|
);
|
|
}
|
|
|
|
const dirname = pathDirname(filename);
|
|
const require = makeRequireFunction(this);
|
|
const exports = this.exports;
|
|
const thisValue = exports;
|
|
if (requireDepth === 0) {
|
|
statCache = new SafeMap();
|
|
}
|
|
|
|
if (hasInspectBrk && !hasBrokenOnInspectBrk) {
|
|
hasBrokenOnInspectBrk = true;
|
|
op_require_break_on_next_statement();
|
|
}
|
|
|
|
const {
|
|
Buffer,
|
|
clearImmediate,
|
|
clearInterval,
|
|
clearTimeout,
|
|
console,
|
|
global,
|
|
process,
|
|
setImmediate,
|
|
setInterval,
|
|
setTimeout,
|
|
performance,
|
|
} = nodeGlobals;
|
|
|
|
const result = compiledWrapper.call(
|
|
thisValue,
|
|
exports,
|
|
require,
|
|
this,
|
|
filename,
|
|
dirname,
|
|
Buffer,
|
|
clearImmediate,
|
|
clearInterval,
|
|
clearTimeout,
|
|
console,
|
|
global,
|
|
process,
|
|
setImmediate,
|
|
setInterval,
|
|
setTimeout,
|
|
performance,
|
|
);
|
|
if (requireDepth === 0) {
|
|
statCache = null;
|
|
}
|
|
return result;
|
|
};
|
|
|
|
Module._extensions[".js"] = function (module, filename) {
|
|
const content = op_require_read_file(filename);
|
|
|
|
let format;
|
|
if (StringPrototypeEndsWith(filename, ".js")) {
|
|
const pkg = op_require_read_closest_package_json(filename);
|
|
if (pkg?.typ === "module") {
|
|
// TODO(https://github.com/denoland/deno/issues/24822): implement require esm
|
|
format = "module";
|
|
throw createRequireEsmError(
|
|
filename,
|
|
moduleParentCache.get(module)?.filename,
|
|
);
|
|
} else if (pkg?.type === "commonjs") {
|
|
format = "commonjs";
|
|
}
|
|
} else if (StringPrototypeEndsWith(filename, ".cjs")) {
|
|
format = "commonjs";
|
|
}
|
|
|
|
module._compile(content, filename, format);
|
|
};
|
|
|
|
function createRequireEsmError(filename, parent) {
|
|
let message = `require() of ES Module ${filename}`;
|
|
|
|
if (parent) {
|
|
message += ` from ${parent}`;
|
|
}
|
|
|
|
message +=
|
|
` not supported. Instead change the require to a dynamic import() which is available in all CommonJS modules.`;
|
|
const err = new Error(message);
|
|
err.code = "ERR_REQUIRE_ESM";
|
|
return err;
|
|
}
|
|
|
|
function stripBOM(content) {
|
|
if (StringPrototypeCharCodeAt(content, 0) === 0xfeff) {
|
|
content = StringPrototypeSlice(content, 1);
|
|
}
|
|
return content;
|
|
}
|
|
|
|
// Native extension for .json
|
|
Module._extensions[".json"] = function (module, filename) {
|
|
const content = op_require_read_file(filename);
|
|
|
|
try {
|
|
module.exports = JSONParse(stripBOM(content));
|
|
} catch (err) {
|
|
err.message = filename + ": " + err.message;
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
// Native extension for .node
|
|
Module._extensions[".node"] = function (module, filename) {
|
|
module.exports = op_napi_open(
|
|
filename,
|
|
globalThis,
|
|
nodeGlobals.Buffer,
|
|
reportError,
|
|
);
|
|
};
|
|
|
|
function createRequireFromPath(filename) {
|
|
const proxyPath = op_require_proxy_path(filename);
|
|
const mod = new Module(proxyPath);
|
|
mod.filename = proxyPath;
|
|
mod.paths = Module._nodeModulePaths(mod.path);
|
|
return makeRequireFunction(mod);
|
|
}
|
|
|
|
function makeRequireFunction(mod) {
|
|
const require = function require(path) {
|
|
return mod.require(path);
|
|
};
|
|
|
|
function resolve(request, options) {
|
|
return Module._resolveFilename(request, mod, false, options);
|
|
}
|
|
|
|
require.resolve = resolve;
|
|
|
|
function paths(request) {
|
|
return Module._resolveLookupPaths(request, mod);
|
|
}
|
|
|
|
resolve.paths = paths;
|
|
require.main = mainModule;
|
|
// Enable support to add extra extension types.
|
|
require.extensions = Module._extensions;
|
|
require.cache = Module._cache;
|
|
|
|
return require;
|
|
}
|
|
|
|
// Matches to:
|
|
// - /foo/...
|
|
// - \foo\...
|
|
// - C:/foo/...
|
|
// - C:\foo\...
|
|
const RE_START_OF_ABS_PATH = /^([/\\]|[a-zA-Z]:[/\\])/;
|
|
|
|
function isAbsolute(filenameOrUrl) {
|
|
return RE_START_OF_ABS_PATH.test(filenameOrUrl);
|
|
}
|
|
|
|
function createRequire(filenameOrUrl) {
|
|
let fileUrlStr;
|
|
if (filenameOrUrl instanceof URL) {
|
|
if (filenameOrUrl.protocol !== "file:") {
|
|
throw new Error(
|
|
`The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received ${filenameOrUrl}`,
|
|
);
|
|
}
|
|
fileUrlStr = filenameOrUrl.toString();
|
|
} else if (typeof filenameOrUrl === "string") {
|
|
if (!filenameOrUrl.startsWith("file:") && !isAbsolute(filenameOrUrl)) {
|
|
throw new Error(
|
|
`The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received ${filenameOrUrl}`,
|
|
);
|
|
}
|
|
fileUrlStr = filenameOrUrl;
|
|
} else {
|
|
throw new Error(
|
|
`The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received ${filenameOrUrl}`,
|
|
);
|
|
}
|
|
const filename = op_require_as_file_path(fileUrlStr);
|
|
return createRequireFromPath(filename);
|
|
}
|
|
|
|
function isBuiltin(moduleName) {
|
|
if (typeof moduleName !== "string") {
|
|
return false;
|
|
}
|
|
|
|
if (StringPrototypeStartsWith(moduleName, "node:")) {
|
|
moduleName = StringPrototypeSlice(moduleName, 5);
|
|
} else if (moduleName === "test") {
|
|
// test is only a builtin if it has the "node:" scheme
|
|
// see https://github.com/nodejs/node/blob/73025c4dec042e344eeea7912ed39f7b7c4a3991/test/parallel/test-module-isBuiltin.js#L14
|
|
return false;
|
|
}
|
|
|
|
return moduleName in nativeModuleExports &&
|
|
!StringPrototypeStartsWith(moduleName, "internal/");
|
|
}
|
|
|
|
Module.isBuiltin = isBuiltin;
|
|
|
|
Module.createRequire = createRequire;
|
|
|
|
Module._initPaths = function () {
|
|
const paths = op_require_init_paths();
|
|
modulePaths = paths;
|
|
Module.globalPaths = ArrayPrototypeSlice(modulePaths);
|
|
};
|
|
|
|
Module.syncBuiltinESMExports = function syncBuiltinESMExports() {
|
|
throw new Error("not implemented");
|
|
};
|
|
|
|
// Mostly used by tools like ts-node.
|
|
Module.runMain = function () {
|
|
Module._load(process.argv[1], null, true);
|
|
};
|
|
|
|
Module.Module = Module;
|
|
|
|
nativeModuleExports.module = Module;
|
|
|
|
function loadNativeModule(_id, request) {
|
|
if (nativeModulePolyfill.has(request)) {
|
|
return nativeModulePolyfill.get(request);
|
|
}
|
|
const modExports = nativeModuleExports[request];
|
|
if (modExports) {
|
|
const nodeMod = new Module(request);
|
|
nodeMod.exports = modExports;
|
|
nodeMod.loaded = true;
|
|
nativeModulePolyfill.set(request, nodeMod);
|
|
return nodeMod;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
function nativeModuleCanBeRequiredByUsers(request) {
|
|
return !!nativeModuleExports[request];
|
|
}
|
|
|
|
function readPackageScope() {
|
|
throw new Error("not implemented");
|
|
}
|
|
|
|
/** @param specifier {string} */
|
|
function packageSpecifierSubPath(specifier) {
|
|
let parts = StringPrototypeSplit(specifier, "/");
|
|
if (StringPrototypeStartsWith(parts[0], "@")) {
|
|
parts = ArrayPrototypeSlice(parts, 2);
|
|
} else {
|
|
parts = ArrayPrototypeSlice(parts, 1);
|
|
}
|
|
return ArrayPrototypeJoin(parts, "/");
|
|
}
|
|
|
|
// This is a temporary namespace, that will be removed when initializing
|
|
// in `02_init.js`.
|
|
internals.requireImpl = {
|
|
setUsesLocalNodeModulesDir() {
|
|
usesLocalNodeModulesDir = true;
|
|
},
|
|
setInspectBrk() {
|
|
hasInspectBrk = true;
|
|
},
|
|
Module,
|
|
nativeModuleExports,
|
|
};
|
|
|
|
/**
|
|
* @param {string} path
|
|
* @returns {SourceMap | undefined}
|
|
*/
|
|
export function findSourceMap(_path) {
|
|
// TODO(@marvinhagemeister): Stub implementation for now to unblock ava
|
|
return undefined;
|
|
}
|
|
|
|
export { builtinModules, createRequire, isBuiltin, Module };
|
|
export const _cache = Module._cache;
|
|
export const _extensions = Module._extensions;
|
|
export const _findPath = Module._findPath;
|
|
export const _initPaths = Module._initPaths;
|
|
export const _load = Module._load;
|
|
export const _nodeModulePaths = Module._nodeModulePaths;
|
|
export const _pathCache = Module._pathCache;
|
|
export const _preloadModules = Module._preloadModules;
|
|
export const _resolveFilename = Module._resolveFilename;
|
|
export const _resolveLookupPaths = Module._resolveLookupPaths;
|
|
export const globalPaths = Module.globalPaths;
|
|
export const wrap = Module.wrap;
|
|
|
|
export default Module;
|