diff --git a/.vitepress/data/rules.json b/.vitepress/data/rules.json
index a9eda307591..53a365d0ea6 100644
--- a/.vitepress/data/rules.json
+++ b/.vitepress/data/rules.json
@@ -1228,7 +1228,7 @@
"value": "no-useless-computed-key",
"category": "style",
"type_aware": false,
- "fix": "pending",
+ "fix": "conditional_fix",
"default": false,
"docs_url": "https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-useless-computed-key.html"
},
@@ -4601,7 +4601,7 @@
{
"scope": "typescript",
"value": "prefer-find",
- "category": "nursery",
+ "category": "style",
"type_aware": true,
"fix": "none",
"default": false,
@@ -4682,7 +4682,7 @@
{
"scope": "typescript",
"value": "prefer-readonly",
- "category": "nursery",
+ "category": "style",
"type_aware": true,
"fix": "none",
"default": false,
@@ -4709,7 +4709,7 @@
{
"scope": "typescript",
"value": "prefer-regexp-exec",
- "category": "nursery",
+ "category": "style",
"type_aware": true,
"fix": "none",
"default": false,
@@ -4727,7 +4727,7 @@
{
"scope": "typescript",
"value": "prefer-string-starts-ends-with",
- "category": "nursery",
+ "category": "style",
"type_aware": true,
"fix": "none",
"default": true,
@@ -6056,6 +6056,15 @@
"default": false,
"docs_url": "https://oxc.rs/docs/guide/usage/linter/rules/vitest/no-importing-vitest-globals.html"
},
+ {
+ "scope": "vitest",
+ "value": "prefer-called-exactly-once-with",
+ "category": "style",
+ "type_aware": false,
+ "fix": "fixable_dangerous_fix",
+ "default": false,
+ "docs_url": "https://oxc.rs/docs/guide/usage/linter/rules/vitest/prefer-called-exactly-once-with.html"
+ },
{
"scope": "vitest",
"value": "prefer-called-once",
@@ -6137,6 +6146,15 @@
"default": false,
"docs_url": "https://oxc.rs/docs/guide/usage/linter/rules/vitest/prefer-to-be-truthy.html"
},
+ {
+ "scope": "vitest",
+ "value": "require-awaited-expect-poll",
+ "category": "correctness",
+ "type_aware": false,
+ "fix": "none",
+ "default": false,
+ "docs_url": "https://oxc.rs/docs/guide/usage/linter/rules/vitest/require-awaited-expect-poll.html"
+ },
{
"scope": "vitest",
"value": "require-local-test-context-for-concurrent-snapshots",
@@ -6146,6 +6164,24 @@
"default": false,
"docs_url": "https://oxc.rs/docs/guide/usage/linter/rules/vitest/require-local-test-context-for-concurrent-snapshots.html"
},
+ {
+ "scope": "vitest",
+ "value": "require-mock-type-parameters",
+ "category": "correctness",
+ "type_aware": false,
+ "fix": "none",
+ "default": false,
+ "docs_url": "https://oxc.rs/docs/guide/usage/linter/rules/vitest/require-mock-type-parameters.html"
+ },
+ {
+ "scope": "vitest",
+ "value": "require-test-timeout",
+ "category": "restriction",
+ "type_aware": false,
+ "fix": "none",
+ "default": false,
+ "docs_url": "https://oxc.rs/docs/guide/usage/linter/rules/vitest/require-test-timeout.html"
+ },
{
"scope": "vitest",
"value": "warn-todo",
diff --git a/src/docs/guide/usage/formatter/generated-config.md b/src/docs/guide/usage/formatter/generated-config.md
index 6d328e3d4ef..8addf08073b 100644
--- a/src/docs/guide/usage/formatter/generated-config.md
+++ b/src/docs/guide/usage/formatter/generated-config.md
@@ -81,7 +81,7 @@ Whether to insert a final newline at the end of the file.
## jsdoc
-type: `object`
+type: `object | boolean`
Enable JSDoc comment formatting.
@@ -89,7 +89,7 @@ When enabled, JSDoc comments are normalized and reformatted:
tag aliases are canonicalized, descriptions are capitalized,
long lines are wrapped, and short comments are collapsed to single-line.
-Pass an object (`jsdoc: {}`) to enable with defaults, or omit to disable.
+Pass `true` or an object to enable with defaults, or omit/set `false` to disable.
- Default: Disabled
@@ -302,7 +302,7 @@ Whether to insert a final newline at the end of the file.
##### overrides[n].options.jsdoc
-type: `object`
+type: `object | boolean`
Enable JSDoc comment formatting.
@@ -310,7 +310,7 @@ When enabled, JSDoc comments are normalized and reformatted:
tag aliases are canonicalized, descriptions are capitalized,
long lines are wrapped, and short comments are collapsed to single-line.
-Pass an object (`jsdoc: {}`) to enable with defaults, or omit to disable.
+Pass `true` or an object to enable with defaults, or omit/set `false` to disable.
- Default: Disabled
@@ -487,13 +487,15 @@ For JSX, you can set the `jsxSingleQuote` option.
##### overrides[n].options.sortImports
-type: `object`
+type: `object | boolean`
Sort import statements.
Using the similar algorithm as [eslint-plugin-perfectionist/sort-imports](https://perfectionist.dev/rules/sort-imports).
For details, see each field's documentation.
+Pass `true` or an object to enable with defaults, or omit/set `false` to disable.
+
- Default: Disabled
###### overrides[n].options.sortImports.customGroups
@@ -713,7 +715,7 @@ Sort the `scripts` field alphabetically.
##### overrides[n].options.sortTailwindcss
-type: `object`
+type: `object | boolean`
Sort Tailwind CSS classes.
@@ -721,6 +723,8 @@ Using the same algorithm as [prettier-plugin-tailwindcss](https://github.com/tai
Option names omit the `tailwind` prefix used in the original plugin (e.g., `config` instead of `tailwindConfig`).
For details, see each field's documentation.
+Pass `true` or an object to enable with defaults, or omit/set `false` to disable.
+
- Default: Disabled
###### overrides[n].options.sortTailwindcss.attributes
@@ -876,13 +880,15 @@ For JSX, you can set the `jsxSingleQuote` option.
## sortImports
-type: `object`
+type: `object | boolean`
Sort import statements.
Using the similar algorithm as [eslint-plugin-perfectionist/sort-imports](https://perfectionist.dev/rules/sort-imports).
For details, see each field's documentation.
+Pass `true` or an object to enable with defaults, or omit/set `false` to disable.
+
- Default: Disabled
### sortImports.customGroups
@@ -1102,7 +1108,7 @@ Sort the `scripts` field alphabetically.
## sortTailwindcss
-type: `object`
+type: `object | boolean`
Sort Tailwind CSS classes.
@@ -1110,6 +1116,8 @@ Using the same algorithm as [prettier-plugin-tailwindcss](https://github.com/tai
Option names omit the `tailwind` prefix used in the original plugin (e.g., `config` instead of `tailwindConfig`).
For details, see each field's documentation.
+Pass `true` or an object to enable with defaults, or omit/set `false` to disable.
+
- Default: Disabled
### sortTailwindcss.attributes
diff --git a/src/docs/guide/usage/linter/generated-config.md b/src/docs/guide/usage/linter/generated-config.md
index 00a5f842861..7e6422fdaf7 100644
--- a/src/docs/guide/usage/linter/generated-config.md
+++ b/src/docs/guide/usage/linter/generated-config.md
@@ -207,6 +207,25 @@ Basic usage with a local plugin path.
}
```
+Basic usage with a TypeScript plugin and a local plugin path.
+
+TypeScript plugin files are supported in the following environments:
+
+- Deno and Bun: TypeScript files are supported natively.
+- Node.js >=22.18.0 and Node.js ^20.19.0: TypeScript files are supported natively with built-in
+ type-stripping enabled by default.
+
+For older Node.js versions, TypeScript plugins are not supported. Please use JavaScript plugins or upgrade your Node version.
+
+```json
+{
+ "jsPlugins": ["./custom-plugin.ts"],
+ "rules": {
+ "custom/rule-name": "warn"
+ }
+}
+```
+
Using a built-in Rust plugin alongside a JS plugin with the same name
by giving the JS plugin an alias.
diff --git a/src/docs/guide/usage/linter/rules/eslint/no-unused-vars.md b/src/docs/guide/usage/linter/rules/eslint/no-unused-vars.md
index 466b061cb83..58060deeb00 100644
--- a/src/docs/guide/usage/linter/rules/eslint/no-unused-vars.md
+++ b/src/docs/guide/usage/linter/rules/eslint/no-unused-vars.md
@@ -299,7 +299,7 @@ Fine-grained auto-fix controls for `no-unused-vars`.
#### fix.imports
-type: `"off" | "suggestion" | "fix"`
+type: `"off" | "suggestion" | "fix" | "safe-fix"`
##### `"off"`
@@ -313,9 +313,14 @@ Emit suggestion-style fixes (current behavior).
Emit fix-style fixes.
+##### `"safe-fix"`
+
+Like `Fix`, but does not mark them as dangerous.
+Only applicable for imports, unavailable for variables.
+
#### fix.variables
-type: `"off" | "suggestion" | "fix"`
+type: `"off" | "suggestion" | "fix" | "safe-fix"`
##### `"off"`
@@ -329,6 +334,11 @@ Emit suggestion-style fixes (current behavior).
Emit fix-style fixes.
+##### `"safe-fix"`
+
+Like `Fix`, but does not mark them as dangerous.
+Only applicable for imports, unavailable for variables.
+
### ignoreClassWithStaticInitBlock
type: `boolean`
diff --git a/src/docs/guide/usage/linter/rules/eslint/no-useless-computed-key.md b/src/docs/guide/usage/linter/rules/eslint/no-useless-computed-key.md
index 418794c309f..1367b7d1284 100644
--- a/src/docs/guide/usage/linter/rules/eslint/no-useless-computed-key.md
+++ b/src/docs/guide/usage/linter/rules/eslint/no-useless-computed-key.md
@@ -3,7 +3,7 @@ title: "eslint/no-useless-computed-key"
category: "Style"
default: false
type_aware: false
-fix: "pending"
+fix: "conditional_fix"
---
diff --git a/src/docs/guide/usage/linter/rules/jest/prefer-to-have-been-called-times.md b/src/docs/guide/usage/linter/rules/jest/prefer-to-have-been-called-times.md
index f535b86f12e..6f2f5ad41ea 100644
--- a/src/docs/guide/usage/linter/rules/jest/prefer-to-have-been-called-times.md
+++ b/src/docs/guide/usage/linter/rules/jest/prefer-to-have-been-called-times.md
@@ -44,6 +44,17 @@ expect(uncalledFunction).not.toBeCalled();
expect(method.mock.calls[0][0]).toStrictEqual(value);
```
+This rule is compatible with [eslint-plugin-vitest](https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/prefer-to-have-been-called-times.md),
+to use it, add the following configuration to your `.oxlintrc.json`:
+
+```json
+{
+ "rules": {
+ "vitest/prefer-to-have-been-called-times": "error"
+ }
+}
+```
+
## How to use
diff --git a/src/docs/guide/usage/linter/rules/jsdoc/require-property.md b/src/docs/guide/usage/linter/rules/jsdoc/require-property.md
index 874400940d4..fa31faf5e4a 100644
--- a/src/docs/guide/usage/linter/rules/jsdoc/require-property.md
+++ b/src/docs/guide/usage/linter/rules/jsdoc/require-property.md
@@ -36,7 +36,7 @@ Examples of **incorrect** code for this rule:
*/
/**
- * @namespace {Object} SomeNamesoace
+ * @namespace {Object} SomeNamespace
*/
```
diff --git a/src/docs/guide/usage/linter/rules/typescript/prefer-find.md b/src/docs/guide/usage/linter/rules/typescript/prefer-find.md
index d75730f8bf2..861f4409c0f 100644
--- a/src/docs/guide/usage/linter/rules/typescript/prefer-find.md
+++ b/src/docs/guide/usage/linter/rules/typescript/prefer-find.md
@@ -1,6 +1,6 @@
---
title: "typescript/prefer-find"
-category: "Nursery"
+category: "Style"
default: false
type_aware: true
fix: "none"
diff --git a/src/docs/guide/usage/linter/rules/typescript/prefer-readonly.md b/src/docs/guide/usage/linter/rules/typescript/prefer-readonly.md
index e3fbe5d45de..96cd410402f 100644
--- a/src/docs/guide/usage/linter/rules/typescript/prefer-readonly.md
+++ b/src/docs/guide/usage/linter/rules/typescript/prefer-readonly.md
@@ -1,6 +1,6 @@
---
title: "typescript/prefer-readonly"
-category: "Nursery"
+category: "Style"
default: false
type_aware: true
fix: "none"
diff --git a/src/docs/guide/usage/linter/rules/typescript/prefer-regexp-exec.md b/src/docs/guide/usage/linter/rules/typescript/prefer-regexp-exec.md
index 87cf3cf4ac1..db664ccc02a 100644
--- a/src/docs/guide/usage/linter/rules/typescript/prefer-regexp-exec.md
+++ b/src/docs/guide/usage/linter/rules/typescript/prefer-regexp-exec.md
@@ -1,6 +1,6 @@
---
title: "typescript/prefer-regexp-exec"
-category: "Nursery"
+category: "Style"
default: false
type_aware: true
fix: "none"
diff --git a/src/docs/guide/usage/linter/rules/typescript/prefer-string-starts-ends-with.md b/src/docs/guide/usage/linter/rules/typescript/prefer-string-starts-ends-with.md
index 7120baa9e1a..e1587d93df2 100644
--- a/src/docs/guide/usage/linter/rules/typescript/prefer-string-starts-ends-with.md
+++ b/src/docs/guide/usage/linter/rules/typescript/prefer-string-starts-ends-with.md
@@ -1,6 +1,6 @@
---
title: "typescript/prefer-string-starts-ends-with"
-category: "Nursery"
+category: "Style"
default: true
type_aware: true
fix: "none"
diff --git a/src/docs/guide/usage/linter/rules/version.data.js b/src/docs/guide/usage/linter/rules/version.data.js
index 699d52d5ba2..7c6097f96d4 100644
--- a/src/docs/guide/usage/linter/rules/version.data.js
+++ b/src/docs/guide/usage/linter/rules/version.data.js
@@ -1,5 +1,5 @@
export default {
load() {
- return "180dd0f8f60c383dff3325334b595e67845824a1";
+ return "6620ad82e20eab334f1ec8710cb938e2a6e5cd4d";
},
};
diff --git a/src/docs/guide/usage/linter/rules/vitest/prefer-called-exactly-once-with.md b/src/docs/guide/usage/linter/rules/vitest/prefer-called-exactly-once-with.md
new file mode 100644
index 00000000000..f96d6ebbbcd
--- /dev/null
+++ b/src/docs/guide/usage/linter/rules/vitest/prefer-called-exactly-once-with.md
@@ -0,0 +1,56 @@
+---
+title: "vitest/prefer-called-exactly-once-with"
+category: "Style"
+default: false
+type_aware: false
+fix: "fixable_dangerous_fix"
+---
+
+
+
+
+
+
+
+### What it does
+
+It checks when a target is expected with `toHaveBeenCalledOnce` and `toHaveBeenCalledWith` instead of
+`toHaveBeenCalledExactlyOnceWith`.
+
+### Why is this bad?
+
+The user must deduct from both expects that the spy function is called once and with a specific arguments.
+
+### Examples
+
+Examples of **incorrect** code for this rule:
+
+```js
+test("foo", () => {
+ const mock = vi.fn();
+ mock("foo");
+ expect(mock).toHaveBeenCalledOnce();
+ expect(mock).toHaveBeenCalledWith("foo");
+});
+```
+
+Examples of **correct** code for this rule:
+
+```js
+test("foo", () => {
+ const mock = vi.fn();
+ mock("foo");
+ expect(mock).toHaveBeenCalledExactlyOnceWith("foo");
+});
+```
+
+## How to use
+
+
+
+## References
+
+
diff --git a/src/docs/guide/usage/linter/rules/vitest/prefer-import-in-mock.md b/src/docs/guide/usage/linter/rules/vitest/prefer-import-in-mock.md
index 862c29876bf..bb15fd40c13 100644
--- a/src/docs/guide/usage/linter/rules/vitest/prefer-import-in-mock.md
+++ b/src/docs/guide/usage/linter/rules/vitest/prefer-import-in-mock.md
@@ -17,7 +17,7 @@ const source = `https://github.com/oxc-project/oxc/blob/${ data }/crates/oxc_lin
### What it does
-This rule enforces using a dynamic `import()` in `vi.mock()`, which improves type information and IntelliSense for the mocked module.
+This rule enforces using a dynamic `import()` in `vi.mock()` or `vi.doMock()`, which improves type information and IntelliSense for the mocked module.
### Why is this bad?
@@ -29,12 +29,14 @@ Examples of **incorrect** code for this rule:
```js
vi.mock("./path/to/module");
+vi.doMock("./path/to/module");
```
Examples of **correct** code for this rule:
```js
vi.mock(import("./path/to/module"));
+vi.doMock(import("./path/to/module"));
```
## Configuration
diff --git a/src/docs/guide/usage/linter/rules/vitest/require-awaited-expect-poll.md b/src/docs/guide/usage/linter/rules/vitest/require-awaited-expect-poll.md
new file mode 100644
index 00000000000..c377ae9508a
--- /dev/null
+++ b/src/docs/guide/usage/linter/rules/vitest/require-awaited-expect-poll.md
@@ -0,0 +1,61 @@
+---
+title: "vitest/require-awaited-expect-poll"
+category: "Correctness"
+default: false
+type_aware: false
+fix: "none"
+---
+
+
+
+
+
+
+
+### What it does
+
+This rule ensures that promises returned by `expect.poll` and `expect.element` calls are handled properly.
+
+### Why is this bad?
+
+`expect.poll` and `expect.element` return promises. If not awaited or returned,
+the test completes before the assertion resolves, meaning the test will pass
+regardless of whether the assertion succeeds or fails.
+
+### Examples
+
+Examples of **incorrect** code for this rule:
+
+```js
+test("element exists", () => {
+ asyncInjectElement();
+
+ expect.poll(() => document.querySelector(".element")).toBeInTheDocument();
+});
+```
+
+Examples of **correct** code for this rule:
+
+```js
+test("element exists", () => {
+ asyncInjectElement();
+
+ return expect.poll(() => document.querySelector(".element")).toBeInTheDocument();
+});
+test("element exists", async () => {
+ asyncInjectElement();
+
+ await expect.poll(() => document.querySelector(".element")).toBeInTheDocument();
+});
+```
+
+## How to use
+
+
+
+## References
+
+
diff --git a/src/docs/guide/usage/linter/rules/vitest/require-mock-type-parameters.md b/src/docs/guide/usage/linter/rules/vitest/require-mock-type-parameters.md
new file mode 100644
index 00000000000..8827d9ce963
--- /dev/null
+++ b/src/docs/guide/usage/linter/rules/vitest/require-mock-type-parameters.md
@@ -0,0 +1,99 @@
+---
+title: "vitest/require-mock-type-parameters"
+category: "Correctness"
+default: false
+type_aware: false
+fix: "none"
+---
+
+
+
+
+
+
+
+### What it does
+
+Enforces the use of type parameters on vi.fn(), and optionally on vi.importActual() and vi.importMock().
+
+By default, only vi.fn() is checked. Set checkImportFunctions to true to also check vi.importActual() and vi.importMock().
+
+### Why is this bad?
+
+Without explicit type parameters, vi.fn() creates a mock typed as (...args: any[]) => any.
+This disables type checking between the mock and the real implementation, which can lead to two problems:
+
+- tests that fail due to incorrect mock usage when they should pass, or worse, tests that pass while the mock silently diverges from the actual runtime behavior.
+
+### Examples
+
+Examples of **incorrect** code for this rule configured as `{ "checkImportFunctions": false }`:
+
+```js
+import { vi } from "vitest";
+
+test("foo", () => {
+ const myMockedFn = vi.fn();
+});
+```
+
+Examples of **incorrect** code for this rule configured as `{ "checkImportFunctions": true }`:
+
+```js
+import { vi } from "vitest";
+
+vi.mock("./example.js", async () => {
+ const originalModule = await vi.importActual("./example.js");
+
+ return { ...originalModule };
+});
+const fs = await vi.importMock("fs");
+```
+
+Examples of **correct** code for this rule configured as `{ "checkImportFunctions": false }`:
+
+```js
+import { vi } from 'vitest'
+
+ test('foo', () => {
+ const myMockedFnOne = vi.fn<(arg1: string, arg2: boolean) => number>()
+ const myMockedFnTwo = vi.fn<() => void>()
+ const myMockedFnThree = vi.fn()
+ })
+```
+
+Examples of **correct** code for this rule configured as `{ "checkImportFunctions": true }`:
+
+```js
+import { vi } from "vitest";
+
+vi.mock("./example.js", async () => {
+ const originalModule = (await vi.importActual) < any > "./example.js";
+
+ return { ...originalModule };
+});
+const fs = (await vi.importMock) < any > "fs";
+```
+
+## Configuration
+
+This rule accepts a configuration object with the following properties:
+
+### checkImportFunctions
+
+type: `boolean`
+
+default: `false`
+
+Also require type parameters for `importActual` and `importMock`.
+
+## How to use
+
+
+
+## References
+
+
diff --git a/src/docs/guide/usage/linter/rules/vitest/require-test-timeout.md b/src/docs/guide/usage/linter/rules/vitest/require-test-timeout.md
new file mode 100644
index 00000000000..35e256a597c
--- /dev/null
+++ b/src/docs/guide/usage/linter/rules/vitest/require-test-timeout.md
@@ -0,0 +1,66 @@
+---
+title: "vitest/require-test-timeout"
+category: "Restriction"
+default: false
+type_aware: false
+fix: "none"
+---
+
+
+
+
+
+
+
+### What it does
+
+Requires every test to have a timeout specified, either as a numeric third
+argument, a `{ timeout }` option, or via `vi.setConfig({ testTimeout: ... })`.
+
+### Why is this bad?
+
+Tests without an explicit timeout rely on the default, which may be too
+generous to catch performance regressions or too short for slow CI
+environments, leading to flaky failures.
+
+### Examples
+
+Examples of **incorrect** code for this rule:
+
+```js
+it("slow test", async () => {
+ await doSomethingSlow();
+});
+```
+
+Examples of **correct** code for this rule:
+
+```js
+// good (numeric timeout)
+test("slow test", async () => {
+ await doSomethingSlow();
+}, 1000);
+
+// good (options object)
+test("slow test", { timeout: 1000 }, async () => {
+ await doSomethingSlow();
+});
+
+// good (file-level)
+vi.setConfig({ testTimeout: 1000 });
+
+test("slow test", async () => {
+ await doSomethingSlow();
+});
+```
+
+## How to use
+
+
+
+## References
+
+
diff --git a/src/docs/guide/usage/rule-count.data.js b/src/docs/guide/usage/rule-count.data.js
index 01973fa55ac..d9d62a63082 100644
--- a/src/docs/guide/usage/rule-count.data.js
+++ b/src/docs/guide/usage/rule-count.data.js
@@ -1,5 +1,5 @@
export default {
load() {
- return 701;
+ return 705;
},
};