ESLint چیست؟ آموزش کامل ESLint در JavaScript، React و TypeScript

در این آموزش ESLint را از صفر یاد می‌گیرید؛ از نصب و Flat Config تا Rules، Plugins، React، TypeScript، Prettier، VS Code و CI. همچنین می‌بینیم چگونه کد تولیدشده با هوش مصنوعی را پیش از اجرا و انتشار بررسی کنیم.

Share
ESLint چیست؟ آموزش کامل ESLint در JavaScript، React و TypeScript

ابزارهای هوش مصنوعی می‌توانند در چند ثانیه ده‌ها خط کد JavaScript، React یا TypeScript تولید کنند؛ اما سرعت تولید کد الزاماً به‌معنای درست بودن، قابل‌نگهداری بودن یا آماده انتشار بودن آن نیست.

یک متغیر تعریف‌شده و استفاده‌نشده، ارجاع به نامی که وجود ندارد، Promise مدیریت‌نشده، وابستگی ناقص یک React Hook یا شرطی که همیشه مقدار یکسانی دارد، ممکن است در نگاه اول دیده نشود. ESLint برای پیدا کردن بسیاری از این الگوها پیش از رسیدن کد به محیط Production استفاده می‌شود.

اما ESLint دقیقاً چیست؟ چه تفاوتی با Prettier، TypeScript، تست و Compiler دارد؟ چگونه باید فایل جدید eslint.config.js را تنظیم کنیم؟ Rule، Plugin، Parser و Flat Config چه هستند؟ چگونه ESLint را در React، TypeScript، VS Code و CI اجرا کنیم؟

در این راهنما، ESLint را از مفاهیم پایه تا تنظیم یک پروژه واقعی JavaScript و React بررسی می‌کنیم و در پایان نشان می‌دهیم چگونه از آن به‌عنوان بخشی از فرایند کنترل کیفیت کدهای تولیدشده با هوش مصنوعی استفاده کنیم.

ESLint چیست؟

ESLint یک ابزار تحلیل ایستای کد یا Static Analysis برای JavaScript و زبان‌های مرتبط با آن است. این ابزار Source Code را بدون اجرای برنامه بررسی می‌کند و الگوهای مشکوک، خطاهای احتمالی و موارد ناسازگار با استانداردهای تعریف‌شده پروژه را گزارش می‌دهد.

براساس مستندات رسمی ESLint، هدف ESLint شناسایی و گزارش الگوهای موجود در کد JavaScript برای افزایش سازگاری کد و جلوگیری از بعضی خطاها است.

ESLint می‌تواند مواردی مانند این‌ها را تشخیص دهد:

const modelName = "example-model";

console.log(modelNam);

در این کد، modelNam تعریف نشده است. ESLint می‌تواند با Rule مربوط به no-undef آن را گزارش کند.

مثال دیگر:

const response = await fetch("/api/chat");
const unusedData = await response.json();

console.log("Request completed");

متغیر unusedData تعریف شده اما استفاده نشده است. Rule مربوط به no-unused-vars می‌تواند این موضوع را پیدا کند.

Lint یا Linter چیست؟

Lint به فرایند بررسی خودکار Source Code برای یافتن الگوهای مشکل‌دار گفته می‌شود. ابزاری که این بررسی را انجام می‌دهد Linter نام دارد.

در JavaScript، ESLint یکی از شناخته‌شده‌ترین Linterها است.

فرایند ساده Lint:

Source Code
    |
    v
Parser
    |
    v
ساخت AST
    |
    v
اجرای Ruleها
    |
    v
Error و Warning

ESLint ابتدا کد را Parse و آن را به ساختاری به نام Abstract Syntax Tree یا AST تبدیل می‌کند. سپس Ruleهای فعال روی این ساختار اجرا می‌شوند.

لازم نیست برای استفاده روزمره ESLint جزئیات AST را بدانید؛ اما دانستن این نکته کمک می‌کند درک کنید ESLint فقط یک جست‌وجوی متنی ساده نیست.

ESLint چه مشکلاتی را پیدا می‌کند؟

بسته به Ruleها و Pluginهای نصب‌شده، ESLint می‌تواند در شناسایی این موارد کمک کند:

  • متغیر تعریف‌نشده
  • متغیر استفاده‌نشده
  • کد غیرقابل‌دسترسی
  • شرط‌های مشکوک
  • مقایسه‌های ناخواسته
  • استفاده اشتباه از بعضی Syntaxها
  • خطاهای مرتبط با Scope
  • مشکلات متداول React
  • استفاده نادرست از React Hooks
  • بعضی خطاهای وابسته به TypeScript
  • ناسازگاری با استاندارد کدنویسی تیم
  • Importهای مشکل‌دار با Pluginهای مربوط
  • استفاده از APIهای ممنوع‌شده در پروژه
  • الگوهای ناامن یا نامناسب با Pluginهای تخصصی

ESLint نمی‌تواند درستی کامل برنامه را تضمین کند. ممکن است کد از نظر ESLint بدون خطا باشد، اما منطق تجاری آن اشتباه باشد.

تفاوت ESLint با Formatter چیست؟

Linter و Formatter وظایف متفاوتی دارند.

ESLint

ESLint بیشتر روی کیفیت، الگوهای خطا و قواعد کدنویسی تمرکز دارد:

const result = unknownVariable + 1;

ESLint می‌تواند تشخیص دهد unknownVariable تعریف نشده است.

Formatter

Formatter روی شکل ظاهری کد تمرکز می‌کند:

const user={name:"Amir",role:"admin"}

یک Formatter مانند Prettier آن را به شکل منظم درمی‌آورد:

const user = {
  name: "Amir",
  role: "admin",
};

مقایسه کلی:

قابلیتESLintPrettier
شناسایی خطای احتمالیبلهخیر
بررسی متغیر تعریف‌نشدهبلهخیر
بررسی قواعد Reactبا Pluginخیر
تنظیم فاصله و شکست خطوطمحدود و وابسته به Ruleهدف اصلی
مرتب‌سازی ظاهر کدمحدودبله
تحلیل TypeScriptبا ابزار مرتبطخیر
اصلاح خودکار بعضی مواردبلهبله

در بسیاری از پروژه‌ها ESLint و Prettier در کنار یکدیگر استفاده می‌شوند:

  • ESLint برای کیفیت و خطاهای احتمالی
  • Prettier برای Format کردن کد

طبق راهنمای رسمی Prettier برای یکپارچه‌سازی با Linterها، بهتر است Ruleهای Formatting متعارض با Prettier غیرفعال شوند تا دو ابزار بر سر ظاهر کد با یکدیگر درگیر نشوند.

تفاوت ESLint با TypeScript

TypeScript و ESLint بخشی از مشکلات مشابه را پیدا می‌کنند، اما جایگزین کامل یکدیگر نیستند.

TypeScript بیشتر روی Type Checking تمرکز دارد:

const total: number = "100";

TypeScript تشخیص می‌دهد که مقدار string به متغیر number داده شده است.

ESLint روی الگوهای کدنویسی تمرکز می‌کند:

const unusedTotal: number = 100;

ESLint می‌تواند متغیر استفاده‌نشده را گزارش کند.

ترکیب مناسب در پروژه TypeScript:

TypeScript Compiler + ESLint + Tests

هرکدام بخشی از کیفیت پروژه را پوشش می‌دهند.

تفاوت ESLint با تست

ESLint بدون اجرای برنامه، ساختار و الگوهای Source Code را بررسی می‌کند. تست، رفتار برنامه را هنگام اجرا ارزیابی می‌کند.

فرض کنید تابع زیر را داریم:

function calculateTotal(price, quantity) {
  return price - quantity;
}

