feat(lint): integrate Oxlint for enhanced linting capabilities

Added a new configuration file `.oxlintrc.json` to incorporate Oxlint into the project, allowing for improved linting of TypeScript and React code. Updated the linting scripts in `package.json` to run Oxlint alongside ESLint, ensuring a comprehensive linting process. This change enhances code quality and consistency across the codebase.
This commit is contained in:
alisaza 2026-09-10 12:54:10 +03:30
parent 1da7df0786
commit 09debac84f
7 changed files with 4130 additions and 2035 deletions

1633
.oxlintrc.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -138,7 +138,6 @@ const persistUserStorage = (next: UserStorageData & Record<string, unknown>): vo
refreshToken?: unknown refreshToken?: unknown
} }
void _legacyRefreshToken
localStorage.setItem(AUTH_CONFIG.localStorageKey, JSON.stringify(sanitized)) localStorage.setItem(AUTH_CONFIG.localStorageKey, JSON.stringify(sanitized))
} }

View File

@ -27,6 +27,14 @@ function rulesOnly(configs, files = ['**/*.{ts,tsx}']) {
* - no-redundant-type-constituents: off `string | 'literal'` is intentional public API style * - no-redundant-type-constituents: off `string | 'literal'` is intentional public API style
* - prefer-nullish-coalescing: ignorePrimitives flag object nullish only, not `x || 0` * - prefer-nullish-coalescing: ignorePrimitives flag object nullish only, not `x || 0`
* - react-hooks/set-state-in-effect: off HeroUI / controlled-input patterns * - react-hooks/set-state-in-effect: off HeroUI / controlled-input patterns
*
* Hybrid with Oxlint (`pnpm lint` = oxlint then eslint):
* ESLint remains the authority for the full rule bar. Do not weaken rules here
* to satisfy Oxlint. Rules left ESLint-only (not ported or incomplete in Oxlint):
* no-restricted-syntax, import/order, padding-line-between-statements, react/jsx-sort-props,
* prettier/prettier, and no-misused-promises (Oxlint option parity for JSX attributes).
* no-restricted-imports stays on in Oxlint for app/components/features, with the same
* wrapper exceptions ESLint ignores (formElements, consumer/input, heroui).
*/ */
const eslintConfig = defineConfig([ const eslintConfig = defineConfig([
{ {

View File

@ -1,6 +1,6 @@
{ {
"name": "ghabilee-admin", "name": "ghabilee-admin",
"version": "0.1.9", "version": "0.1.10",
"license": "MIT", "license": "MIT",
"private": true, "private": true,
"scripts": { "scripts": {
@ -13,7 +13,9 @@
"build:next": "next build && pnpm bundle:check", "build:next": "next build && pnpm bundle:check",
"start": "next start", "start": "next start",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"lint": "eslint . --max-warnings 0", "lint": "pnpm lint:oxlint && pnpm lint:eslint",
"lint:oxlint": "oxlint --type-aware --deny-warnings .",
"lint:eslint": "eslint . --max-warnings 0",
"lint:fix": "eslint . --fix --max-warnings 0", "lint:fix": "eslint . --fix --max-warnings 0",
"check": "pnpm typecheck && pnpm lint && pnpm test && pnpm architecture:check && pnpm unused:check", "check": "pnpm typecheck && pnpm lint && pnpm test && pnpm architecture:check && pnpm unused:check",
"architecture:check": "madge --extensions ts,tsx --ts-config tsconfig.json --circular app components context hooks services lib config", "architecture:check": "madge --extensions ts,tsx --ts-config tsconfig.json --circular app components context hooks services lib config",
@ -57,7 +59,7 @@
"clsx": "2.1.1", "clsx": "2.1.1",
"dayjs": "^1.11.19", "dayjs": "^1.11.19",
"framer-motion": "12.43.0", "framer-motion": "12.43.0",
"isomorphic-dompurify": "^3.19.0", "isomorphic-dompurify": "3.19.0",
"jalaali-js": "^1.2.8", "jalaali-js": "^1.2.8",
"js-cookie": "^3.0.7", "js-cookie": "^3.0.7",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
@ -79,9 +81,11 @@
"devDependencies": { "devDependencies": {
"@axe-core/playwright": "^4.12.1", "@axe-core/playwright": "^4.12.1",
"@eslint/js": "^9.39.1", "@eslint/js": "^9.39.1",
"@oxlint/migrate": "^1.82.0",
"@playwright/test": "^1.61.1", "@playwright/test": "^1.61.1",
"@tailwindcss/postcss": "^4.1.17", "@tailwindcss/postcss": "^4.1.17",
"@testing-library/jest-dom": "^6.9.1", "@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^7.0.1",
"@testing-library/react": "^16.3.2", "@testing-library/react": "^16.3.2",
"@types/js-cookie": "^3.0.6", "@types/js-cookie": "^3.0.6",
"@types/node": "26.1.2", "@types/node": "26.1.2",
@ -108,6 +112,8 @@
"lint-staged": "^17.3.0", "lint-staged": "^17.3.0",
"madge": "8.0.0", "madge": "8.0.0",
"orval": "8.22.0", "orval": "8.22.0",
"oxlint": "^1.82.0",
"oxlint-tsgolint": "^7.0.2001",
"postcss": "8.5.23", "postcss": "8.5.23",
"prettier": "3.6.2", "prettier": "3.6.2",
"sass": "^1.94.2", "sass": "^1.94.2",
@ -117,6 +123,11 @@
"typescript-eslint": "^8.66.0", "typescript-eslint": "^8.66.0",
"vitest": "^4.1.10" "vitest": "^4.1.10"
}, },
"pnpm": {
"allowedDeprecatedVersions": {
"eslint": "9"
}
},
"lint-staged": { "lint-staged": {
"*.{js,jsx,ts,tsx}": [ "*.{js,jsx,ts,tsx}": [
"prettier --write", "prettier --write",

4497
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -147,8 +147,8 @@ run_frontend_quality() {
# Always run full typecheck (no checkpoint skip) — same surface as CI `pnpm typecheck`. # Always run full typecheck (no checkpoint skip) — same surface as CI `pnpm typecheck`.
run_step "TypeScript" pnpm typecheck run_step "TypeScript" pnpm typecheck
run_cached_step lint "ESLint" \ run_cached_step lint "Oxlint + ESLint" \
"$(hash_paths '*.ts' '*.tsx' '*.js' '*.jsx' eslint.config.mjs)" \ "$(hash_paths '*.ts' '*.tsx' '*.js' '*.jsx' eslint.config.mjs .oxlintrc.json)" \
pnpm lint pnpm lint
run_cached_step build "Production build and bundle budget" \ run_cached_step build "Production build and bundle budget" \

View File

@ -114,7 +114,8 @@ export const events = {
priceTomanLabel: 'قیمت (تومان)', priceTomanLabel: 'قیمت (تومان)',
autoCreateGroupAfterEndLabel: 'ساخت خودکار گروه چت بعد از پایان رویداد', autoCreateGroupAfterEndLabel: 'ساخت خودکار گروه چت بعد از پایان رویداد',
sendReviewSmsAfterEndLabel: 'ارسال پیامک درخواست نظر بعد از پایان رویداد', sendReviewSmsAfterEndLabel: 'ارسال پیامک درخواست نظر بعد از پایان رویداد',
editLockedWithBookings: 'این رویداد {count} رزرو فعال دارد؛ زمان، مکان، قیمت، هزینهٔ کنسلی، محدودیت جنسی/سنی و تنظیمات رفتاری قفل شده‌اند.', editLockedWithBookings:
'این رویداد {count} رزرو فعال دارد؛ زمان، مکان، قیمت، هزینهٔ کنسلی، محدودیت جنسی/سنی و تنظیمات رفتاری قفل شده‌اند.',
editMediaCardTitle: 'پوستر و تصاویر', editMediaCardTitle: 'پوستر و تصاویر',
editFaqCardTitle: 'سوالات متداول', editFaqCardTitle: 'سوالات متداول',
reservedCapacityEditHint: 'ظرفیت رزرو شده: {count} نفر (مهمان‌های خارج از قبیله). تغییر این عدد از صفحه مدیریت ایونت انجام می‌شود.', reservedCapacityEditHint: 'ظرفیت رزرو شده: {count} نفر (مهمان‌های خارج از قبیله). تغییر این عدد از صفحه مدیریت ایونت انجام می‌شود.',