diff --git a/apps/oxlint/src-js/index.ts b/apps/oxlint/src-js/index.ts index 5f3817c88eea3..a53960f7f1cba 100644 --- a/apps/oxlint/src-js/index.ts +++ b/apps/oxlint/src-js/index.ts @@ -10,7 +10,8 @@ import type { SetNullable } from "./utils/types.ts"; export type * as ESTree from "./generated/types.d.ts"; export type { Context, LanguageOptions } from "./plugins/context.ts"; export type { Fix, Fixer, FixFn } from "./plugins/fix.ts"; -export type { CreateOnceRule, CreateRule, Options, Plugin, Rule } from "./plugins/load.ts"; +export type { CreateOnceRule, CreateRule, Plugin, Rule } from "./plugins/load.ts"; +export type { Options } from "./plugins/options.ts"; export type { Diagnostic, Suggestion } from "./plugins/report.ts"; export type { Definition, diff --git a/apps/oxlint/src-js/plugins/context.ts b/apps/oxlint/src-js/plugins/context.ts index 994fb25fdea94..bdb42fe79deb1 100644 --- a/apps/oxlint/src-js/plugins/context.ts +++ b/apps/oxlint/src-js/plugins/context.ts @@ -31,7 +31,8 @@ import { report } from "./report.js"; import { settings, initSettings } from "./settings.js"; import { debugAssertIsNonNull } from "../utils/asserts.js"; -import type { Options, RuleDetails } from "./load.ts"; +import type { RuleDetails } from "./load.ts"; +import type { Options } from "./options.ts"; import type { Diagnostic } from "./report.ts"; import type { Settings } from "./settings.ts"; import type { SourceCode } from "./source_code.ts"; @@ -363,6 +364,7 @@ export function createContext(fullRuleName: string, ruleDetails: RuleDetails): R // 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; }, /** diff --git a/apps/oxlint/src-js/plugins/lint.ts b/apps/oxlint/src-js/plugins/lint.ts index f846237410ed8..152321d8a5691 100644 --- a/apps/oxlint/src-js/plugins/lint.ts +++ b/apps/oxlint/src-js/plugins/lint.ts @@ -1,5 +1,6 @@ import { setupFileContext, resetFileContext } from "./context.js"; import { registeredRules } from "./load.js"; +import { allOptions, DEFAULT_OPTIONS_ID } from "./options.js"; import { diagnostics } from "./report.js"; import { setSettingsForFile, resetSettings } from "./settings.js"; import { ast, initAst, resetSourceAndAst, setupSourceForFile } from "./source_code.js"; @@ -55,8 +56,11 @@ export function lintFile( ruleIds: number[], settingsJSON: string, ): string { + // TODO: Get `optionsIds` from Rust side + const optionsIds = ruleIds.map((_) => DEFAULT_OPTIONS_ID); + try { - lintFileImpl(filePath, bufferId, buffer, ruleIds, settingsJSON); + lintFileImpl(filePath, bufferId, buffer, ruleIds, optionsIds, settingsJSON); return JSON.stringify({ Success: diagnostics }); } catch (err) { return JSON.stringify({ Failure: getErrorMessage(err) }); @@ -72,6 +76,7 @@ export function lintFile( * @param bufferId - ID of buffer containing file data * @param buffer - Buffer containing file data, or `null` if buffer with this ID was previously sent to JS * @param ruleIds - IDs of rules to run on this file + * @param optionsIds - IDs of options to use for rules on this file * @param settingsJSON - Stringified settings for this file * @returns Diagnostics to send back to Rust * @throws {Error} If any parameters are invalid @@ -82,6 +87,7 @@ function lintFileImpl( bufferId: number, buffer: Uint8Array | null, ruleIds: number[], + optionsIds: number[], settingsJSON: string, ) { // If new buffer, add it to `buffers` array. Otherwise, get existing buffer from array. @@ -141,6 +147,9 @@ function lintFileImpl( // Set `ruleIndex` for rule. It's used when sending diagnostics back to Rust. ruleDetails.ruleIndex = i; + // Set `options` for rule + ruleDetails.options = allOptions[optionsIds[i]]; + let { visitor } = ruleDetails; if (visitor === null) { // Rule defined with `create` method diff --git a/apps/oxlint/src-js/plugins/load.ts b/apps/oxlint/src-js/plugins/load.ts index 6d522d4ae1d3c..e73246d677205 100644 --- a/apps/oxlint/src-js/plugins/load.ts +++ b/apps/oxlint/src-js/plugins/load.ts @@ -5,7 +5,7 @@ import { getErrorMessage } from "../utils/utils.js"; import type { Writable } from "type-fest"; import type { Context } from "./context.ts"; -import type { JsonValue } from "./json.ts"; +import type { Options } from "./options.ts"; import type { RuleMeta } from "./rule_meta.ts"; import type { AfterHook, BeforeHook, Visitor, VisitorWithHooks } from "./types.ts"; import type { SetNullable } from "../utils/types.ts"; @@ -46,11 +46,6 @@ export interface CreateOnceRule { createOnce: (context: Context) => VisitorWithHooks; } -/** - * Options for a rule on a file. - */ -export type Options = JsonValue[]; - /** * Linter rule, context object, and other details of rule. * If `rule` has a `createOnce` method, the visitor it returns is stored in `visitor` property. @@ -64,7 +59,7 @@ interface RuleDetailsBase { readonly messages: Readonly> | null; // Updated for each file ruleIndex: number; - options: Readonly; + options: Readonly | null; // Initially `null`, set to options object before linting a file } interface CreateRuleDetails extends RuleDetailsBase { @@ -91,9 +86,6 @@ export const registeredRules: RuleDetails[] = []; // `before` hook which makes rule never run. const neverRunBeforeHook: BeforeHook = () => false; -// Default rule options -const DEFAULT_OPTIONS: Readonly = Object.freeze([]); - // Plugin details returned to Rust interface PluginDetails { // Plugin name @@ -186,7 +178,7 @@ async function loadPluginImpl(path: string, packageName: string | null): Promise isFixable, messages, ruleIndex: 0, - options: DEFAULT_OPTIONS, + options: null, visitor: null, beforeHook: null, afterHook: null, diff --git a/apps/oxlint/src-js/plugins/options.ts b/apps/oxlint/src-js/plugins/options.ts new file mode 100644 index 0000000000000..f396662b81f2d --- /dev/null +++ b/apps/oxlint/src-js/plugins/options.ts @@ -0,0 +1,19 @@ +/* + * Options for rules. + */ + +import type { JsonValue } from "./json.ts"; + +/** + * Options for a rule on a file. + */ +export type Options = JsonValue[]; + +// Default rule options +const DEFAULT_OPTIONS: Readonly = Object.freeze([]); + +// All rule options +export const allOptions: Readonly[] = [DEFAULT_OPTIONS]; + +// Index into `allOptions` for default options +export const DEFAULT_OPTIONS_ID = 0;