ممکن است ESLint هیچ خطایی در این کد پیدا نکند؛ زیرا Syntax و ساختار آن معتبر است. اما اگر هدف ضرب قیمت در تعداد باشد، منطق تابع اشتباه است.

تست می‌تواند این مشکل را پیدا کند:

expect(calculateTotal(100, 3)).toBe(300);

بنابراین:

  • ESLint جایگزین تست نیست.
  • تست جایگزین ESLint نیست.
  • TypeScript جایگزین هیچ‌کدام از آن‌ها نیست.

تفاوت ESLint با Compiler

Compiler یا Transpiler کد را به شکل دیگری تبدیل می‌کند. برای مثال TypeScript Compiler می‌تواند TypeScript را به JavaScript تبدیل کند.

ESLint معمولاً خروجی اجرایی تولید نمی‌کند. وظیفه اصلی آن گزارش مشکلات و در بعضی موارد اصلاح خودکار Source Code است.

پیش‌نیازهای نصب ESLint

برای استفاده از ESLint به نسخه سازگار Node.js نیاز دارید. نسخه موردنیاز با نسخه ESLint تغییر می‌کند؛ بنابراین قبل از نصب، بخش Prerequisites در راهنمای رسمی شروع ESLint را بررسی کنید.

نسخه‌های نصب‌شده را ببینید:

node --version
npm --version

اگر پروژه هنوز package.json ندارد:

npm init -y

نصب خودکار ESLint

روش پیشنهادی برای ساخت تنظیمات اولیه:

npm init @eslint/config@latest

این دستور چند سؤال می‌پرسد؛ برای مثال:

  • کد شما در چه محیطی اجرا می‌شود؟
  • از JavaScript یا TypeScript استفاده می‌کنید؟
  • آیا پروژه React یا فریم‌ورک دیگری دارد؟
  • از چه Package Manager استفاده می‌کنید؟

پس از پاسخ، معمولاً فایل eslint.config.js یا eslint.config.mjs ساخته می‌شود.

روش‌های دیگر:

pnpm create @eslint/config@latest
yarn create @eslint/config
bun create @eslint/config@latest

نصب دستی ESLint

برای نصب دستی ESLint و قواعد پایه JavaScript:

npm install --save-dev eslint @eslint/js

ESLint را به‌صورت Development Dependency نصب می‌کنیم؛ زیرا برای بررسی Source Code هنگام توسعه و CI لازم است و معمولاً بخشی از Runtime برنامه Production نیست.

در package.json:

{
  "devDependencies": {
    "@eslint/js": "...",
    "eslint": "..."
  }
}

نسخه دقیق نصب‌شده را package-lock.json ثبت می‌کند.

Flat Config چیست؟

نسخه‌های جدید ESLint از سیستم تنظیمات Flat Config استفاده می‌کنند. فایل اصلی آن معمولاً یکی از این موارد است:

eslint.config.js
eslint.config.mjs
eslint.config.cjs
eslint.config.ts

در پروژه‌های مبتنی بر ES Modules می‌توان از eslint.config.js یا eslint.config.mjs استفاده کرد.

نمونه ساده:

import js from "@eslint/js";
import { defineConfig } from "eslint/config";

export default defineConfig([
  js.configs.recommended,
]);

در Flat Config، تنظیمات به‌شکل یک Array از Configuration Objectها نوشته می‌شوند. هر Object می‌تواند برای گروه مشخصی از فایل‌ها اعمال شود.

تنظیمات Flat Config در مستندات Configuration Files در ESLint توضیح داده شده است.

اولین تنظیم ESLint برای JavaScript

فایل eslint.config.js:

import js from "@eslint/js";
import globals from "globals";
import { defineConfig } from "eslint/config";

export default defineConfig([
  {
    ignores: [
      "dist/**",
      "coverage/**",
      "node_modules/**",
    ],
  },

  {
    files: ["**/*.{js,mjs,cjs}"],

    extends: [
      js.configs.recommended,
    ],

    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
      globals: {
        ...globals.node,
      },
    },

    rules: {
      "no-unused-vars": [
        "warn",
        {
          argsIgnorePattern: "^_",
          varsIgnorePattern: "^_",
        },
      ],
      "no-console": "off",
      "eqeqeq": ["error", "always"],
      "curly": ["error", "all"],
    },
  },
]);

نصب Package مربوط به Globalها:

npm install --save-dev globals

اجرای ESLint

بررسی تمام پروژه:

npx eslint .

بررسی یک فایل:

npx eslint src/app.js

بررسی یک پوشه:

npx eslint src

بررسی فایل‌های مشخص:

npx eslint "src/**/*.{js,jsx}"

در بسیاری از Shellها بهتر است Pattern را داخل کوتیشن قرار دهید تا به‌جای Shell، ESLint آن را پردازش کند.

افزودن Script به package.json

در package.json:

{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  }
}

حالا اجرا کنید:

npm run lint

اصلاح خودکار:

npm run lint:fix

Rule در ESLint چیست؟

Rule یک قانون مستقل برای بررسی الگوی مشخصی از کد است.

نمونه Ruleها:

no-undef
no-unused-vars
eqeqeq
curly
no-unreachable
no-constant-condition
no-duplicate-imports
prefer-const

هر Rule یکی از سطح‌های زیر را می‌گیرد:

"off"
"warn"
"error"

یا معادل عددی:

0
1
2

مثال:

rules: {
  "no-console": "warn",
  "no-debugger": "error",
  "no-unused-vars": "warn",
}

معنای سطح‌ها:

  • off: Rule غیرفعال است.
  • warn: مشکل به‌صورت Warning گزارش می‌شود.
  • error: مشکل Error است و می‌تواند باعث شکست فرمان ESLint شود.

طبق مستندات تنظیم Ruleهای ESLint، سطح warn روی Exit Code معمولی اثر شکست ندارد، اما سطح error باعث Exit Code ناموفق می‌شود.

Ruleهای پیشنهادی و شخصی‌سازی‌شده

پیکربندی پیشنهادی JavaScript:

import js from "@eslint/js";
import { defineConfig } from "eslint/config";

export default defineConfig([
  js.configs.recommended,

  {
    rules: {
      "eqeqeq": ["error", "always"],
      "curly": ["error", "all"],
      "no-debugger": "error",
      "no-duplicate-imports": "error",
      "no-unneeded-ternary": "warn",
      "prefer-const": "warn",
      "no-unused-vars": [
        "warn",
        {
          argsIgnorePattern: "^_",
        },
      ],
    },
  },
]);

eqeqeq

این Rule استفاده از مقایسه دقیق را الزامی می‌کند.

مشکل‌دار:

if (status == "200") {
  console.log("Success");
}

مناسب‌تر:

if (status === 200) {
  console.log("Success");
}

curly

استفاده از آکولاد برای Blockها:

if (loading) return;

با Rule سخت‌گیرانه:

if (loading) {
  return;
}

prefer-const

اگر متغیر دوباره مقداردهی نمی‌شود:

let baseUrl = "/api";

پیشنهاد:

const baseUrl = "/api";

no-debugger

از باقی ماندن دستور debugger در کد جلوگیری می‌کند:

debugger;

no-unused-vars

متغیرهای بدون استفاده را گزارش می‌کند:

const unusedResult = await request();

Rule دارای Option

بعضی Ruleها علاوه بر سطح، تنظیمات دیگری نیز می‌گیرند:

"no-unused-vars": [
  "warn",
  {
    argsIgnorePattern: "^_",
    varsIgnorePattern: "^_",
    caughtErrorsIgnorePattern: "^_",
  },
]

حالا آرگومان‌هایی که با _ شروع می‌شوند نادیده گرفته خواهند شد:

function errorHandler(error, _request, response, _next) {
  response.status(500).json({
    error: "Internal error",
  });
}

