Skip to content

خط فرمان

This content is not available in your language yet.

Terminal window
npx darzsaz <فرمان> [پروژه.json] [پرچم‌ها] # از npm (بستهٔ darzsaz)
pnpm -r build && node apps/cli/dist/darzsaz.mjs <فرمان> # از خودِ مخزن

بدون مسیر پروژه، آشپزخانهٔ نمونه (myKitchen) به کار می‌رود. پرونده — .darz ِ برنامه یا JSON ِ خام — از راه unpackDarzWithAssets هسته خوانده می‌شود (src/project.ts؛ تصویرهای assets/ ِ .darz برای جلدِ export و pdf، imageOf): همان سقف‌های اندازه، اعتبارسنجی و مهاجرت رابط؛ اندازه پیش از خواندن سنجیده می‌شود. فرمان‌ها با همان هستهٔ رابط حساب می‌کنند (derive، یا تابع‌های هسته‌ای که derive از آن‌ها ساخته شده) و --json روی همه یک معنا دارد: فقط یک شیء JSON روی خروجی استاندارد، عدد عدد (نه رشتهٔ فارسی) و بی‌جدول — برای اسکریپت و اتوماسیون. prices --update هم (تا پیگیریِ موجِ ۶ تأییدِ متنی چاپ می‌کرد): { usdToman, note, noteId, noteValues, capturedAt, baseCapturedAt, factor, written } — نرخ و تاریخِ مرجعِ نوشته‌شده، تاریخِ مرجعی که جلو برده شد، و noteId که cli.prices.rate-failed یعنی نرخ زنده نرسید و ضریب ۱ است. خروجیِ موفقِ هیچ فرمانی ok ندارد؛ فقط خطا ok: false است. darzsaz --help و darzsaz <فرمان> --help راهنمای citty را می‌دهند، به زبانِ --lang.

فرمان چه می‌کند پرچم‌ها
parts لیست برش؛ ابعاد، اندازهٔ برش است --raw بدون ادغام؛ --material <id>
nest ورق مصرفی و بازده هر جنس --cuts ترتیب برش؛ --seed <n>
check بررسی طرح با قواعد دستیار؛ با خطا کد خروج ۱
bom لیست خرید و هزینه به واحدِ پروژه، با تاریخِ برداشتِ مرجع
units یونیت‌های هر ردیف و موانع دیوار
export بستهٔ کاغذی: darzsaz.html، cutlist.csv، bom.csv --out <پوشه>؛ --dxf برای CNC (با لایهٔ سوراخ و شیار)؛ --xlsx سه برگهٔ اکسل
assemble راهنمای مونتاژ assembly.html --out <پوشه>
pdf PDF از همان HTML با کروم بی‌سر --out <پوشه>؛ --chrome <مسیر>
prices قیمت مرجع با نشان اطمینان --live نرخ روز؛ --from <مرجع.json>؛ --update --out <پرونده> مرجع تازه (تقریب)؛ --write <پروژه.json>
demo پروژهٔ نمونه را می‌نویسد <مسیر>
bench بنچمارک پیکرهٔ ده آشپزخانهٔ واقعی: زمان، ورق، بازده، خطا --iterations <n>
render عکس رندر بی‌سر از اپ ساخته‌شده (جایگزینِ اسکریپتِ عکسِ قدیمی) --out، --view، --quality، --width، --dof، --no-ao، --gpu، --url یا --app <پوشهٔ dist>، --chrome

همه --json و --lang می‌گیرند.

prices هر ورق را با ابعادش می‌آورد — قیمت مالِ جنس و ابعاد است (sheetPriceKey، ۹.۶) — و --write دفتر را به واحدِ خودش (تومان) و با capturedAt در پروژه می‌نویسد، حتی در پروژهٔ ریالی؛ تبدیل فقط در نمایش است (catalog.md).

Terminal window
npx darzsaz bom --lang en-US # خروجی و راهنما انگلیسی
DARZSAZ_LANG=en-US npx darzsaz check # برای کسی که همیشه انگلیسی می‌خواهد
npx darzsaz --lang en-US --help

