/
require.ts
98 lines (78 loc) · 2.56 KB
/
require.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
const { extname } = require('path');
const { readFileSync } = require('fs');
const tsm = require('./utils');
import type { Config, Options } from 'tsm/config';
type TSM = typeof import('./utils.d');
type Module = NodeJS.Module & {
_compile?(source: string, filename: string): typeof loader;
};
const loadJS = require.extensions['.js'];
let esbuild: typeof import('esbuild');
let env = (tsm as TSM).$defaults('cjs');
let uconf = env.file && require(env.file);
let config: Config = (tsm as TSM).$finalize(env, uconf);
declare const $$req: NodeJS.Require;
const tsrequire = 'var $$req=require;require=(' + function () {
let { existsSync } = $$req('fs');
let { URL, pathToFileURL } = $$req('url');
return new Proxy($$req, {
// NOTE: only here if source is TS
apply(req, ctx, args: [id: string]) {
let [ident] = args;
if (!ident) return req.apply(ctx || $$req, args);
// ignore "prefix:" and non-relative identifiers
if (/^\w+\:?/.test(ident)) return $$req(ident);
// exit early if no extension provided
let match = /\.([mc])?js(?=\?|$)/.exec(ident);
if (match == null) return $$req(ident);
let base = pathToFileURL(__filename) as import('url').URL;
let file = new URL(ident, base).pathname as string;
if (existsSync(file)) return $$req(ident);
// ?js -> ?ts file
file = file.replace(
new RegExp(match[0] + '$'),
match[0].replace('js', 'ts')
);
// return the new "[mc]ts" file, or let error
return existsSync(file) ? $$req(file) : $$req(ident);
}
})
} + ')();';
function transform(source: string, sourcefile: string, options: Options): string {
let banner = options.banner || '';
if (/\.[mc]?tsx?$/.test(sourcefile)) {
banner = tsrequire + banner;
}
esbuild = esbuild || require('esbuild');
return esbuild.transformSync(source, {
...options, banner, sourcefile
}).code;
}
function loader(Module: Module, sourcefile: string) {
let pitch = Module._compile!.bind(Module);
let extn = extname(sourcefile);
let options = config[extn];
if (options != null) {
Module._compile = source => {
let result = transform(source, sourcefile, options);
return pitch(result, sourcefile);
};
}
try {
return loadJS(Module, sourcefile);
} catch (err) {
let ec = err && (err as any).code;
if (ec !== 'ERR_REQUIRE_ESM') throw err;
let input = readFileSync(sourcefile, 'utf8');
let result = transform(input, sourcefile, {
...options, format: 'cjs'
});
return pitch(result, sourcefile);
}
}
for (let extn in config) {
require.extensions[extn] = loader;
}
if (config['.js'] == null) {
require.extensions['.js'] = loader;
}