⁦ESLint⁩

⁦eslint-plugin-textjs⁩: کونسول کے لیے محفوظ JSX، سیل کی چوڑائی والے گلفس، فریم کی رفتار والے ٹائمرز اور ⁦App Router⁩ کی جانچ۔

eslint-plugin-textjs ایڈیٹر میں Text.js کی غلطیاں پکڑتا ہے: کونسول کمپوننٹس میں DOM ٹیگز، متن کے اندر باکس، ایسے گلف جو Menlo میں نہیں ہیں، غیر ضروری console.log کالز اور ⁦App Router⁩ کے ایسے ایکسپورٹس جنہیں خاموشی سے نظر انداز کر دیا جاتا ہے۔

سیٹ اپ

bun add -d eslint eslint-plugin-textjs typescript-eslint
eslint.config.jsjs
import { defineConfig } from "eslint/config";import tseslint from "typescript-eslint";import textjs from "eslint-plugin-textjs";export default defineConfig(tseslint.configs.recommended, textjs.configs.recommended);

پلگ ان فلیٹ کنفگ کے ساتھ ⁦ESLint 9⁩ اور 10 کو سپورٹ کرتا ہے۔ قواعد نحوی ہیں اور انہیں ٹائپ کی معلومات یا parserOptions.project کی ضرورت نہیں ہے۔ TypeScript اور JSX کو سمجھنے والا کوئی بھی پارسر کام کرتا ہے۔

کنفگز

کنفگفعال ہونے والے قواعد
textjs.configs.recommendedدرستگی کا ہر قاعدہ بطور ایرر؛ کونسول، ٹائمر اور فریم کی رفتار کے قواعد بطور وارننگ
textjs.configs.strictسب کچھ بطور ایرر، ساتھ میں prefer-use-keymap بطور وارننگ

اس کے بجائے قواعد الگ الگ منتخب کریں:

eslint.config.jsjs
import textjs from "eslint-plugin-textjs";export default [  {    plugins: { textjs },    rules: {      "textjs/no-box-in-text": "error",      "textjs/no-console-in-components": ["warn", { allow: ["error"], logger: "log" }],    },  },];

کونسول فائلیں

زیادہ تر قواعد صرف ان فائلوں پر لاگو ہوتے ہیں جو کونسول میں رینڈر کرتی ہیں: ایسی فائلیں جو @textjs/app یا @textjs/react سے کوئی کمپوننٹ یا ہک (Box، Text، useInput، …) امپورٹ کرتی ہیں۔ react-dom یا @textjs/react/dom امپورٹ کرنے والی فائلیں صفحے کا کوڈ ہیں اور انہیں نہیں چھیڑا جاتا، اس لیے ویب سائٹ ایک ہی پروجیکٹ میں DOM صفحات اور کونسول ایپس رکھ سکتی ہے۔ tokenize یا parseMarkdown جیسی یوٹیلیٹی امپورٹ کرنے سے فائل کونسول فائل نہیں بنتی۔

