Run Oxlint directly instead of through Vite+

Nothing else from Vite+ is used, and Oxlint reads the same rules from
.oxlintrc.json. This drops vite-plus and with it Vitest, a second copy
of Vite and about 130 packages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bbassieandClaude Opus 5.5 committed 2026-10-27 22:53:13 +00:00
1 parent f40113e01c
commit ebedf6b3b0
5 files changed
+463 -376

No files matched your search

+458
View File
@@ -0,0 +1,458 @@
// Formatting rules come from @stylistic as Oxlint does not implement them.
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": [
"node"
],
"jsPlugins": [
"@stylistic/eslint-plugin"
],
"categories": {
"correctness": "off"
},
"env": {
"builtin": true,
"node": true
},
"ignorePatterns": [
"**/dist/",
"dist/"
],
"rules": {
"@stylistic/indent": [
"error",
"tab",
{
"ignoredNodes": [
"JSXFragment"
],
"ignoreComments": true,
"SwitchCase": 1
}
],
"accessor-pairs": "error",
"array-callback-return": "error",
"arrow-body-style": "error",
"block-scoped-var": "error",
"complexity": [
"error",
{
"max": 25
}
],
"curly": "error",
"default-case": "error",
"default-case-last": "error",
"eqeqeq": "error",
"func-name-matching": "error",
"func-style": [
"error",
"declaration",
{
"allowArrowFunctions": true
}
],
"grouped-accessor-pairs": "error",
"guard-for-in": "error",
"id-match": "error",
"max-depth": "error",
"max-nested-callbacks": "error",
"new-cap": [
"error",
{
"capIsNewExceptions": [
"StringEnum",
"StringKey"
],
"capIsNewExceptionPattern": "^Type\\.",
"newIsCapExceptions": [
"constructor"
]
}
],
"no-alert": "error",
"no-array-constructor": "error",
"no-caller": "error",
"no-console": "error",
"no-constant-condition": [
"error",
{
"checkLoops": false
}
],
"no-constructor-return": "error",
"no-div-regex": "error",
"no-duplicate-imports": "error",
"no-else-return": "error",
"no-eq-null": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-implicit-coercion": "error",
"no-implicit-globals": "error",
"no-implied-eval": "error",
"no-iterator": "error",
"no-label-var": "error",
"no-lone-blocks": "error",
"no-lonely-if": "error",
"no-loop-func": "error",
"no-multi-assign": "error",
"no-multi-str": "error",
"no-nested-ternary": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-plusplus": [
"error",
{
"allowForLoopAfterthoughts": true
}
],
"no-proto": "error",
"no-restricted-globals": "error",
"no-restricted-imports": "error",
"no-restricted-properties": "error",
"no-return-assign": "error",
"no-script-url": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow": [
"error",
{
"allow": [
"Event",
"Request",
"yargs"
]
}
],
"no-template-curly-in-string": "error",
"no-throw-literal": "error",
"no-unmodified-loop-condition": "error",
"no-unneeded-ternary": "error",
"no-unused-expressions": "error",
"no-useless-backreference": "error",
"no-useless-call": "error",
"no-useless-computed-key": "error",
"no-useless-concat": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-var": "error",
"no-void": [
"error",
{
"allowAsStatement": true
}
],
"prefer-arrow-callback": "error",
"prefer-exponentiation-operator": "error",
"prefer-numeric-literals": "error",
"prefer-object-spread": "error",
"prefer-promise-reject-errors": "error",
"prefer-regex-literals": "error",
"prefer-rest-params": "error",
"prefer-spread": "error",
"prefer-template": "error",
"radix": [
"error",
"always"
],
"symbol-description": "error",
"unicode-bom": [
"error",
"never"
],
"vars-on-top": "error",
"yoda": [
"error",
"never",
{
"exceptRange": true
}
],
"node/no-sync": [
"error",
{
"ignores": [
"TechnologySync",
"techsToSync"
]
}
],
"@stylistic/array-bracket-newline": "off",
"@stylistic/array-bracket-spacing": [
"error",
"never"
],
"@stylistic/array-element-newline": "off",
"@stylistic/arrow-parens": "off",
"@stylistic/arrow-spacing": [
"error",
{
"after": true,
"before": true
}
],
"@stylistic/block-spacing": "error",
"@stylistic/brace-style": [
"error",
"1tbs",
{
"allowSingleLine": true
}
],
"@stylistic/comma-dangle": [
"error",
{
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "always-multiline",
"exports": "always-multiline",
"functions": "only-multiline",
"generics": "only-multiline",
"enums": "always-multiline",
"tuples": "always-multiline"
}
],
"@stylistic/comma-spacing": "error",
"@stylistic/comma-style": [
"error",
"last"
],
"@stylistic/computed-property-spacing": [
"error",
"never"
],
"@stylistic/dot-location": [
"error",
"property"
],
"@stylistic/eol-last": "error",
"@stylistic/function-call-argument-newline": "off",
"@stylistic/function-paren-newline": "off",
"@stylistic/generator-star-spacing": [
"error",
{
"before": false,
"after": true
}
],
"@stylistic/implicit-arrow-linebreak": "error",
"@stylistic/jsx-quotes": "error",
"@stylistic/key-spacing": "error",
"@stylistic/keyword-spacing": "error",
"@stylistic/line-comment-position": "off",
"@stylistic/linebreak-style": [
"error",
"unix"
],
"@stylistic/lines-around-comment": "off",
"@stylistic/lines-between-class-members": [
"error",
"always",
{
"exceptAfterSingleLine": true
}
],
"@stylistic/max-len": [
"error",
{
"code": 120
}
],
"@stylistic/max-statements-per-line": "off",
"@stylistic/multiline-comment-style": [
"error",
"separate-lines"
],
"@stylistic/multiline-ternary": "off",
"@stylistic/new-parens": "error",
"@stylistic/newline-per-chained-call": "off",
"@stylistic/no-confusing-arrow": "error",
"@stylistic/no-extra-parens": "off",
"@stylistic/no-floating-decimal": "error",
"@stylistic/no-mixed-operators": [
"error",
{
"groups": [
[
"&",
"|",
"^",
"~",
"<<",
">>",
">>>"
],
[
"==",
"!=",
"===",
"!==",
">",
">=",
"<",
"<="
],
[
"in",
"instanceof"
]
]
}
],
"@stylistic/no-multi-spaces": "error",
"@stylistic/no-multiple-empty-lines": "error",
"@stylistic/no-tabs": "off",
"@stylistic/no-trailing-spaces": "error",
"@stylistic/no-whitespace-before-property": "error",
"@stylistic/nonblock-statement-body-position": "error",
"@stylistic/object-curly-newline": "error",
"@stylistic/object-curly-spacing": "off",
"@stylistic/one-var-declaration-per-line": "error",
"@stylistic/operator-linebreak": [
"error",
"after",
{
"overrides": {
"?": "before",
":": "before",
"||": "before",
"&&": "before",
"??": "before",
"|": "before",
"&": "before"
}
}
],
"@stylistic/padded-blocks": "off",
"@stylistic/padding-line-between-statements": "error",
"@stylistic/quote-props": "off",
"@stylistic/quotes": [
"error",
"double",
{
"avoidEscape": true
}
],
"@stylistic/rest-spread-spacing": [
"error",
"never"
],
"@stylistic/semi": "error",
"@stylistic/semi-spacing": "error",
"@stylistic/semi-style": "off",
"@stylistic/space-before-blocks": "error",
"@stylistic/space-before-function-paren": "off",
"@stylistic/space-in-parens": [
"error",
"never"
],
"@stylistic/space-infix-ops": "off",
"@stylistic/space-unary-ops": "error",
"@stylistic/spaced-comment": [
"error",
"always",
{
"line": {
"markers": [
"/"
]
}
}
],
"@stylistic/switch-colon-spacing": "error",
"@stylistic/template-curly-spacing": [
"error",
"never"
],
"@stylistic/template-tag-spacing": "error",
"@stylistic/wrap-iife": "error",
"@stylistic/wrap-regex": "off",
"@stylistic/yield-star-spacing": "error"
},
"overrides": [
{
"files": [
"{packages,plugins}/**/*.{ts,tsx}"
],
"rules": {
"no-unused-vars": "off",
"typescript/ban-ts-comment": "error",
"typescript/no-duplicate-enum-values": "error",
"typescript/no-empty-object-type": "error",
"typescript/no-explicit-any": "off",
"typescript/no-extra-non-null-assertion": "error",
"typescript/no-misused-new": "error",
"typescript/no-namespace": "error",
"typescript/no-non-null-asserted-optional-chain": "error",
"typescript/no-require-imports": "off",
"typescript/no-this-alias": "error",
"typescript/no-unnecessary-type-constraint": "error",
"typescript/no-unsafe-declaration-merging": "error",
"typescript/no-unsafe-function-type": "error",
"typescript/no-wrapper-object-types": "error",
"typescript/prefer-as-const": "error",
"typescript/prefer-namespace-keyword": "error",
"typescript/triple-slash-reference": "off",
"no-shadow": [
"error",
{
"allow": [
"Event",
"Request",
"yargs"
]
}
],
"no-useless-constructor": "error"
},
"plugins": [
"typescript"
]
},
{
"files": [
"test/**/*.js",
"plugins/*/test/**/*.js"
],
"rules": {
"prefer-arrow-callback": "off"
},
"env": {
"mocha": true
}
},
{
"files": [
"packages/web_ui/src/**/*.{ts,tsx}",
"packages/lib/browser.ts",
"packages/create/templates/*/web/**/*.{ts,js,tsx,jsx}",
"{packages,plugins}/*/web/**/*.{ts,tsx}"
],
"globals": {
"SpeechRecognitionAlternative": "readonly",
"SpeechRecognitionResult": "readonly",
"SpeechRecognitionResultList": "readonly"
},
"env": {
"browser": true
}
},
{
"files": [
"packages/create/templates/**/*.{js,cjs,ts,cts,jsx,tsx}"
],
"rules": {
"@stylistic/indent": "off",
"@stylistic/spaced-comment": "off",
"@stylistic/comma-spacing": "off",
"@stylistic/max-len": "off"
},
"jsPlugins": [
"@stylistic/eslint-plugin"
]
}
]
}
+1 -1
View File
@@ -18,7 +18,7 @@ Use the detailed guides for the affected area:
- Read the relevant source and tests before changing behavior. - Read the relevant source and tests before changing behavior.
If documentation and implementation disagree, report the discrepancy and distinguish observed behavior from intended policy. If documentation and implementation disagree, report the discrepancy and distinguish observed behavior from intended policy.
Update affected documentation in the same change. Update affected documentation in the same change.
- Follow nearby code and the `lint` section of `vite.config.ts`: tabs, double quotes, semicolons, and `.js` extensions in relative TypeScript imports. - Follow nearby code and `.oxlintrc.json`: tabs, double quotes, semicolons, and `.js` extensions in relative TypeScript imports.
Import shared public APIs through `@clusterio/lib` and check Node/browser exports when changing them. Import shared public APIs through `@clusterio/lib` and check Node/browser exports when changing them.
- Run commands from the root using the pinned pnpm version and the [documented Node requirements](docs/contributing.md#supported-nodejs-and-factorio-versions). - Run commands from the root using the pinned pnpm version and the [documented Node requirements](docs/contributing.md#supported-nodejs-and-factorio-versions).
Install with `pnpm install --no-frozen-lockfile`; the lockfile is intentionally ignored. Install with `pnpm install --no-frozen-lockfile`; the lockfile is intentionally ignored.
+1 -1
View File
@@ -161,7 +161,7 @@ Therefore, we selected double quotes as our standard.
🧾 20th October 2026 🧾 20th October 2026
> Use Oxlint through `vp lint` for style checking, with formatting rules from `@stylistic/eslint-plugin`. > Use Oxlint for style checking, with formatting rules from `@stylistic/eslint-plugin`.
We needed to maintain a consistent style across all our files and used ESLint for it from the start. We needed to maintain a consistent style across all our files and used ESLint for it from the start.
Oxlint runs the same rules about three times faster, reads ESLint disable comments, and does not depend on the TypeScript compiler API. Oxlint runs the same rules about three times faster, reads ESLint disable comments, and does not depend on the TypeScript compiler API.
+3 -3
View File
@@ -15,8 +15,8 @@
"cover": "c8 pnpm test", "cover": "c8 pnpm test",
"fast-cover": "FAST_TEST=y c8 pnpm test", "fast-cover": "FAST_TEST=y c8 pnpm test",
"ci-cover": "c8 --reporter=lcovonly pnpm test", "ci-cover": "c8 --reporter=lcovonly pnpm test",
"lint": "vp lint packages plugins test", "lint": "oxlint packages plugins test",
"lint-fix": "vp lint --fix packages plugins test", "lint-fix": "oxlint --fix packages plugins test",
"clean": "node ./clean.js", "clean": "node ./clean.js",
"docs": "typedoc", "docs": "typedoc",
"bundle-dependencies": "bundle-dependencies" "bundle-dependencies": "bundle-dependencies"
@@ -50,9 +50,9 @@
"form-data": "^4.0.6", "form-data": "^4.0.6",
"jsonwebtoken": "catalog:", "jsonwebtoken": "catalog:",
"mocha": "^11.8.0", "mocha": "^11.8.0",
"oxlint": "^1.88.0",
"typedoc": "^0.28.20", "typedoc": "^0.28.20",
"typescript": "catalog:", "typescript": "catalog:",
"vite-plus": "^1.3.0",
"yargs": "catalog:", "yargs": "catalog:",
"yauzl": "catalog:", "yauzl": "catalog:",
"yazl": "catalog:" "yazl": "catalog:"
-371
View File
@@ -1,371 +0,0 @@
import { defineConfig } from "vite-plus";
// Formatting rules come from @stylistic as Oxlint does not implement them.
export default defineConfig({
lint: {
plugins: ["node"],
jsPlugins: ["@stylistic/eslint-plugin"],
categories: {
correctness: "off",
},
env: {
builtin: true,
node: true,
},
ignorePatterns: ["**/dist/", "dist/"],
rules: {
"@stylistic/indent": [
"error",
"tab",
{
ignoredNodes: ["JSXFragment"],
ignoreComments: true,
SwitchCase: 1,
},
],
"accessor-pairs": "error",
"array-callback-return": "error",
"arrow-body-style": "error",
"block-scoped-var": "error",
complexity: [
"error",
{
max: 25,
},
],
curly: "error",
"default-case": "error",
"default-case-last": "error",
eqeqeq: "error",
"func-name-matching": "error",
"func-style": [
"error",
"declaration",
{
allowArrowFunctions: true,
},
],
"grouped-accessor-pairs": "error",
"guard-for-in": "error",
"id-match": "error",
"max-depth": "error",
"max-nested-callbacks": "error",
"new-cap": [
"error",
{
capIsNewExceptions: ["StringEnum", "StringKey"],
capIsNewExceptionPattern: "^Type\\.",
newIsCapExceptions: ["constructor"],
},
],
"no-alert": "error",
"no-array-constructor": "error",
"no-caller": "error",
"no-console": "error",
"no-constant-condition": [
"error",
{
checkLoops: false,
},
],
"no-constructor-return": "error",
"no-div-regex": "error",
"no-duplicate-imports": "error",
"no-else-return": "error",
"no-eq-null": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-implicit-coercion": "error",
"no-implicit-globals": "error",
"no-implied-eval": "error",
"no-iterator": "error",
"no-label-var": "error",
"no-lone-blocks": "error",
"no-lonely-if": "error",
"no-loop-func": "error",
"no-multi-assign": "error",
"no-multi-str": "error",
"no-nested-ternary": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-plusplus": [
"error",
{
allowForLoopAfterthoughts: true,
},
],
"no-proto": "error",
"no-restricted-globals": "error",
"no-restricted-imports": "error",
"no-restricted-properties": "error",
"no-return-assign": "error",
"no-script-url": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow": [
"error",
{
allow: ["Event", "Request", "yargs"],
},
],
"no-template-curly-in-string": "error",
"no-throw-literal": "error",
"no-unmodified-loop-condition": "error",
"no-unneeded-ternary": "error",
"no-unused-expressions": "error",
"no-useless-backreference": "error",
"no-useless-call": "error",
"no-useless-computed-key": "error",
"no-useless-concat": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-var": "error",
"no-void": [
"error",
{
allowAsStatement: true,
},
],
"prefer-arrow-callback": "error",
"prefer-exponentiation-operator": "error",
"prefer-numeric-literals": "error",
"prefer-object-spread": "error",
"prefer-promise-reject-errors": "error",
"prefer-regex-literals": "error",
"prefer-rest-params": "error",
"prefer-spread": "error",
"prefer-template": "error",
radix: ["error", "always"],
"symbol-description": "error",
"unicode-bom": ["error", "never"],
"vars-on-top": "error",
yoda: [
"error",
"never",
{
exceptRange: true,
},
],
"node/no-sync": [
"error",
{
// Oxlint also reports identifiers ending in Sync that are not calls
ignores: ["TechnologySync", "techsToSync"],
},
],
"@stylistic/array-bracket-newline": "off",
"@stylistic/array-bracket-spacing": ["error", "never"],
"@stylistic/array-element-newline": "off",
"@stylistic/arrow-parens": "off",
"@stylistic/arrow-spacing": [
"error",
{
after: true,
before: true,
},
],
"@stylistic/block-spacing": "error",
"@stylistic/brace-style": [
"error",
"1tbs",
{
allowSingleLine: true,
},
],
"@stylistic/comma-dangle": [
"error",
{
arrays: "always-multiline",
objects: "always-multiline",
imports: "always-multiline",
exports: "always-multiline",
functions: "only-multiline",
generics: "only-multiline",
enums: "always-multiline",
tuples: "always-multiline",
},
],
"@stylistic/comma-spacing": "error",
"@stylistic/comma-style": ["error", "last"],
"@stylistic/computed-property-spacing": ["error", "never"],
"@stylistic/dot-location": ["error", "property"],
"@stylistic/eol-last": "error",
"@stylistic/function-call-argument-newline": "off",
"@stylistic/function-paren-newline": "off",
"@stylistic/generator-star-spacing": [
"error",
{
before: false,
after: true,
},
],
"@stylistic/implicit-arrow-linebreak": "error",
"@stylistic/jsx-quotes": "error",
"@stylistic/key-spacing": "error",
"@stylistic/keyword-spacing": "error",
"@stylistic/line-comment-position": "off",
"@stylistic/linebreak-style": ["error", "unix"],
"@stylistic/lines-around-comment": "off",
"@stylistic/lines-between-class-members": [
"error",
"always",
{
exceptAfterSingleLine: true,
},
],
"@stylistic/max-len": [
"error",
{
code: 120,
},
],
"@stylistic/max-statements-per-line": "off",
"@stylistic/multiline-comment-style": ["error", "separate-lines"],
"@stylistic/multiline-ternary": "off",
"@stylistic/new-parens": "error",
"@stylistic/newline-per-chained-call": "off",
"@stylistic/no-confusing-arrow": "error",
"@stylistic/no-extra-parens": "off",
"@stylistic/no-floating-decimal": "error",
"@stylistic/no-mixed-operators": [
"error",
{
groups: [
["&", "|", "^", "~", "<<", ">>", ">>>"],
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["in", "instanceof"],
],
},
],
"@stylistic/no-multi-spaces": "error",
"@stylistic/no-multiple-empty-lines": "error",
"@stylistic/no-tabs": "off",
"@stylistic/no-trailing-spaces": "error",
"@stylistic/no-whitespace-before-property": "error",
"@stylistic/nonblock-statement-body-position": "error",
"@stylistic/object-curly-newline": "error",
"@stylistic/object-curly-spacing": "off",
"@stylistic/one-var-declaration-per-line": "error",
"@stylistic/operator-linebreak": [
"error",
"after",
{
overrides: {
"?": "before",
":": "before",
"||": "before",
"&&": "before",
"??": "before",
"|": "before",
"&": "before",
},
},
],
"@stylistic/padded-blocks": "off",
"@stylistic/padding-line-between-statements": "error",
"@stylistic/quote-props": "off",
"@stylistic/quotes": [
"error",
"double",
{
avoidEscape: true,
},
],
"@stylistic/rest-spread-spacing": ["error", "never"],
"@stylistic/semi": "error",
"@stylistic/semi-spacing": "error",
"@stylistic/semi-style": "off",
"@stylistic/space-before-blocks": "error",
"@stylistic/space-before-function-paren": "off",
"@stylistic/space-in-parens": ["error", "never"],
"@stylistic/space-infix-ops": "off",
"@stylistic/space-unary-ops": "error",
"@stylistic/spaced-comment": [
"error",
"always",
{
line: {
markers: ["/"],
},
},
],
"@stylistic/switch-colon-spacing": "error",
"@stylistic/template-curly-spacing": ["error", "never"],
"@stylistic/template-tag-spacing": "error",
"@stylistic/wrap-iife": "error",
"@stylistic/wrap-regex": "off",
"@stylistic/yield-star-spacing": "error",
},
overrides: [
{
files: ["{packages,plugins}/**/*.{ts,tsx}"],
rules: {
"no-unused-vars": "off",
"typescript/ban-ts-comment": "error",
"typescript/no-duplicate-enum-values": "error",
"typescript/no-empty-object-type": "error",
"typescript/no-explicit-any": "off",
"typescript/no-extra-non-null-assertion": "error",
"typescript/no-misused-new": "error",
"typescript/no-namespace": "error",
"typescript/no-non-null-asserted-optional-chain": "error",
"typescript/no-require-imports": "off",
"typescript/no-this-alias": "error",
"typescript/no-unnecessary-type-constraint": "error",
"typescript/no-unsafe-declaration-merging": "error",
"typescript/no-unsafe-function-type": "error",
"typescript/no-wrapper-object-types": "error",
"typescript/prefer-as-const": "error",
"typescript/prefer-namespace-keyword": "error",
"typescript/triple-slash-reference": "off",
"no-shadow": [
"error",
{
allow: ["Event", "Request", "yargs"],
},
],
"no-useless-constructor": "error",
},
plugins: ["typescript"],
},
{
files: ["test/**/*.js", "plugins/*/test/**/*.js"],
rules: {
"prefer-arrow-callback": "off",
},
env: {
mocha: true,
},
},
{
files: [
"packages/web_ui/src/**/*.{ts,tsx}",
"packages/lib/browser.ts",
"packages/create/templates/*/web/**/*.{ts,js,tsx,jsx}",
"{packages,plugins}/*/web/**/*.{ts,tsx}",
],
globals: {
SpeechRecognitionAlternative: "readonly",
SpeechRecognitionResult: "readonly",
SpeechRecognitionResultList: "readonly",
},
env: {
browser: true,
},
},
{
files: ["packages/create/templates/**/*.{js,cjs,ts,cts,jsx,tsx}"],
rules: {
"@stylistic/indent": "off",
"@stylistic/spaced-comment": "off",
"@stylistic/comma-spacing": "off",
"@stylistic/max-len": "off",
},
jsPlugins: ["@stylistic/eslint-plugin"],
},
],
},
});