chore(configs): migrate oxlint→eslint presets, refactor tsconfig

- Replace @robonen/oxlint with @robonen/eslint (composable ESLint flat-config
  presets: base, typescript, vue, vitest, imports, node, stylistic).
- Plugins bundled as deps: typescript-eslint, eslint-plugin-vue,
  @vitest/eslint-plugin, eslint-plugin-import-x, eslint-plugin-n,
  eslint-plugin-unicorn, @stylistic/eslint-plugin.
- @robonen/tsconfig: add base/dom/node/vue configs for composite project refs.
This commit is contained in:
2026-06-07 16:28:10 +07:00
parent 1d3efa5028
commit 7693b49253
51 changed files with 988 additions and 916 deletions
+21
View File
@@ -0,0 +1,21 @@
# Rules Reference
Документация по preset-ам `@robonen/eslint`: что включает каждый preset и какие правила чаще всего влияют на код.
## Presets
- [base](./base.md)
- [typescript](./typescript.md)
- [vue](./vue.md)
- [vitest](./vitest.md)
- [imports](./imports.md)
- [node](./node.md)
- [stylistic](./stylistic.md)
## Как читать
- `Purpose` — зачем preset подключать.
- `Key Rules` — ключевые правила из preset-а (не полный dump).
- `Examples` — минимальные `good/bad` примеры.
Для точного источника правил см. файлы в `configs/eslint/src/presets/*.ts`.
+36
View File
@@ -0,0 +1,36 @@
# base preset
## Purpose
Базовый quality-профиль для JS/TS-проектов: корректность, анти-паттерны, безопасные дефолты. Включает `@eslint/js` recommended (аналог oxlint-категории `correctness`) + правила `unicorn`.
## Key Rules
- `eqeqeq`: запрещает `==`, требует `===`.
- `no-unused-vars`: запрещает неиспользуемые переменные (кроме `_name`).
- `no-eval`, `no-var`, `prefer-const`.
- `unicorn/prefer-node-protocol`: требует `node:` для built-in модулей.
- `unicorn/no-thenable`: запрещает thenable-объекты.
> Правила `oxc/*` из `@robonen/oxlint` не имеют аналога в ESLint и были убраны;
> их назначение покрывается `@eslint/js` recommended и `unicorn`.
## Examples
```ts
// ✅ Good
import { readFile } from 'node:fs/promises';
const id = 42;
if (id === 42) {
throw new Error('unexpected');
}
// ❌ Bad
import { readFile } from 'fs/promises';
var id = 42;
if (id == '42') {
throw 'unexpected';
}
```
+27
View File
@@ -0,0 +1,27 @@
# imports preset
## Purpose
Чистые границы модулей и предсказуемые импорты (через `eslint-plugin-import-x`).
## Key Rules
- `import-x/no-duplicates`.
- `import-x/no-self-import`.
- `import-x/no-cycle` (warn).
- `import-x/no-mutable-exports`.
- `import-x/consistent-type-specifier-style`: `prefer-top-level`.
## Examples
```ts
// ✅ Good
import type { User } from './types';
import { getUser } from './service';
// ❌ Bad
import { getUser } from './service';
import { getUser as getUser2 } from './service';
export let state = 0;
```
+22
View File
@@ -0,0 +1,22 @@
# node preset
## Purpose
Node.js-правила (через `eslint-plugin-n`) и Node-глобалы в `languageOptions.globals`.
## Key Rules
- `n/no-exports-assign`: запрещает перезапись `exports`.
- `n/no-new-require`: запрещает `new require(...)`.
## Examples
```ts
// ✅ Good
module.exports = { run };
const mod = require('./mod');
// ❌ Bad
exports = { run };
const bad = new require('./mod');
```
+51
View File
@@ -0,0 +1,51 @@
# stylistic preset
## Purpose
Форматирование через `@stylistic/eslint-plugin` (отступы, пробелы, скобки, переносы, TS/JSX-стиль).
## Defaults
- `indent: 2`
- `quotes: single`
- `semi: always`
- `braceStyle: stroustrup`
- `commaDangle: always-multiline`
- `arrowParens: as-needed`
## Key Rules
- `@stylistic/indent`, `@stylistic/no-tabs`.
- `@stylistic/quotes`, `@stylistic/semi`.
- `@stylistic/object-curly-spacing`, `@stylistic/comma-spacing`.
- `@stylistic/arrow-spacing`, `@stylistic/space-before-function-paren`.
- `@stylistic/max-statements-per-line`.
- `@stylistic/no-mixed-operators`.
- `@stylistic/member-delimiter-style` (TS).
## Examples
```ts
// ✅ Good
type User = {
id: string;
role: 'admin' | 'user';
};
const value = condition
? 'yes'
: 'no';
const sum = (a: number, b: number) => a + b;
// ❌ Bad
type User = {
id: string
role: 'admin' | 'user'
}
const value = condition ? 'yes' : 'no'; const x = 1;
const sum=(a:number,b:number)=>{ return a+b };
```
Полный список правил и их настройки см. в `src/presets/stylistic.ts`.
+33
View File
@@ -0,0 +1,33 @@
# typescript preset
## Purpose
TypeScript-правила для `.ts/.tsx/.mts/.cts` и `<script lang="ts">` в `.vue`. Базируется на `typescript-eslint` recommended (без type-checking).
## Key Rules
- `@typescript-eslint/consistent-type-imports`: выносит типы в `import type`.
- `@typescript-eslint/no-import-type-side-effects`: запрещает сайд-эффекты в type import.
- `@typescript-eslint/prefer-as-const`.
- `@typescript-eslint/no-namespace`, `@typescript-eslint/triple-slash-reference`.
- `@typescript-eslint/no-wrapper-object-types`: запрещает `String`, `Number`, `Boolean`.
## Examples
```ts
// ✅ Good
import type { User } from './types';
const status = 'ok' as const;
interface Payload {
value: string;
}
// ❌ Bad
import { User } from './types';
type Boxed = String;
namespace Legacy {
export const x = 1;
}
```
+34
View File
@@ -0,0 +1,34 @@
# vitest preset
## Purpose
Правила для тестов (`*.test.*`, `*.spec.*`, `test/**`, `__tests__/**`).
## Key Rules
- `vitest/no-conditional-tests`.
- `vitest/no-import-node-test`.
- `vitest/prefer-to-be-truthy`, `vitest/prefer-to-be-falsy`.
- `vitest/prefer-to-have-length`.
- Relaxations: `no-unused-vars` и `@typescript-eslint/no-explicit-any` выключены для тестов.
## Examples
```ts
// ✅ Good
import { describe, it, expect } from 'vitest';
describe('list', () => {
it('has items', () => {
expect([1, 2, 3]).toHaveLength(3);
expect(true).toBeTruthy();
});
});
// ❌ Bad
if (process.env.CI) {
it('conditionally runs', () => {
expect(true).toBe(true);
});
}
```
+30
View File
@@ -0,0 +1,30 @@
# vue preset
## Purpose
Правила для Vue 3 с упором на Composition API и `<script setup>`.
## Key Rules
- `vue/no-export-in-script-setup`.
- `vue/no-import-compiler-macros`.
- `vue/define-props-declaration`: type-based.
- `vue/define-emits-declaration`: type-based.
- `vue/valid-define-props`, `vue/valid-define-emits`.
- `vue/no-lifecycle-after-await`.
## Examples
```vue
<script setup lang="ts">
const props = defineProps<{ id: string }>();
const emit = defineEmits<{ change: [value: string] }>();
</script>
<!-- Bad -->
<script setup lang="ts">
import { defineProps } from 'vue';
export const x = 1;
const props = defineProps({ id: String });
</script>
```