1 | "use strict";
|
2 | var __assign = (this && this.__assign) || function () {
|
3 | __assign = Object.assign || function(t) {
|
4 | for (var s, i = 1, n = arguments.length; i < n; i++) {
|
5 | s = arguments[i];
|
6 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
7 | t[p] = s[p];
|
8 | }
|
9 | return t;
|
10 | };
|
11 | return __assign.apply(this, arguments);
|
12 | };
|
13 | var __importStar = (this && this.__importStar) || function (mod) {
|
14 | if (mod && mod.__esModule) return mod;
|
15 | var result = {};
|
16 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
17 | result["default"] = mod;
|
18 | return result;
|
19 | };
|
20 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
21 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
22 | };
|
23 | var path = __importStar(require("path"));
|
24 | var childProcess = __importStar(require("child_process"));
|
25 | var semver = __importStar(require("semver"));
|
26 | var micromatch_1 = __importDefault(require("micromatch"));
|
27 | var chalk_1 = __importDefault(require("chalk"));
|
28 | var worker_rpc_1 = require("worker-rpc");
|
29 | var CancellationToken_1 = require("./CancellationToken");
|
30 | var formatter_1 = require("./formatter");
|
31 | var FsHelper_1 = require("./FsHelper");
|
32 | var hooks_1 = require("./hooks");
|
33 | var RpcTypes_1 = require("./RpcTypes");
|
34 | var issue_1 = require("./issue");
|
35 | var checkerPluginName = 'fork-ts-checker-webpack-plugin';
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 | var ForkTsCheckerWebpackPlugin = (function () {
|
44 | function ForkTsCheckerWebpackPlugin(options) {
|
45 | this.eslint = false;
|
46 | this.eslintOptions = {};
|
47 | this.tsconfigPath = undefined;
|
48 |
|
49 | this.compiler = undefined;
|
50 | this.started = undefined;
|
51 | this.elapsed = undefined;
|
52 | this.cancellationToken = undefined;
|
53 | this.isWatching = false;
|
54 | this.checkDone = false;
|
55 | this.compilationDone = false;
|
56 | this.diagnostics = [];
|
57 | this.lints = [];
|
58 | this.eslintVersion = undefined;
|
59 | this.startAt = 0;
|
60 | this.nodeArgs = [];
|
61 | options = options || {};
|
62 | this.options = __assign({}, options);
|
63 | this.ignoreDiagnostics = options.ignoreDiagnostics || [];
|
64 | this.ignoreLints = options.ignoreLints || [];
|
65 | this.ignoreLintWarnings = options.ignoreLintWarnings === true;
|
66 | this.reportFiles = options.reportFiles || [];
|
67 | this.logger = options.logger || console;
|
68 | this.silent = options.silent === true;
|
69 | this.async = options.async !== false;
|
70 | this.checkSyntacticErrors = options.checkSyntacticErrors === true;
|
71 | this.resolveModuleNameModule = options.resolveModuleNameModule;
|
72 | this.resolveTypeReferenceDirectiveModule =
|
73 | options.resolveTypeReferenceDirectiveModule;
|
74 | this.memoryLimit =
|
75 | options.memoryLimit || ForkTsCheckerWebpackPlugin.DEFAULT_MEMORY_LIMIT;
|
76 | this.formatter = formatter_1.createFormatter(options.formatter, options.formatterOptions);
|
77 | this.rawFormatter = formatter_1.createRawFormatter();
|
78 | this.emitCallback = this.createNoopEmitCallback();
|
79 | this.doneCallback = this.createDoneCallback();
|
80 | var _a = this.validateTypeScript(options), typescript = _a.typescript, typescriptPath = _a.typescriptPath, typescriptVersion = _a.typescriptVersion, tsconfig = _a.tsconfig, compilerOptions = _a.compilerOptions;
|
81 | this.typescript = typescript;
|
82 | this.typescriptPath = typescriptPath;
|
83 | this.typescriptVersion = typescriptVersion;
|
84 | this.tsconfig = tsconfig;
|
85 | this.compilerOptions = compilerOptions;
|
86 | if (options.eslint === true) {
|
87 | var _b = this.validateEslint(options), eslintVersion = _b.eslintVersion, eslintOptions = _b.eslintOptions;
|
88 | this.eslint = true;
|
89 | this.eslintVersion = eslintVersion;
|
90 | this.eslintOptions = eslintOptions;
|
91 | }
|
92 | this.vue = ForkTsCheckerWebpackPlugin.prepareVueOptions(options.vue);
|
93 | this.useTypescriptIncrementalApi =
|
94 | options.useTypescriptIncrementalApi === undefined
|
95 | ? semver.gte(this.typescriptVersion, '3.0.0') && !this.vue.enabled
|
96 | : options.useTypescriptIncrementalApi;
|
97 | this.measureTime = options.measureCompilationTime === true;
|
98 | if (this.measureTime) {
|
99 | if (semver.lt(process.version, '8.5.0')) {
|
100 | throw new Error("To use 'measureCompilationTime' option, please update to Node.js >= v8.5.0 " +
|
101 | ("(current version is " + process.version + ")"));
|
102 | }
|
103 |
|
104 |
|
105 | this.performance = require('perf_hooks').performance;
|
106 | }
|
107 | }
|
108 |
|
109 | ForkTsCheckerWebpackPlugin.getCompilerHooks = function (compiler) {
|
110 | return hooks_1.getForkTsCheckerWebpackPluginHooks(compiler);
|
111 | };
|
112 | ForkTsCheckerWebpackPlugin.prototype.validateTypeScript = function (options) {
|
113 | var typescriptPath = options.typescript || require.resolve('typescript');
|
114 | var tsconfig = options.tsconfig || './tsconfig.json';
|
115 | var compilerOptions = typeof options.compilerOptions === 'object'
|
116 | ? options.compilerOptions
|
117 | : {};
|
118 | var typescript, typescriptVersion;
|
119 | try {
|
120 | typescript = require(typescriptPath);
|
121 | typescriptVersion = typescript.version;
|
122 | }
|
123 | catch (_ignored) {
|
124 | throw new Error('When you use this plugin you must install `typescript`.');
|
125 | }
|
126 | if (semver.lt(typescriptVersion, '2.1.0')) {
|
127 | throw new Error("Cannot use current typescript version of " + typescriptVersion + ", the minimum required version is 2.1.0");
|
128 | }
|
129 | return {
|
130 | typescriptPath: typescriptPath,
|
131 | typescript: typescript,
|
132 | typescriptVersion: typescriptVersion,
|
133 | tsconfig: tsconfig,
|
134 | compilerOptions: compilerOptions
|
135 | };
|
136 | };
|
137 | ForkTsCheckerWebpackPlugin.prototype.validateEslint = function (options) {
|
138 | var eslintVersion;
|
139 | var eslintOptions = typeof options.eslintOptions === 'object' ? options.eslintOptions : {};
|
140 | if (semver.lt(process.version, '8.10.0')) {
|
141 | throw new Error("To use 'eslint' option, please update to Node.js >= v8.10.0 " +
|
142 | ("(current version is " + process.version + ")"));
|
143 | }
|
144 | try {
|
145 | eslintVersion = require('eslint').Linter.version;
|
146 | }
|
147 | catch (error) {
|
148 | throw new Error("When you use 'eslint' option, make sure to install 'eslint'.");
|
149 | }
|
150 | return { eslintVersion: eslintVersion, eslintOptions: eslintOptions };
|
151 | };
|
152 | ForkTsCheckerWebpackPlugin.prepareVueOptions = function (vueOptions) {
|
153 | var defaultVueOptions = {
|
154 | compiler: 'vue-template-compiler',
|
155 | enabled: false
|
156 | };
|
157 | if (typeof vueOptions === 'boolean') {
|
158 | return Object.assign(defaultVueOptions, { enabled: vueOptions });
|
159 | }
|
160 | else if (typeof vueOptions === 'object' && vueOptions !== null) {
|
161 | return Object.assign(defaultVueOptions, vueOptions);
|
162 | }
|
163 | else {
|
164 | return defaultVueOptions;
|
165 | }
|
166 | };
|
167 |
|
168 | ForkTsCheckerWebpackPlugin.prototype.apply = function (compiler) {
|
169 | this.compiler = compiler;
|
170 | this.tsconfigPath = this.computeContextPath(this.tsconfig);
|
171 |
|
172 | var tsconfigOk = FsHelper_1.fileExistsSync(this.tsconfigPath);
|
173 |
|
174 | if (this.logger) {
|
175 | if (!this.logger.error || !this.logger.warn || !this.logger.info) {
|
176 | throw new Error("Invalid logger object - doesn't provide `error`, `warn` or `info` method.");
|
177 | }
|
178 | }
|
179 | if (!tsconfigOk) {
|
180 | throw new Error('Cannot find "' +
|
181 | this.tsconfigPath +
|
182 | '" file. Please check webpack and ForkTsCheckerWebpackPlugin configuration. \n' +
|
183 | 'Possible errors: \n' +
|
184 | ' - wrong `context` directory in webpack configuration' +
|
185 | ' (if `tsconfig` is not set or is a relative path in fork plugin configuration)\n' +
|
186 | ' - wrong `tsconfig` path in fork plugin configuration' +
|
187 | ' (should be a relative or absolute path)');
|
188 | }
|
189 | this.pluginStart();
|
190 | this.pluginStop();
|
191 | this.pluginCompile();
|
192 | this.pluginEmit();
|
193 | this.pluginDone();
|
194 | };
|
195 | ForkTsCheckerWebpackPlugin.prototype.computeContextPath = function (filePath) {
|
196 | return path.isAbsolute(filePath)
|
197 | ? filePath
|
198 | : path.resolve(this.compiler.options.context, filePath);
|
199 | };
|
200 | ForkTsCheckerWebpackPlugin.prototype.pluginStart = function () {
|
201 | var _this = this;
|
202 | var run = function (compilation, callback) {
|
203 | _this.isWatching = false;
|
204 | callback();
|
205 | };
|
206 | var watchRun = function (compiler, callback) {
|
207 | _this.isWatching = true;
|
208 | callback();
|
209 | };
|
210 | this.compiler.hooks.run.tapAsync(checkerPluginName, run);
|
211 | this.compiler.hooks.watchRun.tapAsync(checkerPluginName, watchRun);
|
212 | };
|
213 | ForkTsCheckerWebpackPlugin.prototype.pluginStop = function () {
|
214 | var _this = this;
|
215 | var watchClose = function () {
|
216 | _this.killService();
|
217 | };
|
218 | var done = function () {
|
219 | if (!_this.isWatching) {
|
220 | _this.killService();
|
221 | }
|
222 | };
|
223 | this.compiler.hooks.watchClose.tap(checkerPluginName, watchClose);
|
224 | this.compiler.hooks.done.tap(checkerPluginName, done);
|
225 | process.on('exit', function () {
|
226 | _this.killService();
|
227 | });
|
228 | };
|
229 | ForkTsCheckerWebpackPlugin.prototype.pluginCompile = function () {
|
230 | var _this = this;
|
231 | var forkTsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(this.compiler);
|
232 | this.compiler.hooks.compile.tap(checkerPluginName, function () {
|
233 | _this.compilationDone = false;
|
234 | forkTsCheckerHooks.serviceBeforeStart.callAsync(function () {
|
235 | if (_this.cancellationToken) {
|
236 |
|
237 | _this.cancellationToken.requestCancellation();
|
238 | forkTsCheckerHooks.cancel.call(_this.cancellationToken);
|
239 | }
|
240 | _this.checkDone = false;
|
241 | _this.started = process.hrtime();
|
242 |
|
243 | _this.cancellationToken = new CancellationToken_1.CancellationToken(_this.typescript);
|
244 | if (!_this.service || !_this.service.connected) {
|
245 | _this.spawnService();
|
246 | }
|
247 | try {
|
248 | if (_this.measureTime) {
|
249 | _this.startAt = _this.performance.now();
|
250 | }
|
251 |
|
252 | _this.serviceRpc.rpc(RpcTypes_1.RUN, _this.cancellationToken.toJSON()).then(function (result) {
|
253 | if (result) {
|
254 | _this.handleServiceMessage(result);
|
255 | }
|
256 | });
|
257 | }
|
258 | catch (error) {
|
259 | if (!_this.silent && _this.logger) {
|
260 | _this.logger.error(chalk_1.default.red('Cannot start checker service: ' +
|
261 | (error ? error.toString() : 'Unknown error')));
|
262 | }
|
263 | forkTsCheckerHooks.serviceStartError.call(error);
|
264 | }
|
265 | });
|
266 | });
|
267 | };
|
268 | ForkTsCheckerWebpackPlugin.prototype.pluginEmit = function () {
|
269 | var _this = this;
|
270 |
|
271 | var emit = function (compilation, callback) {
|
272 | if (_this.isWatching && _this.async) {
|
273 | callback();
|
274 | return;
|
275 | }
|
276 | _this.emitCallback = _this.createEmitCallback(compilation, callback);
|
277 | if (_this.checkDone) {
|
278 | _this.emitCallback();
|
279 | }
|
280 | _this.compilationDone = true;
|
281 | };
|
282 | this.compiler.hooks.emit.tapAsync(checkerPluginName, emit);
|
283 | };
|
284 | ForkTsCheckerWebpackPlugin.prototype.pluginDone = function () {
|
285 | var _this = this;
|
286 | var forkTsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(this.compiler);
|
287 | this.compiler.hooks.done.tap(checkerPluginName, function () {
|
288 | if (!_this.isWatching || !_this.async) {
|
289 | return;
|
290 | }
|
291 | if (_this.checkDone) {
|
292 | _this.doneCallback();
|
293 | }
|
294 | else {
|
295 | if (_this.compiler) {
|
296 | forkTsCheckerHooks.waiting.call();
|
297 | }
|
298 | if (!_this.silent && _this.logger) {
|
299 | _this.logger.info('Type checking in progress...');
|
300 | }
|
301 | }
|
302 | _this.compilationDone = true;
|
303 | });
|
304 | };
|
305 | ForkTsCheckerWebpackPlugin.prototype.spawnService = function () {
|
306 | var _this = this;
|
307 | var env = __assign({}, process.env, { TYPESCRIPT_PATH: this.typescriptPath, TSCONFIG: this.tsconfigPath, COMPILER_OPTIONS: JSON.stringify(this.compilerOptions), CONTEXT: this.compiler.options.context, ESLINT: String(this.eslint), ESLINT_OPTIONS: JSON.stringify(this.eslintOptions), MEMORY_LIMIT: String(this.memoryLimit), CHECK_SYNTACTIC_ERRORS: String(this.checkSyntacticErrors), USE_INCREMENTAL_API: String(this.useTypescriptIncrementalApi === true), VUE: JSON.stringify(this.vue) });
|
308 | if (typeof this.resolveModuleNameModule !== 'undefined') {
|
309 | env.RESOLVE_MODULE_NAME = this.resolveModuleNameModule;
|
310 | }
|
311 | else {
|
312 | delete env.RESOLVE_MODULE_NAME;
|
313 | }
|
314 | if (typeof this.resolveTypeReferenceDirectiveModule !== 'undefined') {
|
315 | env.RESOLVE_TYPE_REFERENCE_DIRECTIVE = this.resolveTypeReferenceDirectiveModule;
|
316 | }
|
317 | else {
|
318 | delete env.RESOLVE_TYPE_REFERENCE_DIRECTIVE;
|
319 | }
|
320 | this.service = childProcess.fork(path.resolve(__dirname, './service.js'), [], {
|
321 | env: env,
|
322 | execArgv: ['--max-old-space-size=' + this.memoryLimit].concat(this.nodeArgs),
|
323 | stdio: ['inherit', 'inherit', 'inherit', 'ipc']
|
324 | });
|
325 |
|
326 | this.serviceRpc = new worker_rpc_1.RpcProvider(function (message) { return _this.service.send(message); });
|
327 | this.service.on('message', function (message) {
|
328 | if (_this.serviceRpc) {
|
329 |
|
330 | _this.serviceRpc.dispatch(message);
|
331 | }
|
332 | });
|
333 | var forkTsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(this.compiler);
|
334 | forkTsCheckerHooks.serviceStart.call(this.tsconfigPath, this.memoryLimit);
|
335 | if (!this.silent && this.logger) {
|
336 | this.logger.info('Starting type checking service...');
|
337 | }
|
338 | this.service.on('exit', function (code, signal) {
|
339 | return _this.handleServiceExit(code, signal);
|
340 | });
|
341 | };
|
342 | ForkTsCheckerWebpackPlugin.prototype.killService = function () {
|
343 | if (!this.service) {
|
344 | return;
|
345 | }
|
346 | try {
|
347 | if (this.cancellationToken) {
|
348 | this.cancellationToken.cleanupCancellation();
|
349 | }
|
350 |
|
351 | this.service.removeAllListeners();
|
352 | this.service.kill();
|
353 | this.service = undefined;
|
354 | this.serviceRpc = undefined;
|
355 | }
|
356 | catch (e) {
|
357 | if (this.logger && !this.silent) {
|
358 | this.logger.error(e);
|
359 | }
|
360 | }
|
361 | };
|
362 | ForkTsCheckerWebpackPlugin.prototype.handleServiceMessage = function (message) {
|
363 | var _this = this;
|
364 | if (this.measureTime) {
|
365 | var delta = this.performance.now() - this.startAt;
|
366 | var deltaRounded = Math.round(delta * 100) / 100;
|
367 | this.logger.info("Compilation took: " + deltaRounded + " ms.");
|
368 | }
|
369 | if (this.cancellationToken) {
|
370 | this.cancellationToken.cleanupCancellation();
|
371 |
|
372 | this.cancellationToken = undefined;
|
373 | }
|
374 | this.checkDone = true;
|
375 | this.elapsed = process.hrtime(this.started);
|
376 | this.diagnostics = message.diagnostics;
|
377 | this.lints = message.lints;
|
378 | if (this.ignoreDiagnostics.length) {
|
379 | this.diagnostics = this.diagnostics.filter(function (diagnostic) {
|
380 | return !_this.ignoreDiagnostics.includes(parseInt(diagnostic.code, 10));
|
381 | });
|
382 | }
|
383 | if (this.ignoreLints.length) {
|
384 | this.lints = this.lints.filter(function (lint) { return !_this.ignoreLints.includes(lint.code); });
|
385 | }
|
386 | if (this.reportFiles.length) {
|
387 | var reportFilesPredicate = function (issue) {
|
388 | if (issue.file) {
|
389 | var relativeFileName = path.relative(_this.compiler.options.context, issue.file);
|
390 | var matchResult = micromatch_1.default([relativeFileName], _this.reportFiles);
|
391 | if (matchResult.length === 0) {
|
392 | return false;
|
393 | }
|
394 | }
|
395 | return true;
|
396 | };
|
397 | this.diagnostics = this.diagnostics.filter(reportFilesPredicate);
|
398 | this.lints = this.lints.filter(reportFilesPredicate);
|
399 | }
|
400 | var forkTsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(this.compiler);
|
401 | forkTsCheckerHooks.receive.call(this.diagnostics, this.lints);
|
402 | if (this.compilationDone) {
|
403 | this.isWatching && this.async ? this.doneCallback() : this.emitCallback();
|
404 | }
|
405 | };
|
406 | ForkTsCheckerWebpackPlugin.prototype.handleServiceExit = function (_code, signal) {
|
407 | if (signal !== 'SIGABRT') {
|
408 | return;
|
409 | }
|
410 |
|
411 | if (this.compiler) {
|
412 | var forkTsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(this.compiler);
|
413 | forkTsCheckerHooks.serviceOutOfMemory.call();
|
414 | }
|
415 | if (!this.silent && this.logger) {
|
416 | this.logger.error(chalk_1.default.red('Type checking and linting aborted - probably out of memory. ' +
|
417 | 'Check `memoryLimit` option in ForkTsCheckerWebpackPlugin configuration.'));
|
418 | }
|
419 | };
|
420 | ForkTsCheckerWebpackPlugin.prototype.createEmitCallback = function (compilation, callback) {
|
421 | return function emitCallback() {
|
422 | var _this = this;
|
423 | if (!this.elapsed) {
|
424 | throw new Error('Execution order error');
|
425 | }
|
426 | var elapsed = Math.round(this.elapsed[0] * 1e9 + this.elapsed[1]);
|
427 | var forkTsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(this.compiler);
|
428 | forkTsCheckerHooks.emit.call(this.diagnostics, this.lints, elapsed);
|
429 | this.diagnostics.concat(this.lints).forEach(function (issue) {
|
430 |
|
431 | var formatted = {
|
432 | rawMessage: _this.rawFormatter(issue),
|
433 | message: _this.formatter(issue),
|
434 | location: {
|
435 | line: issue.line,
|
436 | character: issue.character
|
437 | },
|
438 | file: issue.file
|
439 | };
|
440 | if (issue.severity === issue_1.IssueSeverity.WARNING) {
|
441 | if (!_this.ignoreLintWarnings) {
|
442 | compilation.warnings.push(formatted);
|
443 | }
|
444 | }
|
445 | else {
|
446 | compilation.errors.push(formatted);
|
447 | }
|
448 | });
|
449 | callback();
|
450 | };
|
451 | };
|
452 | ForkTsCheckerWebpackPlugin.prototype.createNoopEmitCallback = function () {
|
453 |
|
454 |
|
455 | return function noopEmitCallback() { };
|
456 | };
|
457 | ForkTsCheckerWebpackPlugin.prototype.printLoggerMessage = function (issue, formattedIssue) {
|
458 | if (issue.severity === issue_1.IssueSeverity.WARNING) {
|
459 | if (this.ignoreLintWarnings) {
|
460 | return;
|
461 | }
|
462 | this.logger.warn(formattedIssue);
|
463 | }
|
464 | else {
|
465 | this.logger.error(formattedIssue);
|
466 | }
|
467 | };
|
468 | ForkTsCheckerWebpackPlugin.prototype.createDoneCallback = function () {
|
469 | return function doneCallback() {
|
470 | var _this = this;
|
471 | if (!this.elapsed) {
|
472 | throw new Error('Execution order error');
|
473 | }
|
474 | var elapsed = Math.round(this.elapsed[0] * 1e9 + this.elapsed[1]);
|
475 | if (this.compiler) {
|
476 | var forkTsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(this.compiler);
|
477 | forkTsCheckerHooks.done.call(this.diagnostics, this.lints, elapsed);
|
478 | }
|
479 | if (!this.silent && this.logger) {
|
480 | if (this.diagnostics.length || this.lints.length) {
|
481 | (this.lints || []).concat(this.diagnostics).forEach(function (diagnostic) {
|
482 | var formattedDiagnostic = _this.formatter(diagnostic);
|
483 | _this.printLoggerMessage(diagnostic, formattedDiagnostic);
|
484 | });
|
485 | }
|
486 | if (!this.diagnostics.length) {
|
487 | this.logger.info(chalk_1.default.green('No type errors found'));
|
488 | }
|
489 | this.logger.info('Version: typescript ' +
|
490 | chalk_1.default.bold(this.typescriptVersion) +
|
491 | (this.eslint
|
492 | ? ', eslint ' + chalk_1.default.bold(this.eslintVersion)
|
493 | : ''));
|
494 | this.logger.info('Time: ' + chalk_1.default.bold(Math.round(elapsed / 1e6).toString()) + 'ms');
|
495 | }
|
496 | };
|
497 | };
|
498 | ForkTsCheckerWebpackPlugin.DEFAULT_MEMORY_LIMIT = 2048;
|
499 | return ForkTsCheckerWebpackPlugin;
|
500 | }());
|
501 | module.exports = ForkTsCheckerWebpackPlugin;
|
502 |
|
\ | No newline at end of file |