30
30
31
31
import process from 'process' ;
32
32
import 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' ;
35
35
36
- const { loadOptionsAsync , transformAsync } = babel ;
36
+ const BABEL_FORMATS_TRANSFORMED = new Set ( [ 'module' ] ) ;
37
37
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
+ ] ) ;
58
47
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
+ }
62
55
63
- return (
64
- getFormatWithCertitude ( filename ) ??
65
- ( / \. j s $ / . test ( filename ) ? packageType : defaultFormat )
66
- ) ;
56
+ throw error ;
57
+ }
67
58
} ;
68
59
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
+ } ;
72
64
65
+ const getSourceType = ( format ) => {
73
66
switch ( format ) {
74
67
case 'module' :
75
68
return 'module' ;
@@ -80,41 +73,60 @@ const getSourceType = (filename) => {
80
73
}
81
74
} ;
82
75
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 ) ;
86
78
87
- const transformLoad = async ( url , context , defaultLoad ) => {
88
- const { source} = await defaultLoad ( url , context , defaultLoad ) ;
79
+ const noop = ( ) => ( {
80
+ transform : false ,
81
+ original,
82
+ } ) ;
89
83
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 ( ) ;
98
90
}
99
91
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} ) => {
100
108
const options = await loadOptionsAsync ( {
101
- sourceType : getSourceType ( filename ) ,
109
+ sourceType : getSourceType ( format ) ,
102
110
root : process . cwd ( ) ,
103
111
rootMode : 'root' ,
104
112
filename,
105
113
configFile : true ,
106
114
} ) ;
107
- const transformed = await transformAsync ( source , options ) ;
115
+
116
+ const result = await transformAsync ( source , options ) ;
108
117
109
118
return {
110
- source : transformed . code ,
119
+ source : result . code ,
111
120
// TODO: look at babel config to see whether it will output ESM/CJS or other formats
112
- format : getFormat ( filename ) ,
121
+ format,
113
122
} ;
114
123
} ;
115
124
116
125
export 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 ;
120
132
} ;
0 commit comments