/** * @fileoverview ESLint Processor Service * @author Nicholas C. Zakas */ /* eslint class-methods-use-this: off -- Anticipate future constructor arguments. */ "use strict"; //----------------------------------------------------------------------------- // Requirements //----------------------------------------------------------------------------- const path = require("node:path"); const { VFile } = require("../linter/vfile.js"); //----------------------------------------------------------------------------- // Types //----------------------------------------------------------------------------- /** @typedef {import("../shared/types.js").LintMessage} LintMessage */ /** @typedef {import("../linter/vfile.js").VFile} VFile */ /** @typedef {import("@eslint/core").Language} Language */ /** @typedef {import("@eslint/core").LanguageOptions} LanguageOptions */ /** @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, errors?: Array}} 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, nodeType: null } ] }; } 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 };