@oxlint/migrate
Version:
Generates a `.oxlintrc.json` from a existing eslint flat config
192 lines (191 loc) • 6.07 kB
JavaScript
import * as rules from "./generated/rules.mjs";
import { nurseryRules } from "./generated/rules.mjs";
import { typescriptTypeAwareRules, rulesPrefixesForPlugins, typescriptRulesExtendEslintRules } from "./constants.mjs";
const allRules = Object.values(rules).flat();
const isValueInSet = (value, validSet) => validSet.includes(value) || Array.isArray(value) && validSet.includes(value[0]);
const isActiveValue = (value) => isValueInSet(value, ["error", "warn", 1, 2]);
const isOffValue = (value) => isValueInSet(value, ["off", 0]);
const isErrorValue = (value) => isValueInSet(value, ["error", 1]);
const isWarnValue = (value) => isValueInSet(value, ["warn", 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";
}
return void 0;
};
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)) {
if (allRules.includes(rule)) {
if (!options?.withNursery && nurseryRules.includes(rule)) {
options?.reporter !== void 0 && options.reporter(`unsupported rule, but in development: ${rule}`);
continue;
}
if (!options?.typeAware && typescriptTypeAwareRules.includes(rule)) {
options?.reporter !== void 0 && options.reporter(
`type-aware rule detected, but \`--type-aware\` is not enabled: ${rule}`
);
continue;
}
if (options?.merge) {
if (!(rule in targetConfig.rules)) {
targetConfig.rules[rule] = normalizeSeverityValue(config);
}
} else {
targetConfig.rules[rule] = normalizeSeverityValue(config);
}
} else {
if (isActiveValue(config)) {
options?.reporter !== void 0 && options.reporter(`unsupported rule: ${rule}`);
}
}
}
};
const detectNeededRulesPlugins = (targetConfig, options) => {
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;
}
let found = false;
for (const [prefix, plugin] of Object.entries(rulesPrefixesForPlugins)) {
if (rule.startsWith(`${prefix}/`)) {
if (!targetConfig.plugins.includes(plugin)) {
targetConfig.plugins.push(plugin);
}
found = true;
}
}
if (!found) {
options?.reporter !== void 0 && options.reporter(`unsupported plugin for rule: ${rule}`);
}
}
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;
}
for (const override of config.overrides) {
if (override.rules === void 0) {
continue;
}
for (const [rule, settings] of Object.entries(override.rules)) {
if (config.rules[rule] === settings) {
delete override.rules[rule];
}
}
if (Object.keys(override.rules).length === 0) {
delete override.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 && // @ts-expect-error -- ts can not resolve the type
rules[`${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 replaceTypescriptAliasRules = (config) => {
if (config.rules === void 0) {
return;
}
for (const rule of Object.keys(config.rules)) {
const prefix = "@typescript-eslint/";
if (!rule.startsWith(prefix)) {
continue;
}
const eslintRule = rule.slice(prefix.length);
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;
}
};
const replaceNodePluginName = (config) => {
if (config.rules === void 0) {
return;
}
for (const rule of Object.keys(config.rules)) {
const prefix = "n/";
if (!rule.startsWith(prefix)) {
continue;
}
const nodeRule = `node/${rule.slice(prefix.length)}`;
config.rules[nodeRule] = config.rules[rule];
delete config.rules[rule];
}
};
export {
cleanUpRulesWhichAreCoveredByCategory,
cleanUpUselessOverridesPlugins,
cleanUpUselessOverridesRules,
detectNeededRulesPlugins,
replaceNodePluginName,
replaceTypescriptAliasRules,
transformRuleEntry
};