Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 210 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"categories": {
"correctness": "off"
},
"plugins": ["eslint", "typescript", "import", "unicorn", "react"],
"env": {
"browser": true,
"builtin": true,
"es2020": true
},
"ignorePatterns": [
"**/.nx/**",
"**/.svelte-kit/**",
"**/build/**",
"**/coverage/**",
"**/dist/**",
"**/snap/**",
"**/vite.config.*.timestamp-*.*",
"packages/{react-router,solid-router,vue-router,vue-start}/bin/**"
],
"options": {
"typeAware": true,
"respectEslintDisableDirectives": true
},
"rules": {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/sh
set -eu

printf '%s\n' '--- .oxlintrc.json ---'
cat -n .oxlintrc.json | sed -n '1,150p'

printf '%s\n' '--- repository references to curly and Oxlint configuration ---'
rg -n --hidden -g '!node_modules' -g '!dist' -g '!build' \
  '"curly"|curly|oxlint|oxlintrc' . | sed -n '1,240p'

printf '%s\n' '--- local Oxlint metadata, if present ---'
find . -maxdepth 3 \( -iname '*oxlint*' -o -name 'package.json' \) -type f -print | sed -n '1,120p'

Repository: TanStack/router

Length of output: 21764


🌐 Web query:

Oxlint curly rule support configuration schema

💡 Result:

In Oxlint, the curly rule is configured using an array format that accepts up to two elements, mirroring the traditional ESLint configuration style [1][2]. It does not support a single configuration object with named properties [3]. The configuration schema for the curly rule is as follows: 1. The first element (required) is the enforcement type, which must be one of: "all", "multi", "multi-line", or "multi-or-nest" [1][2]. 2. The second element (optional) accepts the string "consistent", which enforces consistent brace usage within if-else chains [1][2]. Example configurations in your.oxlintrc.json or oxlint.config.ts file: // Require braces for multi-statement blocks "rules": { "curly": ["error", "multi"] } // Require braces for multi-line blocks, with consistent usage in if-else chains "rules": { "curly": ["error", "multi-line", "consistent"] } Oxlint maintains its own rule implementations in Rust [4][5], and the curly rule's behavior and accepted configuration options are defined by the underlying native implementation, not by passing a configuration object [2][3]. If you encounter documentation or suggestions indicating that a configuration object (e.g., { "curlyType": "..." }) is supported, please note that this is incorrect and such configurations will not function as expected [3].

Citations:


🏁 Script executed:

#!/bin/sh
set -eu

repo='oxc-project/oxc'
tag='oxlint_v1.78.0'

printf '%s\n' '--- exact-version curly rule source ---'
curl -fsSL "https://raw.githubusercontent.com/${repo}/${tag}/crates/oxc_linter/src/rules/eslint/curly.rs" \
  | sed -n '1,240p'

printf '%s\n' '--- exact-version rule registration references ---'
curl -fsSL "https://api.github.com/repos/${repo}/git/trees/${tag}?recursive=1" \
  | jq -r '.tree[]?.path' \
  | rg 'curly|configuration_schema' \
  | sed -n '1,120p'

printf '%s\n' '--- exact-version commit resolution ---'
curl -fsSL "https://api.github.com/repos/${repo}/git/ref/tags/${tag}" \
  | jq '{ref, object}'

Repository: TanStack/router

Length of output: 7918


🌐 Web query:

site:github.com/oxc-project/oxc "oxlint_v1.78.0" "curly"

💡 Result:

In oxlint, the curly rule corresponds to the standard ESLint rule of the same name, which enforces consistent use of curly braces for control statements [1][2]. As of oxlint v1.78.0, the rule configuration follows the ESLint-style format, using strings as arguments rather than an object-based configuration [3][4][5]. The rule supports the following configuration options: "all" (default): Requires curly braces for all control statements [1]. "multi": Requires curly braces only when the control statement block contains multiple lines [1]. "multi-line": Requires curly braces if the statement is multiline or if the body spans multiple lines [1]. "multi-or-nest": Requires curly braces for control statements that are multiline or nested [1]. Additionally, the "consistent" option can be added as a separate string argument to ensure consistency across statements (e.g., ["error", "multi-or-nest", "consistent"]) [4][5]. While there was previous confusion in the documentation regarding whether "consistent" should be an object property or a string argument, the project has clarified that it is implemented as a string argument to match ESLint's behavior [3][6][4]. If you are working with JSX, oxlint also provides the react/jsx-curly-brace-presence rule, which manages the presence of curly braces for JSX props and children [7].

Citations:


Enable the required curly rule.

Oxlint 1.78.0 supports this rule. Add "curly": ["error", "all"] to enforce braces for all control statements.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.oxlintrc.json at line 26, Update the rules configuration in .oxlintrc.json
to enable the curly rule with error severity and the all option, enforcing
braces for every control statement.

Source: Coding guidelines

"for-direction": "error",
"no-async-promise-executor": "error",
"no-case-declarations": "error",
"no-class-assign": "error",
"no-compare-neg-zero": "error",
"no-cond-assign": "error",
"no-constant-binary-expression": "error",
"no-constant-condition": "error",
"no-control-regex": "error",
"no-debugger": "error",
"no-delete-var": "error",
"no-dupe-else-if": "error",
"no-duplicate-case": "error",
"no-empty-character-class": "error",
"no-empty-pattern": "error",
"no-empty-static-block": "error",
"no-ex-assign": "error",
"no-extra-boolean-cast": "error",
"no-fallthrough": "error",
"no-global-assign": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-loss-of-precision": "error",
"no-misleading-character-class": "error",
"no-nonoctal-decimal-escape": "error",
"no-regex-spaces": "error",
"no-self-assign": "error",
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-unsafe-finally": "error",
"no-unsafe-optional-chaining": "error",
"no-unused-labels": "error",
"no-unused-private-class-members": "error",
"no-unused-vars": [
"warn",
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_",
"caughtErrors": "all",
"caughtErrorsIgnorePattern": "^_",
"reportVarsOnlyUsedAsTypes": true,
"fix": {
"imports": "safe-fix",
"variables": "off"
}
}
],
"no-useless-backreference": "error",
"no-useless-catch": "error",
"no-useless-escape": "error",
"no-var": "error",
"no-with": "error",
"prefer-const": "error",
"require-yield": "error",
"sort-imports": ["error", { "ignoreDeclarationSort": true }],
"use-isnan": "error",
"valid-typeof": "error",
"import/consistent-type-specifier-style": ["error", "prefer-top-level"],
"import/first": "error",
"import/newline-after-import": "error",
"import/no-commonjs": "error",
"import/no-duplicates": "error",
"typescript/array-type": [
"error",
{ "default": "generic", "readonly": "generic" }
],
"typescript/ban-ts-comment": [
"error",
{ "ts-expect-error": false, "ts-ignore": "allow-with-description" }
],
"typescript/consistent-type-imports": [
"error",
{ "prefer": "type-imports" }
],
"typescript/method-signature-style": ["error", "property"],
"typescript/no-duplicate-enum-values": "error",
"typescript/no-extra-non-null-assertion": "error",
"typescript/no-for-in-array": "error",
"typescript/no-inferrable-types": ["error", { "ignoreParameters": true }],
"typescript/no-misused-new": "error",
"typescript/no-namespace": "error",
"typescript/no-non-null-asserted-optional-chain": "error",
"typescript/no-unnecessary-condition": "error",
"typescript/no-unnecessary-type-assertion": "error",
"typescript/no-wrapper-object-types": "error",
"typescript/prefer-as-const": "error",
"typescript/prefer-for-of": "warn",
"typescript/require-await": "warn",
"typescript/triple-slash-reference": "error",
"unicorn/prefer-node-protocol": "error"
},
"overrides": [
{
"files": [
"packages/{react-router-devtools,react-router-ssr-query,react-start,react-start-client,react-start-rsc,react-start-server,router-devtools,solid-start}/**/*.{ts,tsx}"
],
"rules": {
"react/forward-ref-uses-ref": "warn",
"react/jsx-key": "error",
"react/jsx-no-comment-textnodes": "warn",
"react/jsx-no-duplicate-props": "warn",
"react/no-array-index-key": "warn",
"react/no-clone-element": "warn",
"react/no-danger": "warn",
"react/no-danger-with-children": "error",
"react/no-did-mount-set-state": "warn",
"react/no-did-update-set-state": "warn",
"react/no-direct-mutation-state": "error",
"react/no-find-dom-node": "error",
"react/no-namespace": "error",
"react/no-redundant-should-component-update": "error",
"react/no-render-return-value": "error",
"react/no-string-refs": "error",
"react/no-unstable-nested-components": "error",
"react/no-will-update-set-state": "warn",
"react/void-dom-elements-no-children": "warn",
"react/iframe-missing-sandbox": "warn",
"react/jsx-no-script-url": "warn",
"react/jsx-no-target-blank": "warn"
}
},
{
"files": [
"packages/{react-router,react-router-devtools,react-router-ssr-query,react-start,react-start-client,react-start-rsc,react-start-server,router-devtools,solid-start}/**/*.{js,ts,tsx}"
],
"rules": {
"react/exhaustive-deps": "error",
"react/rules-of-hooks": "error"
}
},
{
"files": [
"packages/react-router/src/fileRoute.ts",
"packages/react-router/src/route.tsx"
],
"rules": {
"react/rules-of-hooks": "off",
"typescript/no-unnecessary-type-assertion": "off"
}
},
{
"files": [
"packages/{eslint-plugin-start,react-router,react-start-rsc,router-core,router-plugin,router-utils,solid-router,solid-start-client,start-plugin-core,vue-router,vue-router-devtools}/**/*"
],
"rules": {
"typescript/no-unnecessary-type-assertion": "off"
}
},
{
"files": ["packages/router-utils/src/ast.ts"],
"rules": {
"import/no-duplicates": "off"
}
},
{
"files": [
"packages/{react-router-devtools,react-router-ssr-query,react-start,react-start-client,react-start-rsc,react-start-server,router-devtools,router-devtools-core,solid-router-devtools,solid-start,solid-start-client,solid-start-server,start-client-core,start-server-core,start-static-server-functions,start-storage-context,vue-router-devtools}/**/__tests__/**",
"packages/{router-core,router-ssr-query-core,solid-router,vue-router,vue-router-ssr-query,vue-start,vue-start-client,vue-start-server}/{src,tests}/**/*.{ts,tsx}",
"packages/react-router/**/*"
],
"rules": {
"typescript/no-unnecessary-condition": "off"
}
},
{
"files": ["packages/react-start-rsc/src/**/*.{ts,tsx}"],
"rules": {
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "@tanstack/start-server-core",
"message": "Import from a dedicated @tanstack/start-server-core subpath to avoid pulling the full server barrel into the RSC module graph."
}
]
}
]
}
}
]
}
10 changes: 5 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ TanStack Router is a type-safe router with built-in caching and URL state manage
- Nx provides caching, affected testing, targeting, and parallel execution for efficiency
- Use `pnpm nx show projects` to list all available packages
- Target specific packages: `pnpm nx run @tanstack/react-router:test:unit`
- Target multiple packages: `pnpm nx run-many --target=test:eslint --projects=@tanstack/history,@tanstack/router-core`
- Target multiple packages: `pnpm nx run-many --target=test:lint --projects=@tanstack/history,@tanstack/router-core`
- Run affected tests only: `pnpm nx affected --target=test:unit`
- Exclude patterns: `pnpm nx run-many --target=test:unit --exclude="examples/**,e2e/**"`
- Navigate to examples and run `pnpm dev` to test changes: `cd examples/react/basic && pnpm dev`
Expand All @@ -39,7 +39,7 @@ TanStack Router is a type-safe router with built-in caching and URL state manage
- Name patterns: `pnpm nx run @tanstack/react-router:test:unit -- -t "navigation"` (all tests with "navigation" in name)
- Exclude patterns: `pnpm nx run @tanstack/react-router:test:unit -- --exclude="**/*link*" tests/`
- List tests: `pnpm nx run @tanstack/react-router:test:unit -- list tests/link.test.tsx` (or `-- list` for all)
- **Available test targets per package:** `test:unit`, `test:types`, `test:eslint`, `test:build`, `test:perf`, `build`
- **Available test targets per package:** `test:unit`, `test:types`, `test:lint`, `test:build`, `test:perf`, `build`
- **Testing strategy:** Package level (nx) → File-level args via nx → Test-level args (`-t`) via nx → Pattern-level args (`--exclude`) via nx
- **Agent execution guardrails (important):**
- Always prefer `pnpm nx ...` over `npx nx ...`.
Expand All @@ -52,7 +52,7 @@ TanStack Router is a type-safe router with built-in caching and URL state manage
## Testing instructions

