IlmHamroh
JavaScript Full-stack/24-qism. Node.js18/55-dars17 daqiqa
Mundarija (32)

Node.js path va os: Windows, Linux va macOS'da bir xil ishlaydigan kod

Qisqacha: Yo'llarni hech qachon + "/" + bilan yig'mang. path.join bo'laklarni joriy OS ajratgichi (Windows — \, Linux/macOS — /) bilan birlashtiradi va .. ni hisoblaydi; path.resolve esa natijani to'liq (mutlaq) yo'lga aylantiradi. Boshqa OS'ning yo'li kerak bo'lsa — path.win32 va path.posix. Skript yonidagi fayl — import.meta.dirname. Qator oxiri Windows'da \r\n (CRLF), boshqalarida \n — split("\n") dan keyin \r qoladi. Foydalanuvchi papkalari — os.homedir(), vaqtinchalik — os.tmpdir(), kesh va sozlama esa har OS'ning o'z joyida.

Bu darsda

  • join, resolve, normalize, relative, parse farqini bilasiz va to'g'risini tanlaysiz.
  • path.win32 va path.posix bilan boshqa OS yo'llarini Windows'da (yoki aksincha) sinay olasiz.
  • CRLF tuzog'ini tanib, matnni OS'dan qat'i nazar to'g'ri bo'lasiz.
  • os modulidan kerakli ma'lumotni olasiz: homedir, tmpdir, EOL, availableParallelism.
  • valyuta keshi va sozlamasini OS konvensiyasi bo'yicha joylashtirasiz va holat 18 ni commit qilasiz.

Oldin bilishingiz kerak: fs: uch API shakli, Xavfsiz fayl operatsiyalari, process: argv, env va signallar, Global obyektlar.

1. Nega bu kerak?

Siz valyuta ni Windows'da yozyapsiz. Do'stingiz uni MacBook'da, serveringiz Linux'da ishga tushiradi. Uchala kompyuterda yo'l har xil ko'rinadi:

OS Uy papkasi Ajratgich
Windows C:\Users\aziz \
macOS /Users/aziz /
Linux /home/aziz /

Kodda "kesh" + "/" + "kurslar.json" deb yozsangiz, Windows ko'p hollarda kechirimli — / ni ham tushunadi. Lekin \ ni qo'lda yozsangiz, Linux uni papka ajratgichi emas, oddiy harf deb biladi. Natijada kesh\kurslar.json nomli bitta fayl paydo bo'ladi.

Ikkinchi muammo — "fayl qayerda saqlanadi". Keshni dastur papkasiga yozish yomon: npx uni har safar boshqa papkaga ochishi mumkin, global o'rnatilgan dasturning papkasiga esa yozish huquqi bo'lmasligi mumkin. Har OS'da "dastur keshi shu yerda turadi" degan kelishuv bor. Yaxshi CLI unga amal qiladi.

O'xshatish: manzil yozish. O'zbekistonda "Toshkent sh., Chilonzor t., 5-uy", AQShda "5 Main St, Springfield". Xatni to'g'ri yetkazish uchun pochtachi qaysi davlat qoidasi ekanini bilishi kerak. path — har davlat qoidasini biladigan pochtachi.

2. path moduli asoslari

2.1 join: bo'laklarni birlashtirish

path.join bo'laklarni ajratgich bilan birlashtiradi, ortiqcha / va . ni tozalaydi, .. ni hisoblaydi. Natija joriy OS'ga bog'liq bo'lmasligi uchun misollarni path.posix (Linux/macOS qoidasi) va path.win32 (Windows qoidasi) bilan yozamiz. Oddiy path — joriy OS'ning bittasi.

js
import path from "node:path";

console.log(path.posix.join("kesh", "2026", "kurslar.json"));
console.log(path.win32.join("kesh", "2026", "kurslar.json"));
console.log(path.posix.join("/home/aziz/", "/.cache/", "./valyuta"));
console.log(path.posix.join("kesh", "..", "..", "sozlama"));

Konsolda:

