diff --git a/.github/workflows/wiki-sync.yml b/.github/workflows/wiki-sync.yml index b69d9a4..2bf6fa9 100644 --- a/.github/workflows/wiki-sync.yml +++ b/.github/workflows/wiki-sync.yml @@ -6,6 +6,9 @@ on: paths: - '.wiki/**' +permissions: + contents: write + jobs: sync: name: Sync .wiki/ to GitHub Wiki diff --git a/.wiki/API-Reference.md b/.wiki/API-Reference.md index 5590cb0..1b6dc09 100644 --- a/.wiki/API-Reference.md +++ b/.wiki/API-Reference.md @@ -30,7 +30,7 @@ Converts the moment to a Hijri date. **Signature:** `(options?: ConversionOptions) => HijriDate | null` -Returns `null` if the date falls outside the supported calendar range (UAQ covers AH 1356-1500, approximately CE 1937-2077). +Returns `null` if the date falls outside the supported calendar range (UAQ covers AH 1318-1500, approximately CE 1900-2076). ```javascript const h = moment(new Date(2023, 2, 23)).toHijri(); @@ -162,8 +162,8 @@ interface ConversionOptions { | Calendar ID | Description | | --- | --- | -| `uaq` | Umm al-Qura — official Saudi calendar, tabular, covers AH 1356-1500 | -| `fcna` | FCNA/ISNA — Fiqh Council of North America calculated calendar | +| `uaq` | Umm al-Qura: official Saudi calendar, tabular, covers AH 1318-1500 | +| `fcna` | FCNA/ISNA: Fiqh Council of North America calculated calendar | Custom calendars can be registered with hijri-core's `registerCalendar()`. diff --git a/.wiki/Architecture.md b/.wiki/Architecture.md index 11fc4e6..0bbe138 100644 --- a/.wiki/Architecture.md +++ b/.wiki/Architecture.md @@ -4,7 +4,7 @@ The package has one job: adapt the hijri-core API to Moment.js idioms. No calendar logic belongs here. All date arithmetic, table lookups, and validation live in hijri-core, which is tested and maintained independently. -This constraint keeps moment-hijri-plus small, maintainable, and calendar-agnostic — it benefits automatically from any calendar or correctness improvements made in hijri-core. +This constraint keeps moment-hijri-plus small, maintainable, and calendar-agnostic. It benefits automatically from any calendar or correctness improvements made in hijri-core. ## Plugin pattern @@ -15,25 +15,25 @@ import installHijri from 'moment-hijri-plus'; installHijri(moment); ``` -This approach avoids accidental double-registration, keeps the plugin stateless, and works with any moment instance — including custom ones created by `moment.utc()` or locale-scoped instances. +This approach avoids accidental double-registration, keeps the plugin stateless, and works with any moment instance, including custom ones created by `moment.utc()` or locale-scoped instances. ## Module augmentation -The TypeScript types are added to `moment.Moment` and `moment.MomentStatic` via declaration merging. This is the standard TypeScript way to extend third-party interfaces: +The TypeScript types are added to `moment.Moment` and `moment.MomentStatic` via declaration merging: ```typescript declare module 'moment' { + interface MomentStatic { + fromHijri(hy: number, hm: number, hd: number, options?: ConversionOptions): Moment; + } interface Moment { toHijri(options?: ConversionOptions): HijriDate | null; // ... } - interface MomentStatic { - fromHijri(hy: number, hm: number, hd: number, options?: ConversionOptions): Moment; - } } ``` -The augmentation is emitted in the declaration files produced by tsup, so consumers get full type inference without any extra imports. +The augmentation is emitted in the declaration files produced by tsup, so consumers get full type inference without extra imports. ## Format token system @@ -47,7 +47,7 @@ The regex is ordered longest-match-first to prevent prefix collisions: `iYYYY` must appear before `iYY` for obvious reasons; `iMMMM` before `iMMM` and `iMM`; `iDD` before `iD`; `iEEEE` before `iEEE`. The global flag allows the regex to find all non-overlapping tokens in one pass. -Moment's own bracket escaping (`[literal text]`) is preserved because it only runs during the `moment.format()` call on the residual string — any `[...]` sequences in the user's format string that don't contain Hijri tokens pass through untouched. +Moment's own bracket escaping (`[literal text]`) is preserved because it only runs during the `moment.format()` call on the residual string. Any `[...]` sequences in the user's format string that don't contain Hijri tokens pass through untouched. ## Delegation to hijri-core @@ -60,7 +60,7 @@ fromHijri() → hijri-core.toGregorian(hy, hm, hd, options) hijri-core maintains a registry of calendar engines. The default engine is `uaq` (Umm al-Qura). Callers can switch to `fcna` (FCNA/ISNA) or register custom engines via `hijri-core`'s `registerCalendar()`. -Because moment-hijri-plus uses hijri-core as a peer dependency, the registry is shared — a calendar registered in application code via `hijri-core`'s `registerCalendar()` is immediately available to this plugin. +Because moment-hijri-plus uses hijri-core as a peer dependency, the registry is shared. A calendar registered in application code via `hijri-core`'s `registerCalendar()` is immediately available to this plugin. ## Build output @@ -79,7 +79,7 @@ Both `moment` and `hijri-core` are marked external, so they are not bundled. The | Calendar | ID | Range | Authority | | --- | --- | --- | --- | -| Umm al-Qura | `uaq` | AH 1356-1500 (approx CE 1937-2077) | Official Saudi calendar | +| Umm al-Qura | `uaq` | AH 1318-1500 (approx CE 1900-2076) | Official Saudi calendar | | FCNA/ISNA | `fcna` | Calculated, no hard range | Fiqh Council of North America | The UAQ calendar is tabular: dates are looked up in a precomputed table published by the Umm al-Qura University. Dates outside the table return `null`. The FCNA calendar uses an astronomical calculation rule and has no strict boundary. diff --git a/.wiki/Home.md b/.wiki/Home.md index 08d1011..5c9c4fd 100644 --- a/.wiki/Home.md +++ b/.wiki/Home.md @@ -11,8 +11,8 @@ A Moment.js plugin for Hijri calendar conversion and formatting. All calendar ar ## Pages -- [API Reference](API-Reference) — complete method signatures and examples -- [Architecture](Architecture) — design rationale, token system, calendar delegation +- [API Reference](API-Reference): complete method signatures and examples +- [Architecture](Architecture): design rationale, token system, calendar delegation ## Quick start @@ -38,9 +38,9 @@ moment.fromHijri(1446, 1, 1).format('YYYY-MM-DD'); ## Related packages -- [hijri-core](https://github.com/acamarata/hijri-core) — the calendar engine -- [luxon-hijri](https://github.com/acamarata/luxon-hijri) — same support for Luxon -- [pray-calc](https://github.com/acamarata/pray-calc) — Islamic prayer time calculation +- [hijri-core](https://github.com/acamarata/hijri-core): the calendar engine +- [luxon-hijri](https://github.com/acamarata/luxon-hijri): same support for Luxon +- [pray-calc](https://github.com/acamarata/pray-calc): Islamic prayer time calculation --- diff --git a/README.md b/README.md index fb243b4..93c5cc6 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ interface ConversionOptions { | ID | Name | Description | | --- | --- | --- | -| `uaq` | Umm al-Qura | Official calendar of Saudi Arabia. Tabular, covers AH 1356-1500. Default. | +| `uaq` | Umm al-Qura | Official calendar of Saudi Arabia. Tabular, covers AH 1318-1500 (1900-2076 CE). Default. | | `fcna` | FCNA/ISNA | Fiqh Council of North America calculated calendar. | Pass the calendar ID via `options`: @@ -129,9 +129,9 @@ Full API reference, architecture notes, and calendar algorithm details are in th ## Related -- [hijri-core](https://github.com/acamarata/hijri-core) — zero-dependency Hijri calendar engine used by this plugin -- [luxon-hijri](https://github.com/acamarata/luxon-hijri) — same Hijri support for Luxon -- [pray-calc](https://github.com/acamarata/pray-calc) — Islamic prayer time calculation +- [hijri-core](https://github.com/acamarata/hijri-core): zero-dependency Hijri calendar engine used by this plugin +- [luxon-hijri](https://github.com/acamarata/luxon-hijri): same Hijri support for Luxon +- [pray-calc](https://github.com/acamarata/pray-calc): Islamic prayer time calculation ## License diff --git a/package.json b/package.json index 2400631..2fa3d59 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "peerDependencies": { "moment": "^2.0.0", "hijri-core": "^1.0.0" }, "devDependencies": { "@types/node": "^22.0.0", - "hijri-core": "file:../hijri-core", + "hijri-core": "^1.0.0", "moment": "^2.30.0", "tsup": "^8.0.0", "typescript": "^5.5.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ad320b8..45be19f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^22.0.0 version: 22.19.11 hijri-core: - specifier: file:../hijri-core - version: file:../hijri-core + specifier: ^1.0.0 + version: 1.0.0 moment: specifier: ^2.30.0 version: 2.30.1 @@ -403,8 +403,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: @@ -791,7 +791,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/index.ts b/src/index.ts index c91174d..ffcd2c9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import moment from 'moment'; +import type { Moment as MomentInstance } from 'moment'; import { toHijri, toGregorian, @@ -11,6 +12,15 @@ import { import type { HijriDate, ConversionOptions } from './types'; declare module 'moment' { + interface MomentStatic { + /** + * Construct a moment from a Hijri date. + * Throws if the date is invalid or outside the supported range. + * Call installHijri(moment) before use. + */ + fromHijri(hy: number, hm: number, hd: number, options?: ConversionOptions): MomentInstance; + } + interface Moment { /** * Convert this moment to a Hijri date. @@ -119,7 +129,7 @@ function install(momentInstance: typeof moment): void { // Attach fromHijri as a property on the constructor. We use a type assertion // because MomentStatic augmentation produces a DTS visibility error with some - // TypeScript configurations — attaching at runtime is equivalent and safe. + // TypeScript configurations; attaching at runtime is equivalent and safe. (momentInstance as unknown as Record).fromHijri = function ( hy: number, hm: number, @@ -142,4 +152,5 @@ function install(momentInstance: typeof moment): void { } export default install; -export type { HijriDate, ConversionOptions } from 'hijri-core'; +export type { HijriDate, ConversionOptions, CalendarEngine } from 'hijri-core'; +export { registerCalendar, getCalendar, listCalendars } from 'hijri-core'; diff --git a/test-cjs.cjs b/test-cjs.cjs index ea7ae06..abf7dcd 100644 --- a/test-cjs.cjs +++ b/test-cjs.cjs @@ -17,7 +17,7 @@ function test(name, fn) { passed++; } catch (err) { console.error(`[${name}]... FAIL: ${err.message}`); - process.exitCode = 1; + process.exit(1); } } diff --git a/test.mjs b/test.mjs index 8d40f51..627fa6d 100644 --- a/test.mjs +++ b/test.mjs @@ -15,7 +15,7 @@ function test(name, fn) { passed++; } catch (err) { console.error(`[${name}]... FAIL: ${err.message}`); - process.exitCode = 1; + process.exit(1); } }