forked from aelbore/esbuild-jest
/
index.ts
86 lines (79 loc) · 2.62 KB
/
index.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
import { Loader, transformSync } from 'esbuild'
import path, { extname } from 'path'
export interface Options {
jsxFactory?: string
jsxFragment?: string
loaders?: {
[ext: string]: Loader
}
target?: string
}
export default {
createTransformer(options: Options | null) {
if (!options) options = {}
const { loaders = {} } = options
delete options.loaders
return {
process(content: string, filename: string) {
const ext = getExt(filename)
const strict = /^(im|ex)port /m.test(content)
const result = transformSync(content, {
loader: loaders[ext] || (extname(filename).slice(1) as Loader),
format: 'cjs',
target: 'es2018',
sourcemap: 'external',
sourcefile: filename,
...options,
// Esbuild does not enable strict mode when compiling ES modules to
// CommonJS format: https://github.com/evanw/esbuild/issues/422#issuecomment-739740602
banner: strict ? '"use strict";' : undefined,
})
if (/\bjest\.mock\b/.test(result.code)) {
const { nebu } = require('nebu') as typeof import('nebu')
result.code = nebu.process(result.code, {
plugins: [hoistJestMock],
state: { strict },
}).js
}
const map = {
...JSON.parse(result.map),
sourcesContent: null,
}
// Append the inline sourcemap manually to ensure the "sourcesContent"
// is null. Otherwise, breakpoints won't pause within the actual source.
return {
code:
result.code +
'\n//# sourceMappingURL=data:application/json;base64,' +
Buffer.from(JSON.stringify(map)).toString('base64'),
map,
}
},
}
},
}
function getExt(str: string) {
const basename = path.basename(str)
const firstDot = basename.indexOf('.')
const lastDot = basename.lastIndexOf('.')
const extname = path.extname(basename).replace(/(\.[a-z0-9]+).*/i, '$1')
if (firstDot === lastDot) return extname
return basename.slice(firstDot, lastDot) + extname
}
const hoistJestMock: import('nebu').Plugin = {
Program(prog, { strict }) {
// Keep "use strict" on top.
const hoistTo = strict ? prog.body[1] : prog
prog.walk('body', stmt => {
if (!stmt.isExpressionStatement()) return
const expr = stmt.expression
if (!expr.isCallExpression()) return
if (!expr.callee.isMemberExpression()) return
const callee = expr.callee.toString()
if (callee == 'jest.mock') {
hoistTo.before(stmt.toString() + '\n')
stmt.remove()
}
})
},
}