UNPKG

12.6 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.makeAfterCompile = void 0;
4const path = require("path");
5const constants = require("./constants");
6const instances_1 = require("./instances");
7const utils_1 = require("./utils");
8function makeAfterCompile(instance, configFilePath) {
9 let getCompilerOptionDiagnostics = true;
10 let checkAllFilesForErrors = true;
11 return (compilation, callback) => {
12 // Don't add errors for child compilations
13 if (compilation.compiler.isChild()) {
14 callback();
15 return;
16 }
17 if (instance.loaderOptions.transpileOnly) {
18 provideAssetsFromSolutionBuilderHost(instance, compilation);
19 callback();
20 return;
21 }
22 removeCompilationTSLoaderErrors(compilation);
23 provideCompilerOptionDiagnosticErrorsToWebpack(getCompilerOptionDiagnostics, compilation, instance, configFilePath);
24 getCompilerOptionDiagnostics = false;
25 const modules = determineModules(compilation, instance);
26 const filesToCheckForErrors = determineFilesToCheckForErrors(checkAllFilesForErrors, instance);
27 checkAllFilesForErrors = false;
28 const filesWithErrors = new Map();
29 provideErrorsToWebpack(filesToCheckForErrors, filesWithErrors, compilation, modules, instance);
30 provideDeclarationFilesToWebpack(filesToCheckForErrors, instance, compilation);
31 provideTsBuildInfoFilesToWebpack(instance, compilation);
32 provideSolutionErrorsToWebpack(compilation, modules, instance);
33 provideAssetsFromSolutionBuilderHost(instance, compilation);
34 instance.filesWithErrors = filesWithErrors;
35 instance.modifiedFiles = undefined;
36 instance.projectsMissingSourceMaps = new Set();
37 callback();
38 };
39}
40exports.makeAfterCompile = makeAfterCompile;
41/**
42 * handle compiler option errors after the first compile
43 */
44function provideCompilerOptionDiagnosticErrorsToWebpack(getCompilerOptionDiagnostics, compilation, instance, configFilePath) {
45 if (getCompilerOptionDiagnostics) {
46 const { languageService, loaderOptions, compiler, program } = instance;
47 const errors = utils_1.formatErrors(program === undefined
48 ? languageService.getCompilerOptionsDiagnostics()
49 : program.getOptionsDiagnostics(), loaderOptions, instance.colors, compiler, { file: configFilePath || 'tsconfig.json' }, compilation.compiler.context);
50 compilation.errors.push(...errors);
51 }
52}
53/**
54 * build map of all modules based on normalized filename
55 * this is used for quick-lookup when trying to find modules
56 * based on filepath
57 */
58function determineModules(compilation, { filePathKeyMapper }) {
59 const modules = new Map();
60 compilation.modules.forEach(module => {
61 if (module.resource) {
62 const modulePath = filePathKeyMapper(module.resource);
63 const existingModules = modules.get(modulePath);
64 if (existingModules !== undefined) {
65 if (!existingModules.includes(module)) {
66 existingModules.push(module);
67 }
68 }
69 else {
70 modules.set(modulePath, [module]);
71 }
72 }
73 });
74 return modules;
75}
76function determineFilesToCheckForErrors(checkAllFilesForErrors, instance) {
77 const { files, modifiedFiles, filesWithErrors, otherFiles } = instance;
78 // calculate array of files to check
79 const filesToCheckForErrors = new Map();
80 if (checkAllFilesForErrors) {
81 // check all files on initial run
82 for (const [filePath, file] of files) {
83 addFileToCheckForErrors(filePath, file);
84 }
85 for (const [filePath, file] of otherFiles) {
86 addFileToCheckForErrors(filePath, file);
87 }
88 }
89 else if (modifiedFiles !== null &&
90 modifiedFiles !== undefined &&
91 modifiedFiles.size) {
92 const reverseDependencyGraph = utils_1.populateReverseDependencyGraph(instance);
93 // check all modified files, and all dependants
94 for (const modifiedFileName of modifiedFiles.keys()) {
95 for (const fileName of utils_1.collectAllDependants(reverseDependencyGraph, modifiedFileName).keys()) {
96 const fileToCheckForErrors = files.get(fileName) || otherFiles.get(fileName);
97 addFileToCheckForErrors(fileName, fileToCheckForErrors);
98 }
99 }
100 }
101 // re-check files with errors from previous build
102 if (filesWithErrors !== undefined) {
103 for (const [fileWithErrorName, fileWithErrors] of filesWithErrors) {
104 addFileToCheckForErrors(fileWithErrorName, fileWithErrors);
105 }
106 }
107 return filesToCheckForErrors;
108 function addFileToCheckForErrors(filePath, file) {
109 if (!utils_1.isReferencedFile(instance, filePath)) {
110 filesToCheckForErrors.set(filePath, file);
111 }
112 }
113}
114function provideErrorsToWebpack(filesToCheckForErrors, filesWithErrors, compilation, modules, instance) {
115 const { compiler, files, loaderOptions, compilerOptions, otherFiles, } = instance;
116 const filePathRegex = compilerOptions.allowJs === true
117 ? constants.dtsTsTsxJsJsxRegex
118 : constants.dtsTsTsxRegex;
119 // I’m pretty sure this will never be undefined here
120 const program = utils_1.ensureProgram(instance);
121 for (const [filePath, { fileName }] of filesToCheckForErrors.entries()) {
122 if (fileName.match(filePathRegex) === null) {
123 continue;
124 }
125 const sourceFile = program && program.getSourceFile(fileName);
126 const errors = [];
127 if (program && sourceFile) {
128 errors.push(...program.getSyntacticDiagnostics(sourceFile), ...program
129 .getSemanticDiagnostics(sourceFile)
130 // Output file has not been built from source file - this message is redundant with
131 // program.getOptionsDiagnostics() separately added in instances.ts
132 .filter(({ code }) => code !== 6305));
133 }
134 if (errors.length > 0) {
135 const fileWithError = files.get(filePath) || otherFiles.get(filePath);
136 filesWithErrors.set(filePath, fileWithError);
137 }
138 // if we have access to a webpack module, use that
139 const associatedModules = modules.get(instance.filePathKeyMapper(fileName));
140 if (associatedModules !== undefined) {
141 associatedModules.forEach(module => {
142 removeModuleTSLoaderError(module);
143 // append errors
144 const formattedErrors = utils_1.formatErrors(errors, loaderOptions, instance.colors, compiler, { module }, compilation.compiler.context);
145 formattedErrors.forEach(error => {
146 if (module.addError) {
147 module.addError(error);
148 }
149 else {
150 module.errors.push(error);
151 }
152 });
153 compilation.errors.push(...formattedErrors);
154 });
155 }
156 else {
157 // otherwise it's a more generic error
158 const formattedErrors = utils_1.formatErrors(errors, loaderOptions, instance.colors, compiler, { file: fileName }, compilation.compiler.context);
159 compilation.errors.push(...formattedErrors);
160 }
161 }
162}
163function provideSolutionErrorsToWebpack(compilation, modules, instance) {
164 if (!instance.solutionBuilderHost ||
165 !(instance.solutionBuilderHost.diagnostics.global.length ||
166 instance.solutionBuilderHost.diagnostics.perFile.size)) {
167 return;
168 }
169 const { compiler, loaderOptions, solutionBuilderHost: { diagnostics }, } = instance;
170 for (const [filePath, perFileDiagnostics] of diagnostics.perFile) {
171 // if we have access to a webpack module, use that
172 const associatedModules = modules.get(filePath);
173 if (associatedModules !== undefined) {
174 associatedModules.forEach(module => {
175 removeModuleTSLoaderError(module);
176 // append errors
177 const formattedErrors = utils_1.formatErrors(perFileDiagnostics, loaderOptions, instance.colors, compiler, { module }, compilation.compiler.context);
178 formattedErrors.forEach(error => {
179 if (module.addError) {
180 module.addError(error);
181 }
182 else {
183 module.errors.push(error);
184 }
185 });
186 compilation.errors.push(...formattedErrors);
187 });
188 }
189 else {
190 // otherwise it's a more generic error
191 const formattedErrors = utils_1.formatErrors(perFileDiagnostics, loaderOptions, instance.colors, compiler, { file: path.resolve(perFileDiagnostics[0].file.fileName) }, compilation.compiler.context);
192 compilation.errors.push(...formattedErrors);
193 }
194 }
195 // Add global solution errors
196 compilation.errors.push(...utils_1.formatErrors(diagnostics.global, instance.loaderOptions, instance.colors, instance.compiler, { file: 'tsconfig.json' }, compilation.compiler.context));
197}
198/**
199 * gather all declaration files from TypeScript and output them to webpack
200 */
201function provideDeclarationFilesToWebpack(filesToCheckForErrors, instance, compilation) {
202 for (const { fileName } of filesToCheckForErrors.values()) {
203 if (fileName.match(constants.tsTsxRegex) === null) {
204 continue;
205 }
206 addDeclarationFilesAsAsset(instances_1.getEmitOutput(instance, fileName), compilation);
207 }
208}
209function addDeclarationFilesAsAsset(outputFiles, compilation, skipOutputFile) {
210 outputFilesToAsset(outputFiles, compilation, outputFile => skipOutputFile && skipOutputFile(outputFile)
211 ? true
212 : !outputFile.name.match(constants.dtsDtsxOrDtsDtsxMapRegex));
213}
214function outputFileToAsset(outputFile, compilation) {
215 const assetPath = path.relative(compilation.compiler.outputPath, outputFile.name);
216 compilation.assets[assetPath] = {
217 source: () => outputFile.text,
218 size: () => outputFile.text.length,
219 };
220}
221function outputFilesToAsset(outputFiles, compilation, skipOutputFile) {
222 for (const outputFile of outputFiles) {
223 if (!skipOutputFile || !skipOutputFile(outputFile)) {
224 outputFileToAsset(outputFile, compilation);
225 }
226 }
227}
228/**
229 * gather all .tsbuildinfo for the project
230 */
231function provideTsBuildInfoFilesToWebpack(instance, compilation) {
232 if (instance.watchHost) {
233 // Ensure emit is complete
234 instances_1.getEmitFromWatchHost(instance);
235 if (instance.watchHost.tsbuildinfo) {
236 outputFileToAsset(instance.watchHost.tsbuildinfo, compilation);
237 }
238 instance.watchHost.outputFiles.clear();
239 instance.watchHost.tsbuildinfo = undefined;
240 }
241}
242/**
243 * gather all solution builder assets
244 */
245function provideAssetsFromSolutionBuilderHost(instance, compilation) {
246 if (instance.solutionBuilderHost) {
247 // written files
248 outputFilesToAsset(instance.solutionBuilderHost.writtenFiles, compilation);
249 instance.solutionBuilderHost.writtenFiles.length = 0;
250 }
251}
252/**
253 * handle all other errors. The basic approach here to get accurate error
254 * reporting is to start with a "blank slate" each compilation and gather
255 * all errors from all files. Since webpack tracks errors in a module from
256 * compilation-to-compilation, and since not every module always runs through
257 * the loader, we need to detect and remove any pre-existing errors.
258 */
259function removeCompilationTSLoaderErrors(compilation) {
260 compilation.errors = compilation.errors.filter(error => error.loaderSource !== 'ts-loader');
261}
262function removeModuleTSLoaderError(module) {
263 /**
264 * Since webpack 5, the `errors` property is deprecated,
265 * so we can check if some methods for reporting errors exist.
266 */
267 if (!!module.addError) {
268 const warnings = module.getWarnings();
269 const errors = module.getErrors();
270 module.clearWarningsAndErrors();
271 Array.from(warnings || []).forEach(warning => module.addWarning(warning));
272 Array.from(errors || [])
273 .filter((error) => error.loaderSource !== 'ts-loader')
274 .forEach(error => module.addError(error));
275 }
276 else {
277 module.errors = module.errors.filter(error => error.loaderSource !== 'ts-loader');
278 }
279}
280//# sourceMappingURL=after-compile.js.map
\No newline at end of file