Skip to content

refactor: simplify oxlint config toward defaults - #2729

Open
joyenjoyer wants to merge 1 commit into
masterfrom
INSTUI-5159-simplify-oxlint-config
Open

joyenjoyer wants to merge 1 commit into
masterfrom
INSTUI-5159-simplify-oxlint-config

Conversation

@joyenjoyer

@joyenjoyer joyenjoyer commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Goal

Get .oxlintrc.json as close to stock oxlint as possible for a React/TypeScript codebase, keeping only what InstUI genuinely adds on top: the a11y set, the monorepo and licensing plugins, the import boundaries, and our TypeScript strictness choices. Everything oxlint already does by default comes out.

Summary

  • Restore oxc and unicorn in plugins. That array replaces oxlint's defaults instead of extending them
  • Remove the categories block and 77 rule lines that duplicate oxlint defaults, 17 of them carrying options objects that only wrote the defaults out longhand.
  • Remove four rules as redundant or obsolete: no-array-constructor, the @typescript-eslint/no-unused-vars alias, and the react-js rules prop-types and require-default-props, which both steer toward deprecated APIs.
  • Silence vitest/require-mock-type-parameters, which the re-enabled category surfaced as 663 stylistic warnings.

Test Plan

  • pnpm run lint exits 1 both before and after this PR, from 12 pre-existing errors: no-undef in two ui-icons .cjs config files, notice/notice in five files whose licence header follows a shebang, and no-redeclare in safeCloneElement.ts. Confirm that list is unchanged rather than that it passes.

Fixes INSTUI-5159

🤖 Generated with Claude Code

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@joyenjoyer joyenjoyer self-assigned this Sep 24, 2026
Comment thread .oxlintrc.json
@@ -1,15 +1,6 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["eslint", "typescript", "react"],

@joyenjoyer joyenjoyer Sep 24, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

plugins replaces oxlint's defaults rather than extending them. Stock oxlint runs ["unicorn", "typescript", "oxc"]

Comment thread .oxlintrc.json
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["eslint", "typescript", "react"],
"categories": {

@joyenjoyer joyenjoyer Sep 24, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Lines 4-12, the categories block.

All seven categories were set "off". Only correctness is on in stock oxlint anyway, at warn, so six of these lines had no effect at all. The seventh is what forced the 129-rule manual list below.

Comment thread .oxlintrc.json
"./scripts/oxlint/notice-plugin.mjs"
],
"rules": {
"constructor-super": "error",

@joyenjoyer joyenjoyer Sep 24, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Applies to this whole block, roughly lines 49-197.

Every rule here is one oxlint already enables in the correctness category. With the categories block gone they all stay on, at the default warn instead of the error written here.

That severity drop is not observable, because none of these rules reports a single violation anywhere in the repo. The error count is 12 before and after this PR, identical file for file, and all of it comes from no-undef (5, in two ui-icons .cjs config files), notice/notice (5, files whose licence header follows a shebang), and no-redeclare (2, in safeCloneElement.ts). All 12 are pre-existing on master. None is in this block.

17 of these lines also carried an options object that only repeated oxlint's own defaults longhand. Each was tested by running the rule with its options and then bare; the counts matched every time.

Proof that nothing was lost: I generated 94 fixture files, one minimal violation per rule, and ran the old and new configs over the identical set. Old caught 75, new caught 97, and nothing detected by old is missed by new.

Comment thread .oxlintrc.json
],
"no-unused-labels": "error",
"no-unused-private-class-members": "error",
"no-unused-vars": [

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The one rule in that block whose options were not a harmless repeat. args: "none" is far weaker than oxlint's default, and it was being overridden anyway by the @typescript-eslint alias on line 244, which sits later in the file and wins.

Measured on packages/:

Config Hits
{args: "none", ignoreRestSiblings: true} 17
{args: "after-used", ignoreRestSiblings: true} 79
{args: "after-used"} 373
bare (oxlint default) 309

Bare matches exactly what the alias was already enforcing, so deleting the line outright preserves behavior. Keeping the old options would have quietly dropped enforcement to 17.

Comment thread .oxlintrc.json
"ts-ignore": "allow-with-description"
}
],
"@typescript-eslint/no-array-constructor": "error",

@joyenjoyer joyenjoyer Sep 24, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I removed it as redundant with unicorn/no-new-array, which this PR turns on, but that's only partly true:

