jiti-native.mjs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /**
  2. * @typedef {import('./types').Jiti} Jiti
  3. * @typedef {import('./types').JitiOptions} JitiOptions
  4. */
  5. const isDeno = "Deno" in globalThis;
  6. /**
  7. * @param {string|URL} [parentURL]
  8. * @param {JitiOptions} [jitiOptions]
  9. * @returns {Jiti}
  10. */
  11. export function createJiti(parentURL, jitiOptions) {
  12. parentURL = normalizeParentURL(parentURL);
  13. /** @type {Jiti} */
  14. function jiti() {
  15. throw unsupportedError(
  16. "`jiti()` is not supported in native mode, use `jiti.import()` instead.",
  17. );
  18. }
  19. jiti.resolve = () => {
  20. throw unsupportedError("`jiti.resolve()` is not supported in native mode.");
  21. };
  22. jiti.esmResolve = (id, opts) => {
  23. try {
  24. const importMeta = jitiOptions?.importMeta || import.meta;
  25. if (isDeno) {
  26. // Deno throws TypeError: Invalid arguments when passing parentURL
  27. return importMeta.resolve(id);
  28. }
  29. const parent = normalizeParentURL(opts?.parentURL || parentURL);
  30. return importMeta.resolve(id, parent);
  31. } catch (error) {
  32. if (opts?.try) {
  33. return undefined;
  34. } else {
  35. throw error;
  36. }
  37. }
  38. };
  39. jiti.import = async function (id, opts) {
  40. for (const suffix of ["", "/index"]) {
  41. // prettier-ignore
  42. for (const ext of ["", ".js", ".mjs", ".cjs", ".ts", ".tsx", ".mts", ".cts"]) {
  43. try {
  44. const resolved = this.esmResolve(id + suffix + ext, opts);
  45. if (!resolved) {
  46. continue;
  47. }
  48. let importAttrs = undefined
  49. if (resolved.endsWith('.json')) {
  50. importAttrs = { with: { type: 'json'}}
  51. }
  52. return await import(resolved, importAttrs);
  53. } catch (error) {
  54. if (error.code === 'ERR_MODULE_NOT_FOUND' || error.code === 'ERR_UNSUPPORTED_DIR_IMPORT') {
  55. continue
  56. }
  57. if (opts?.try) {
  58. return undefined;
  59. }
  60. throw error;
  61. }
  62. }
  63. }
  64. if (!opts?.try) {
  65. const parent = normalizeParentURL(opts?.parentURL || parentURL);
  66. const error = new Error(
  67. `[jiti] [ERR_MODULE_NOT_FOUND] Cannot import '${id}' from '${parent}'.`,
  68. );
  69. error.code = "ERR_MODULE_NOT_FOUND";
  70. throw error;
  71. }
  72. };
  73. jiti.transform = () => {
  74. throw unsupportedError(
  75. "`jiti.transform()` is not supported in native mode.",
  76. );
  77. };
  78. jiti.evalModule = () => {
  79. throw unsupportedError(
  80. "`jiti.evalModule()` is not supported in native mode.",
  81. );
  82. };
  83. jiti.main = undefined;
  84. jiti.extensions = Object.create(null);
  85. jiti.cache = Object.create(null);
  86. return jiti;
  87. }
  88. export default createJiti;
  89. /**
  90. * @param {string} message
  91. */
  92. function unsupportedError(message) {
  93. throw new Error(
  94. `[jiti] ${message} (import or require 'jiti' instead of 'jiti/native' for more features).`,
  95. );
  96. }
  97. function normalizeParentURL(input) {
  98. if (!input) {
  99. return "file:///";
  100. }
  101. if (typeof filename !== "string" || input.startsWith("file://")) {
  102. return input;
  103. }
  104. if (input.endsWith("/")) {
  105. input += "_"; // append a dummy filename
  106. }
  107. return `file://${input}`;
  108. }