You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

122 lines
3.7 KiB

'use strict';
const fs = require('fs');
const internalCJSModule = require('internal/module');
const internalURLModule = require('internal/url');
const internalFS = require('internal/fs');
const NativeModule = require('native_module');
const { extname, _makeLong } = require('path');
const { URL } = require('url');
const { realpathSync } = require('fs');
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
const {
ModuleWrap,
createDynamicModule
} = require('internal/loader/ModuleWrap');
const errors = require('internal/errors');
const search = require('internal/loader/search');
const asyncReadFile = require('util').promisify(require('fs').readFile);
const debug = require('util').debuglog('esm');
const realpathCache = new Map();
const loaders = new Map();
exports.loaders = loaders;
// Strategy for loading a standard JavaScript module
loaders.set('esm', async (url) => {
const source = `${await asyncReadFile(new URL(url))}`;
debug(`Loading StandardModule ${url}`);
return {
module: new ModuleWrap(internalCJSModule.stripShebang(source), url),
reflect: undefined
};
});
// Strategy for loading a node-style CommonJS module
loaders.set('cjs', async (url) => {
return createDynamicModule(['default'], url, (reflect) => {
debug(`Loading CJSModule ${url}`);
const CJSModule = require('module');
const pathname = internalURLModule.getPathFromURL(new URL(url));
CJSModule._load(pathname);
});
});
// Strategy for loading a node builtin CommonJS module that isn't
// through normal resolution
loaders.set('builtin', async (url) => {
return createDynamicModule(['default'], url, (reflect) => {
debug(`Loading BuiltinModule ${url}`);
const exports = NativeModule.require(url.substr(5));
reflect.exports.default.set(exports);
});
});
loaders.set('addon', async (url) => {
const ctx = createDynamicModule(['default'], url, (reflect) => {
debug(`Loading NativeModule ${url}`);
const module = { exports: {} };
const pathname = internalURLModule.getPathFromURL(new URL(url));
process.dlopen(module, _makeLong(pathname));
reflect.exports.default.set(module.exports);
});
return ctx;
});
loaders.set('json', async (url) => {
return createDynamicModule(['default'], url, (reflect) => {
debug(`Loading JSONModule ${url}`);
const pathname = internalURLModule.getPathFromURL(new URL(url));
const content = fs.readFileSync(pathname, 'utf8');
try {
const exports = JSON.parse(internalCJSModule.stripBOM(content));
reflect.exports.default.set(exports);
} catch (err) {
err.message = pathname + ': ' + err.message;
throw err;
}
});
});
exports.resolve = (specifier, parentURL) => {
if (NativeModule.nonInternalExists(specifier)) {
return {
url: specifier,
format: 'builtin'
};
}
let url = search(specifier, parentURL);
if (url.protocol !== 'file:') {
throw new errors.Error('ERR_INVALID_PROTOCOL',
url.protocol, 'file:');
}
if (!preserveSymlinks) {
const real = realpathSync(internalURLModule.getPathFromURL(url), {
[internalFS.realpathCacheKey]: realpathCache
});
const old = url;
url = internalURLModule.getURLFromFilePath(real);
url.search = old.search;
url.hash = old.hash;
}
const ext = extname(url.pathname);
switch (ext) {
case '.mjs':
return { url: `${url}`, format: 'esm' };
case '.json':
return { url: `${url}`, format: 'json' };
case '.node':
return { url: `${url}`, format: 'addon' };
case '.js':
return { url: `${url}`, format: 'cjs' };
default:
throw new errors.Error('ERR_UNKNOWN_FILE_EXTENSION',
internalURLModule.getPathFromURL(url));
}
};