این روش باید براساس استاندارد تیم استفاده شود. پیشوند _ نباید راهی برای پنهان کردن بی‌دلیل متغیرهای بلااستفاده باشد.

Globals در ESLint

ESLint باید بداند کد در چه محیطی اجرا می‌شود.

در Browser متغیرهایی مانند این‌ها وجود دارند:

window
document
navigator

در Node.js متغیرهایی مانند این‌ها ممکن است وجود داشته باشند:

process
Buffer
setImmediate

برای Browser:

import globals from "globals";

export default [
  {
    languageOptions: {
      globals: {
        ...globals.browser,
      },
    },
  },
];

برای Node.js:

import globals from "globals";

export default [
  {
    languageOptions: {
      globals: {
        ...globals.node,
      },
    },
  },
];

اگر پروژه Frontend و Backend را هم‌زمان دارد، تنظیمات را براساس مسیر جدا کنید:

import js from "@eslint/js";
import globals from "globals";
import { defineConfig } from "eslint/config";

export default defineConfig([
  js.configs.recommended,

  {
    files: ["src/**/*.{js,jsx}"],
    languageOptions: {
      globals: {
        ...globals.browser,
      },
    },
  },

  {
    files: ["server/**/*.js"],
    languageOptions: {
      globals: {
        ...globals.node,
      },
    },
  },
]);

این روش بهتر از فعال کردن هم‌زمان همه Globalها برای تمام فایل‌ها است.

files و ignores در Flat Config

با files مشخص می‌کنید تنظیم روی چه فایل‌هایی اجرا شود:

{
  files: ["src/**/*.{js,jsx}"],
}

با ignores مسیرهای خارج از بررسی را مشخص می‌کنید:

{
  ignores: [
    "dist/**",
    "build/**",
    "coverage/**",
    "node_modules/**",
    "public/vendor/**",
  ],
}

یک Config Object که فقط ignores دارد می‌تواند Ignored Pathهای سراسری را تعریف کند:

export default [
  {
    ignores: [
      "dist/**",
      "coverage/**",
      "*.min.js",
    ],
  },
];

فایل‌های تولیدشده، Bundleها و پوشه‌های وابستگی معمولاً نباید Lint شوند.

Override کردن Rule برای مسیر مشخص

ممکن است Rule خاصی برای فایل‌های تست متفاوت باشد:

export default [
  {
    files: ["src/**/*.js"],
    rules: {
      "no-console": "warn",
    },
  },

  {
    files: ["tests/**/*.js"],
    rules: {
      "no-console": "off",
    },
  },
];

یا برای Scriptهای Migration:

{
  files: ["scripts/**/*.js"],
  rules: {
    "no-console": "off",
  },
}

Plugin در ESLint چیست؟

Plugin مجموعه‌ای از Ruleها، Processorها یا Configهای اضافه است که قابلیت ESLint را گسترش می‌دهد.

نمونه Pluginها:

  • Pluginهای React
  • Pluginهای React Hooks
  • Pluginهای Import
  • Pluginهای Promise
  • Pluginهای Testing
  • Pluginهای Accessibility
  • ابزارهای TypeScript ESLint

Plugin را باید نصب و سپس در Config استفاده کنید.

فرایند کلی:

نصب Package
    |
    v
Import در Config
    |
    v
ثبت Plugin یا Config
    |
    v
فعال کردن Ruleها

فقط Pluginهایی را نصب کنید که واقعاً به آن‌ها نیاز دارید. تعداد زیاد Plugin می‌تواند Config، زمان اجرا و فرایند ارتقا را پیچیده کند.

تنظیم ESLint برای React

یک پروژه React جدید با Vite معمولاً از ابتدا تنظیم ESLint دارد. اگر می‌خواهید آن را دستی بسازید، Packageهای لازم را نصب کنید:

npm install --save-dev \
  eslint \
  @eslint/js \
  globals \
  eslint-plugin-react \
  eslint-plugin-react-hooks \
  eslint-plugin-react-refresh

نمونه eslint.config.js:

import js from "@eslint/js";
import globals from "globals";
import react from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import { defineConfig } from "eslint/config";

export default defineConfig([
  {
    ignores: [
      "dist/**",
      "coverage/**",
    ],
  },

  {
    files: ["**/*.{js,jsx}"],

    extends: [
      js.configs.recommended,
      react.configs.flat.recommended,
      react.configs.flat["jsx-runtime"],
      reactHooks.configs.flat.recommended,
    ],

    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
      parserOptions: {
        ecmaFeatures: {
          jsx: true,
        },
      },
      globals: {
        ...globals.browser,
      },
    },

    settings: {
      react: {
        version: "detect",
      },
    },

    plugins: {
      "react-refresh": reactRefresh,
    },

    rules: {
      "react-refresh/only-export-components": [
        "warn",
        {
          allowConstantExport: true,
        },
      ],

      "no-unused-vars": [
        "warn",
        {
          argsIgnorePattern: "^_",
          varsIgnorePattern: "^_",
        },
      ],

      "no-debugger": "error",
      "eqeqeq": ["error", "always"],
    },
  },
]);

Plugin رسمی جامعه React برای ESLint، Configهای Flat مانند recommended و jsx-runtime ارائه می‌کند. جزئیات آن در مخزن eslint-plugin-react آمده است.

قبل از کپی کردن Config، آن را با نسخه Packageهای نصب‌شده در پروژه تطبیق دهید؛ زیرا نام Exportها ممکن است میان نسخه‌ها تغییر کند.

ESLint و React Hooks

React Hooks قواعد خاصی دارند. برای مثال Hook نباید به‌صورت شرطی فراخوانی شود:

function Profile({ authenticated }) {
  if (authenticated) {
    const [user, setUser] = useState(null);
  }

  return <div>Profile</div>;
}

ساختار صحیح:

function Profile({ authenticated }) {
  const [user, setUser] = useState(null);

  if (!authenticated) {
    return null;
  }

  return <div>{user?.name}</div>;
}

Plugin React Hooks برای بررسی این الگوها استفاده می‌شود.

نمونه دیگر، Dependency ناقص در Effect:

useEffect(() => {
  loadConversation(conversationId);
}, []);

اگر Effect به conversationId وابسته است، Rule مربوط می‌تواند هشدار دهد:

useEffect(() => {
  loadConversation(conversationId);
}, [conversationId]);

البته اضافه کردن کورکورانه Dependencyها همیشه راه‌حل نهایی نیست. گاهی لازم است ساختار Effect، تعریف تابع یا جریان State بازطراحی شود.

نمونه خطای واقعی در کامپوننت هوش مصنوعی

کد مشکل‌دار:

import { useState } from "react";

export default function ChatForm() {
  const [message, setMessage] = useState("");
  const [answer, setAnswer] = useState("");

  async function sendMessage() {
    const response = await fetch("/api/chat", {
      method: "POST",
      body: JSON.stringify({
        prompt: message,
      }),
    });

    const data = await response.json();
    setAnswer(data.answer);
  }

  return (
    <form>
      <textarea
        value={message}
        onChange={(event) => setMessage(event.target.value)}
      />

      <button onClick={sendMessage}>
        ارسال
      </button>
    </form>
  );
}

مشکلاتی که باید بررسی شوند:

  • Submit پیش‌فرض Form کنترل نشده است.
  • دکمه type صریح ندارد.
  • Header مربوط به JSON ارسال نشده است.
  • response.ok بررسی نشده است.
  • خطای شبکه مدیریت نشده است.
  • Loading State وجود ندارد.
  • درخواست تکراری کنترل نشده است.
  • امکان لغو Request وجود ندارد.

