-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathindex.ts
154 lines (126 loc) · 3.5 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
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
import { join } from 'path';
import { Plugin } from 'rollup';
import {
CompilerOptions,
findConfigFile,
nodeModuleNameResolver,
parseConfigFileTextToJson,
sys,
} from 'typescript';
export const typescriptPaths = ({
absolute = true,
nonRelative = false,
preserveExtensions = false,
tsConfigPath = findConfigFile('./', sys.fileExists),
transform,
}: Options = {}): Plugin => {
const { compilerOptions, outDir } = getTsConfig(tsConfigPath);
return {
name: 'resolve-typescript-paths',
resolveId: (importee: string, importer?: string) => {
const enabled = Boolean(
compilerOptions.paths || (compilerOptions.baseUrl && nonRelative),
);
if (
typeof importer === 'undefined' ||
importee.startsWith('\0') ||
!enabled
) {
return null;
}
const hasMatchingPath =
!!compilerOptions.paths &&
Object.keys(compilerOptions.paths).some((path) =>
new RegExp('^' + escapeRegex(path.replace('*', '.+')) + '$').test(
importee,
),
);
if (!hasMatchingPath && !nonRelative) {
return null;
}
if (importee.startsWith('.')) {
return null; // never resolve relative modules, only non-relative
}
const { resolvedModule } = nodeModuleNameResolver(
importee,
importer,
compilerOptions,
sys,
);
if (!resolvedModule) {
return null;
}
const { resolvedFileName } = resolvedModule;
if (!resolvedFileName || resolvedFileName.endsWith('.d.ts')) {
return null;
}
const targetFileName = join(
outDir,
preserveExtensions
? resolvedFileName
: resolvedFileName.replace(/\.tsx?$/i, '.js'),
);
const resolved = absolute
? sys.resolvePath(targetFileName)
: targetFileName;
return transform ? transform(resolved) : resolved;
},
};
};
const getTsConfig = (configPath?: string): TsConfig => {
const defaults: TsConfig = { compilerOptions: {}, outDir: '.' };
if (!configPath) {
return defaults;
}
const configJson = sys.readFile(configPath);
if (!configJson) {
return defaults;
}
const { config } = parseConfigFileTextToJson(configPath, configJson);
return { ...defaults, ...config };
};
/**
* Escapes $ and ^ characters in the given string. This is necessary if you
* want to use `$/*` in your paths, for example.
*/
const escapeRegex = (str: string) => {
return str.replace(/[$^]/g, '\\$&');
};
export interface Options {
/**
* Whether to resolve to absolute paths; defaults to `true`.
*/
absolute?: boolean;
/**
* Whether to resolve non-relative paths based on tsconfig's `baseUrl`, even
* if none of the `paths` are matched; defaults to `false`.
*
* @see https://www.typescriptlang.org/docs/handbook/module-resolution.html#relative-vs-non-relative-module-imports
* @see https://www.typescriptlang.org/docs/handbook/module-resolution.html#base-url
*/
nonRelative?: boolean;
/**
* Whether to preserve `.ts` and `.tsx` file extensions instead of having them
* changed to `.js`; defaults to `false`.
*/
preserveExtensions?: boolean;
/**
* Custom path to your `tsconfig.json`. Use this if the plugin can't seem to
* find the correct one by itself.
*/
tsConfigPath?: string;
/**
* If the plugin successfully resolves a path, this function allows you to
* hook into the process and transform that path before it is returned.
*/
transform?(path: string): string;
}
interface TsConfig {
compilerOptions: CompilerOptions;
outDir: string;
}
/**
* For backwards compatibility.
*/
export const resolveTypescriptPaths = typescriptPaths;
export default typescriptPaths;