index.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _path = require("path");
  7. var _micromatch = require("micromatch");
  8. var _options = require("./options");
  9. var _linter = _interopRequireDefault(require("./linter"));
  10. var _utils = require("./utils");
  11. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  12. /** @typedef {import('webpack').Compiler} Compiler */
  13. /** @typedef {import('./options').Options} Options */
  14. const ESLINT_PLUGIN = 'ESLintWebpackPlugin';
  15. let counter = 0;
  16. class ESLintWebpackPlugin {
  17. /**
  18. * @param {Options} options
  19. */
  20. constructor(options = {}) {
  21. this.key = ESLINT_PLUGIN;
  22. this.options = (0, _options.getOptions)(options);
  23. this.run = this.run.bind(this);
  24. }
  25. /**
  26. * @param {Compiler} compiler
  27. * @returns {void}
  28. */
  29. apply(compiler) {
  30. // Generate key for each compilation,
  31. // this differentiates one from the other when being cached.
  32. this.key = compiler.name || `${this.key}_${counter += 1}`;
  33. const options = { ...this.options,
  34. exclude: (0, _utils.parseFiles)(this.options.exclude || [], this.getContext(compiler)),
  35. extensions: (0, _utils.arrify)(this.options.extensions),
  36. files: (0, _utils.parseFiles)(this.options.files || '', this.getContext(compiler))
  37. };
  38. const wanted = (0, _utils.parseFoldersToGlobs)(options.files, options.extensions);
  39. const exclude = (0, _utils.parseFoldersToGlobs)(this.options.exclude ? options.exclude : '**/node_modules/**', []); // If `lintDirtyModulesOnly` is disabled,
  40. // execute the linter on the build
  41. if (!this.options.lintDirtyModulesOnly) {
  42. compiler.hooks.run.tapPromise(this.key, c => this.run(c, options, wanted, exclude));
  43. }
  44. let isFirstRun = this.options.lintDirtyModulesOnly;
  45. compiler.hooks.watchRun.tapPromise(this.key, c => {
  46. if (isFirstRun) {
  47. isFirstRun = false;
  48. return Promise.resolve();
  49. }
  50. return this.run(c, options, wanted, exclude);
  51. });
  52. }
  53. /**
  54. * @param {Compiler} compiler
  55. * @param {Options} options
  56. * @param {string[]} wanted
  57. * @param {string[]} exclude
  58. */
  59. async run(compiler, options, wanted, exclude) {
  60. // Do not re-hook
  61. if ( // @ts-ignore
  62. compiler.hooks.compilation.taps.find(({
  63. name
  64. }) => name === this.key)) {
  65. return;
  66. }
  67. compiler.hooks.compilation.tap(this.key, compilation => {
  68. /** @type {import('./linter').Linter} */
  69. let lint;
  70. /** @type {import('./linter').Reporter} */
  71. let report;
  72. /** @type number */
  73. let threads;
  74. try {
  75. ({
  76. lint,
  77. report,
  78. threads
  79. } = (0, _linter.default)(this.key, options, compilation));
  80. } catch (e) {
  81. compilation.errors.push(e);
  82. return;
  83. }
  84. /** @type {string[]} */
  85. const files = []; // @ts-ignore
  86. // Add the file to be linted
  87. compilation.hooks.succeedModule.tap(this.key, ({
  88. resource
  89. }) => {
  90. if (resource) {
  91. const [file] = resource.split('?');
  92. if (file && !files.includes(file) && (0, _micromatch.isMatch)(file, wanted, {
  93. dot: true
  94. }) && !(0, _micromatch.isMatch)(file, exclude, {
  95. dot: true
  96. })) {
  97. files.push(file);
  98. if (threads > 1) {
  99. lint(file);
  100. }
  101. }
  102. }
  103. }); // Lint all files added
  104. compilation.hooks.finishModules.tap(this.key, () => {
  105. if (files.length > 0 && threads <= 1) {
  106. lint(files);
  107. }
  108. }); // await and interpret results
  109. compilation.hooks.additionalAssets.tapPromise(this.key, processResults);
  110. async function processResults() {
  111. const {
  112. errors,
  113. warnings,
  114. generateReportAsset
  115. } = await report();
  116. if (warnings && !options.failOnWarning) {
  117. // @ts-ignore
  118. compilation.warnings.push(warnings);
  119. } else if (warnings && options.failOnWarning) {
  120. // @ts-ignore
  121. compilation.errors.push(warnings);
  122. }
  123. if (errors && options.failOnError) {
  124. // @ts-ignore
  125. compilation.errors.push(errors);
  126. } else if (errors && !options.failOnError) {
  127. // @ts-ignore
  128. compilation.warnings.push(errors);
  129. }
  130. if (generateReportAsset) {
  131. await generateReportAsset(compilation);
  132. }
  133. }
  134. });
  135. }
  136. /**
  137. *
  138. * @param {Compiler} compiler
  139. * @returns {string}
  140. */
  141. getContext(compiler) {
  142. if (!this.options.context) {
  143. return String(compiler.options.context);
  144. }
  145. if (!(0, _path.isAbsolute)(this.options.context)) {
  146. return (0, _path.join)(String(compiler.options.context), this.options.context);
  147. }
  148. return this.options.context;
  149. }
  150. }
  151. var _default = ESLintWebpackPlugin;
  152. exports.default = _default;