همه این موارد الزاماً با ESLint Core شناسایی نمی‌شوند؛ اما ESLint، Pluginهای مناسب، تست و Code Review در کنار یکدیگر می‌توانند بخش بزرگی از این مشکلات را پوشش دهند.

نسخه بهتر:

import { useRef, useState } from "react";

export default function ChatForm() {
  const [message, setMessage] = useState("");
  const [answer, setAnswer] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  const controllerRef = useRef(null);

  async function handleSubmit(event) {
    event.preventDefault();

    const cleanMessage = message.trim();

    if (!cleanMessage || loading) {
      return;
    }

    controllerRef.current?.abort();
    controllerRef.current = new AbortController();

    setLoading(true);
    setError("");

    try {
      const response = await fetch("/api/chat", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          message: cleanMessage,
        }),
        signal: controllerRef.current.signal,
      });

      const data = await response.json().catch(() => null);

      if (!response.ok) {
        throw new Error(
          data?.error || "دریافت پاسخ با خطا روبه‌رو شد."
        );
      }

      setAnswer(data.answer);
    } catch (requestError) {
      if (requestError.name !== "AbortError") {
        setError(
          requestError instanceof Error
            ? requestError.message
            : "خطای پیش‌بینی‌نشده‌ای رخ داد."
        );
      }
    } finally {
      setLoading(false);
      controllerRef.current = null;
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="message">پیام</label>

      <textarea
        id="message"
        value={message}
        onChange={(event) => setMessage(event.target.value)}
        disabled={loading}
      />

      <button
        type="submit"
        disabled={loading || !message.trim()}
      >
        {loading ? "در حال ارسال..." : "ارسال"}
      </button>

      {error && <p role="alert">{error}</p>}
      {answer && <p>{answer}</p>}
    </form>
  );
}

تنظیم ESLint برای TypeScript

برای TypeScript از پروژه typescript-eslint استفاده می‌شود.

نصب:

npm install --save-dev \
  eslint \
  @eslint/js \
  typescript \
  typescript-eslint

فایل eslint.config.mjs:

// @ts-check

import js from "@eslint/js";
import { defineConfig } from "eslint/config";
import tseslint from "typescript-eslint";

export default defineConfig([
  {
    ignores: [
      "dist/**",
      "coverage/**",
    ],
  },

  {
    files: [
      "**/*.{js,mjs,cjs,ts,mts,cts}",
    ],

    extends: [
      js.configs.recommended,
      tseslint.configs.recommended,
    ],

    rules: {
      "no-debugger": "error",
      "eqeqeq": ["error", "always"],

      "@typescript-eslint/no-unused-vars": [
        "warn",
        {
          argsIgnorePattern: "^_",
          varsIgnorePattern: "^_",
        },
      ],
    },
  },
]);

هنگام استفاده از Rule نسخه TypeScript، نسخه Core مشابه را غیرفعال کنید اگر Config انتخابی آن را از قبل مدیریت نکرده است:

rules: {
  "no-unused-vars": "off",

  "@typescript-eslint/no-unused-vars": [
    "warn",
    {
      argsIgnorePattern: "^_",
    },
  ],
}

راهنمای رسمی typescript-eslint استفاده از Flat Config و Config پیشنهادی TypeScript را توضیح می‌دهد.

Type-aware Linting چیست؟

بعضی Ruleهای TypeScript فقط Syntax را بررسی می‌کنند. گروه دیگری برای تصمیم‌گیری به اطلاعات Type نیاز دارند.

مثال:

async function getAnswer(): Promise<string> {
  return "Hello";
}

getAnswer();

یک Rule وابسته به Type می‌تواند تشخیص دهد Promise ایجاد شده اما await یا مدیریت نشده است.

برای استفاده از Ruleهای Type-aware باید Config مناسب و Project Service تنظیم شود. این نوع Lint قدرتمندتر است، اما می‌تواند زمان اجرای بیشتری نیاز داشته باشد.

یک تنظیم رایج:

import js from "@eslint/js";
import { defineConfig } from "eslint/config";
import tseslint from "typescript-eslint";

export default defineConfig([
  {
    ignores: [
      "dist/**",
      "coverage/**",
    ],
  },

  {
    files: ["**/*.{ts,tsx}"],

    extends: [
      js.configs.recommended,
      tseslint.configs.recommendedTypeChecked,
    ],

    languageOptions: {
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
  },
]);

پیش از فعال کردن Type-aware Linting:

  • نسخه‌های ESLint، TypeScript و typescript-eslint را تطبیق دهید.
  • مسیر tsconfig را بررسی کنید.
  • زمان اجرای CI را اندازه‌گیری کنید.
  • Ruleها را به‌تدریج فعال کنید.
  • فایل‌های خارج از TypeScript Project را جداگانه تنظیم کنید.

تنظیم ESLint برای React و TypeScript

نصب پایه:

npm install --save-dev \
  eslint \
  @eslint/js \
  globals \
  typescript \
  typescript-eslint \
  eslint-plugin-react \
  eslint-plugin-react-hooks \
  eslint-plugin-react-refresh

Config نمونه:

import js from "@eslint/js";
import globals from "globals";
import react from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import { defineConfig } from "eslint/config";
import tseslint from "typescript-eslint";

export default defineConfig([
  {
    ignores: [
      "dist/**",
      "coverage/**",
    ],
  },

  {
    files: ["**/*.{ts,tsx}"],

    extends: [
      js.configs.recommended,
      tseslint.configs.recommended,
      react.configs.flat.recommended,
      react.configs.flat["jsx-runtime"],
      reactHooks.configs.flat.recommended,
    ],

    languageOptions: {
      globals: {
        ...globals.browser,
      },
    },

    settings: {
      react: {
        version: "detect",
      },
    },

    plugins: {
      "react-refresh": reactRefresh,
    },

    rules: {
      "no-unused-vars": "off",

      "@typescript-eslint/no-unused-vars": [
        "warn",
        {
          argsIgnorePattern: "^_",
          varsIgnorePattern: "^_",
        },
      ],

      "react-refresh/only-export-components": [
        "warn",
        {
          allowConstantExport: true,
        },
      ],
    },
  },
]);

این Config یک نقطه شروع است، نه نسخه یکسان برای همه پروژه‌ها. آن را با ساختار، نسخه React، ابزار Build و نیاز تیم تطبیق دهید.

ESLint و Prettier

نصب Prettier:

npm install --save-dev prettier

برای جلوگیری از تداخل Ruleهای Formatting ESLint با Prettier:

npm install --save-dev eslint-config-prettier

Config:

import js from "@eslint/js";
import prettierConfig from "eslint-config-prettier";
import { defineConfig } from "eslint/config";

export default defineConfig([
  js.configs.recommended,

  {
    rules: {
      "no-unused-vars": "warn",
    },
  },

  prettierConfig,
]);

Config مربوط به Prettier را معمولاً در انتهای Array قرار دهید تا Ruleهای Formatting متعارض را غیرفعال کند.

Scriptهای package.json:

{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix",
    "format": "prettier . --write",
    "format:check": "prettier . --check"
  }
}

اجرای Format:

npm run format

بررسی بدون تغییر فایل:

npm run format:check

بهتر است وظایف را روشن نگه دارید:

ESLint = کیفیت و خطاهای احتمالی
Prettier = ظاهر و Format

آیا از eslint-plugin-prettier استفاده کنیم؟

این Plugin خروجی Prettier را به‌عنوان Rule در ESLint اجرا می‌کند. برای بعضی تیم‌ها مناسب است، اما اجرای Formatter از طریق ESLint می‌تواند پیچیدگی و زمان Lint را افزایش دهد.

رویکرد ساده‌تر در بسیاری از پروژه‌ها:

npm run lint
npm run format:check

