diff --git a/apps/oxlint/src-js/plugins/context.ts b/apps/oxlint/src-js/plugins/context.ts index 68b87f53981db..b7c0697fbcfac 100644 --- a/apps/oxlint/src-js/plugins/context.ts +++ b/apps/oxlint/src-js/plugins/context.ts @@ -516,6 +516,7 @@ export function createContext(ruleDetails: RuleDetails): Readonly { return Object.freeze({ // Inherit from `FILE_CONTEXT`, which provides getters for file-specific properties __proto__: FILE_CONTEXT, + // Rule ID, in form `/` get id(): string { // It's not possible to allow access to `id` in `createOnce` in ESLint compatibility mode, so we don't @@ -523,61 +524,31 @@ export function createContext(ruleDetails: RuleDetails): Readonly { if (filePath === null) throw new Error("Cannot access `context.id` in `createOnce`"); return ruleDetails.fullName; }, + // Getter for rule options for this rule on this file get options(): Readonly { if (filePath === null) throw new Error("Cannot access `context.options` in `createOnce`"); debugAssertIsNonNull(ruleDetails.options); return ruleDetails.options; }, + /** * Report error. + * + * Normally called with a single `Diagnostic` object. + * + * Can also be called with legacy positional forms: + * - `context.report(node, message, data?, fix?)` + * - `context.report(node, loc, message, data?, fix?)` + * These legacy forms are not included in type def for this method, as they are deprecated, + * but some plugins still use them, so we support them. + * * @param diagnostic - Diagnostic object * @throws {TypeError} If `diagnostic` is invalid */ - report(this: void, diagnostic: Diagnostic): void { - const normalizedDiagnostic = normalizeReportCallArgs(diagnostic, arguments); - + report(this: void, diagnostic: Diagnostic, ...extraArgs: unknown[]): void { // Delegate to `report` implementation shared between all rules, passing rule-specific details (`RuleDetails`) - report(normalizedDiagnostic, ruleDetails); + report(diagnostic, extraArgs, ruleDetails); }, } as unknown as Context); // It seems TS can't understand `__proto__: FILE_CONTEXT` } - -/** - * Normalize `context.report()` arguments. - * - * Supports both forms: - * 1. New-style: `context.report({ ...descriptor })` - * 2. Legacy: `context.report(node, message, data?, fix?)` - * or `context.report(node, loc, message, data?, fix?)` - */ -function normalizeReportCallArgs(diagnostic: Diagnostic, args: IArguments): Diagnostic { - // New-style call already has a descriptor object. - if (args.length <= 1) return diagnostic; - - // Legacy positional forms. - const node = diagnostic as unknown; - let loc: unknown = undefined, - message: unknown, - data: unknown = undefined, - fix: unknown = undefined; - - if (typeof args[1] === "string") { - // [node, message, data, fix] - message = args[1]; - data = args[2]; - fix = args[3]; - } else { - // [node, loc, message, data, fix] - loc = args[1]; - message = args[2]; - data = args[3]; - fix = args[4]; - } - - const descriptor: Record = { node, message }; - if (loc !== undefined) descriptor.loc = loc; - if (data !== undefined) descriptor.data = data; - if (fix !== undefined) descriptor.fix = fix; - return descriptor as Diagnostic; -} diff --git a/apps/oxlint/src-js/plugins/report.ts b/apps/oxlint/src-js/plugins/report.ts index 314f44513aa53..29c76cc32d0ec 100644 --- a/apps/oxlint/src-js/plugins/report.ts +++ b/apps/oxlint/src-js/plugins/report.ts @@ -98,12 +98,20 @@ export const PLACEHOLDER_REGEX = /\{\{([^{}]+)\}\}/gu; /** * Report error. * @param diagnostic - Diagnostic object + * @param extraArgs - Extra arguments passed to `context.report()` (legacy positional forms) * @param ruleDetails - `RuleDetails` object, containing rule-specific details e.g. `isFixable` * @throws {TypeError} If `diagnostic` is invalid */ -export function report(diagnostic: Diagnostic, ruleDetails: RuleDetails): void { +export function report( + diagnostic: Diagnostic, + extraArgs: unknown[], + ruleDetails: RuleDetails, +): void { if (filePath === null) throw new Error("Cannot report errors in `createOnce`"); + // Handle legacy positional forms + if (extraArgs.length > 0) diagnostic = convertLegacyCallArgs(diagnostic, extraArgs); + const { message, messageId } = getMessage( Object.hasOwn(diagnostic, "message") ? diagnostic.message : null, diagnostic, @@ -195,6 +203,40 @@ export function report(diagnostic: Diagnostic, ruleDetails: RuleDetails): void { if (CONFORMANCE) diagnostics.at(-1)!.loc = conformedLoc; } +/** + * Convert legacy `context.report()` arguments to a `Diagnostic` object. + * + * Supported: + * - `context.report(node, message, data?, fix?)` + * - `context.report(node, loc, message, data?, fix?)` + * + * @param node - Node to report (first argument) + * @param extraArgs - Extra arguments passed to `context.report()` + * @returns Diagnostic object + */ +function convertLegacyCallArgs(node: unknown, extraArgs: unknown[]): Diagnostic { + const firstExtraArg = extraArgs[0]; + if (typeof firstExtraArg === "string") { + // `context.report(node, message, data, fix)` + return { + message: firstExtraArg, + node, + loc: undefined, + data: extraArgs[1], + fix: extraArgs[2], + } as Diagnostic; + } + + // `context.report(node, loc, message, data, fix)` + return { + message: extraArgs[1], + node, + loc: firstExtraArg, + data: extraArgs[2], + fix: extraArgs[3], + } as Diagnostic; +} + /** * Get message from a diagnostic or suggestion. *