- **Critical**: Always run unit and type tests during development - do not proceed if they fail
- **Test types:** `pnpm test:unit`, `pnpm test:types`, `pnpm test:eslint`, `pnpm test:e2e`, `pnpm test:build`
- **Test types:** `pnpm test:unit`, `pnpm test:types`, `pnpm test:lint`, `pnpm test:e2e`, `pnpm test:build`
- **Full CI suite:** `pnpm test:ci`
- **Fix formatting:** `pnpm format`
- **Efficient targeted testing workflow:**
Expand All @@ -69,7 +69,7 @@ TanStack Router is a type-safe router with built-in caching and URL state manage

## PR instructions

- Always run `pnpm test:eslint`, `pnpm test:types`, and `pnpm test:unit` before committing
- Always run `pnpm test:lint`, `pnpm test:types`, and `pnpm test:unit` before committing
- Test changes in relevant example apps: `cd examples/react/basic && pnpm dev`
- Update corresponding documentation in `docs/` directory when adding features
- Add or update tests for any code changes
Expand Down Expand Up @@ -168,7 +168,7 @@ TanStack Router is a type-safe router with built-in caching and URL state manage
2. **Build**: `pnpm build:all` or `pnpm dev` for watch mode
3. **Test**: Make changes and run relevant tests (use nx for targeted testing)
4. **Examples**: Navigate to examples and run `pnpm dev` to test changes
5. **Quality**: Run `pnpm test:eslint`, `pnpm test:types`, `pnpm test:unit` before committing
5. **Quality**: Run `pnpm test:lint`, `pnpm test:types`, `pnpm test:unit` before committing

