chore: finalize oxlint migration config

This commit is contained in:
xingyu4j
2026-03-13 20:25:25 +08:00
parent 40c66958bc
commit e7fa87b301
47 changed files with 1466 additions and 414 deletions

View File

@@ -0,0 +1,17 @@
import type { OxlintConfig } from 'oxlint';
const ignores: OxlintConfig = {
ignorePatterns: [
'**/dist/**',
'**/node_modules/**',
'docs/**',
'playground/public/**',
'**/*.json',
'**/*.md',
'**/*.svg',
'**/*.yaml',
'**/*.yml',
],
};
export { ignores };

View File

@@ -0,0 +1,18 @@
import type { OxlintConfig } from 'oxlint';
const importPluginConfig: OxlintConfig = {
rules: {
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
'import/first': 'error',
'import/no-duplicates': 'error',
'import/no-mutable-exports': 'error',
'import/no-named-as-default': 'off',
'import/no-named-as-default-member': 'off',
'import/no-named-default': 'error',
'import/no-self-import': 'error',
'import/no-unassigned-import': 'off',
'import/no-webpack-loader-syntax': 'error',
},
};
export { importPluginConfig };

View File

@@ -0,0 +1,90 @@
import type { OxlintConfig } from 'oxlint';
import { defineConfig as defineOxlintConfig } from 'oxlint';
import { ignores } from './ignores';
import { importPluginConfig } from './import';
import { javascript } from './javascript';
import { node } from './node';
import { overrides } from './overrides';
import { plugins } from './plugins';
import { tailwindcss } from './tailwindcss';
import { test } from './test';
import { typescript } from './typescript';
import { unicorn } from './unicorn';
import { vue } from './vue';
function mergeOxlintConfigs(...configs: OxlintConfig[]): OxlintConfig {
const merged: OxlintConfig = {};
for (const config of configs) {
merged.categories =
merged.categories && config.categories
? { ...merged.categories, ...config.categories }
: (config.categories ?? merged.categories);
merged.env =
merged.env && config.env
? { ...merged.env, ...config.env }
: (config.env ?? merged.env);
merged.globals =
merged.globals && config.globals
? { ...merged.globals, ...config.globals }
: (config.globals ?? merged.globals);
merged.ignorePatterns = [
...(merged.ignorePatterns ?? []),
...(config.ignorePatterns ?? []),
];
merged.jsPlugins = [
...new Set([...(merged.jsPlugins ?? []), ...(config.jsPlugins ?? [])]),
];
merged.overrides = [
...(merged.overrides ?? []),
...(config.overrides ?? []),
];
merged.plugins = [
...new Set([...(merged.plugins ?? []), ...(config.plugins ?? [])]),
];
merged.rules =
merged.rules && config.rules
? { ...merged.rules, ...config.rules }
: (config.rules ?? merged.rules);
merged.settings =
merged.settings && config.settings
? { ...merged.settings, ...config.settings }
: (config.settings ?? merged.settings);
}
return merged;
}
const oxlintConfig = defineOxlintConfig(
mergeOxlintConfigs(
javascript,
ignores,
plugins,
importPluginConfig,
node,
overrides,
tailwindcss,
test,
typescript,
unicorn,
vue,
),
);
export {
ignores,
importPluginConfig,
javascript,
mergeOxlintConfigs,
node,
overrides,
oxlintConfig,
plugins,
tailwindcss,
test,
typescript,
unicorn,
vue,
};

View File

