-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathdetect.ts
155 lines (138 loc) · 4.05 KB
/
detect.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import type { FeaturesOptions, SupportedLoader } from './types'
export interface LoaderMatrix {
name: SupportedLoader
supported?: boolean
cache: boolean[]
listDependencies: boolean[]
type: ('module' | 'commonjs')[]
importTS: boolean[]
}
export interface LoaderDetectionContext extends Required<FeaturesOptions> {
isTs: boolean
}
let _loaderMatrix: LoaderMatrix[]
/**
* Internal function for tests
*/
export async function _createLoaderMatrix(options: {
isNativeTsImportSupported: boolean
isRuntimeSupportsTsx: boolean
}) {
const matrix: LoaderMatrix[] = [
{
name: 'native',
cache: [true],
listDependencies: [false],
type: ['module', 'commonjs'],
importTS: options.isNativeTsImportSupported
? [true, false]
: [false],
},
{
name: 'tsx',
supported: options.isRuntimeSupportsTsx,
type: ['module', 'commonjs'],
cache: [true, false],
listDependencies: [true, false],
importTS: [true, false],
},
{
name: 'jiti',
type: ['commonjs'],
cache: [true, false],
listDependencies: [true, false],
importTS: [true, false],
},
{
name: 'bundle-require',
type: ['module', 'commonjs'],
cache: [false],
listDependencies: [true],
importTS: [true, false],
},
]
return matrix
.filter(i => i.supported !== false)
}
export async function getLoaderMatrix(): Promise<LoaderMatrix[]> {
if (_loaderMatrix)
return _loaderMatrix
_loaderMatrix = await _createLoaderMatrix({
isNativeTsImportSupported: await isNativeTsImportSupported(),
isRuntimeSupportsTsx: await isRuntimeSupportsTsx(),
})
return _loaderMatrix
}
let _isNativeTsImportSupported: boolean | undefined
/**
* Import a tiny TypeScript module to verify if native TypeScript import is supported.
*/
export async function isNativeTsImportSupported(): Promise<boolean> {
if (_isNativeTsImportSupported === undefined) {
// @ts-expect-error missing `typescript` property
// eslint-disable-next-line node/prefer-global/process
if (typeof process !== 'undefined' && process.features?.typescript) {
return _isNativeTsImportSupported = true
}
try {
const modName = 'dummy.mts'
const mod = await import(`../runtime-fixtures/${modName}`)
_isNativeTsImportSupported = mod.default === 'dummy'
}
catch {
_isNativeTsImportSupported = false
}
}
return _isNativeTsImportSupported
}
// eslint-disable-next-line node/prefer-global/process
const nodeVersionNumbers = globalThis?.process?.versions?.node?.split('.').map(Number)
/**
* Detect the 'auto' loader to use for importing the file.
* @private
*/
export async function detectLoader(
context: LoaderDetectionContext,
matrix?: LoaderMatrix[],
): Promise<SupportedLoader | null> {
matrix = matrix || await getLoaderMatrix()
for (const loader of matrix) {
if (context.excludeLoaders?.includes(loader.name))
continue
if (
(context.cache === null || loader.cache.includes(context.cache))
&& (context.listDependencies === null || loader.listDependencies.includes(context.listDependencies))
&& (context.type === null || loader.type.includes(context.type))
&& loader.importTS.includes(context.isTs)
) {
return loader.name
}
}
return null
}
/**
* tsx is supported in v18.18.0+ and 20.8.0+
* Otherwise we fallback to jiti
*
* @see https://nodejs.org/api/module.html#moduleregisterspecifier-parenturl-options
*/
async function isRuntimeSupportsTsx() {
if (
!nodeVersionNumbers
|| nodeVersionNumbers[0] < 18
|| (nodeVersionNumbers[0] === 18 && nodeVersionNumbers[1] < 19)
|| (nodeVersionNumbers[0] === 20 && nodeVersionNumbers[1] < 8)
) {
return false
}
// Disable in Electron
// eslint-disable-next-line node/prefer-global/process
if (typeof process !== 'undefined' && typeof process.versions.electron === 'string') {
return false
}
return true
}
const reIsTypeScriptFile = /\.[mc]?tsx?$/
export function isTypeScriptFile(path: string) {
return reIsTypeScriptFile.test(path)
}