Linter.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _process = _interopRequireDefault(require("process"));
  7. var _path = require("path");
  8. var _fsExtra = require("fs-extra");
  9. var _loaderUtils = require("loader-utils");
  10. var _ESLintError = _interopRequireDefault(require("./ESLintError"));
  11. var _createEngine = _interopRequireDefault(require("./createEngine"));
  12. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  13. class Linter {
  14. constructor(loaderContext, options) {
  15. this.loaderContext = loaderContext;
  16. this.options = options;
  17. this.resourcePath = this.parseResourcePath();
  18. const {
  19. CLIEngine,
  20. engine
  21. } = (0, _createEngine.default)(options);
  22. this.CLIEngine = CLIEngine;
  23. this.engine = engine;
  24. }
  25. parseResourcePath() {
  26. const cwd = _process.default.cwd();
  27. let {
  28. resourcePath
  29. } = this.loaderContext; // remove cwd from resource path in case webpack has been started from project
  30. // root, to allow having relative paths in .eslintignore
  31. // istanbul ignore next
  32. if (resourcePath.indexOf(cwd) === 0) {
  33. resourcePath = resourcePath.substr(cwd.length + (cwd === '/' ? 0 : 1));
  34. }
  35. return resourcePath;
  36. }
  37. lint(content) {
  38. try {
  39. return this.engine.executeOnText(content, this.resourcePath, true);
  40. } catch (_) {
  41. this.getEmitter(false)(_);
  42. return {
  43. src: content
  44. };
  45. }
  46. }
  47. printOutput(data) {
  48. const {
  49. options
  50. } = this; // skip ignored file warning
  51. if (this.constructor.skipIgnoredFileWarning(data)) {
  52. return;
  53. } // quiet filter done now
  54. // eslint allow rules to be specified in the input between comments
  55. // so we can found warnings defined in the input itself
  56. const res = this.filter(data); // if enabled, use eslint auto-fixing where possible
  57. if (options.fix) {
  58. this.autoFix(res);
  59. } // skip if no errors or warnings
  60. if (res.errorCount < 1 && res.warningCount < 1) {
  61. return;
  62. }
  63. const results = this.parseResults(res); // Do not analyze if there are no results or eslint config
  64. if (!results) {
  65. return;
  66. }
  67. const messages = options.formatter(results);
  68. this.reportOutput(results, messages);
  69. this.failOnErrorOrWarning(res, messages);
  70. const emitter = this.getEmitter(res);
  71. emitter(new _ESLintError.default(messages));
  72. }
  73. static skipIgnoredFileWarning(res) {
  74. return res && res.warningCount === 1 && res.results && res.results[0] && res.results[0].messages[0] && res.results[0].messages[0].message && res.results[0].messages[0].message.indexOf('ignore') > 1;
  75. }
  76. filter(data) {
  77. const res = data; // quiet filter done now
  78. // eslint allow rules to be specified in the input between comments
  79. // so we can found warnings defined in the input itself
  80. if (this.options.quiet && res && res.warningCount && res.results && res.results[0]) {
  81. res.warningCount = 0;
  82. res.results[0].warningCount = 0;
  83. res.results[0].messages = res.results[0].messages.filter(message => message.severity !== 1);
  84. }
  85. return res;
  86. }
  87. autoFix(res) {
  88. if (res && res.results && res.results[0] && (res.results[0].output !== res.src || res.results[0].fixableErrorCount > 0 || res.results[0].fixableWarningCount > 0)) {
  89. this.CLIEngine.outputFixes(res);
  90. }
  91. }
  92. parseResults({
  93. results
  94. }) {
  95. // add filename for each results so formatter can have relevant filename
  96. if (results) {
  97. results.forEach(r => {
  98. // eslint-disable-next-line no-param-reassign
  99. r.filePath = this.loaderContext.resourcePath;
  100. });
  101. }
  102. return results;
  103. }
  104. reportOutput(results, messages) {
  105. const {
  106. outputReport
  107. } = this.options;
  108. if (!outputReport || !outputReport.filePath) {
  109. return;
  110. }
  111. let content = messages; // if a different formatter is passed in as an option use that
  112. if (outputReport.formatter) {
  113. content = outputReport.formatter(results);
  114. }
  115. let filePath = (0, _loaderUtils.interpolateName)(this.loaderContext, outputReport.filePath, {
  116. content
  117. });
  118. if (!(0, _path.isAbsolute)(filePath)) {
  119. filePath = (0, _path.join)( // eslint-disable-next-line no-underscore-dangle
  120. this.loaderContext._compiler.options.output.path, filePath);
  121. }
  122. (0, _fsExtra.ensureFileSync)(filePath);
  123. (0, _fsExtra.writeFileSync)(filePath, content);
  124. }
  125. failOnErrorOrWarning({
  126. errorCount,
  127. warningCount
  128. }, messages) {
  129. const {
  130. failOnError,
  131. failOnWarning
  132. } = this.options;
  133. if (failOnError && errorCount) {
  134. throw new _ESLintError.default(`Module failed because of a eslint error.\n${messages}`);
  135. }
  136. if (failOnWarning && warningCount) {
  137. throw new _ESLintError.default(`Module failed because of a eslint warning.\n${messages}`);
  138. }
  139. }
  140. getEmitter({
  141. errorCount
  142. }) {
  143. const {
  144. options,
  145. loaderContext
  146. } = this; // default behavior: emit error only if we have errors
  147. let emitter = errorCount ? loaderContext.emitError : loaderContext.emitWarning; // force emitError or emitWarning if user want this
  148. if (options.emitError) {
  149. emitter = loaderContext.emitError;
  150. } else if (options.emitWarning) {
  151. emitter = loaderContext.emitWarning;
  152. }
  153. return emitter;
  154. }
  155. }
  156. exports.default = Linter;