new Array(1,2,3) Array(1,2,3) new Array(5)
no-array-constructor yes yes yes
unicorn/no-new-array no no yes

no-new-array only covers the single-argument form, so multi-argument use is now unchecked. Zero hits in the repo today, so nothing regressed, but this is a genuine narrowing.

Comment thread .oxlintrc.json
"@typescript-eslint/no-unnecessary-type-constraint": "error",
"@typescript-eslint/no-unsafe-declaration-merging": "error",
"@typescript-eslint/no-unsafe-function-type": "error",
"no-unused-expressions": [

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This line, plus the alias at 236 and the one at 244.

no-unused-expressions is written twice under two names. oxlint treats @typescript-eslint/no-unused-expressions as an alias and reports both as eslint(no-unused-expressions).

They were configured with opposite options: the core block here allowed short-circuits, ternaries, and tagged templates, while the TS block at 236 forbade all three. oxlint resolves duplicates last-key-wins, so the strict one governed and this permissive block was dead config. Verified: 3 violations on a test file in this order, 0 when reversed.

Strict is also oxlint's default, so both lines go and the count stays at 68. Those 68 are all the a && a.method() null-guard idiom, which ?. replaces. It's a modernization backlog that is now visible.

Line 244 is the same alias trap for no-unused-vars. See the note on line 168.

Comment thread .oxlintrc.json
"@typescript-eslint/prefer-namespace-keyword": "error",
"@typescript-eslint/triple-slash-reference": "error",
"react/display-name": "error",
"react/jsx-key": "error",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Applies to the remaining typescript and react defaults through line 262.

Same as the main block: all default-on in correctness, all zero-hit, all repeated here at error. react/no-find-dom-node is the one exception worth naming, since it was listed at warn, which is also its default. It still reports the same 41 warnings after removal.

Comment thread .oxlintrc.json
"requireDataLowercase": false
}
],
"react-js/prop-types": [

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed as obsolete. This repo types props with TypeScript, so a runtime propTypes check pushes toward an API the codebase has moved off. Zero hits today, because it ran with skipUndeclared: true.

Comment thread .oxlintrc.json
],
"react-js/forbid-foreign-prop-types": "error",
"react/no-danger": "error",
"react-js/require-default-props": "warn",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed as obsolete. defaultProps is deprecated for function components in React 19, so this rule was actively steering code toward an API being removed. Drops 32 warnings, the only coverage this PR intentionally gives up.

@github-actions

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://instructure.design/pr-preview/pr-2729/

Built to branch gh-pages at 2026-09-24 12:35 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

Copy link
Copy Markdown
Contributor

Visual regression report

Cypress suite: ✅ Passing

Visual diff: ✅ No changes.

Status Count
Unchanged 99
Changed 0
New 0
Removed 0

Accessibility (axe): ✅ No violations.

📊 View full report — click a screenshot's ⚠ badge to see each violation boxed on the image, with the offending element named and contrast failures shown as color swatches.

Baselines come from the visual-baselines branch. They refresh on every merge to master. The Cypress suite line covers the a11y and console-error assertions — a ❌ there means the suite found real issues even if the visual diff is clean.

github-actions Bot pushed a commit that referenced this pull request Sep 24, 2026
@joyenjoyer
joyenjoyer requested a review from balzss September 24, 2026 12:46

@balzss balzss left a comment

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.

much cleaner :)

@balzss
balzss requested a review from matyasf October 2, 2026 07:10

@matyasf matyasf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nice work, one suggestion, see my comment

Comment thread .oxlintrc.json
Comment on lines 31 to 35
"jsPlugins": [
{
"name": "react-js",
"specifier": "eslint-plugin-react"
},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I really dont like that we have this here. This pulls in the whole ESLint (see the root package.json) which adds package.json bloat and makes IDE go a bit crazy because it thinks that this project uses ESLint.

According to Claude we could remove it, which would lead to the following rules dropped (the others are natively in the react oxlint plugin`):

  • no-typos mostly catches misspelled propTypes, defaultProps, and lifecycle names. TypeScript covers most of that already.
  • forbid-foreign-prop-types does not matter here, we stopped using proptypes.
  • no-deprecated flags findDOMNode, ReactDOM.render, and the componentWill* methods, but we need a complex support matrix anyway, and I doubt anyone would write code that uses these.

I can you please try to remove this (and then you can remove the dependencies from the package.json too)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants