module-importer.cjs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. /**
  2. * @fileoverview Universal module importer
  3. */
  4. //-----------------------------------------------------------------------------
  5. // Imports
  6. //-----------------------------------------------------------------------------
  7. const { createRequire } = require("module");
  8. const { pathToFileURL } = require("url");
  9. //-----------------------------------------------------------------------------
  10. // Helpers
  11. //-----------------------------------------------------------------------------
  12. const SLASHES = new Set(["/", "\\"]);
  13. /**
  14. * Normalizes directories to have a trailing slash.
  15. * Resolve is pretty finicky -- if the directory name doesn't have
  16. * a trailing slash then it tries to look in the parent directory.
  17. * i.e., if the directory is "/usr/nzakas/foo" it will start the
  18. * search in /usr/nzakas. However, if the directory is "/user/nzakas/foo/",
  19. * then it will start the search in /user/nzakas/foo.
  20. * @param {string} directory The directory to check.
  21. * @returns {string} The normalized directory.
  22. */
  23. function normalizeDirectory(directory) {
  24. if (!SLASHES.has(directory[directory.length-1])) {
  25. return directory + "/";
  26. }
  27. return directory;
  28. }
  29. //-----------------------------------------------------------------------------
  30. // Exports
  31. //-----------------------------------------------------------------------------
  32. /**
  33. * Class for importing both CommonJS and ESM modules in Node.js.
  34. */
  35. exports.ModuleImporter = class ModuleImporter {
  36. /**
  37. * Creates a new instance.
  38. * @param {string} [cwd] The current working directory to resolve from.
  39. */
  40. constructor(cwd = process.cwd()) {
  41. /**
  42. * The base directory from which paths should be resolved.
  43. * @type {string}
  44. */
  45. this.cwd = normalizeDirectory(cwd);
  46. }
  47. /**
  48. * Resolves a module based on its name or location.
  49. * @param {string} specifier Either an npm package name or
  50. * relative file path.
  51. * @returns {string|undefined} The location of the import.
  52. * @throws {Error} If specifier cannot be located.
  53. */
  54. resolve(specifier) {
  55. const require = createRequire(this.cwd);
  56. return require.resolve(specifier);
  57. }
  58. /**
  59. * Imports a module based on its name or location.
  60. * @param {string} specifier Either an npm package name or
  61. * relative file path.
  62. * @returns {Promise<object>} The module's object.
  63. */
  64. import(specifier) {
  65. const location = this.resolve(specifier);
  66. return import(pathToFileURL(location).href);
  67. }
  68. }