Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

220 wiersze
10 KiB

  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. Object.defineProperty(exports, "__esModule", { value: true });
  14. var fs = require("fs");
  15. var endsWith = require("lodash/endsWith");
  16. var path = require("path");
  17. var FilesRegister_1 = require("./FilesRegister");
  18. var FilesWatcher_1 = require("./FilesWatcher");
  19. var WorkSet_1 = require("./WorkSet");
  20. var NormalizedMessage_1 = require("./NormalizedMessage");
  21. var minimatch = require("minimatch");
  22. var VueProgram_1 = require("./VueProgram");
  23. var IncrementalChecker = /** @class */ (function () {
  24. function IncrementalChecker(typescriptPath, programConfigFile, compilerOptions, linterConfigFile, watchPaths, workNumber, workDivision, checkSyntacticErrors, vue) {
  25. this.typescript = require(typescriptPath);
  26. this.programConfigFile = programConfigFile;
  27. this.compilerOptions = compilerOptions;
  28. this.linterConfigFile = linterConfigFile;
  29. this.watchPaths = watchPaths;
  30. this.workNumber = workNumber || 0;
  31. this.workDivision = workDivision || 1;
  32. this.checkSyntacticErrors = checkSyntacticErrors || false;
  33. this.vue = vue || false;
  34. // Use empty array of exclusions in general to avoid having
  35. // to check of its existence later on.
  36. this.linterExclusions = [];
  37. // it's shared between compilations
  38. this.files = new FilesRegister_1.FilesRegister(function () { return ({
  39. // data shape
  40. source: undefined,
  41. linted: false,
  42. lints: []
  43. }); });
  44. }
  45. IncrementalChecker.loadProgramConfig = function (typescript, configFile, compilerOptions) {
  46. var tsconfig = typescript.readConfigFile(configFile, typescript.sys.readFile).config;
  47. tsconfig.compilerOptions = tsconfig.compilerOptions || {};
  48. tsconfig.compilerOptions = __assign({}, tsconfig.compilerOptions, compilerOptions);
  49. var parsed = typescript.parseJsonConfigFileContent(tsconfig, typescript.sys, path.dirname(configFile));
  50. return parsed;
  51. };
  52. IncrementalChecker.loadLinterConfig = function (configFile) {
  53. // tslint:disable-next-line:no-implicit-dependencies
  54. var tslint = require('tslint');
  55. return tslint.Configuration.loadConfigurationFromPath(configFile);
  56. };
  57. IncrementalChecker.createProgram = function (typescript, programConfig, files, watcher, oldProgram) {
  58. var host = typescript.createCompilerHost(programConfig.options);
  59. var realGetSourceFile = host.getSourceFile;
  60. host.getSourceFile = function (filePath, languageVersion, onError) {
  61. // first check if watcher is watching file - if not - check it's mtime
  62. if (!watcher.isWatchingFile(filePath)) {
  63. try {
  64. var stats = fs.statSync(filePath);
  65. files.setMtime(filePath, stats.mtime.valueOf());
  66. }
  67. catch (e) {
  68. // probably file does not exists
  69. files.remove(filePath);
  70. }
  71. }
  72. // get source file only if there is no source in files register
  73. if (!files.has(filePath) || !files.getData(filePath).source) {
  74. files.mutateData(filePath, function (data) {
  75. data.source = realGetSourceFile(filePath, languageVersion, onError);
  76. });
  77. }
  78. return files.getData(filePath).source;
  79. };
  80. return typescript.createProgram(programConfig.fileNames, programConfig.options, host, oldProgram // re-use old program
  81. );
  82. };
  83. IncrementalChecker.createLinter = function (program) {
  84. // tslint:disable-next-line:no-implicit-dependencies
  85. var tslint = require('tslint');
  86. return new tslint.Linter({ fix: false }, program);
  87. };
  88. IncrementalChecker.isFileExcluded = function (filePath, linterExclusions) {
  89. return (endsWith(filePath, '.d.ts') ||
  90. linterExclusions.some(function (matcher) { return matcher.match(filePath); }));
  91. };
  92. IncrementalChecker.prototype.nextIteration = function () {
  93. var _this = this;
  94. if (!this.watcher) {
  95. var watchExtensions = this.vue
  96. ? ['.ts', '.tsx', '.vue']
  97. : ['.ts', '.tsx'];
  98. this.watcher = new FilesWatcher_1.FilesWatcher(this.watchPaths, watchExtensions);
  99. // connect watcher with register
  100. this.watcher.on('change', function (filePath, stats) {
  101. _this.files.setMtime(filePath, stats.mtime.valueOf());
  102. });
  103. this.watcher.on('unlink', function (filePath) {
  104. _this.files.remove(filePath);
  105. });
  106. this.watcher.watch();
  107. }
  108. if (!this.linterConfig && this.linterConfigFile) {
  109. this.linterConfig = IncrementalChecker.loadLinterConfig(this.linterConfigFile);
  110. if (this.linterConfig.linterOptions &&
  111. this.linterConfig.linterOptions.exclude) {
  112. // Pre-build minimatch patterns to avoid additional overhead later on.
  113. // Note: Resolving the path is required to properly match against the full file paths,
  114. // and also deals with potential cross-platform problems regarding path separators.
  115. this.linterExclusions = this.linterConfig.linterOptions.exclude.map(function (pattern) { return new minimatch.Minimatch(path.resolve(pattern)); });
  116. }
  117. }
  118. this.program = this.vue ? this.loadVueProgram() : this.loadDefaultProgram();
  119. if (this.linterConfig) {
  120. this.linter = IncrementalChecker.createLinter(this.program);
  121. }
  122. };
  123. IncrementalChecker.prototype.loadVueProgram = function () {
  124. this.programConfig =
  125. this.programConfig ||
  126. VueProgram_1.VueProgram.loadProgramConfig(this.typescript, this.programConfigFile, this.compilerOptions);
  127. return VueProgram_1.VueProgram.createProgram(this.typescript, this.programConfig, path.dirname(this.programConfigFile), this.files, this.watcher, this.program);
  128. };
  129. IncrementalChecker.prototype.loadDefaultProgram = function () {
  130. this.programConfig =
  131. this.programConfig ||
  132. IncrementalChecker.loadProgramConfig(this.typescript, this.programConfigFile, this.compilerOptions);
  133. return IncrementalChecker.createProgram(this.typescript, this.programConfig, this.files, this.watcher, this.program);
  134. };
  135. IncrementalChecker.prototype.hasLinter = function () {
  136. return this.linter !== undefined;
  137. };
  138. IncrementalChecker.prototype.getDiagnostics = function (cancellationToken) {
  139. var _this = this;
  140. var diagnostics = [];
  141. // select files to check (it's semantic check - we have to include all files :/)
  142. var filesToCheck = this.program.getSourceFiles();
  143. // calculate subset of work to do
  144. var workSet = new WorkSet_1.WorkSet(filesToCheck, this.workNumber, this.workDivision);
  145. // check given work set
  146. workSet.forEach(function (sourceFile) {
  147. if (cancellationToken) {
  148. cancellationToken.throwIfCancellationRequested();
  149. }
  150. var diagnosticsToRegister = _this
  151. .checkSyntacticErrors
  152. ? []
  153. .concat(_this.program.getSemanticDiagnostics(sourceFile, cancellationToken))
  154. .concat(_this.program.getSyntacticDiagnostics(sourceFile, cancellationToken))
  155. : _this.program.getSemanticDiagnostics(sourceFile, cancellationToken);
  156. diagnostics.push.apply(diagnostics, diagnosticsToRegister);
  157. });
  158. // normalize and deduplicate diagnostics
  159. return NormalizedMessage_1.NormalizedMessage.deduplicate(diagnostics.map(function (d) {
  160. return NormalizedMessage_1.NormalizedMessage.createFromDiagnostic(_this.typescript.flattenDiagnosticMessageText, d);
  161. }));
  162. };
  163. IncrementalChecker.prototype.getLints = function (cancellationToken) {
  164. var _this = this;
  165. if (!this.hasLinter()) {
  166. throw new Error('Cannot get lints - checker has no linter.');
  167. }
  168. // select files to lint
  169. var filesToLint = this.files
  170. .keys()
  171. .filter(function (filePath) {
  172. return !_this.files.getData(filePath).linted &&
  173. !IncrementalChecker.isFileExcluded(filePath, _this.linterExclusions);
  174. });
  175. // calculate subset of work to do
  176. var workSet = new WorkSet_1.WorkSet(filesToLint, this.workNumber, this.workDivision);
  177. // lint given work set
  178. workSet.forEach(function (fileName) {
  179. cancellationToken.throwIfCancellationRequested();
  180. try {
  181. _this.linter.lint(fileName, undefined, _this.linterConfig);
  182. }
  183. catch (e) {
  184. if (fs.existsSync(fileName) &&
  185. // check the error type due to file system lag
  186. !(e instanceof Error) &&
  187. !(e.constructor.name === 'FatalError') &&
  188. !(e.message && e.message.trim().startsWith('Invalid source file'))) {
  189. // it's not because file doesn't exist - throw error
  190. throw e;
  191. }
  192. }
  193. });
  194. // set lints in files register
  195. this.linter.getResult().failures.forEach(function (lint) {
  196. var filePath = lint.getFileName();
  197. _this.files.mutateData(filePath, function (data) {
  198. data.linted = true;
  199. data.lints.push(lint);
  200. });
  201. });
  202. // set all files as linted
  203. this.files.keys().forEach(function (filePath) {
  204. _this.files.mutateData(filePath, function (data) {
  205. data.linted = true;
  206. });
  207. });
  208. // get all lints
  209. var lints = this.files
  210. .keys()
  211. .reduce(function (innerLints, filePath) {
  212. return innerLints.concat(_this.files.getData(filePath).lints);
  213. }, []);
  214. // normalize and deduplicate lints
  215. return NormalizedMessage_1.NormalizedMessage.deduplicate(lints.map(NormalizedMessage_1.NormalizedMessage.createFromLint));
  216. };
  217. return IncrementalChecker;
  218. }());
  219. exports.IncrementalChecker = IncrementalChecker;