یعنی ESLint و Prettier به‌صورت دو مرحله مجزا اجرا شوند.

اصلاح خودکار با --fix

بعضی Ruleها قابل اصلاح خودکار هستند:

npx eslint . --fix

نمونه:

let baseUrl = "/api";

اگر Rule مناسب فعال باشد:

const baseUrl = "/api";

اما --fix همه مشکلات را حل نمی‌کند. خطاهای منطقی و مواردی که چند راه‌حل دارند معمولاً نیازمند تصمیم توسعه‌دهنده هستند.

پس از --fix:

  • تغییرات Git را بررسی کنید.
  • تست‌ها را اجرا کنید.
  • Build بگیرید.
  • تغییرات گسترده را بدون Review Commit نکنید.

غیرفعال کردن موقت Rule

برای یک خط:

// eslint-disable-next-line no-console
console.log("Development information");

برای بخشی از فایل:

/* eslint-disable no-console */

console.log("First");
console.log("Second");

/* eslint-enable no-console */

برای کل فایل:

/* eslint-disable no-console */

استفاده زیاد از eslint-disable معمولاً نشانه یکی از این موارد است:

  • Rule برای پروژه مناسب نیست.
  • ساختار کد نیازمند اصلاح است.
  • Config بیش از حد سخت‌گیرانه است.
  • توسعه‌دهنده بدون بررسی هشدار را خاموش کرده است.

برای Disable توضیح بنویسید:

// دلیل: این Script خط فرمان عمداً خروجی را در Terminal چاپ می‌کند.
// eslint-disable-next-line no-console
console.log("Migration completed.");

استفاده از --fix-dry-run

برای دیدن اصلاحات بدون تغییر مستقیم فایل‌ها:

npx eslint . --fix-dry-run

می‌توانید Formatter خروجی را نیز مشخص کنید:

npx eslint . --fix-dry-run --format json

این قابلیت برای ابزارهای خودکار و بررسی تغییرات احتمالی مفید است.

محدود کردن تعداد Warningها

ممکن است پروژه صدها Warning داشته باشد و هیچ‌وقت اصلاح نشوند. در CI می‌توانید اجازه ندهید Warning جدید وارد شود:

npx eslint . --max-warnings 0

در package.json:

{
  "scripts": {
    "lint": "eslint . --max-warnings 0"
  }
}

در این حالت حتی یک Warning نیز باعث شکست فرمان می‌شود.

برای پروژه قدیمی با Warningهای زیاد، ابتدا یک برنامه تدریجی تعریف کنید. تغییر ناگهانی همه Warningها به Error ممکن است تیم را به غیرفعال کردن گسترده Ruleها سوق دهد.

استفاده از --quiet

برای نمایش فقط Errorها:

npx eslint . --quiet

این گزینه می‌تواند خروجی را خلوت‌تر کند؛ اما Warningها را نادیده نگیرید. بهتر است در CI سیاست مشخصی برای Warningها داشته باشید.

فهرست گزینه‌های CLI در مستندات Command Line Interface رسمی ESLint قرار دارد.

Cache کردن ESLint

برای پروژه‌های بزرگ:

npx eslint . --cache

ESLint اطلاعات فایل‌های بررسی‌شده را Cache می‌کند تا اجرای بعدی سریع‌تر شود.

Script:

{
  "scripts": {
    "lint": "eslint . --cache --max-warnings 0"
  }
}

فایل Cache را معمولاً وارد Git نمی‌کنند:

.eslintcache

در CI همیشه بررسی کنید که Cache با نسخه Dependencyها و Config فعلی سازگار باشد.

اجرای ESLint در VS Code

افزونه ESLint برای Visual Studio Code می‌تواند خطاها و Warningها را هنگام ویرایش نمایش دهد.

پس از نصب افزونه رسمی ESLint، تنظیمات Workspace را در فایل .vscode/settings.json قرار دهید:

{
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact"
  ]
}

اگر می‌خواهید Prettier Formatter پیش‌فرض باشد:

{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  }
}

ترتیب Format و Fix باید در پروژه آزمایش شود تا تغییرات تکراری یا متعارض ایجاد نشود.

صفحه افزونه ESLint در Visual Studio Marketplace تنظیمات قابل‌استفاده در VS Code را توضیح می‌دهد.

چرا ESLint در Editor کار می‌کند اما در Terminal نه؟

دلایل متداول:

  • VS Code از نسخه متفاوت ESLint استفاده می‌کند.
  • فایل Config در مسیر دیگری قرار دارد.
  • Workspace اشتباه باز شده است.
  • Dependencyها نصب نشده‌اند.
  • نسخه Node.js Terminal و Editor متفاوت است.
  • Config فقط بعضی Extensionها را پوشش می‌دهد.
  • افزونه از Working Directory دیگری استفاده می‌کند.

فرمان اصلی پروژه باید در Terminal و CI قابل اجرا باشد:

npm run lint

Editor فقط یک ابزار کمکی است و نباید تنها محل اجرای ESLint باشد.

اجرای ESLint قبل از Commit

می‌توانید ESLint را پیش از Commit روی فایل‌های تغییرکرده اجرا کنید. ابزارهایی مانند Git Hooks و lint-staged برای این کار استفاده می‌شوند.

یک Workflow معمول:

ویرایش کد
   |
   v
ESLint روی فایل‌های تغییرکرده
   |
   v
تست‌های سریع
   |
   v
Commit
   |
   v
Lint و Test کامل در CI

Hook محلی مفید است، اما جایگزین CI نیست؛ زیرا Hook ممکن است اجرا نشود یا عمداً Skip شود.

اجرای ESLint در CI

نمونه GitHub Actions:

name: Code Quality

on:
  push:
    branches:
      - main

  pull_request:

jobs:
  lint:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 24
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

      - name: Check formatting
        run: npm run format:check

      - name: Run tests
        run: npm test

      - name: Build project
        run: npm run build

نسخه Node.js در CI باید با نسخه پشتیبانی‌شده پروژه و ESLint هماهنگ باشد.

استفاده از npm ci باعث می‌شود Dependencyها براساس Lock File نصب شوند:

npm ci

ESLint در Monorepo

در Monorepo می‌توانید یک Config پایه در ریشه داشته باشید و تنظیمات هر Package را براساس مسیر اعمال کنید:

import js from "@eslint/js";
import globals from "globals";
import { defineConfig } from "eslint/config";

export default defineConfig([
  {
    ignores: [
      "**/dist/**",
      "**/coverage/**",
      "**/node_modules/**",
    ],
  },

  js.configs.recommended,

  {
    files: ["apps/web/**/*.{js,jsx}"],
    languageOptions: {
      globals: {
        ...globals.browser,
      },
    },
  },

  {
    files: [
      "apps/api/**/*.js",
      "packages/server/**/*.js",
    ],
    languageOptions: {
      globals: {
        ...globals.node,
      },
    },
  },

  {
    files: ["scripts/**/*.js"],
    rules: {
      "no-console": "off",
    },
  },
]);

در پروژه بزرگ بهتر است Configها:

  • قابل‌فهم باشند.
  • توضیح داشته باشند.
  • به تعداد کمی لایه تقسیم شوند.
  • بدون دلیل از چند Config عمومی متناقض استفاده نکنند.
  • نسخه Pluginها هماهنگ نگه داشته شود.

ساخت Config مشترک برای تیم

اگر چند Repository استاندارد مشابه دارند، می‌توانید یک Package داخلی برای ESLint Config بسازید:

packages/
└── eslint-config/
    ├── package.json
    ├── base.js
    ├── react.js
    └── typescript.js

فایل base.js:

import js from "@eslint/js";
import { defineConfig } from "eslint/config";