@@ -0,0 +1,156 @@
import type { OxlintConfig } from 'oxlint';
const javascript: OxlintConfig = {
categories: {
correctness: 'error',
suspicious: 'warn',
},
env: {
browser: true,
es2021: true,
node: true,
},
globals: {
document: 'readonly',
navigator: 'readonly',
window: 'readonly',
},
rules: {
'accessor-pairs': [
'error',
{
enforceForClassMembers: true,
setWithoutGet: true,
},
],
'array-callback-return': 'error',
'block-scoped-var': 'error',
'default-case-last': 'error',
eqeqeq: ['error', 'always'],
'eslint/no-unreachable': 'error',
'new-cap': [
'error',
{
capIsNew: false,
newIsCap: true,
properties: true,
},
],
'no-alert': 'error',
'no-array-constructor': 'error',
'no-caller': 'error',
'no-case-declarations': 'error',
'no-console': ['error', { allow: ['warn', 'error'] }],
'no-control-regex': 'off',
'no-debugger': 'error',
'no-empty': ['error', { allowEmptyCatch: true }],
'no-fallthrough': 'error',
'no-new-func': 'error',
'no-new-object': 'error',
'no-new-symbol': 'error',
'no-labels': ['error', { allowLoop: false, allowSwitch: false }],
'no-lone-blocks': 'error',
'no-multi-str': 'error',
'no-octal': 'error',
'no-octal-escape': 'error',
'no-proto': 'error',
'no-prototype-builtins': 'error',
'no-redeclare': ['error', { builtinGlobals: false }],
'no-regex-spaces': 'error',
'no-self-compare': 'error',
'no-sequences': 'error',
'no-shadow': 'off',
'no-shadow-restricted-names': 'error',
'eslint/no-empty-function': [
'error',
{
allow: ['arrowFunctions', 'functions', 'methods'],
},
],
'no-template-curly-in-string': 'error',
'no-throw-literal': 'error',
'no-undef-init': 'error',
'no-unused-expressions': [
'error',
{
allowShortCircuit: true,
allowTaggedTemplates: true,
allowTernary: true,
},
],
'eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
},
],
'no-var': 'error',
'no-eval': 'error',
'no-iterator': 'error',
'no-new-wrappers': 'error',
'no-restricted-globals': [
'error',
{ message: 'Use `globalThis` instead.', name: 'global' },
{ message: 'Use `globalThis` instead.', name: 'self' },
],
'no-useless-call': 'error',
'no-useless-computed-key': 'error',
'no-useless-constructor': 'error',
'no-useless-return': 'error',
'object-shorthand': [
'error',
'always',
{
avoidQuotes: true,
ignoreConstructors: false,
},
],
'one-var': ['error', { initialized: 'never' }],
'prefer-const': [
'error',
{
destructuring: 'all',
ignoreReadBeforeAssign: true,
},
],
'eslint/prefer-arrow-callback': [
'error',
{
allowNamedFunctions: false,
allowUnboundThis: true,
},
],
'prefer-exponentiation-operator': 'error',
'prefer-promise-reject-errors': 'error',
'eslint/prefer-regex-literals': [
'error',
{
disallowRedundantWrapping: true,
},
],
'prefer-rest-params': 'error',
'prefer-spread': 'error',
'prefer-template': 'error',
'spaced-comment': 'error',
'symbol-description': 'error',
'unicode-bom': ['error', 'never'],
'use-isnan': [
'error',
{
enforceForIndexOf: true,
enforceForSwitchCase: true,
},
],
'valid-typeof': [
'error',
{
requireStringLiterals: true,
},
],
'vars-on-top': 'error',
yoda: ['error', 'never'],
},
};
export { javascript };

View File

@@ -0,0 +1,11 @@
import type { OxlintConfig } from 'oxlint';
const node: OxlintConfig = {
rules: {
'node/no-exports-assign': 'error',
'node/no-new-require': 'error',
'node/no-path-concat': 'error',
},
};
export { node };

View File

@@ -0,0 +1,98 @@
import type { OxlintConfig } from 'oxlint';
const overrides: OxlintConfig = {
overrides: [
{
files: ['*.d.ts', '**/*.d.ts'],
rules: {
'import/no-unassigned-import': 'off',
'typescript/triple-slash-reference': 'off',
},
},
{
files: [
'**/__tests__/**/*.js',
'**/__tests__/**/*.cjs',
'**/__tests__/**/*.mjs',
'**/__tests__/**/*.jsx',
'**/__tests__/**/*.ts',
'**/__tests__/**/*.cts',
'**/__tests__/**/*.mts',
'**/__tests__/**/*.tsx',
'**/*.spec.js',
'**/*.spec.cjs',
'**/*.spec.mjs',
'**/*.spec.jsx',
'**/*.spec.ts',
'**/*.spec.cts',
'**/*.spec.mts',
'**/*.spec.tsx',
'**/*.test.js',
'**/*.test.cjs',
'**/*.test.mjs',
'**/*.test.jsx',
'**/*.test.ts',
'**/*.test.cts',
'**/*.test.mts',
'**/*.test.tsx',
'**/*.bench.js',
'**/*.bench.cjs',
'**/*.bench.mjs',
'**/*.bench.jsx',
'**/*.bench.ts',
'**/*.bench.cts',
'**/*.bench.mts',
'**/*.bench.tsx',
'**/*.benchmark.js',
'**/*.benchmark.cjs',
'**/*.benchmark.mjs',
'**/*.benchmark.jsx',
'**/*.benchmark.ts',
'**/*.benchmark.cts',
'**/*.benchmark.mts',
'**/*.benchmark.tsx',
],
rules: {
'no-console': 'off',
},
},
{
files: ['packages/@core/base/shared/src/utils/inference.ts'],
rules: {
'vue/prefer-import-from-vue': 'off',
},
},
{
files: ['packages/@core/ui-kit/menu-ui/src/sub-menu.vue'],
rules: {
'import/no-self-import': 'off',
},
},
{
files: [
'scripts/**/*.js',
'scripts/**/*.cjs',
'scripts/**/*.mjs',
'scripts/**/*.jsx',
'scripts/**/*.ts',
'scripts/**/*.cts',
'scripts/**/*.mts',
'scripts/**/*.tsx',
'internal/**/*.js',
'internal/**/*.cjs',
'internal/**/*.mjs',
'internal/**/*.jsx',
'internal/**/*.ts',
'internal/**/*.cts',
'internal/**/*.mts',
'internal/**/*.tsx',
],
rules: {
'no-console': 'off',
'unicorn/no-process-exit': 'off',
},
},
],
};
export { overrides };

