/
resolve-id.js
128 lines (115 loc) · 3.88 KB
/
resolve-id.js
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
/* eslint-disable no-param-reassign, no-undefined */
import { statSync } from 'fs';
import { dirname, resolve, sep } from 'path';
import {
DYNAMIC_MODULES_ID,
ENTRY_SUFFIX,
ES_IMPORT_SUFFIX,
EXPORTS_SUFFIX,
EXTERNAL_SUFFIX,
HELPERS_ID,
IS_WRAPPED_COMMONJS,
isWrappedId,
MODULE_SUFFIX,
PROXY_SUFFIX,
unwrapId,
wrapId,
WRAPPED_SUFFIX
} from './helpers';
function getCandidatesForExtension(resolved, extension) {
return [resolved + extension, `${resolved}${sep}index${extension}`];
}
function getCandidates(resolved, extensions) {
return extensions.reduce(
(paths, extension) => paths.concat(getCandidatesForExtension(resolved, extension)),
[resolved]
);
}
export function resolveExtensions(importee, importer, extensions) {
// not our problem
if (importee[0] !== '.' || !importer) return undefined;
const resolved = resolve(dirname(importer), importee);
const candidates = getCandidates(resolved, extensions);
for (let i = 0; i < candidates.length; i += 1) {
try {
const stats = statSync(candidates[i]);
if (stats.isFile()) return { id: candidates[i] };
} catch (err) {
/* noop */
}
}
return undefined;
}
export default function getResolveId(extensions) {
return async function resolveId(importee, importer, resolveOptions) {
// We assume that all requires are pre-resolved
const customOptions = resolveOptions.custom;
if (customOptions && customOptions['node-resolve'] && customOptions['node-resolve'].isRequire) {
return null;
}
if (isWrappedId(importee, WRAPPED_SUFFIX)) {
return unwrapId(importee, WRAPPED_SUFFIX);
}
if (
importee.endsWith(ENTRY_SUFFIX) ||
isWrappedId(importee, MODULE_SUFFIX) ||
isWrappedId(importee, EXPORTS_SUFFIX) ||
isWrappedId(importee, PROXY_SUFFIX) ||
isWrappedId(importee, ES_IMPORT_SUFFIX) ||
isWrappedId(importee, EXTERNAL_SUFFIX) ||
importee.startsWith(HELPERS_ID) ||
importee === DYNAMIC_MODULES_ID
) {
return importee;
}
if (importer) {
if (
importer === DYNAMIC_MODULES_ID ||
// Proxies are only importing resolved ids, no need to resolve again
isWrappedId(importer, PROXY_SUFFIX) ||
isWrappedId(importer, ES_IMPORT_SUFFIX) ||
importer.endsWith(ENTRY_SUFFIX)
) {
return importee;
}
if (isWrappedId(importer, EXTERNAL_SUFFIX)) {
// We need to return null for unresolved imports so that the proper warning is shown
if (!(await this.resolve(importee, importer, { skipSelf: true }))) {
return null;
}
// For other external imports, we need to make sure they are handled as external
return { id: importee, external: true };
}
}
if (importee.startsWith('\0')) {
return null;
}
// If this is an entry point or ESM import, we need to figure out if the importee is wrapped and
// if that is the case, we need to add a proxy.
const resolved =
(await this.resolve(importee, importer, Object.assign({ skipSelf: true }, resolveOptions))) ||
resolveExtensions(importee, importer, extensions);
// Make sure that even if other plugins resolve again, we ignore our own proxies
if (
!resolved ||
resolved.external ||
resolved.id.endsWith(ENTRY_SUFFIX) ||
isWrappedId(resolved.id, ES_IMPORT_SUFFIX)
) {
return resolved;
}
const moduleInfo = await this.load(resolved);
if (resolveOptions.isEntry) {
moduleInfo.moduleSideEffects = true;
// We must not precede entry proxies with a `\0` as that will mess up relative external resolution
return resolved.id + ENTRY_SUFFIX;
}
const {
meta: { commonjs: commonjsMeta }
} = moduleInfo;
if (commonjsMeta && commonjsMeta.isCommonJS === IS_WRAPPED_COMMONJS) {
return wrapId(resolved.id, ES_IMPORT_SUFFIX);
}
return resolved;
};
}