forked from rollup/rollup
-
Notifications
You must be signed in to change notification settings - Fork 0
/
resolveId.ts
104 lines (95 loc) · 3.26 KB
/
resolveId.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
import type { ModuleLoaderResolveId } from '../ModuleLoader';
import type { CustomPluginOptions, Plugin, ResolveIdResult } from '../rollup/types';
import type { PluginDriver } from './PluginDriver';
import { lstat, readdir, realpath } from './fs';
import { basename, dirname, isAbsolute, resolve } from './path';
import { resolveIdViaPlugins } from './resolveIdViaPlugins';
export async function resolveId(
source: string,
importer: string | undefined,
preserveSymlinks: boolean | 'auto',
pluginDriver: PluginDriver,
moduleLoaderResolveId: ModuleLoaderResolveId,
skip: readonly { importer: string | undefined; plugin: Plugin; source: string }[] | null,
customOptions: CustomPluginOptions | undefined,
isEntry: boolean,
attributes: Record<string, string>
): Promise<ResolveIdResult> {
const pluginResult = await resolveIdViaPlugins(
source,
importer,
pluginDriver,
moduleLoaderResolveId,
skip,
customOptions,
isEntry,
attributes
);
if (pluginResult != null) {
const [resolveIdResult, plugin] = pluginResult;
if (typeof resolveIdResult === 'object' && !resolveIdResult.resolvedBy) {
return {
...resolveIdResult,
resolvedBy: plugin.name
};
}
if (typeof resolveIdResult === 'string') {
return {
id: resolveIdResult,
resolvedBy: plugin.name
};
}
return resolveIdResult;
}
// external modules (non-entry modules that start with neither '.' or '/')
// are skipped at this stage.
if (importer !== undefined && !isAbsolute(source) && source[0] !== '.') return null;
switch (preserveSymlinks) {
case 'auto': {
// Try to resolve the importee.
if (!importer) return addJsExtensionIfNecessary(resolve(source), true);
const resolved = await addJsExtensionIfNecessary(resolve(dirname(importer), source), true);
if (resolved) return resolved;
// Since resolving the importee failed, see if the importer is a symlink and can be resolved.
importer = await addJsExtensionIfNecessary(resolve(importer), false);
if (!importer) return;
// Try again
return addJsExtensionIfNecessary(resolve(dirname(importer), source), true);
}
default: {
// `resolve` processes paths from right to left, prepending them until an
// absolute path is created. Absolute importees therefore shortcircuit the
// resolve call and require no special handing on our part.
// See https://nodejs.org/api/path.html#path_path_resolve_paths
return addJsExtensionIfNecessary(
importer ? resolve(dirname(importer), source) : resolve(source),
preserveSymlinks
);
}
}
}
async function addJsExtensionIfNecessary(
file: string,
preserveSymlinks: boolean
): Promise<string | undefined> {
return (
(await findFile(file, preserveSymlinks)) ??
(await findFile(file + '.mjs', preserveSymlinks)) ??
(await findFile(file + '.js', preserveSymlinks))
);
}
async function findFile(file: string, preserveSymlinks: boolean): Promise<string | undefined> {
try {
const stats = await lstat(file);
if (!preserveSymlinks && stats.isSymbolicLink())
return await findFile(await realpath(file), preserveSymlinks);
if ((preserveSymlinks && stats.isSymbolicLink()) || stats.isFile()) {
// check case
const name = basename(file);
const files = await readdir(dirname(file));
if (files.includes(name)) return file;
}
} catch {
// suppress
}
}