text
kesh/2026/kurslar.json
kesh\2026\kurslar.json
/home/aziz/.cache/valyuta
../sozlama

Uchinchi qatorga qarang: ortiqcha / lar va ./ yo'qoldi. To'rtinchisi — .. lar hisoblandi va asosdan ham yuqoriga chiqdi. join buni to'xtatmaydi — path traversal himoyasini o'zingiz qilasiz.

2.2 resolve: to'liq yo'l

path.resolve o'ngdan chapga qarab yuradi va birinchi mutlaq yo'lni topgach to'xtaydi. Mutlaq yo'l topilmasa, joriy papka (process.cwd()) ni boshiga qo'shadi. Natija doim to'liq yo'l:

js
import path from "node:path";

const p = path.posix;
console.log(p.resolve("/srv/valyuta", "kesh", "kurslar.json"));
console.log(p.resolve("/srv/valyuta", "/tmp", "a.json"));
console.log(p.isAbsolute("kesh"), p.isAbsolute("/kesh"));
console.log(path.win32.resolve("C:\\kesh", "D:\\boshqa"));

Konsolda:

text
/srv/valyuta/kesh/kurslar.json
/tmp/a.json
false true
D:\boshqa

Ikkinchi qatorda /tmp mutlaq — undan chapdagi /srv/valyuta tashlab yuborildi. To'rtinchi qatorda xuddi shu narsa Windows'da: boshqa disk harfi — boshqa ildiz.

join va resolve farqi bitta jadvalda:

join resolve
Natija nisbiy bo'lishi mumkin doim mutlaq
process.cwd() ishlatmaydi mutlaq bo'lak bo'lmasa, qo'shadi
O'rtadagi mutlaq bo'lak oddiy bo'lak kabi qo'shadi undan oldingilarni tashlaydi
Qachon bo'laklarni birlashtirish "aslida qayerda?" degan savol, xavfsizlik tekshiruvi

Tekshirib ko'ring: path.posix.join("/srv", "/etc/passwd") va path.posix.resolve("/srv", "/etc/passwd") nima qaytaradi?

Javob

join → /srv/etc/passwd (ikkinchi bo'lak oddiy bo'lak sifatida qo'shildi). resolve → /etc/passwd (mutlaq bo'lak oldingisini tashladi). Shuning uchun xavfsizlik tekshiruvi resolve bilan qilinadi — u fayl aslida qayerga tushishini ko'rsatadi.

2.3 Yo'lni bo'laklarga ajratish

js
import path from "node:path";

const fayl = "/home/aziz/.cache/valyuta/kurslar-7d1a.json";
const p = path.posix;
console.log(p.dirname(fayl));
console.log(p.basename(fayl));
console.log(p.basename(fayl, ".json"));
console.log(p.extname(fayl));
console.log(p.parse(fayl).name);
console.log(p.relative("/home/aziz", fayl));
console.log(p.normalize("/home//aziz/./x/../.cache"));

Konsolda:

text
/home/aziz/.cache/valyuta
kurslar-7d1a.json
kurslar-7d1a
.json
kurslar-7d1a
.cache/valyuta/kurslar-7d1a.json
/home/aziz/.cache
Funksiya Nima qaytaradi
dirname Papka qismi
basename(f, ext?) Fayl nomi (ixtiyoriy kengaytmasiz)
extname Kengaytma, nuqta bilan
parse { root, dir, base, name, ext } obyekti; teskarisi — path.format
relative(a, b) a dan b ga nisbiy yo'l
normalize //, ., .. tozalangan yo'l

2.4 sep va delimiter

js
import path from "node:path";

console.log(path.posix.sep, path.win32.sep);
console.log(path.posix.delimiter, path.win32.delimiter);
const PATH = "C:\\Windows;C:\\Program Files\\nodejs";
console.log(PATH.split(path.win32.delimiter));

Konsolda:

text
/ \
: ;
[ 'C:\\Windows', 'C:\\Program Files\\nodejs' ]

