chore: CR/QA polish for v1.0.0 release

Fix documentation style (no em dashes). Update hijri-core devDep
from file: path to ^1.0.0. Add wiki-sync workflow permissions.
Correct UAQ range to 1318-1500 AH / 1900-2076 CE throughout.
This commit is contained in:
Aric Camarata 2026-02-25 15:12:10 -05:00
parent 60690bd8c9
commit a872c5b5ed
10 changed files with 46 additions and 32 deletions

View file

@ -6,6 +6,9 @@ on:
paths:
- '.wiki/**'
permissions:
contents: write
jobs:
sync:
name: Sync .wiki/ to GitHub Wiki

View file

@ -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()`.

View file

@ -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.

View file

@ -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
---

View file

@ -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

View file

@ -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"

View file

@ -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: {}

View file

@ -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<string, unknown>).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';

View file

@ -17,7 +17,7 @@ function test(name, fn) {
passed++;
} catch (err) {
console.error(`[${name}]... FAIL: ${err.message}`);
process.exitCode = 1;
process.exit(1);
}
}

View file

@ -15,7 +15,7 @@ function test(name, fn) {
passed++;
} catch (err) {
console.error(`[${name}]... FAIL: ${err.message}`);
process.exitCode = 1;
process.exit(1);
}
}