یک جا تصمیم می‌گیرد (src/lang.ts، langOf): پرچم ← متغیرِ محیطی ← fa-IR. متغیرِ خالی یعنی نگذاشته‌ای؛ پرچم هم پیش از نامِ فرمان (darzsaz --lang en-US parts) کار می‌کند هم پس از آن، با همان تجزیه‌گرِ citty (پرچمِ آخر برنده؛ پس از -- آرگومان است). هر چه به زبان می‌گوید با setLang با هم عوض می‌شود: say (پیام)، cliFmt() (عددِ جدول و نقشهٔ ورق)، cliI18n (برگه، CSV، اکسل)، و Say ِ آشپزخانهٔ نمونه (demo، bench و هر فرمانِ بی‌پرونده) — نامِ پروژهٔ نمونه داده است و به زبانِ همان اجرا ساخته می‌شود.

  • LANG ِ سیستم خوانده نمی‌شود — همان تصمیمِ رابط که navigator.languages را نمی‌خواند (i18n.md): ترمینالِ انگلیسی در ایران نشانهٔ زبانِ کاربر نیست.
  • زبانِ ناشناخته خطاست، نه فارسیِ بی‌صدا. --lang en یا DARZSAZ_LANG=english پیش از هر کاری با کدِ ۲ بیرون می‌رود و پیام را به همهٔ زبان‌ها می‌گوید — زبانِ کاربر درست همان است که نمی‌دانیم: ✖ Unknown language “en” from --lang. Languages: fa-IR (فارسی) and en-US (English).
  • راهنما پیش از citty. citty --help را پیش از هر setup چاپ می‌کند (فرمانِ ناشناخته از setup ِ ریشه می‌گذرد و بعد راهنما می‌گیرد)، پس main.ts زبان را پیش از runMain می‌نشاند (startLangsetup ِ ریشه همان تصمیم را برای هر راهِ دیگرِ درخت (runCommand ِ آزمون) می‌گیرد. توضیحِ فرمان‌ها و آرگومان‌ها تابع‌اند (meta: () => …، args: () => …) که citty هنگامِ راهنما حل می‌کند؛ ثابتِ سطحِ ماژول با زبانِ پیش از --lang قفل می‌شد. سرتیترهای خودِ citty (USAGE، OPTIONS، (Default: …)) انگلیسی‌اند، در فارسی هم مثل همیشه.
  • --lang روی هر فرمان اعلام شده (langArg در cli.ts): citty پرچمِ ناشناخته را بولی و مقدارش را آرگومانِ جایگاهی می‌گیرد — darzsaz parts --lang en-US بی آن پروندهٔ «en-US» را می‌خواند. test/lang.test.ts هر دوازده فرمان را می‌سنجد.
  • اکسل جهتِ زبان را دارد: xlsx(sheets, dir) برگهٔ en-US را چپ‌به‌راست می‌نویسد؛ تا ۳.۶ هر برگه rightToLeft بود.

آزمون‌ها: test/lang.test.ts (ترتیبِ تصمیم، خطای زبان، یک‌جا عوض شدن، درختِ citty، --help ِ هر فرمان)، test/english.test.ts (خروجیِ متنیِ check، parts، bom، nest، units، prices، bench، demo و export در en-US بی هیچ حرفِ فارسی، با کاتالوگی که نامِ هر قلمش شناسه است — نامِ محصول ترجمه نمی‌شود)، test/smoke.test.ts (راهنما و کدِ ۲ روی بستهٔ ساخته‌شده).

darzsaz روی npm است و اسکریپتِ کسی کلیدهای دیروز را می‌خواند (۳.۶). هر جا خروجی پیامِ هسته دارد، کلیدِ دیروز همان متن را به زبانِ خط فرمان (--lang، پیش‌فرض فارسی) نگه می‌دارد و شناسه و مقدارِ پیام کنارش می‌آیند:

شکل کلیدِ دیروز کلیدهای تازه
شیء با message message messageId، values
میدانِ پیام‌دارِ دیگر: bomlines[].name/unit/note، pricesnote name، unit، … nameId، nameValues، unitId، unitValues، …
فهرستِ رشته: nestproblems problems problemMessages: { code, message, messageId, values } به همان ترتیب
برچسبِ قطعه: partsrows[].label، nestlayouts[].placements[].label label labelId (part.label یا part.label.mergedlabelValues
نامِ آشپزخانه: benchrows[].name name nameId (sample.kitchen.*nameValues
برچسبِ یونیت: unitswalls[].runs[].units[].label label — (فقط متنِ رندرشدهٔ unitLabel، بی labelId/labelValues)

values همان مقدارِ تیپ‌دارِ هسته است ({ "kind": "count", "value": 105 })، پس اسکریپتِ تازه به زبانِ خروجی وابسته نمی‌شود. واحدِ سطرِ صورت‌حساب در هسته کلید است (sheet) و unitId شناسهٔ واژه‌اش (bom.unit.sheet). سطری که یادداشت ندارد، مثل دیروز کلیدِ یادداشت هم ندارد. کمکی‌ها jsonField و jsonMessage در src/lang.ts؛ عکسِ کلیدهای پیش و پس در test/json-messages.test.ts و test/commands.test.ts.

--lang متن را عوض می‌کند، قرارداد را نه: در en-US همان کلیدها با همان شناسه‌ها می‌آیند و فقط متنِ کلیدِ دیروز انگلیسی است (test/json-messages.test.ts برای check، parts، nest، bom، units، prices و bench مسیرِ هر کلید و هر …Id را در دو زبان برابر می‌خواهد). پیش‌فرض همچنان فارسی است.

قراردادِ عمومی: { project, errors, issues[] } و هر مسئله { ruleId, severity, category, message, messageId, values, unitIds, fixes }. message و هر fixes متنِ رندرشده به زبانِ خط فرمان‌اند (پیش‌فرض فارسی، بی نویسهٔ جداسازِ جهت) — همان کلیدها با همان معنای نسل چهارم. messageId و values تازه‌اند: شناسهٔ پیامِ هسته و مقدارِ تیپ‌دارش ({ kind: 'mm', value: 43 }؛ یونیتِ بی نامِ کاربر { kind: 'ref', value: { ref: { id: 'unit.preset.base-hob' }, values: {} } } و نامِ کاربر text)، تا اسکریپتِ زبانِ دیگر پیام را بی تجزیهٔ متنِ فارسی بسازد (i18n.md). آزمون: test/check-json.test.ts.

  • 0 موفق؛ check هم با هشدار صفر می‌دهد — هشدار جلوی کار را نمی‌گیرد.
  • 1 خطای دامنه (DarzError، پیام به زبانِ خط فرمان با کد) یا check با دست‌کم یک خطا — تا در اسکریپت بشود جلوی خرید ورق را گرفت. پروندهٔ ناموجود (cli/file-not-found) یا ناخوانا (cli/file-unreadable)، گزینهٔ نادرستِ render (render/bad-view، render/bad-quality، و render/bad-width که صفحه می‌سنجد)، رندری که در صفحه نشد یا به مهلت نرسید (render/failed، render/timeout)، نبودنِ بستهٔ وب (render/no-app) و کروم (cli/no-chrome از pdf، render/no-chrome از render — یک پیام برای هر دو)، نقشهٔ مشکل‌دار در export/pdf (export/problems، pdf/problems) و مرجعِ prices --from هم خطای دامنه‌اند: ناموجود، ناخوانا یا JSON ِ خراب همان خطای هر پروندهٔ کاربر (cli/file-not-found، cli/file-unreadable، cli/bad-json از readJsonFile؛ تا پیگیریِ موجِ ۶ خطای خامِ Node بود) و JSON ِ ناهم‌شکل prices/bad-reference. تا نسل چهارم پروندهٔ ناموجود پشتهٔ خامِ ENOENT بود و چهار فرمان خودشان console.error و process.exit می‌زدند.
  • 2 خطای کاربرد: زبانِ ناشناخته (--lang، DARZSAZ_LANGdemo بی مسیر (cli/no-out) و پرچمِ عددیِ بدشکل (cli/bad-number: --seed، --iterations، --width با intFlag؛ citty ۰٫۲ تیپِ عددی ندارد و --seed abc پیش‌تر بی‌صدا بذرِ پیش‌فرض می‌گرفت).
  • فرمان ناشناخته: citty راهنما را چاپ می‌کند و غیرصفر می‌دهد.

هر خطای دامنه از guarded (src/cli.ts) می‌گذرد و با --json یک شیء روی خروجیِ استاندارد می‌دهد — همان جایی که خروجیِ موفق است — و stderr خالی می‌ماند. زبانِ ناشناخته به guarded نمی‌رسد: startLang پیش از citty آن را به همهٔ زبان‌ها روی stderr می‌گوید، با --json یا بی آن.

{
"ok": false,
"code": "cli/file-not-found",
"message": "",
"messageId": "cli.file.not-found",
"values": { "path": { "kind": "text", "value": "x.json" } }
}

detail فقط وقتی هست که خطا جزئیات دارد: export/problems و pdf/problems همان problems و problemMessages ِ nest --json را دارند. بی --json همان متن روی stderr با پنج مشکلِ اول و «… و N مورد دیگر». آزمون: test/json-errors.test.ts (همهٔ فرمان‌های پروژه‌خوان، مرجعِ prices --from، خطای کاربرد، متن).

src/find-chrome.ts کروم را از DARZSAZ_CHROME، PUPPETEER_EXECUTABLE_PATH یا CHROME_PATH می‌گیرد، وگرنه مسیرهای رایج macOS، Linux و Windows را می‌گردد (findChrome، از src/chrome.ts دوباره صادر) — یک یابنده برای pdf، render و اسکریپت‌های مخزن (scripts/lib/chrome.mjs همین پرونده را با زدودنِ تیپِ Node وارد می‌کند؛ بستهٔ npm همان dist/darzsaz.mjs می‌ماند) و یک پیامِ «کروم پیدا نشد» (noChromeMsg) برای pdf و render؛ پیش‌تر دو متنِ جدا بود و هر اسکریپت فهرستِ کوتاه‌ترِ خودش را داشت. --gpu پشتیبانِ ANGLE ِ همان سکو را می‌گیرد (gpuAngle: metal روی مک، d3d11 روی ویندوز، gl روی لینوکس)؛ تا نسل چهارم همیشه metal بود. src/pdf.ts (htmlToPdf) مسیرِ کروم را اجباری می‌گیرد: گفتنِ «کروم پیدا نشد» کارِ فرمان است، به زبانِ خودش؛ نسخهٔ دومِ آن پیام به فارسیِ ثابت در htmlToPdf بود و هیچ فراخوانی به آن نمی‌رسید. قلم در خودِ HTML جاسازی شده، پس PDF روی هر دستگاهی یک شکل است. render (commands/render.ts، رانندهٔ کروم در src/render.ts) بستهٔ وب را از --app با سرور ایستای کوچک (src/serve.ts) از زیرمسیر /darzsaz/ بالا می‌آورد یا به --url وصل می‌شود، پروژه را از خانه با قلاب window.__darzsazOpen (apps/web/src/app/automation.ts) باز می‌کند و با window.__darzsazRender({ view, quality, width, dof, ao }) رندر می‌گیرد؛ PNG را می‌نویسد، بی‌سر با SwiftShader یا با --gpu. تا نسل چهارم منتظرِ window.__darzsazLoad ِ ویرایشگر بود که خانه ندارد، و هر رندر پس از شصت ثانیه می‌افتاد.

روی API، نه برچسب (۳.۷): تا نسل چهارم پنلِ رندر را مثلِ کاربر می‌راند — دکمه با title="رندر با کیفیت بالا"، زبانه با متنِ «سه‌رخ»، <select id="q"> — و در رابطِ انگلیسی (و از وقتی پهنا و کیفیت Select ِ سیستم طراحی شدند، در فارسی هم) رندر نمی‌شد. قلاب همان نگاشتِ پنل (components/render/presets.ts) را می‌خواند و پاسخِ بی‌زبان می‌دهد: { ok: true, dataUrl } یا کدِ خطا (bad-view، bad-quality، bad-width با فهرستِ مجاز، failed)؛ متن را خط فرمان به زبانِ خودش می‌سازد. اسکریپتِ صفحه کوتاه است و نتیجه را روی window.__darzsazJob می‌گذارد تا Node هر نیم ثانیه نظر کند (ارزیابیِ طولانی از مهلتِ پروتکل رد می‌شود). قلاب تا صحنهٔ سه‌بعدی بالا نیامده نیست.

apps/cli با نام darzsaz منتشر می‌شود: tsdown یک پروندهٔ dist/darzsaz.mjs می‌سازد که بسته‌های ورک‌اسپیس (هسته، زبان، گزارش، هندسه) داخلش‌اند و وابستگی‌های بیرونی (@lingui/core، citty، fflate، puppeteer-core، zod) بیرون. پس بسته‌های ورک‌اسپیس در devDependencies اند، نه dependencies: pnpm pack آن‌ها را 0.0.0 می‌نوشت و npm i darzsaz با 404 می‌افتاد. node scripts/release-check.mjs بسته را می‌سازد و می‌سنجد (نصب‌شدنی، فقط وزیرمتن)؛ انتشار با release.yml (deploy.md).

src/main.ts ورود و src/cli-main.ts درخت فرمان citty با نسخه؛ نسخه را src/version.ts از define ِ tsdown (و در آزمون، vitest) می‌گیرد که package.json ِ همین بسته را می‌خواند — نسخهٔ محصول یک منبع دارد (deploy.md). هر فرمان commands/<نام>.ts با یک تابع run<نام>(opts, cat) خالص (آزمون‌پذیر) و یک defineCommand برای راهنما و آرگومان — آزمون‌ها run<نام> را مستقیم صدا می‌زنند، جز pdf و render که خصوصی‌اش دارند (pdf از راهِ درختِ citty با htmlToPdf ِ ساختگی، render با renderJobOf ِ صادرشده)؛ cli.ts مشترکات (help، projectArg، jsonArg، langArg، outArg، emit، guarded، loadFor، readUserFile، readJsonFile، intFlag، shownfind-chrome.ts یابندهٔ کروم و chrome.ts پیامِ نبودنش و gpuAngle؛ lang.ts زبان (langOf، setLang، say، cliFmt، cliI18n، jsonFieldwords.ts واژه‌های مشترکِ چند فرمان (سرستون، گروهِ هزینه، «نوشته شد») — یک شناسه برای یک معنا؛ table.ts جدولِ ترمینال (عدد را فرمان با cliFmt() رشته می‌کند)؛ sheet-art.ts نقشهٔ ورق متنی؛ xlsx.ts نویسندهٔ اکسل و workbook.ts سه برگهٔ آن؛ render-page.ts پروتکلِ صفحهٔ رندر (kickoffScript، failureOfusd.ts نرخِ دلارِ زنده؛ commands/prices-text.ts خروجیِ متنیِ prices. هر رشتهٔ کاربرپسند پیام است و در کاتالوگِ جدای خط فرمان (cli.<زبان>.po، i18n.md). آزمون‌ها، پانزده پرونده در test/: واحدِ فرمان‌ها (commands.test.ts)، درختِ citty (cli-tree.test.ts)، زبان و --json (بالا)، جدول، اکسل، prices --from، رندرِ بی‌سر و سرورش، و برگه‌ها؛ و دو آزمون روی بستهٔ ساخته‌شده (smoke.test.ts، darz-open.test.ts) که بسته را test/global-setup.ts از سورس می‌سازد — بی بیلدِ پیشین، و بی آن آزمون می‌افتد، کنار نمی‌رود.