Skip to content

Commit decdaaa

Browse files
♻️ refactor(test): Rewrite babel loader.
1 parent fb2e30c commit decdaaa

File tree

1 file changed

+65
-53
lines changed

1 file changed

+65
-53
lines changed

test/loader/babel.js

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -30,46 +30,39 @@
3030

3131
import process from 'process';
3232
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';
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 /\.cjs$/.test(filename)
53-
? 'commonjs'
54-
: /\.mjs$/.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-
(/\.js$/.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 /node_modules/.test(url) || /node:/.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+
/node_modules/.test(url) ||
86+
/node:/.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

116125
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;
120132
};

0 commit comments

Comments
 (0)