@oxlint/migrate
Version:
Generates a `.oxlintrc.json` from a existing eslint flat config
1,488 lines (1,475 loc) • 52 kB
JavaScript
import globals from "globals";
//#region rolldown:runtime
var __defProp = Object.defineProperty;
var __exportAll = (all, symbols) => {
let target = {};
for (var name in all) {
__defProp(target, name, {
get: all[name],
enumerable: true
});
}
if (symbols) {
__defProp(target, Symbol.toStringTag, { value: "Module" });
}
return target;
};
//#endregion
//#region src/env_globals.ts
const ES_VERSIONS = [
6,
2016,
2017,
2018,
2019,
2020,
2021,
2022,
2023,
2024,
2025,
2026
];
const OTHER_SUPPORTED_ENVS = [
"browser",
"node",
"shared-node-browser",
"worker",
"serviceworker",
"amd",
"applescript",
"astro",
"atomtest",
"audioworklet",
"commonjs",
"embertest",
"greasemonkey",
"jasmine",
"jest",
"jquery",
"meteor",
"mocha",
"mongo",
"nashorn",
"protractor",
"prototypejs",
"phantomjs",
"shelljs",
"svelte",
"webextensions",
"qunit",
"vitest",
"vue"
];
const SUPPORTED_ESLINT_PARSERS = ["typescript-eslint/parser"];
const normalizeGlobValue = (value) => {
if (value === "readable" || value === "readonly" || value === false) return false;
if (value === "off") return;
return true;
};
const removeGlobalsWithAreCoveredByEnv = (config) => {
if (config.globals === void 0 || config.env === void 0) return;
for (const [env, entries] of Object.entries(globals)) if (config.env[env] === true) {
for (const entry of Object.keys(entries)) if (normalizeGlobValue(config.globals[entry]) === entries[entry]) delete config.globals[entry];
}
if (Object.keys(config.globals).length === 0) delete config.globals;
};
const transformBoolGlobalToString = (config) => {
if (config.globals === void 0) return;
for (const [entry, value] of Object.entries(config.globals)) if (value === false || value === "readable") config.globals[entry] = "readonly";
else if (value === true || value === "writeable") config.globals[entry] = "writable";
};
const THRESHOLD_ENVS = [
"browser",
"node",
"serviceworker",
"worker"
];
const detectEnvironmentByGlobals = (config) => {
if (config.globals === void 0) return;
for (const [env, entries] of Object.entries(globals)) {
if (!env.startsWith("es") && !OTHER_SUPPORTED_ENVS.includes(env)) continue;
if (env.startsWith("es") && !ES_VERSIONS.includes(parseInt(env.replace(/^es/, "")))) continue;
let search = Object.keys(entries);
let matches = search.filter((entry) => entry in config.globals && normalizeGlobValue(config.globals[entry]) === entries[entry]);
const useThreshold = THRESHOLD_ENVS.includes(env);
if (useThreshold && matches.length / search.length >= .97 || !useThreshold && matches.length === search.length) {
if (config.env === void 0) config.env = {};
config.env[env] = true;
}
}
};
const transformEnvAndGlobals = (eslintConfig, targetConfig, options) => {
if (eslintConfig.languageOptions?.parser !== void 0 && eslintConfig.languageOptions?.parser !== null && typeof eslintConfig.languageOptions.parser === "object" && "meta" in eslintConfig.languageOptions.parser && !SUPPORTED_ESLINT_PARSERS.includes(eslintConfig.languageOptions.parser.meta?.name)) options?.reporter?.report("special parser detected: " + eslintConfig.languageOptions.parser.meta?.name);
if (eslintConfig.languageOptions?.globals !== void 0 && eslintConfig.languageOptions?.globals !== null) {
if (targetConfig.globals === void 0) targetConfig.globals = {};
if (options?.merge) {
for (const [global, globalSetting] of Object.entries(eslintConfig.languageOptions.globals)) if (!(global in targetConfig.globals)) targetConfig.globals[global] = globalSetting;
} else Object.assign(targetConfig.globals, eslintConfig.languageOptions.globals);
}
if (eslintConfig.languageOptions?.ecmaVersion !== void 0) {
if (eslintConfig.languageOptions.ecmaVersion === "latest") {
if (targetConfig.env === void 0) targetConfig.env = {};
const latestVersion = `es${ES_VERSIONS[ES_VERSIONS.length - 1]}`;
if (!(latestVersion in targetConfig.env)) targetConfig.env[latestVersion] = true;
} else if (typeof eslintConfig.languageOptions.ecmaVersion === "number" && ES_VERSIONS.includes(eslintConfig.languageOptions.ecmaVersion)) {
if (targetConfig.env === void 0) targetConfig.env = {};
const targetVersion = `es${eslintConfig.languageOptions.ecmaVersion}`;
if (!(targetVersion in targetConfig.env)) targetConfig.env[targetVersion] = true;
}
}
};
const cleanUpUselessOverridesEnv = (config) => {
if (config.env === void 0 || config.overrides === void 0) return;
for (const override of config.overrides) {
if (override.env === void 0) continue;
for (const [overrideEnv, overrideEnvConfig] of Object.entries(override.env)) if (overrideEnv in config.env && config.env[overrideEnv] === overrideEnvConfig) delete override.env[overrideEnv];
if (Object.keys(override.env).length === 0) delete override.env;
}
};
const SUPERSET_ENVS = {
node: [
"nodeBuiltin",
"shared-node-browser",
"commonjs"
],
browser: ["shared-node-browser"]
};
/**
* Cleans up superset environments in the config and its overrides.
* If a superset environment is present, its subset environments are removed, e.g. all globals from `shared-node-browser` are also in `browser` and `node`.
*
* This also applies for overrides, where if a superset env is defined in the override or main config,
* the subset envs can be removed from the override if the override has the same value as the superset.
*/
const cleanUpSupersetEnvs = (config) => {
if (config.env !== void 0) for (const [supersetEnv, subsetEnvs] of Object.entries(SUPERSET_ENVS)) {
if (!(supersetEnv in config.env)) continue;
for (const subsetEnv of subsetEnvs) if (config.env[subsetEnv] === config.env[supersetEnv]) delete config.env[subsetEnv];
}
if (config.overrides !== void 0) for (const override of config.overrides) {
if (override.env === void 0) continue;
for (const [supersetEnv, subsetEnvs] of Object.entries(SUPERSET_ENVS)) {
const supersetInOverride = supersetEnv in override.env;
const supersetInMain = config.env !== void 0 && supersetEnv in config.env;
for (const subsetEnv of subsetEnvs) {
if (!(subsetEnv in override.env)) continue;
if (supersetInOverride && override.env[subsetEnv] === override.env[supersetEnv]) {
delete override.env[subsetEnv];
continue;
}
if (supersetInMain && !supersetInOverride && config.env[supersetEnv] === override.env[subsetEnv]) delete override.env[subsetEnv];
}
}
if (Object.keys(override.env).length === 0) delete override.env;
}
};
//#endregion
//#region src/generated/rules.ts
var rules_exports = /* @__PURE__ */ __exportAll({
correctnessRules: () => correctnessRules,
nurseryRules: () => nurseryRules,
pedanticRules: () => pedanticRules,
perfRules: () => perfRules,
restrictionRules: () => restrictionRules,
styleRules: () => styleRules,
suspiciousRules: () => suspiciousRules
});
const pedanticRules = [
"accessor-pairs",
"array-callback-return",
"eqeqeq",
"max-classes-per-file",
"max-depth",
"max-lines-per-function",
"max-lines",
"max-nested-callbacks",
"no-inline-comments",
"no-loop-func",
"no-array-constructor",
"no-case-declarations",
"no-lonely-if",
"no-object-constructor",
"no-constructor-return",
"no-else-return",
"no-fallthrough",
"no-inner-declarations",
"no-negated-condition",
"no-new-wrappers",
"no-promise-executor-return",
"no-prototype-builtins",
"no-redeclare",
"no-self-compare",
"no-throw-literal",
"no-useless-return",
"no-warning-comments",
"radix",
"require-await",
"sort-vars",
"symbol-description",
"import/max-dependencies",
"jest/no-conditional-in-test",
"jsdoc/require-param",
"jsdoc/require-param-description",
"jsdoc/require-param-name",
"jsdoc/require-param-type",
"jsdoc/require-returns",
"jsdoc/require-returns-description",
"jsdoc/require-returns-type",
"react/checked-requires-onchange-or-readonly",
"react/jsx-no-target-blank",
"react/jsx-no-useless-fragment",
"react/no-unescaped-entities",
"react-hooks/rules-of-hooks",
"@typescript-eslint/ban-ts-comment",
"@typescript-eslint/ban-types",
"@typescript-eslint/no-misused-promises",
"@typescript-eslint/no-confusing-void-expression",
"@typescript-eslint/no-deprecated",
"@typescript-eslint/no-mixed-enums",
"@typescript-eslint/no-unsafe-argument",
"@typescript-eslint/no-unsafe-assignment",
"@typescript-eslint/no-unsafe-call",
"@typescript-eslint/no-unsafe-function-type",
"@typescript-eslint/no-unsafe-member-access",
"@typescript-eslint/no-unsafe-return",
"@typescript-eslint/only-throw-error",
"@typescript-eslint/prefer-enum-initializers",
"@typescript-eslint/prefer-includes",
"@typescript-eslint/prefer-nullish-coalescing",
"@typescript-eslint/prefer-promise-reject-errors",
"@typescript-eslint/prefer-ts-expect-error",
"@typescript-eslint/related-getter-setter-pairs",
"@typescript-eslint/require-await",
"@typescript-eslint/restrict-plus-operands",
"@typescript-eslint/return-await",
"@typescript-eslint/strict-boolean-expressions",
"@typescript-eslint/switch-exhaustiveness-check",
"unicorn/consistent-assert",
"unicorn/consistent-empty-array-spread",
"unicorn/escape-case",
"unicorn/explicit-length-check",
"unicorn/new-for-builtins",
"unicorn/no-immediate-mutation",
"unicorn/no-unnecessary-array-splice-count",
"unicorn/no-array-callback-reference",
"unicorn/no-unnecessary-array-flat-depth",
"unicorn/no-unnecessary-slice-end",
"unicorn/no-hex-escape",
"unicorn/no-instanceof-array",
"unicorn/no-lonely-if",
"unicorn/no-negation-in-equality-check",
"unicorn/no-new-buffer",
"unicorn/no-object-as-default-parameter",
"unicorn/no-static-only-class",
"unicorn/no-this-assignment",
"unicorn/no-typeof-undefined",
"unicorn/no-unreadable-iife",
"unicorn/no-useless-promise-resolve-reject",
"unicorn/no-useless-switch-case",
"unicorn/no-useless-undefined",
"unicorn/prefer-top-level-await",
"unicorn/prefer-at",
"unicorn/prefer-array-flat",
"unicorn/prefer-array-some",
"unicorn/prefer-blob-reading-methods",
"unicorn/prefer-code-point",
"unicorn/prefer-date-now",
"unicorn/prefer-dom-node-append",
"unicorn/prefer-dom-node-dataset",
"unicorn/prefer-dom-node-remove",
"unicorn/prefer-event-target",
"unicorn/prefer-math-min-max",
"unicorn/prefer-math-trunc",
"unicorn/prefer-native-coercion-functions",
"unicorn/prefer-prototype-methods",
"unicorn/prefer-query-selector",
"unicorn/prefer-regexp-test",
"unicorn/prefer-string-replace-all",
"unicorn/prefer-string-slice",
"unicorn/prefer-type-error",
"unicorn/require-number-to-fixed-digits-argument",
"@typescript-eslint/no-loop-func",
"@typescript-eslint/no-array-constructor",
"unicorn/no-negated-condition",
"@typescript-eslint/no-redeclare",
"import-x/max-dependencies",
"vitest/no-conditional-in-test"
];
const styleRules = [
"arrow-body-style",
"capitalized-comments",
"curly",
"default-case-last",
"default-param-last",
"func-style",
"func-names",
"grouped-accessor-pairs",
"guard-for-in",
"id-length",
"init-declarations",
"max-params",
"max-statements",
"new-cap",
"no-implicit-coercion",
"no-useless-computed-key",
"no-duplicate-imports",
"no-extra-label",
"no-labels",
"no-lone-blocks",
"no-multi-assign",
"no-nested-ternary",
"no-continue",
"no-label-var",
"no-magic-numbers",
"no-multi-str",
"no-new-func",
"no-return-assign",
"no-script-url",
"no-template-curly-in-string",
"no-ternary",
"operator-assignment",
"prefer-template",
"prefer-destructuring",
"prefer-promise-reject-errors",
"prefer-exponentiation-operator",
"prefer-numeric-literals",
"prefer-object-has-own",
"prefer-object-spread",
"prefer-rest-params",
"prefer-spread",
"sort-imports",
"sort-keys",
"vars-on-top",
"yoda",
"import/consistent-type-specifier-style",
"import/exports-last",
"import/first",
"import/group-exports",
"import/no-named-export",
"import/no-anonymous-default-export",
"import/no-mutable-exports",
"import/no-named-default",
"import/no-namespace",
"import/no-duplicates",
"import/prefer-default-export",
"jest/consistent-test-it",
"jest/max-expects",
"jest/max-nested-describe",
"jest/no-alias-methods",
"jest/no-confusing-set-timeout",
"jest/no-deprecated-functions",
"jest/no-done-callback",
"jest/no-duplicate-hooks",
"jest/no-hooks",
"jest/no-identical-title",
"jest/no-interpolation-in-snapshots",
"jest/no-jasmine-globals",
"jest/no-large-snapshots",
"jest/no-mocks-import",
"jest/no-restricted-jest-methods",
"jest/no-restricted-matchers",
"jest/no-test-prefixes",
"jest/no-test-return-statement",
"jest/no-untyped-mock-factory",
"jest/padding-around-test-blocks",
"jest/prefer-each",
"jest/prefer-called-with",
"jest/prefer-comparison-matcher",
"jest/prefer-equality-matcher",
"jest/prefer-expect-resolves",
"jest/prefer-hooks-in-order",
"jest/prefer-hooks-on-top",
"jest/prefer-jest-mocked",
"jest/prefer-lowercase-title",
"jest/prefer-mock-promise-shorthand",
"jest/prefer-spy-on",
"jest/prefer-strict-equal",
"jest/prefer-to-be",
"jest/prefer-to-contain",
"jest/prefer-to-have-been-called",
"jest/prefer-to-have-been-called-times",
"jest/prefer-to-have-length",
"jest/prefer-todo",
"jest/require-hook",
"jest/require-top-level-describe",
"node/global-require",
"node/no-exports-assign",
"promise/avoid-new",
"promise/no-return-wrap",
"promise/no-nesting",
"promise/param-names",
"promise/prefer-catch",
"promise/prefer-await-to-callbacks",
"promise/prefer-await-to-then",
"react/jsx-pascal-case",
"react/jsx-fragments",
"react/jsx-boolean-value",
"react/jsx-curly-brace-presence",
"react/jsx-handler-names",
"react/jsx-max-depth",
"react/jsx-props-no-spreading",
"react/no-redundant-should-component-update",
"react/no-set-state",
"react/prefer-es6-class",
"react/self-closing-comp",
"react/state-in-constructor",
"@typescript-eslint/adjacent-overload-signatures",
"@typescript-eslint/array-type",
"@typescript-eslint/ban-tslint-comment",
"@typescript-eslint/consistent-generic-constructors",
"@typescript-eslint/consistent-indexed-object-style",
"@typescript-eslint/consistent-type-definitions",
"@typescript-eslint/consistent-type-imports",
"@typescript-eslint/no-inferrable-types",
"@typescript-eslint/no-empty-interface",
"@typescript-eslint/prefer-for-of",
"@typescript-eslint/prefer-function-type",
"@typescript-eslint/prefer-namespace-keyword",
"@typescript-eslint/prefer-reduce-type-parameter",
"@typescript-eslint/prefer-return-this-type",
"unicorn/catch-error-name",
"unicorn/consistent-date-clone",
"unicorn/consistent-existence-index-check",
"unicorn/empty-brace-spaces",
"unicorn/error-message",
"unicorn/filename-case",
"unicorn/no-useless-collection-argument",
"unicorn/no-array-method-this-argument",
"unicorn/no-await-expression-member",
"unicorn/no-console-spaces",
"unicorn/no-nested-ternary",
"unicorn/no-null",
"unicorn/no-unreadable-array-destructuring",
"unicorn/no-zero-fractions",
"unicorn/number-literal-case",
"unicorn/numeric-separators-style",
"unicorn/prefer-classlist-toggle",
"unicorn/prefer-class-fields",
"unicorn/prefer-bigint-literals",
"unicorn/prefer-default-parameters",
"unicorn/prefer-response-static-json",
"unicorn/prefer-global-this",
"unicorn/prefer-keyboard-event-key",
"unicorn/prefer-object-from-entries",
"unicorn/prefer-array-index-of",
"unicorn/prefer-spread",
"unicorn/prefer-dom-node-text-content",
"unicorn/prefer-includes",
"unicorn/prefer-logical-operator-over-ternary",
"unicorn/prefer-modern-dom-apis",
"unicorn/prefer-negative-index",
"unicorn/prefer-optional-catch-binding",
"unicorn/prefer-reflect-apply",
"unicorn/prefer-string-raw",
"unicorn/prefer-string-trim-start-end",
"unicorn/prefer-structured-clone",
"unicorn/require-module-attributes",
"unicorn/require-array-join-separator",
"unicorn/switch-case-braces",
"unicorn/text-encoding-identifier-case",
"unicorn/throw-new-error",
"vitest/consistent-test-filename",
"vitest/consistent-vitest-vi",
"vitest/no-import-node-test",
"vitest/no-unneeded-async-expect-function",
"vitest/prefer-called-once",
"vitest/prefer-called-times",
"vitest/prefer-describe-function-title",
"vitest/prefer-to-be-falsy",
"vitest/prefer-to-be-object",
"vitest/prefer-to-be-truthy",
"vue/define-emits-declaration",
"vue/define-props-declaration",
"vue/define-props-destructuring",
"vue/require-typed-ref",
"@typescript-eslint/default-param-last",
"@typescript-eslint/init-declarations",
"@typescript-eslint/max-params",
"@typescript-eslint/no-magic-numbers",
"import-x/consistent-type-specifier-style",
"import-x/exports-last",
"import-x/first",
"import-x/group-exports",
"import-x/no-named-export",
"import-x/no-anonymous-default-export",
"import-x/no-mutable-exports",
"import-x/no-named-default",
"import-x/no-namespace",
"import-x/no-duplicates",
"import-x/prefer-default-export",
"vitest/consistent-test-it",
"vitest/max-expects",
"vitest/max-nested-describe",
"vitest/no-alias-methods",
"vitest/no-duplicate-hooks",
"vitest/no-hooks",
"vitest/no-identical-title",
"vitest/no-interpolation-in-snapshots",
"vitest/no-large-snapshots",
"vitest/no-mocks-import",
"vitest/no-restricted-jest-methods",
"vitest/no-restricted-matchers",
"vitest/no-test-prefixes",
"vitest/no-test-return-statement",
"vitest/prefer-each",
"vitest/prefer-called-with",
"vitest/prefer-comparison-matcher",
"vitest/prefer-equality-matcher",
"vitest/prefer-expect-resolves",
"vitest/prefer-hooks-in-order",
"vitest/prefer-hooks-on-top",
"vitest/prefer-lowercase-title",
"vitest/prefer-mock-promise-shorthand",
"vitest/prefer-spy-on",
"vitest/prefer-strict-equal",
"vitest/prefer-to-be",
"vitest/prefer-to-contain",
"vitest/prefer-to-have-length",
"vitest/prefer-todo",
"vitest/require-hook",
"vitest/require-top-level-describe"
];
const suspiciousRules = [
"block-scoped-var",
"no-extra-bind",
"no-unneeded-ternary",
"no-extend-native",
"no-new",
"no-unexpected-multiline",
"no-useless-concat",
"no-useless-constructor",
"preserve-caught-error",
"import/no-unassigned-import",
"import/no-empty-named-blocks",
"import/no-absolute-path",
"import/no-named-as-default",
"import/no-named-as-default-member",
"import/no-self-import",
"jest/no-commented-out-tests",
"promise/always-return",
"promise/no-promise-in-callback",
"promise/no-multiple-resolved",
"react/iframe-missing-sandbox",
"react/jsx-no-comment-textnodes",
"react/jsx-no-script-url",
"react/no-namespace",
"react/react-in-jsx-scope",
"react/style-prop-object",
"@typescript-eslint/no-confusing-non-null-assertion",
"@typescript-eslint/no-extraneous-class",
"@typescript-eslint/no-unnecessary-boolean-literal-compare",
"@typescript-eslint/no-unnecessary-template-expression",
"@typescript-eslint/no-unnecessary-type-arguments",
"@typescript-eslint/no-unnecessary-type-assertion",
"@typescript-eslint/no-unnecessary-type-constraint",
"@typescript-eslint/no-unsafe-enum-comparison",
"@typescript-eslint/no-unsafe-type-assertion",
"unicorn/consistent-function-scoping",
"unicorn/no-array-sort",
"unicorn/no-array-reverse",
"unicorn/no-instanceof-builtins",
"unicorn/no-accessor-recursion",
"unicorn/prefer-add-event-listener",
"unicorn/require-module-specifiers",
"unicorn/require-post-message-target-origin",
"vue/no-required-prop-with-default",
"vue/require-default-export",
"@typescript-eslint/no-useless-constructor",
"import-x/no-unassigned-import",
"import-x/no-empty-named-blocks",
"import-x/no-absolute-path",
"import-x/no-named-as-default",
"import-x/no-named-as-default-member",
"import-x/no-self-import",
"vitest/no-commented-out-tests"
];
const restrictionRules = [
"class-methods-use-this",
"complexity",
"default-case",
"no-alert",
"no-bitwise",
"no-param-reassign",
"no-restricted-imports",
"no-console",
"no-div-regex",
"no-empty-function",
"no-empty",
"no-eq-null",
"no-iterator",
"no-plusplus",
"no-proto",
"no-regex-spaces",
"no-restricted-globals",
"no-sequences",
"no-undefined",
"no-var",
"no-void",
"unicode-bom",
"import/extensions",
"import/no-amd",
"import/no-commonjs",
"import/no-cycle",
"import/no-default-export",
"import/no-dynamic-require",
"import/no-webpack-loader-syntax",
"import/unambiguous",
"jsdoc/check-access",
"jsdoc/empty-tags",
"jsx-a11y/anchor-ambiguous-text",
"node/no-process-env",
"node/no-new-require",
"promise/catch-or-return",
"promise/spec-only",
"react/button-has-type",
"react/forbid-dom-props",
"react/forbid-elements",
"react/jsx-filename-extension",
"react/no-danger",
"react/no-unknown-property",
"react/only-export-components",
"@typescript-eslint/explicit-module-boundary-types",
"@typescript-eslint/explicit-function-return-type",
"@typescript-eslint/no-dynamic-delete",
"@typescript-eslint/no-empty-object-type",
"@typescript-eslint/no-explicit-any",
"@typescript-eslint/no-import-type-side-effects",
"@typescript-eslint/no-namespace",
"@typescript-eslint/no-non-null-asserted-nullish-coalescing",
"@typescript-eslint/no-non-null-assertion",
"@typescript-eslint/no-require-imports",
"@typescript-eslint/no-restricted-types",
"@typescript-eslint/no-var-requires",
"@typescript-eslint/non-nullable-type-assertion-style",
"@typescript-eslint/prefer-literal-enum-member",
"@typescript-eslint/promise-function-async",
"@typescript-eslint/use-unknown-in-catch-callback-variable",
"unicorn/no-useless-error-capture-stack-trace",
"unicorn/no-abusive-eslint-disable",
"unicorn/no-anonymous-default-export",
"unicorn/no-array-for-each",
"unicorn/no-array-reduce",
"unicorn/no-document-cookie",
"unicorn/no-length-as-slice-end",
"unicorn/no-magic-array-flat-depth",
"unicorn/no-process-exit",
"unicorn/prefer-modern-math-apis",
"unicorn/prefer-node-protocol",
"unicorn/prefer-number-properties",
"vue/max-props",
"vue/no-import-compiler-macros",
"vue/no-multiple-slot-args",
"@typescript-eslint/class-methods-use-this",
"@typescript-eslint/no-restricted-imports",
"@typescript-eslint/no-empty-function",
"import-x/extensions",
"import-x/no-amd",
"import-x/no-commonjs",
"import-x/no-cycle",
"import-x/no-default-export",
"import-x/no-dynamic-require",
"import-x/no-webpack-loader-syntax",
"import-x/unambiguous"
];
const correctnessRules = [
"constructor-super",
"for-direction",
"no-unassigned-vars",
"no-async-promise-executor",
"no-caller",
"no-class-assign",
"no-useless-backreference",
"no-compare-neg-zero",
"no-cond-assign",
"no-const-assign",
"no-constant-binary-expression",
"no-constant-condition",
"no-control-regex",
"no-debugger",
"no-delete-var",
"no-dupe-class-members",
"no-dupe-else-if",
"no-dupe-keys",
"no-duplicate-case",
"no-empty-character-class",
"no-empty-pattern",
"no-empty-static-block",
"no-eval",
"no-ex-assign",
"no-extra-boolean-cast",
"no-func-assign",
"no-global-assign",
"no-import-assign",
"no-invalid-regexp",
"no-irregular-whitespace",
"no-loss-of-precision",
"no-new-native-nonconstructor",
"no-nonoctal-decimal-escape",
"no-obj-calls",
"no-self-assign",
"no-setter-return",
"no-shadow-restricted-names",
"no-sparse-arrays",
"no-this-before-super",
"no-unsafe-finally",
"no-unsafe-negation",
"no-unsafe-optional-chaining",
"no-unused-expressions",
"no-unused-labels",
"no-unused-private-class-members",
"no-unused-vars",
"no-useless-catch",
"no-useless-escape",
"no-useless-rename",
"no-with",
"require-yield",
"use-isnan",
"valid-typeof",
"import/default",
"import/namespace",
"jest/expect-expect",
"jest/no-conditional-expect",
"jest/no-disabled-tests",
"jest/no-export",
"jest/no-focused-tests",
"jest/no-standalone-expect",
"jest/require-to-throw-message",
"jest/valid-describe-callback",
"jest/valid-expect",
"jest/valid-title",
"jsdoc/check-property-names",
"jsdoc/check-tag-names",
"jsdoc/implements-on-classes",
"jsdoc/no-defaults",
"jsdoc/require-property",
"jsdoc/require-property-description",
"jsdoc/require-property-name",
"jsdoc/require-property-type",
"jsdoc/require-yields",
"jsx-a11y/alt-text",
"jsx-a11y/anchor-has-content",
"jsx-a11y/anchor-is-valid",
"jsx-a11y/aria-activedescendant-has-tabindex",
"jsx-a11y/aria-props",
"jsx-a11y/aria-proptypes",
"jsx-a11y/aria-role",
"jsx-a11y/aria-unsupported-elements",
"jsx-a11y/autocomplete-valid",
"jsx-a11y/click-events-have-key-events",
"jsx-a11y/heading-has-content",
"jsx-a11y/html-has-lang",
"jsx-a11y/iframe-has-title",
"jsx-a11y/img-redundant-alt",
"jsx-a11y/label-has-associated-control",
"jsx-a11y/lang",
"jsx-a11y/media-has-caption",
"jsx-a11y/mouse-events-have-key-events",
"jsx-a11y/no-noninteractive-tabindex",
"jsx-a11y/no-access-key",
"jsx-a11y/no-aria-hidden-on-focusable",
"jsx-a11y/no-autofocus",
"jsx-a11y/no-distracting-elements",
"jsx-a11y/no-redundant-roles",
"jsx-a11y/prefer-tag-over-role",
"jsx-a11y/role-has-required-aria-props",
"jsx-a11y/role-supports-aria-props",
"jsx-a11y/scope",
"jsx-a11y/tabindex-no-positive",
"@next/next/google-font-display",
"@next/next/google-font-preconnect",
"@next/next/inline-script-id",
"@next/next/next-script-for-ga",
"@next/next/no-assign-module-variable",
"@next/next/no-async-client-component",
"@next/next/no-before-interactive-script-outside-document",
"@next/next/no-css-tags",
"@next/next/no-document-import-in-page",
"@next/next/no-duplicate-head",
"@next/next/no-head-element",
"@next/next/no-head-import-in-document",
"@next/next/no-img-element",
"@next/next/no-page-custom-font",
"@next/next/no-script-component-in-head",
"@next/next/no-styled-jsx-in-document",
"@next/next/no-sync-scripts",
"@next/next/no-title-in-document-head",
"@next/next/no-typos",
"@next/next/no-unwanted-polyfillio",
"@next/next/no-html-link-for-pages",
"promise/no-callback-in-promise",
"promise/no-new-statics",
"promise/valid-params",
"react-hooks/exhaustive-deps",
"react/forward-ref-uses-ref",
"react/jsx-key",
"react/jsx-no-duplicate-props",
"react/jsx-no-undef",
"react/jsx-props-no-spread-multi",
"react/no-did-mount-set-state",
"react/no-children-prop",
"react/no-danger-with-children",
"react/no-direct-mutation-state",
"react/no-find-dom-node",
"react/no-is-mounted",
"react/no-render-return-value",
"react/no-string-refs",
"react/no-this-in-sfc",
"react/no-unsafe",
"react/no-will-update-set-state",
"react/void-dom-elements-no-children",
"@typescript-eslint/await-thenable",
"@typescript-eslint/no-floating-promises",
"@typescript-eslint/no-array-delete",
"@typescript-eslint/no-base-to-string",
"@typescript-eslint/no-duplicate-enum-values",
"@typescript-eslint/no-duplicate-type-constituents",
"@typescript-eslint/no-extra-non-null-assertion",
"@typescript-eslint/no-for-in-array",
"@typescript-eslint/no-implied-eval",
"@typescript-eslint/no-meaningless-void-operator",
"@typescript-eslint/no-misused-new",
"@typescript-eslint/no-misused-spread",
"@typescript-eslint/no-non-null-asserted-optional-chain",
"@typescript-eslint/no-redundant-type-constituents",
"@typescript-eslint/no-this-alias",
"@typescript-eslint/no-unnecessary-parameter-property-assignment",
"@typescript-eslint/no-unsafe-declaration-merging",
"@typescript-eslint/no-unsafe-unary-minus",
"@typescript-eslint/no-useless-empty-export",
"@typescript-eslint/no-wrapper-object-types",
"@typescript-eslint/prefer-as-const",
"@typescript-eslint/require-array-sort-compare",
"@typescript-eslint/restrict-template-expressions",
"@typescript-eslint/triple-slash-reference",
"@typescript-eslint/unbound-method",
"unicorn/no-invalid-fetch-options",
"unicorn/no-await-in-promise-methods",
"unicorn/no-empty-file",
"unicorn/no-invalid-remove-event-listener",
"unicorn/no-new-array",
"unicorn/no-single-promise-in-promise-methods",
"unicorn/no-thenable",
"unicorn/no-unnecessary-await",
"unicorn/no-useless-fallback-in-spread",
"unicorn/no-useless-length-check",
"unicorn/no-useless-spread",
"unicorn/prefer-set-size",
"unicorn/prefer-string-starts-ends-with",
"vitest/consistent-each-for",
"vitest/hoisted-apis-on-top",
"vitest/no-conditional-tests",
"vitest/require-local-test-context-for-concurrent-snapshots",
"vitest/warn-todo",
"vue/no-arrow-functions-in-watch",
"vue/no-deprecated-destroyed-lifecycle",
"vue/no-export-in-script-setup",
"vue/no-lifecycle-after-await",
"vue/no-this-in-before-route-enter",
"vue/prefer-import-from-vue",
"vue/valid-define-emits",
"vue/valid-define-props",
"@typescript-eslint/no-dupe-class-members",
"@typescript-eslint/no-loss-of-precision",
"@typescript-eslint/no-unused-expressions",
"@typescript-eslint/no-unused-vars",
"import-x/default",
"import-x/namespace",
"vitest/expect-expect",
"vitest/no-conditional-expect",
"vitest/no-disabled-tests",
"vitest/no-focused-tests",
"vitest/no-standalone-expect",
"vitest/require-to-throw-message",
"vitest/valid-describe-callback",
"vitest/valid-expect"
];
const nurseryRules = [
"getter-return",
"no-misleading-character-class",
"no-undef",
"no-unreachable",
"import/export",
"import/named",
"jsx-a11y/no-static-element-interactions",
"promise/no-return-in-finally",
"react/require-render-return",
"@typescript-eslint/prefer-optional-chain",
"import-x/export",
"import-x/named"
];
const perfRules = [
"no-await-in-loop",
"no-useless-call",
"react/no-array-index-key",
"react-perf/jsx-no-jsx-as-prop",
"react-perf/jsx-no-new-array-as-prop",
"react-perf/jsx-no-new-function-as-prop",
"react-perf/jsx-no-new-object-as-prop",
"unicorn/prefer-array-find",
"unicorn/prefer-array-flat-map",
"unicorn/prefer-set-has"
];
//#endregion
//#region src/constants.ts
const rulesPrefixesForPlugins = {
import: "import",
"import-x": "import",
jest: "jest",
jsdoc: "jsdoc",
"jsx-a11y": "jsx-a11y",
"@next/next": "nextjs",
node: "node",
n: "node",
promise: "promise",
react: "react",
"react-perf": "react-perf",
"react-hooks": "react",
"@typescript-eslint": "typescript",
unicorn: "unicorn",
vitest: "vitest",
vue: "vue"
};
const typescriptRulesExtendEslintRules = [
"class-methods-use-this",
"default-param-last",
"init-declarations",
"max-params",
"no-array-constructor",
"no-dupe-class-members",
"no-empty-function",
"no-invalid-this",
"no-loop-func",
"no-loss-of-precision",
"no-magic-numbers",
"no-redeclare",
"no-restricted-imports",
"no-shadow",
"no-unused-expressions",
"no-unused-vars",
"no-use-before-define",
"no-useless-constructor"
];
const typescriptTypeAwareRules = [
"@typescript-eslint/await-thenable",
"@typescript-eslint/consistent-return",
"@typescript-eslint/consistent-type-exports",
"@typescript-eslint/dot-notation",
"@typescript-eslint/naming-convention",
"@typescript-eslint/no-array-delete",
"@typescript-eslint/no-base-to-string",
"@typescript-eslint/no-confusing-void-expression",
"@typescript-eslint/no-deprecated",
"@typescript-eslint/no-duplicate-type-constituents",
"@typescript-eslint/no-floating-promises",
"@typescript-eslint/no-for-in-array",
"@typescript-eslint/no-implied-eval",
"@typescript-eslint/no-meaningless-void-operator",
"@typescript-eslint/no-misused-promises",
"@typescript-eslint/no-misused-spread",
"@typescript-eslint/no-mixed-enums",
"@typescript-eslint/no-redundant-type-constituents",
"@typescript-eslint/no-unnecessary-boolean-literal-compare",
"@typescript-eslint/no-unnecessary-condition",
"@typescript-eslint/no-unnecessary-qualifier",
"@typescript-eslint/no-unnecessary-template-expression",
"@typescript-eslint/no-unnecessary-type-arguments",
"@typescript-eslint/no-unnecessary-type-assertion",
"@typescript-eslint/no-unnecessary-type-conversion",
"@typescript-eslint/no-unnecessary-type-parameters",
"@typescript-eslint/no-unsafe-argument",
"@typescript-eslint/no-unsafe-assignment",
"@typescript-eslint/no-unsafe-call",
"@typescript-eslint/no-unsafe-enum-comparison",
"@typescript-eslint/no-unsafe-member-access",
"@typescript-eslint/no-unsafe-return",
"@typescript-eslint/no-unsafe-type-assertion",
"@typescript-eslint/no-unsafe-unary-minus",
"@typescript-eslint/non-nullable-type-assertion-style",
"@typescript-eslint/only-throw-error",
"@typescript-eslint/prefer-destructuring",
"@typescript-eslint/prefer-find",
"@typescript-eslint/prefer-includes",
"@typescript-eslint/prefer-nullish-coalescing",
"@typescript-eslint/prefer-optional-chain",
"@typescript-eslint/prefer-promise-reject-errors",
"@typescript-eslint/prefer-readonly",
"@typescript-eslint/prefer-readonly-parameter-types",
"@typescript-eslint/prefer-reduce-type-parameter",
"@typescript-eslint/prefer-regexp-exec",
"@typescript-eslint/prefer-return-this-type",
"@typescript-eslint/prefer-string-starts-ends-with",
"@typescript-eslint/promise-function-async",
"@typescript-eslint/related-getter-setter-pairs",
"@typescript-eslint/require-array-sort-compare",
"@typescript-eslint/require-await",
"@typescript-eslint/restrict-plus-operands",
"@typescript-eslint/restrict-template-expressions",
"@typescript-eslint/return-await",
"@typescript-eslint/strict-boolean-expressions",
"@typescript-eslint/switch-exhaustiveness-check",
"@typescript-eslint/unbound-method",
"@typescript-eslint/use-unknown-in-catch-callback-variable"
];
//#endregion
//#region src/jsPlugins.ts
const ignorePlugins = new Set([
...Object.keys(rulesPrefixesForPlugins),
...Object.values(rulesPrefixesForPlugins),
"local"
]);
const guessEslintPluginName = (pluginName) => {
if (pluginName.startsWith("@")) {
const [scope, maybeSub] = pluginName.split("/");
if (maybeSub) return `${scope}/eslint-plugin-${maybeSub}`;
return `${scope}/eslint-plugin`;
}
return `eslint-plugin-${pluginName}`;
};
const extractPluginId = (ruleId) => {
const firstSlash = ruleId.indexOf("/");
if (firstSlash === -1) return;
if (ruleId.startsWith("@")) {
const secondSlash = ruleId.indexOf("/", firstSlash + 1);
if (secondSlash !== -1) return ruleId.substring(0, secondSlash);
}
return ruleId.substring(0, firstSlash);
};
const isIgnoredPluginRule = (ruleId) => {
const pluginName = extractPluginId(ruleId);
if (pluginName === void 0) return true;
return ignorePlugins.has(pluginName);
};
const enableJsPluginRule = (targetConfig, rule, ruleEntry) => {
const pluginName = extractPluginId(rule);
if (pluginName === void 0) return false;
if (ignorePlugins.has(pluginName)) return false;
if (targetConfig.jsPlugins === void 0) targetConfig.jsPlugins = [];
const eslintPluginName = guessEslintPluginName(pluginName);
if (!targetConfig.jsPlugins.includes(eslintPluginName)) targetConfig.jsPlugins.push(eslintPluginName);
targetConfig.rules = targetConfig.rules || {};
targetConfig.rules[rule] = ruleEntry;
return true;
};
//#endregion
//#region src/plugins_rules.ts
const allRules = Object.values(rules_exports).flat();
/**
* checks if value is validSet, or if validSet is an array, check if value is first value of it
*/
const isValueInSet = (value, validSet) => validSet.includes(value) || Array.isArray(value) && validSet.includes(value[0]);
/**
* check if the value is "error", "warn", 1, 2, ["error", ...], ["warn", ...], [1, ...], or [2, ...]
*/
const isActiveValue = (value) => isValueInSet(value, [
"error",
"warn",
1,
2
]);
const isOffValue = (value) => isValueInSet(value, ["off", 0]);
const isWarnValue = (value) => isValueInSet(value, ["warn", 1]);
const isErrorValue = (value) => isValueInSet(value, ["error", 2]);
const normalizeSeverityValue = (value) => {
if (value === void 0) return value;
if (isWarnValue(value)) {
if (Array.isArray(value)) {
value[0] = "warn";
return value;
}
return "warn";
} else if (isErrorValue(value)) {
if (Array.isArray(value)) {
value[0] = "error";
return value;
}
return "error";
}
if (isOffValue(value)) {
if (Array.isArray(value)) {
value[0] = "off";
return value;
}
return "off";
}
};
const transformRuleEntry = (eslintConfig, targetConfig, options) => {
if (eslintConfig.rules === void 0) return;
if (targetConfig.rules === void 0) targetConfig.rules = {};
for (const [rule, config] of Object.entries(eslintConfig.rules)) {
const normalizedConfig = normalizeSeverityValue(config);
const unsupportedRuleMessage = `unsupported rule: ${rule}`;
if (allRules.includes(rule)) {
if (!options?.withNursery && nurseryRules.includes(rule)) {
options?.reporter?.report(`unsupported rule, but available as a nursery rule: ${rule}`);
continue;
}
if (!options?.typeAware && typescriptTypeAwareRules.includes(rule)) {
options?.reporter?.report(`type-aware rule detected, but \`--type-aware\` is not enabled: ${rule}`);
continue;
}
if (options?.merge) {
if (!(rule in targetConfig.rules)) targetConfig.rules[rule] = normalizedConfig;
} else targetConfig.rules[rule] = normalizedConfig;
} else {
if (options?.jsPlugins) {
if (isOffValue(normalizedConfig)) {
if (eslintConfig.files === void 0) delete targetConfig.rules[rule];
else if (!isIgnoredPluginRule(rule)) targetConfig.rules[rule] = normalizedConfig;
if (eslintConfig.files === void 0) options.reporter?.remove(unsupportedRuleMessage);
continue;
}
if (enableJsPluginRule(targetConfig, rule, normalizedConfig)) continue;
}
if (!isActiveValue(normalizedConfig)) {
if (isOffValue(normalizedConfig)) delete targetConfig.rules[rule];
if (eslintConfig.files === void 0) options?.reporter?.remove(unsupportedRuleMessage);
continue;
}
options?.reporter?.report(unsupportedRuleMessage);
}
}
};
const detectNeededRulesPlugins = (targetConfig) => {
if (targetConfig.rules === void 0) return;
if (targetConfig.plugins === void 0) targetConfig.plugins = [];
for (const rule of Object.keys(targetConfig.rules)) {
if (!rule.includes("/")) continue;
for (const [prefix, plugin] of Object.entries(rulesPrefixesForPlugins)) if (rule.startsWith(`${prefix}/`) && !targetConfig.plugins.includes(plugin)) targetConfig.plugins.push(plugin);
}
if ("files" in targetConfig && targetConfig.plugins.length === 0) delete targetConfig.plugins;
};
const cleanUpUselessOverridesPlugins = (config) => {
if (config.overrides === void 0) return;
if (config.plugins !== void 0) for (const override of config.overrides) {
if (override.plugins === void 0) continue;
override.plugins = override.plugins.filter((overridePlugin) => !config.plugins.includes(overridePlugin));
if (override.plugins.length === 0) delete override.plugins;
}
};
const cleanUpUselessOverridesRules = (config) => {
if (config.rules === void 0 || config.overrides === void 0) return;
const filesPatternMap = /* @__PURE__ */ new Map();
for (const [i, override] of config.overrides.entries()) {
if (override.files === void 0) continue;
const filesKey = JSON.stringify(override.files);
let entry = filesPatternMap.get(filesKey);
if (!entry) {
entry = {
firstIndex: i,
finalRules: {},
indicesToRemove: []
};
filesPatternMap.set(filesKey, entry);
} else entry.indicesToRemove.push(i);
if (override.rules) Object.assign(entry.finalRules, override.rules);
}
for (const entry of filesPatternMap.values()) {
const firstOverride = config.overrides[entry.firstIndex];
firstOverride.rules = entry.finalRules;
if (firstOverride.rules) {
for (const [rule, settings] of Object.entries(firstOverride.rules)) if (config.rules[rule] === settings) delete firstOverride.rules[rule];
if (Object.keys(firstOverride.rules).length === 0) delete firstOverride.rules;
}
for (const indexToRemove of entry.indicesToRemove) delete config.overrides[indexToRemove].rules;
}
};
const cleanUpRulesWhichAreCoveredByCategory = (config) => {
if (config.rules === void 0 || config.categories === void 0) return;
const enabledCategories = Object.entries(config.categories).filter(([, severity]) => severity === "warn" || severity === "error").map(([category]) => category);
for (const [rule, settings] of Object.entries(config.rules)) for (const category of enabledCategories) if (`${category}Rules` in rules_exports && rules_exports[`${category}Rules`].includes(rule)) {
if (settings === config.categories[category] || Array.isArray(settings) && settings.length === 1 && settings[0] === config.categories[category]) delete config.rules[rule];
}
};
const getEnabledCategories = (config) => {
if (config.categories === void 0) return ["correctness"];
const categories = Object.entries(config.categories).filter(([, severity]) => severity === "warn" || severity === "error").map(([category]) => category);
if (Object.keys(config.categories).includes("correctness")) return categories;
return [...categories, "correctness"];
};
const isRuleInEnabledCategory = (rule, enabledCategories) => {
for (const category of enabledCategories) if (`${category}Rules` in rules_exports && rules_exports[`${category}Rules`].includes(rule)) return true;
return false;
};
const cleanUpDisabledRootRules = (config) => {
if (config.rules === void 0) return;
const enabledCategories = getEnabledCategories(config);
for (const [rule, settings] of Object.entries(config.rules)) if (isOffValue(settings) && !isRuleInEnabledCategory(rule, enabledCategories)) delete config.rules[rule];
};
const replaceTypescriptAliasRules = (config) => {
if (config.rules === void 0) return;
for (const rule of Object.keys(config.rules)) {
if (!rule.startsWith("@typescript-eslint/")) continue;
const eslintRule = rule.slice(19);
if (!typescriptRulesExtendEslintRules.includes(eslintRule)) continue;
config.rules[eslintRule] = config.rules[rule];
delete config.rules[rule];
}
if (Object.keys(config.rules).length === 0) delete config.rules;
};
/**
* Oxlint support them only under the node plugin name
*/
const replaceNodePluginName = (config) => {
if (config.rules === void 0) return;
for (const rule of Object.keys(config.rules)) {
if (!rule.startsWith("n/")) continue;
const nodeRule = `node/${rule.slice(2)}`;
config.rules[nodeRule] = config.rules[rule];
delete config.rules[rule];
}
};
//#endregion
//#region src/utilities.ts
const isEqualDeep = (a, b) => {
if (a === b) return true;
const bothAreObjects = a && b && typeof a === "object" && typeof b === "object";
return Boolean(bothAreObjects && Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([k, v]) => isEqualDeep(v, b[k])));
};
//#endregion
//#region src/cleanup.ts
const TS_ESLINT_DEFAULT_OVERRIDE = {
files: [
"**/*.ts",
"**/*.tsx",
"**/*.mts",
"**/*.cts"
],
rules: {
"no-class-assign": "off",
"no-const-assign": "off",
"no-dupe-class-members": "off",
"no-dupe-keys": "off",
"no-func-assign": "off",
"no-import-assign": "off",
"no-new-native-nonconstructor": "off",
"no-obj-calls": "off",
"no-redeclare": "off",
"no-setter-return": "off",
"no-this-before-super": "off",
"no-unsafe-negation": "off",
"no-var": "error",
"prefer-rest-params": "error",
"prefer-spread": "error"
}
};
const cleanUpDefaultTypeScriptOverridesForEslint = (config) => {
if (config.overrides === void 0) return;
for (const [index, override] of config.overrides.entries()) if (isEqualDeep(override, TS_ESLINT_DEFAULT_OVERRIDE)) delete config.overrides[index];
config.overrides = config.overrides.filter((overrides) => Object.keys(overrides).length > 0);
if (Object.keys(config.overrides).length === 0) delete config.overrides;
};
const cleanUpUselessOverridesEntries = (config) => {
cleanUpDefaultTypeScriptOverridesForEslint(config);
cleanUpUselessOverridesRules(config);
cleanUpUselessOverridesPlugins(config);
cleanUpUselessOverridesEnv(config);
cleanUpSupersetEnvs(config);
if (config.overrides === void 0) return;
for (const [overrideIndex, override] of config.overrides.entries()) if (Object.keys(override).length === 1) delete config.overrides[overrideIndex];
config.overrides = config.overrides.filter((overrides) => Object.keys(overrides).length > 0);
mergeConsecutiveIdenticalOverrides(config);
mergeConsecutiveOverridesWithDifferingFiles(config);
if (config.overrides.length === 0) delete config.overrides;
};
const cleanUpOxlintConfig = (config) => {
removeGlobalsWithAreCoveredByEnv(config);
transformBoolGlobalToString(config);
replaceTypescriptAliasRules(config);
replaceNodePluginName(config);
cleanUpRulesWhichAreCoveredByCategory(config);
if (config.globals !== void 0 && Object.keys(config.globals).length === 0) delete config.globals;
if (config.env !== void 0) {
delete config.env.es3;
delete config.env.es5;
delete config.env.es2015;
let detected = false;
for (const esVersion of [...ES_VERSIONS].reverse()) if (detected) delete config.env[`es${esVersion}`];
else if (config.env[`es${esVersion}`] === true) detected = true;
}
if (!("files" in config)) {
cleanUpUselessOverridesEntries(config);
cleanUpDisabledRootRules(config);
}
};
/**
* Merges consecutive identical overrides in the config's overrides array
* Merges only if the overrides are directly next to each other
* (otherwise they could be overriden in between one another).
*
* Example:
*
* ```json
* overrides: [
* {
* "files": [
* "*.ts",
* "*.tsx",
* ],
* "plugins": [
* "typescript",
* ],
* },
* {
* "files": [
* "*.ts",
* "*.tsx",
* ],
* "plugins": [
* "typescript",
* ],
* },
* ]
* ```
*/
function mergeConsecutiveIdenticalOverrides(config) {
if (config.overrides === void 0) return;
if (config.overrides.length <= 1) return;
const mergedOverrides = [];
let i = 0;
while (i < config.overrides.length) {
const current = config.overrides[i];
if (i + 1 < config.overrides.length && isEqualDeep(current, config.overrides[i + 1])) {
mergedOverrides.push(current);
while (i + 1 < config.overrides.length && isEqualDeep(current, config.overrides[i + 1])) i++;
} else mergedOverrides.push(current);
i++;
}
config.overrides = mergedOverrides;
}
/**
* Merge consecutive overrides that have differing files but everything else is identical.
*
* ```json
* "overrides": [
* {
* "files": [
* "*.ts",
* ],
* "rules": {
* "arrow-body-style": "error",
* },
* },
* {
* "files": [
* "*.mts",
* "*.cts",
* ],
* "rules": {
* "arrow-body-style": "error",
* },
* },
* ],
* ```
*/
function mergeConsecutiveOverridesWithDifferingFiles(config) {
if (config.overrides === void 0) return;
if (config.overrides.length <= 1) return;
const mergedOverrides = [];
let i = 0;
while (i < config.overrides.length) {
const current = config.overrides[i];
const currentFiles = current.files;
const { files: _, ...currentWithoutFiles } = current;
let j = i + 1;
const filesToMerge = [...currentFiles];
while (j < config.overrides.length) {
const next = config.overrides[j];
const { files: __, ...nextWithoutFiles } = next;
if (isEqualDeep(currentWithoutFiles, nextWithoutFiles)) {
filesToMerge.push(...next.files);
j++;
} else break;
}
if (j > i + 1) {
const uniqueFiles = [...new Set(filesToMerge)];
mergedOverrides.push({
...current,
files: uniqueFiles
});
i = j;
} else {
mergedOverrides.push(current);
i++;
}
}
config.overrides = mergedOverrides;
}
//#endregion
//#region src/ignorePatterns.ts
const transformIgnorePatterns = (eslintConfig, targetConfig, options) => {
if (eslintConfig.ignores === void 0) return;
if ("files" in targetConfig) {
options?.reporter?.report("ignore list inside overrides is not supported");
return;
}
if (targetConfig.ignorePatterns === void 0) targetConfig.ignorePatterns = [];
for (const ignores of eslintConfig.ignores) if (!targetConfig.ignorePatterns.includes(ignores)) targetConfig.ignorePatterns.push(ignores);
};
//#endregion
//#region src/overrides.ts
const detectSameOverride = (config, override) => {
if (config.overrides === void 0) return [true, override];
const matchedOverride = config.overrides.find(({ files, categories }) => {
return categories === void 0 && isEqualDeep(files, override.files);
});
if (matchedOverride !== void 0) return [false, matchedOverride];
return [true, override];
};
//#endregion
//#region src/js_plugin_fixes.ts
/**
* @link https://github.com/antfu/eslint-config?tab=readme-ov-file#plugins-renaming
*/
const fixForAntfuEslintConfig = (config) => {
if ("renamePlugins" in config && typeof config.renamePlugins === "function") return config.renamePlugins({
ts: "@typescript-eslint",
test: "vitest",
next: "@next/next",
style: "@stylistic"
});
return config;
};
/**
* @link https://github.com/oxc-project/oxlint-migrate/issues/160
*/
const fixForNextEslintConfig = async () => {
if ("Deno" in globalThis || "Bun" in globalThis) return () => {};
const Module = await import("module");
const mod = Module.default || Module;
const originalLoad = mod._load;
mod._load = function(request, ...args) {
if (request && request.includes("@rushstack/eslint-patch")) return {};
return originalLoad.apply(mod, [request, ...args]);
};
return () => {
mod._load = originalLoad;
};
};
function fixForJsPlugins(configs) {
return fixForAntfuEslintConfig(configs);
}
const preFixForJsPlugins = () => {
return fixForNextEslintConfig();
};
//#endregion
//#region src/files.ts
/**
* Process ESLint config files field, separating simple string patterns
* from nested arrays (AND glob patterns which are unsupported in oxlint).
*
* @param files - The files field from ESLint config (can be string, array of strings, or array with nested arrays)
* @param reporter - Optional reporter to report unsupported AND patterns
* @returns Array of simple string patterns (valid files)
*/
function processConfigFiles(files, reporter) {
const filesArray = Array.isArray(files) ? files : [files];
const simpleFiles = [];
for (const file of filesArray) if (Array.isArray(file)) reporter?.report(`ESLint AND glob patterns (nested arrays in files) are not supported in oxlint: ${JSON.stringify(file)}`);
else simpleFiles.push(file);
return simpleFiles;
}
//#endregion
//#region src/index.ts
const buildConfig = (configs, oxlintConfig, options) => {
if (ox