## References

Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pnpm dev

Run the checks relevant to your changes while developing:

- `pnpm test:eslint` checks linting for affected packages.
- `pnpm test:lint` checks linting for affected packages with Oxlint.
- `pnpm test:types` checks types for affected packages.
- `pnpm test:unit` runs unit tests for affected packages.
- `pnpm test:build` checks builds for affected packages.
Expand All @@ -61,7 +61,7 @@ Run the checks relevant to your changes while developing:
Before opening a pull request, run at least:

```sh
pnpm test:eslint
pnpm test:lint
pnpm test:types
pnpm test:unit
```
Expand Down
5 changes: 0 additions & 5 deletions e2e/e2e-utils/eslint.config.js

This file was deleted.

2 changes: 1 addition & 1 deletion e2e/e2e-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"scripts": {
"clean": "rimraf ./dist && rimraf ./coverage",
"build": "vite build",
"test:eslint": "eslint ./src",
"test:lint": "oxlint ./src",
"test:unit": "exit 0; vitest --typecheck"
},
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion e2e/eslint-plugin-start/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"type": "module",
"scripts": {
"test:e2e": "vitest run",
"test:lint": "eslint src/",
"test:eslint": "eslint src/",
"perf:gen": "node scripts/generate-perf-fixtures.mjs",
"perf:gen:small": "PERF_MODE=small pnpm perf:gen",
"perf:gen:huge": "PERF_MODE=huge pnpm perf:gen",
Expand Down
35 changes: 0 additions & 35 deletions eslint.config.js

This file was deleted.

10 changes: 5 additions & 5 deletions nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"production": [
"default",
"!{projectRoot}/tests/**/*",
"!{projectRoot}/eslint.config.js"
"!{projectRoot}/.oxlintrc.json"
],
"buildProduction": ["sharedGlobals", "{projectRoot}/**/*"]
},
Expand All @@ -38,13 +38,13 @@
"cache": true,
"inputs": ["{workspaceRoot}/docs/**/*"]
},
"test:eslint": {
"test:lint": {
"cache": true,
"dependsOn": ["^build", "build"],
"inputs": [
"default",
"^production",
"{workspaceRoot}/eslint.config.js",
"{workspaceRoot}/.oxlintrc.json",
"dependentTaskOutputs"
]
},
Expand All @@ -54,7 +54,7 @@
"inputs": [
"default",
"^production",
"{workspaceRoot}/eslint.config.js",
"{workspaceRoot}/.oxlintrc.json",
"dependentTaskOutputs"
],
"outputs": ["{projectRoot}/coverage"]
Expand Down Expand Up @@ -90,7 +90,7 @@
"inputs": [
"default",
"^production",
"{workspaceRoot}/eslint.config.js",
"{workspaceRoot}/.oxlintrc.json",
"dependentTaskOutputs"
]
},
Expand Down
Loading
Loading