3030
3131import process from 'process' ;
3232import path from 'path' ;
33- import urlModule from 'url' ;
34- import babel from '@babel/core' ;
33+ import { fileURLToPath } from 'url' ;
34+ import { loadOptionsAsync , transformAsync } from '@babel/core' ;
3535
36- const { loadOptionsAsync , transformAsync } = babel ;
36+ const BABEL_FORMATS_TRANSFORMED = new Set ( [ 'module' ] ) ;
3737
38- const isBabelConfigFile = ( filename ) => {
39- const basename = path . basename ( filename ) ;
40- return (
41- basename === '.babelrc.js' ||
42- basename === '.babelrc.mjs' ||
43- basename === 'babel.config.js' ||
44- basename === 'babel.config.mjs' ||
45- basename === '.babelrc' ||
46- basename === '.babelrc.cjs' ||
47- basename === 'babel.config.cjs'
48- ) ;
49- } ;
50-
51- const getFormatWithCertitude = ( filename ) => {
52- return / \. c j s $ / . test ( filename )
53- ? 'commonjs'
54- : / \. m j s $ / . test ( filename )
55- ? 'module'
56- : undefined ;
57- } ;
38+ const BABEL_CONFIG_FILES = new Set ( [
39+ '.babelrc.js' ,
40+ '.babelrc.mjs' ,
41+ 'babel.config.js' ,
42+ 'babel.config.mjs' ,
43+ '.babelrc' ,
44+ '.babelrc.cjs' ,
45+ 'babel.config.cjs' ,
46+ ] ) ;
5847
59- const getFormat = ( filename ) => {
60- const packageType = 'module' ; // TODO query package.json
61- const defaultFormat = 'json' ; // TODO is this correct as default?
48+ const anyURLToPathOrUndefined = ( url ) => {
49+ try {
50+ return fileURLToPath ( url ) ;
51+ } catch ( error ) {
52+ if ( error instanceof TypeError && error . code === 'ERR_INVALID_URL_SCHEME' ) {
53+ return undefined ;
54+ }
6255
63- return (
64- getFormatWithCertitude ( filename ) ??
65- ( / \. j s $ / . test ( filename ) ? packageType : defaultFormat )
66- ) ;
56+ throw error ;
57+ }
6758} ;
6859
69- const getSourceType = ( filename ) => {
70- // TODO replace with getFormat once getFormat queries package.json
71- const format = getFormatWithCertitude ( filename ) ;
60+ const isBabelConfigFile = ( filename ) => {
61+ const basename = path . basename ( filename ) ;
62+ return BABEL_CONFIG_FILES . has ( basename ) ;
63+ } ;
7264
65+ const getSourceType = ( format ) => {
7366 switch ( format ) {
7467 case 'module' :
7568 return 'module' ;
@@ -80,41 +73,60 @@ const getSourceType = (filename) => {
8073 }
8174} ;
8275
83- const skip = ( url ) => {
84- return / n o d e _ m o d u l e s / . test ( url ) || / n o d e : / . test ( url ) ;
85- } ;
76+ const prepare = async ( url , context , defaultLoad ) => {
77+ const original = await defaultLoad ( url , context , defaultLoad ) ;
8678
87- const transformLoad = async ( url , context , defaultLoad ) => {
88- const { source} = await defaultLoad ( url , context , defaultLoad ) ;
79+ const noop = ( ) => ( {
80+ transform : false ,
81+ original,
82+ } ) ;
8983
90- const filename = urlModule . fileURLToPath ( url ) ;
91- // Babel config files can themselves be ES modules,
92- // but we cannot transform those since doing so would cause an infinite loop.
93- if ( isBabelConfigFile ( filename ) ) {
94- return {
95- source,
96- format : getFormat ( filename ) ,
97- } ;
84+ if (
85+ / n o d e _ m o d u l e s / . test ( url ) ||
86+ / n o d e : / . test ( url ) ||
87+ ! BABEL_FORMATS_TRANSFORMED . has ( original . format )
88+ ) {
89+ return noop ( ) ;
9890 }
9991
92+ const filename = anyURLToPathOrUndefined ( url ) ;
93+
94+ // Babel config files can themselves be ES modules,
95+ // but transforming those could require more than one pass.
96+ if ( isBabelConfigFile ( filename ) ) return noop ( ) ;
97+
98+ return {
99+ transform : true ,
100+ original,
101+ options : {
102+ filename,
103+ } ,
104+ } ;
105+ } ;
106+
107+ const transformed = async ( { format, source} , { filename} ) => {
100108 const options = await loadOptionsAsync ( {
101- sourceType : getSourceType ( filename ) ,
109+ sourceType : getSourceType ( format ) ,
102110 root : process . cwd ( ) ,
103111 rootMode : 'root' ,
104112 filename,
105113 configFile : true ,
106114 } ) ;
107- const transformed = await transformAsync ( source , options ) ;
115+
116+ const result = await transformAsync ( source , options ) ;
108117
109118 return {
110- source : transformed . code ,
119+ source : result . code ,
111120 // TODO: look at babel config to see whether it will output ESM/CJS or other formats
112- format : getFormat ( filename ) ,
121+ format,
113122 } ;
114123} ;
115124
116125export const load = async ( url , context , defaultLoad ) => {
117- return skip ( url )
118- ? defaultLoad ( url , context , defaultLoad )
119- : transformLoad ( url , context , defaultLoad ) ;
126+ const { transform, original, options} = await prepare (
127+ url ,
128+ context ,
129+ defaultLoad ,
130+ ) ;
131+ return transform ? transformed ( original , options ) : original ;
120132} ;
0 commit comments