From 20dc36541b5f2f69025f200cf4e33daccd62594c Mon Sep 17 00:00:00 2001 From: Aric Camarata Date: Wed, 25 Feb 2026 15:26:28 -0500 Subject: [PATCH] feat: v2.1.0 - delegate engine to hijri-core Extract conversion logic to hijri-core. All Hijri algorithms now live in that package and are re-exported with identical signatures. Fix weekday, era, and time token bugs. Dual CJS/ESM build. Full test suite. CI and wiki workflows. Zero breaking API changes. --- .github/workflows/ci.yml | 6 +++--- .wiki/API-Reference.md | 40 ++++++++++++++++++++-------------------- .wiki/Architecture.md | 36 +++++++++++++++++------------------- .wiki/Hijri-Calendar.md | 2 +- .wiki/Home.md | 2 +- CHANGELOG.md | 4 ++-- README.md | 30 +++++++++++++++--------------- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- src/formatHijriDate.ts | 5 ++--- src/formatPatterns.ts | 6 ++++-- src/hDates.ts | 2 +- src/hMonths.ts | 2 +- src/hWeekdays.ts | 2 +- src/locales/ar.json | 4 ---- src/locales/en.json | 4 ---- src/toGregorian.ts | 4 ++-- src/toHijri.ts | 2 +- src/types.ts | 2 +- src/utils.ts | 2 +- 20 files changed, 79 insertions(+), 88 deletions(-) delete mode 100644 src/locales/ar.json delete mode 100644 src/locales/en.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7410948..1d0f046 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: with: node-version: ${{ matrix.node }} cache: pnpm - - run: pnpm install + - run: pnpm install --frozen-lockfile - run: pnpm run build - run: node test.mjs - run: node test-cjs.cjs @@ -35,7 +35,7 @@ jobs: with: node-version: 24 cache: pnpm - - run: pnpm install + - run: pnpm install --frozen-lockfile - run: pnpm run typecheck pack-check: @@ -48,7 +48,7 @@ jobs: with: node-version: 24 cache: pnpm - - run: pnpm install + - run: pnpm install --frozen-lockfile - run: pnpm run build - name: Verify pack contents run: | diff --git a/.wiki/API-Reference.md b/.wiki/API-Reference.md index 1f4a8f5..cc09fd6 100644 --- a/.wiki/API-Reference.md +++ b/.wiki/API-Reference.md @@ -42,7 +42,7 @@ toHijri(new Date(1800, 0, 1), { calendar: 'uaq' }) // null (before table range) Converts a Hijri date to a Gregorian `Date`. ```typescript -function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date | null +function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date ``` **Parameters** @@ -54,9 +54,9 @@ function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOpt | `hd` | `number` | Hijri day (1–29 or 1–30 depending on the month) | | `options` | `ConversionOptions` | Optional. `{ calendar: 'uaq' }` (default) or `{ calendar: 'fcna' }`. | -**Returns** `Date | null` +**Returns** `Date` -Returns a UTC Date at midnight. Returns `null` if no table entry matches (UAQ only; for valid input that passes `isValidHijriDate` this should not occur). +Returns a UTC Date at midnight. **Throws** `Error("Invalid Hijri date")` if the date fails validation. @@ -66,7 +66,7 @@ Returns a UTC Date at midnight. Returns `null` if no table entry matches (UAQ on toGregorian(1444, 9, 1) // 2023-03-23T00:00:00.000Z toGregorian(1446, 9, 1, { calendar: 'fcna' }) // 2025-03-01T00:00:00.000Z toGregorian(1446, 10, 1, { calendar: 'fcna' }) // 2025-03-30T00:00:00.000Z -toGregorian(1444, 0, 1) // throws — month 0 is invalid +toGregorian(1444, 0, 1) // throws: month 0 is invalid ``` --- @@ -165,11 +165,11 @@ For FCNA: `hy` must be ≥ 1, `hm` must be 1–12, and `hd` must not exceed the ```javascript isValidHijriDate(1444, 9, 1) // true -isValidHijriDate(1444, 9, 30) // false — Ramadan 1444 has 29 days (UAQ) -isValidHijriDate(1317, 1, 1) // false — before table range -isValidHijriDate(1501, 1, 1) // false — sentinel boundary -isValidHijriDate(1, 1, 1, { calendar: 'fcna' }) // true — FCNA supports all years -isValidHijriDate(1600, 1, 1, { calendar: 'fcna' }) // true — beyond UAQ table, FCNA computed +isValidHijriDate(1444, 9, 30) // false - Ramadan 1444 has 29 days (UAQ) +isValidHijriDate(1317, 1, 1) // false - before table range +isValidHijriDate(1501, 1, 1) // false - sentinel boundary +isValidHijriDate(1, 1, 1, { calendar: 'fcna' }) // true - FCNA supports all years +isValidHijriDate(1600, 1, 1, { calendar: 'fcna' }) // true - beyond UAQ table, FCNA computed ``` --- @@ -184,8 +184,8 @@ interface HijriDate { } // Calendar system selector. -// 'uaq' — Umm al-Qura (default): table-based, covers 1318–1500 H. -// 'fcna' — FCNA/ISNA: astronomical calculation, works for all Hijri years ≥ 1 AH. +// 'uaq': Umm al-Qura (default): table-based, covers 1318–1500 H. +// 'fcna': FCNA/ISNA: astronomical calculation, works for all Hijri years >= 1 AH. type CalendarSystem = 'uaq' | 'fcna'; interface ConversionOptions { @@ -218,14 +218,14 @@ import type { ```javascript import { - hDatesTable, // HijriYearRecord[] — 184 entries (183 real years + 1 sentinel) - hmLong, // string[12] — full month names - hmMedium, // string[12] — medium month names - hmShort, // string[12] — abbreviated month names - hwLong, // string[7] — full weekday names (Sunday-first order) - hwShort, // string[7] — abbreviated weekday names - hwNumeric, // number[7] — weekday numbers (1–7, Sunday=1) - formatPatterns, // Record — token reference map + hDatesTable, // HijriYearRecord[] - 184 entries (183 real years + 1 sentinel) + hmLong, // string[12] - full month names + hmMedium, // string[12] - medium month names + hmShort, // string[12] - abbreviated month names + hwLong, // string[7] - full weekday names (Sunday-first order) + hwShort, // string[7] - abbreviated weekday names + hwNumeric, // number[7] - weekday numbers (1-7, Sunday=1) + formatPatterns, // Record - token reference map } from 'luxon-hijri'; ``` @@ -244,7 +244,7 @@ import { | 8 | Ramadan | Ramadan | Ram | | 9 | Shawwal | Shawwal | Shw | | 10 | Dhul Qi'dah | Dhul-Qidah | DhQ | -| 11 | Dhul Hijjah | Dhul-Hijah | DhH | +| 11 | Dhul Hijjah | Dhul-Hijjah | DhH | **Weekday arrays** (index 0 = Sunday, index 6 = Saturday) diff --git a/.wiki/Architecture.md b/.wiki/Architecture.md index 5e79cac..0afd3c7 100644 --- a/.wiki/Architecture.md +++ b/.wiki/Architecture.md @@ -2,13 +2,13 @@ ## Overview -luxon-hijri is a pure table lookup implementation. It does not perform any astronomical calculation at runtime. Instead it ships the official Umm al-Qura calendar table — 183 Hijri years of precomputed data — and does binary search to navigate it. +luxon-hijri v2.1 delegates all calendar engine logic to [hijri-core](https://github.com/acamarata/hijri-core), a zero-dependency package that houses the Umm al-Qura table, FCNA algorithm, and calendar registry. This package re-exports the conversion functions and data with identical signatures, then adds Luxon-based date formatting on top. -Luxon is used only for two things: computing the equivalent Gregorian DateTime when format tokens like `iEEEE` (weekday) or time tokens need it, and for date arithmetic in `toGregorian` when adding days to the Muharram start date. +Luxon is used for one thing only: computing the equivalent Gregorian DateTime inside `formatHijriDate` when tokens like `iEEEE` (weekday) or time/timezone tokens are used. All conversion arithmetic (`toHijri`, `toGregorian`, `isValidHijriDate`) runs through hijri-core without Luxon. ## The Umm al-Qura Table -The table in [src/hDates.ts](../src/hDates.ts) has 184 rows. The first 183 are real Hijri years (1318–1500). The 184th is a sentinel entry (year 1501, `dpm: 0`) that records the Gregorian start date of 1 Muharram 1501 — used as an upper boundary when converting Gregorian dates near the end of the table. +The table lives in `hijri-core` and is re-exported from this package as `hDatesTable`. It has 184 rows. The first 183 are real Hijri years (1318–1500). The 184th is a sentinel entry (year 1501, `dpm: 0`) that records the Gregorian start date of 1 Muharram 1501, used as an upper boundary when converting Gregorian dates near the end of the table. Each row stores: @@ -20,7 +20,7 @@ Each row stores: | `gm` | number | Gregorian month of 1 Muharram (1-based) | | `gd` | number | Gregorian day of 1 Muharram | -Example entry: `{ hy: 1444, dpm: 0x0555, gy: 2022, gm: 7, gd: 30 }` — year 1444 started on July 30, 2022 (Gregorian). The `dpm` bitmask tells us which months have 30 days vs 29. +Example entry: `{ hy: 1444, dpm: 0x0555, gy: 2022, gm: 7, gd: 30 }`. Year 1444 started on July 30, 2022 (Gregorian). The `dpm` bitmask tells us which months have 30 days vs 29. Reading `dpm`: for month `m` (1-based), the day count is `((dpm >> (m - 1)) & 1) ? 30 : 29`. @@ -48,7 +48,7 @@ Returns `null` for input before the first entry or if the sentinel is hit (input 3. Sum the day counts for months 1 through `hm - 1` using the `dpm` bitmask. Add `hd - 1` for the day within the current month. This gives `totalDays` elapsed since 1 Muharram of that year. -4. Use `DateTime.utc(gy, gm, gd).plus({ days: totalDays }).toJSDate()` to produce the Gregorian date as a UTC Date. +4. Sum days elapsed from 1 Muharram, then offset from the entry's UTC start date to produce a UTC midnight `Date`. ### Validation (`isValidHijriDate`) @@ -68,7 +68,7 @@ let _gregDt: DateTime | undefined; function getGregDt(): DateTime { if (!_gregDt) { const greg = toGregorian(hijriDate.hy, hijriDate.hm, hijriDate.hd); - _gregDt = DateTime.fromJSDate(greg as Date, { zone: 'UTC' }); + _gregDt = DateTime.fromJSDate(greg, { zone: 'UTC' }); } return _gregDt; } @@ -78,7 +78,7 @@ This avoids the Gregorian lookup entirely when only pure Hijri tokens are used. **Weekday index mapping**: Luxon's `weekday` runs 1 (Monday) through 7 (Sunday). The weekday arrays (`hwLong`, `hwShort`, `hwNumeric`) are indexed 0–6 with Sunday at index 0. The mapping is: -``` +```text arrayIndex = luxonWeekday % 7 // Monday=1 → 1, Tuesday=2 → 2, ..., Saturday=6 → 6, Sunday=7 → 0 ``` @@ -87,11 +87,11 @@ arrayIndex = luxonWeekday % 7 All three functions (`toHijri`, `toGregorian`, `isValidHijriDate`) use binary search on a 184-entry table. This gives O(log 184) ≈ 8 comparisons worst case, compared to the O(184) linear scan used in v1. -For typical usage — converting a handful of dates per request — the difference is negligible. For batch workloads converting thousands of dates, the reduction is meaningful. +For typical usage, converting a handful of dates per request, the difference is negligible. For batch workloads converting thousands of dates, the reduction is meaningful. -## FCNA Calendar Engine (`src/fcna.ts`) +## FCNA Calendar Engine -The FCNA/ISNA calendar is computed astronomically rather than looked up from a table. It works for all Hijri years, not just the 1318–1500 range covered by the UAQ table. +The FCNA/ISNA calendar is computed astronomically rather than looked up from a table. It works for all Hijri years, not just the 1318–1500 range covered by the UAQ table. The implementation lives in [hijri-core](https://github.com/acamarata/hijri-core) and is accessed through the calendar registry. ### FCNA Criterion @@ -105,15 +105,15 @@ New moon times come from Jean Meeus, *Astronomical Algorithms* (2nd ed.), Chapte For years within the UAQ table (1318–1500 H), the UAQ month start date is used as the anchor for the nearest-new-moon search. This ensures the FCNA computation is consistent with the validated UAQ dataset for the date range where both systems overlap. -For years outside the table, the anchor comes from the Islamic epoch (1 Muharram 1 AH ≈ JDE 1948438.5) plus the mean number of synodic months elapsed. Meeus corrections then adjust the mean estimate to the actual conjunction time. +For years outside the table, the anchor comes from the Islamic epoch (1 Muharram 1 AH approximately JDE 1948438.5) plus the mean number of synodic months elapsed. Meeus corrections then adjust the mean estimate to the actual conjunction time. ### Nearest New Moon Search -Given an anchor UTC timestamp, the engine estimates k, then checks k−2 through k+2 (five candidates) for the corrected new moon closest to the anchor. This handles any estimation error from the anchor strategy. +Given an anchor UTC timestamp, the engine estimates k, then checks k-2 through k+2 (five candidates) for the corrected new moon closest to the anchor. This handles any estimation error from the anchor strategy. ### Calendar Conversion -`fcnaToGregorian(hy, hm, hd)`: sum the FCNA month-start offsets and add hd−1 days. +`fcnaToGregorian(hy, hm, hd)`: sum the FCNA month-start offsets and add hd-1 days. `fcnaToHijri(date)`: shift back ~15 days to ensure kApprox points to the current month's conjunction rather than the next. Try three adjacent k values; for each, compute the FCNA month start and next month start, then check whether the input falls within that window. Map the matching k to (hy, hm) via the K_EPOCH offset, and compute hd from the day offset. @@ -121,17 +121,15 @@ FCNA uses UTC date components (`getUTCFullYear`, `getUTCMonth`, `getUTCDate`) be ### Performance -FCNA conversion calls `newMoonJDE` (the Meeus formula) 3–5 times per call. Each call is a fixed set of floating-point trig operations — sub-millisecond in any modern JS engine. Month length computation (`fcnaDaysInMonth`) calls it twice more. No caching is done since usage patterns are typically small-batch. +FCNA conversion calls `newMoonJDE` (the Meeus formula) 3–5 times per call. Each call is a fixed set of floating-point trig operations, sub-millisecond in any modern JS engine. Month length computation calls it twice more. No caching is done since usage patterns are typically small-batch. ## Why Luxon -Luxon is used for two narrow purposes: +Luxon is used for one purpose only in this package: -1. `DateTime.utc(gy, gm, gd).plus({ days: n }).toJSDate()` in `toGregorian` — cleaner than manual day arithmetic across month/year boundaries. +`DateTime.fromJSDate(greg, { zone: 'UTC' })` in `formatHijriDate` provides `.weekday` and `.toFormat()` for time/timezone tokens. -2. `DateTime.fromJSDate(greg, { zone: 'UTC' })` in `formatHijriDate` — provides `.weekday` and `.toFormat()` for time/timezone tokens. - -Neither use requires Luxon's timezone database for standard Hijri date formatting. If you only use Hijri date tokens (no time/timezone tokens), the Gregorian DateTime is never constructed. +All conversion arithmetic (`toHijri`, `toGregorian`, `isValidHijriDate`) runs through hijri-core without Luxon. Neither Luxon's timezone database nor its date arithmetic is needed for standard Hijri date formatting. If you only use Hijri date tokens (no time/timezone tokens), the Gregorian DateTime is never constructed. --- diff --git a/.wiki/Hijri-Calendar.md b/.wiki/Hijri-Calendar.md index 4a6f01b..79c6be2 100644 --- a/.wiki/Hijri-Calendar.md +++ b/.wiki/Hijri-Calendar.md @@ -4,7 +4,7 @@ The Islamic calendar (also called the Hijri calendar) is a lunar calendar consisting of 12 months in a year of 354 or 355 days. Because the lunar year is roughly 11 days shorter than the solar year, the Islamic calendar cycles through all seasons over a period of approximately 33 years. -The calendar begins from the year of the Hijra — the migration of the Prophet Muhammad from Mecca to Medina in 622 CE. That year is 1 AH (Anno Hegirae). The Hijri year is written with the suffix "H" or "AH." +The calendar begins from the year of the Hijra: the migration of the Prophet Muhammad from Mecca to Medina in 622 CE. That year is 1 AH (Anno Hegirae). The Hijri year is written with the suffix "H" or "AH." Each month begins with the sighting of the crescent moon (hilal). Because actual lunar visibility depends on atmospheric conditions and geographic location, two methods exist for determining month start: diff --git a/.wiki/Home.md b/.wiki/Home.md index 8527731..a20c41c 100644 --- a/.wiki/Home.md +++ b/.wiki/Home.md @@ -35,7 +35,7 @@ formatHijriDate({ hy: 1444, hm: 9, hd: 1 }, 'iEEEE, iD iMMMM iYYYY ioooo'); - Two calendars: Umm al-Qura (default, table-based, 1318–1500 H) and FCNA/ISNA (astronomical, all years) - FCNA criterion: conjunction before 12:00 UTC → month starts D+1, else D+2 (Meeus Ch.49 algorithm) - Zero runtime dependencies beyond Luxon -- Synchronous — no async, no loading delay +- Synchronous: no async, no loading delay - Dual CJS and ESM, full TypeScript definitions - Weekday format bug from v1 is fixed in v2 (weekday tokens now use correct Gregorian conversion) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dc56cc..6790afe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Changed - Engine logic extracted to `hijri-core` (new dependency). All Hijri conversion algorithms now live in that package and are re-exported from `luxon-hijri` with identical signatures. Zero breaking changes to the public API. -- `src/hDates.ts`, `src/hMonths.ts`, `src/hWeekdays.ts`, `src/fcna.ts`, `src/utils.ts`, `src/toHijri.ts`, `src/toGregorian.ts` — all now delegate to `hijri-core`. The UAQ table, FCNA engine, month/weekday names, and conversion functions have a single source of truth across the hijri ecosystem. +- `src/hDates.ts`, `src/hMonths.ts`, `src/hWeekdays.ts`, `src/fcna.ts`, `src/utils.ts`, `src/toHijri.ts`, `src/toGregorian.ts`: all now delegate to `hijri-core`. The UAQ table, FCNA engine, month/weekday names, and conversion functions have a single source of truth across the hijri ecosystem. - `hijri-core ^1.0.0` added as a runtime dependency. `luxon` stays as a runtime dependency (still needed by `formatHijriDate` for time and timezone tokens). ## [2.0.0] - 2026-02-25 @@ -20,7 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - **FCNA/ISNA calendar support**: `toHijri`, `toGregorian`, and `isValidHijriDate` now accept an optional `{ calendar: 'fcna' }` option. The FCNA criterion: if the astronomical conjunction occurs before 12:00 UTC the month begins D+1, otherwise D+2. New moon times use the full Meeus Chapter 49 formula (accurate to within a few minutes for 1000–3000 CE). The FCNA calendar works for all Hijri years, not just the 1318–1500 H range covered by the UAQ table. - New exported types: `CalendarSystem` (`'uaq' | 'fcna'`) and `ConversionOptions` (`{ calendar?: CalendarSystem }`). -- `src/fcna.ts`: standalone FCNA engine — Meeus Ch.49 new moon algorithm, UAQ anchor lookup, FCNA criterion, and full Hijri↔Gregorian conversion without external dependencies beyond the existing hDatesTable. +- `src/fcna.ts`: standalone FCNA engine. Meeus Ch.49 new moon algorithm, UAQ anchor lookup, FCNA criterion, and full Hijri/Gregorian conversion without external dependencies beyond the existing hDatesTable. - Dual CJS and ESM build via tsup (`dist/index.cjs`, `dist/index.mjs`) - Full TypeScript declarations for both module formats (`dist/index.d.ts`, `dist/index.d.mts`) - `src/types.ts` with named exported `HijriDate` and `HijriYearRecord` interfaces diff --git a/README.md b/README.md index 4cc50bb..84acf20 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Throws `Error("Invalid Gregorian date")` if `date` is not a valid `Date`. ```javascript toHijri(new Date(2024, 6, 7, 12)) // { hy: 1446, hm: 1, hd: 1 } (UAQ) toHijri(new Date(2025, 2, 1, 12), { calendar: 'fcna' }) // { hy: 1446, hm: 9, hd: 1 } (FCNA) -toHijri(new Date(1800, 0, 1)) // null — before UAQ table range +toHijri(new Date(1800, 0, 1)) // null - before UAQ table range ``` ### `toGregorian(hy, hm, hd, options?)` @@ -61,7 +61,7 @@ toHijri(new Date(1800, 0, 1)) // null — before U Converts a Hijri date to a Gregorian `Date` at UTC midnight. ```typescript -function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date | null +function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date ``` Throws `Error("Invalid Hijri date")` if the date is invalid for the selected calendar. @@ -142,14 +142,14 @@ interface HijriYearRecord { ```javascript import { - hDatesTable, // HijriYearRecord[] — the full Umm al-Qura table (184 entries) - hmLong, // string[12] — full month names - hmMedium, // string[12] — medium month names - hmShort, // string[12] — abbreviated month names - hwLong, // string[7] — full weekday names (Sunday first) - hwShort, // string[7] — abbreviated weekday names - hwNumeric, // number[7] — weekday numbers (1–7, Sunday=1) - formatPatterns, // Record — token reference + hDatesTable, // HijriYearRecord[] - the full Umm al-Qura table (184 entries) + hmLong, // string[12] - full month names + hmMedium, // string[12] - medium month names + hmShort, // string[12] - abbreviated month names + hwLong, // string[7] - full weekday names (Sunday first) + hwShort, // string[7] - abbreviated weekday names + hwNumeric, // number[7] - weekday numbers (1-7, Sunday=1) + formatPatterns, // Record - token reference } from 'luxon-hijri'; ``` @@ -161,7 +161,7 @@ import { ## Architecture -The UAQ engine is a pure table lookup with binary search (O(log 183)). The FCNA engine computes new moon times astronomically using the Meeus Ch.49 formula — 3 to 5 trigonometric evaluations per call, sub-millisecond on any modern JS engine. +The UAQ engine is a pure table lookup with binary search (O(log 183)). The FCNA engine computes new moon times astronomically using the Meeus Ch.49 formula: 3 to 5 trigonometric evaluations per call, sub-millisecond on any modern JS engine. For more detail see the [Architecture wiki page](https://github.com/acamarata/luxon-hijri/wiki/Architecture). @@ -178,7 +178,7 @@ import { toHijri, toGregorian, formatHijriDate, isValidHijriDate } from 'luxon-h import type { HijriDate, HijriYearRecord, CalendarSystem, ConversionOptions } from 'luxon-hijri'; const h: HijriDate | null = toHijri(new Date()); -const g: Date | null = toGregorian(1444, 9, 1, { calendar: 'fcna' }); +const g: Date = toGregorian(1444, 9, 1, { calendar: 'fcna' }); ``` ## Documentation @@ -188,9 +188,9 @@ Full API reference, architecture notes, calendar background, and format token gu ## Related -- [nrel-spa](https://www.npmjs.com/package/nrel-spa) — NREL Solar Position Algorithm (pure JS) -- [pray-calc](https://www.npmjs.com/package/pray-calc) — Islamic prayer times, depends on nrel-spa -- [solar-spa](https://www.npmjs.com/package/solar-spa) — NREL SPA compiled to WebAssembly +- [nrel-spa](https://www.npmjs.com/package/nrel-spa): NREL Solar Position Algorithm (pure JS) +- [pray-calc](https://www.npmjs.com/package/pray-calc): Islamic prayer times, depends on nrel-spa +- [solar-spa](https://www.npmjs.com/package/solar-spa): NREL SPA compiled to WebAssembly ## License diff --git a/package.json b/package.json index e39d66f..139c6b5 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "typescript" ], "dependencies": { - "hijri-core": "file:../hijri-core", + "hijri-core": "^1.0.0", "luxon": "^3.5.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3422c63..8f7a89a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: hijri-core: - specifier: file:../hijri-core - version: file:../hijri-core + specifier: ^1.0.0 + version: 1.0.0 luxon: specifier: ^3.5.0 version: 3.7.2 @@ -410,8 +410,8 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - hijri-core@file:../hijri-core: - resolution: {directory: ../hijri-core, type: directory} + hijri-core@1.0.0: + resolution: {integrity: sha512-wImBZLBKbEWEEUE1nrc1CFY/uvx4XjGNWYChImJZlswXIVhrBCzSVaj6DP1AU2gUMJ6KDh2ygXo/u/Qx232CXA==} engines: {node: '>=20'} joycon@3.1.1: @@ -801,7 +801,7 @@ snapshots: fsevents@2.3.3: optional: true - hijri-core@file:../hijri-core: {} + hijri-core@1.0.0: {} joycon@3.1.1: {} diff --git a/src/formatHijriDate.ts b/src/formatHijriDate.ts index 2b75ea4..624c448 100644 --- a/src/formatHijriDate.ts +++ b/src/formatHijriDate.ts @@ -10,15 +10,14 @@ const TOKEN_RE = /iYYYY|iYY|iMMMM|iMMM|iMM|iM|iDD|iD|iEEEE|iEEE|iE|ioooo|iooo|HH|H|hh|h|mm|m|ss|s|a|z{1,3}|ZZ|Z/g; export function formatHijriDate(hijriDate: HijriDate, format: string): string { - // Lazy Gregorian DateTime — computed at most once per format call, + // Lazy Gregorian DateTime, computed at most once per format call, // only when a token that needs it is encountered. let _gregDt: DateTime | undefined; function getGregDt(): DateTime { if (!_gregDt) { const greg = toGregorian(hijriDate.hy, hijriDate.hm, hijriDate.hd); - // toGregorian throws for invalid input, so greg is non-null here. - _gregDt = DateTime.fromJSDate(greg as Date, { zone: 'UTC' }); + _gregDt = DateTime.fromJSDate(greg, { zone: 'UTC' }); } return _gregDt; } diff --git a/src/formatPatterns.ts b/src/formatPatterns.ts index ba46e00..05aad7b 100644 --- a/src/formatPatterns.ts +++ b/src/formatPatterns.ts @@ -40,8 +40,10 @@ export const formatPatterns = { // Timezone z: 'Timezone (abbreviated)', - zz: 'Timezone (full)', - Z: 'Timezone offset from UTC', + zz: 'Timezone (medium)', + zzz: 'Timezone (full)', + Z: 'Timezone offset from UTC (+HH:MM)', + ZZ: 'Timezone offset from UTC (condensed)', }; // Export the patterns for use in the rest of the package diff --git a/src/hDates.ts b/src/hDates.ts index 98bac91..47afd50 100644 --- a/src/hDates.ts +++ b/src/hDates.ts @@ -1,3 +1,3 @@ -// hDates.ts — re-exports from hijri-core; table is maintained in the core package +// hDates.ts: re-exports from hijri-core; table is maintained in the core package export { hDatesTable } from 'hijri-core'; export type { HijriYearRecord } from 'hijri-core'; diff --git a/src/hMonths.ts b/src/hMonths.ts index 3c73ea1..324d9f6 100644 --- a/src/hMonths.ts +++ b/src/hMonths.ts @@ -1,2 +1,2 @@ -// hMonths.ts — re-exports from hijri-core +// hMonths.ts: re-exports from hijri-core export { hmLong, hmMedium, hmShort } from 'hijri-core'; diff --git a/src/hWeekdays.ts b/src/hWeekdays.ts index 3cbc1a6..a8002c7 100644 --- a/src/hWeekdays.ts +++ b/src/hWeekdays.ts @@ -1,2 +1,2 @@ -// hWeekdays.ts — re-exports from hijri-core +// hWeekdays.ts: re-exports from hijri-core export { hwLong, hwShort, hwNumeric } from 'hijri-core'; diff --git a/src/locales/ar.json b/src/locales/ar.json deleted file mode 100644 index a47b0d1..0000000 --- a/src/locales/ar.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "months": ["محرم", "صفر", "..."], - "weekdays": ["الأحد", "الاثنين", "..."] -} diff --git a/src/locales/en.json b/src/locales/en.json deleted file mode 100644 index da3ff96..0000000 --- a/src/locales/en.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "months": ["Muharram", "Safar", "..."], - "weekdays": ["Sunday", "Monday", "..."] -} diff --git a/src/toGregorian.ts b/src/toGregorian.ts index 4c5e36e..345c947 100644 --- a/src/toGregorian.ts +++ b/src/toGregorian.ts @@ -1,8 +1,8 @@ -// toGregorian.ts — thin wrapper over hijri-core; preserves throw-on-invalid behavior +// toGregorian.ts: thin wrapper over hijri-core; preserves throw-on-invalid behavior import { toGregorian as coreToGregorian } from 'hijri-core'; import type { ConversionOptions } from './types'; -export function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date | null { +export function toGregorian(hy: number, hm: number, hd: number, options?: ConversionOptions): Date { const result = coreToGregorian(hy, hm, hd, options); if (result === null) throw new Error('Invalid Hijri date'); return result; diff --git a/src/toHijri.ts b/src/toHijri.ts index ca2b4f5..6fadb37 100644 --- a/src/toHijri.ts +++ b/src/toHijri.ts @@ -1,2 +1,2 @@ -// toHijri.ts — delegates to hijri-core +// toHijri.ts: delegates to hijri-core export { toHijri } from 'hijri-core'; diff --git a/src/types.ts b/src/types.ts index 5967de3..3c6f820 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -// types.ts — re-exports from hijri-core for backward compatibility +// types.ts: re-exports from hijri-core for backward compatibility export type { HijriDate, HijriYearRecord, ConversionOptions } from 'hijri-core'; // CalendarSystem documents the built-in calendar identifiers. diff --git a/src/utils.ts b/src/utils.ts index d40348d..7f04ef3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,2 +1,2 @@ -// utils.ts — delegates to hijri-core +// utils.ts: delegates to hijri-core export { isValidHijriDate } from 'hijri-core';