| /** |
| * @fileoverview Universal module importer |
| */ |
| |
| //----------------------------------------------------------------------------- |
| // Imports |
| //----------------------------------------------------------------------------- |
| |
| const { createRequire } = require("module"); |
| const { pathToFileURL } = require("url"); |
| |
| //----------------------------------------------------------------------------- |
| // Helpers |
| //----------------------------------------------------------------------------- |
| |
| const SLASHES = new Set(["/", "\\"]); |
| |
| /** |
| * Normalizes directories to have a trailing slash. |
| * Resolve is pretty finicky -- if the directory name doesn't have |
| * a trailing slash then it tries to look in the parent directory. |
| * i.e., if the directory is "/usr/nzakas/foo" it will start the |
| * search in /usr/nzakas. However, if the directory is "/user/nzakas/foo/", |
| * then it will start the search in /user/nzakas/foo. |
| * @param {string} directory The directory to check. |
| * @returns {string} The normalized directory. |
| */ |
| function normalizeDirectory(directory) { |
| if (!SLASHES.has(directory[directory.length-1])) { |
| return directory + "/"; |
| } |
| |
| return directory; |
| } |
| |
| //----------------------------------------------------------------------------- |
| // Exports |
| //----------------------------------------------------------------------------- |
| |
| /** |
| * Class for importing both CommonJS and ESM modules in Node.js. |
| */ |
| exports.ModuleImporter = class ModuleImporter { |
| |
| /** |
| * Creates a new instance. |
| * @param {string} [cwd] The current working directory to resolve from. |
| */ |
| constructor(cwd = process.cwd()) { |
| |
| /** |
| * The base directory from which paths should be resolved. |
| * @type {string} |
| */ |
| this.cwd = normalizeDirectory(cwd); |
| } |
| |
| /** |
| * Resolves a module based on its name or location. |
| * @param {string} specifier Either an npm package name or |
| * relative file path. |
| * @returns {string|undefined} The location of the import. |
| * @throws {Error} If specifier cannot be located. |
| */ |
| resolve(specifier) { |
| const require = createRequire(this.cwd); |
| return require.resolve(specifier); |
| } |
| |
| /** |
| * Imports a module based on its name or location. |
| * @param {string} specifier Either an npm package name or |
| * relative file path. |
| * @returns {Promise<object>} The module's object. |
| */ |
| import(specifier) { |
| const location = this.resolve(specifier); |
| return import(pathToFileURL(location).href); |
| } |
| |
| } |