eslint.config.jsjs
import textjs from "eslint-plugin-textjs";export default [  textjs.configs.recommended,  {    settings: {      textjs: {        packages: ["@acme/console-ui"], // also re-exports Text.js components        consoleFiles: "imports", // or "all"      },    },  },];

⁦App Router⁩ کے قواعد کسی بھی app/ ڈائریکٹری میں فائل کے نام (page.tsx، layout.tsx، route.ts، …) کے مطابق چلتے ہیں، جس میں src/app/ بھی شامل ہے۔ اگر آپ کی ڈائریکٹری کا نام کچھ اور ہے تو valid-route-module، valid-metadata اور route-handler-exports کو { appDir: "routes" } دیں۔

قواعد

قاعدہتجویز کردہاصلاح
no-dom-elementsایررتجویز
no-box-in-textایرر
no-unsupported-glyphsایررخودکار اصلاح، تجویز
no-console-in-componentsوارننگتجویز
prefer-use-intervalوارننگتجویز
no-sub-frame-timersوارننگ
prefer-use-keymapصرف strict
valid-route-moduleایرر
valid-metadataایرر
route-handler-exportsایررتجویز

no-dom-elements

<div>، <span>، کسٹم ایلیمنٹس اور دیگر DOM ٹیگز کونسول میں موجود نہیں ہیں۔ ریکنسائلر صرف اپنے ہوسٹ نوڈز کو پہچانتا ہے اور کسی بھی دوسری چیز پر TX003 ایرر دیتا ہے۔

<div className="flex-col">       // ✗<Box className="flex-col">       // ✓<strong>Deployed</strong>        // ✗<Text bold>Deployed</Text>       // ✓

تجویز ٹیگ کو قریب ترین کمپوننٹ (div → Box، span/p → Text، strong → Text bold، a → Link، input → Input، hr → Divider، …) سے بدلتی ہے اور امپورٹ شامل کرتی ہے۔

no-box-in-text

<Text> اسٹائل والے spans کا سلسلہ ہے؛ اس کے اندر باکس نہیں ہو سکتا۔ <Box> یا باکس روٹ والے کسی کمپوننٹ (<ScrollBox>، <Input>، <Code>، <ProgressBar>، <Divider>، …) کو اندر رکھنے سے رینڈر کے وقت TX004 ایرر آتا ہے۔ یہ قاعدہ اسے ایڈیٹر ہی میں پکڑ لیتا ہے، بشمول &&، ٹرنری ایکسپریشنز، فریگمنٹس اور .map() کے اندر۔

<Text>Status <Box /></Text>                     // ✗<Box className="flex-row gap-1"><Text>Status</Text><Box /></Box>  // ✓<Text>Press <Kbd>⌘K</Kbd> <Spinner /></Text>     // ✓ inline components

no-unsupported-glyphs

⁦Text.js⁩ ہر حرف کو مقررہ سیل گرڈ میں ترتیب دیتا ہے۔ جو گلف macOS پر DevTools کونسول کے فونٹ Menlo میں نہیں ہیں، وہ فال بیک فونٹ میں رینڈر ہوتے ہیں جو سیل سے چوڑا ہوتا ہے، اس لیے ان کے بعد ہر سیل اپنی جگہ سے ہٹ جاتا ہے۔

  • بریل (⁦U+2800–U+28FF⁩، ٹرمینل کے روایتی اسپنر فریم): بلاک یا کواڈرنٹ حروف (▘▝▗▖)، <Spinner variant="dots"> یا چارٹس پر marker="quadrant" استعمال کریں۔ صرف ٹرمینل میں text run سے چلنے والی ایپس کے لیے { allowBraille: true } سیٹ کریں۔
  • متفرق علامات اور تیر (⁦U+2B00–U+2BFF⁩، جیسے چھوٹا مربع ⁦U+2B1D⁩): تجاویز Menlo کے متبادل (·، ●، ←) پیش کرتی ہیں۔
  • ایک سیل کی علامات کی ایموجی شکل (▶ یا ↩ کے بعد ⁦U+FE0F⁩): ویری ایشن سلیکٹر انہیں دو سیل کے ایموجی میں بدل دیتا ہے جبکہ گرڈ ایک سیل محفوظ رکھتا ہے۔ خودکار اصلاح اسے ہٹا دیتی ہے۔

چوڑے ایموجی (🚀، ✅) درست ہیں: Text.js انہیں دو سیل کے طور پر ماپتا ہے۔

no-console-in-components

ہر فریم ایک console.log ہے۔ آپ کے اپنے لاگز فریموں کے درمیان آتے ہیں، اگلا فریم انہیں اسکرول کرکے ہٹا دیتا ہے اور وہ نیچے چپکے رہنے والے ویو میں چھپ جاتے ہیں۔ console.clear() خود ایپ کو مٹا دیتا ہے۔

"textjs/no-console-in-components": ["warn", { allow: ["error"], logger: "log" }]

⁦UI⁩ میں پیغامات دکھانے کے لیے useToast() یا لاگ <ScrollBox> استعمال کریں، یا [▼] ⁦Dev Overlay⁩ (Ctrl+`) میں اسٹیٹ کا معائنہ کریں۔ logger کے ساتھ، تجویز console.warn(…) کو log.warn(…) میں بدلتی ہے۔ ٹیسٹ فائلوں اور @textjs/app/testing رینڈرز کو چھوڑ دیا جاتا ہے۔

prefer-use-interval

کمپوننٹ میں براہ راست setInterval استعمال کرنے پر پرانی اسٹیٹ سے بچنے کے لیے ایک افیکٹ، ایک کلین اپ اور ایک ریف درکار ہوتا ہے۔ useInterval تینوں کام کرتا ہے، اور null اسے روک دیتا ہے۔

useEffect(() => {  if (paused) return;  const id = setInterval(tick, 1000);  return () => clearInterval(id);}, [paused]);useInterval(tick, paused ? null : 1000); // the suggestion

اینیمیشن کے لیے، useAnimationFrame رینڈرر کی فریم رفتار کی پیروی کرتا ہے اور آؤٹ پٹ موقوف ہونے پر رک جاتا ہے۔ یوٹیلیٹی ہکس دیکھیں۔

no-sub-frame-timers

⁦Text.js⁩ ہر 66 ms میں زیادہ سے زیادہ ایک فریم خارج کرتا ہے (تقریباً 15 fps)۔ 16 ms کا وقفہ ہر خارج شدہ فریم پر چار بار رینڈر کرتا ہے؛ اضافی فریم یکجا ہو جاتے ہیں اور صرف CPU استعمال کرتے ہیں۔ یہ minInterval (ڈیفالٹ 66) سے کم setInterval/useInterval تاخیر اور 15 سے زیادہ fps والے useAnimationFrame کی نشاندہی کرتا ہے۔

prefer-use-keymap

e.key کا دستی موازنہ کام کرتا ہے، لیکن شارٹ کٹس نظر نہیں آتے۔ useKeymap لیبل والی بائنڈنگز کو <KeyHelp>، <KeyHints> (hint: true والی بائنڈنگز) اور کمانڈ پیلیٹ میں رکھتا ہے، g g جیسے سلسلے سنبھالتا ہے اور میچ ہونے والی کیز کی پروپیگیشن روک دیتا ہے۔ یہ ان useInput ہینڈلرز کی نشاندہی کرتا ہے جو دو یا زیادہ کی لٹرلز (minKeys) کا موازنہ کرتے ہیں اور ٹائپنگ کے لیے e.input پڑھنے والے ہینڈلرز کو چھوڑ دیتا ہے۔

useKeymap({  "up, k": { label: "Increment", run: inc, hint: true },  "down, j": { label: "Decrement", run: dec, hint: true },});

کی بورڈ شارٹ کٹس دیکھیں۔

valid-route-module

  • page، layout، loading، error اور not-found فائلوں کو ایک کمپوننٹ بطور ڈیفالٹ ایکسپورٹ کرنا ضروری ہے (TX015)۔
  • export const dynamic لازماً "auto"، "force-static" یا "force-dynamic" ہونا چاہیے (TX031)۔ Text.js، Next.js کے "error" کو سپورٹ نہیں کرتا۔ اسے صفحات، لے آؤٹس اور روٹ ہینڈلرز سے پڑھا جاتا ہے۔ صفحات اور لے آؤٹس میں اسے سادہ اسٹرنگ لٹرل کے طور پر لکھیں: text build ماڈیول چلائے بغیر اسے سورس سے پڑھتا ہے۔

valid-metadata

⁦Metadata⁩ پہلے لے آؤٹس سے، پھر صفحے (یا not-found) سے مرج ہوتا ہے۔ یہ قاعدہ ان چیزوں کی نشاندہی کرتا ہے جنہیں راؤٹر خاموشی سے نظر انداز کر دیتا:

  • loading یا error فائلوں میں metadata یا generateMetadata
  • ایک فائل میں دونوں ایکسپورٹس
  • async generateMetadata: اسے سنکرونس طور پر کال کیا جاتا ہے، اس لیے Promise کبھی عنوان سیٹ نہیں کرتا
  • ایسا title جو اسٹرنگ یا { default, template?, absolute? } نہ ہو، یا غلط ہجے والی کی
  • %s کے بغیر title.template، یا صفحے میں اس کا استعمال، جہاں اس کا کوئی اثر نہیں ہوتا
  • غیر اسٹرنگ description

route-handler-exports

route.ts فائلیں صرف ان HTTP میتھڈز کا جواب دیتی ہیں جنہیں وہ ایکسپورٹ کرتی ہیں: GET، HEAD، POST، PUT، PATCH، DELETE اور OPTIONS۔ چھوٹے حروف والا get یا Post کبھی کال نہیں ہوتا (درخواستوں کو 405 ملتا ہے)؛ تجویز اس کا نام بدل دیتی ہے۔ ڈیفالٹ ایکسپورٹس، نان فنکشن ہینڈلرز اور دیگر ایکسپورٹس کی نشاندہی ہوتی ہے، سوائے dynamic اور revalidate روٹ سیگمنٹ کنفگ کے۔ مشترکہ کوڈ lib/ میں منتقل کریں، یا { allow: [...] } کے ساتھ اضافی نام درج کریں۔

app/api/health/route.tsts
export function get() { … }   // ✗ never calledexport function GET() { … }   // ✓
⁦GitHub⁩ پر اس صفحے میں ترمیم کریں