executor.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. /**
  4. * @license
  5. * Copyright Google Inc. All Rights Reserved.
  6. *
  7. * Use of this source code is governed by an MIT-style license that can be
  8. * found in the LICENSE file at https://angular.io/license
  9. */
  10. const fs = require("fs");
  11. const path = require("path");
  12. function _loadConfiguration(Configuration, options, root, file) {
  13. if (options.tslintConfig) {
  14. return Configuration.parseConfigFile(options.tslintConfig, root);
  15. }
  16. else if (options.tslintPath) {
  17. return Configuration.findConfiguration(path.join(root, options.tslintPath)).results;
  18. }
  19. else if (file) {
  20. return Configuration.findConfiguration(null, file).results;
  21. }
  22. else {
  23. throw new Error('Executor must specify a tslint configuration.');
  24. }
  25. }
  26. function _getFileContent(file, options, program) {
  27. // The linter retrieves the SourceFile TS node directly if a program is used
  28. if (program) {
  29. const source = program.getSourceFile(file);
  30. if (!source) {
  31. const message = `File '${file}' is not part of the TypeScript project '${options.tsConfigPath}'.`;
  32. throw new Error(message);
  33. }
  34. return source.getFullText(source);
  35. }
  36. // NOTE: The tslint CLI checks for and excludes MPEG transport streams; this does not.
  37. try {
  38. // Strip BOM from file data.
  39. // https://stackoverflow.com/questions/24356713
  40. return fs.readFileSync(file, 'utf-8').replace(/^\uFEFF/, '');
  41. }
  42. catch (_a) {
  43. throw new Error(`Could not read file '${file}'.`);
  44. }
  45. }
  46. function _listAllFiles(root) {
  47. const result = [];
  48. function _recurse(location) {
  49. const dir = fs.readdirSync(path.join(root, location));
  50. dir.forEach(name => {
  51. const loc = path.join(location, name);
  52. if (fs.statSync(path.join(root, loc)).isDirectory()) {
  53. _recurse(loc);
  54. }
  55. else {
  56. result.push(loc);
  57. }
  58. });
  59. }
  60. _recurse('');
  61. return result;
  62. }
  63. function default_1() {
  64. return async (options, context) => {
  65. const root = process.cwd();
  66. const tslint = await Promise.resolve().then(() => require('tslint')); // tslint:disable-line:no-implicit-dependencies
  67. const includes = (Array.isArray(options.includes)
  68. ? options.includes
  69. : (options.includes ? [options.includes] : []));
  70. const files = (Array.isArray(options.files)
  71. ? options.files
  72. : (options.files ? [options.files] : []));
  73. const Linter = tslint.Linter;
  74. const Configuration = tslint.Configuration;
  75. let program = undefined;
  76. let filesToLint = files;
  77. if (options.tsConfigPath && files.length == 0) {
  78. const tsConfigPath = path.join(process.cwd(), options.tsConfigPath);
  79. if (!fs.existsSync(tsConfigPath)) {
  80. throw new Error('Could not find tsconfig.');
  81. }
  82. program = Linter.createProgram(tsConfigPath);
  83. filesToLint = Linter.getFileNames(program);
  84. }
  85. if (includes.length > 0) {
  86. const allFilesRel = _listAllFiles(root);
  87. const pattern = '^('
  88. + includes
  89. .map(ex => '('
  90. + ex.split(/[\/\\]/g).map(f => f
  91. .replace(/[\-\[\]{}()+?.^$|]/g, '\\$&')
  92. .replace(/^\*\*/g, '(.+?)?')
  93. .replace(/\*/g, '[^/\\\\]*'))
  94. .join('[\/\\\\]')
  95. + ')')
  96. .join('|')
  97. + ')($|/|\\\\)';
  98. const re = new RegExp(pattern);
  99. filesToLint.push(...allFilesRel
  100. .filter(x => re.test(x))
  101. .map(x => path.join(root, x)));
  102. }
  103. const lintOptions = {
  104. fix: true,
  105. formatter: options.format || 'prose',
  106. };
  107. const linter = new Linter(lintOptions, program);
  108. // If directory doesn't change, we
  109. let lastDirectory = null;
  110. let config;
  111. for (const file of filesToLint) {
  112. const dir = path.dirname(file);
  113. if (lastDirectory !== dir) {
  114. lastDirectory = dir;
  115. config = _loadConfiguration(Configuration, options, root, file);
  116. }
  117. const content = _getFileContent(file, options, program);
  118. if (!content) {
  119. continue;
  120. }
  121. linter.lint(file, content, config);
  122. }
  123. const result = linter.getResult();
  124. // Format and show the results.
  125. if (!options.silent) {
  126. const Formatter = tslint.findFormatter(options.format || 'prose');
  127. if (!Formatter) {
  128. throw new Error(`Invalid lint format "${options.format}".`);
  129. }
  130. const formatter = new Formatter();
  131. // Certain tslint formatters outputs '\n' when there are no failures.
  132. // This will bloat the console when having schematics running refactor tasks.
  133. // see https://github.com/palantir/tslint/issues/4244
  134. const output = (formatter.format(result.failures, result.fixes) || '').trim();
  135. if (output) {
  136. context.logger.info(output);
  137. }
  138. }
  139. if (!options.ignoreErrors && result.errorCount > 0) {
  140. throw new Error('Lint errors were found.');
  141. }
  142. };
  143. }
  144. exports.default = default_1;