Mundarija (32)
- Bu darsda
- 1. Nega bu kerak?
- 2. path moduli asoslari
- 2.1 join: bo'laklarni birlashtirish
- 2.2 resolve: to'liq yo'l
- 2.3 Yo'lni bo'laklarga ajratish
- 2.4 sep va delimiter
- 3. Skriptning o'z papkasi
- 3.1 cwd va skript papkasi — ikki xil narsa
- 3.2 valyuta fixture'ni qanday topadi
- 4. Qator oxiri: CRLF tuzog'i
- 4.1 Ikki xil qator oxiri
- 4.2 Tuzoq
- 5. os moduli
- 5.1 Biz ishga tushirdik
- 5.2 os.tmpdir() va vaqtinchalik papka
- 6. Dastur fayllari qayerda yashaydi
- 6.1 OS konvensiyalari
- 6.2 joylar funksiyasi
- 6.3 valyuta joylar
- 7. CLI qadami: holat 18 — commit
- 7.1 Tekshiruv
- 7.2 Commit
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): natijani toping
- 2-mashq (o'rta): qatorlarni normallashtirish
- 3-mashq (qiyin): ikki OS uchun yo'l
- 4-mashq: CLI qadami
- 10. Real ishda
- Xulosa
- Manbalar
Node.js path va os: Windows, Linux va macOS'da bir xil ishlaydigan kod
Qisqacha: Yo'llarni hech qachon
+ "/" +bilan yig'mang.path.joinbo'laklarni joriy OS ajratgichi (Windows —\, Linux/macOS —/) bilan birlashtiradi va..ni hisoblaydi;path.resolveesa natijani to'liq (mutlaq) yo'lga aylantiradi. Boshqa OS'ning yo'li kerak bo'lsa —path.win32vapath.posix. Skript yonidagi fayl —import.meta.dirname. Qator oxiri Windows'da\r\n(CRLF), boshqalarida\n—split("\n")dan keyin\rqoladi. Foydalanuvchi papkalari —os.homedir(), vaqtinchalik —os.tmpdir(), kesh va sozlama esa har OS'ning o'z joyida.
Bu darsda
join,resolve,normalize,relative,parsefarqini bilasiz va to'g'risini tanlaysiz.path.win32vapath.posixbilan 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.
osmodulidan kerakli ma'lumotni olasiz:homedir,tmpdir,EOL,availableParallelism.valyutakeshi 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.
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:
kesh/2026/kurslar.json
kesh\2026\kurslar.json
/home/aziz/.cache/valyuta
../sozlamaUchinchi 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:
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:
/srv/valyuta/kesh/kurslar.json
/tmp/a.json
false true
D:\boshqaIkkinchi 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")vapath.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
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:
/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
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:
/ \
: ;
[ '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"— buC:+\v(vertikal tabulyatsiya belgisi!) +aluta. Kanon testlarini yozishda aynan shu xato chiqdi —"C:\L\valyuta"buzildi. Windows yo'lini satrda yozsangiz —\\("C:\\valyuta"),String.rawyoki eng yaxshisipath.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:
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:
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:
valyutareadFile("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:
import os from "node:os";
console.log(JSON.stringify(os.EOL));"\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:
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:
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.tsCSV maydonida qaysi belgilar bo'lsa qo'shtirnoqqa oladi? Nega u yerda\rham 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):
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");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:
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:
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 --> GKanon 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:
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:
C:\Users\aziz\AppData\Local\valyuta\Cache
/Users/aziz/Library/Preferences/valyuta
/home/aziz/.cache/valyuta
/x/valyuta
/kTo'rt detal:
path.win32/path.posixplatforma bo'yicha tanlanadi — Windows'da Linux yo'li\bilan buzilmaydi.??— muhit o'zgaruvchisi bo'lmasa, uy papkasidan hisoblanadi (nullish operatorlar).VALYUTA_KESH/VALYUTA_SOZLAMAhammasini almashtiradi. Testlar shu bilan o'z vaqtinchalik papkasini beradi — foydalanuvchining haqiqiy keshiga tegmaydi.- 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):
$ valyuta joylar
kesh: C:\Users\…\AppData\Local\valyuta\Cache
sozlama: C:\Users\…\AppData\Roaming\valyutaFoydalanuvchi "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/appo'rnatilgan.valyutakeshi qayerda bo'ladi?VALYUTA_KESH=/tmp/vham 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:
$ 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 dollariExit 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
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.EOLbelgilar soni: - Linux'da kesh uchun muhit o'zgaruvchisi:
Yechim
- a/c —
..bni bekor qildi. - .gz — faqat oxirgi nuqtadan keyingi qism;
.tar.gzni 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
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:
[ 'kod,kurs', 'USD,11903.15', 'EUR,13329.15' ]
trueBOM'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
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:
C:\Users\aziz\AppData\Local\valyuta\Cache\kurslar-oxirgi.json
/home/aziz/.cache/valyuta/kurslar-2026-10-01.jsonKanon 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.joinva OS papkalari bilan yozilgan.env-paths(npm paketi) —joylarning 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.joinvapath.resolvefarqi nima?" — eng ko'p so'raladigan Node savollaridan biri.
Xulosa
- Yo'l —
path.join(birlashtirish) yokipath.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\nbilan 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
- Node.js 24 hujjati — Path (Windows vs. POSIX,
join,resolve,relative,parse) - Node.js 24 hujjati — OS (
availableParallelism,EOL,homedir,tmpdir) - Node.js 24 hujjati —
import.meta.dirname/filename - freedesktop.org — XDG Base Directory Specification
- Microsoft — Known Folders (
LOCALAPPDATA,APPDATA)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!