file-extensions.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.getExtensions = void 0;
  4. const util_1 = require("./util");
  5. const nodeEquivalents = new Map([
  6. ['.ts', '.js'],
  7. ['.tsx', '.js'],
  8. ['.jsx', '.js'],
  9. ['.mts', '.mjs'],
  10. ['.cts', '.cjs'],
  11. ]);
  12. const tsResolverEquivalents = new Map([
  13. ['.ts', ['.js']],
  14. ['.tsx', ['.js', '.jsx']],
  15. ['.mts', ['.mjs']],
  16. ['.cts', ['.cjs']],
  17. ]);
  18. // All extensions understood by vanilla node
  19. const vanillaNodeExtensions = [
  20. '.js',
  21. '.json',
  22. '.node',
  23. '.mjs',
  24. '.cjs',
  25. ];
  26. // Extensions added by vanilla node's require() if you omit them:
  27. // js, json, node
  28. // Extensions added by vanilla node if you omit them with --experimental-specifier-resolution=node
  29. // js, json, node, mjs
  30. // Extensions added by ESM codepath's legacy package.json "main" resolver
  31. // js, json, node (not mjs!)
  32. const nodeDoesNotUnderstand = [
  33. '.ts',
  34. '.tsx',
  35. '.jsx',
  36. '.cts',
  37. '.mts',
  38. ];
  39. /**
  40. * [MUST_UPDATE_FOR_NEW_FILE_EXTENSIONS]
  41. * @internal
  42. */
  43. function getExtensions(config, options, tsVersion) {
  44. // TS 4.5 is first version to understand .cts, .mts, .cjs, and .mjs extensions
  45. const tsSupportsMtsCtsExts = (0, util_1.versionGteLt)(tsVersion, '4.5.0');
  46. const requiresHigherTypescriptVersion = [];
  47. if (!tsSupportsMtsCtsExts)
  48. requiresHigherTypescriptVersion.push('.cts', '.cjs', '.mts', '.mjs');
  49. const allPossibleExtensionsSortedByPreference = Array.from(new Set([
  50. ...(options.preferTsExts ? nodeDoesNotUnderstand : []),
  51. ...vanillaNodeExtensions,
  52. ...nodeDoesNotUnderstand,
  53. ]));
  54. const compiledJsUnsorted = ['.ts'];
  55. const compiledJsxUnsorted = [];
  56. if (config.options.jsx)
  57. compiledJsxUnsorted.push('.tsx');
  58. if (tsSupportsMtsCtsExts)
  59. compiledJsUnsorted.push('.mts', '.cts');
  60. if (config.options.allowJs) {
  61. compiledJsUnsorted.push('.js');
  62. if (config.options.jsx)
  63. compiledJsxUnsorted.push('.jsx');
  64. if (tsSupportsMtsCtsExts)
  65. compiledJsUnsorted.push('.mjs', '.cjs');
  66. }
  67. const compiledUnsorted = [...compiledJsUnsorted, ...compiledJsxUnsorted];
  68. const compiled = allPossibleExtensionsSortedByPreference.filter((ext) => compiledUnsorted.includes(ext));
  69. const compiledNodeDoesNotUnderstand = nodeDoesNotUnderstand.filter((ext) => compiled.includes(ext));
  70. /**
  71. * TS's resolver can resolve foo.js to foo.ts, by replacing .js extension with several source extensions.
  72. * IMPORTANT: Must preserve ordering according to preferTsExts!
  73. * Must include the .js/.mjs/.cjs extension in the array!
  74. * This affects resolution behavior!
  75. * [MUST_UPDATE_FOR_NEW_FILE_EXTENSIONS]
  76. */
  77. const r = allPossibleExtensionsSortedByPreference.filter((ext) => [...compiledUnsorted, '.js', '.mjs', '.cjs', '.mts', '.cts'].includes(ext));
  78. const replacementsForJs = r.filter((ext) => ['.js', '.jsx', '.ts', '.tsx'].includes(ext));
  79. const replacementsForJsx = r.filter((ext) => ['.jsx', '.tsx'].includes(ext));
  80. const replacementsForMjs = r.filter((ext) => ['.mjs', '.mts'].includes(ext));
  81. const replacementsForCjs = r.filter((ext) => ['.cjs', '.cts'].includes(ext));
  82. const replacementsForJsOrMjs = r.filter((ext) => ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.mts'].includes(ext));
  83. // Node allows omitting .js or .mjs extension in certain situations (CJS, ESM w/experimental flag)
  84. // So anything that compiles to .js or .mjs can also be omitted.
  85. const experimentalSpecifierResolutionAddsIfOmitted = Array.from(new Set([...replacementsForJsOrMjs, '.json', '.node']));
  86. // Same as above, except node curiuosly doesn't do .mjs here
  87. const legacyMainResolveAddsIfOmitted = Array.from(new Set([...replacementsForJs, '.json', '.node']));
  88. return {
  89. /** All file extensions we transform, ordered by resolution preference according to preferTsExts */
  90. compiled,
  91. /** Resolved extensions that vanilla node will not understand; we should handle them */
  92. nodeDoesNotUnderstand,
  93. /** Like the above, but only the ones we're compiling */
  94. compiledNodeDoesNotUnderstand,
  95. /**
  96. * Mapping from extensions understood by tsc to the equivalent for node,
  97. * as far as getFormat is concerned.
  98. */
  99. nodeEquivalents,
  100. /**
  101. * Mapping from extensions rejected by TSC in import specifiers, to the
  102. * possible alternatives that TS's resolver will accept.
  103. *
  104. * When we allow users to opt-in to .ts extensions in import specifiers, TS's
  105. * resolver requires us to replace the .ts extensions with .js alternatives.
  106. * Otherwise, resolution fails.
  107. *
  108. * Note TS's resolver is only used by, and only required for, typechecking.
  109. * This is separate from node's resolver, which we hook separately and which
  110. * does not require this mapping.
  111. */
  112. tsResolverEquivalents,
  113. /**
  114. * Extensions that we can support if the user upgrades their typescript version.
  115. * Used when raising hints.
  116. */
  117. requiresHigherTypescriptVersion,
  118. /**
  119. * --experimental-specifier-resolution=node will add these extensions.
  120. */
  121. experimentalSpecifierResolutionAddsIfOmitted,
  122. /**
  123. * ESM loader will add these extensions to package.json "main" field
  124. */
  125. legacyMainResolveAddsIfOmitted,
  126. replacementsForMjs,
  127. replacementsForCjs,
  128. replacementsForJsx,
  129. replacementsForJs,
  130. };
  131. }
  132. exports.getExtensions = getExtensions;
  133. //# sourceMappingURL=file-extensions.js.map