node/lib/internal/loader/DefaultResolve.js
Joyee Cheung ff7a116ba3
src: move internal loaders out of bootstrap_node.js
- Moves the creation of `process.binding()`, `process._linkedBinding()`
  `internalBinding()` and `NativeModule` into a separate file
  `lib/internal/bootstrap_loaders.js`, and documents them there.
  This file will be compiled and run before `bootstrap_node.js`, which
  means we now bootstrap the internal module & binding system before
  actually bootstrapping Node.js.
- Rename the special ID that can be used to require `NativeModule`
  as `internal/bootstrap_loaders` since it is setup there. Also put
  `internalBinding` in the object exported by `NativeModule.require`
  instead of putting it inside the `NativeModule.wrapper`
- Use the original `getBinding()` to get the source code of native
  modules instead of getting it from `process.binding('native')`
  so that users cannot fake native modules by modifying the binding
  object.
- Names the bootstrapping functions so their names show up
  in the stack trace.

Backport-PR-URL: https://github.com/nodejs/node/pull/19374
PR-URL: https://github.com/nodejs/node/pull/19112
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
2018-04-04 16:20:45 +02:00

97 lines
2.6 KiB
JavaScript

'use strict';
const { URL } = require('url');
const CJSmodule = require('module');
const internalFS = require('internal/fs');
const { NativeModule, internalBinding } = require('internal/bootstrap_loaders');
const { extname } = require('path');
const { realpathSync } = require('fs');
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
const errors = require('internal/errors');
const { resolve: moduleWrapResolve } = internalBinding('module_wrap');
const StringStartsWith = Function.call.bind(String.prototype.startsWith);
const { getURLFromFilePath, getPathFromURL } = require('internal/url');
const realpathCache = new Map();
function search(target, base) {
if (base === undefined) {
// We cannot search without a base.
throw new errors.Error('ERR_MISSING_MODULE', target);
}
try {
return moduleWrapResolve(target, base);
} catch (e) {
e.stack; // cause V8 to generate stack before rethrow
let error = e;
try {
const questionedBase = new URL(base);
const tmpMod = new CJSmodule(questionedBase.pathname, null);
tmpMod.paths = CJSmodule._nodeModulePaths(
new URL('./', questionedBase).pathname);
const found = CJSmodule._resolveFilename(target, tmpMod);
error = new errors.Error('ERR_MODULE_RESOLUTION_LEGACY', target,
base, found);
} catch (problemChecking) {
// ignore
}
throw error;
}
}
const extensionFormatMap = {
'__proto__': null,
'.mjs': 'esm',
'.json': 'json',
'.node': 'addon',
'.js': 'cjs'
};
function resolve(specifier, parentURL) {
if (NativeModule.nonInternalExists(specifier)) {
return {
url: specifier,
format: 'builtin'
};
}
let url;
try {
url = search(specifier,
parentURL || getURLFromFilePath(`${process.cwd()}/`).href);
} catch (e) {
if (typeof e.message === 'string' &&
StringStartsWith(e.message, 'Cannot find module'))
e.code = 'MODULE_NOT_FOUND';
throw e;
}
const isMain = parentURL === undefined;
if (!preserveSymlinks || isMain) {
const real = realpathSync(getPathFromURL(url), {
[internalFS.realpathCacheKey]: realpathCache
});
const old = url;
url = getURLFromFilePath(real);
url.search = old.search;
url.hash = old.hash;
}
const ext = extname(url.pathname);
let format = extensionFormatMap[ext];
if (!format) {
if (isMain)
format = 'cjs';
else
throw new errors.Error('ERR_UNKNOWN_FILE_EXTENSION', url.pathname);
}
return { url: `${url}`, format };
}
module.exports = resolve;
// exported for tests
module.exports.search = search;