chore: bump to v1.0.1

- Flatten exports map to ADR-015 standard
- Add coverage script (c8)
- Migrate CI to corepack enable
This commit is contained in:
Aric Camarata 2026-05-28 13:54:58 -04:00
parent e1050df823
commit c7bb2941b5
4 changed files with 85 additions and 107 deletions

View file

@ -1 +0,0 @@
CLAUDE.md

41
.claude/AGENTS.md Normal file
View file

@ -0,0 +1,41 @@
# hijri-core — PRI (Per-Repo Instructions)
**PPI:** `~/Sites/acamarata/.claude/CLAUDE.md`
## What This Is
Core Hijri calendar engine for JavaScript/TypeScript. Provides Hijri/Gregorian date conversion with a pluggable calendar registry supporting multiple calculation methods.
**npm:** `hijri-core@1.0.0`
**Language:** TypeScript
**License:** MIT
## Key Technical Details
- Zero runtime dependencies
- Pluggable engine architecture: UAQ (Umm al-Qura, 1318-1500 AH) and FCNA engines built in
- Foundation package: used by luxon-hijri, date-fns-hijri, dayjs-hijri-plus, moment-hijri-plus, temporal-hijri
- Dart counterpart: hijri-core-dart (hijri_core@1.0.0 on pub.dev)
## API Surface
- `toHijri(gregorianDate, engine?)` — Gregorian to Hijri
- `toGregorian(hijriYear, hijriMonth, hijriDay, engine?)` — Hijri to Gregorian
- `registerCalendar(name, engine)` — add custom calendar engine
- `getCalendar(name)` — retrieve registered engine
- `isValidHijriDate(year, month, day, engine?)` — validation
- `daysInHijriMonth(year, month, engine?)` — month length
- Month name arrays: long/medium/short (Arabic + English)
- Weekday name arrays
## Important Notes
- This is a FOUNDATION package. Breaking changes here affect 5 downstream plugin packages.
- When making API changes: update all 5 plugin packages (luxon-hijri, date-fns-hijri, dayjs-hijri-plus, moment-hijri-plus, temporal-hijri) and bump their versions too.
- Test all 5 plugins against any hijri-core change before publishing.
## Commands
- `pnpm test` — run test.mjs + test-cjs.cjs
- `pnpm run typecheck` — tsc --noEmit
- `pnpm build` — tsup build

21
CHANGELOG.md Normal file
View file

@ -0,0 +1,21 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.0.1] - 2026-05-28
### Changed
- Flatten exports map to ADR-015 standard (import/require/types at top level)
- Add "./package.json" export condition
- Add coverage script (c8 --reporter=lcov)
- Migrate CI from pnpm/action-setup to corepack enable
## [1.0.0] - 2026-05-28
### Added
- Initial release

107
README.md
View file