sep — yo'l ichidagi ajratgich. delimiter — PATH muhit o'zgaruvchisidagi yo'llar ro'yxati ajratgichi (process.env). Windows'da ;, chunki : disk harfida (C:) band.

Diqqat: JS satrida teskari chiziq maxsus belgi: "C:\valyuta" — bu C: + \v (vertikal tabulyatsiya belgisi!) + aluta. Kanon testlarini yozishda aynan shu xato chiqdi — "C:\L\valyuta" buzildi. Windows yo'lini satrda yozsangiz — \\ ("C:\\valyuta"), String.raw yoki eng yaxshisi path.win32.join("C:", "valyuta").

3. Skriptning o'z papkasi

3.1 cwd va skript papkasi — ikki xil narsa

fs darsida nisbiy yo'l joriy papkaga (cwd) nisbatan ochilishini ko'rdik. Terminalda qayerda turgan bo'lsangiz — o'sha. Skript faylining o'zi esa boshqa joyda bo'lishi mumkin. valyuta ning fixture fayli paket ichida, dist/ yonida yotadi. Foydalanuvchi esa valyuta ni istalgan papkadan chaqiradi.

ESM'da skriptning o'z joyi — import.meta da (ES Modules Node'da):

Ifoda Misol natija (Windows)
import.meta.url file:///C:/Users/…/valyuta/dist/manba.js
import.meta.filename C:\Users\…\valyuta\dist\manba.js
import.meta.dirname C:\Users\…\valyuta\dist

filename va dirname — Node 20.11 dan bor, CommonJS'dagi __filename va __dirname ning ESM o'rnini bosuvchisi. Eski kodda ko'pincha shunday yozilgan:

js
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));

3.2 valyuta fixture'ni qanday topadi

Kanon manba.ts path'ni umuman ishlatmaydi — to'g'ridan URL quradi:

ts
export const FIXTURE = new URL("../fixtures/kurslar-2026-10-23.json", import.meta.url);

new URL(nisbiy, asos) — brauzerdagidek URL hisoblash. readFile URL obyektini ham qabul qiladi. src/manba.ts dan ham, dist/manba.js dan ham ../fixtures/ bir xil joyga tushadi. Bu usul kross-platforma: URL'da ajratgich doim /.

Tekshirib ko'ring: valyuta readFile("fixtures/kurslar-2026-10-23.json") deb yozganda nima bo'lardi?

Javob

Fayl joriy papkaga (cwd) nisbatan qidirilardi. Siz loyiha papkasida turganingizda ishlaydi, lekin foydalanuvchi valyuta ni boshqa joydan chaqirsa — ENOENT. Bunday xato faqat paket o'rnatilgandan keyin chiqadi, shuning uchun npm pack sinovi boshqa papkada qilinadi.

4. Qator oxiri: CRLF tuzog'i

4.1 Ikki xil qator oxiri

Matn faylida "yangi qator" — bitta yoki ikkita belgi:

  • \n — LF (line feed), Linux va macOS;
  • \r\n — CRLF (carriage return + line feed), Windows an'anasi.

Nomlari yozuv mashinasidan qolgan: "karetkani boshiga qaytar" (\r) va "qog'ozni bir qator sur" (\n). Node'da joriy OS odati — os.EOL (end of line). Windows'da biz ishga tushirdik:

js
import os from "node:os";
console.log(JSON.stringify(os.EOL));
text
"\r\n"

4.2 Tuzoq

Windows'da Excel yoki Bloknotda saqlangan CSV ko'pincha CRLF bilan tugaydi. split("\n") qilsangiz, har qator oxirida \r qoladi. U ko'rinmaydi, lekin solishtirishni buzadi. Bu toza JS — saytda ham ishlaydi:

js
const csv = "kod,kurs\r\nUSD,11903.15\r\nEUR,13329.15\r\n";

const notogri = csv.split("\n");
console.log(notogri[1].split(",")[1] === "11903.15");
console.log(JSON.stringify(notogri[1]));

const togri = csv.split(/\r?\n/).filter((q) => q !== "");
console.log(togri[1].split(",")[1] === "11903.15");
console.log(togri.length);

