| /** | |
| * @fileoverview ESLint Processor Service | |
| * @author Nicholas C. Zakas | |
| */ | |
| /* eslint class-methods-use-this: off -- Anticipate future constructor arguments. */ | |
| ; | |
| //----------------------------------------------------------------------------- | |
| // Requirements | |
| //----------------------------------------------------------------------------- | |
| const path = require("node:path"); | |
| const { VFile } = require("../linter/vfile.js"); | |
| //----------------------------------------------------------------------------- | |
| // Types | |
| //----------------------------------------------------------------------------- | |
| /** @typedef {import("../types").Linter.LintMessage} LintMessage */ | |
| /** @typedef {import("../linter/vfile.js").VFile} VFile */ | |
| /** @typedef {import("@eslint/core").Language} Language */ | |
| /** @typedef {import("eslint").Linter.Processor} Processor */ | |
| //----------------------------------------------------------------------------- | |
| // Exports | |
| //----------------------------------------------------------------------------- | |
| /** | |
| * The service that applies processors to files. | |
| */ | |
| class ProcessorService { | |
| /** | |
| * Preprocesses the given file synchronously. | |
| * @param {VFile} file The file to preprocess. | |
| * @param {{processor:Processor}} config The configuration to use. | |
| * @returns {{ok:boolean, files?: Array<VFile>, errors?: Array<LintMessage>}} An array of preprocessed files or errors. | |
| * @throws {Error} If the preprocessor returns a promise. | |
| */ | |
| preprocessSync(file, config) { | |
| const { processor } = config; | |
| let blocks; | |
| try { | |
| blocks = processor.preprocess(file.rawBody, file.path); | |
| } catch (ex) { | |
| // If the message includes a leading line number, strip it: | |
| const message = `Preprocessing error: ${ex.message.replace(/^line \d+:/iu, "").trim()}`; | |
| return { | |
| ok: false, | |
| errors: [ | |
| { | |
| ruleId: null, | |
| fatal: true, | |
| severity: 2, | |
| message, | |
| line: ex.lineNumber, | |
| column: ex.column, | |
| }, | |
| ], | |
| }; | |
| } | |
| if (typeof blocks.then === "function") { | |
| throw new Error("Unsupported: Preprocessor returned a promise."); | |
| } | |
| return { | |
| ok: true, | |
| files: blocks.map((block, i) => { | |
| // Legacy behavior: return the block as a string | |
| if (typeof block === "string") { | |
| return block; | |
| } | |
| const filePath = path.join(file.path, `${i}_${block.filename}`); | |
| return new VFile(filePath, block.text, { | |
| physicalPath: file.physicalPath, | |
| }); | |
| }), | |
| }; | |
| } | |
| /** | |
| * Postprocesses the given messages synchronously. | |
| * @param {VFile} file The file to postprocess. | |
| * @param {LintMessage[][]} messages The messages to postprocess. | |
| * @param {{processor:Processor}} config The configuration to use. | |
| * @returns {LintMessage[]} The postprocessed messages. | |
| */ | |
| postprocessSync(file, messages, config) { | |
| const { processor } = config; | |
| return processor.postprocess(messages, file.path); | |
| } | |
| } | |
| module.exports = { ProcessorService }; | |