forked from rollup/plugins
/
tsconfig.ts
193 lines (173 loc) · 6.03 KB
/
tsconfig.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import { readFileSync } from 'fs';
import { dirname, resolve } from 'path';
import { PluginContext } from 'rollup';
import type {
Diagnostic,
ExtendedConfigCacheEntry,
MapLike,
ParsedCommandLine,
ProjectReference,
TypeAcquisition,
WatchDirectoryFlags,
WatchOptions
} from 'typescript';
import { RollupTypescriptOptions } from '../../types';
import diagnosticToWarning from '../diagnostics/toWarning';
import {
CompilerOptions,
DEFAULT_COMPILER_OPTIONS,
EnumCompilerOptions,
FORCED_COMPILER_OPTIONS,
OVERRIDABLE_EMIT_COMPILER_OPTIONS,
PartialCompilerOptions
} from './interfaces';
import { normalizeCompilerOptions, makePathsAbsolute } from './normalize';
export interface TypeScriptConfig {
autoSetSourceMap: boolean;
options: CompilerOptions;
typeAcquisition?: TypeAcquisition | undefined;
fileNames: string[];
projectReferences?: readonly ProjectReference[] | undefined;
watchOptions?: WatchOptions | undefined;
raw?: any;
errors: Diagnostic[];
wildcardDirectories?: MapLike<WatchDirectoryFlags> | undefined;
compileOnSave?: boolean | undefined;
}
function makeForcedCompilerOptions(noForceEmit: boolean) {
return { ...FORCED_COMPILER_OPTIONS, ...(noForceEmit ? OVERRIDABLE_EMIT_COMPILER_OPTIONS : {}) };
}
/**
* Finds the path to the tsconfig file relative to the current working directory.
* @param relativePath Relative tsconfig path given by the user.
* If `false` is passed, then a null path is returned.
* @returns The absolute path, or null if the file does not exist.
*/
function getTsConfigPath(ts: typeof import('typescript'), relativePath?: string | false) {
if (relativePath === false) return null;
// Resolve path to file. `tsConfigOption` defaults to 'tsconfig.json'.
const tsConfigPath = resolve(process.cwd(), relativePath || 'tsconfig.json');
if (!ts.sys.fileExists(tsConfigPath)) {
if (relativePath) {
// If an explicit path was provided but no file was found, throw
throw new Error(`Could not find specified tsconfig.json at ${tsConfigPath}`);
} else {
return null;
}
}
return tsConfigPath;
}
/**
* Tries to read the tsconfig file at `tsConfigPath`.
* @param tsConfigPath Absolute path to tsconfig JSON file.
* @param explicitPath If true, the path was set by the plugin user.
* If false, the path was computed automatically.
*/
function readTsConfigFile(ts: typeof import('typescript'), tsConfigPath: string) {
const { config, error } = ts.readConfigFile(tsConfigPath, (path) => readFileSync(path, 'utf8'));
if (error) {
throw Object.assign(Error(), diagnosticToWarning(ts, null, error));
}
return config || {};
}
/**
* Returns true if any of the `compilerOptions` contain an enum value (i.e.: ts.ScriptKind) rather than a string.
* This indicates that the internal CompilerOptions type is used rather than the JsonCompilerOptions.
*/
function containsEnumOptions(
compilerOptions: PartialCompilerOptions
): compilerOptions is Partial<CompilerOptions> {
const enums: Array<EnumCompilerOptions> = [
'module',
'target',
'jsx',
'moduleResolution',
'newLine'
];
return enums.some((prop) => prop in compilerOptions && typeof compilerOptions[prop] === 'number');
}
const configCache = new Map() as import('typescript').Map<ExtendedConfigCacheEntry>;
/**
* Parse the Typescript config to use with the plugin.
* @param ts Typescript library instance.
* @param tsconfig Path to the tsconfig file, or `false` to ignore the file.
* @param compilerOptions Options passed to the plugin directly for Typescript.
*
* @returns Parsed tsconfig.json file with some important properties:
* - `options`: Parsed compiler options.
* - `fileNames` Type definition files that should be included in the build.
* - `errors`: Any errors from parsing the config file.
*/
export function parseTypescriptConfig(
ts: typeof import('typescript'),
tsconfig: RollupTypescriptOptions['tsconfig'],
compilerOptions: PartialCompilerOptions,
noForceEmit: boolean
): TypeScriptConfig {
/* eslint-disable no-undefined */
const cwd = process.cwd();
makePathsAbsolute(compilerOptions, cwd);
let parsedConfig: ParsedCommandLine;
// Resolve path to file. If file is not found, pass undefined path to `parseJsonConfigFileContent`.
// eslint-disable-next-line no-undefined
const tsConfigPath = getTsConfigPath(ts, tsconfig) || undefined;
const tsConfigFile = tsConfigPath ? readTsConfigFile(ts, tsConfigPath) : {};
const basePath = tsConfigPath ? dirname(tsConfigPath) : cwd;
// If compilerOptions has enums, it represents an CompilerOptions object instead of parsed JSON.
// This determines where the data is passed to the parser.
if (containsEnumOptions(compilerOptions)) {
parsedConfig = ts.parseJsonConfigFileContent(
{
...tsConfigFile,
compilerOptions: {
...DEFAULT_COMPILER_OPTIONS,
...tsConfigFile.compilerOptions
}
},
ts.sys,
basePath,
{ ...compilerOptions, ...makeForcedCompilerOptions(noForceEmit) },
tsConfigPath,
undefined,
undefined,
configCache
);
} else {
parsedConfig = ts.parseJsonConfigFileContent(
{
...tsConfigFile,
compilerOptions: {
...DEFAULT_COMPILER_OPTIONS,
...tsConfigFile.compilerOptions,
...compilerOptions
}
},
ts.sys,
basePath,
makeForcedCompilerOptions(noForceEmit),
tsConfigPath,
undefined,
undefined,
configCache
);
}
const autoSetSourceMap = normalizeCompilerOptions(ts, parsedConfig.options);
return {
...parsedConfig,
autoSetSourceMap
};
}
/**
* If errors are detected in the parsed options,
* display all of them as warnings then emit an error.
*/
export function emitParsedOptionsErrors(
ts: typeof import('typescript'),
context: PluginContext,
parsedOptions: ParsedCommandLine
) {
if (parsedOptions.errors.length > 0) {
parsedOptions.errors.forEach((error) => context.warn(diagnosticToWarning(ts, null, error)));
context.error(`@rollup/plugin-typescript: Couldn't process compiler options`);
}
}