Reza-kh80/zod-ir(新しいタブで開きます)
主要言語: TypeScript
Official Zod utility for Iranian data validation & metadata extraction: national code, phone number, bank card, postal code, etc.
- star 数
- 69
- watcher 数
- 1
- fork 数
- 1
- issue 数
- 0
- 最終更新
- 2026/10/29
主要言語: TypeScript
Official Zod utility for Iranian data validation & metadata extraction: national code, phone number, bank card, postal code, etc.
Validation for national code, bank cards, Sheba, bills, license plates, crypto, etc.
Lightweight • Zero Dependencies • Type-safe.
Building forms for Iranian applications often involves validating specific local data structures like national codes, bank cards, and Sheba numbers. zod-ir seamlessly integrates these validations into Zod, while also offering powerful Data Extraction tools and a superior Developer Experience.
npm install zod zod-ir # or pnpm add zod zod-ir # or yarn add zod zod-ir
You don't need to use Zod! zod-ir exports all validation logic as pure functions—perfect for backend utilities or non-form logic.
import { isMelliCode, getBankInfo, getLandlineInfo } from 'zod-ir'; // Validate national code anywhere if (isMelliCode('0023456789')) { console.log('Valid user.'); } // Extract details from bank card number const bank = getBankInfo('6219861012345678'); console.log(bank.name); // "Saman" console.log(bank.color); // "#46a0e6" // Extract location from landline phone number const location = getLandlineInfo('02122334455'); console.log(location.province_fa); // "تهران"
import * as z from 'zod'; import { zLandline, zPostalCode, getLandlineInfo, getPostalCodeInfo } from 'zod-ir'; const ValidationSchema = z.object({ phone: zLandline({ message: 'Invalid landline number.' }), zip: zPostalCode(), }); const phoneInfo = getLandlineInfo('02122334455'); console.log(phoneInfo); /* { province: "Tehran", city: "Tehran", province_fa: "تهران", city_fa: "تهران" } */ // Extract metadata from postal code (smart range matching) const zipInfo = getPostalCodeInfo('8391853612'); /* { province: { name: "اصفهان", slug: "Isfahan" }, city: { name_fa: "نائین", name_en: "Naein" } } */
zFinancial to accept both!import * as z from 'zod'; import { zFinancial, getFinancialInfo } from 'zod-ir'; const ValidationSchema = z.object({ destination: zFinancial({ message: 'Invalid card number or Sheba.' }), }); // Extract metadata (bank name, Logo, type) const info = getFinancialInfo('6037991155667788'); // OR const infoSheba = getFinancialInfo('IR120170000000123456789012'); console.log(info); /* { type: "card", // or "sheba" isValid: true, bank: { name: "Melli", label: "ملی", color: "#EF3F3E", logo: "https://.../melli.svg", formatted: "6037-9911-..." } } */
import { zCrypto, getCryptoInfo } from 'zod-ir'; const ValidationSchema = z.object({ // Accept any valid wallet (TRX, ETH, BTC) anyWallet: zCrypto(), // Strict: only accept Tether (TRC20) usdtWallet: zCrypto({ ticker: 'TRX', message: 'Only TRC20 addresses are allowed.', }), }); const details = getCryptoInfo('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'); console.log(details); /* { ticker: "TRX", network: "TRC20", isValid: true } */
import { zJalaliDate } from 'zod-ir'; const ValidationSchema = z.object({ birthDate: zJalaliDate({ message: 'Invalid date.' }), }); // ✅ Valid (Leap Year) ValidationSchema.parse({ birthDate: '1403/12/30' }); // ❌ Invalid (1402 is not a Leap Year) ValidationSchema.parse({ birthDate: '1402/12/30' });
import * as z from 'zod'; import { zMelliCode, zIranianMobile, zCardNumber, zBillId, zPaymentId, zPlateNumber, preprocessNumber, // Converts "۱۲۳" to 123 } from 'zod-ir'; const UserSchema = z.object({ // Auto-convert Persian digits before validation nationalCode: preprocessNumber(zMelliCode()), mobile: zIranianMobile({ strictZero: true }), card: zCardNumber(), plate: zPlateNumber(), // e.g., "12م345-11" // Utility Bill billId: zBillId(), paymentId: zPaymentId(), });
import { zToman, transformToCurrency, numberToText } from 'zod-ir'; const ValidationSchema = z.object({ // Accepts inputs such as "2.5 میلیون" ,"2,500,000" ,"دو میلیون و پانصد" price: zToman({ min: 1000, max: 50_000_000, message: 'Amount must be between 1,000 and 50 Million Tomans.', }), }); // --- Utility Functions for UI --- // Convert text/mixed to number (useful for database storage) console.log(transformToCurrency('2 میلیون و پانصد')); // 2500000 console.log(transformToCurrency('سی صد')); // 300 (Auto-fixes typos) // Convert number to Persian text (useful for UI display) console.log(numberToText(2500000)); // "دو میلیون و پانصد هزار"
zod-ir isn't just for validation—it also provides rich metadata for your UI.
| Function | Return Type | Description |
|---|---|---|
getFinancialInfo(val) |
{ type, bank, isValid } |
Smart! Detects card or Sheba, returns bank logo/color. |
getBankInfo(card) |
{ name, label, logo, ... } |
Details for card numbers. |
getCryptoInfo(addr) |
{ ticker, network } |
Detects TRC20, ERC20, and BTC networks. |
getMobileOperator(num) |
{ name, label, logo } |
Returns the operator (MCI, Irancell) and the Logo. |
getBillInfo(id, payId) |
{ type, amount, ... } |
Bill type (water, gas), amount calculation, validity. |
getPlateInfo(plate) |
{ province, city } |
Province and city of the license plate. |
getJalaliDateInfo(date) |
{ year, month, isLeap } |
Deconstructs Jalali date and checks for Leap Years. |
getLandlineInfo(num) |
{ province, city, ... } |
Returns province/city (FA & EN) for landlines. |
getPostalCodeInfo(code) |
{ province, city } |
Returns province/city based on the postal code. |
Identity & Contact
| Validator | Description |
|---|---|
zMelliCode |
National code (Melli code) |
zShenaseMelli |
Legal person ID (company) |
zPassport |
Iranian passport |
zIranianMobile |
Mobile number (09xx, +989xx) |
zPostalCode |
10-digit postal code |
zLandline |
Landline phone number (021xx...) |
Financial & Assets
| Validator | Description |
|---|---|
zFinancial |
Smart input (card number or Sheba) |
zCardNumber |
Bank card number (16 digits) |
zSheba |
IBAN (Sheba) |
zCrypto |
Crypto wallet (TRX, ETH, BTC) |
zBillId |
Utility bill ID |
zPaymentId |
Utility payment ID |
zPlateNumber |
Vehicle license plate |
zJalaliDate |
Persian date (YYYY/MM/DD) |
zToman |
Automatically validates the currency input |
This project adheres to The Semantic Versioning Standard.
Any form of contribution is always appreciated! Please refer to the CONTRIBUTING.md file.
Bank and operator logos are courtesy of Zegond's Logos Project.
zod-ir is an open-source project and free to use. If it saved you some time and you'd like to say thanks, you can support its development via crypto currency transactions. It's completely optional and highly appreciated!
TWtnFa4xpvH9BvciSzw4hqXUDCibWhcYxXbc1qf2ry7mpnvncwapgu0al3wkxm4jxecac3s3pmf0MIT License © 2026-PRESENT — Reza Kheradmandi