Konsolda:

text
false
"USD,11903.15\r"
true
3

/\r?\n/ — "ixtiyoriy \r va keyin \n" (regex asoslari). Ikkala formatni ham to'g'ri bo'ladi. Yozishda esa qoida oddiy: o'z fayllaringizni doim \n bilan yozing — os.EOL faqat foydalanuvchi aniq Windows formatini kutganda kerak. Git ham bu farqni avtomatik o'zgartirishi mumkin (core.autocrlf, .gitattributes da eol=lf) — shuning uchun loyihalarda .gitattributes qo'yiladi.

Yana bir ko'rinmas belgi — BOM (byte order mark, \uFEFF). Ba'zi Windows dasturlari UTF-8 faylning boshiga uni qo'yadi. JSON.parse BOM bilan boshlangan matnni qabul qilmaydi. Shubha bo'lsa — matn.replace(/^\uFEFF/, "").

Tekshirib ko'ring: Kanon format.ts CSV maydonida qaysi belgilar bo'lsa qo'shtirnoqqa oladi? Nega u yerda \r ham bor?

Javob

", ,, \n va \r (/[",\n\r]/). RFC 4180 bo'yicha qator ajratgichi bor maydon qo'shtirnoq ichida bo'lishi shart. Faqat \n tekshirilsa, \r li maydon Excel'da qatorni buzib yuborardi.

5. os moduli

5.1 Biz ishga tushirdik

os — operatsion tizim haqida ma'lumot. Natijalar mashinaga bog'liq; kanon mashinasida (Windows 11, i5-12500H) shunday chiqdi (shaxsiy qismlar … bilan almashtirildi):

js
import os from "node:os";

console.log(process.platform, os.type(), os.release(), os.arch());
console.log(os.availableParallelism(), os.cpus().length);
console.log(os.homedir());
console.log(os.tmpdir());
console.log(Math.round(os.totalmem() / 2 ** 30), "GB");
text
win32 Windows_NT 10.0.26200 x64
16 16
C:\Users\…
C:\Users\…\AppData\Local\Temp
16 GB
Funksiya Nima uchun
process.platform "win32", "darwin", "linux" — kod tarmoqlanishi uchun
os.homedir() Foydalanuvchi uy papkasi
os.tmpdir() Vaqtinchalik fayllar papkasi
os.availableParallelism() Nechta parallel ish foydali — worker'lar soni uchun
os.EOL Qator oxiri
os.totalmem(), os.freemem() Xotira (baytda)

availableParallelism() va cpus().length bu mashinada bir xil — 16. Konteynerda (Docker) yoki CPU cheklangan muhitda availableParallelism to'g'riroq javob beradi. Shuning uchun yangi kodda u tavsiya qilinadi (Node 18.14 dan bor).

process.platform Windows 64-bitda ham "win32" — tarixiy nom, "32-bit" degani emas.

5.2 os.tmpdir() va vaqtinchalik papka

Testlarda va tajribalarda o'z papkangizni yaratish uchun mkdtemp + tmpdir:

js
import { mkdtemp, rm, writeFile, readdir } from "node:fs/promises";
import os from "node:os";
import path from "node:path";

const papka = await mkdtemp(path.join(os.tmpdir(), "valyuta-test-"));
await writeFile(path.join(papka, "a.json"), "[]");
console.log(path.basename(papka).startsWith("valyuta-test-"));
console.log(await readdir(papka));
await rm(papka, { recursive: true, force: true });

Konsolda:

text
true
[ 'a.json' ]

mkdtemp prefiksga 6 ta tasodifiy belgi qo'shadi (valyuta-test-Ab12Cd). Har test o'z papkasini oladi — testlar bir-birining fayllariga tegmaydi. valyuta testlaridagi vaqtinchalikPapka() aynan shu. Ish tugagach — o'chirish.

Eslatma: atomik yozishning .tmp fayli os.tmpdir() da emas, maqsad fayl yonida bo'ladi (sababi — rename boshqa diskda atomik emas).

6. Dastur fayllari qayerda yashaydi

