diff --git a/packages/oxlint-config/README.md b/packages/oxlint-config/README.md
new file mode 100644
index 0000000..e0b7895
--- /dev/null
+++ b/packages/oxlint-config/README.md
@@ -0,0 +1,205 @@
+# @qlik/oxlint-config
+
+Qlik's shared [oxlint](https://oxc.rs/docs/guide/usage/linter) configurations.
+
+This package mirrors the rules from `@qlik/eslint-config` for projects that have adopted (or are migrating to) oxlint. oxlint is dramatically faster than ESLint and covers the majority of rules used in our ESLint configs.
+
+## Requirements
+
+- `oxlint >= 1.0.0`
+
+## Configs
+
+| Config | Plugins | Use for |
+| ---------------- | ------------------------------------------- | ----------------------- |
+| `recommended.js` | `typescript`, `import` | Any JS/TS project |
+| `react.js` | `typescript`, `import`, `react`, `jsx-a11y` | React projects |
+| `node.js` | `typescript`, `import`, `node` | Node.js scripts/servers |
+| `vitest.js` | `typescript`, `import`, `vitest` | Vitest test files |
+| `jest.js` | `typescript`, `import`, `jest` | Jest test files |
+
+## Usage
+
+Configs are plain JS objects and are consumed via an `oxlint.config.ts` file in your project root. The `defineConfig` helper from `oxlint` provides typing and merging.
+
+### TypeScript / JavaScript project
+
+```ts
+// oxlint.config.ts
+import { defineConfig } from "oxlint";
+import recommended from "@qlik/oxlint-config/recommended.js";
+
+export default defineConfig({ extends: [recommended] });
+```
+
+### React project
+
+```ts
+// oxlint.config.ts
+import { defineConfig } from "oxlint";
+import react from "@qlik/oxlint-config/react.js";
+
+export default defineConfig({ extends: [react] });
+```
+
+### Node.js project
+
+```ts
+// oxlint.config.ts
+import { defineConfig } from "oxlint";
+import node from "@qlik/oxlint-config/node.js";
+
+export default defineConfig({ extends: [node] });
+```
+
+### With test file overrides
+
+Use `overrides` to apply test-specific rules only to test file globs:
+
+```ts
+// oxlint.config.ts
+import { defineConfig } from "oxlint";
+import recommended from "@qlik/oxlint-config/recommended.js";
+import vitest from "@qlik/oxlint-config/vitest.js";
+
+export default defineConfig({
+ extends: [recommended],
+ overrides: [
+ {
+ files: ["**/__tests__/**", "**/*.test.*", "**/*.spec.*"],
+ extends: [vitest],
+ },
+ ],
+});
+```
+
+## Running oxlint
+
+```sh
+# oxlint.config.ts is picked up automatically
+oxlint
+
+# Or point to it explicitly
+oxlint --config oxlint.config.ts
+```
+
+## Testing
+
+Snapshot files in [`test/generated/`](./test/generated/) show the fully-resolved rule set for each config (as printed by `oxlint --print-config`). They make it easy to review the exact rules that will be enforced and to spot unintended changes in pull requests.
+
+```sh
+# Verify committed snapshots match the current config (used in CI)
+pnpm test
+
+# Regenerate snapshots after changing a config, then commit the result
+pnpm test:update
+```
+
+---
+
+## Local development (consuming without npm publish)
+
+You can build and test this package locally without publishing to the npm registry.
+
+### 1. Pack a tarball
+
+```sh
+cd packages/oxlint-config
+pnpm pack
+# Creates: qlik-oxlint-config-0.1.0.tgz
+```
+
+### 2. Consume the tarball in another project
+
+```sh
+# In your consumer project
+pnpm add /absolute/path/to/dev-tools-js/packages/oxlint-config/qlik-oxlint-config-0.1.0.tgz
+```
+
+Or with npm / yarn:
+
+```sh
+npm install /absolute/path/to/dev-tools-js/packages/oxlint-config/qlik-oxlint-config-0.1.0.tgz
+yarn add /absolute/path/to/dev-tools-js/packages/oxlint-config/qlik-oxlint-config-0.1.0.tgz
+```
+
+### 3. Inside this monorepo (workspace protocol)
+
+If your consumer is also a package in this monorepo, use the workspace protocol instead:
+
+```json
+// consumer/package.json
+{
+ "devDependencies": {
+ "@qlik/oxlint-config": "workspace:^"
+ }
+}
+```
+
+Then run `pnpm install` from the monorepo root.
+
+### 4. Create your oxlint config
+
+```ts
+// oxlint.config.ts
+import { defineConfig } from "oxlint";
+import recommended from "@qlik/oxlint-config/recommended.js";
+
+export default defineConfig({ extends: [recommended] });
+```
+
+---
+
+## Running oxlint alongside ESLint
+
+During migration you can run both linters in sequence. Use
+[`eslint-plugin-oxlint`](https://github.com/oxc-project/eslint-plugin-oxlint) to
+disable ESLint rules that are already covered by oxlint and avoid duplicate
+diagnostics:
+
+```sh
+npm install --save-dev eslint-plugin-oxlint
+```
+
+```js
+// eslint.config.js
+import oxlint from "eslint-plugin-oxlint";
+export default [
+ // ... your existing eslint config
+ oxlint.configs["flat/recommended"],
+];
+```
+
+Then run both:
+
+```sh
+oxlint && eslint
+```
+
+## Rule coverage notes
+
+The following rules from `@qlik/eslint-config` are **not yet implemented** in
+oxlint and remain ESLint-only:
+
+| ESLint rule | Notes |
+| ---------------------------------------------------- | ---------------------------------------------------------------- |
+| `camelcase` / `@typescript-eslint/naming-convention` | Not implemented in oxlint; TypeScript types enforce PascalCase |
+| `no-restricted-syntax` | Not implemented; `no-labels`/`no-with` cover the important cases |
+| `no-restricted-exports` | Not implemented |
+| `no-restricted-properties` | Not implemented; `prefer-object-has-own` etc. cover key cases |
+
+### Type-aware TypeScript rules
+
+The following rules from `@typescript-eslint` require type information (💠in
+the oxlint docs). They are available via oxlint's
+[type-aware alpha](https://oxc.rs/blog/2025-12-08-type-aware-alpha) and will be
+covered automatically once type-aware mode is stable:
+
+- `@typescript-eslint/no-floating-promises`
+- `@typescript-eslint/no-misused-promises`
+- `@typescript-eslint/no-unnecessary-condition`
+- `@typescript-eslint/no-unnecessary-type-arguments`
+- `@typescript-eslint/return-await`
+- `@typescript-eslint/switch-exhaustiveness-check`
+- `@typescript-eslint/use-unknown-in-catch-callback-variable`
+- and more
diff --git a/packages/oxlint-config/jest.js b/packages/oxlint-config/jest.js
new file mode 100644
index 0000000..4b866c0
--- /dev/null
+++ b/packages/oxlint-config/jest.js
@@ -0,0 +1,54 @@
+// @ts-check
+// Qlik Jest oxlint config
+// Extends recommended with jest plugin rules for test files.
+//
+// Typical usage – add an override to your project's .oxlintrc.json:
+//
+// {
+// "extends": ["@qlik/oxlint-config/recommended.json"],
+// "overrides": [
+// {
+// "files": ["**/__tests__/**", "**/*.test.*", "**/*.spec.*"],
+// "extends": ["@qlik/oxlint-config/jest.json"]
+// }
+// ]
+// }
+//
+// Or, in an oxlint.config.ts:
+//
+// import { defineConfig } from "oxlint";
+// import jest from "@qlik/oxlint-config/jest.js";
+// export default defineConfig({ extends: [jest] });
+
+import recommended from "./recommended.js";
+
+/** @type {import("oxlint").OxlintConfig} */
+const config = {
+ extends: [recommended],
+
+ plugins: ["typescript", "import", "jest"],
+
+ env: {
+ jest: true,
+ },
+
+ rules: {
+ // console output in tests is usually intentional (debugging assertions)
+ "no-console": "off",
+
+ // test files don't export production code, so import restrictions are relaxed
+ "no-restricted-imports": "off",
+
+ /* ------------------------------------------------------------------ */
+ /* Jest – correctness (override to make explicit) */
+ /* ------------------------------------------------------------------ */
+
+ // focused tests (test.only / describe.only) must never be committed
+ "jest/no-focused-tests": "error",
+
+ // disabled tests (test.skip / xtest) should be reviewed and removed
+ "jest/no-disabled-tests": "error",
+ },
+};
+
+export default config;
diff --git a/packages/oxlint-config/node.js b/packages/oxlint-config/node.js
new file mode 100644
index 0000000..535420f
--- /dev/null
+++ b/packages/oxlint-config/node.js
@@ -0,0 +1,26 @@
+// @ts-check
+// Qlik Node.js oxlint config
+// Extends recommended with Node.js-friendly overrides and the node plugin.
+
+import recommended from "./recommended.js";
+
+/** @type {import("oxlint").OxlintConfig} */
+const config = {
+ extends: [recommended],
+
+ plugins: ["typescript", "import", "node"],
+
+ rules: {
+ // console is perfectly fine in Node.js scripts and servers
+ "no-console": "off",
+
+ /* ------------------------------------------------------------------ */
+ /* node plugin – restriction category */
+ /* ------------------------------------------------------------------ */
+
+ // string concatenation for paths is fragile; use path.join/path.resolve
+ "node/no-path-concat": "error",
+ },
+};
+
+export default config;
diff --git a/packages/oxlint-config/package.json b/packages/oxlint-config/package.json
new file mode 100644
index 0000000..0b11005
--- /dev/null
+++ b/packages/oxlint-config/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "@qlik/oxlint-config",
+ "version": "0.1.0",
+ "description": "Qlik's oxlint configs",
+ "repository": "git@github.com:qlik-oss/dev-tools-js.git",
+ "license": "ISC",
+ "type": "module",
+ "exports": {
+ "./recommended.js": "./recommended.js",
+ "./react.js": "./react.js",
+ "./node.js": "./node.js",
+ "./vitest.js": "./vitest.js",
+ "./jest.js": "./jest.js"
+ },
+ "files": [
+ "recommended.js",
+ "react.js",
+ "node.js",
+ "vitest.js",
+ "jest.js"
+ ],
+ "scripts": {
+ "format:check": "cd ../.. && prettier --check 'packages/oxlint-config' --ignore-unknown",
+ "format:write": "cd ../.. && prettier --write 'packages/oxlint-config' --ignore-unknown",
+ "test": "./test/verify-configs.sh",
+ "test:update": "./test/update-configs.sh"
+ },
+ "devDependencies": {
+ "oxlint": "^1.50.0"
+ },
+ "peerDependencies": {
+ "oxlint": ">=1.0.0"
+ }
+}
diff --git a/packages/oxlint-config/react.js b/packages/oxlint-config/react.js
new file mode 100644
index 0000000..528846a
--- /dev/null
+++ b/packages/oxlint-config/react.js
@@ -0,0 +1,117 @@
+// @ts-check
+// Qlik React oxlint config
+// Extends recommended with React and jsx-a11y plugins.
+// Most jsx-a11y rules are already caught by the `correctness` category;
+// only rules that need non-default options are configured explicitly.
+
+import recommended from "./recommended.js";
+
+/** @type {import("oxlint").OxlintConfig} */
+const config = {
+ extends: [recommended],
+
+ // plugins must include all parent plugins plus any additions
+ plugins: ["typescript", "import", "react", "jsx-a11y"],
+
+ rules: {
+ /* ------------------------------------------------------------------ */
+ /* React – style category (not on by default) */
+ /* ------------------------------------------------------------------ */
+
+ // boolean props should be written as not
+ "react/jsx-boolean-value": ["error", "never"],
+
+ // user-defined JSX components must use PascalCase
+ "react/jsx-pascal-case": "error",
+
+ // self-close components that have no children: not
+ "react/self-closing-comp": "error",
+
+ /* ------------------------------------------------------------------ */
+ /* React – pedantic category */
+ /* ------------------------------------------------------------------ */
+
+ // rules of hooks must always be followed
+ "react/rules-of-hooks": "error",
+
+ // useless fragments add noise and affect perf
+ "react/jsx-no-useless-fragment": "error",
+
+ // target="_blank" without rel="noreferrer" allows tab-napping attacks
+ "react/jsx-no-target-blank": "error",
+
+ /* ------------------------------------------------------------------ */
+ /* React – restriction category */
+ /* ------------------------------------------------------------------ */
+
+ // dangerouslySetInnerHTML is an XSS vector; warn rather than error
+ // because there are legitimate uses (e.g. server-rendered HTML)
+ "react/no-danger": "warn",
+
+ // unknown DOM props are silently ignored by React but almost always typos
+ "react/no-unknown-property": "error",
+
+ /* ------------------------------------------------------------------ */
+ /* React – suspicious overrides */
+ /* ------------------------------------------------------------------ */
+
+ // since React 17 the JSX transform handles the React import automatically
+ "react/react-in-jsx-scope": "off",
+
+ /* ------------------------------------------------------------------ */
+ /* jsx-a11y – option overrides */
+ /* Most rules are already enforced via the correctness category; */
+ /* only rules that need project-specific options are listed here. */
+ /* ------------------------------------------------------------------ */
+
+ // autofocus steals focus unexpectedly – allow it on non-DOM components
+ // (e.g. a custom component that wraps a native input)
+ "jsx-a11y/no-autofocus": ["error", { ignoreNonDOM: true }],
+
+ // support custom Link components that use `to` instead of `href`
+ "jsx-a11y/anchor-is-valid": [
+ "error",
+ {
+ components: ["Link"],
+ specialLink: ["to"],
+ aspects: ["noHref", "invalidHref", "preferButton"],
+ },
+ ],
+
+ // every label must have both a for/htmlFor attribute and a matching control
+ "jsx-a11y/label-has-associated-control": [
+ "error",
+ {
+ assert: "both",
+ depth: 25,
+ },
+ ],
+
+ // interactive elements turned non-interactive must use one of these roles
+ "jsx-a11y/no-interactive-element-to-noninteractive-role": [
+ "error",
+ {
+ tr: ["none", "presentation"],
+ },
+ ],
+
+ // non-interactive elements that are given an interactive role must be
+ // limited to semantically appropriate roles for each element type
+ "jsx-a11y/no-noninteractive-element-to-interactive-role": [
+ "error",
+ {
+ ul: ["listbox", "menu", "menubar", "radiogroup", "tablist", "tree", "treegrid"],
+ ol: ["listbox", "menu", "menubar", "radiogroup", "tablist", "tree", "treegrid"],
+ li: ["menuitem", "option", "row", "tab", "treeitem"],
+ table: ["grid"],
+ td: ["gridcell"],
+ },
+ ],
+
+ // oxlint's no-redundant-roles does not accept options; the default
+ // behaviour already catches the most common case (nav + navigation)
+ "jsx-a11y/no-redundant-roles": "error",
+ },
+};
+
+export default config;
diff --git a/packages/oxlint-config/recommended.js b/packages/oxlint-config/recommended.js
new file mode 100644
index 0000000..54f29e4
--- /dev/null
+++ b/packages/oxlint-config/recommended.js
@@ -0,0 +1,293 @@
+// @ts-check
+// Qlik Recommended oxlint config
+// Covers ESLint core, TypeScript, and Import rules.
+//
+// Category strategy
+// ─────────────────
+// correctness → rules that catch definite bugs (oxlint default)
+// suspicious → code that is likely wrong (oxlint default)
+// pedantic → extra-strict, few false positives — Qlik standard
+// enables: array-callback-return, no-case-declarations,
+// no-constructor-return, no-else-return, no-fallthrough,
+// no-loop-func, no-lonely-if, no-new-wrappers, no-redeclare,
+// no-self-compare, no-throw-literal, no-useless-return, radix,
+// symbol-description, no-array-constructor,
+// typescript/ban-ts-comment, typescript/prefer-enum-initializers
+//
+// Rules listed explicitly are those that need custom options, a non-"error"
+// severity, belong to an opt-in category (restriction / style / perf), or
+// override a category-level default.
+//
+// Rules NOT yet implemented in oxlint (remain ESLint-only):
+// - camelcase / @typescript-eslint/naming-convention
+// - no-restricted-syntax
+// - no-restricted-exports
+// - no-restricted-properties
+
+/** @type {import("oxlint").OxlintConfig} */
+const config = {
+ plugins: ["typescript", "import"],
+
+ categories: {
+ correctness: "error",
+ suspicious: "error",
+ pedantic: "error",
+ },
+
+ rules: {
+ /* ------------------------------------------------------------------ */
+ /* Category overrides – custom options */
+ /* ------------------------------------------------------------------ */
+
+ // allow implicit returns in array callbacks (e.g. `arr.map(x => x && x.y)`)
+ "array-callback-return": ["error", { allowImplicit: true }],
+
+ // strict equality everywhere, but allow `== null` to catch both null/undefined
+ eqeqeq: ["error", "always", { null: "ignore" }],
+
+ // else-after-return is redundant; also disallow else-if-after-return
+ "no-else-return": ["error", { allowElseIf: false }],
+
+ // always reject Promises with Error objects; allow empty rejections
+ "prefer-promise-reject-errors": ["error", { allowEmptyReject: true }],
+
+ // assignment-in-return is almost always a bug; "always" = no exception
+ "no-return-assign": ["error", "always"],
+
+ // constructor/class names must be PascalCase; don't require cap for plain calls
+ "new-cap": ["error", { newIsCap: true, capIsNew: false }],
+
+ // param mutation is confusing; allow common accumulator/context/request patterns
+ "no-param-reassign": [
+ "error",
+ {
+ props: true,
+ ignorePropertyModificationsFor: [
+ "prev", // reduce accumulators
+ "acc", // reduce accumulators
+ "accumulator", // reduce accumulators
+ "e", // event objects (e.returnValue etc.)
+ "ctx", // Koa routing
+ "context", // Koa routing
+ "req", // Express requests
+ "request", // Express requests
+ "res", // Express responses
+ "response", // Express responses
+ "$scope", // Angular scopes
+ "staticContext", // React Router
+ "sharedState", // shared reducers
+ "state", // shared reducers
+ ],
+ },
+ ],
+
+ // restrict confusing browser globals that shadow window properties
+ "no-restricted-globals": [
+ "error",
+ { name: "isFinite", message: "Use Number.isFinite instead" },
+ { name: "isNaN", message: "Use Number.isNaN instead" },
+ { name: "addEventListener", message: "Use window.addEventListener instead" },
+ { name: "blur", message: "Use window.blur instead" },
+ { name: "close", message: "Use window.close instead" },
+ { name: "closed", message: "Use window.closed instead" },
+ { name: "confirm", message: "Use window.confirm instead" },
+ { name: "defaultStatus", message: "Use window.defaultStatus instead" },
+ { name: "defaultstatus", message: "Use window.defaultstatus instead" },
+ { name: "error", message: "Use window.error instead" },
+ { name: "event", message: "Use window.event instead" },
+ { name: "find", message: "Use window.find instead" },
+ { name: "focus", message: "Use window.focus instead" },
+ { name: "frameElement", message: "Use window.frameElement instead" },
+ { name: "frames", message: "Use window.frames instead" },
+ { name: "history", message: "Use window.history instead" },
+ { name: "innerHeight", message: "Use window.innerHeight instead" },
+ { name: "innerWidth", message: "Use window.innerWidth instead" },
+ { name: "length", message: "Use window.length instead" },
+ { name: "localStorage", message: "Use window.localStorage instead" },
+ { name: "location", message: "Use window.location instead" },
+ { name: "menubar", message: "Use window.menubar instead" },
+ { name: "moveBy", message: "Use window.moveBy instead" },
+ { name: "moveTo", message: "Use window.moveTo instead" },
+ { name: "name", message: "Use window.name instead" },
+ { name: "onblur", message: "Use window.onblur instead" },
+ { name: "onerror", message: "Use window.onerror instead" },
+ { name: "onfocus", message: "Use window.onfocus instead" },
+ { name: "onload", message: "Use window.onload instead" },
+ { name: "onresize", message: "Use window.onresize instead" },
+ { name: "onunload", message: "Use window.onunload instead" },
+ { name: "open", message: "Use window.open instead" },
+ { name: "opener", message: "Use window.opener instead" },
+ { name: "opera", message: "Use window.opera instead" },
+ { name: "outerHeight", message: "Use window.outerHeight instead" },
+ { name: "outerWidth", message: "Use window.outerWidth instead" },
+ { name: "pageXOffset", message: "Use window.pageXOffset instead" },
+ { name: "pageYOffset", message: "Use window.pageYOffset instead" },
+ { name: "parent", message: "Use window.parent instead" },
+ { name: "print", message: "Use window.print instead" },
+ { name: "removeEventListener", message: "Use window.removeEventListener instead" },
+ { name: "resizeBy", message: "Use window.resizeBy instead" },
+ { name: "resizeTo", message: "Use window.resizeTo instead" },
+ { name: "screen", message: "Use window.screen instead" },
+ { name: "screenLeft", message: "Use window.screenLeft instead" },
+ { name: "screenTop", message: "Use window.screenTop instead" },
+ { name: "screenX", message: "Use window.screenX instead" },
+ { name: "screenY", message: "Use window.screenY instead" },
+ { name: "scroll", message: "Use window.scroll instead" },
+ { name: "scrollbars", message: "Use window.scrollbars instead" },
+ { name: "scrollBy", message: "Use window.scrollBy instead" },
+ { name: "scrollTo", message: "Use window.scrollTo instead" },
+ { name: "scrollX", message: "Use window.scrollX instead" },
+ { name: "scrollY", message: "Use window.scrollY instead" },
+ { name: "self", message: "Use window.self instead" },
+ { name: "sessionStorage", message: "Use window.sessionStorage instead" },
+ { name: "status", message: "Use window.status instead" },
+ { name: "statusbar", message: "Use window.statusbar instead" },
+ { name: "stop", message: "Use window.stop instead" },
+ { name: "toolbar", message: "Use window.toolbar instead" },
+ { name: "top", message: "Use window.top instead" },
+ ],
+
+ // BOM causes encoding issues in source files
+ "unicode-bom": ["error", "never"],
+
+ // circular imports cause subtle bugs; trust external packages
+ "import/no-cycle": ["error", { ignoreExternal: true }],
+
+ /* ------------------------------------------------------------------ */
+ /* Warn instead of error */
+ /* ------------------------------------------------------------------ */
+
+ // console output should be intentional; warn so CI surfaces it without blocking
+ "no-console": "warn",
+
+ // anonymous functions make stack traces harder to read
+ "func-names": "warn",
+
+ // empty function bodies should be a deliberate and visible choice
+ "no-empty-function": "warn",
+
+ /* ------------------------------------------------------------------ */
+ /* Restriction – explicit opt-in */
+ /* ------------------------------------------------------------------ */
+
+ // alert/confirm/prompt are debug tools, not production patterns
+ "no-alert": "error",
+
+ // bitwise ops are almost always a typo for logical operators (|, &)
+ "no-bitwise": "error",
+
+ // __proto__ is deprecated; use Object.getPrototypeOf instead
+ "no-proto": "error",
+
+ // comma sequences produce surprising evaluated values
+ "no-sequences": "error",
+
+ // var has confusing function scope; always use let/const
+ "no-var": "error",
+
+ // switch without a default case silently ignores unhandled values
+ "default-case": "error",
+
+ // teams configure their own restricted imports per project
+ "no-restricted-imports": "off",
+
+ /* ------------------------------------------------------------------ */
+ /* TypeScript – restriction */
+ /* ------------------------------------------------------------------ */
+
+ // always use `import type` for type-only imports
+ "typescript/consistent-type-imports": "error",
+
+ // delete on dynamic keys bypasses type safety
+ "typescript/no-dynamic-delete": "error",
+
+ // side-effect imports of type-only modules defeat `import type`
+ "typescript/no-import-type-side-effects": "error",
+
+ // void used as a type where it shouldn't be is confusing
+ "typescript/no-invalid-void-type": "error",
+
+ // !foo ?? bar is always a logical bug
+ "typescript/no-non-null-asserted-nullish-coalescing": "error",
+
+ // non-null assertions hide potential null bugs; use explicit checks
+ "typescript/no-non-null-assertion": "error",
+
+ // enum members with explicit values are easier to audit
+ "typescript/prefer-literal-enum-member": "error",
+
+ /* ------------------------------------------------------------------ */
+ /* TypeScript – nursery / style (not covered by pedantic) */
+ /* ------------------------------------------------------------------ */
+
+ // enforce consistent type-only exports (mirrors consistent-type-imports)
+ "typescript/consistent-type-exports": "error",
+
+ // overloaded signatures that can be unified reduce API surface area
+ "typescript/unified-signatures": "error",
+
+ /* ------------------------------------------------------------------ */
+ /* Import – restriction */
+ /* ------------------------------------------------------------------ */
+
+ // AMD require() is legacy and incompatible with ES modules
+ "import/no-amd": "error",
+
+ // dynamic require() defeats static analysis and tree-shaking
+ "import/no-dynamic-require": "error",
+
+ // webpack-specific loader syntax in import paths is non-standard
+ "import/no-webpack-loader-syntax": "error",
+
+ /* ------------------------------------------------------------------ */
+ /* Import – suspicious overrides (disable noisy defaults) */
+ /* ------------------------------------------------------------------ */
+
+ // TypeScript already catches misused default imports
+ "import/no-named-as-default-member": "off",
+
+ // empty named import blocks cause false positives with re-export patterns
+ "import/no-empty-named-blocks": "off",
+
+ /* ------------------------------------------------------------------ */
+ /* Style – explicit opt-in */
+ /* (style category is intentionally not enabled globally; it includes */
+ /* sort-imports, no-inline-comments, no-undefined, no-ternary, etc.) */
+ /* ------------------------------------------------------------------ */
+
+ "default-case-last": "error",
+ "default-param-last": "error",
+ "no-continue": "error",
+ "no-extra-label": "error",
+ "no-labels": "error",
+ "no-label-var": "error",
+ "no-lone-blocks": "error",
+ "no-multi-str": "error",
+ "no-multi-assign": "error",
+ "no-nested-ternary": "error",
+ "no-new-func": "error",
+ "no-script-url": "error",
+ "operator-assignment": "error",
+ "prefer-const": "error",
+ "prefer-exponentiation-operator": "error",
+ "prefer-numeric-literals": "error",
+ "prefer-object-has-own": "error",
+ "prefer-object-spread": "error",
+ "prefer-rest-params": "error",
+ "prefer-spread": "error",
+ "prefer-template": "error",
+ yoda: "error",
+
+ /* ------------------------------------------------------------------ */
+ /* Perf – explicit opt-in */
+ /* ------------------------------------------------------------------ */
+
+ // await in loops blocks parallelism – batch with Promise.all instead
+ "no-await-in-loop": "error",
+
+ // unnecessary .call()/.apply() skip the optimised fast-path
+ "no-useless-call": "error",
+ },
+};
+
+export default config;
diff --git a/packages/oxlint-config/test/generate-configs.js b/packages/oxlint-config/test/generate-configs.js
new file mode 100644
index 0000000..edc1363
--- /dev/null
+++ b/packages/oxlint-config/test/generate-configs.js
@@ -0,0 +1,99 @@
+/**
+ * Generates test/generated/*.json snapshot files for each oxlint config preset.
+ *
+ * Each snapshot is produced by writing a temporary oxlint.config.mjs that
+ * extends the preset, running `oxlint --print-config` against a dummy file,
+ * and capturing the fully-resolved JSON output. This lets reviewers see the
+ * exact rules oxlint will enforce at a glance, without running the linter.
+ *
+ * Usage:
+ * node test/generate-configs.js
+ */
+
+import { execSync } from "node:child_process";
+import fs from "node:fs/promises";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const root = path.resolve(__dirname, "..");
+const generatedDir = path.resolve(__dirname, "generated");
+
+await fs.mkdir(generatedDir, { recursive: true });
+
+/**
+ * Configs to snapshot.
+ * Each entry maps a name to the import path (relative to the package root).
+ */
+const configs = {
+ recommended: "../recommended.js",
+ react: "../react.js",
+ node: "../node.js",
+ vitest: "../vitest.js",
+ jest: "../jest.js",
+};
+
+// Reusable dummy file for --print-config (just needs to exist)
+const dummyFile = path.resolve(root, "_print-config-dummy.js");
+await fs.writeFile(dummyFile, "");
+
+for (const [name, importPath] of Object.entries(configs)) {
+ // Write the ephemeral config inside the package root so that Node can
+ // resolve both "oxlint" and the local preset via the workspace node_modules.
+ const configFile = path.resolve(root, `_print-config-${name}.mjs`);
+
+ await fs.writeFile(
+ configFile,
+ [
+ `import { defineConfig } from "oxlint";`,
+ `import preset from "${path.resolve(root, importPath)}";`,
+ `export default defineConfig(preset);`,
+ ].join("\n"),
+ );
+
+ let resolved;
+ try {
+ resolved = execSync(`node_modules/.bin/oxlint --config "${configFile}" --print-config "${dummyFile}"`, {
+ cwd: root,
+ encoding: "utf8",
+ });
+ } catch (err) {
+ console.error(`Failed to resolve config for "${name}":`, err.message);
+ process.exitCode = 1;
+ continue;
+ } finally {
+ await fs.rm(configFile, { force: true });
+ }
+
+ // Pretty-print the JSON with sorted keys for stable diffs
+ const parsed = JSON.parse(resolved);
+ const sorted = sortKeys(parsed);
+ const pretty = JSON.stringify(sorted, null, 2);
+
+ const outFile = path.resolve(generatedDir, `${name}-final-config.json`);
+ await fs.writeFile(outFile, pretty + "\n");
+ console.log(` ✓ ${name} → test/generated/${name}-final-config.json`);
+}
+
+// Clean up the shared dummy file
+await fs.rm(dummyFile, { force: true });
+
+/**
+ * Recursively sorts object keys for a stable representation.
+ * Arrays and primitives are left unchanged.
+ * @param {unknown} value
+ * @returns {unknown}
+ */
+function sortKeys(value) {
+ if (Array.isArray(value)) {
+ return value.map(sortKeys);
+ }
+ if (value !== null && typeof value === "object") {
+ return Object.fromEntries(
+ Object.entries(value)
+ .sort(([a], [b]) => a.localeCompare(b))
+ .map(([k, v]) => [k, sortKeys(v)]),
+ );
+ }
+ return value;
+}
diff --git a/packages/oxlint-config/test/generated/jest-final-config.json b/packages/oxlint-config/test/generated/jest-final-config.json
new file mode 100644
index 0000000..a9699d1
--- /dev/null
+++ b/packages/oxlint-config/test/generated/jest-final-config.json
@@ -0,0 +1,233 @@
+{
+ "categories": {},
+ "env": {
+ "jest": true
+ },
+ "globals": {},
+ "ignorePatterns": [],
+ "plugins": [
+ "typescript",
+ "import",
+ "jest"
+ ],
+ "rules": {
+ "array-callback-return": "deny",
+ "block-scoped-var": "deny",
+ "class-methods-use-this": "warn",
+ "constructor-super": "deny",
+ "default-case": "deny",
+ "default-case-last": "deny",
+ "default-param-last": "deny",
+ "eqeqeq": "deny",
+ "for-direction": "deny",
+ "func-names": "warn",
+ "getter-return": "deny",
+ "import/default": "deny",
+ "import/max-dependencies": "allow",
+ "import/namespace": "deny",
+ "import/no-absolute-path": "deny",
+ "import/no-amd": "deny",
+ "import/no-cycle": "deny",
+ "import/no-duplicates": "deny",
+ "import/no-dynamic-require": "deny",
+ "import/no-empty-named-blocks": "allow",
+ "import/no-mutable-exports": "deny",
+ "import/no-named-as-default": "deny",
+ "import/no-named-as-default-member": "allow",
+ "import/no-named-default": "deny",
+ "import/no-self-import": "deny",
+ "import/no-unassigned-import": "deny",
+ "import/no-webpack-loader-syntax": "deny",
+ "jest/expect-expect": "deny",
+ "jest/no-commented-out-tests": "deny",
+ "jest/no-conditional-expect": "deny",
+ "jest/no-disabled-tests": "deny",
+ "jest/no-export": "deny",
+ "jest/no-focused-tests": "deny",
+ "jest/no-standalone-expect": "deny",
+ "jest/require-to-throw-message": "deny",
+ "jest/valid-describe-callback": "deny",
+ "jest/valid-expect": "deny",
+ "jest/valid-title": "deny",
+ "new-cap": "deny",
+ "no-alert": "deny",
+ "no-async-promise-executor": "deny",
+ "no-await-in-loop": "deny",
+ "no-bitwise": "deny",
+ "no-caller": "deny",
+ "no-class-assign": "deny",
+ "no-compare-neg-zero": "deny",
+ "no-cond-assign": "deny",
+ "no-console": "allow",
+ "no-const-assign": "deny",
+ "no-constant-binary-expression": "deny",
+ "no-constant-condition": "deny",
+ "no-continue": "deny",
+ "no-control-regex": "deny",
+ "no-debugger": "deny",
+ "no-delete-var": "deny",
+ "no-dupe-class-members": "deny",
+ "no-dupe-else-if": "deny",
+ "no-dupe-keys": "deny",
+ "no-duplicate-case": "deny",
+ "no-else-return": "deny",
+ "no-empty-character-class": "deny",
+ "no-empty-function": "allow",
+ "no-empty-pattern": "deny",
+ "no-empty-static-block": "deny",
+ "no-eval": "deny",
+ "no-ex-assign": "deny",
+ "no-extend-native": "deny",
+ "no-extra-bind": "deny",
+ "no-extra-boolean-cast": "deny",
+ "no-extra-label": "deny",
+ "no-func-assign": "deny",
+ "no-global-assign": "deny",
+ "no-import-assign": "deny",
+ "no-invalid-regexp": "deny",
+ "no-irregular-whitespace": "deny",
+ "no-iterator": "deny",
+ "no-label-var": "deny",
+ "no-labels": "deny",
+ "no-lone-blocks": "deny",
+ "no-loss-of-precision": "deny",
+ "no-misleading-character-class": "deny",
+ "no-multi-assign": "deny",
+ "no-multi-str": "deny",
+ "no-nested-ternary": "deny",
+ "no-new": "deny",
+ "no-new-func": "deny",
+ "no-new-native-nonconstructor": "deny",
+ "no-nonoctal-decimal-escape": "deny",
+ "no-obj-calls": "deny",
+ "no-param-reassign": "deny",
+ "no-proto": "deny",
+ "no-regex-spaces": "deny",
+ "no-restricted-globals": "deny",
+ "no-restricted-imports": "allow",
+ "no-return-assign": "deny",
+ "no-script-url": "deny",
+ "no-self-assign": "deny",
+ "no-sequences": "deny",
+ "no-setter-return": "deny",
+ "no-shadow": "deny",
+ "no-shadow-restricted-names": "deny",
+ "no-sparse-arrays": "deny",
+ "no-template-curly-in-string": "deny",
+ "no-this-before-super": "deny",
+ "no-unassigned-vars": "deny",
+ "no-unexpected-multiline": "deny",
+ "no-unmodified-loop-condition": "deny",
+ "no-unneeded-ternary": "deny",
+ "no-unreachable": "deny",
+ "no-unsafe-finally": "deny",
+ "no-unsafe-negation": "deny",
+ "no-unsafe-optional-chaining": "deny",
+ "no-unused-expressions": "deny",
+ "no-unused-labels": "deny",
+ "no-unused-private-class-members": "deny",
+ "no-unused-vars": "deny",
+ "no-useless-backreference": "deny",
+ "no-useless-call": "deny",
+ "no-useless-catch": "deny",
+ "no-useless-concat": "deny",
+ "no-useless-constructor": "deny",
+ "no-useless-escape": "deny",
+ "no-useless-rename": "deny",
+ "no-var": "deny",
+ "no-with": "deny",
+ "operator-assignment": "deny",
+ "prefer-const": "deny",
+ "prefer-exponentiation-operator": "deny",
+ "prefer-numeric-literals": "deny",
+ "prefer-object-has-own": "deny",
+ "prefer-object-spread": "deny",
+ "prefer-promise-reject-errors": "deny",
+ "prefer-rest-params": "deny",
+ "prefer-spread": "deny",
+ "prefer-template": "deny",
+ "preserve-caught-error": "deny",
+ "require-await": "warn",
+ "require-yield": "deny",
+ "typescript/await-thenable": "deny",
+ "typescript/consistent-type-exports": "deny",
+ "typescript/consistent-type-imports": "deny",
+ "typescript/no-array-delete": "deny",
+ "typescript/no-base-to-string": "deny",
+ "typescript/no-confusing-non-null-assertion": "deny",
+ "typescript/no-duplicate-enum-values": "deny",
+ "typescript/no-duplicate-type-constituents": "deny",
+ "typescript/no-dynamic-delete": "deny",
+ "typescript/no-extra-non-null-assertion": "deny",
+ "typescript/no-extraneous-class": "deny",
+ "typescript/no-floating-promises": "deny",
+ "typescript/no-for-in-array": "deny",
+ "typescript/no-implied-eval": "deny",
+ "typescript/no-import-type-side-effects": "deny",
+ "typescript/no-invalid-void-type": "deny",
+ "typescript/no-meaningless-void-operator": "deny",
+ "typescript/no-misused-new": "deny",
+ "typescript/no-misused-spread": "deny",
+ "typescript/no-non-null-asserted-nullish-coalescing": "deny",
+ "typescript/no-non-null-asserted-optional-chain": "deny",
+ "typescript/no-non-null-assertion": "deny",
+ "typescript/no-redundant-type-constituents": "deny",
+ "typescript/no-this-alias": "deny",
+ "typescript/no-unnecessary-boolean-literal-compare": "deny",
+ "typescript/no-unnecessary-parameter-property-assignment": "deny",
+ "typescript/no-unnecessary-template-expression": "deny",
+ "typescript/no-unnecessary-type-arguments": "deny",
+ "typescript/no-unnecessary-type-assertion": "deny",
+ "typescript/no-unnecessary-type-constraint": "deny",
+ "typescript/no-unsafe-declaration-merging": "deny",
+ "typescript/no-unsafe-enum-comparison": "deny",
+ "typescript/no-unsafe-type-assertion": "deny",
+ "typescript/no-unsafe-unary-minus": "deny",
+ "typescript/no-useless-empty-export": "deny",
+ "typescript/no-wrapper-object-types": "deny",
+ "typescript/prefer-as-const": "deny",
+ "typescript/prefer-literal-enum-member": "deny",
+ "typescript/prefer-namespace-keyword": "deny",
+ "typescript/prefer-reduce-type-parameter": "deny",
+ "typescript/prefer-return-this-type": "deny",
+ "typescript/require-array-sort-compare": "deny",
+ "typescript/restrict-template-expressions": "deny",
+ "typescript/triple-slash-reference": "deny",
+ "typescript/unbound-method": "deny",
+ "typescript/unified-signatures": "deny",
+ "typescript/use-unknown-in-catch-callback-variable": "deny",
+ "unicode-bom": "deny",
+ "use-isnan": "deny",
+ "valid-typeof": "deny",
+ "yoda": "deny"
+ },
+ "settings": {
+ "jsdoc": {
+ "augmentsExtendsReplacesDocs": false,
+ "exemptDestructuredRootsFromChecks": false,
+ "ignoreInternal": false,
+ "ignorePrivate": false,
+ "ignoreReplacesDocs": true,
+ "implementsReplacesDocs": false,
+ "overrideReplacesDocs": true,
+ "tagNamePreference": {}
+ },
+ "jsx-a11y": {
+ "attributes": {},
+ "components": {},
+ "polymorphicPropName": null
+ },
+ "next": {
+ "rootDir": []
+ },
+ "react": {
+ "componentWrapperFunctions": [],
+ "formComponents": [],
+ "linkComponents": [],
+ "version": null
+ },
+ "vitest": {
+ "typecheck": false
+ }
+ }
+}
diff --git a/packages/oxlint-config/test/generated/node-final-config.json b/packages/oxlint-config/test/generated/node-final-config.json
new file mode 100644
index 0000000..28552a3
--- /dev/null
+++ b/packages/oxlint-config/test/generated/node-final-config.json
@@ -0,0 +1,223 @@
+{
+ "categories": {},
+ "env": {
+ "builtin": true
+ },
+ "globals": {},
+ "ignorePatterns": [],
+ "plugins": [
+ "typescript",
+ "import",
+ "node"
+ ],
+ "rules": {
+ "array-callback-return": "deny",
+ "block-scoped-var": "deny",
+ "class-methods-use-this": "warn",
+ "constructor-super": "deny",
+ "default-case": "deny",
+ "default-case-last": "deny",
+ "default-param-last": "deny",
+ "eqeqeq": "deny",
+ "for-direction": "deny",
+ "func-names": "warn",
+ "getter-return": "deny",
+ "import/default": "deny",
+ "import/max-dependencies": "allow",
+ "import/namespace": "deny",
+ "import/no-absolute-path": "deny",
+ "import/no-amd": "deny",
+ "import/no-cycle": "deny",
+ "import/no-duplicates": "deny",
+ "import/no-dynamic-require": "deny",
+ "import/no-empty-named-blocks": "allow",
+ "import/no-mutable-exports": "deny",
+ "import/no-named-as-default": "deny",
+ "import/no-named-as-default-member": "allow",
+ "import/no-named-default": "deny",
+ "import/no-self-import": "deny",
+ "import/no-unassigned-import": "deny",
+ "import/no-webpack-loader-syntax": "deny",
+ "new-cap": "deny",
+ "no-alert": "deny",
+ "no-async-promise-executor": "deny",
+ "no-await-in-loop": "deny",
+ "no-bitwise": "deny",
+ "no-caller": "deny",
+ "no-class-assign": "deny",
+ "no-compare-neg-zero": "deny",
+ "no-cond-assign": "deny",
+ "no-console": "allow",
+ "no-const-assign": "deny",
+ "no-constant-binary-expression": "deny",
+ "no-constant-condition": "deny",
+ "no-continue": "deny",
+ "no-control-regex": "deny",
+ "no-debugger": "deny",
+ "no-delete-var": "deny",
+ "no-dupe-class-members": "deny",
+ "no-dupe-else-if": "deny",
+ "no-dupe-keys": "deny",
+ "no-duplicate-case": "deny",
+ "no-else-return": "deny",
+ "no-empty-character-class": "deny",
+ "no-empty-function": "allow",
+ "no-empty-pattern": "deny",
+ "no-empty-static-block": "deny",
+ "no-eval": "deny",
+ "no-ex-assign": "deny",
+ "no-extend-native": "deny",
+ "no-extra-bind": "deny",
+ "no-extra-boolean-cast": "deny",
+ "no-extra-label": "deny",
+ "no-func-assign": "deny",
+ "no-global-assign": "deny",
+ "no-import-assign": "deny",
+ "no-invalid-regexp": "deny",
+ "no-irregular-whitespace": "deny",
+ "no-iterator": "deny",
+ "no-label-var": "deny",
+ "no-labels": "deny",
+ "no-lone-blocks": "deny",
+ "no-loss-of-precision": "deny",
+ "no-misleading-character-class": "deny",
+ "no-multi-assign": "deny",
+ "no-multi-str": "deny",
+ "no-nested-ternary": "deny",
+ "no-new": "deny",
+ "no-new-func": "deny",
+ "no-new-native-nonconstructor": "deny",
+ "no-nonoctal-decimal-escape": "deny",
+ "no-obj-calls": "deny",
+ "no-param-reassign": "deny",
+ "no-proto": "deny",
+ "no-regex-spaces": "deny",
+ "no-restricted-globals": "deny",
+ "no-restricted-imports": "allow",
+ "no-return-assign": "deny",
+ "no-script-url": "deny",
+ "no-self-assign": "deny",
+ "no-sequences": "deny",
+ "no-setter-return": "deny",
+ "no-shadow": "deny",
+ "no-shadow-restricted-names": "deny",
+ "no-sparse-arrays": "deny",
+ "no-template-curly-in-string": "deny",
+ "no-this-before-super": "deny",
+ "no-unassigned-vars": "deny",
+ "no-unexpected-multiline": "deny",
+ "no-unmodified-loop-condition": "deny",
+ "no-unneeded-ternary": "deny",
+ "no-unreachable": "deny",
+ "no-unsafe-finally": "deny",
+ "no-unsafe-negation": "deny",
+ "no-unsafe-optional-chaining": "deny",
+ "no-unused-expressions": "deny",
+ "no-unused-labels": "deny",
+ "no-unused-private-class-members": "deny",
+ "no-unused-vars": "deny",
+ "no-useless-backreference": "deny",
+ "no-useless-call": "deny",
+ "no-useless-catch": "deny",
+ "no-useless-concat": "deny",
+ "no-useless-constructor": "deny",
+ "no-useless-escape": "deny",
+ "no-useless-rename": "deny",
+ "no-var": "deny",
+ "no-with": "deny",
+ "node/no-path-concat": "deny",
+ "operator-assignment": "deny",
+ "prefer-const": "deny",
+ "prefer-exponentiation-operator": "deny",
+ "prefer-numeric-literals": "deny",
+ "prefer-object-has-own": "deny",
+ "prefer-object-spread": "deny",
+ "prefer-promise-reject-errors": "deny",
+ "prefer-rest-params": "deny",
+ "prefer-spread": "deny",
+ "prefer-template": "deny",
+ "preserve-caught-error": "deny",
+ "require-await": "warn",
+ "require-yield": "deny",
+ "typescript/await-thenable": "deny",
+ "typescript/consistent-type-exports": "deny",
+ "typescript/consistent-type-imports": "deny",
+ "typescript/no-array-delete": "deny",
+ "typescript/no-base-to-string": "deny",
+ "typescript/no-confusing-non-null-assertion": "deny",
+ "typescript/no-duplicate-enum-values": "deny",
+ "typescript/no-duplicate-type-constituents": "deny",
+ "typescript/no-dynamic-delete": "deny",
+ "typescript/no-extra-non-null-assertion": "deny",
+ "typescript/no-extraneous-class": "deny",
+ "typescript/no-floating-promises": "deny",
+ "typescript/no-for-in-array": "deny",
+ "typescript/no-implied-eval": "deny",
+ "typescript/no-import-type-side-effects": "deny",
+ "typescript/no-invalid-void-type": "deny",
+ "typescript/no-meaningless-void-operator": "deny",
+ "typescript/no-misused-new": "deny",
+ "typescript/no-misused-spread": "deny",
+ "typescript/no-non-null-asserted-nullish-coalescing": "deny",
+ "typescript/no-non-null-asserted-optional-chain": "deny",
+ "typescript/no-non-null-assertion": "deny",
+ "typescript/no-redundant-type-constituents": "deny",
+ "typescript/no-this-alias": "deny",
+ "typescript/no-unnecessary-boolean-literal-compare": "deny",
+ "typescript/no-unnecessary-parameter-property-assignment": "deny",
+ "typescript/no-unnecessary-template-expression": "deny",
+ "typescript/no-unnecessary-type-arguments": "deny",
+ "typescript/no-unnecessary-type-assertion": "deny",
+ "typescript/no-unnecessary-type-constraint": "deny",
+ "typescript/no-unsafe-declaration-merging": "deny",
+ "typescript/no-unsafe-enum-comparison": "deny",
+ "typescript/no-unsafe-type-assertion": "deny",
+ "typescript/no-unsafe-unary-minus": "deny",
+ "typescript/no-useless-empty-export": "deny",
+ "typescript/no-wrapper-object-types": "deny",
+ "typescript/prefer-as-const": "deny",
+ "typescript/prefer-literal-enum-member": "deny",
+ "typescript/prefer-namespace-keyword": "deny",
+ "typescript/prefer-reduce-type-parameter": "deny",
+ "typescript/prefer-return-this-type": "deny",
+ "typescript/require-array-sort-compare": "deny",
+ "typescript/restrict-template-expressions": "deny",
+ "typescript/triple-slash-reference": "deny",
+ "typescript/unbound-method": "deny",
+ "typescript/unified-signatures": "deny",
+ "typescript/use-unknown-in-catch-callback-variable": "deny",
+ "unicode-bom": "deny",
+ "use-isnan": "deny",
+ "valid-typeof": "deny",
+ "yoda": "deny"
+ },
+ "settings": {
+ "jsdoc": {
+ "augmentsExtendsReplacesDocs": false,
+ "exemptDestructuredRootsFromChecks": false,
+ "ignoreInternal": false,
+ "ignorePrivate": false,
+ "ignoreReplacesDocs": true,
+ "implementsReplacesDocs": false,
+ "overrideReplacesDocs": true,
+ "tagNamePreference": {}
+ },
+ "jsx-a11y": {
+ "attributes": {},
+ "components": {},
+ "polymorphicPropName": null
+ },
+ "next": {
+ "rootDir": []
+ },
+ "react": {
+ "componentWrapperFunctions": [],
+ "formComponents": [],
+ "linkComponents": [],
+ "version": null
+ },
+ "vitest": {
+ "typecheck": false
+ }
+ }
+}
diff --git a/packages/oxlint-config/test/generated/react-final-config.json b/packages/oxlint-config/test/generated/react-final-config.json
new file mode 100644
index 0000000..5d575d9
--- /dev/null
+++ b/packages/oxlint-config/test/generated/react-final-config.json
@@ -0,0 +1,322 @@
+{
+ "categories": {},
+ "env": {
+ "builtin": true
+ },
+ "globals": {},
+ "ignorePatterns": [],
+ "plugins": [
+ "react",
+ "typescript",
+ "import",
+ "jsx-a11y"
+ ],
+ "rules": {
+ "array-callback-return": "deny",
+ "block-scoped-var": "deny",
+ "class-methods-use-this": "warn",
+ "constructor-super": "deny",
+ "default-case": "deny",
+ "default-case-last": "deny",
+ "default-param-last": "deny",
+ "eqeqeq": "deny",
+ "for-direction": "deny",
+ "func-names": "warn",
+ "getter-return": "deny",
+ "import/default": "deny",
+ "import/max-dependencies": "allow",
+ "import/namespace": "deny",
+ "import/no-absolute-path": "deny",
+ "import/no-amd": "deny",
+ "import/no-cycle": "deny",
+ "import/no-duplicates": "deny",
+ "import/no-dynamic-require": "deny",
+ "import/no-empty-named-blocks": "allow",
+ "import/no-mutable-exports": "deny",
+ "import/no-named-as-default": "deny",
+ "import/no-named-as-default-member": "allow",
+ "import/no-named-default": "deny",
+ "import/no-self-import": "deny",
+ "import/no-unassigned-import": "deny",
+ "import/no-webpack-loader-syntax": "deny",
+ "jsx_a11y/alt-text": "deny",
+ "jsx_a11y/anchor-has-content": "deny",
+ "jsx_a11y/anchor-is-valid": [
+ "deny",
+ [
+ {
+ "aspects": [
+ "noHref",
+ "invalidHref",
+ "preferButton"
+ ],
+ "components": [
+ "Link"
+ ],
+ "specialLink": [
+ "to"
+ ]
+ }
+ ]
+ ],
+ "jsx_a11y/aria-activedescendant-has-tabindex": "deny",
+ "jsx_a11y/aria-props": "deny",
+ "jsx_a11y/aria-proptypes": "deny",
+ "jsx_a11y/aria-role": "deny",
+ "jsx_a11y/aria-unsupported-elements": "deny",
+ "jsx_a11y/autocomplete-valid": "deny",
+ "jsx_a11y/click-events-have-key-events": "deny",
+ "jsx_a11y/heading-has-content": "deny",
+ "jsx_a11y/html-has-lang": "deny",
+ "jsx_a11y/iframe-has-title": "deny",
+ "jsx_a11y/img-redundant-alt": "deny",
+ "jsx_a11y/label-has-associated-control": [
+ "deny",
+ [
+ {
+ "assert": "both",
+ "depth": 25
+ }
+ ]
+ ],
+ "jsx_a11y/lang": "deny",
+ "jsx_a11y/media-has-caption": "deny",
+ "jsx_a11y/mouse-events-have-key-events": "deny",
+ "jsx_a11y/no-access-key": "deny",
+ "jsx_a11y/no-aria-hidden-on-focusable": "deny",
+ "jsx_a11y/no-autofocus": [
+ "deny",
+ [
+ {
+ "ignoreNonDOM": true
+ }
+ ]
+ ],
+ "jsx_a11y/no-distracting-elements": "deny",
+ "jsx_a11y/no-noninteractive-tabindex": "deny",
+ "jsx_a11y/no-redundant-roles": "deny",
+ "jsx_a11y/no-static-element-interactions": "deny",
+ "jsx_a11y/prefer-tag-over-role": "deny",
+ "jsx_a11y/role-has-required-aria-props": "deny",
+ "jsx_a11y/role-supports-aria-props": "deny",
+ "jsx_a11y/scope": "deny",
+ "jsx_a11y/tabindex-no-positive": "deny",
+ "new-cap": "deny",
+ "no-alert": "deny",
+ "no-async-promise-executor": "deny",
+ "no-await-in-loop": "deny",
+ "no-bitwise": "deny",
+ "no-caller": "deny",
+ "no-class-assign": "deny",
+ "no-compare-neg-zero": "deny",
+ "no-cond-assign": "deny",
+ "no-console": "warn",
+ "no-const-assign": "deny",
+ "no-constant-binary-expression": "deny",
+ "no-constant-condition": "deny",
+ "no-continue": "deny",
+ "no-control-regex": "deny",
+ "no-debugger": "deny",
+ "no-delete-var": "deny",
+ "no-dupe-class-members": "deny",
+ "no-dupe-else-if": "deny",
+ "no-dupe-keys": "deny",
+ "no-duplicate-case": "deny",
+ "no-else-return": "deny",
+ "no-empty-character-class": "deny",
+ "no-empty-function": "allow",
+ "no-empty-pattern": "deny",
+ "no-empty-static-block": "deny",
+ "no-eval": "deny",
+ "no-ex-assign": "deny",
+ "no-extend-native": "deny",
+ "no-extra-bind": "deny",
+ "no-extra-boolean-cast": "deny",
+ "no-extra-label": "deny",
+ "no-func-assign": "deny",
+ "no-global-assign": "deny",
+ "no-import-assign": "deny",
+ "no-invalid-regexp": "deny",
+ "no-irregular-whitespace": "deny",
+ "no-iterator": "deny",
+ "no-label-var": "deny",
+ "no-labels": "deny",
+ "no-lone-blocks": "deny",
+ "no-loss-of-precision": "deny",
+ "no-misleading-character-class": "deny",
+ "no-multi-assign": "deny",
+ "no-multi-str": "deny",
+ "no-nested-ternary": "deny",
+ "no-new": "deny",
+ "no-new-func": "deny",
+ "no-new-native-nonconstructor": "deny",
+ "no-nonoctal-decimal-escape": "deny",
+ "no-obj-calls": "deny",
+ "no-param-reassign": "deny",
+ "no-proto": "deny",
+ "no-regex-spaces": "deny",
+ "no-restricted-globals": "deny",
+ "no-restricted-imports": "allow",
+ "no-return-assign": "deny",
+ "no-script-url": "deny",
+ "no-self-assign": "deny",
+ "no-sequences": "deny",
+ "no-setter-return": "deny",
+ "no-shadow": "deny",
+ "no-shadow-restricted-names": "deny",
+ "no-sparse-arrays": "deny",
+ "no-template-curly-in-string": "deny",
+ "no-this-before-super": "deny",
+ "no-unassigned-vars": "deny",
+ "no-unexpected-multiline": "deny",
+ "no-unmodified-loop-condition": "deny",
+ "no-unneeded-ternary": "deny",
+ "no-unreachable": "deny",
+ "no-unsafe-finally": "deny",
+ "no-unsafe-negation": "deny",
+ "no-unsafe-optional-chaining": "deny",
+ "no-unused-expressions": "deny",
+ "no-unused-labels": "deny",
+ "no-unused-private-class-members": "deny",
+ "no-unused-vars": "deny",
+ "no-useless-backreference": "deny",
+ "no-useless-call": "deny",
+ "no-useless-catch": "deny",
+ "no-useless-concat": "deny",
+ "no-useless-constructor": "deny",
+ "no-useless-escape": "deny",
+ "no-useless-rename": "deny",
+ "no-var": "deny",
+ "no-with": "deny",
+ "operator-assignment": "deny",
+ "prefer-const": "deny",
+ "prefer-exponentiation-operator": "deny",
+ "prefer-numeric-literals": "deny",
+ "prefer-object-has-own": "deny",
+ "prefer-object-spread": "deny",
+ "prefer-promise-reject-errors": "deny",
+ "prefer-rest-params": "deny",
+ "prefer-spread": "deny",
+ "prefer-template": "deny",
+ "preserve-caught-error": "deny",
+ "react/exhaustive-deps": "deny",
+ "react/forward-ref-uses-ref": "deny",
+ "react/iframe-missing-sandbox": "deny",
+ "react/jsx-boolean-value": [
+ "deny",
+ [
+ "never"
+ ]
+ ],
+ "react/jsx-key": "deny",
+ "react/jsx-no-comment-textnodes": "deny",
+ "react/jsx-no-duplicate-props": "deny",
+ "react/jsx-no-script-url": "deny",
+ "react/jsx-no-target-blank": "deny",
+ "react/jsx-no-undef": "deny",
+ "react/jsx-no-useless-fragment": "deny",
+ "react/jsx-pascal-case": "deny",
+ "react/jsx-props-no-spread-multi": "deny",
+ "react/no-children-prop": "deny",
+ "react/no-danger": "warn",
+ "react/no-danger-with-children": "deny",
+ "react/no-did-mount-set-state": "deny",
+ "react/no-direct-mutation-state": "deny",
+ "react/no-find-dom-node": "deny",
+ "react/no-is-mounted": "deny",
+ "react/no-namespace": "deny",
+ "react/no-render-return-value": "deny",
+ "react/no-string-refs": "deny",
+ "react/no-this-in-sfc": "deny",
+ "react/no-unknown-property": "deny",
+ "react/no-unsafe": "deny",
+ "react/no-will-update-set-state": "deny",
+ "react/react-in-jsx-scope": "allow",
+ "react/rules-of-hooks": "deny",
+ "react/self-closing-comp": "deny",
+ "react/style-prop-object": "deny",
+ "react/void-dom-elements-no-children": "deny",
+ "require-await": "warn",
+ "require-yield": "deny",
+ "typescript/await-thenable": "deny",
+ "typescript/consistent-type-exports": "deny",
+ "typescript/consistent-type-imports": "deny",
+ "typescript/no-array-delete": "deny",
+ "typescript/no-base-to-string": "deny",
+ "typescript/no-confusing-non-null-assertion": "deny",
+ "typescript/no-duplicate-enum-values": "deny",
+ "typescript/no-duplicate-type-constituents": "deny",
+ "typescript/no-dynamic-delete": "deny",
+ "typescript/no-extra-non-null-assertion": "deny",
+ "typescript/no-extraneous-class": "deny",
+ "typescript/no-floating-promises": "deny",
+ "typescript/no-for-in-array": "deny",
+ "typescript/no-implied-eval": "deny",
+ "typescript/no-import-type-side-effects": "deny",
+ "typescript/no-invalid-void-type": "deny",
+ "typescript/no-meaningless-void-operator": "deny",
+ "typescript/no-misused-new": "deny",
+ "typescript/no-misused-spread": "deny",
+ "typescript/no-non-null-asserted-nullish-coalescing": "deny",
+ "typescript/no-non-null-asserted-optional-chain": "deny",
+ "typescript/no-non-null-assertion": "deny",
+ "typescript/no-redundant-type-constituents": "deny",
+ "typescript/no-this-alias": "deny",
+ "typescript/no-unnecessary-boolean-literal-compare": "deny",
+ "typescript/no-unnecessary-parameter-property-assignment": "deny",
+ "typescript/no-unnecessary-template-expression": "deny",
+ "typescript/no-unnecessary-type-arguments": "deny",
+ "typescript/no-unnecessary-type-assertion": "deny",
+ "typescript/no-unnecessary-type-constraint": "deny",
+ "typescript/no-unsafe-declaration-merging": "deny",
+ "typescript/no-unsafe-enum-comparison": "deny",
+ "typescript/no-unsafe-type-assertion": "deny",
+ "typescript/no-unsafe-unary-minus": "deny",
+ "typescript/no-useless-empty-export": "deny",
+ "typescript/no-wrapper-object-types": "deny",
+ "typescript/prefer-as-const": "deny",
+ "typescript/prefer-literal-enum-member": "deny",
+ "typescript/prefer-namespace-keyword": "deny",
+ "typescript/prefer-reduce-type-parameter": "deny",
+ "typescript/prefer-return-this-type": "deny",
+ "typescript/require-array-sort-compare": "deny",
+ "typescript/restrict-template-expressions": "deny",
+ "typescript/triple-slash-reference": "deny",
+ "typescript/unbound-method": "deny",
+ "typescript/unified-signatures": "deny",
+ "typescript/use-unknown-in-catch-callback-variable": "deny",
+ "unicode-bom": "deny",
+ "use-isnan": "deny",
+ "valid-typeof": "deny",
+ "yoda": "deny"
+ },
+ "settings": {
+ "jsdoc": {
+ "augmentsExtendsReplacesDocs": false,
+ "exemptDestructuredRootsFromChecks": false,
+ "ignoreInternal": false,
+ "ignorePrivate": false,
+ "ignoreReplacesDocs": true,
+ "implementsReplacesDocs": false,
+ "overrideReplacesDocs": true,
+ "tagNamePreference": {}
+ },
+ "jsx-a11y": {
+ "attributes": {},
+ "components": {},
+ "polymorphicPropName": null
+ },
+ "next": {
+ "rootDir": []
+ },
+ "react": {
+ "componentWrapperFunctions": [],
+ "formComponents": [],
+ "linkComponents": [],
+ "version": null
+ },
+ "vitest": {
+ "typecheck": false
+ }
+ }
+}
diff --git a/packages/oxlint-config/test/generated/recommended-final-config.json b/packages/oxlint-config/test/generated/recommended-final-config.json
new file mode 100644
index 0000000..b51395f
--- /dev/null
+++ b/packages/oxlint-config/test/generated/recommended-final-config.json
@@ -0,0 +1,556 @@
+{
+ "categories": {
+ "correctness": "deny",
+ "suspicious": "deny"
+ },
+ "env": {
+ "builtin": true
+ },
+ "globals": {},
+ "ignorePatterns": [],
+ "plugins": [
+ "typescript",
+ "import"
+ ],
+ "rules": {
+ "array-callback-return": [
+ "deny",
+ [
+ {
+ "allowImplicit": true
+ }
+ ]
+ ],
+ "block-scoped-var": "deny",
+ "class-methods-use-this": "warn",
+ "constructor-super": "deny",
+ "default-case": "deny",
+ "default-case-last": "deny",
+ "default-param-last": "deny",
+ "eqeqeq": [
+ "deny",
+ [
+ "always",
+ {
+ "null": "ignore"
+ }
+ ]
+ ],
+ "for-direction": "deny",
+ "func-names": "warn",
+ "getter-return": [
+ "deny",
+ [
+ {
+ "allowImplicit": true
+ }
+ ]
+ ],
+ "import/default": "deny",
+ "import/max-dependencies": "allow",
+ "import/namespace": "deny",
+ "import/no-absolute-path": "deny",
+ "import/no-amd": "deny",
+ "import/no-cycle": [
+ "deny",
+ [
+ {
+ "ignoreExternal": true
+ }
+ ]
+ ],
+ "import/no-duplicates": "deny",
+ "import/no-dynamic-require": "deny",
+ "import/no-empty-named-blocks": "allow",
+ "import/no-mutable-exports": "deny",
+ "import/no-named-as-default": "deny",
+ "import/no-named-as-default-member": "allow",
+ "import/no-named-default": "deny",
+ "import/no-self-import": "deny",
+ "import/no-unassigned-import": "deny",
+ "import/no-webpack-loader-syntax": "deny",
+ "new-cap": [
+ "deny",
+ [
+ {
+ "capIsNew": false,
+ "newIsCap": true
+ }
+ ]
+ ],
+ "no-alert": "deny",
+ "no-async-promise-executor": "deny",
+ "no-await-in-loop": "deny",
+ "no-bitwise": "deny",
+ "no-caller": "deny",
+ "no-class-assign": "deny",
+ "no-compare-neg-zero": "deny",
+ "no-cond-assign": "deny",
+ "no-console": "warn",
+ "no-const-assign": "deny",
+ "no-constant-binary-expression": "deny",
+ "no-constant-condition": "deny",
+ "no-continue": "deny",
+ "no-control-regex": "deny",
+ "no-debugger": "deny",
+ "no-delete-var": "deny",
+ "no-dupe-class-members": "deny",
+ "no-dupe-else-if": "deny",
+ "no-dupe-keys": "deny",
+ "no-duplicate-case": "deny",
+ "no-else-return": [
+ "deny",
+ [
+ {
+ "allowElseIf": false
+ }
+ ]
+ ],
+ "no-empty-character-class": "deny",
+ "no-empty-function": "allow",
+ "no-empty-pattern": "deny",
+ "no-empty-static-block": "deny",
+ "no-eval": "deny",
+ "no-ex-assign": "deny",
+ "no-extend-native": "deny",
+ "no-extra-bind": "deny",
+ "no-extra-boolean-cast": "deny",
+ "no-extra-label": "deny",
+ "no-func-assign": "deny",
+ "no-global-assign": "deny",
+ "no-import-assign": "deny",
+ "no-invalid-regexp": "deny",
+ "no-irregular-whitespace": "deny",
+ "no-iterator": "deny",
+ "no-label-var": "deny",
+ "no-labels": "deny",
+ "no-lone-blocks": "deny",
+ "no-loss-of-precision": "deny",
+ "no-misleading-character-class": "deny",
+ "no-multi-assign": "deny",
+ "no-multi-str": "deny",
+ "no-nested-ternary": "deny",
+ "no-new": "deny",
+ "no-new-func": "deny",
+ "no-new-native-nonconstructor": "deny",
+ "no-nonoctal-decimal-escape": "deny",
+ "no-obj-calls": "deny",
+ "no-param-reassign": [
+ "deny",
+ [
+ {
+ "ignorePropertyModificationsFor": [
+ "prev",
+ "acc",
+ "accumulator",
+ "e",
+ "ctx",
+ "context",
+ "req",
+ "request",
+ "res",
+ "response",
+ "$scope",
+ "staticContext",
+ "sharedState",
+ "state"
+ ],
+ "props": true
+ }
+ ]
+ ],
+ "no-proto": "deny",
+ "no-regex-spaces": "deny",
+ "no-restricted-globals": [
+ "deny",
+ [
+ {
+ "message": "Use Number.isFinite instead",
+ "name": "isFinite"
+ },
+ {
+ "message": "Use Number.isNaN instead",
+ "name": "isNaN"
+ },
+ {
+ "message": "Use window.addEventListener instead",
+ "name": "addEventListener"
+ },
+ {
+ "message": "Use window.blur instead",
+ "name": "blur"
+ },
+ {
+ "message": "Use window.close instead",
+ "name": "close"
+ },
+ {
+ "message": "Use window.closed instead",
+ "name": "closed"
+ },
+ {
+ "message": "Use window.confirm instead",
+ "name": "confirm"
+ },
+ {
+ "message": "Use window.defaultStatus instead",
+ "name": "defaultStatus"
+ },
+ {
+ "message": "Use window.defaultstatus instead",
+ "name": "defaultstatus"
+ },
+ {
+ "message": "Use window.error instead",
+ "name": "error"
+ },
+ {
+ "message": "Use window.event instead",
+ "name": "event"
+ },
+ {
+ "message": "Use window.find instead",
+ "name": "find"
+ },
+ {
+ "message": "Use window.focus instead",
+ "name": "focus"
+ },
+ {
+ "message": "Use window.frameElement instead",
+ "name": "frameElement"
+ },
+ {
+ "message": "Use window.frames instead",
+ "name": "frames"
+ },
+ {
+ "message": "Use window.history instead",
+ "name": "history"
+ },
+ {
+ "message": "Use window.innerHeight instead",
+ "name": "innerHeight"
+ },
+ {
+ "message": "Use window.innerWidth instead",
+ "name": "innerWidth"
+ },
+ {
+ "message": "Use window.length instead",
+ "name": "length"
+ },
+ {
+ "message": "Use window.localStorage instead",
+ "name": "localStorage"
+ },
+ {
+ "message": "Use window.location instead",
+ "name": "location"
+ },
+ {
+ "message": "Use window.menubar instead",
+ "name": "menubar"
+ },
+ {
+ "message": "Use window.moveBy instead",
+ "name": "moveBy"
+ },
+ {
+ "message": "Use window.moveTo instead",
+ "name": "moveTo"
+ },
+ {
+ "message": "Use window.name instead",
+ "name": "name"
+ },
+ {
+ "message": "Use window.onblur instead",
+ "name": "onblur"
+ },
+ {
+ "message": "Use window.onerror instead",
+ "name": "onerror"
+ },
+ {
+ "message": "Use window.onfocus instead",
+ "name": "onfocus"
+ },
+ {
+ "message": "Use window.onload instead",
+ "name": "onload"
+ },
+ {
+ "message": "Use window.onresize instead",
+ "name": "onresize"
+ },
+ {
+ "message": "Use window.onunload instead",
+ "name": "onunload"
+ },
+ {
+ "message": "Use window.open instead",
+ "name": "open"
+ },
+ {
+ "message": "Use window.opener instead",
+ "name": "opener"
+ },
+ {
+ "message": "Use window.opera instead",
+ "name": "opera"
+ },
+ {
+ "message": "Use window.outerHeight instead",
+ "name": "outerHeight"
+ },
+ {
+ "message": "Use window.outerWidth instead",
+ "name": "outerWidth"
+ },
+ {
+ "message": "Use window.pageXOffset instead",
+ "name": "pageXOffset"
+ },
+ {
+ "message": "Use window.pageYOffset instead",
+ "name": "pageYOffset"
+ },
+ {
+ "message": "Use window.parent instead",
+ "name": "parent"
+ },
+ {
+ "message": "Use window.print instead",
+ "name": "print"
+ },
+ {
+ "message": "Use window.removeEventListener instead",
+ "name": "removeEventListener"
+ },
+ {
+ "message": "Use window.resizeBy instead",
+ "name": "resizeBy"
+ },
+ {
+ "message": "Use window.resizeTo instead",
+ "name": "resizeTo"
+ },
+ {
+ "message": "Use window.screen instead",
+ "name": "screen"
+ },
+ {
+ "message": "Use window.screenLeft instead",
+ "name": "screenLeft"
+ },
+ {
+ "message": "Use window.screenTop instead",
+ "name": "screenTop"
+ },
+ {
+ "message": "Use window.screenX instead",
+ "name": "screenX"
+ },
+ {
+ "message": "Use window.screenY instead",
+ "name": "screenY"
+ },
+ {
+ "message": "Use window.scroll instead",
+ "name": "scroll"
+ },
+ {
+ "message": "Use window.scrollbars instead",
+ "name": "scrollbars"
+ },
+ {
+ "message": "Use window.scrollBy instead",
+ "name": "scrollBy"
+ },
+ {
+ "message": "Use window.scrollTo instead",
+ "name": "scrollTo"
+ },
+ {
+ "message": "Use window.scrollX instead",
+ "name": "scrollX"
+ },
+ {
+ "message": "Use window.scrollY instead",
+ "name": "scrollY"
+ },
+ {
+ "message": "Use window.self instead",
+ "name": "self"
+ },
+ {
+ "message": "Use window.sessionStorage instead",
+ "name": "sessionStorage"
+ },
+ {
+ "message": "Use window.status instead",
+ "name": "status"
+ },
+ {
+ "message": "Use window.statusbar instead",
+ "name": "statusbar"
+ },
+ {
+ "message": "Use window.stop instead",
+ "name": "stop"
+ },
+ {
+ "message": "Use window.toolbar instead",
+ "name": "toolbar"
+ },
+ {
+ "message": "Use window.top instead",
+ "name": "top"
+ }
+ ]
+ ],
+ "no-restricted-imports": "allow",
+ "no-return-assign": [
+ "deny",
+ [
+ "always"
+ ]
+ ],
+ "no-script-url": "deny",
+ "no-self-assign": "deny",
+ "no-sequences": "deny",
+ "no-setter-return": "deny",
+ "no-shadow": "deny",
+ "no-shadow-restricted-names": "deny",
+ "no-sparse-arrays": "deny",
+ "no-template-curly-in-string": "deny",
+ "no-this-before-super": "deny",
+ "no-unassigned-vars": "deny",
+ "no-unexpected-multiline": "deny",
+ "no-unmodified-loop-condition": "deny",
+ "no-unneeded-ternary": "deny",
+ "no-unreachable": "deny",
+ "no-unsafe-finally": "deny",
+ "no-unsafe-negation": "deny",
+ "no-unsafe-optional-chaining": "deny",
+ "no-unused-expressions": "deny",
+ "no-unused-labels": "deny",
+ "no-unused-private-class-members": "deny",
+ "no-unused-vars": "deny",
+ "no-useless-backreference": "deny",
+ "no-useless-call": "deny",
+ "no-useless-catch": "deny",
+ "no-useless-concat": "deny",
+ "no-useless-constructor": "deny",
+ "no-useless-escape": "deny",
+ "no-useless-rename": "deny",
+ "no-var": "deny",
+ "no-with": "deny",
+ "operator-assignment": "deny",
+ "prefer-const": "deny",
+ "prefer-exponentiation-operator": "deny",
+ "prefer-numeric-literals": "deny",
+ "prefer-object-has-own": "deny",
+ "prefer-object-spread": "deny",
+ "prefer-promise-reject-errors": [
+ "deny",
+ [
+ {
+ "allowEmptyReject": true
+ }
+ ]
+ ],
+ "prefer-rest-params": "deny",
+ "prefer-spread": "deny",
+ "prefer-template": "deny",
+ "preserve-caught-error": "deny",
+ "require-await": "warn",
+ "require-yield": "deny",
+ "typescript/await-thenable": "deny",
+ "typescript/consistent-type-exports": "deny",
+ "typescript/consistent-type-imports": "deny",
+ "typescript/no-array-delete": "deny",
+ "typescript/no-base-to-string": "deny",
+ "typescript/no-confusing-non-null-assertion": "deny",
+ "typescript/no-duplicate-enum-values": "deny",
+ "typescript/no-duplicate-type-constituents": "deny",
+ "typescript/no-dynamic-delete": "deny",
+ "typescript/no-extra-non-null-assertion": "deny",
+ "typescript/no-extraneous-class": "deny",
+ "typescript/no-floating-promises": "deny",
+ "typescript/no-for-in-array": "deny",
+ "typescript/no-implied-eval": "deny",
+ "typescript/no-import-type-side-effects": "deny",
+ "typescript/no-invalid-void-type": "deny",
+ "typescript/no-meaningless-void-operator": "deny",
+ "typescript/no-misused-new": "deny",
+ "typescript/no-misused-spread": "deny",
+ "typescript/no-non-null-asserted-nullish-coalescing": "deny",
+ "typescript/no-non-null-asserted-optional-chain": "deny",
+ "typescript/no-non-null-assertion": "deny",
+ "typescript/no-redundant-type-constituents": "deny",
+ "typescript/no-this-alias": "deny",
+ "typescript/no-unnecessary-boolean-literal-compare": "deny",
+ "typescript/no-unnecessary-parameter-property-assignment": "deny",
+ "typescript/no-unnecessary-template-expression": "deny",
+ "typescript/no-unnecessary-type-arguments": "deny",
+ "typescript/no-unnecessary-type-assertion": "deny",
+ "typescript/no-unnecessary-type-constraint": "deny",
+ "typescript/no-unsafe-declaration-merging": "deny",
+ "typescript/no-unsafe-enum-comparison": "deny",
+ "typescript/no-unsafe-type-assertion": "deny",
+ "typescript/no-unsafe-unary-minus": "deny",
+ "typescript/no-useless-empty-export": "deny",
+ "typescript/no-wrapper-object-types": "deny",
+ "typescript/prefer-as-const": "deny",
+ "typescript/prefer-literal-enum-member": "deny",
+ "typescript/prefer-namespace-keyword": "deny",
+ "typescript/prefer-reduce-type-parameter": "deny",
+ "typescript/prefer-return-this-type": "deny",
+ "typescript/require-array-sort-compare": "deny",
+ "typescript/restrict-template-expressions": "deny",
+ "typescript/triple-slash-reference": "deny",
+ "typescript/unbound-method": "deny",
+ "typescript/unified-signatures": "deny",
+ "typescript/use-unknown-in-catch-callback-variable": "deny",
+ "unicode-bom": [
+ "deny",
+ [
+ "never"
+ ]
+ ],
+ "use-isnan": "deny",
+ "valid-typeof": "deny",
+ "yoda": "deny"
+ },
+ "settings": {
+ "jsdoc": {
+ "augmentsExtendsReplacesDocs": false,
+ "exemptDestructuredRootsFromChecks": false,
+ "ignoreInternal": false,
+ "ignorePrivate": false,
+ "ignoreReplacesDocs": true,
+ "implementsReplacesDocs": false,
+ "overrideReplacesDocs": true,
+ "tagNamePreference": {}
+ },
+ "jsx-a11y": {
+ "attributes": {},
+ "components": {},
+ "polymorphicPropName": null
+ },
+ "next": {
+ "rootDir": []
+ },
+ "react": {
+ "componentWrapperFunctions": [],
+ "formComponents": [],
+ "linkComponents": [],
+ "version": null
+ },
+ "vitest": {
+ "typecheck": false
+ }
+ }
+}
diff --git a/packages/oxlint-config/test/generated/vitest-final-config.json b/packages/oxlint-config/test/generated/vitest-final-config.json
new file mode 100644
index 0000000..3cf8dcd
--- /dev/null
+++ b/packages/oxlint-config/test/generated/vitest-final-config.json
@@ -0,0 +1,238 @@
+{
+ "categories": {},
+ "env": {
+ "builtin": true
+ },
+ "globals": {},
+ "ignorePatterns": [],
+ "plugins": [
+ "typescript",
+ "import",
+ "vitest"
+ ],
+ "rules": {
+ "array-callback-return": "deny",
+ "block-scoped-var": "deny",
+ "class-methods-use-this": "warn",
+ "constructor-super": "deny",
+ "default-case": "deny",
+ "default-case-last": "deny",
+ "default-param-last": "deny",
+ "eqeqeq": "deny",
+ "for-direction": "deny",
+ "func-names": "warn",
+ "getter-return": "deny",
+ "import/default": "deny",
+ "import/max-dependencies": "allow",
+ "import/namespace": "deny",
+ "import/no-absolute-path": "deny",
+ "import/no-amd": "deny",
+ "import/no-cycle": "deny",
+ "import/no-duplicates": "deny",
+ "import/no-dynamic-require": "deny",
+ "import/no-empty-named-blocks": "allow",
+ "import/no-mutable-exports": "deny",
+ "import/no-named-as-default": "deny",
+ "import/no-named-as-default-member": "allow",
+ "import/no-named-default": "deny",
+ "import/no-self-import": "deny",
+ "import/no-unassigned-import": "deny",
+ "import/no-webpack-loader-syntax": "deny",
+ "jest/expect-expect": "deny",
+ "jest/no-commented-out-tests": "deny",
+ "jest/no-conditional-expect": "deny",
+ "jest/no-disabled-tests": "deny",
+ "jest/no-export": "deny",
+ "jest/no-focused-tests": "deny",
+ "jest/no-standalone-expect": "deny",
+ "jest/require-to-throw-message": "deny",
+ "jest/valid-describe-callback": "deny",
+ "jest/valid-expect": "deny",
+ "jest/valid-title": "deny",
+ "new-cap": "deny",
+ "no-alert": "deny",
+ "no-async-promise-executor": "deny",
+ "no-await-in-loop": "deny",
+ "no-bitwise": "deny",
+ "no-caller": "deny",
+ "no-class-assign": "deny",
+ "no-compare-neg-zero": "deny",
+ "no-cond-assign": "deny",
+ "no-console": "allow",
+ "no-const-assign": "deny",
+ "no-constant-binary-expression": "deny",
+ "no-constant-condition": "deny",
+ "no-continue": "deny",
+ "no-control-regex": "deny",
+ "no-debugger": "deny",
+ "no-delete-var": "deny",
+ "no-dupe-class-members": "deny",
+ "no-dupe-else-if": "deny",
+ "no-dupe-keys": "deny",
+ "no-duplicate-case": "deny",
+ "no-else-return": "deny",
+ "no-empty-character-class": "deny",
+ "no-empty-function": "allow",
+ "no-empty-pattern": "deny",
+ "no-empty-static-block": "deny",
+ "no-eval": "deny",
+ "no-ex-assign": "deny",
+ "no-extend-native": "deny",
+ "no-extra-bind": "deny",
+ "no-extra-boolean-cast": "deny",
+ "no-extra-label": "deny",
+ "no-func-assign": "deny",
+ "no-global-assign": "deny",
+ "no-import-assign": "deny",
+ "no-invalid-regexp": "deny",
+ "no-irregular-whitespace": "deny",
+ "no-iterator": "deny",
+ "no-label-var": "deny",
+ "no-labels": "deny",
+ "no-lone-blocks": "deny",
+ "no-loss-of-precision": "deny",
+ "no-misleading-character-class": "deny",
+ "no-multi-assign": "deny",
+ "no-multi-str": "deny",
+ "no-nested-ternary": "deny",
+ "no-new": "deny",
+ "no-new-func": "deny",
+ "no-new-native-nonconstructor": "deny",
+ "no-nonoctal-decimal-escape": "deny",
+ "no-obj-calls": "deny",
+ "no-param-reassign": "deny",
+ "no-proto": "deny",
+ "no-regex-spaces": "deny",
+ "no-restricted-globals": "deny",
+ "no-restricted-imports": "allow",
+ "no-return-assign": "deny",
+ "no-script-url": "deny",
+ "no-self-assign": "deny",
+ "no-sequences": "deny",
+ "no-setter-return": "deny",
+ "no-shadow": "deny",
+ "no-shadow-restricted-names": "deny",
+ "no-sparse-arrays": "deny",
+ "no-template-curly-in-string": "deny",
+ "no-this-before-super": "deny",
+ "no-unassigned-vars": "deny",
+ "no-unexpected-multiline": "deny",
+ "no-unmodified-loop-condition": "deny",
+ "no-unneeded-ternary": "deny",
+ "no-unreachable": "deny",
+ "no-unsafe-finally": "deny",
+ "no-unsafe-negation": "deny",
+ "no-unsafe-optional-chaining": "deny",
+ "no-unused-expressions": "deny",
+ "no-unused-labels": "deny",
+ "no-unused-private-class-members": "deny",
+ "no-unused-vars": "deny",
+ "no-useless-backreference": "deny",
+ "no-useless-call": "deny",
+ "no-useless-catch": "deny",
+ "no-useless-concat": "deny",
+ "no-useless-constructor": "deny",
+ "no-useless-escape": "deny",
+ "no-useless-rename": "deny",
+ "no-var": "deny",
+ "no-with": "deny",
+ "operator-assignment": "deny",
+ "prefer-const": "deny",
+ "prefer-exponentiation-operator": "deny",
+ "prefer-numeric-literals": "deny",
+ "prefer-object-has-own": "deny",
+ "prefer-object-spread": "deny",
+ "prefer-promise-reject-errors": "deny",
+ "prefer-rest-params": "deny",
+ "prefer-spread": "deny",
+ "prefer-template": "deny",
+ "preserve-caught-error": "deny",
+ "require-await": "warn",
+ "require-yield": "deny",
+ "typescript/await-thenable": "deny",
+ "typescript/consistent-type-exports": "deny",
+ "typescript/consistent-type-imports": "deny",
+ "typescript/no-array-delete": "deny",
+ "typescript/no-base-to-string": "deny",
+ "typescript/no-confusing-non-null-assertion": "deny",
+ "typescript/no-duplicate-enum-values": "deny",
+ "typescript/no-duplicate-type-constituents": "deny",
+ "typescript/no-dynamic-delete": "deny",
+ "typescript/no-extra-non-null-assertion": "deny",
+ "typescript/no-extraneous-class": "deny",
+ "typescript/no-floating-promises": "deny",
+ "typescript/no-for-in-array": "deny",
+ "typescript/no-implied-eval": "deny",
+ "typescript/no-import-type-side-effects": "deny",
+ "typescript/no-invalid-void-type": "deny",
+ "typescript/no-meaningless-void-operator": "deny",
+ "typescript/no-misused-new": "deny",
+ "typescript/no-misused-spread": "deny",
+ "typescript/no-non-null-asserted-nullish-coalescing": "deny",
+ "typescript/no-non-null-asserted-optional-chain": "deny",
+ "typescript/no-non-null-assertion": "deny",
+ "typescript/no-redundant-type-constituents": "deny",
+ "typescript/no-this-alias": "deny",
+ "typescript/no-unnecessary-boolean-literal-compare": "deny",
+ "typescript/no-unnecessary-parameter-property-assignment": "deny",
+ "typescript/no-unnecessary-template-expression": "deny",
+ "typescript/no-unnecessary-type-arguments": "deny",
+ "typescript/no-unnecessary-type-assertion": "deny",
+ "typescript/no-unnecessary-type-constraint": "deny",
+ "typescript/no-unsafe-declaration-merging": "deny",
+ "typescript/no-unsafe-enum-comparison": "deny",
+ "typescript/no-unsafe-type-assertion": "deny",
+ "typescript/no-unsafe-unary-minus": "deny",
+ "typescript/no-useless-empty-export": "deny",
+ "typescript/no-wrapper-object-types": "deny",
+ "typescript/prefer-as-const": "deny",
+ "typescript/prefer-literal-enum-member": "deny",
+ "typescript/prefer-namespace-keyword": "deny",
+ "typescript/prefer-reduce-type-parameter": "deny",
+ "typescript/prefer-return-this-type": "deny",
+ "typescript/require-array-sort-compare": "deny",
+ "typescript/restrict-template-expressions": "deny",
+ "typescript/triple-slash-reference": "deny",
+ "typescript/unbound-method": "deny",
+ "typescript/unified-signatures": "deny",
+ "typescript/use-unknown-in-catch-callback-variable": "deny",
+ "unicode-bom": "deny",
+ "use-isnan": "deny",
+ "valid-typeof": "deny",
+ "vitest/consistent-each-for": "deny",
+ "vitest/hoisted-apis-on-top": "deny",
+ "vitest/no-conditional-tests": "deny",
+ "vitest/require-local-test-context-for-concurrent-snapshots": "deny",
+ "vitest/warn-todo": "deny",
+ "yoda": "deny"
+ },
+ "settings": {
+ "jsdoc": {
+ "augmentsExtendsReplacesDocs": false,
+ "exemptDestructuredRootsFromChecks": false,
+ "ignoreInternal": false,
+ "ignorePrivate": false,
+ "ignoreReplacesDocs": true,
+ "implementsReplacesDocs": false,
+ "overrideReplacesDocs": true,
+ "tagNamePreference": {}
+ },
+ "jsx-a11y": {
+ "attributes": {},
+ "components": {},
+ "polymorphicPropName": null
+ },
+ "next": {
+ "rootDir": []
+ },
+ "react": {
+ "componentWrapperFunctions": [],
+ "formComponents": [],
+ "linkComponents": [],
+ "version": null
+ },
+ "vitest": {
+ "typecheck": false
+ }
+ }
+}
diff --git a/packages/oxlint-config/test/update-configs.sh b/packages/oxlint-config/test/update-configs.sh
new file mode 100755
index 0000000..1379db3
--- /dev/null
+++ b/packages/oxlint-config/test/update-configs.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# update-configs.sh
+# Regenerates the test/generated snapshot files and commits them if they changed.
+#
+# Run this after any change to a config preset:
+# ./test/update-configs.sh
+
+set -euo pipefail
+
+cd "$(dirname "$0")/.." || exit 1
+
+echo "Regenerating oxlint config snapshots..."
+node test/generate-configs.js
+
+cd test || exit 1
+
+if ! git diff --exit-code generated/; then
+ git add generated/
+ git commit -m "chore(oxlint-config): update oxlint config snapshots"
+ git push
+ echo -e "\033[32mBranch has been updated with new config snapshots\033[0m"
+else
+ echo -e "\033[32mNothing changed, snapshots are already up to date\033[0m"
+fi
diff --git a/packages/oxlint-config/test/verify-configs.sh b/packages/oxlint-config/test/verify-configs.sh
new file mode 100755
index 0000000..13f5302
--- /dev/null
+++ b/packages/oxlint-config/test/verify-configs.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+# verify-configs.sh
+# Regenerates snapshots in a temp copy and fails if they differ from committed.
+# Intended for CI.
+#
+# Usage: ./test/verify-configs.sh
+
+set -euo pipefail
+
+cd "$(dirname "$0")/.." || exit 1
+
+echo "Verifying oxlint config snapshots..."
+node test/generate-configs.js
+
+cd test || exit 1
+
+if ! git diff --exit-code generated/; then
+ echo -e "\033[31mSnapshot mismatch: the committed snapshots are out of date.\033[0m"
+ echo -e "\033[31mRun './test/update-configs.sh' locally and commit the result.\033[0m"
+ exit 1
+fi
+
+echo -e "\033[32mAll snapshots match, no diff found!\033[0m"
diff --git a/packages/oxlint-config/vitest.js b/packages/oxlint-config/vitest.js
new file mode 100644
index 0000000..f1df8d6
--- /dev/null
+++ b/packages/oxlint-config/vitest.js
@@ -0,0 +1,50 @@
+// @ts-check
+// Qlik Vitest oxlint config
+// Extends recommended with vitest plugin rules for test files.
+//
+// Typical usage – add an override to your project's .oxlintrc.json:
+//
+// {
+// "extends": ["@qlik/oxlint-config/recommended.json"],
+// "overrides": [
+// {
+// "files": ["**/__tests__/**", "**/*.test.*", "**/*.spec.*"],
+// "extends": ["@qlik/oxlint-config/vitest.json"]
+// }
+// ]
+// }
+//
+// Or, in an oxlint.config.ts:
+//
+// import { defineConfig } from "oxlint";
+// import vitest from "@qlik/oxlint-config/vitest.js";
+// export default defineConfig({ extends: [vitest] });
+
+import recommended from "./recommended.js";
+
+/** @type {import("oxlint").OxlintConfig} */
+const config = {
+ extends: [recommended],
+
+ plugins: ["typescript", "import", "vitest"],
+
+ rules: {
+ // console output in tests is usually intentional (debugging assertions)
+ "no-console": "off",
+
+ // test files don't export production code, so import restrictions are relaxed
+ "no-restricted-imports": "off",
+
+ /* ------------------------------------------------------------------ */
+ /* Vitest – correctness (override to make explicit) */
+ /* ------------------------------------------------------------------ */
+
+ // conditional test logic masks bugs that should be fixed unconditionally
+ "vitest/no-conditional-tests": "error",
+
+ // TODO-marked tests should surface as warnings so they aren't forgotten
+ "vitest/warn-todo": "error",
+ },
+};
+
+export default config;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d6edeed..35996f2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -111,6 +111,12 @@ importers:
specifier: ^4.0.18
version: 4.0.18(@types/node@25.3.0)
+ packages/oxlint-config:
+ devDependencies:
+ oxlint:
+ specifier: ^1.50.0
+ version: 1.50.0
+
packages/prettier-config:
dependencies:
prettier:
@@ -583,6 +589,128 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
+ '@oxlint/binding-android-arm-eabi@1.50.0':
+ resolution: {integrity: sha512-G7MRGk/6NCe+L8ntonRdZP7IkBfEpiZ/he3buLK6JkLgMHgJShXZ+BeOwADmspXez7U7F7L1Anf4xLSkLHiGTg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [android]
+
+ '@oxlint/binding-android-arm64@1.50.0':
+ resolution: {integrity: sha512-GeSuMoJWCVpovJi/e3xDSNgjeR8WEZ6MCXL6EtPiCIM2NTzv7LbflARINTXTJy2oFBYyvdf/l2PwHzYo6EdXvg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@oxlint/binding-darwin-arm64@1.50.0':
+ resolution: {integrity: sha512-w3SY5YtxGnxCHPJ8Twl3KmS9oja1gERYk3AMoZ7Hv8P43ZtB6HVfs02TxvarxfL214Tm3uzvc2vn+DhtUNeKnw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@oxlint/binding-darwin-x64@1.50.0':
+ resolution: {integrity: sha512-hNfogDqy7tvmllXKBSlHo6k5x7dhTUVOHbMSE15CCAcXzmqf5883aPvBYPOq9AE7DpDUQUZ1kVE22YbiGW+tuw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@oxlint/binding-freebsd-x64@1.50.0':
+ resolution: {integrity: sha512-ykZevOWEyu0nsxolA911ucxpEv0ahw8jfEeGWOwwb/VPoE4xoexuTOAiPNlWZNJqANlJl7yp8OyzCtXTUAxotw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@oxlint/binding-linux-arm-gnueabihf@1.50.0':
+ resolution: {integrity: sha512-hif3iDk7vo5GGJ4OLCCZAf2vjnU9FztGw4L0MbQL0M2iY9LKFtDMMiQAHmkF0PQGQMVbTYtPdXCLKVgdkiqWXQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxlint/binding-linux-arm-musleabihf@1.50.0':
+ resolution: {integrity: sha512-dVp9iSssiGAnTNey2Ruf6xUaQhdnvcFOJyRWd/mu5o2jVbFK15E5fbWGeFRfmuobu5QXuROtFga44+7DOS3PLg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxlint/binding-linux-arm64-gnu@1.50.0':
+ resolution: {integrity: sha512-1cT7yz2HA910CKA9NkH1ZJo50vTtmND2fkoW1oyiSb0j6WvNtJ0Wx2zoySfXWc/c+7HFoqRK5AbEoL41LOn9oA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxlint/binding-linux-arm64-musl@1.50.0':
+ resolution: {integrity: sha512-++B3k/HEPFVlj89cOz8kWfQccMZB/aWL9AhsW7jPIkG++63Mpwb2cE9XOEsd0PATbIan78k2Gky+09uWM1d/gQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxlint/binding-linux-ppc64-gnu@1.50.0':
+ resolution: {integrity: sha512-Z9b/KpFMkx66w3gVBqjIC1AJBTZAGoI9+U+K5L4QM0CB/G0JSNC1es9b3Y0Vcrlvtdn8A+IQTkYjd/Q0uCSaZw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxlint/binding-linux-riscv64-gnu@1.50.0':
+ resolution: {integrity: sha512-jvmuIw8wRSohsQlFNIST5uUwkEtEJmOQYr33bf/K2FrFPXHhM4KqGekI3ShYJemFS/gARVacQFgBzzJKCAyJjg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxlint/binding-linux-riscv64-musl@1.50.0':
+ resolution: {integrity: sha512-x+UrN47oYNh90nmAAyql8eQaaRpHbDPu5guasDg10+OpszUQ3/1+1J6zFMmV4xfIEgTcUXG/oI5fxJhF4eWCNA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxlint/binding-linux-s390x-gnu@1.50.0':
+ resolution: {integrity: sha512-i/JLi2ljLUIVfekMj4ISmdt+Hn11wzYUdRRrkVUYsCWw7zAy5xV7X9iA+KMyM156LTFympa7s3oKBjuCLoTAUQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxlint/binding-linux-x64-gnu@1.50.0':
+ resolution: {integrity: sha512-/C7brhn6c6UUPccgSPCcpLQXcp+xKIW/3sji/5VZ8/OItL3tQ2U7KalHz887UxxSQeEOmd1kY6lrpuwFnmNqOA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxlint/binding-linux-x64-musl@1.50.0':
+ resolution: {integrity: sha512-oDR1f+bGOYU8LfgtEW8XtotWGB63ghtcxk5Jm6IDTCk++rTA/IRMsjOid2iMd+1bW+nP9Mdsmcdc7VbPD3+iyQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxlint/binding-openharmony-arm64@1.50.0':
+ resolution: {integrity: sha512-4CmRGPp5UpvXyu4jjP9Tey/SrXDQLRvZXm4pb4vdZBxAzbFZkCyh0KyRy4txld/kZKTJlW4TO8N1JKrNEk+mWw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@oxlint/binding-win32-arm64-msvc@1.50.0':
+ resolution: {integrity: sha512-Fq0M6vsGcFsSfeuWAACDhd5KJrO85ckbEfe1EGuBj+KPyJz7KeWte2fSFrFGmNKNXyhEMyx4tbgxiWRujBM2KQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@oxlint/binding-win32-ia32-msvc@1.50.0':
+ resolution: {integrity: sha512-qTdWR9KwY/vxJGhHVIZG2eBOhidOQvOwzDxnX+jhW/zIVacal1nAhR8GLkiywW8BIFDkQKXo/zOfT+/DY+ns/w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@oxlint/binding-win32-x64-msvc@1.50.0':
+ resolution: {integrity: sha512-682t7npLC4G2Ca+iNlI9fhAKTcFPYYXJjwoa88H4q+u5HHHlsnL/gHULapX3iqp+A8FIJbgdylL5KMYo2LaluQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
'@reteps/dockerfmt@0.3.6':
resolution: {integrity: sha512-Tb5wIMvBf/nLejTQ61krK644/CEMB/cpiaIFXqGApfGqO3GwcR3qnI0DbmkFVCl2OyEp8LnLX3EkucoL0+tbFg==}
engines: {node: ^v12.20.0 || ^14.13.0 || >=16.0.0}
@@ -1951,6 +2079,16 @@ packages:
resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
engines: {node: '>= 0.4'}
+ oxlint@1.50.0:
+ resolution: {integrity: sha512-iSJ4IZEICBma8cZX7kxIIz9PzsYLF2FaLAYN6RKu7VwRVKdu7RIgpP99bTZaGl//Yao7fsaGZLSEo5xBrI5ReQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ oxlint-tsgolint: '>=0.14.1'
+ peerDependenciesMeta:
+ oxlint-tsgolint:
+ optional: true
+
p-filter@2.1.0:
resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==}
engines: {node: '>=8'}
@@ -3033,6 +3171,63 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.20.1
+ '@oxlint/binding-android-arm-eabi@1.50.0':
+ optional: true
+
+ '@oxlint/binding-android-arm64@1.50.0':
+ optional: true
+
+ '@oxlint/binding-darwin-arm64@1.50.0':
+ optional: true
+
+ '@oxlint/binding-darwin-x64@1.50.0':
+ optional: true
+
+ '@oxlint/binding-freebsd-x64@1.50.0':
+ optional: true
+
+ '@oxlint/binding-linux-arm-gnueabihf@1.50.0':
+ optional: true
+
+ '@oxlint/binding-linux-arm-musleabihf@1.50.0':
+ optional: true
+
+ '@oxlint/binding-linux-arm64-gnu@1.50.0':
+ optional: true
+
+ '@oxlint/binding-linux-arm64-musl@1.50.0':
+ optional: true
+
+ '@oxlint/binding-linux-ppc64-gnu@1.50.0':
+ optional: true
+
+ '@oxlint/binding-linux-riscv64-gnu@1.50.0':
+ optional: true
+
+ '@oxlint/binding-linux-riscv64-musl@1.50.0':
+ optional: true
+
+ '@oxlint/binding-linux-s390x-gnu@1.50.0':
+ optional: true
+
+ '@oxlint/binding-linux-x64-gnu@1.50.0':
+ optional: true
+
+ '@oxlint/binding-linux-x64-musl@1.50.0':
+ optional: true
+
+ '@oxlint/binding-openharmony-arm64@1.50.0':
+ optional: true
+
+ '@oxlint/binding-win32-arm64-msvc@1.50.0':
+ optional: true
+
+ '@oxlint/binding-win32-ia32-msvc@1.50.0':
+ optional: true
+
+ '@oxlint/binding-win32-x64-msvc@1.50.0':
+ optional: true
+
'@reteps/dockerfmt@0.3.6': {}
'@rollup/rollup-android-arm-eabi@4.59.0':
@@ -4477,6 +4672,28 @@ snapshots:
object-keys: 1.1.1
safe-push-apply: 1.0.0
+ oxlint@1.50.0:
+ optionalDependencies:
+ '@oxlint/binding-android-arm-eabi': 1.50.0
+ '@oxlint/binding-android-arm64': 1.50.0
+ '@oxlint/binding-darwin-arm64': 1.50.0
+ '@oxlint/binding-darwin-x64': 1.50.0
+ '@oxlint/binding-freebsd-x64': 1.50.0
+ '@oxlint/binding-linux-arm-gnueabihf': 1.50.0
+ '@oxlint/binding-linux-arm-musleabihf': 1.50.0
+ '@oxlint/binding-linux-arm64-gnu': 1.50.0
+ '@oxlint/binding-linux-arm64-musl': 1.50.0
+ '@oxlint/binding-linux-ppc64-gnu': 1.50.0
+ '@oxlint/binding-linux-riscv64-gnu': 1.50.0
+ '@oxlint/binding-linux-riscv64-musl': 1.50.0
+ '@oxlint/binding-linux-s390x-gnu': 1.50.0
+ '@oxlint/binding-linux-x64-gnu': 1.50.0
+ '@oxlint/binding-linux-x64-musl': 1.50.0
+ '@oxlint/binding-openharmony-arm64': 1.50.0
+ '@oxlint/binding-win32-arm64-msvc': 1.50.0
+ '@oxlint/binding-win32-ia32-msvc': 1.50.0
+ '@oxlint/binding-win32-x64-msvc': 1.50.0
+
p-filter@2.1.0:
dependencies:
p-map: 2.1.0