1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.getSolutionErrors = exports.makeSolutionBuilderHost = exports.makeWatchHost = exports.updateFileWithText = exports.makeServicesHost = void 0;
|
4 | const path = require("path");
|
5 | const config_1 = require("./config");
|
6 | const constants = require("./constants");
|
7 | const instances_1 = require("./instances");
|
8 | const resolver_1 = require("./resolver");
|
9 | const utils_1 = require("./utils");
|
10 | function makeResolversHandlingProjectReferences(scriptRegex, loader, instance, originalFileExists, enableFileCaching) {
|
11 | const { compiler, compilerOptions, appendTsTsxSuffixesIfRequired, loaderOptions: { resolveModuleName: customResolveModuleName, resolveTypeReferenceDirective: customResolveTypeReferenceDirective, }, } = instance;
|
12 | const newLine = compilerOptions.newLine === constants.CarriageReturnLineFeedCode
|
13 | ? constants.CarriageReturnLineFeed
|
14 | : compilerOptions.newLine === constants.LineFeedCode
|
15 | ? constants.LineFeed
|
16 | : constants.EOL;
|
17 |
|
18 | const getCurrentDirectory = () => loader.context;
|
19 |
|
20 | const resolveSync = resolver_1.makeResolver(loader._compiler.options);
|
21 | const moduleResolutionHost = {
|
22 | trace: logData => instance.log.log(logData),
|
23 | fileExists,
|
24 | readFile,
|
25 | realpath: compiler.sys.realpath && realpath,
|
26 | directoryExists,
|
27 | getCurrentDirectory,
|
28 | getDirectories,
|
29 | readDirectory,
|
30 | useCaseSensitiveFileNames: () => utils_1.useCaseSensitiveFileNames(compiler, instance.loaderOptions),
|
31 | getNewLine: () => newLine,
|
32 | getDefaultLibFileName: options => compiler.getDefaultLibFilePath(options),
|
33 | };
|
34 | if (enableFileCaching) {
|
35 | addCache(moduleResolutionHost);
|
36 | }
|
37 | return makeResolvers(compiler, compilerOptions, moduleResolutionHost, customResolveTypeReferenceDirective, customResolveModuleName, resolveSync, appendTsTsxSuffixesIfRequired, scriptRegex, instance);
|
38 | function fileExists(filePathToCheck) {
|
39 | var _a;
|
40 | const outputFile = (_a = instance.solutionBuilderHost) === null || _a === void 0 ? void 0 : _a.getOutputFileFromReferencedProject(filePathToCheck);
|
41 | if (outputFile !== undefined) {
|
42 | return !!outputFile;
|
43 | }
|
44 | return originalFileExists(filePathToCheck);
|
45 | }
|
46 | function readFile(filePath, encoding) {
|
47 | var _a;
|
48 | const outputFile = (_a = instance.solutionBuilderHost) === null || _a === void 0 ? void 0 : _a.getOutputFileFromReferencedProject(filePath);
|
49 | if (outputFile !== undefined) {
|
50 | return outputFile ? outputFile.text : undefined;
|
51 | }
|
52 | return (instance.compiler.sys.readFile(filePath, encoding) ||
|
53 | utils_1.fsReadFile(filePath, encoding));
|
54 | }
|
55 | function directoryExists(directoryName) {
|
56 | return instance.solutionBuilderHost
|
57 | ? instance.solutionBuilderHost.directoryExists(directoryName)
|
58 | : compiler.sys.directoryExists(directoryName);
|
59 | }
|
60 | function realpath(path) {
|
61 | return instance.solutionBuilderHost
|
62 | ? instance.solutionBuilderHost.realpath(path)
|
63 | : compiler.sys.realpath(path);
|
64 | }
|
65 | function getDirectories(path) {
|
66 | return instance.solutionBuilderHost
|
67 | ? instance.solutionBuilderHost.getDirectories(path)
|
68 | : compiler.sys.getDirectories(path);
|
69 | }
|
70 | function readDirectory(path, extensions, exclude, include, depth) {
|
71 | return instance.solutionBuilderHost
|
72 | ? instance.solutionBuilderHost.readDirectory(path, extensions, exclude, include, depth)
|
73 | : compiler.sys.readDirectory(path, extensions, exclude, include, depth);
|
74 | }
|
75 | }
|
76 |
|
77 |
|
78 |
|
79 | function makeServicesHost(scriptRegex, loader, instance, projectReferences) {
|
80 | const { compiler, compilerOptions, files, filePathKeyMapper } = instance;
|
81 | const { moduleResolutionHost: { fileExists, readFile, trace, directoryExists, realpath, getCurrentDirectory, getDirectories, clearCache, useCaseSensitiveFileNames, getNewLine, getDefaultLibFileName, readDirectory, }, resolveModuleNames, resolveTypeReferenceDirectives, } = makeResolversHandlingProjectReferences(scriptRegex, loader, instance, filePathToCheck => compiler.sys.fileExists(filePathToCheck) ||
|
82 | utils_1.fsReadFile(filePathToCheck) !== undefined, instance.loaderOptions.experimentalFileCaching);
|
83 | const servicesHost = {
|
84 | getProjectVersion: () => `${instance.version}`,
|
85 | getProjectReferences: () => projectReferences,
|
86 | getScriptFileNames: () => [...files.values()]
|
87 | .map(({ fileName }) => fileName)
|
88 | .filter(filePath => filePath.match(scriptRegex)),
|
89 | getScriptVersion: (fileName) => {
|
90 | fileName = path.normalize(fileName);
|
91 | const key = filePathKeyMapper(fileName);
|
92 | const file = files.get(key);
|
93 | if (file) {
|
94 | return file.version.toString();
|
95 | }
|
96 | const outputFileAndKey = instance.solutionBuilderHost &&
|
97 | instance.solutionBuilderHost.getOutputFileAndKeyFromReferencedProject(fileName);
|
98 | if (outputFileAndKey !== undefined) {
|
99 | instance.solutionBuilderHost.outputAffectingInstanceVersion.set(outputFileAndKey.key, true);
|
100 | }
|
101 | return outputFileAndKey && outputFileAndKey.outputFile
|
102 | ? outputFileAndKey.outputFile.version.toString()
|
103 | : '';
|
104 | },
|
105 | getScriptSnapshot: (fileName) => {
|
106 |
|
107 |
|
108 | fileName = path.normalize(fileName);
|
109 | const key = filePathKeyMapper(fileName);
|
110 | let file = files.get(key);
|
111 | if (file === undefined) {
|
112 | if (instance.solutionBuilderHost) {
|
113 | const outputFileAndKey = instance.solutionBuilderHost.getOutputFileAndKeyFromReferencedProject(fileName);
|
114 | if (outputFileAndKey !== undefined) {
|
115 | instance.solutionBuilderHost.outputAffectingInstanceVersion.set(outputFileAndKey.key, true);
|
116 | return outputFileAndKey && outputFileAndKey.outputFile
|
117 | ? compiler.ScriptSnapshot.fromString(outputFileAndKey.outputFile.text)
|
118 | : undefined;
|
119 | }
|
120 | }
|
121 | const text = readFile(fileName);
|
122 | if (text === undefined) {
|
123 | return undefined;
|
124 | }
|
125 | file = { fileName, version: 0, text };
|
126 | files.set(key, file);
|
127 | }
|
128 | return compiler.ScriptSnapshot.fromString(file.text);
|
129 | },
|
130 | |
131 |
|
132 |
|
133 |
|
134 | getDirectories,
|
135 | |
136 |
|
137 |
|
138 | directoryExists,
|
139 | useCaseSensitiveFileNames,
|
140 | realpath,
|
141 |
|
142 | fileExists,
|
143 | readFile,
|
144 | readDirectory,
|
145 | getCurrentDirectory,
|
146 | getCompilationSettings: () => compilerOptions,
|
147 | getDefaultLibFileName,
|
148 | getNewLine,
|
149 | trace,
|
150 | log: trace,
|
151 |
|
152 | resolveTypeReferenceDirectives,
|
153 | resolveModuleNames,
|
154 | getCustomTransformers: () => instance.transformers,
|
155 | clearCache,
|
156 | };
|
157 | return servicesHost;
|
158 | }
|
159 | exports.makeServicesHost = makeServicesHost;
|
160 | function makeResolvers(compiler, compilerOptions, moduleResolutionHost, customResolveTypeReferenceDirective, customResolveModuleName, resolveSync, appendTsTsxSuffixesIfRequired, scriptRegex, instance) {
|
161 | const resolveTypeReferenceDirective = makeResolveTypeReferenceDirective(compiler, compilerOptions, moduleResolutionHost, customResolveTypeReferenceDirective);
|
162 | const resolveTypeReferenceDirectives = (typeDirectiveNames, containingFile, _redirectedReference) => typeDirectiveNames.map(directive => resolveTypeReferenceDirective(directive, containingFile, _redirectedReference).resolvedTypeReferenceDirective);
|
163 | const resolveModuleName = makeResolveModuleName(compiler, compilerOptions, moduleResolutionHost, customResolveModuleName);
|
164 | const resolveModuleNames = (moduleNames, containingFile, _reusedNames, _redirectedReference) => {
|
165 | const resolvedModules = moduleNames.map(moduleName => resolveModule(resolveSync, resolveModuleName, appendTsTsxSuffixesIfRequired, scriptRegex, moduleName, containingFile));
|
166 | utils_1.populateDependencyGraph(resolvedModules, instance, containingFile);
|
167 | return resolvedModules;
|
168 | };
|
169 | return {
|
170 | resolveTypeReferenceDirectives,
|
171 | resolveModuleNames,
|
172 | moduleResolutionHost,
|
173 | };
|
174 | }
|
175 | function createWatchFactory(filePathKeyMapper, compiler) {
|
176 | const watchedFiles = new Map();
|
177 | const watchedDirectories = new Map();
|
178 | const watchedDirectoriesRecursive = new Map();
|
179 | return {
|
180 | watchedFiles,
|
181 | watchedDirectories,
|
182 | watchedDirectoriesRecursive,
|
183 | invokeFileWatcher,
|
184 | watchFile,
|
185 | watchDirectory,
|
186 | };
|
187 | function invokeWatcherCallbacks(map, key, fileName, eventKind) {
|
188 | var _a;
|
189 | const callbacks = (_a = map.get(filePathKeyMapper(key))) === null || _a === void 0 ? void 0 : _a.callbacks;
|
190 | if (callbacks !== undefined && callbacks.length) {
|
191 |
|
192 |
|
193 | const cbs = callbacks.slice();
|
194 | for (const cb of cbs) {
|
195 | cb(fileName, eventKind);
|
196 | }
|
197 | return true;
|
198 | }
|
199 | return false;
|
200 | }
|
201 | function invokeFileWatcher(fileName, eventKind) {
|
202 | fileName = path.normalize(fileName);
|
203 | let result = invokeWatcherCallbacks(watchedFiles, fileName, fileName, eventKind);
|
204 | if (eventKind !== compiler.FileWatcherEventKind.Changed) {
|
205 | const directory = path.dirname(fileName);
|
206 | result =
|
207 | invokeWatcherCallbacks(watchedDirectories, directory, fileName) ||
|
208 | result;
|
209 | result = invokeRecursiveDirectoryWatcher(directory, fileName) || result;
|
210 | }
|
211 | return result;
|
212 | }
|
213 | ``;
|
214 | function invokeRecursiveDirectoryWatcher(directory, fileAddedOrRemoved) {
|
215 | directory = path.normalize(directory);
|
216 | let result = invokeWatcherCallbacks(watchedDirectoriesRecursive, directory, fileAddedOrRemoved);
|
217 | const basePath = path.dirname(directory);
|
218 | if (directory !== basePath) {
|
219 | result =
|
220 | invokeRecursiveDirectoryWatcher(basePath, fileAddedOrRemoved) || result;
|
221 | }
|
222 | return result;
|
223 | }
|
224 | function createWatcher(file, callbacks, callback) {
|
225 | const key = filePathKeyMapper(file);
|
226 | const existing = callbacks.get(key);
|
227 | if (existing === undefined) {
|
228 | callbacks.set(key, {
|
229 | fileName: path.normalize(file),
|
230 | callbacks: [callback],
|
231 | });
|
232 | }
|
233 | else {
|
234 | existing.callbacks.push(callback);
|
235 | }
|
236 | return {
|
237 | close: () => {
|
238 | const existing = callbacks.get(key);
|
239 | if (existing !== undefined) {
|
240 | utils_1.unorderedRemoveItem(existing.callbacks, callback);
|
241 | if (!existing.callbacks.length) {
|
242 | callbacks.delete(key);
|
243 | }
|
244 | }
|
245 | },
|
246 | };
|
247 | }
|
248 | function watchFile(fileName, callback, _pollingInterval) {
|
249 | return createWatcher(fileName, watchedFiles, callback);
|
250 | }
|
251 | function watchDirectory(fileName, callback, recursive) {
|
252 | return createWatcher(fileName, recursive === true ? watchedDirectoriesRecursive : watchedDirectories, callback);
|
253 | }
|
254 | }
|
255 | function updateFileWithText(instance, key, filePath, text) {
|
256 | const nFilePath = path.normalize(filePath);
|
257 | const file = instance.files.get(key) || instance.otherFiles.get(key);
|
258 | if (file !== undefined) {
|
259 | const newText = text(nFilePath);
|
260 | if (newText !== file.text) {
|
261 | file.text = newText;
|
262 | file.version++;
|
263 | file.modifiedTime = new Date();
|
264 | instance.version++;
|
265 | if (!instance.modifiedFiles) {
|
266 | instance.modifiedFiles = new Map();
|
267 | }
|
268 | instance.modifiedFiles.set(key, true);
|
269 | if (instance.watchHost !== undefined) {
|
270 | instance.watchHost.invokeFileWatcher(nFilePath, instance.compiler.FileWatcherEventKind.Changed);
|
271 | }
|
272 | if (instance.solutionBuilderHost !== undefined) {
|
273 | instance.solutionBuilderHost.invokeFileWatcher(nFilePath, instance.compiler.FileWatcherEventKind.Changed);
|
274 | }
|
275 | }
|
276 | }
|
277 | }
|
278 | exports.updateFileWithText = updateFileWithText;
|
279 |
|
280 |
|
281 |
|
282 | function makeWatchHost(scriptRegex, loader, instance, projectReferences) {
|
283 | const { compiler, compilerOptions, files, otherFiles, filePathKeyMapper, } = instance;
|
284 | const { watchFile, watchDirectory, invokeFileWatcher } = createWatchFactory(filePathKeyMapper, compiler);
|
285 | const { moduleResolutionHost: { fileExists, readFile, trace, directoryExists, realpath, getCurrentDirectory, getDirectories, useCaseSensitiveFileNames, getNewLine, getDefaultLibFileName, readDirectory, }, resolveModuleNames, resolveTypeReferenceDirectives, } = makeResolversHandlingProjectReferences(scriptRegex, loader, instance, (fileName) => {
|
286 | const filePath = filePathKeyMapper(fileName);
|
287 | return files.has(filePath) || compiler.sys.fileExists(filePath);
|
288 | },
|
289 | false);
|
290 | const watchHost = {
|
291 | rootFiles: getRootFileNames(),
|
292 | options: compilerOptions,
|
293 | useCaseSensitiveFileNames,
|
294 | getNewLine,
|
295 | getCurrentDirectory,
|
296 | getDefaultLibFileName,
|
297 | fileExists,
|
298 | readFile: readFileWithCachingText,
|
299 | directoryExists,
|
300 | getDirectories,
|
301 | readDirectory,
|
302 | realpath,
|
303 | trace,
|
304 | watchFile: (fileName, callback, pollingInterval, options) => {
|
305 | var _a;
|
306 | const outputFileAndKey = (_a = instance.solutionBuilderHost) === null || _a === void 0 ? void 0 : _a.getOutputFileAndKeyFromReferencedProject(fileName);
|
307 | if (!outputFileAndKey ||
|
308 | outputFileAndKey.key === filePathKeyMapper(fileName)) {
|
309 | return watchFile(fileName, callback, pollingInterval, options);
|
310 | }
|
311 |
|
312 | const outputFileName = instance.solutionBuilderHost.realpath(fileName);
|
313 | const watcher = watchFile(outputFileName, (_fileName, eventKind) => callback(fileName, eventKind), pollingInterval, options);
|
314 | return { close: () => watcher.close() };
|
315 | },
|
316 | watchDirectory,
|
317 |
|
318 | resolveTypeReferenceDirectives,
|
319 | resolveModuleNames,
|
320 | invokeFileWatcher,
|
321 | updateRootFileNames: () => {
|
322 | instance.changedFilesList = false;
|
323 | if (instance.watchOfFilesAndCompilerOptions !== undefined) {
|
324 | instance.watchOfFilesAndCompilerOptions.updateRootFileNames(getRootFileNames());
|
325 | }
|
326 | },
|
327 | createProgram: projectReferences === undefined
|
328 | ? compiler.createEmitAndSemanticDiagnosticsBuilderProgram
|
329 | : createBuilderProgramWithReferences,
|
330 | outputFiles: new Map(),
|
331 | };
|
332 | return watchHost;
|
333 | function getRootFileNames() {
|
334 | return [...files.values()]
|
335 | .map(({ fileName }) => fileName)
|
336 | .filter(filePath => filePath.match(scriptRegex));
|
337 | }
|
338 | function readFileWithCachingText(fileName, encoding) {
|
339 | var _a;
|
340 | fileName = path.normalize(fileName);
|
341 | const key = filePathKeyMapper(fileName);
|
342 | const file = files.get(key) || otherFiles.get(key);
|
343 | if (file !== undefined) {
|
344 | return file.text;
|
345 | }
|
346 | const text = readFile(fileName, encoding);
|
347 | if (text === undefined) {
|
348 | return undefined;
|
349 | }
|
350 | if (!((_a = instance.solutionBuilderHost) === null || _a === void 0 ? void 0 : _a.getOutputFileKeyFromReferencedProject(fileName))) {
|
351 | otherFiles.set(key, { fileName, version: 0, text });
|
352 | }
|
353 | return text;
|
354 | }
|
355 | function createBuilderProgramWithReferences(rootNames, options, host, oldProgram, configFileParsingDiagnostics) {
|
356 | const program = compiler.createProgram({
|
357 | rootNames: rootNames,
|
358 | options: options,
|
359 | host,
|
360 | oldProgram: oldProgram && oldProgram.getProgram(),
|
361 | configFileParsingDiagnostics,
|
362 | projectReferences,
|
363 | });
|
364 | const builderProgramHost = host;
|
365 | return compiler.createEmitAndSemanticDiagnosticsBuilderProgram(program, builderProgramHost, oldProgram, configFileParsingDiagnostics);
|
366 | }
|
367 | }
|
368 | exports.makeWatchHost = makeWatchHost;
|
369 | function normalizeSlashes(file) {
|
370 | return file.replace(/\\/g, '/');
|
371 | }
|
372 |
|
373 |
|
374 |
|
375 | function makeSolutionBuilderHost(scriptRegex, loader, instance) {
|
376 | const { compiler, compilerOptions, appendTsTsxSuffixesIfRequired, loaderOptions: { resolveModuleName: customResolveModuleName, resolveTypeReferenceDirective: customResolveTypeReferenceDirective, transpileOnly, }, filePathKeyMapper, } = instance;
|
377 |
|
378 | const getCurrentDirectory = () => loader.context;
|
379 | const formatDiagnosticHost = {
|
380 | getCurrentDirectory: compiler.sys.getCurrentDirectory,
|
381 | getCanonicalFileName: utils_1.useCaseSensitiveFileNames(compiler, instance.loaderOptions)
|
382 | ? s => s
|
383 | : s => s.toLowerCase(),
|
384 | getNewLine: () => compiler.sys.newLine,
|
385 | };
|
386 | const diagnostics = {
|
387 | global: [],
|
388 | perFile: new Map(),
|
389 | transpileErrors: [],
|
390 | };
|
391 | const reportDiagnostic = (d) => {
|
392 | if (transpileOnly) {
|
393 | const filePath = d.file ? filePathKeyMapper(d.file.fileName) : undefined;
|
394 | const last = diagnostics.transpileErrors[diagnostics.transpileErrors.length - 1];
|
395 | if (diagnostics.transpileErrors.length && last[0] === filePath) {
|
396 | last[1].push(d);
|
397 | }
|
398 | else {
|
399 | diagnostics.transpileErrors.push([filePath, [d]]);
|
400 | }
|
401 | }
|
402 | else if (d.file) {
|
403 | const filePath = filePathKeyMapper(d.file.fileName);
|
404 | const existing = diagnostics.perFile.get(filePath);
|
405 | if (existing) {
|
406 | existing.push(d);
|
407 | }
|
408 | else {
|
409 | diagnostics.perFile.set(filePath, [d]);
|
410 | }
|
411 | }
|
412 | else {
|
413 | diagnostics.global.push(d);
|
414 | }
|
415 | instance.log.logInfo(compiler.formatDiagnostic(d, formatDiagnosticHost));
|
416 | };
|
417 | const reportSolutionBuilderStatus = (d) => instance.log.logInfo(compiler.formatDiagnostic(d, formatDiagnosticHost));
|
418 | const reportWatchStatus = (d, newLine, _options) => instance.log.logInfo(`${compiler.flattenDiagnosticMessageText(d.messageText, compiler.sys.newLine)}${newLine + newLine}`);
|
419 | const outputFiles = new Map();
|
420 | const writtenFiles = [];
|
421 | const outputAffectingInstanceVersion = new Map();
|
422 | let timeoutId;
|
423 | const symlinkedDirectories = new Map();
|
424 | const symlinkedFiles = new Map();
|
425 | const cachedSys = {
|
426 | fileExists: fileName => compiler.sys.fileExists(fileName),
|
427 | directoryExists: directory => compiler.sys.directoryExists(directory),
|
428 | realpath: compiler.sys.realpath && (path => compiler.sys.realpath(path)),
|
429 | };
|
430 | addCache(cachedSys);
|
431 | const configFileInfo = new Map();
|
432 | const solutionBuilderHost = Object.assign(Object.assign(Object.assign(Object.assign({}, compiler.createSolutionBuilderWithWatchHost(compiler.sys, compiler.createEmitAndSemanticDiagnosticsBuilderProgram, reportDiagnostic, reportSolutionBuilderStatus, reportWatchStatus)), { useCaseSensitiveFileNames: () => utils_1.useCaseSensitiveFileNames(compiler, instance.loaderOptions), diagnostics }), createWatchFactory(filePathKeyMapper, compiler)), {
|
433 |
|
434 | getCurrentDirectory,
|
435 |
|
436 | readFile: (fileName, encoding) => {
|
437 | const outputFile = ensureOutputFile(fileName);
|
438 | return outputFile !== undefined
|
439 | ? outputFile
|
440 | ? outputFile.text
|
441 | : undefined
|
442 | : readInputFile(fileName, encoding).text;
|
443 | }, writeFile: (name, text, writeByteOrderMark) => {
|
444 | const key = filePathKeyMapper(name);
|
445 | updateFileWithText(instance, key, name, () => text);
|
446 | const existing = outputFiles.get(key);
|
447 | const newOutputFile = {
|
448 | name,
|
449 | text,
|
450 | writeByteOrderMark: !!writeByteOrderMark,
|
451 | time: new Date(),
|
452 | version: existing
|
453 | ? existing.text !== text
|
454 | ? existing.version + 1
|
455 | : existing.version
|
456 | : 0,
|
457 | };
|
458 | outputFiles.set(key, newOutputFile);
|
459 | writtenFiles.push(newOutputFile);
|
460 | if (outputAffectingInstanceVersion.has(key) &&
|
461 | (!existing || existing.text !== text)) {
|
462 | instance.version++;
|
463 | }
|
464 | if (instance.watchHost &&
|
465 | !instance.files.has(key) &&
|
466 | !instance.otherFiles.has(key)) {
|
467 |
|
468 | if (!existing) {
|
469 | instance.hasUnaccountedModifiedFiles =
|
470 | instance.watchHost.invokeFileWatcher(name, compiler.FileWatcherEventKind.Created) || instance.hasUnaccountedModifiedFiles;
|
471 | }
|
472 | else if (existing.version !== newOutputFile.version) {
|
473 | instance.hasUnaccountedModifiedFiles =
|
474 | instance.watchHost.invokeFileWatcher(name, compiler.FileWatcherEventKind.Changed) || instance.hasUnaccountedModifiedFiles;
|
475 | }
|
476 | }
|
477 | compiler.sys.writeFile(name, text, writeByteOrderMark);
|
478 | }, getModifiedTime: fileName => {
|
479 | const outputFile = ensureOutputFile(fileName);
|
480 | if (outputFile !== undefined) {
|
481 | return outputFile ? outputFile.time : undefined;
|
482 | }
|
483 | const key = filePathKeyMapper(fileName);
|
484 | const existing = instance.files.get(key) || instance.otherFiles.get(key);
|
485 | return existing
|
486 | ? existing.modifiedTime
|
487 | : compiler.sys.getModifiedTime(fileName);
|
488 | }, setModifiedTime: (fileName, time) => {
|
489 | const outputFile = ensureOutputFile(fileName);
|
490 | if (outputFile !== undefined) {
|
491 | if (outputFile) {
|
492 | outputFile.time = time;
|
493 | }
|
494 | }
|
495 | compiler.sys.setModifiedTime(fileName, time);
|
496 | const key = filePathKeyMapper(fileName);
|
497 | const existing = instance.files.get(key) || instance.otherFiles.get(key);
|
498 | if (existing) {
|
499 | existing.modifiedTime = time;
|
500 | }
|
501 | }, fileExists: fileName => {
|
502 | const outputFile = ensureOutputFile(fileName);
|
503 | if (outputFile !== undefined) {
|
504 | return !!outputFile;
|
505 | }
|
506 | const key = filePathKeyMapper(fileName);
|
507 | const existing = instance.files.get(key) || instance.otherFiles.get(key);
|
508 | return existing
|
509 | ? existing.text !== undefined
|
510 | : cachedSys.fileExists(fileName);
|
511 | }, directoryExists: directory => {
|
512 | if (cachedSys.directoryExists(directory)) {
|
513 | return true;
|
514 | }
|
515 | const resolvedDirectory = trailingDirectorySeparatorPathKey(directory);
|
516 | for (const outputFile of outputFiles.keys()) {
|
517 | if (normalizeSlashes(outputFile).startsWith(resolvedDirectory)) {
|
518 | return true;
|
519 | }
|
520 | }
|
521 |
|
522 | const ancestor = findExistingAncestor(directory);
|
523 | const ancestorRealpath = getRealpathOfExistingDirectory(ancestor);
|
524 | return ancestorRealpath
|
525 | ? solutionBuilderHost.directoryExists(path.resolve(ancestorRealpath, path.relative(ancestor, directory)))
|
526 | : false;
|
527 | }, getDirectories: directory => cachedSys.directoryExists(directory)
|
528 | ? compiler.sys.getDirectories(directory)
|
529 | : [], readDirectory: (path, extensions, exclude, include, depth) => cachedSys.directoryExists(path)
|
530 | ? compiler.sys.readDirectory(path, extensions, exclude, include, depth)
|
531 | : [], realpath: cachedSys.realpath && (file => getRealpathOfFile(file) || file), afterProgramEmitAndDiagnostics: transpileOnly ? undefined : storeDtsFiles, setTimeout: (callback, _time, ...args) => {
|
532 | timeoutId = [callback, args];
|
533 | return timeoutId;
|
534 | }, clearTimeout: _timeoutId => {
|
535 | timeoutId = undefined;
|
536 | }, writtenFiles,
|
537 | configFileInfo,
|
538 | outputAffectingInstanceVersion,
|
539 | getOutputFileKeyFromReferencedProject,
|
540 | getOutputFileFromReferencedProject,
|
541 | getOutputFileAndKeyFromReferencedProject, getInputFileNameFromOutput: fileName => {
|
542 | const result = getInputFileNameFromOutput(fileName);
|
543 | return typeof result === 'string' ? result : undefined;
|
544 | }, getOutputFilesFromReferencedProjectInput,
|
545 | buildReferences,
|
546 | clearCache });
|
547 | solutionBuilderHost.trace = logData => instance.log.logInfo(logData);
|
548 | solutionBuilderHost.getParsedCommandLine = file => {
|
549 | const config = config_1.getParsedCommandLine(compiler, instance.loaderOptions, file);
|
550 | configFileInfo.set(filePathKeyMapper(file), { config });
|
551 | return config;
|
552 | };
|
553 |
|
554 | const resolveSync = resolver_1.makeResolver(loader._compiler.options);
|
555 | const resolvers = makeResolvers(compiler, compilerOptions, solutionBuilderHost, customResolveTypeReferenceDirective, customResolveModuleName, resolveSync, appendTsTsxSuffixesIfRequired, scriptRegex, instance);
|
556 |
|
557 | solutionBuilderHost.resolveTypeReferenceDirectives =
|
558 | resolvers.resolveTypeReferenceDirectives;
|
559 | solutionBuilderHost.resolveModuleNames = resolvers.resolveModuleNames;
|
560 | return solutionBuilderHost;
|
561 | function trailingDirectorySeparatorPathKey(directory) {
|
562 | return utils_1.ensureTrailingDirectorySeparator(normalizeSlashes(filePathKeyMapper(directory)));
|
563 | }
|
564 | function clearCache() {
|
565 | cachedSys.clearCache();
|
566 | symlinkedDirectories.clear();
|
567 | symlinkedFiles.clear();
|
568 | }
|
569 | function findExistingAncestor(fileOrDirectory) {
|
570 | let ancestor = path.dirname(fileOrDirectory);
|
571 | while (ancestor !== path.dirname(ancestor)) {
|
572 | if (cachedSys.directoryExists(ancestor))
|
573 | return ancestor;
|
574 | ancestor = path.dirname(ancestor);
|
575 | }
|
576 |
|
577 | return ancestor;
|
578 | }
|
579 | function getRealpathOfExistingDirectory(directory) {
|
580 | return getRealpath(directory, symlinkedDirectories, () => cachedSys.realpath(directory));
|
581 | }
|
582 | function getRealpathOfFile(file) {
|
583 | return getRealpath(file, symlinkedFiles, () => {
|
584 | if (cachedSys.fileExists(file))
|
585 | return cachedSys.realpath(file);
|
586 |
|
587 | const ancestor = findExistingAncestor(file);
|
588 | const ancestorRealpath = getRealpathOfExistingDirectory(ancestor);
|
589 | if (!ancestorRealpath)
|
590 | return file;
|
591 | const newFile = path.resolve(ancestorRealpath, path.relative(ancestor, file));
|
592 | return getRealpathOfFile(newFile) || newFile;
|
593 | });
|
594 | }
|
595 | function getRealpath(fileOrDirectory, symlinked, realpath) {
|
596 | if (!cachedSys.realpath)
|
597 | return undefined;
|
598 | const fileOrDirectoryKey = filePathKeyMapper(fileOrDirectory);
|
599 | const existing = symlinked.get(fileOrDirectoryKey);
|
600 | if (existing !== undefined)
|
601 | return existing || undefined;
|
602 | const real = realpath();
|
603 | if (real === fileOrDirectory ||
|
604 | filePathKeyMapper(real) === fileOrDirectoryKey) {
|
605 |
|
606 | symlinked.set(fileOrDirectoryKey, false);
|
607 | return undefined;
|
608 | }
|
609 | symlinked.set(fileOrDirectoryKey, real);
|
610 | return real;
|
611 | }
|
612 | function buildReferences() {
|
613 | if (!timeoutId) {
|
614 | return;
|
615 | }
|
616 | diagnostics.global.length = 0;
|
617 | diagnostics.perFile.clear();
|
618 | diagnostics.transpileErrors.length = 0;
|
619 | while (timeoutId) {
|
620 | const [callback, args] = timeoutId;
|
621 | timeoutId = undefined;
|
622 | callback(...args);
|
623 | }
|
624 | }
|
625 | function storeDtsFiles(builderProgram) {
|
626 | const program = builderProgram.getProgram();
|
627 | for (const configInfo of configFileInfo.values()) {
|
628 | if (!configInfo.config ||
|
629 | program.getRootFileNames() !== configInfo.config.fileNames ||
|
630 | program.getCompilerOptions() !== configInfo.config.options ||
|
631 | program.getProjectReferences() !== configInfo.config.projectReferences) {
|
632 | continue;
|
633 | }
|
634 | configInfo.dtsFiles = program
|
635 | .getSourceFiles()
|
636 | .map(file => path.resolve(file.fileName))
|
637 | .filter(fileName => fileName.match(constants.dtsDtsxOrDtsDtsxMapRegex));
|
638 | return;
|
639 | }
|
640 | }
|
641 | function getInputFileNameFromOutput(outputFileName) {
|
642 | const resolvedFileName = filePathKeyMapper(outputFileName);
|
643 | for (const configInfo of configFileInfo.values()) {
|
644 | ensureInputOutputInfo(configInfo);
|
645 | if (configInfo.outputFileNames) {
|
646 | for (const { inputFileName, outputNames, } of configInfo.outputFileNames.values()) {
|
647 | if (outputNames.indexOf(resolvedFileName) !== -1) {
|
648 | return inputFileName;
|
649 | }
|
650 | }
|
651 | }
|
652 | if (configInfo.tsbuildInfoFile &&
|
653 | filePathKeyMapper(configInfo.tsbuildInfoFile) === resolvedFileName) {
|
654 | return true;
|
655 | }
|
656 | }
|
657 | const symlinkedOutputFileName = getRealpathOfFile(outputFileName);
|
658 | return symlinkedOutputFileName
|
659 | ? getInputFileNameFromOutput(symlinkedOutputFileName)
|
660 | : undefined;
|
661 | }
|
662 | function ensureInputOutputInfo(configInfo) {
|
663 | if (configInfo.outputFileNames || !configInfo.config) {
|
664 | return;
|
665 | }
|
666 | configInfo.outputFileNames = new Map();
|
667 | configInfo.config.fileNames.forEach(inputFile => configInfo.outputFileNames.set(filePathKeyMapper(inputFile), {
|
668 | inputFileName: path.resolve(inputFile),
|
669 | outputNames: instances_1.getOutputFileNames(instance, configInfo.config, inputFile).map(filePathKeyMapper),
|
670 | }));
|
671 | configInfo.tsbuildInfoFile = instance.compiler
|
672 | .getTsBuildInfoEmitOutputFilePath
|
673 | ? instance.compiler.getTsBuildInfoEmitOutputFilePath(configInfo.config.options)
|
674 | :
|
675 | instance.compiler.getOutputPathForBuildInfo(configInfo.config.options);
|
676 | }
|
677 | function getOutputFileAndKeyFromReferencedProject(outputFileName) {
|
678 | const key = getOutputFileKeyFromReferencedProject(outputFileName);
|
679 | return key && { key, outputFile: outputFiles.get(key) };
|
680 | }
|
681 | function getOutputFileFromReferencedProject(outputFileName) {
|
682 | const key = getOutputFileKeyFromReferencedProject(outputFileName);
|
683 | return key && outputFiles.get(key);
|
684 | }
|
685 | function getOutputFileKeyFromReferencedProject(outputFileName) {
|
686 | const key = filePathKeyMapper(outputFileName);
|
687 | const result = outputFiles.has(key);
|
688 | if (result)
|
689 | return key;
|
690 | const symlinkedOutputFileName = getRealpathOfFile(outputFileName);
|
691 | return symlinkedOutputFileName
|
692 | ? getOutputFileKeyFromReferencedProject(symlinkedOutputFileName)
|
693 | : undefined;
|
694 | }
|
695 | function ensureOutputFile(outputFileName, encoding) {
|
696 | const outputFile = getOutputFileFromReferencedProject(outputFileName);
|
697 | if (outputFile !== undefined) {
|
698 | return outputFile;
|
699 | }
|
700 | if (!getInputFileNameFromOutput(outputFileName)) {
|
701 | return undefined;
|
702 | }
|
703 | outputFileName = getRealpathOfFile(outputFileName) || outputFileName;
|
704 | const key = filePathKeyMapper(outputFileName);
|
705 | const text = compiler.sys.readFile(outputFileName, encoding);
|
706 | if (text === undefined) {
|
707 | outputFiles.set(key, false);
|
708 | return false;
|
709 | }
|
710 | const newOutputFile = {
|
711 | name: outputFileName,
|
712 | text,
|
713 | writeByteOrderMark: false,
|
714 | time: compiler.sys.getModifiedTime(outputFileName),
|
715 | version: 0,
|
716 | };
|
717 | outputFiles.set(key, newOutputFile);
|
718 | return newOutputFile;
|
719 | }
|
720 | function getOutputFilesFromReferencedProjectInput(inputFileName) {
|
721 | const resolvedFileName = filePathKeyMapper(inputFileName);
|
722 | for (const configInfo of configFileInfo.values()) {
|
723 | ensureInputOutputInfo(configInfo);
|
724 | if (configInfo.outputFileNames) {
|
725 | const result = configInfo.outputFileNames.get(resolvedFileName);
|
726 | if (result) {
|
727 | return result.outputNames
|
728 | .map(outputFile => outputFiles.get(outputFile))
|
729 | .filter(output => !!output);
|
730 | }
|
731 | }
|
732 | }
|
733 | return [];
|
734 | }
|
735 | function readInputFile(inputFileName, encoding) {
|
736 | const resolvedFileName = filePathKeyMapper(inputFileName);
|
737 | const existing = instance.otherFiles.get(resolvedFileName);
|
738 | if (existing) {
|
739 | return existing;
|
740 | }
|
741 | inputFileName = path.resolve(inputFileName);
|
742 | const tsFile = {
|
743 | fileName: inputFileName,
|
744 | version: 1,
|
745 | text: compiler.sys.readFile(inputFileName, encoding),
|
746 | modifiedTime: compiler.sys.getModifiedTime(inputFileName),
|
747 | };
|
748 | instance.otherFiles.set(resolvedFileName, tsFile);
|
749 | return tsFile;
|
750 | }
|
751 | }
|
752 | exports.makeSolutionBuilderHost = makeSolutionBuilderHost;
|
753 | function getSolutionErrors(instance, context) {
|
754 | const solutionErrors = [];
|
755 | if (instance.solutionBuilderHost &&
|
756 | instance.solutionBuilderHost.diagnostics.transpileErrors.length) {
|
757 | instance.solutionBuilderHost.diagnostics.transpileErrors.forEach(([filePath, errors]) => solutionErrors.push(...utils_1.formatErrors(errors, instance.loaderOptions, instance.colors, instance.compiler, { file: filePath ? undefined : 'tsconfig.json' }, context)));
|
758 | }
|
759 | return solutionErrors;
|
760 | }
|
761 | exports.getSolutionErrors = getSolutionErrors;
|
762 | function makeResolveTypeReferenceDirective(compiler, compilerOptions, moduleResolutionHost, customResolveTypeReferenceDirective) {
|
763 | if (customResolveTypeReferenceDirective === undefined) {
|
764 | return (directive, containingFile, redirectedReference) => compiler.resolveTypeReferenceDirective(directive, containingFile, compilerOptions, moduleResolutionHost, redirectedReference);
|
765 | }
|
766 | return (directive, containingFile) => customResolveTypeReferenceDirective(directive, containingFile, compilerOptions, moduleResolutionHost, compiler.resolveTypeReferenceDirective);
|
767 | }
|
768 | function isJsImplementationOfTypings(resolvedModule, tsResolution) {
|
769 | return (resolvedModule.resolvedFileName.endsWith('js') &&
|
770 | /\.d\.ts$/.test(tsResolution.resolvedFileName));
|
771 | }
|
772 | function resolveModule(resolveSync, resolveModuleName, appendTsTsxSuffixesIfRequired, scriptRegex, moduleName, containingFile) {
|
773 | let resolutionResult;
|
774 | try {
|
775 | const originalFileName = resolveSync(undefined, path.normalize(path.dirname(containingFile)), moduleName);
|
776 | const resolvedFileName = appendTsTsxSuffixesIfRequired(originalFileName);
|
777 | if (resolvedFileName.match(scriptRegex) !== null) {
|
778 | resolutionResult = { resolvedFileName, originalFileName };
|
779 | }
|
780 | }
|
781 | catch (e) { }
|
782 | const tsResolution = resolveModuleName(moduleName, containingFile);
|
783 | if (tsResolution.resolvedModule !== undefined) {
|
784 | const resolvedFileName = path.normalize(tsResolution.resolvedModule.resolvedFileName);
|
785 | const tsResolutionResult = {
|
786 | originalFileName: resolvedFileName,
|
787 | resolvedFileName,
|
788 | isExternalLibraryImport: tsResolution.resolvedModule.isExternalLibraryImport,
|
789 | };
|
790 | return resolutionResult === undefined ||
|
791 | resolutionResult.resolvedFileName ===
|
792 | tsResolutionResult.resolvedFileName ||
|
793 | isJsImplementationOfTypings(resolutionResult, tsResolutionResult)
|
794 | ? tsResolutionResult
|
795 | : resolutionResult;
|
796 | }
|
797 | return resolutionResult;
|
798 | }
|
799 | function makeResolveModuleName(compiler, compilerOptions, moduleResolutionHost, customResolveModuleName) {
|
800 | if (customResolveModuleName === undefined) {
|
801 | return (moduleName, containingFile) => compiler.resolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionHost);
|
802 | }
|
803 | return (moduleName, containingFile) => customResolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionHost, compiler.resolveModuleName);
|
804 | }
|
805 | function addCache(host) {
|
806 | const clearCacheFunctions = [];
|
807 | host.fileExists = createCache(host.fileExists);
|
808 | host.directoryExists = createCache(host.directoryExists);
|
809 | host.realpath = host.realpath && createCache(host.realpath);
|
810 | host.clearCache = () => clearCacheFunctions.forEach(clear => clear());
|
811 | function createCache(originalFunction) {
|
812 | const cache = new Map();
|
813 | clearCacheFunctions.push(() => cache.clear());
|
814 | return function getCached(arg) {
|
815 | let res = cache.get(arg);
|
816 | if (res !== undefined) {
|
817 | return res;
|
818 | }
|
819 | res = originalFunction(arg);
|
820 | cache.set(arg, res);
|
821 | return res;
|
822 | };
|
823 | }
|
824 | }
|
825 |
|
\ | No newline at end of file |