6.1 OS konvensiyalari

Har OS'da "dastur keshi" va "dastur sozlamasi" uchun alohida joy bor:

OS Kesh Sozlama
Windows %LOCALAPPDATA%\valyuta\Cache %APPDATA%\valyuta
macOS ~/Library/Caches/valyuta ~/Library/Preferences/valyuta
Linux $XDG_CACHE_HOME/valyuta yoki ~/.cache/valyuta $XDG_CONFIG_HOME/valyuta yoki ~/.config/valyuta

Nega kesh va sozlama alohida? Kesh — o'chirsa bo'ladigan narsa: tozalash dasturlari uni o'chiradi, zaxira nusxaga kirmaydi. Sozlama — foydalanuvchining qimmatli ma'lumoti. Windows'da APPDATA (Roaming) — tarmoq profili bilan boshqa kompyuterga ko'chadi, LOCALAPPDATA esa yo'q. Linux'dagi qoida — XDG Base Directory spetsifikatsiyasi (freedesktop.org).

6.2 joylar funksiyasi

Avval qaror yo'lini rasmda ko'ring. Yuqoridan pastga: env'dagi maxsus o'zgaruvchi hammasidan ustun, keyin platforma, keyin OS'ning o'z o'zgaruvchilari:

flowchart TD
  A{"VALYUTA_KESH berilganmi?"} -->|ha| Z["shu papka"]
  A -->|yo'q| B{"process.platform"}
  B -->|win32| C["LOCALAPPDATA yoki uy/AppData/Local"]
  B -->|darwin| D["uy/Library/Caches"]
  B -->|linux| E["XDG_CACHE_HOME yoki uy/.cache"]
  C --> F["+ valyuta/Cache"]
  D --> G["+ valyuta"]
  E --> G

Kanon src/joylar.ts — toza funksiya: platforma, muhit o'zgaruvchilari va uy papkasi parametr sifatida keladi. Shuning uchun uchala OS'ni bitta Windows kompyuterida sinash mumkin. JS ko'rinishi:

js
import path from "node:path";

function joylar(env, platforma, uy) {
  const p = platforma === "win32" ? path.win32 : path.posix;
  let kesh;
  let sozlama;
  if (platforma === "win32") {
    const local = env.LOCALAPPDATA ?? p.join(uy, "AppData", "Local");
    const roaming = env.APPDATA ?? p.join(uy, "AppData", "Roaming");
    kesh = p.join(local, "valyuta", "Cache");
    sozlama = p.join(roaming, "valyuta");
  } else if (platforma === "darwin") {
    kesh = p.join(uy, "Library", "Caches", "valyuta");
    sozlama = p.join(uy, "Library", "Preferences", "valyuta");
  } else {
    const cache = env.XDG_CACHE_HOME ?? p.join(uy, ".cache");
    kesh = p.join(cache, "valyuta");
    const config = env.XDG_CONFIG_HOME ?? p.join(uy, ".config");
    sozlama = p.join(config, "valyuta");
  }
  return {
    kesh: env.VALYUTA_KESH ?? kesh,
    sozlama: env.VALYUTA_SOZLAMA ?? sozlama,
  };
}

console.log(joylar({}, "win32", "C:\\Users\\aziz").kesh);
console.log(joylar({}, "darwin", "/Users/aziz").sozlama);
console.log(joylar({}, "linux", "/home/aziz").kesh);
console.log(joylar({ XDG_CACHE_HOME: "/x" }, "linux", "/h").kesh);
console.log(joylar({ VALYUTA_KESH: "/k" }, "linux", "/h").kesh);

Konsolda:

text
C:\Users\aziz\AppData\Local\valyuta\Cache
/Users/aziz/Library/Preferences/valyuta
/home/aziz/.cache/valyuta
/x/valyuta
/k