export default defineConfig([
  js.configs.recommended,

  {
    rules: {
      "eqeqeq": ["error", "always"],
      "curly": ["error", "all"],
      "no-debugger": "error",
      "prefer-const": "warn",
    },
  },
]);

سپس Repositoryها Config مشترک را Import می‌کنند.

این رویکرد زمانی ارزشمند است که چند پروژه واقعاً استاندارد یکسان داشته باشند. برای یک پروژه کوچک، ساخت Package جداگانه ممکن است پیچیدگی غیرضروری ایجاد کند.

استفاده از ESLint برای کد تولیدشده با هوش مصنوعی

هوش مصنوعی می‌تواند تولید کد را سریع‌تر کند، اما خروجی باید مانند کد نوشته‌شده توسط انسان بررسی شود.

Workflow پیشنهادی:

تولید یا ویرایش کد با هوش مصنوعی
              |
              v
بررسی Diff
              |
              v
اجرای ESLint
              |
              v
اجرای Type Check
              |
              v
اجرای Test
              |
              v
اجرای Build
              |
              v
Code Review و Merge

فرمان نمونه:

npm run lint
npm run typecheck
npm test
npm run build

Scriptهای package.json:

{
  "scripts": {
    "lint": "eslint . --cache --max-warnings 0",
    "lint:fix": "eslint . --fix",
    "typecheck": "tsc --noEmit",
    "test": "vitest run",
    "build": "vite build",
    "check": "npm run lint && npm run typecheck && npm test && npm run build"
  }
}

اجرای همه بررسی‌ها:

npm run check

ارسال خروجی ESLint به هوش مصنوعی

اگر ESLint خطا داد، به‌جای ارسال جمله کلی «این کد را درست کن»، اطلاعات دقیق بدهید.

پرامپت مناسب:

کد زیر در یک پروژه React و TypeScript اجرا می‌شود.

خروجی ESLint:
1. @typescript-eslint/no-misused-promises در خط 28
2. react-hooks/exhaustive-deps در خط 42
3. no-unused-vars در خط 51

وظیفه:
1. علت هر خطا را جداگانه توضیح بده.
2. راه‌حل حداقلی ارائه کن.
3. رفتار فعلی برنامه را تغییر نده.
4. هیچ Ruleای را غیرفعال نکن؛ مگر اینکه دلیل فنی مشخصی داشته باشد.
5. فقط فایل اصلاح‌شده را برگردان.

کد:
[کد اینجا قرار می‌گیرد]

این روش بهتر از درخواست مبهم است؛ زیرا:

  • خطاها مشخص‌اند.
  • هدف تغییر محدود است.
  • غیرفعال کردن Rule محدود شده است.
  • رفتار موردانتظار حفظ می‌شود.
  • Review تغییرات ساده‌تر است.

آیا هوش مصنوعی می‌تواند ESLint را اجرا کند؟

یک Coding Agent در صورتی که به Terminal پروژه دسترسی مجاز داشته باشد، می‌تواند فرمان زیر را اجرا کند:

npm run lint

اما نتیجه باید بررسی شود. Agent ممکن است برای عبور از Lint:

  • Rule را غیرفعال کند.
  • متغیر را بدون حل مشکل حذف کند.
  • رفتار برنامه را تغییر دهد.
  • فایل Config را بیش از حد ساده کند.
  • کامنت eslint-disable اضافه کند.
  • Warning را به‌جای رفع مشکل پنهان کند.

در دستور Agent بنویسید:

Lint را اجرا کن و فقط خطاهای مرتبط با تغییر فعلی را اصلاح کن.
فایل eslint.config.js را تغییر نده.
Ruleها را غیرفعال نکن.
پس از اصلاح، Lint، Test و Build را دوباره اجرا کن.
خلاصه Diff و نتیجه فرمان‌ها را گزارش بده.

اتصال پروژه به API هوش مصنوعی درواره

اگر می‌خواهید یک ابزار Code Review، دستیار برنامه‌نویسی یا توضیح‌دهنده خطاهای ESLint بسازید، می‌توانید خروجی کنترل‌شده ESLint را از Backend به API هوش مصنوعی درواره ارسال کنید.

معماری امن:

ESLint Output
      |
      v
Backend برنامه شما
      |
      | API Key خصوصی
      v
API هوش مصنوعی درواره
      |
      v
توضیح و پیشنهاد اصلاح

API Key نباید در Frontend، افزونه عمومی یا فایل Repository قرار بگیرد.

Base URL درواره:

https://api.darvareh.ir/v1

Endpoint مربوط به Chat Completions:

https://api.darvareh.ir/v1/chat/completions

نمونه Backend برای توضیح خطای ESLint

نصب:

npm install express dotenv

فایل .env:

DARVAREH_API_KEY=YOUR_DARVAREH_API_KEY
DARVAREH_MODEL_ID=YOUR_MODEL_ID
PORT=3000

برای مشاهده مدل‌ها، شناسه مدل و اطلاعات به‌روز قیمت، صفحه مدل‌های درواره را بررسی کنید.

فایل server.js:

import "dotenv/config";
import express from "express";

const app = express();
const port = Number(process.env.PORT || 3000);

app.disable("x-powered-by");
app.use(express.json({ limit: "64kb" }));

