Appearance
Developer Journey
This guide explains how developers interact with the codebase, what logic runs for each public API, and how data flows through the package end to end.
1. System mental model
The package is organized in four layers:
- Date conversion: BS <-> AD conversion and formatting.
- Calendar grid: month grid generation for UI consumption.
- Panchang: precomputed lookup + live fallback computation.
- Events and classification: festivals, public holidays, and auspiciousness.
Public APIs are exported from the root package import:
ts
import {
toBS, toAD, today, formatBS,
getMonthCalendar, getMonthDays,
getPanchang, ensurePanchangYear, preloadAllPanchang,
getEventsForDate, getEventsForMonth, getAuspiciousDates, registerEvents,
isAuspicious,
} from 'nepali-calendar-engine'2. Developer setup and first interaction
- Install dependencies and build once.
- Run tests/type checks.
- Run a minimal API smoke script.
bash
pnpm install --frozen-lockfile
pnpm run build
pnpm run typecheck
pnpm run testts
import { toBS, toAD, getMonthCalendar } from 'nepali-calendar-engine'
const bs = toBS(new Date('2025-04-13'))
const ad = toAD({ year: 2082, month: 1, day: 1 })
const month = await getMonthCalendar(2082, 1)
console.log(bs)
console.log(ad.getUTCFullYear(), ad.getUTCMonth(), ad.getUTCDate())
console.log(month.days.length)3. Step-by-step logic by primary API
A) toAD(bsDate) (BS -> AD)
- Validate BS input (range and valid day for month/year).
- Use precomputed cumulative offsets:
- start-of-year offset
- start-of-month offset
- plus
(day - 1)
- Add total days to BS epoch.
- Return AD date at UTC midnight.
Complexity: O(1)
Important: Always read with getUTC* getters.
B) toBS(adDate) (AD -> BS)
- Convert AD date to UTC day index from epoch.
- Bounds-check supported range.
- Binary search year offsets to find BS year.
- Walk month offsets inside the year.
- Compute BS day and return
{ year, month, day }.
Complexity: O(log n) for year search + O(1) month walk.
C) getMonthCalendar(year, month, options?)
- Merge input options with defaults:
includeAdjacentDaysenrichPanchangenrichEvents
- If enrichment is enabled, preload panchang year.
- Compute:
- month day count
- first day weekday
- overflow days (previous and next month)
- Build each day object with:
- BS date
- AD date
- weekday labels
- optional panchang
- optional events
- optional auspicious classification
- Return stable calendar shape ready for UI.
D) getPanchang(date, options?)
- Normalize input to supported BS date.
- Resolve observer coordinates (Kathmandu default).
- Decide path:
- Fast path: precomputed year and Kathmandu coordinates -> in-memory indexed lookup.
- Fallback path: custom location or out-of-precomputed-year -> live astronomy computation.
- Return structured
PanchangInfoornullfor unsupported ranges.
E) getEventsForDate(date)
- Normalize input to BS date.
- Resolve base festival matches by rule:
- fixed BS date
- tithi-based
- fixed AD date
- Resolve government holidays for supported holiday years.
- Merge festivals and holidays with de-dup logic.
- Attach provenance metadata to each event.
- Sort by public-holiday priority and type priority.
F) isAuspicious(date) and getAuspiciousDates(...)
- Load date events and panchang.
- Apply precedence:
inauspicious_period-> inauspiciousauspicious_dateor festival -> auspicious- special tithi checks -> contextual
- otherwise neutral
- Monthly APIs aggregate the per-day result.
4. Data contracts and invariants
Date invariants
- BS months are 1-indexed (1..12).
- AD outputs are UTC midnight.
- All weekday and date logic uses UTC-safe accessors.
Panchang invariants
- Precomputed years: BS 2080-2090.
- Fallback coverage: BS 2000-2079 (live compute).
- Out-of-supported-range requests return
null.
Event invariants
- Every returned event has stable ID and type.
- Government/public holiday mirroring is merged, not duplicated.
- Provenance references are preserved for auditability.
5. Reliability and trust workflow for developers
Run this sequence before PR/release:
bash
pnpm run typecheck
pnpm run test
pnpm run validate:panchang
pnpm run legal:check
pnpm run deps:check
pnpm run trust:check
pnpm audit --prod
pnpm run docs:buildOptional deeper astronomy cross-check:
bash
pnpm run validate:cross -- --year 2082 --no-horizons6. How to safely extend logic
Add a new festival
- Add record in festival data with method/type/category metadata.
- Ensure source mapping/provenance metadata is complete.
- Add or update tests for rule matching and collisions.
- Run legal + trust checks.
Add a new public holiday year
- Add year dataset under public-holidays data.
- Update event resolution logic for that year.
- Add tests for mirrored and fixed-date holidays.
- Re-run full validation pipeline.
Extend panchang year coverage
- Generate year data.
- Validate against references.
- Refresh integrity manifest.
- Re-run trust and cross-validation checks.
7. Typical developer journeys
Journey 1: Build a calendar UI
- Call
await getMonthCalendar(year, month). - Render
daysin a 7-column grid. - Use
isCurrentMonth,isToday,events, andclassificationfor UX.
Journey 2: Daily panchang service endpoint
- Preload year at startup with
ensurePanchangYear. - Resolve
getPanchang(bsDate, locationOptions). - Return panchang plus
getEventsForDatepayload.
Journey 3: Search auspicious windows
- Call
getAuspiciousDates(year, month, purposeCategory). - Filter and rank by domain-specific preferences.
- Show provenance-aware event context in UI.
8. Practical debugging checklist
- Off-by-one AD date -> check UTC getters usage.
- Missing panchang -> confirm year is supported/preloaded.
- Missing festival -> verify method, tithi/paksha/searchMonth alignment.
- Duplicate holiday display -> inspect merged provenance references.
- Slow repeated fallback calls -> reuse location params to benefit from cache.