diff --git a/README.md b/README.md index bf88ef4..7721130 100644 --- a/README.md +++ b/README.md @@ -271,7 +271,7 @@ Set up, write, or review Rstest tests and configuration, including environments, npx skills add rstackjs/agent-skills --skill migrate-to-rslint ``` -Migrate ESLint or other lint tools to Rslint. Use when replacing ESLint flat config, lint scripts, VS Code ESLint settings, inline directives, rules, presets, plugins, or lint dependencies with Rslint equivalents. +Migrate ESLint flat config or Oxlint to Rslint, preserving rule options, file scopes, and plugins while updating lint scripts, editor settings, and inline directives. ## Storybook skills diff --git a/scripts/dictionary.txt b/scripts/dictionary.txt index 1f7bf02..1b48b80 100644 --- a/scripts/dictionary.txt +++ b/scripts/dictionary.txt @@ -21,6 +21,8 @@ llms modernjs mktemp napi +oxlint +oxlintrc pacman pluggable prebundle diff --git a/skills/migrate-to-rslint/SKILL.md b/skills/migrate-to-rslint/SKILL.md index 6a74987..3fc8534 100644 --- a/skills/migrate-to-rslint/SKILL.md +++ b/skills/migrate-to-rslint/SKILL.md @@ -1,6 +1,6 @@ --- name: migrate-to-rslint -description: Migrate ESLint or other linters to Rslint. Use when asked to replace ESLint flat config, lint scripts, VS Code ESLint settings, inline directives, rules, presets, plugins, or lint dependencies with Rslint equivalents. +description: Migrate ESLint flat config or Oxlint to Rslint, preserving rule options, file scopes, and plugins while updating lint scripts, editor settings, and inline directives. --- @@ -14,29 +14,42 @@ Migrate lint tooling to Rslint with minimal behavior changes and clear validatio ## Supported source linters - ESLint flat config +- Oxlint ## Migration principles (must follow) -1. **Official docs first**: treat Rslint docs as source of truth for CLI, config, inline directives, VS Code settings, rules, and presets. +1. **Official docs first**: use Rslint docs for CLI, config, inline directives, VS Code settings, rules, and presets. Check capabilities against the installed version; historical migration gaps and workarounds are not permanent limitations. 2. **Smallest-change-first**: migrate package, command, config, and editor wiring before changing source files. 3. **Preserve lint intent**: keep supported rule severities/options where Rslint supports them; call out unsupported rules/plugins instead of silently dropping behavior. -4. **Do not rewrite inline directives by default**: Rslint supports `eslint-disable` and `rslint-disable`; replace prefixes only when the user asks. -5. **Validate before cleanup**: keep old linter dependencies/config until the Rslint command passes for the migrated scope, then remove obsolete linter-only artifacts. +4. **Preserve inline suppression intent**: preserve which directives take effect, their rule targets, and their scope. Keep compatible prefixes unless the user requests renaming; translate source-only syntax and account for disabled directive compatibility in the source-specific guide. +5. **Validate before cleanup**: switch lint entry points to Rslint and validate the migrated scope before removing obsolete source-linter artifacts. Report unsupported-rule coverage differences without treating them as a blocker or requiring separate approval. ## Workflow 1. **Detect source linter** - ESLint flat config: `eslint.config.*`, `eslint` dependency, or package scripts that run `eslint`. + - Oxlint: `.oxlintrc.json`, `.oxlintrc.jsonc`, `oxlint.config.*`, `oxlint` dependency, or commands that run `oxlint`. + - Record installed versions, commands, working directories, environment switches, and the scope being migrated. Include shared configs, nested configs, and root fallback behavior within that scope. - If the source linter is not covered by a reference yet, inventory the current behavior and explain that no dedicated migration reference exists. -2. **Apply source-specific migration guide** - - ESLint flat config: `references/eslint-flat-config.md` +2. **Prepare Rslint and apply the source-specific guide** + - Select and install the intended `@rslint/core` version with the repository's package manager before checking its rules, config, and plugin APIs. Respect existing version constraints and retain the source linter for validation. + - ESLint flat config: [references/eslint-flat-config.md](references/eslint-flat-config.md) + - Oxlint: [references/oxlint.md](references/oxlint.md) + - For community or local JS plugins from either source, also read [references/eslint-plugins.md](references/eslint-plugins.md). -3. **Validate behavior** +3. **Update lint entry points** + - Use a supported `rslint.config.*` format. Keep source plugin dependencies required by the translated config. + - Update package scripts, CI, hooks, and staged-file commands in the migrated scope. Use the [Rslint CLI reference](https://rslint.rs/guide/cli) to translate flags while preserving working directories, file arguments, warning thresholds, and environment switches. + - Update existing editor integration using the [Rslint VS Code guide](https://rslint.rs/guide/vscode-extension). Keep unrelated editor tools and settings. + +4. **Validate behavior** - Run the migrated lint command. + - Check effective rules/options, file coverage, suppressions, and plugin execution against the source inventory. A successful exit alone does not establish equivalent behavior. + - For enabled source rules without a validated native or compatible JS-plugin replacement, omit unsupported target keys and record the rule names, affected file scope, and lost coverage for the final report. Continue the migration with the supported rules. - If the project had a fix command, run the migrated fix command only when appropriate for the task. - - Resolve config, rule, and editor-setting issues before removing legacy files. + - Resolve target config-loading errors, invalid options for supported rules, command failures, and editor-integration errors before cleanup. -4. **Cleanup and summarize** - - Remove obsolete linter dependencies/config after Rslint is green. - - Summarize changed files, migrated presets/plugins, unsupported gaps, and remaining manual follow-ups. +5. **Cleanup and summarize** + - Confirm all lint entry points in the migrated scope use Rslint, then remove obsolete source-linter commands, configuration, and dependencies after validation. + - Summarize the completed switchover and validation, naming any omitted rules/plugins, affected scopes, and coverage or behavior changes. diff --git a/skills/migrate-to-rslint/references/eslint-flat-config.md b/skills/migrate-to-rslint/references/eslint-flat-config.md index 50f0e74..d720a60 100644 --- a/skills/migrate-to-rslint/references/eslint-flat-config.md +++ b/skills/migrate-to-rslint/references/eslint-flat-config.md @@ -8,6 +8,8 @@ Use this reference when the source project uses `eslint.config.*`. - Rslint configuration: https://rslint.rs/config/ - Rslint ignores and `.gitignore`: https://rslint.rs/config/ignoring-files - Rslint rules and presets: https://rslint.rs/config/rules-and-presets +- Rslint TypeScript project settings: https://rslint.rs/config/language-options +- Rslint ESLint plugin compatibility: https://rslint.rs/guide/eslint-plugins - Rslint inline directives: https://rslint.rs/guide/inline-directives - Rslint VS Code extension: https://rslint.rs/guide/vscode-extension - `jiti`: https://npmjs.com/package/jiti @@ -39,7 +41,7 @@ Do not delete the ESLint config or dependencies until the migrated Rslint comman ## Step 1: replace linter package dependencies -Install Rslint: +If Rslint was not already installed in the main workflow, install it with the intended version constraints: ```bash pnpm add -D @rslint/core @@ -95,7 +97,7 @@ Use only Rslint-supported CLI flags. Supported flags include `--init`, `--config Do not copy ESLint-only flags blindly. For example, remove or re-evaluate flags such as `--ext`, `--cache`, `--cache-location`, `--resolve-plugins-relative-to`, and `--report-unused-disable-directives` unless the Rslint CLI docs provide an equivalent. -If the old lint command relied on type-aware TypeScript linting, validate the migrated command with `--type-check` or preserve the project's existing Rslint type-checking setup. +If the old lint command relied on type-aware TypeScript rules, preserve its project selection through `languageOptions.parserOptions.project` or `projectService: true`, using the installed Rslint version's supported settings. These modes are alternatives. `--type-check` additionally reports TypeScript compiler diagnostics; do not add it merely to enable type-aware lint rules. ## Step 3: rename and translate config file @@ -110,7 +112,7 @@ Recommended mapping: | `eslint.config.ts` | `rslint.config.ts` | | `eslint.config.mts` | `rslint.config.mts` | -Rslint uses flat config arrays, so the shape is close to ESLint flat config. Import built-in helpers and presets from `@rslint/core`: +Rslint uses flat config arrays, so the shape is close to ESLint flat config. Import built-in helpers and presets from `@rslint/core`. The following illustrates available imports; include only presets that match the source configuration's intent: ```ts import { @@ -168,14 +170,14 @@ Rslint aligns its JavaScript recommended preset with ESLint's `js.configs.recomm For rules: - Keep rule severities and options when Rslint supports the rule. -- If Rslint reports an unknown rule, remove it from the Rslint config and list it as an unsupported migration gap. -- Do not keep installing ESLint plugins in an attempt to make Rslint load them. +- Check unknown rules against the installed native rule catalog and any registered JS plugin. Record unresolved rules as migration gaps; do not silently disable them to make lint pass. +- For community or local JS plugins, follow [ESLint-compatible JS plugins](eslint-plugins.md). Retain packages still needed by those plugins. - For built-in plugin presets, remove the old plugin dependency after validation if it is no longer used elsewhere. For ignores: - Rslint automatically reads `.gitignore` files and treats those patterns as global ignores. -- Remove `ignores` entries that only duplicate `.gitignore` patterns. +- Remove duplicate `ignores` entries only after confirming that the relevant `.gitignore` is read for that invocation and config boundary. Nested configs do not automatically inherit ancestor `.gitignore` files outside their Git scope. - Keep lint-specific ignores that are not in `.gitignore`, such as source fixtures, generated checked-in files, or deliberate lint exclusions. - Remember that a config entry containing only `ignores` is a global ignore and can block nested config discovery in ignored directories. @@ -260,7 +262,7 @@ Resolve validation failures in this order: 4. Type-aware linting behavior. 5. Autofix differences. -After validation passes: +Complete the main workflow's [behavior validation](../SKILL.md#workflow), including the source inventory comparison, before cleanup. After validation passes: - Remove obsolete ESLint config files. - Remove obsolete ESLint dependencies that are not used elsewhere. diff --git a/skills/migrate-to-rslint/references/eslint-plugins.md b/skills/migrate-to-rslint/references/eslint-plugins.md new file mode 100644 index 0000000..f7ff637 --- /dev/null +++ b/skills/migrate-to-rslint/references/eslint-plugins.md @@ -0,0 +1,37 @@ +# ESLint-compatible JS plugins + +Use this reference when the source config loads community or local JS plugins. Oxlint-specific `createOnce` adaptation is covered in [the Oxlint guide](oxlint.md#step-4-adapt-js-plugins). + +Check the installed Rslint version against the official [plugin configuration](https://rslint.rs/config/plugins) and [ESLint API compatibility](https://rslint.rs/guide/eslint-plugins) references. + +## Preserve plugin identity and configuration + +- Record each module, configured namespace, enabled rules, options, settings, file scope, and environment-dependent wrapper. A loaded module or an explicitly disabled rule is not an enabled rule. +- Reuse the plugin implementation when supported. Keep its package and runtime dependencies resolvable from the migrated config. +- Register native namespaces with a `plugins` array and JS plugin objects with a `plugins` object in separate entries. Keep their original scope and precedence. +- Preserve custom aliases. If an alias conflicts with a Rslint built-in namespace, choose a distinct alias and update its rule keys and directive references together; do not merge unrelated rules by name. + +For example, separate native and JS plugin registration while retaining the same file scope: + +```js +import customPlugin from './lint/custom-plugin.js'; + +export default [ + { + files: ['src/**/*.ts'], + plugins: ['@typescript-eslint'], + rules: { '@typescript-eslint/no-explicit-any': 'warn' }, + }, + { + files: ['src/**/*.ts'], + plugins: { custom: customPlugin }, + rules: { 'custom/project-rule': 'error' }, + }, +]; +``` + +## Check the APIs used by enabled rules + +Confirm that the target version supports the plugin's selectors, context APIs, and fix behavior. In particular, inspect uses of parser services, custom parsers/processors, and code-path listeners against the compatibility reference. Loading a plugin successfully does not prove that its rules execute. + +Use a representative known violation to confirm execution, including any environment switch that enables or disables a wrapper. Preserve rule logic; report an API gap when the existing implementation cannot run. Return to the calling source-specific guide and finish its remaining steps before continuing with the main workflow. diff --git a/skills/migrate-to-rslint/references/oxlint.md b/skills/migrate-to-rslint/references/oxlint.md new file mode 100644 index 0000000..755a647 --- /dev/null +++ b/skills/migrate-to-rslint/references/oxlint.md @@ -0,0 +1,163 @@ +# Oxlint -> Rslint migration guide + +Use this reference for `.oxlintrc.json`, `.oxlintrc.jsonc`, or `oxlint.config.*`. It translates Oxlint-specific configuration into Rslint entries, then returns to the shared entry-point, validation, and cleanup steps in [SKILL.md](../SKILL.md). + +## Official references + +- Oxlint [configuration](https://oxc.rs/docs/guide/usage/linter/config), [CLI](https://oxc.rs/docs/guide/usage/linter/cli.html), and [rules](https://oxc.rs/docs/guide/usage/linter/rules.html) +- Oxlint [JS plugins](https://oxc.rs/docs/guide/usage/linter/js-plugins.html) and [`createOnce` compatibility](https://oxc.rs/docs/guide/usage/linter/writing-js-plugins.html) +- Rslint [rules](https://rslint.rs/rules/), [file selectors](https://rslint.rs/config/files), [ignores](https://rslint.rs/config/ignoring-files), and [project settings](https://rslint.rs/config/language-options) + +## Checklist + +Copy this checklist and check off items as you complete them: + +- [ ] Step 0: Resolve source configs, defaults, and command overrides +- [ ] Step 1: Normalize rule values without losing inherited options +- [ ] Step 2: Map rule identities and split combined JS/TS behavior +- [ ] Step 3: Preserve file scopes, ignores, and TypeScript projects +- [ ] Step 4: Adapt JS plugins while retaining their configuration +- [ ] Step 5: Translate source-specific flags and directives, then resume the shared workflow + +## Step 0: resolve the effective source configuration + +Read the leaf config and its shared presets, imports, object spreads, and `extends`. Use the installed Oxlint version and the same working directory and environment as the original command. + +Collect both the evaluated configuration and Oxlint's `--print-config` output for each distinct configuration in the migrated scope. The evaluated form retains inheritance, plugin objects, and options; the printed form reveals defaults, category expansion, and normalized native rule names. Reconcile them rather than treating either as a complete substitute for the other. + +For example, adapt these commands to the repository's package manager, config path, and original flags: + +```bash +pnpm exec oxlint --print-config --config oxlint.config.mts +pnpm exec oxlint --rules --format json +``` + +Include `--type-aware` when the source command enables it. Preserve the order of CLI category/rule overrides such as `-D correctness -A no-debugger`, and plugin switches. Check the installed CLI's supported export options before using these examples. + +| Source input | Information to retain | +| ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | +| `plugins`, `categories`, defaults, CLI overrides | Effective native rules, including rules absent from the authored `rules` object | +| `rules` | Severity, full options, and explicit `off` entries | +| `extends`, `overrides` | Inheritance order, `files`, `excludeFiles`, and local changes | +| `jsPlugins` | Module or object, configured alias, wrapper, and JS rule configuration | +| `ignorePatterns`, ignore files, `env`, `globals`, `settings` | Path origins, environment globals, plugin settings, and precedence | +| Runtime options and environment variables | Type-aware mode, project context, warning policy, directive compatibility, and conditional plugin behavior | + +Inspect files without a leaf config separately: root fallback or default rules can differ from workspace presets. `--quiet` hiding warnings does not mean warning-level rules are disabled. Do not use diagnostic output alone as a rule inventory. + +Keep native and JS plugin data separately identifiable. Native-only exports or comparison configs that remove `jsPlugins` are incomplete migration inputs. + +## Step 1: normalize rule values and inheritance + +Normalize severity aliases: + +| Oxlint value | Rslint value | +| -------------------- | ------------ | +| `allow`, `off`, `0` | `off` | +| `warn`, `1` | `warn` | +| `deny`, `error`, `2` | `error` | + +Inspect the export schema before converting options. Oxlint 1.79.0 printed some values as `[level, [option1, option2]]`; those need `[level, option1, option2]` in ESLint-style config. Unwrap only that schema layer. An option that is itself an array must remain an array; do not flatten authored rule values indiscriminately. + +Resolve severity-only overrides using the source version's merge semantics. For example, when a parent sets `['warn', { max: 3 }]` for `max-params` and a child changes only the severity to `error`, preserve the effective `{ max: 3 }` option. The historical print output omitted some inherited options, so consult the evaluated inheritance tree when necessary. + +Track the latest explicit options and later severity changes for each rule through `extends` and each override. Preserve ordered entries instead of using a shallow object spread to approximate rule merging. Retain options such as selectors/messages in `no-restricted-syntax`, nested objects, and explicit disabled rules. + +## Step 2: map rule identities + +Resolve aliases with the installed Oxlint registry and Rslint rule catalog. Treat these as candidate mappings, then check the actual rule and options: + +| Oxlint rule | Rslint candidate | +| ----------------------- | --------------------------------------------------- | +| `eslint/` | `` | +| `typescript/` | `@typescript-eslint/` | +| `react/rules-of-hooks` | `react-hooks/rules-of-hooks` | +| `react/exhaustive-deps` | `react-hooks/exhaustive-deps` | +| Custom JS namespace | The same configured alias and plugin implementation | + +Some aliases resolve to core rules despite their source prefix. Do not replace namespaces without checking ownership. Declare the target native plugin namespaces needed by the mapped rules; a rule key alone does not replace plugin registration. Do not add recommended presets as a shortcut for Oxlint categories, because their rule sets differ. + +### Split combined JS and TypeScript rules + +Oxlint can use one rule ID for both JS and TS behavior that Rslint exposes as a core rule and a TypeScript extension. Historical examples include `max-params`, `no-array-constructor`, `no-dupe-class-members`, `no-empty-function`, `no-restricted-imports`, `no-unused-expressions`, `no-unused-vars`, and `no-useless-constructor`. Check each against the versions being migrated; this is not an exhaustive or unconditional replacement list. + +For each confirmed pair, keep the core rule in its original entry and insert a TS entry immediately after it. In the TS entry, disable the core rule and enable its extension with the same effective severity and options. Preserve `basePath` and local ignores, and keep later source overrides later in the array. Use the normalized file patterns described in Step 3 before forming TS intersections. + +For an original `files: ['src/**/*', 'tests/**/*']`, the TS entry intersects each branch with the TS extensions: + +```js +{ + files: [ + ['src/**/*', '**/*.{ts,tsx,mts,cts}'], + ['tests/**/*', '**/*.{ts,tsx,mts,cts}'], + ], + plugins: ['@typescript-eslint'], + rules: { + 'max-params': 'off', + '@typescript-eslint/max-params': ['error', { max: 3 }], + }, +} +``` + +With no original `files`, use only the TS selector. Append it to an existing AND group rather than nesting another group. Two top-level strings mean OR and would broaden the scope. Apply this mapping to later severity/off overrides too, so they do not leave an earlier TS extension enabled. + +Do not split by name alone: core `no-unused-private-class-members` concerns `#private`, while a TypeScript extension may also cover `private` keyword members. More configured IDs after a split do not necessarily mean more active rules per file. + +### Handle proprietary rules and conditional substitutes + +Use the main skill's unsupported-rule handling. Check current native support and compatible JS implementations before declaring a gap. For a proposed substitute, compare detection scope, required type information, options, and fixes/suggestions. Similar names are insufficient: + +- `oxc/missing-throw` is not equivalent to `no-new` or `unicorn/throw-new-error`. +- `oxc/only-used-in-recursion` and `unicorn/no-useless-recursion` inspect different behavior. +- A `TSEnumDeclaration[const=true]` selector for `oxc/no-const-enum` depends on target selector support and does not reproduce its fix by itself. +- A type-aware substitute for `unicorn/prefer-string-starts-ends-with` can change coverage when type information is unavailable. + +Keep unresolved mappings visible. A rule intersection prepared for benchmarking is not the production migration policy; do not copy its blanket rule disables or JS plugin removal. + +## Step 3: preserve scopes, ignores, and projects + +Translate `overrides` to ordered flat entries. Map `excludeFiles` to that entry's local `ignores`; it must not become a global exclusion. Translate `ignorePatterns` into global ignores for the original owning scope. Map environment globals and explicit globals into `languageOptions.globals`, retaining precedence and file scope; keep `settings` with the rules that consume them. + +Normalize override globs before copying them into flat config. Oxlint's [glob normalization](https://github.com/oxc-project/oxc/blob/main/crates/oxc_config/src/glob_set.rs) makes patterns without `/` recursive unless they start with `./`; Rslint's flat selectors do not add that recursion. Use already-normalized patterns from printed config when available. When converting authored patterns, preserve these distinctions for both `files` and `excludeFiles`: + +| Authored Oxlint override pattern | Rslint pattern | Matching scope | +| ---------------------------------- | -------------------------------------- | ----------------------------------------------------- | +| `*.test.ts` | `**/*.test.ts` | Root and nested test files | +| `*.generated.ts` in `excludeFiles` | `**/*.generated.ts` in local `ignores` | Root and nested generated files | +| `./*.test.ts` | `*.test.ts` | Test files directly under the config's base directory | + +Retain each pattern's original base directory and check root and nested file examples against the source version. Do not recursively normalize an already-normalized printed `*.test.ts`: it may have originated from the anchored `./*.test.ts` form. + +Rslint reads `.gitignore`, but its collection roots depend on config discovery and invocation. Compare the source's ancestor ignore behavior with the target's actual config boundaries before removing or copying patterns. When an ancestor ignore is not inherited, preserve it in a global ignore entry with `basePath` bound to the original directory. Keep negations, order, root anchoring, basename patterns, and trailing-directory semantics; a raw concatenation of patterns from different directories changes their meaning. + +For repeated monorepo configs, a shared profile plus a leaf config can reduce duplication. Bind relative file/ignore/project paths to the leaf's location, for example from its `import.meta.url`, rather than to the shared helper directory. Keep ancestor-ignore entries bound to their own directories. Use direct flat config for a simple project; profile JSON and a generator are not required. + +When the source enables type-aware linting, preserve project selection with `languageOptions.parserOptions.project` or `projectService: true` as appropriate. Do not enable both modes together. Account for nonstandard project names used by package commands, such as `tsconfig.lint.json`. Check what a source `--tsconfig` flag actually controls in that Oxlint version: import resolution and type-aware linting may select projects differently. + +Type-aware rules require a selected project that includes the linted file. `--type-check` adds compiler diagnostics and must not be introduced merely because the source used `--type-aware`. + +## Step 4: adapt JS plugins + +Oxlint `plugins` declares native groups; `jsPlugins` loads JS implementations. Preserve the module, configured namespace, rule values, settings, overrides, and environment wrappers for each JS plugin. Resolve imports relative to their original config or package before relocating them. + +Choose adaptation by the plugin's actual API: + +1. An ESLint-compatible `create(context)` plugin can follow [ESLint-compatible JS plugins](eslint-plugins.md) directly. +2. For a `createOnce(context)` plugin, check whether its export already provides compatible `create` methods. Otherwise use the installed `@oxlint/plugins` package's official `eslintCompatPlugin` adapter before registering it with Rslint. Reuse the implementation; do not rename `createOnce` to `create`, because lifecycle behavior differs. +3. Retain plugin and adapter dependencies after removing the Oxlint CLI. Keep environment-controlled wrappers and separate hook invocations intact; an import that becomes a no-op in one environment is not evidence that the plugin is unused. + +One migration with Oxlint 1.79.0 and Rslint 0.9.4 required a context prototype view around the adapted `create`. Treat this only as a troubleshooting lead: reproduce the context-layout failure on the installed versions first. If still needed, clone the plugin and affected rule, capture its original `create`, and delegate with `originalCreate.call(this, Object.create(context))`. Do not mutate the imported plugin or change detection logic, and do not install this historical workaround by default. + +Continue with the shared JS plugin reference to check target APIs and rule execution. + +## Step 5: translate flags and directives + +Carry the resolved rules, plugins, scopes, and settings into the main workflow's entry-point update. Fold Oxlint category and native-plugin flags into the translated configuration. Preserve `--quiet` and warning thresholds; `--deny-warnings` maps to `--max-warnings 0`. Check other flags against the installed Rslint CLI, especially fix modes and output formats, rather than copying them verbatim. + +Check the source's [directive compatibility option](https://oxc.rs/docs/guide/usage/linter/config-file-reference#options-respecteslintdisabledirectives) before preserving comments. With `options.respectEslintDisableDirectives: false`, existing `eslint-*` directives are inactive in Oxlint but would become active in Rslint. Preserve that inactivity: use an equivalent target setting if supported, otherwise make those comments non-directive in fully migrated files. If a retained ESLint check still consumes them, record the compatibility gap rather than breaking its suppressions. + +Inspect both `oxlint-*` and active `eslint-*` comments. Rslint documents `eslint-` and `rslint-` prefixes; translate unsupported `oxlint-disable`, `oxlint-enable`, `oxlint-disable-line`, and `oxlint-disable-next-line` forms to a supported prefix. Map rule aliases using Step 2, including in active `eslint-*` comments. For a split rule, use the rule active for that file's syntax. Preserve descriptions, line/block scope, and disable/enable pairs. Do not turn an unmapped rule-specific suppression into a blanket disable. + +Refer to the official [Oxlint comments](https://oxc.rs/docs/guide/usage/linter/ignore-comments.html) and [Rslint directives](https://rslint.rs/guide/inline-directives) docs for supported syntax. Limit edits to directive comments; keep strings, snapshots, and documentation unchanged unless they are part of the requested migration. + +Resume validation and cleanup in [SKILL.md](../SKILL.md) with the effective source inventory, translated config, required JS dependencies, and explicit unresolved mappings.