Skip to content

Commit

Permalink
feat: support overrides in buildFromOxlintConfig(File)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sysix committed Nov 29, 2024
1 parent 2f27838 commit f786b83
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 12 deletions.
21 changes: 15 additions & 6 deletions src/build-from-oxlint-config/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'node:fs';
import type { Linter } from 'eslint';
import JSONCParser from 'jsonc-parser';
import {
import type {
EslintPluginOxLintConfig,
OxlintConfig,
OxlintConfigCategories,
OxlintConfigPlugins,
Expand All @@ -13,6 +13,7 @@ import {
readCategoriesFromConfig,
} from './categories.js';
import { readPluginsFromConfig } from './plugins.js';
import { handleOverridesScope, readOverridesFromConfig } from './overrides.js';

// default plugins, see <https://oxc.rs/docs/guide/usage/linter/config#plugins>
const defaultPlugins: OxlintConfigPlugins = ['react', 'unicorn', 'typescript'];
Expand Down Expand Up @@ -59,9 +60,10 @@ const getConfigContent = (
*/
export const buildFromOxlintConfig = (
config: OxlintConfig
): Linter.Config<Record<string, 'off'>>[] => {
): EslintPluginOxLintConfig[] => {
const rules: Record<string, 'off'> = {};
const plugins = readPluginsFromConfig(config) ?? defaultPlugins;
const categories = readCategoriesFromConfig(config) ?? defaultCategories;

// it is not a plugin but it is activated by default
plugins.push('eslint');
Expand All @@ -81,15 +83,22 @@ export const buildFromOxlintConfig = (
const configRules = readRulesFromConfig(config);

if (configRules !== undefined) {
handleRulesScope(configRules, rules);
handleRulesScope(configRules, rules, true);
}

return [
const overrides = readOverridesFromConfig(config);
const configs: EslintPluginOxLintConfig[] = [
{
name: 'oxlint/from-oxlint-config',
rules,
},
];

if (overrides !== undefined) {
handleOverridesScope(overrides, configs, categories);
}

return configs;
};

/**
Expand All @@ -101,7 +110,7 @@ export const buildFromOxlintConfig = (
*/
export const buildFromOxlintConfigFile = (
oxlintConfigFile: string
): Linter.Config<Record<string, 'off'>>[] => {
): EslintPluginOxLintConfig[] => {
const config = getConfigContent(oxlintConfigFile);

// we could not parse form the file, do not build with default values
Expand Down
48 changes: 48 additions & 0 deletions src/build-from-oxlint-config/overrides.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { handleCategoriesScope } from './categories.js';
import { readPluginsFromConfig } from './plugins.js';
import { handleRulesScope, readRulesFromConfig } from './rules.js';
import {
EslintPluginOxLintConfig,
OxlintConfig,
OxlintConfigCategories,
OxlintConfigOverride,
} from './types.js';

export const handleOverridesScope = (
overrides: OxlintConfigOverride[],
configs: EslintPluginOxLintConfig[],
baseCategories?: OxlintConfigCategories
): void => {
for (const overrideIndex in overrides) {
const override = overrides[overrideIndex];
const eslintRules: Record<string, 'off'> = {};
const eslintConfig: EslintPluginOxLintConfig = {
name: `oxlint/from-oxlint-config-override-${overrideIndex}`,
};

// expect that oxlint `files` syntax is the same as eslint
eslintConfig.files = override.files;

const plugins = readPluginsFromConfig(override);
if (baseCategories !== undefined && plugins !== undefined) {
handleCategoriesScope(plugins, baseCategories, eslintRules);
}

const rules = readRulesFromConfig(override);
if (rules !== undefined) {
// ToDo -- when off, we should enable the default settings
handleRulesScope(rules, eslintRules, false);
}

eslintConfig.rules = eslintRules;
configs.push(eslintConfig);
}
};

export const readOverridesFromConfig = (
config: OxlintConfig
): OxlintConfigOverride[] | undefined => {
return 'overrides' in config && Array.isArray(config.overrides)
? (config.overrides as OxlintConfigOverride[])
: undefined;
};
8 changes: 6 additions & 2 deletions src/build-from-oxlint-config/plugins.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { OxlintConfig, OxlintConfigPlugins } from './types.js';
import {
OxlintConfig,
OxlintConfigOverride,
OxlintConfigPlugins,
} from './types.js';

/**
* tries to return the "plugins" section from the config.
* it returns `undefined` when not found or invalid.
*/
export const readPluginsFromConfig = (
config: OxlintConfig
config: OxlintConfig | OxlintConfigOverride
): OxlintConfigPlugins | undefined => {
return 'plugins' in config && Array.isArray(config.plugins)
? (config.plugins as OxlintConfigPlugins)
Expand Down
19 changes: 15 additions & 4 deletions src/build-from-oxlint-config/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import {
aliasPluginNames,
reactHookRulesInsideReactScope,
} from '../constants.js';
import { OxlintConfig, OxlintConfigRules } from './types.js';
import {
OxlintConfig,
OxlintConfigOverride,
OxlintConfigRules,
} from './types.js';
import configByCategory from '../generated/configs-by-category.js';
import { isObject } from './utils.js';

Expand Down Expand Up @@ -73,7 +77,8 @@ const isActiveValue = (value: unknown) =>
*/
export const handleRulesScope = (
oxlintRules: OxlintConfigRules,
rules: Record<string, 'off'>
rules: Record<string, 'off' | 'warn'>,
disableRule: boolean
): void => {
for (const rule in oxlintRules) {
const eslintName = getEsLintRuleName(rule);
Expand All @@ -90,7 +95,13 @@ export const handleRulesScope = (
rules[eslintName] = 'off';
} else if (rule in rules && isDeactivateValue(oxlintRules[rule])) {
// rules extended by categories or plugins can be disabled manually
delete rules[eslintName];
if (disableRule) {
delete rules[eslintName];
}
// inside overrides we need to enable the rule again
else {
rules[eslintName] = 'warn';
}
}
}
};
Expand All @@ -100,7 +111,7 @@ export const handleRulesScope = (
* it returns `undefined` when not found or invalid.
*/
export const readRulesFromConfig = (
config: OxlintConfig
config: OxlintConfig | OxlintConfigOverride
): OxlintConfigRules | undefined => {
return 'rules' in config && isObject(config.rules)
? (config.rules as OxlintConfigRules)
Expand Down
12 changes: 12 additions & 0 deletions src/build-from-oxlint-config/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import type { Linter } from 'eslint';

export type OxlintConfigPlugins = string[];

export type OxlintConfigCategories = Record<string, unknown>;

export type OxlintConfigRules = Record<string, unknown>;

export type OxlintConfigOverride = {
files: string[];
plugins?: OxlintConfigPlugins;
rules?: OxlintConfigRules;
};

export type EslintPluginOxLintConfig = Linter.Config<
Record<string, 'off' | 'warn'>
>;

export type OxlintConfig = {
[key: string]: unknown;
plugins?: OxlintConfigPlugins;
Expand Down

0 comments on commit f786b83

Please sign in to comment.