To'rt detal:

  1. path.win32 / path.posix platforma bo'yicha tanlanadi — Windows'da Linux yo'li \ bilan buzilmaydi.
  2. ?? — muhit o'zgaruvchisi bo'lmasa, uy papkasidan hisoblanadi (nullish operatorlar).
  3. VALYUTA_KESH / VALYUTA_SOZLAMA hammasini almashtiradi. Testlar shu bilan o'z vaqtinchalik papkasini beradi — foydalanuvchining haqiqiy keshiga tegmaydi.
  4. Linux va macOS shoxlari Windows'da sinalgan, lekin u OS'larda ishga tushirilmagan — faqat yo'l mantig'i tekshirilgan. Kanon buni ochiq yozadi.

Kanon testida (node:test) shu holatlar assert.deepEqual bilan tekshiriladi. Haqiqiy funksiya imzosi — sukut qiymatlar bilan: joylar(env = process.env, platforma = process.platform, uy = os.homedir()). Dasturda argumentsiz chaqiriladi, testda — hammasi qo'lda beriladi.

Bitta xavf: muhitdan kelgan VALYUTA_KESH ni tekshirmayapmiz. Buning zarari yo'q — foydalanuvchi o'z kompyuterida o'z keshini xohlagan joyga qo'yadi. Begona kirish (path traversal) — boshqa holat: u yerda nom tashqi manbadan keladi.

6.3 valyuta joylar

Yangi buyruq joylar qayerda nima turganini ko'rsatadi. Kanon chiqishi (holat 18):

text
$ valyuta joylar
kesh:    C:\Users\…\AppData\Local\valyuta\Cache
sozlama: C:\Users\…\AppData\Roaming\valyuta

Foydalanuvchi "sozlama faylini qayerga qo'yay?" deb so'rasa — javob shu buyruqda. Yaxshi CLI'lar shunday buyruq beradi (npm config get cache, pip cache dir).

Tekshirib ko'ring: Linux serverda XDG_CACHE_HOME=/var/cache/app o'rnatilgan. valyuta keshi qayerda bo'ladi? VALYUTA_KESH=/tmp/v ham berilsa-chi?

Javob

Birinchi holatda /var/cache/app/valyuta. Ikkinchisida /tmp/v — VALYUTA_KESH hamma qoidadan ustun, chunki return ichida env.VALYUTA_KESH ?? kesh.

7. CLI qadami: holat 18 — commit

To'rt darsning yakuni. fs: uch API shakli — sozlama.ts; fs chuqur — kesh.ts va kesh buyrug'i; xavfsiz fayl operatsiyalari — fayl.ts (atomik yozish); bugun — joylar.ts va joylar buyrug'i. cli.ts endi joylar(env) dan kesh va sozlama papkalarini oladi.

7.1 Tekshiruv

Kanon tekshiruvi (holat 18, Windows 11, Node 24.21.0):

Tekshiruv Natija
npm run build / tip / lint exit 0
npm test 18/18 (+8: joylar ×3 OS, atomik yozish, API → kesh, eski kesh, fixture, buzilgan kesh, sozlama 4 holat)
npm pack --dry-run 29 fayl, 14.7 kB
Sovuq ishga tushish --help 73 ms, kurs USD (fixture) 77 ms

Jonli o'lchov (haqiqiy CBU, kanon): birinchi valyuta kurs USD → (api), 399 ms; ikkinchisi → (kesh), 138 ms. Internet uzilgan va VALYUTA_YANGILA=1:

text
$ valyuta kurs USD
Ogohlantirish: API ishlamadi (fetch failed) — 0.0 soat oldingi kesh ishlatildi
2026-10-23 holatiga (eski-kesh)
USD    1    11 903.15   -62.36  AQSH dollari

Exit kod 0: natija bor, foydalanuvchi esa uning eski ekanini biladi.