@ -4,14 +4,12 @@
[![CI](https://github.com/acamarata/hijri-core/actions/workflows/ci.yml/badge.svg)](https://github.com/acamarata/hijri-core/actions/workflows/ci.yml)
[![license](https://img.shields.io/npm/l/hijri-core.svg)](LICENSE)
Zero-dependency Hijri calendar engine. Supports the Umm al-Qura (UAQ) and FCNA/ISNA calendars out of the box. Extensible via a calendar registry for custom implementations.
Zero-dependency Hijri calendar engine for JavaScript and TypeScript. Supports the Umm al-Qura (UAQ) and FCNA/ISNA calendars out of the box. A pluggable registry lets you add custom calendar implementations at runtime.
## Installation
```bash
npm install hijri-core
# or
pnpm add hijri-core
```
## Quick Start
@ -23,101 +21,22 @@ import { toHijri, toGregorian, isValidHijriDate, daysInHijriMonth } from 'hijri-
const hijri = toHijri(new Date(2025, 2, 1));
// { hy: 1446, hm: 9, hd: 1 }
// Hijri to Gregorian (UAQ)
// Hijri to Gregorian
const greg = toGregorian(1446, 9, 1);
// Date: 2025-03-01
// FCNA/ISNA calendar
const hijriFcna = toHijri(new Date('2025-03-01'), { calendar: 'fcna' });
const gregFcna = toGregorian(1446, 9, 1, { calendar: 'fcna' });
toHijri(new Date('2025-03-01'), { calendar: 'fcna' });
toGregorian(1446, 9, 1, { calendar: 'fcna' });
// Validation and month length
isValidHijriDate(1444, 9, 1); // true
daysInHijriMonth(1444, 9); // 29
daysInHijriMonth(1444, 9); // 29
```
### Custom Calendar
```typescript
import { registerCalendar, toHijri, type CalendarEngine } from 'hijri-core';
const myEngine: CalendarEngine = {
id: 'my-calendar',
toHijri: (date) => {
/* your logic */ return { hy: 1446, hm: 1, hd: 1 };
},
toGregorian: (hy, hm, hd) => {
/* your logic */ return new Date();
},
isValid: (hy, hm, hd) => hy > 0 && hm >= 1 && hm <= 12 && hd >= 1,
daysInMonth: (hy, hm) => 30,
};
registerCalendar('my-calendar', myEngine);
const result = toHijri(new Date(), { calendar: 'my-calendar' });
```
## API
### Conversion functions
| Function | Parameters | Returns | Notes |
| ------------------------------------- | -------------------------------------------- | ------------------- | ----------------------------- |
| `toHijri(date, opts?)` | `Date`, `ConversionOptions?` | `HijriDate \| null` | Throws on invalid Date |
| `toGregorian(hy, hm, hd, opts?)` | `number, number, number, ConversionOptions?` | `Date \| null` | Returns null on invalid input |
| `isValidHijriDate(hy, hm, hd, opts?)` | `number, number, number, ConversionOptions?` | `boolean` | |
| `daysInHijriMonth(hy, hm, opts?)` | `number, number, ConversionOptions?` | `number` | |
`ConversionOptions.calendar` defaults to `'uaq'`. Pass `'fcna'` or any registered calendar name.
### Registry functions
| Function | Parameters | Returns |
| -------------------------------- | ------------------------ | ---------------- |
| `registerCalendar(name, engine)` | `string, CalendarEngine` | `void` |
| `getCalendar(name)` | `string` | `CalendarEngine` |
| `listCalendars()` | none | `string[]` |
### Data exports
| Export | Type | Description |
| ------------- | ------------------- | ---------------------------------------------- |
| `hDatesTable` | `HijriYearRecord[]` | Full Umm al-Qura reference table (184 entries) |
| `hmLong` | `string[]` | Long month names (e.g., "Ramadan") |
| `hmMedium` | `string[]` | Medium month names (e.g., "Ramadan") |
| `hmShort` | `string[]` | Short month names (e.g., "Ram") |
| `hwLong` | `string[]` | Long weekday names |
| `hwShort` | `string[]` | Short weekday names |
| `hwNumeric` | `number[]` | Weekday numbers (1 = Sunday) |
## Custom Calendars
Implement the `CalendarEngine` interface to add any calendar system:
```typescript
interface CalendarEngine {
readonly id: string;
toHijri(date: Date): HijriDate | null;
toGregorian(hy: number, hm: number, hd: number): Date | null;
isValid(hy: number, hm: number, hd: number): boolean;
daysInMonth(hy: number, hm: number): number;
}
```
Register with `registerCalendar('my-id', myEngine)`. Then pass `{ calendar: 'my-id' }` to any conversion function.
## Architecture
The UAQ engine performs a binary search over the 184-entry table: O(log 183) per conversion. The FCNA engine computes new moon times using the Meeus Ch. 49 algorithm (3 to 5 trigonometric evaluations per call). The registry pattern lets any consumer add custom calendar systems at runtime without modifying the core.
For more detail see the [Architecture wiki page](https://github.com/acamarata/hijri-core/wiki/Architecture).
## Compatibility
- Node.js 20, 22, 24
- Modern browsers (ESM build)
- CommonJS and ESM
Implement `CalendarEngine` and call `registerCalendar('my-id', engine)`. Pass `{ calendar: 'my-id' }` to any conversion function.
## TypeScript
@ -127,19 +46,19 @@ import type { HijriDate, HijriYearRecord, CalendarEngine, ConversionOptions } fr
## Documentation
Full API reference and architecture notes: [GitHub Wiki](https://github.com/acamarata/hijri-core/wiki)
Full API reference, architecture notes, and calendar background: [GitHub Wiki](https://github.com/acamarata/hijri-core/wiki)
## Related
- [luxon-hijri](https://github.com/acamarata/luxon-hijri) - Hijri formatting with Luxon
- [dayjs-hijri-plus](https://github.com/acamarata/dayjs-hijri-plus) - Day.js Hijri plugin
- [date-fns-hijri](https://github.com/acamarata/date-fns-hijri) - date-fns Hijri helpers
- [moment-hijri-plus](https://github.com/acamarata/moment-hijri-plus) - Moment.js Hijri plugin
- [temporal-hijri](https://github.com/acamarata/temporal-hijri) - Temporal API Hijri support
- [luxon-hijri](https://github.com/acamarata/luxon-hijri): Hijri formatting with Luxon
- [dayjs-hijri-plus](https://github.com/acamarata/dayjs-hijri-plus): Day.js Hijri plugin
- [date-fns-hijri](https://github.com/acamarata/date-fns-hijri): date-fns Hijri helpers
- [moment-hijri-plus](https://github.com/acamarata/moment-hijri-plus): Moment.js Hijri plugin
- [temporal-hijri](https://github.com/acamarata/temporal-hijri): Temporal API Hijri support
## Acknowledgments
The Umm al-Qura calendar table is derived from data published by the King Abdulaziz City for Science and Technology (KACST), Saudi Arabia. The FCNA new moon algorithm follows Jean Meeus, "Astronomical Algorithms," 2nd ed., Chapter 49.
The Umm al-Qura table is derived from data published by the King Abdulaziz City for Science and Technology (KACST). The FCNA new moon algorithm follows Jean Meeus, "Astronomical Algorithms," 2nd ed., Chapter 49.
## License

View file

@ -1,6 +1,6 @@
{
"name": "hijri-core",
"version": "1.0.0",
"version": "1.0.1",
"description": "Zero-dependency Hijri calendar engine with pluggable calendar support. Includes Umm al-Qura (UAQ) and FCNA/ISNA calendars. Extensible registry for custom calendars.",
"author": "Aric Camarata",
"license": "MIT",
@ -9,15 +9,11 @@
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.ts",
"default": "./dist/index.cjs"
}
}
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./package.json": "./package.json"
},
"sideEffects": false,
"files": [
@ -41,7 +37,8 @@
"prepublishOnly": "tsup",
"lint": "eslint .",
"format": "prettier --write .",
"format:check": "prettier --check ."
"format:check": "prettier --check .",
"coverage": "c8 --reporter=lcov --reporter=text node --test"
},
"keywords": [
"hijri",
@ -76,5 +73,6 @@
"homepage": "https://github.com/acamarata/hijri-core#readme",
"bugs": {
"url": "https://github.com/acamarata/hijri-core/issues"
}
},
"type": "module"
}