processor-service.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /**
  2. * @fileoverview ESLint Processor Service
  3. * @author Nicholas C. Zakas
  4. */
  5. /* eslint class-methods-use-this: off -- Anticipate future constructor arguments. */
  6. "use strict";
  7. //-----------------------------------------------------------------------------
  8. // Requirements
  9. //-----------------------------------------------------------------------------
  10. const path = require("node:path");
  11. const { VFile } = require("../linter/vfile.js");
  12. //-----------------------------------------------------------------------------
  13. // Types
  14. //-----------------------------------------------------------------------------
  15. /** @typedef {import("../shared/types.js").LintMessage} LintMessage */
  16. /** @typedef {import("../linter/vfile.js").VFile} VFile */
  17. /** @typedef {import("@eslint/core").Language} Language */
  18. /** @typedef {import("@eslint/core").LanguageOptions} LanguageOptions */
  19. /** @typedef {import("eslint").Linter.Processor} Processor */
  20. //-----------------------------------------------------------------------------
  21. // Exports
  22. //-----------------------------------------------------------------------------
  23. /**
  24. * The service that applies processors to files.
  25. */
  26. class ProcessorService {
  27. /**
  28. * Preprocesses the given file synchronously.
  29. * @param {VFile} file The file to preprocess.
  30. * @param {{processor:Processor}} config The configuration to use.
  31. * @returns {{ok:boolean, files?: Array<VFile>, errors?: Array<LintMessage>}} An array of preprocessed files or errors.
  32. * @throws {Error} If the preprocessor returns a promise.
  33. */
  34. preprocessSync(file, config) {
  35. const { processor } = config;
  36. let blocks;
  37. try {
  38. blocks = processor.preprocess(file.rawBody, file.path);
  39. } catch (ex) {
  40. // If the message includes a leading line number, strip it:
  41. const message = `Preprocessing error: ${ex.message.replace(/^line \d+:/iu, "").trim()}`;
  42. return {
  43. ok: false,
  44. errors: [
  45. {
  46. ruleId: null,
  47. fatal: true,
  48. severity: 2,
  49. message,
  50. line: ex.lineNumber,
  51. column: ex.column,
  52. nodeType: null
  53. }
  54. ]
  55. };
  56. }
  57. if (typeof blocks.then === "function") {
  58. throw new Error("Unsupported: Preprocessor returned a promise.");
  59. }
  60. return {
  61. ok: true,
  62. files: blocks.map((block, i) => {
  63. // Legacy behavior: return the block as a string
  64. if (typeof block === "string") {
  65. return block;
  66. }
  67. const filePath = path.join(file.path, `${i}_${block.filename}`);
  68. return new VFile(filePath, block.text, {
  69. physicalPath: file.physicalPath
  70. });
  71. })
  72. };
  73. }
  74. /**
  75. * Postprocesses the given messages synchronously.
  76. * @param {VFile} file The file to postprocess.
  77. * @param {LintMessage[][]} messages The messages to postprocess.
  78. * @param {{processor:Processor}} config The configuration to use.
  79. * @returns {LintMessage[]} The postprocessed messages.
  80. */
  81. postprocessSync(file, messages, config) {
  82. const { processor } = config;
  83. return processor.postprocess(messages, file.path);
  84. }
  85. }
  86. module.exports = { ProcessorService };