@@ -8,6 +8,9 @@ import semver from "semver";
88import { endHiddenCallStack } from "../../errors/rewrite-stack-trace" ;
99import ConfigError from "../../errors/config-error" ;
1010
11+ import type { InputOptions } from ".." ;
12+ import { transformFileSync } from "../../transform-file" ;
13+
1114const require = createRequire ( import . meta. url ) ;
1215
1316let import_ : ( ( specifier : string | URL ) => any ) | undefined ;
@@ -23,38 +26,87 @@ export const supportsESM = semver.satisfies(
2326 "^12.17 || >=13.2" ,
2427) ;
2528
26- export default function * loadCjsOrMjsDefault (
29+ export default function * loadCodeDefault (
2730 filepath : string ,
2831 asyncError : string ,
2932 // TODO(Babel 8): Remove this
3033 fallbackToTranspiledModule : boolean = false ,
3134) : Handler < unknown > {
32- switch ( guessJSModuleType ( filepath ) ) {
33- case "cjs" :
35+ switch ( path . extname ( filepath ) ) {
36+ case ". cjs" :
3437 return loadCjsDefault ( filepath , fallbackToTranspiledModule ) ;
35- case "unknown" :
38+ case ".mjs" :
39+ break ;
40+ case ".cts" :
41+ return loadCtsDefault ( filepath ) ;
42+ default :
3643 try {
3744 return loadCjsDefault ( filepath , fallbackToTranspiledModule ) ;
3845 } catch ( e ) {
3946 if ( e . code !== "ERR_REQUIRE_ESM" ) throw e ;
4047 }
41- // fall through
42- case "mjs" :
43- if ( yield * isAsync ( ) ) {
44- return yield * waitFor ( loadMjsDefault ( filepath ) ) ;
45- }
46- throw new ConfigError ( asyncError , filepath ) ;
4748 }
49+ if ( yield * isAsync ( ) ) {
50+ return yield * waitFor ( loadMjsDefault ( filepath ) ) ;
51+ }
52+ throw new ConfigError ( asyncError , filepath ) ;
4853}
4954
50- function guessJSModuleType ( filename : string ) : "cjs" | "mjs" | "unknown" {
51- switch ( path . extname ( filename ) ) {
52- case ".cjs" :
53- return "cjs" ;
54- case ".mjs" :
55- return "mjs" ;
56- default :
57- return "unknown" ;
55+ function loadCtsDefault ( filepath : string ) {
56+ const ext = ".cts" ;
57+ const hasTsSupport = ! ! (
58+ require . extensions [ ".ts" ] ||
59+ require . extensions [ ".cts" ] ||
60+ require . extensions [ ".mts" ]
61+ ) ;
62+
63+ let handler : NodeJS . RequireExtensions [ "" ] ;
64+
65+ if ( ! hasTsSupport ) {
66+ const opts : InputOptions = {
67+ babelrc : false ,
68+ configFile : false ,
69+ sourceType : "script" ,
70+ sourceMaps : "inline" ,
71+ presets : [
72+ [
73+ getTSPreset ( filepath ) ,
74+ {
75+ disallowAmbiguousJSXLike : true ,
76+ allExtensions : true ,
77+ onlyRemoveTypeImports : true ,
78+ optimizeConstEnums : true ,
79+ ...( ! process . env . BABEL_8_BREAKING && {
80+ allowDeclareFields : true ,
81+ } ) ,
82+ } ,
83+ ] ,
84+ ] ,
85+ } ;
86+
87+ handler = function ( m , filename ) {
88+ // If we want to support `.ts`, `.d.ts` must be handled specially.
89+ if ( handler && filename . endsWith ( ext ) ) {
90+ // @ts -expect-error Undocumented API
91+ return m . _compile (
92+ transformFileSync ( filename , {
93+ ...opts ,
94+ filename,
95+ } ) . code ,
96+ filename ,
97+ ) ;
98+ }
99+ return require . extensions [ ".js" ] ( m , filename ) ;
100+ } ;
101+ require . extensions [ ext ] = handler ;
102+ }
103+ try {
104+ return endHiddenCallStack ( require ) ( filepath ) ;
105+ } finally {
106+ if ( ! hasTsSupport ) {
107+ if ( require . extensions [ ext ] === handler ) delete require . extensions [ ext ] ;
108+ handler = undefined ;
109+ }
58110 }
59111}
60112
@@ -69,8 +121,7 @@ function loadCjsDefault(filepath: string, fallbackToTranspiledModule: boolean) {
69121async function loadMjsDefault ( filepath : string ) {
70122 if ( ! import_ ) {
71123 throw new ConfigError (
72- "Internal error: Native ECMAScript modules aren't supported" +
73- " by this platform.\n" ,
124+ "Internal error: Native ECMAScript modules aren't supported by this platform.\n" ,
74125 filepath ,
75126 ) ;
76127 }
@@ -80,3 +131,32 @@ async function loadMjsDefault(filepath: string) {
80131 const module = await endHiddenCallStack ( import_ ) ( pathToFileURL ( filepath ) ) ;
81132 return module . default ;
82133}
134+
135+ function getTSPreset ( filepath : string ) {
136+ try {
137+ // eslint-disable-next-line import/no-extraneous-dependencies
138+ return require ( "@babel/preset-typescript" ) ;
139+ } catch ( error ) {
140+ if ( error . code !== "MODULE_NOT_FOUND" ) throw error ;
141+
142+ let message =
143+ "You appear to be using a .cts file as Babel configuration, but the `@babel/preset-typescript` package was not found: please install it!" ;
144+
145+ if ( process . versions . pnp ) {
146+ // Using Yarn PnP, which doesn't allow requiring packages that are not
147+ // explicitly specified as dependencies.
148+ // TODO(Babel 8): Explicitly add `@babel/preset-typescript` as an
149+ // optional peer dependency of `@babel/core`.
150+ message += `
151+ If you are using Yarn Plug'n'Play, you may also need to add the following configuration to your .yarnrc.yml file:
152+
153+ packageExtensions:
154+ \t"@babel/core@*":
155+ \t\tpeerDependencies:
156+ \t\t\t"@babel/preset-typescript": "*"
157+ ` ;
158+ }
159+
160+ throw new ConfigError ( message , filepath ) ;
161+ }
162+ }
0 commit comments