Halol izoh: sovuq ishga tushish holat 12 dagi 122 ms dan 73 ms ga "tushdi". Bu yaxshilanish emas — mashina yuki boshqa edi. Sovuq start raqamlari ±50 ms tebranadi, ularni faqat bitta seansda solishtirish mumkin (TypeScript'ni Node'da ishga tushirish darsida toza o'lchaymiz).

7.2 Commit

bash
git add -A
git commit -m "Kesh va sozlama: OS papkalari, atomik yozish" \
  -m "Eski kesh/fixture zaxirasi, kesh buyrug'i"

Kanon commit xabari bitta qator: Kesh va sozlama: OS papkalari, atomik yozish, eski kesh/fixture zaxirasi, kesh buyrug'i. U 72 belgidan uzun, shuning uchun Git odatiga ko'ra sarlavha va tanaga bo'ldik (commit xabarlari).

Shu commitga O'z npm paketingiz darsidagi nom o'zgarishi ham kiradi: package.json da "name": "@login/valyuta". Kanonda nom valyuta qolgan — farq faqat shu qatorda. git diff --stat da package.json ko'rinsa, bu kutilgan. .tgz arxivlar esa commitga tushmaydi — .gitignore da *.tgz bor.

8. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
Linux'da kesh\kurslar.json nomli fayl \ qo'lda yozilgan path.join
Fayl topilmaydi, boshqa papkadan chaqirilganda Nisbiy yo'l cwd'ga bog'liq import.meta.dirname yoki new URL(…, import.meta.url)
"C:\valyuta" g'alati ishlaydi \v — maxsus belgi "C:\\valyuta", String.raw, path.win32.join
CSV qiymati "11903.15\r" CRLF split(/\r?\n/)
JSON.parse birinchi belgida xato BOM replace(/^\uFEFF/, "")
__dirname is not defined ESM faylda CJS o'zgaruvchisi import.meta.dirname
Kesh dastur papkasiga yozilmoqda OS konvensiyasi e'tiborsiz joylar()

9. Mashqlar

1-mashq (oson): natijani toping

  • path.posix.join("a", "b", "..", "c") →
  • path.posix.extname("kurs.tar.gz") →
  • path.win32.sep → [___:]
  • Windows'da os.EOL belgilar soni:
  • Linux'da kesh uchun muhit o'zgaruvchisi:
Yechim
  • a/c — .. b ni bekor qildi.
  • .gz — faqat oxirgi nuqtadan keyingi qism; .tar.gz ni o'zingiz aniqlaysiz.
  • \ — teskari chiziq (JS satrida "\\").
  • 2 — \r\n.
  • XDG_CACHE_HOME — bo'lmasa ~/.cache.

2-mashq (o'rta): qatorlarni normallashtirish

qatorlar(matn) funksiyasini yozing: CRLF, LF va boshidagi BOM bilan kelgan matnni qatorlar massiviga ajratsin, bo'sh qatorlarni tashlasin va har qatorni trim qilsin. Toza JS — saytda ham ishlaydi.

Yechim
js
function qatorlar(matn) {
  return matn
    .replace(/^\uFEFF/, "")
    .split(/\r?\n/)
    .map((q) => q.trim())
    .filter((q) => q !== "");
}

const windows =
  "\uFEFFkod,kurs\r\nUSD,11903.15\r\n\r\nEUR,13329.15\r\n";
const linux = "kod,kurs\nUSD,11903.15\nEUR,13329.15\n";
console.log(qatorlar(windows));
const bir = JSON.stringify(qatorlar(windows));
console.log(bir === JSON.stringify(qatorlar(linux)));

Konsolda:

text
[ 'kod,kurs', 'USD,11903.15', 'EUR,13329.15' ]
true

BOM'ni split dan oldin olib tashlash kerak — aks holda u birinchi qatorning boshida qoladi va "kod" sarlavhasi "\uFEFFkod" bo'lib, ustun nomi mos kelmaydi.

3-mashq (qiyin): ikki OS uchun yo'l

keshFayli(platforma, uy, url) funksiyasini yozing: joylar dagidek kesh papkasini tanlasin (faqat Windows va Linux, env bo'sh) va unga kurslar-<kalit>.json faylini qo'shsin. <kalit> — URL'dagi sana (.../json/all/2026-10-01/ → 2026-10-01), sana bo'lmasa — oxirgi. Natija Windows uchun \, Linux uchun / bilan bo'lsin.

Yechim
js
import path from "node:path";

function keshFayli(platforma, uy, url) {
  const p = platforma === "win32" ? path.win32 : path.posix;
  const papka = platforma === "win32"
    ? p.join(uy, "AppData", "Local", "valyuta", "Cache")
    : p.join(uy, ".cache", "valyuta");
  const topildi = url.match(/\/(\d{4}-\d{2}-\d{2})\/?$/);
  const sana = topildi?.[1] ?? "oxirgi";
  return p.join(papka, `kurslar-${sana}.json`);
}

const asos = "https://cbu.uz/uz/arkhiv-kursov-valyut/json/";
console.log(keshFayli("win32", "C:\\Users\\aziz", asos));
const sanali = `${asos}all/2026-10-01/`;
console.log(keshFayli("linux", "/home/aziz", sanali));

Konsolda:

text
C:\Users\aziz\AppData\Local\valyuta\Cache\kurslar-oxirgi.json
/home/aziz/.cache/valyuta/kurslar-2026-10-01.json

Kanon kesh kalitini sanadan emas, butun URL'ning SHA-256 hash'idan oladi (kurslar-7d1a2c0f….json) — API manzili o'zgarsa ham keshlar aralashmaydi. Buni crypto 1 darsida qo'shamiz.

4-mashq: CLI qadami

src/joylar.ts ni yozing va cli.ts ga ulang, joylar buyrug'ini qo'shing. Testda VALYUTA_KESH va VALYUTA_SOZLAMA ni vaqtinchalik papkaga yo'naltiring. npm run check toza bo'lsa — holat 18 ni commit qiling («CLI qadami» bo'limidagi buyruq).

Yechim

Tekshirish ketma-ketligi: valyuta joylar → ikki qator; valyuta kesh → Kesh bo'sh (…); valyuta kurs USD (internet bilan) → (api); yana → (kesh); valyuta kesh → kurslar.json 25533 bayt … (hajm kunga qarab biroz farq qilishi mumkin). npm test 18 ta testni ko'rsatishi kerak.

10. Real ishda

  • Kross-platforma CLI'lar — npm, ESLint, Prettier, VS Code kengaytmalari: hammasi path.join va OS papkalari bilan yozilgan. env-paths (npm paketi) — joylar ning tayyor ko'rinishi; kanon uni o'rnatmadi, chunki 20 qatorlik funksiya yetarli (prod bog'liqlik 0).
  • CI — GitHub Actions'da bir xil testni Windows, macOS va Linux'da parallel yurgizish (matrix). Bunday CI'ni keyingi qismlarda sozlaymiz.
  • Docker — server ko'pincha Linux konteynerda, dasturchi esa Windows'da. CRLF va \ xatolari aynan shu yerda "mening kompyuterimda ishlaydi" muammosiga aylanadi.
  • Intervyu savoli: "path.join va path.resolve farqi nima?" — eng ko'p so'raladigan Node savollaridan biri.

Xulosa

  • Yo'l — path.join (birlashtirish) yoki path.resolve (to'liq yo'l, xavfsizlik); qo'lda / yoki \ yo'q.
  • path.win32 / path.posix — boshqa OS yo'lini istalgan kompyuterda hisoblash va sinash.
  • Skript papkasi — import.meta.dirname / new URL(…, import.meta.url); cwd — boshqa narsa.
  • CRLF (\r\n) va BOM — ko'rinmas tuzoqlar: split(/\r?\n/), BOM'ni olib tashlang, o'z fayllaringizni \n bilan yozing.
  • os.homedir, os.tmpdir, os.availableParallelism; kesh va sozlama — OS konvensiyasi bo'yicha (%LOCALAPPDATA%, ~/Library, XDG).
  • Holat 18 commit qilindi: 18 test, 29 fayl, kesh 399 → 138 ms.

Keyingi dars: util moduli — parseArgs bilan haqiqiy bayroqlar (--sana, --format), styleText bilan rang, inspect va debuglog.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Node.js path va os: Windows, Linux va macOS'da bir xil ishlaydigan kod — IlmHamroh