app.post("/api/explain-lint", async (request, response) => {
  const sourceCode =
    typeof request.body?.sourceCode === "string"
      ? request.body.sourceCode.trim()
      : "";

  const lintOutput =
    typeof request.body?.lintOutput === "string"
      ? request.body.lintOutput.trim()
      : "";

  if (!sourceCode || !lintOutput) {
    return response.status(400).json({
      error: "کد و خروجی ESLint الزامی هستند.",
    });
  }

  if (sourceCode.length > 20000 || lintOutput.length > 10000) {
    return response.status(400).json({
      error: "حجم ورودی بیشتر از مقدار مجاز است.",
    });
  }

  if (
    !process.env.DARVAREH_API_KEY ||
    !process.env.DARVAREH_MODEL_ID
  ) {
    return response.status(500).json({
      error: "تنظیمات سرویس کامل نیست.",
    });
  }

  try {
    const upstreamResponse = await fetch(
      "https://api.darvareh.ir/v1/chat/completions",
      {
        method: "POST",
        headers: {
          Authorization:
            `Bearer ${process.env.DARVAREH_API_KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          model: process.env.DARVAREH_MODEL_ID,
          messages: [
            {
              role: "system",
              content:
                "شما یک بازبین کد JavaScript و TypeScript هستید. خطاهای ESLint را دقیق توضیح دهید. از غیرفعال کردن Ruleها بدون دلیل خودداری کنید و تغییر حداقلی پیشنهاد دهید.",
            },
            {
              role: "user",
              content: [
                "خروجی ESLint:",
                lintOutput,
                "",
                "کد:",
                sourceCode,
              ].join("\n"),
            },
          ],
          temperature: 0.2,
        }),
      }
    );

    const data = await upstreamResponse.json().catch(() => null);

    if (!upstreamResponse.ok) {
      console.error("Darvareh API error:", {
        status: upstreamResponse.status,
      });

      return response.status(502).json({
        error: "سرویس هوش مصنوعی پاسخ معتبری برنگرداند.",
      });
    }

    const explanation =
      data?.choices?.[0]?.message?.content;

    if (
      typeof explanation !== "string" ||
      !explanation.trim()
    ) {
      return response.status(502).json({
        error: "ساختار پاسخ قابل پردازش نبود.",
      });
    }

    return response.json({
      explanation: explanation.trim(),
    });
  } catch (error) {
    console.error("Unexpected error:", error);

    return response.status(500).json({
      error: "ارتباط با سرویس برقرار نشد.",
    });
  }
});

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

قبل از ارسال Source Code به هر سرویس خارجی:

  • Secretها را حذف کنید.
  • API Keyها را حذف کنید.
  • اطلاعات مشتری را حذف یا ناشناس کنید.
  • سیاست محرمانگی سازمان را بررسی کنید.
  • فقط بخش لازم از کد را ارسال کنید.
  • خروجی مدل را قبل از اعمال Review کنید.

ساخت خروجی JSON از ESLint

برای پردازش ماشینی:

npx eslint src --format json

ذخیره در فایل:

npx eslint src --format json --output-file eslint-report.json

این گزارش را می‌توان در ابزار داخلی پردازش کرد. فایل گزارش ممکن است شامل مسیر فایل‌ها و بخش‌هایی از اطلاعات پروژه باشد؛ بنابراین آن را بدون بررسی عمومی نکنید.

نمونه ساختار ساده‌شده:

[
  {
    "filePath": "/project/src/App.jsx",
    "messages": [
      {
        "ruleId": "no-unused-vars",
        "severity": 1,
        "message": "Variable is assigned a value but never used.",
        "line": 12,
        "column": 9
      }
    ],
    "errorCount": 0,
    "warningCount": 1
  }
]

ساخت Custom Rule ساده

اگر تیم شما یک استاندارد اختصاصی دارد، می‌توانید Custom Rule بسازید. برای مثال می‌خواهیم استفاده مستقیم از console.log را در Backend گزارش کنیم.

فایل eslint-rules/no-console-log.js:

export default {
  meta: {
    type: "suggestion",

    docs: {
      description:
        "استفاده مستقیم از console.log را محدود می‌کند.",
    },

    messages: {
      avoidConsoleLog:
        "به‌جای console.log از Logger پروژه استفاده کنید.",
    },

    schema: [],
  },

  create(context) {
    return {
      CallExpression(node) {
        const isConsoleLog =
          node.callee.type === "MemberExpression" &&
          node.callee.object.type === "Identifier" &&
          node.callee.object.name === "console" &&
          node.callee.property.type === "Identifier" &&
          node.callee.property.name === "log";

        if (isConsoleLog) {
          context.report({
            node,
            messageId: "avoidConsoleLog",
          });
        }
      },
    };
  },
};

ثبت Plugin محلی در eslint.config.js:

import noConsoleLog from "./eslint-rules/no-console-log.js";

const localPlugin = {
  rules: {
    "no-console-log": noConsoleLog,
  },
};

export default [
  {
    files: ["server/**/*.js"],

    plugins: {
      local: localPlugin,
    },

    rules: {
      "local/no-console-log": "warn",
    },
  },
];

حالا این کد Warning می‌گیرد:

console.log("Request completed");

و تیم می‌تواند Logger استاندارد استفاده کند:

logger.info("Request completed");

ساخت Custom Rule زمانی ارزشمند است که:

  • یک استاندارد واقعی و تکرارشونده وجود دارد.
  • Rule عمومی مناسب پیدا نشده است.
  • منطق Rule قابل توضیح و تست است.
  • هزینه نگهداری آن پذیرفته شده است.

برای سلیقه‌های کوچک، Custom Rule ممکن است ارزش پیچیدگی اضافی را نداشته باشد.

خطاهای رایج ESLint و راه‌حل آن‌ها

ESLint configuration not found

بررسی کنید فایل زیر در ریشه پروژه باشد:

eslint.config.js

یا:

eslint.config.mjs

همچنین فرمان را از ریشه صحیح پروژه اجرا کنید:

npx eslint .

no-unused-vars

کد:

const response = await fetch("/api/data");

اگر واقعاً نیازی به مقدار ندارید:

await fetch("/api/data");

اگر مقدار لازم است، از آن استفاده کنید:

const response = await fetch("/api/data");

if (!response.ok) {
  throw new Error("Request failed.");
}

Rule را فقط برای عبور از Lint غیرفعال نکنید.

no-undef

کد:

console.log(process.env.PORT);

اگر فایل Node.js است، Globalهای Node را فعال کنید:

languageOptions: {
  globals: {
    ...globals.node,
  },
}

اگر فایل Browser است، استفاده از process ممکن است واقعاً اشتباه باشد.

Parsing error

دلایل متداول:

  • Syntax نامعتبر
  • Parser نادرست
  • TypeScript بدون تنظیم ابزار TypeScript
  • JSX بدون تنظیم مناسب
  • Extension فایل نامتناسب
  • نسخه ناسازگار Plugin و ESLint

ابتدا فایل و Extension را بررسی کنید:

Component.jsx
Component.tsx
server.js

Plugin not found

Package را به‌صورت محلی نصب کنید:

npm install --save-dev eslint-plugin-example

سپس نام Import و نسخه سازگار را بررسی کنید.

Config برای فایل اعمال نمی‌شود

از فرمان بررسی Config استفاده کنید:

npx eslint --print-config src/App.jsx

این دستور Config نهایی اعمال‌شده روی فایل را نمایش می‌دهد.

Rule not found

احتمال‌ها:

  • Plugin نصب نشده است.
  • Plugin در Config ثبت نشده است.
  • نام Rule اشتباه است.
  • نسخه Plugin از آن Rule پشتیبانی نمی‌کند.
  • Config Legacy را در Flat Config کپی کرده‌اید.

خطا پس از ارتقای ESLint

نسخه‌های Major ممکن است تغییرات ناسازگار داشته باشند. قبل از ارتقا:

npm outdated

سپس Compatibility این موارد را بررسی کنید:

  • ESLint
  • Pluginهای React
  • typescript-eslint
  • eslint-config-prettier
  • Pluginهای Import و Testing
  • نسخه Node.js

Dependencyها را یک‌جا و بدون بررسی ارتقا ندهید. ابتدا در Branch جداگانه Lint، Test و Build را اجرا کنید.

VS Code خطا نشان می‌دهد اما CLI نه

ممکن است افزونه:

  • Working Directory متفاوت داشته باشد.
  • Config دیگری پیدا کند.
  • نسخه Global استفاده کند.
  • هنوز Reload نشده باشد.

ابتدا نتیجه CLI را مرجع قرار دهید:

npm run lint

سپس پنجره VS Code را Reload کنید.

اشتباهات رایج در طراحی Config

فعال کردن تمام Ruleها

استفاده از Config شامل همه Ruleها معمولاً برای شروع مناسب نیست. بعضی Ruleها با یکدیگر یا با سبک پروژه تضاد دارند.

از Config پیشنهادی شروع کنید:

js.configs.recommended

سپس Ruleهای جدید را با دلیل اضافه کنید.

تبدیل همه Warningها به Error از روز اول

در پروژه قدیمی، این کار می‌تواند صدها خطا ایجاد کند. بهتر است:

  1. خطاهای واقعی را Error کنید.
  2. Ruleهای جدید را ابتدا Warning قرار دهید.
  3. مشکلات موجود را مرحله‌ای اصلاح کنید.
  4. سپس --max-warnings 0 را فعال کنید.

استفاده بی‌دلیل از eslint-disable

هر Disable باید محدود، مستند و قابل‌بررسی باشد.

ترکیب چند Style Guide متناقض

ترکیب چند Config عمومی ممکن است باعث Overrideهای غیرقابل‌پیش‌بینی شود. Config نهایی را با این فرمان بررسی کنید:

npx eslint --print-config src/App.jsx

Lint کردن فایل‌های Generated

این مسیرها را Ignore کنید:

dist
build
coverage
generated
vendor

استفاده از Config قدیمی بدون بررسی نسخه

نمونه‌های قدیمی .eslintrc را مستقیماً در Flat Config قرار ندهید. ساختار Plugin، extends، parserOptions و ignores در Flat Config متفاوت است.

بهترین روش تعریف Rule در تیم

هر Rule باید حداقل یکی از این اهداف را داشته باشد:

  • جلوگیری از Bug
  • افزایش خوانایی
  • هماهنگی واقعی تیم
  • جلوگیری از الگوی مشکل‌دار شناخته‌شده
  • ساده‌تر کردن Code Review
  • اجرای الزام معماری مشخص

برای Ruleهای بحث‌برانگیز این پرسش‌ها را مطرح کنید:

  • چه مشکلی را حل می‌کند؟
  • چند بار این مشکل در پروژه اتفاق افتاده است؟
  • آیا Rule قابل اصلاح خودکار است؟
  • آیا False Positive زیادی دارد؟
  • هزینه رعایت آن چقدر است؟
  • آیا Prettier همین کار را انجام می‌دهد؟
  • آیا باید Warning باشد یا Error؟

چک‌لیست ESLint برای پروژه واقعی

پیش از نهایی کردن Config بررسی کنید:

  • ESLint به‌صورت محلی نصب شده است.
  • فایل Flat Config در ریشه پروژه قرار دارد.
  • نسخه Node.js سازگار است.
  • Config پیشنهادی JavaScript فعال است.
  • محیط Browser و Node جدا شده است.
  • مسیرهای Build و Coverage نادیده گرفته می‌شوند.
  • Pluginهای React فقط روی فایل‌های React اجرا می‌شوند.
  • Ruleهای TypeScript روی فایل‌های TypeScript اعمال می‌شوند.
  • Rule Core و نسخه TypeScript آن هم‌زمان فعال نیستند.
  • Prettier با ESLint تداخل ندارد.
  • Scriptهای lint و lint:fix تعریف شده‌اند.
  • Lint در CI اجرا می‌شود.
  • Cache در صورت نیاز فعال شده است.
  • Warningها سیاست مشخص دارند.
  • Disableها محدود و دارای توضیح هستند.
  • کد تولیدشده با هوش مصنوعی قبل از Merge بررسی می‌شود.
  • بعد از Fix، تست و Build اجرا می‌شوند.
  • Config در Repository ثبت شده است.
  • Lock File در Repository قرار دارد.
  • API Key و Secret در Source Code وجود ندارند.

پرسش‌های متداول

ESLint چه کاری انجام می‌دهد؟

ESLint کد JavaScript و زبان‌های مرتبط را به‌صورت ایستا تحلیل می‌کند و الگوهای مشکل‌دار یا ناسازگار با قواعد پروژه را گزارش می‌دهد.

آیا ESLint کد را اجرا می‌کند؟

معمولاً خیر. ESLint Source Code را Parse و تحلیل می‌کند؛ اما رفتار کامل Runtime برنامه را آزمایش نمی‌کند.

آیا ESLint رایگان است؟

ESLint یک پروژه متن‌باز است.

آیا ESLint فقط برای JavaScript است؟

هسته ESLint برای JavaScript طراحی شده است، اما با Parser و Pluginهای مناسب می‌توان TypeScript، JSX و ساختارهای مرتبط را بررسی کرد.

فایل تنظیمات جدید ESLint چیست؟

در سیستم Flat Config معمولاً از این فایل استفاده می‌شود:

eslint.config.js

یا:

eslint.config.mjs

تفاوت eslint.config.js و .eslintrc چیست؟

eslint.config.js مربوط به سیستم جدید Flat Config است. .eslintrc متعلق به سیستم قدیمی تنظیمات است. برای پروژه جدید بهتر است از مستندات نسخه فعلی ESLint و Flat Config استفاده کنید.

چگونه ESLint را اجرا کنیم؟

npx eslint .

یا:

npm run lint

چگونه خطاها را خودکار اصلاح کنیم؟

npx eslint . --fix

همه مشکلات قابل اصلاح خودکار نیستند.

آیا ESLint جایگزین Prettier است؟

خیر. ESLint بیشتر برای کیفیت و خطاهای احتمالی و Prettier برای Formatting استفاده می‌شود.

آیا ESLint جایگزین تست است؟

خیر. ESLint نمی‌تواند درستی منطق تجاری و رفتار Runtime را تضمین کند.

آیا ESLint برای React لازم است؟

اجباری نیست، اما در پروژه‌های حرفه‌ای React بسیار مفید است؛ به‌خصوص برای بررسی React Hooks، JSX و استانداردهای تیم.

چرا Ruleهای React Hooks مهم‌اند؟

Hooks باید طبق قواعد مشخص React استفاده شوند. Plugin مربوط می‌تواند بسیاری از استفاده‌های اشتباه مانند فراخوانی شرطی Hook یا Dependency ناقص Effect را گزارش کند.

آیا کد تولیدشده با هوش مصنوعی هم باید Lint شود؟

بله. کد تولیدشده با هوش مصنوعی باید مانند هر کد دیگری Lint، Type Check، Test، Build و Review شود.

آیا ESLint همه خطاهای کد هوش مصنوعی را پیدا می‌کند؟

خیر. ESLint فقط الگوهایی را پیدا می‌کند که Rule فعال برای آن‌ها وجود داشته باشد. خطاهای منطقی، معماری و نیازمندی باید با تست و Review بررسی شوند.

جمع‌بندی

ESLint یکی از ابزارهای اصلی کنترل کیفیت در پروژه‌های JavaScript، React و TypeScript است. این ابزار با تحلیل ایستای Source Code می‌تواند بسیاری از خطاهای احتمالی و ناسازگاری‌های کدنویسی را پیش از اجرا یا انتشار گزارش کند.

مهم‌ترین نکات این آموزش:

  • ESLint با Prettier، TypeScript و تست تفاوت دارد.
  • پروژه‌های جدید باید از Flat Config استفاده کنند.
  • فایل اصلی تنظیمات معمولاً eslint.config.js است.
  • Ruleها می‌توانند off، warn یا error باشند.
  • Config پیشنهادی نقطه شروع مناسبی است.
  • Browser و Node.js باید Globalهای متفاوت داشته باشند.
  • React و TypeScript به Plugin و Config مناسب نیاز دارند.
  • Ruleهای Formatting نباید با Prettier تداخل داشته باشند.
  • --fix فقط مشکلات قابل اصلاح خودکار را برطرف می‌کند.
  • ESLint باید در Editor، Terminal و CI اجرا شود.
  • کد تولیدشده با هوش مصنوعی نیز باید Lint، Test و Review شود.
  • API Key سرویس هوش مصنوعی نباید در Frontend یا Repository قرار بگیرد.

اگر قصد دارید یک دستیار برنامه‌نویسی، ابزار Code Review یا سرویس توضیح خطاهای ESLint بسازید، می‌توانید منطق برنامه را در Backend پیاده‌سازی و آن را از طریق API هوش مصنوعی درواره به مدل مناسب متصل کنید.

برای انتخاب شناسه مدل و مشاهده اطلاعات به‌روز قیمت‌ها، صفحه مدل‌های درواره را ببینید.

مقالات مرتبط

منابع تکمیلی

برای مطالعه شرایط استفاده و محدودیت‌های مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.

Read more

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی با ترکیب گردش‌کارهای خودکار و مدل‌های هوش مصنوعی، پردازش متن، دسته‌بندی، استخراج اطلاعات و تصمیم‌های پیشنهادی را خودکار می‌کند. در این راهنما، معماری و ساخت نمونه عملی آن با API درواره را می‌آموزید.

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce شیوه‌ای جدید برای خرید اینترنتی است که در آن ایجنت هوش مصنوعی می‌تواند نیاز کاربر را بفهمد، محصولات را جست‌وجو و مقایسه کند و فرایند خرید را پیش ببرد. در این راهنما با معماری، UCP، ACP و پیاده‌سازی آن با API درواره آشنا می‌شوید.