View File

@@ -0,0 +1,7 @@
import type { OxlintConfig } from 'oxlint';
const plugins: OxlintConfig = {
plugins: ['import', 'node', 'oxc', 'typescript', 'unicorn', 'vitest', 'vue'],
};
export { plugins };

View File

@@ -0,0 +1,50 @@
import type { OxlintConfig } from 'oxlint';
import eslintPluginBetterTailwindcss from 'eslint-plugin-better-tailwindcss';
import { getDefaultSelectors } from 'eslint-plugin-better-tailwindcss/defaults';
import { SelectorKind } from 'eslint-plugin-better-tailwindcss/types';
const selectors = [
...getDefaultSelectors(),
{
kind: SelectorKind.Attribute,
match: [{ type: 'objectValues' }],
name: '^classNames$',
},
];
const settings = {
entryPoint: 'packages/@core/base/design/src/css/global.css',
selectors,
};
const tailwindcss: OxlintConfig = {
// Generated shadcn-ui internals are intentionally left unmanaged.
ignorePatterns: ['packages/@core/ui-kit/shadcn-ui/**/*'],
jsPlugins: [
{
name: 'better-tailwindcss',
specifier: 'eslint-plugin-better-tailwindcss',
},
],
rules: {
...eslintPluginBetterTailwindcss.configs.recommended.rules,
'better-tailwindcss/enforce-consistent-class-order': [
'error',
{
detectComponentClasses: true,
unknownClassOrder: 'asc',
unknownClassPosition: 'start',
},
],
// Let Prettier own wrapping decisions to avoid ping-pong formatting.
'better-tailwindcss/enforce-consistent-line-wrapping': 'off',
'better-tailwindcss/no-unknown-classes': 'off',
},
settings: {
'better-tailwindcss': settings,
'eslint-plugin-better-tailwindcss': settings,
},
};
export { tailwindcss };

View File

@@ -0,0 +1,23 @@
import type { OxlintConfig } from 'oxlint';
const test: OxlintConfig = {
rules: {
'jest/no-conditional-expect': 'off',
'jest/require-to-throw-message': 'off',
'vitest/consistent-test-it': [
'error',
{
fn: 'it',
withinDescribe: 'it',
},
],
'vitest/hoisted-apis-on-top': 'off',
'vitest/no-focused-tests': 'error',
'vitest/no-identical-title': 'error',
'vitest/no-import-node-test': 'error',
'vitest/prefer-hooks-in-order': 'error',
'vitest/prefer-lowercase-title': 'error',
},
};
export { test };

View File

@@ -0,0 +1,12 @@
import type { OxlintConfig } from 'oxlint';
const typescript: OxlintConfig = {
rules: {
'typescript/ban-ts-comment': 'error',
'typescript/no-non-null-assertion': 'error',
'typescript/no-var-requires': 'error',
'typescript/triple-slash-reference': 'error',
},
};
export { typescript };

View File

@@ -0,0 +1,14 @@
import type { OxlintConfig } from 'oxlint';
const unicorn: OxlintConfig = {
rules: {
'unicorn/consistent-function-scoping': 'off',
'unicorn/no-process-exit': 'error',
'unicorn/no-single-promise-in-promise-methods': 'off',
'unicorn/no-useless-spread': 'off',
'unicorn/prefer-global-this': 'off',
'unicorn/prefer-module': 'error',
},
};
export { unicorn };

View File

@@ -0,0 +1,9 @@
import type { OxlintConfig } from 'oxlint';
const vue: OxlintConfig = {
rules: {
'vue/prefer-import-from-vue': 'error',
},
};
export { vue };

View File

@@ -0,0 +1,21 @@
import type { OxlintConfig } from 'oxlint';
import { defineConfig as defineOxlintConfig } from 'oxlint';
import { mergeOxlintConfigs, oxlintConfig } from './configs';
type VbenOxlintConfig = Omit<OxlintConfig, 'extends'> & {
extends?: OxlintConfig[];
};
function defineConfig(config: VbenOxlintConfig = {}) {
const { extends: extendedConfigs = [], ...restConfig } = config;
return defineOxlintConfig(
mergeOxlintConfigs(oxlintConfig, ...extendedConfigs, restConfig),
);
}
export { defineConfig, oxlintConfig };
export * from './configs';
export type { OxlintConfig, VbenOxlintConfig };