islamic-date-adjustment 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,325 @@
1
+ # 🕌 Islamic Date Adjustment Library
2
+
3
+ A JavaScript library for adjusting Islamic (Hijri) calendar dates based on local moon sighting, with **intelligent handling of month boundaries** and already-observed days.
4
+
5
+ Works everywhere: **React Native**, **Node.js**, **Web**, or any JavaScript environment.
6
+
7
+ ## The Problem
8
+
9
+ Islamic calendar dates are determined by moon sighting, which varies by region. When an authority announces "Ramadan starts on Feb 18," your local community might sight the moon 2 days earlier (Feb 16). Later, when Eid al-Fitr is announced, you can't simply shift the entire calendar — you've already been fasting since Feb 16!
10
+
11
+ This library solves that by:
12
+
13
+ 1. **Global offset** — shift the entire calendar uniformly (e.g., -2 days for your local sighting)
14
+ 2. **Per-event adjustment** — when a specific event (Eid, Laylat al-Qadr, etc.) is confirmed on a different date, adjust only that event forward while **preserving already-passed days**
15
+ 3. **Month-length validation** — Islamic months can only be 29 or 30 days; invalid adjustments are rejected with a clear error
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install islamic-date-adjustment
21
+ ```
22
+
23
+ ---
24
+
25
+ ## Quick Start (React Native)
26
+
27
+ ### 1. Basic usage (no persistence)
28
+
29
+ ```javascript
30
+ import { HijriYear, DEFAULT_1447_STARTS, formatDate } from 'islamic-date-adjustment';
31
+
32
+ const hy = new HijriYear(1447, DEFAULT_1447_STARTS);
33
+ hy.setGlobalOffset(-2); // Your local moon sighting
34
+
35
+ console.log(formatDate(hy.getMonthStart(9))); // "2026-02-15" (Ramadan)
36
+ console.log(formatDate(hy.getEventDate('eid_al_fitr'))); // "2026-03-17"
37
+ ```
38
+
39
+ ### 2. With the React hook
40
+
41
+ ```javascript
42
+ import { useHijriYear, DEFAULT_1447_STARTS } from 'islamic-date-adjustment';
43
+
44
+ function RamadanScreen() {
45
+ const hijri = useHijriYear({
46
+ year: 1447,
47
+ monthStarts: DEFAULT_1447_STARTS,
48
+ globalOffset: -2,
49
+ });
50
+
51
+ // Get valid date options for Eid (only 29–30 day month lengths)
52
+ const eidOptions = hijri.getValidOffsets('eid_al_fitr');
53
+
54
+ return (
55
+ <View>
56
+ <Text>Ramadan starts: {hijri.getMonthStart(9)}</Text>
57
+ <Text>Eid al-Fitr: {hijri.getEventDate('eid_al_fitr')}</Text>
58
+ <Text>Ramadan days: {hijri.getMonthDays(9)}</Text>
59
+
60
+ {eidOptions.map((opt) => (
61
+ <Button
62
+ key={opt.date}
63
+ title={`${opt.date} ${opt.label}`}
64
+ onPress={() => hijri.adjustEvent('eid_al_fitr', opt.date)}
65
+ />
66
+ ))}
67
+ </View>
68
+ );
69
+ }
70
+ ```
71
+
72
+ ### 3. With Firebase persistence
73
+
74
+ ```javascript
75
+ import firestore from '@react-native-firebase/firestore';
76
+ import { useHijriYear, DEFAULT_1447_STARTS, createFirebaseAdapter } from 'islamic-date-adjustment';
77
+
78
+ const adapter = createFirebaseAdapter(firestore());
79
+
80
+ function CalendarScreen({ userId }) {
81
+ const hijri = useHijriYear({
82
+ year: 1447,
83
+ monthStarts: DEFAULT_1447_STARTS,
84
+ globalOffset: -2,
85
+ firebaseAdapter: adapter,
86
+ userId, // saves to Firestore doc: hijri_calendars/{userId}_1447
87
+ realtime: true, // syncs across devices
88
+ });
89
+
90
+ if (hijri.loading) return <ActivityIndicator />;
91
+
92
+ return (
93
+ <View>
94
+ <Text>Ramadan: {hijri.getMonthStart(9)} – {hijri.getMonthEnd(9)}</Text>
95
+ <Text>Days fasted: {hijri.getDaysObserved(9, '2026-03-10')}</Text>
96
+
97
+ <FlatList
98
+ data={hijri.calendar}
99
+ renderItem={({ item }) => (
100
+ <Text>{item.name}: {item.adjustedStart} ({item.adjustedDays} days)</Text>
101
+ )}
102
+ />
103
+ </View>
104
+ );
105
+ }
106
+ ```
107
+
108
+ Changes are **auto-saved** to Firestore 500ms after each adjustment (debounced).
109
+
110
+ ---
111
+
112
+ ## Firebase Adapter API
113
+
114
+ ```javascript
115
+ import { createFirebaseAdapter } from 'islamic-date-adjustment';
116
+
117
+ const adapter = createFirebaseAdapter(firestoreInstance, 'collection_name');
118
+
119
+ await adapter.save(userId, hijriYear); // Save state
120
+ const hy = await adapter.load(userId, 1447); // Load state (returns HijriYear or null)
121
+ await adapter.remove(userId, 1447); // Delete saved data
122
+ const years = await adapter.listYears(userId); // List all saved years
123
+ const unsub = adapter.onSnapshot(userId, 1447, (hy) => { ... }); // Real-time listener
124
+ ```
125
+
126
+ ### Firestore document structure
127
+
128
+ ```
129
+ hijri_calendars/{userId}_{year}
130
+ ├── year: 1447
131
+ ├── globalOffset: -2
132
+ ├── monthStarts: { 1: "2025-06-26", 2: "2025-07-26", ... }
133
+ ├── adjustments: [{ eventId, targetDate, offsetDelta, ... }]
134
+ ├── userId: "user_abc"
135
+ └── updatedAt: "2026-03-18T12:00:00.000Z"
136
+ ```
137
+
138
+ ### Serialization helpers (for custom storage)
139
+
140
+ ```javascript
141
+ import { serialize, deserialize } from 'islamic-date-adjustment';
142
+
143
+ const json = serialize(hijriYear); // → plain JSON-safe object
144
+ const hy = deserialize(json); // → HijriYear instance
145
+ // Use these with AsyncStorage, MMKV, or any storage backend
146
+ ```
147
+
148
+ ---
149
+
150
+ ## useHijriYear Hook Reference
151
+
152
+ ```javascript
153
+ const hijri = useHijriYear({
154
+ year, // number — Hijri year (e.g. 1447)
155
+ monthStarts, // object — { monthIndex: "YYYY-MM-DD" }
156
+ globalOffset, // number — initial offset (default 0)
157
+ firebaseAdapter, // optional — from createFirebaseAdapter()
158
+ userId, // optional — required if firebaseAdapter is set
159
+ realtime, // optional — subscribe to real-time updates (default false)
160
+ });
161
+ ```
162
+
163
+ ### Returned object
164
+
165
+ | Property / Method | Type | Description |
166
+ |---|---|---|
167
+ | `year` | `number` | Hijri year |
168
+ | `globalOffset` | `number` | Current global offset |
169
+ | `adjustments` | `Array` | List of active adjustments |
170
+ | `calendar` | `Array` | Full 12-month calendar (reactive) |
171
+ | `loading` | `boolean` | `true` while loading from Firebase |
172
+ | `error` | `Error\|null` | Last error |
173
+ | `setGlobalOffset(days)` | `void` | Update global offset |
174
+ | `adjustEvent(eventId, date)` | `object` | Adjust event, auto-saves |
175
+ | `simulateAdjustment(eventId, date)` | `object` | Preview without changing state |
176
+ | `getValidOffsets(eventId, range?)` | `Array` | Valid date options (pre-filtered) |
177
+ | `getEventDate(eventId)` | `string` | Adjusted date as "YYYY-MM-DD" |
178
+ | `getMonthStart(index)` | `string` | Month start as "YYYY-MM-DD" |
179
+ | `getMonthEnd(index)` | `string` | Month end as "YYYY-MM-DD" |
180
+ | `getMonthDays(index)` | `number` | Days in month |
181
+ | `getUpcomingEvents(date, days?)` | `Array` | Events within N days |
182
+ | `getDaysObserved(index, date)` | `number` | Days observed in a month |
183
+ | `getHijriMonthForDate(date)` | `object` | Hijri date lookup |
184
+ | `reset()` | `void` | Reset to initial state |
185
+
186
+ ---
187
+
188
+ ## Core API (HijriYear class)
189
+
190
+ ### `new HijriYear(year, monthStarts)`
191
+
192
+ | Param | Type | Description |
193
+ | ------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------- |
194
+ | `year` | `number` | Hijri year number (e.g. 1447) |
195
+ | `monthStarts` | `Object<number, string>` | Map of Hijri month index (1-12) → Gregorian start date (`"YYYY-MM-DD"`). Missing months are auto-computed. |
196
+
197
+ ### Methods
198
+
199
+ | Method | Returns | Description |
200
+ | ---------------------------------------- | ------------------------- | ------------------------------------------------------ |
201
+ | `setGlobalOffset(days)` | `this` | Shift all months uniformly. Range: ±15 days. |
202
+ | `adjustEvent(eventId, date)` | `{ adjustment, message }` | Adjust a specific event to a Gregorian date. |
203
+ | `getValidOffsets(eventId, range?)` | `Array` | Get valid date options for an event (default ±3 days). |
204
+ | `simulateEventAdjustment(eventId, date)` | `Object` | Preview impact without changing state. |
205
+ | `getEventDate(eventId)` | `Date` | Get the adjusted Gregorian date for an event. |
206
+ | `getMonthStart(monthIndex)` | `Date` | Adjusted start date of a Hijri month. |
207
+ | `getMonthEnd(monthIndex)` | `Date` | Adjusted last day of a Hijri month. |
208
+ | `getMonthDays(monthIndex)` | `number` | Adjusted number of days in a month. |
209
+ | `getCalendar()` | `Array` | Full calendar view with all adjustments. |
210
+ | `getHijriMonthForDate(date)` | `Object` | Find which Hijri month a Gregorian date falls in. |
211
+ | `getUpcomingEvents(refDate, days?)` | `Array` | Events within N days of a reference date. |
212
+ | `getDaysObserved(monthIndex, refDate)` | `number` | Days observed in a month up to a date. |
213
+
214
+ ### Event IDs
215
+
216
+ | ID | Name | Hijri Date |
217
+ | ------------------ | ---------------- | ---------------- |
218
+ | `islamic_new_year` | Islamic New Year | 1 Muharram |
219
+ | `ashura` | Day of Ashura | 10 Muharram |
220
+ | `mawlid` | Mawlid al-Nabi | 12 Rabi al-Awwal |
221
+ | `isra_miraj` | Isra and Mi'raj | 27 Rajab |
222
+ | `shab_e_barat` | Shab-e-Barat | 15 Shaban |
223
+ | `ramadan_start` | Start of Ramadan | 1 Ramadan |
224
+ | `laylat_al_qadr` | Laylat al-Qadr | 27 Ramadan |
225
+ | `eid_al_fitr` | Eid al-Fitr | 1 Shawwal |
226
+ | `day_of_arafah` | Day of Arafah | 9 Dhul Hijjah |
227
+ | `eid_al_adha` | Eid al-Adha | 10 Dhul Hijjah |
228
+
229
+ ---
230
+
231
+ ## How Adjustments Work
232
+
233
+ ### Day-1 Events (e.g., Eid al-Fitr = 1 Shawwal)
234
+
235
+ When you move Eid al-Fitr earlier by 1 day:
236
+
237
+ - **Ramadan** (previous month) is shortened by 1 day (30 → 29)
238
+ - **Ramadan start** remains unchanged (you already fasted those days)
239
+ - **Shawwal** and all subsequent months shift accordingly
240
+
241
+ ```
242
+ Before: Ramadan (Feb 16 → Mar 17, 30 days) | Shawwal (Mar 18 →)
243
+ After: Ramadan (Feb 16 → Mar 16, 29 days) | Shawwal (Mar 17 →)
244
+ ↑ unchanged ↑ 1 day earlier
245
+ ```
246
+
247
+ ### Month-Length Validation
248
+
249
+ Islamic months can only be **29 or 30 days**. Adjustments that would violate this are rejected:
250
+
251
+ ```javascript
252
+ const hy = new HijriYear(1447, DEFAULT_1447_STARTS);
253
+ // Ramadan is 30 days. Moving Eid 1 day later would make it 31 — REJECTED:
254
+ hy.adjustEvent('eid_al_fitr', '2026-03-20');
255
+ // throws: "Invalid adjustment: Ramadan would have 31 days, but Islamic months must be 29–30 days."
256
+ ```
257
+
258
+ `getValidOffsets()` automatically filters out invalid options, so your UI only shows dates the user can actually pick.
259
+
260
+ ### Mid-Month Events (e.g., Eid al-Adha = 10 Dhul Hijjah)
261
+
262
+ When you move Eid al-Adha earlier by 1 day:
263
+
264
+ - **Dhul Qadah** (previous month) absorbs the shift (shortened by 1)
265
+ - **Dhul Hijjah** starts 1 day earlier (so day 10 falls on the target date)
266
+ - The event's month length stays the same
267
+
268
+ ---
269
+
270
+ ## Interactive CLI
271
+
272
+ For testing and exploration, a CLI is included:
273
+
274
+ ```bash
275
+ npm start
276
+ ```
277
+
278
+ ---
279
+
280
+ ## Running Tests
281
+
282
+ ```bash
283
+ npm test
284
+ ```
285
+
286
+ 137 tests across 3 test suites covering:
287
+
288
+ - ✅ Calendar data & date helpers (30 tests)
289
+ - ✅ Adjustment engine (93 tests) — offsets, events, validation, simulation, edge cases
290
+ - ✅ Firebase adapter (14 tests) — serialize/deserialize, mock Firestore CRUD, real-time
291
+
292
+ ## Project Structure
293
+
294
+ ```
295
+ src/
296
+ islamicCalendar.js — Month definitions, event catalogue, date helpers
297
+ adjustmentEngine.js — HijriYear class with all adjustment logic
298
+ defaults.js — Default 1447 AH Gregorian start dates
299
+ firebaseAdapter.js — Firebase Firestore persistence (serialize/deserialize/CRUD)
300
+ useHijriYear.js — React/React Native hook with auto-persistence
301
+ cli.js — Interactive command-line interface
302
+ index.js — Public API entry point (re-exports everything)
303
+ tests/
304
+ islamicCalendar.test.js — 30 tests for data & helpers
305
+ adjustmentEngine.test.js — 93 tests for the engine
306
+ firebaseAdapter.test.js — 14 tests for Firebase adapter
307
+ ```
308
+
309
+ ## Imports
310
+
311
+ ```javascript
312
+ // Everything from one place
313
+ import { HijriYear, useHijriYear, createFirebaseAdapter, DEFAULT_1447_STARTS, ... } from 'islamic-date-adjustment';
314
+
315
+ // Or granular imports
316
+ import { HijriYear } from 'islamic-date-adjustment/engine';
317
+ import { useHijriYear } from 'islamic-date-adjustment/hook';
318
+ import { createFirebaseAdapter, serialize, deserialize } from 'islamic-date-adjustment/firebase';
319
+ import { DEFAULT_1447_STARTS } from 'islamic-date-adjustment/defaults';
320
+ import { ISLAMIC_MONTHS, SPECIAL_EVENTS, formatDate, parseDate } from 'islamic-date-adjustment/calendar';
321
+ ```
322
+
323
+ ## License
324
+
325
+ ISC
@@ -0,0 +1,215 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <coverage generated="1773843279368" clover="3.2.0">
3
+ <project timestamp="1773843279368" name="All files">
4
+ <metrics statements="203" coveredstatements="198" conditionals="141" coveredconditionals="118" methods="48" coveredmethods="48" elements="392" coveredelements="364" complexity="0" loc="203" ncloc="203" packages="1" files="2" classes="2"/>
5
+ <file name="adjustmentEngine.js" path="/Users/mac/Projects/IslamicDateAdjustment/src/adjustmentEngine.js">
6
+ <metrics statements="179" coveredstatements="174" conditionals="128" coveredconditionals="105" methods="36" coveredmethods="36"/>
7
+ <line num="48" count="1" type="stmt"/>
8
+ <line num="53" count="1" type="stmt"/>
9
+ <line num="54" count="1" type="stmt"/>
10
+ <line num="69" count="92" type="stmt"/>
11
+ <line num="70" count="92" type="stmt"/>
12
+ <line num="73" count="92" type="stmt"/>
13
+ <line num="76" count="1104" type="stmt"/>
14
+ <line num="84" count="92" type="stmt"/>
15
+ <line num="91" count="92" type="stmt"/>
16
+ <line num="92" count="994" type="stmt"/>
17
+ <line num="93" count="6478" type="stmt"/>
18
+ <line num="94" count="994" type="cond" truecount="1" falsecount="1"/>
19
+ <line num="98" count="92" type="stmt"/>
20
+ <line num="99" count="1012" type="stmt"/>
21
+ <line num="100" count="1012" type="stmt"/>
22
+ <line num="101" count="1012" type="cond" truecount="4" falsecount="0"/>
23
+ <line num="102" count="38" type="stmt"/>
24
+ <line num="107" count="92" type="stmt"/>
25
+ <line num="108" count="1012" type="stmt"/>
26
+ <line num="109" count="1012" type="stmt"/>
27
+ <line num="110" count="1012" type="cond" truecount="4" falsecount="0"/>
28
+ <line num="111" count="72" type="stmt"/>
29
+ <line num="116" count="92" type="stmt"/>
30
+ <line num="123" count="156" type="stmt"/>
31
+ <line num="124" count="1872" type="cond" truecount="1" falsecount="1"/>
32
+ <line num="125" count="1872" type="stmt"/>
33
+ <line num="127" count="1872" type="stmt"/>
34
+ <line num="133" count="156" type="stmt"/>
35
+ <line num="134" count="2" type="cond" truecount="1" falsecount="1"/>
36
+ <line num="135" count="0" type="stmt"/>
37
+ <line num="138" count="156" type="stmt"/>
38
+ <line num="139" count="36" type="stmt"/>
39
+ <line num="159" count="36" type="stmt"/>
40
+ <line num="161" count="351" type="stmt"/>
41
+ <line num="162" count="36" type="cond" truecount="1" falsecount="1"/>
42
+ <line num="164" count="36" type="stmt"/>
43
+ <line num="167" count="36" type="stmt"/>
44
+ <line num="168" count="36" type="stmt"/>
45
+ <line num="169" count="36" type="cond" truecount="2" falsecount="0"/>
46
+ <line num="171" count="35" type="cond" truecount="4" falsecount="0"/>
47
+ <line num="174" count="24" type="stmt"/>
48
+ <line num="175" count="24" type="stmt"/>
49
+ <line num="176" count="24" type="stmt"/>
50
+ <line num="177" count="18" type="stmt"/>
51
+ <line num="180" count="18" type="stmt"/>
52
+ <line num="181" count="18" type="stmt"/>
53
+ <line num="182" count="11" type="cond" truecount="2" falsecount="0"/>
54
+ <line num="187" count="10" type="cond" truecount="2" falsecount="0"/>
55
+ <line num="188" count="9" type="stmt"/>
56
+ <line num="189" count="9" type="stmt"/>
57
+ <line num="190" count="9" type="stmt"/>
58
+ <line num="191" count="6" type="stmt"/>
59
+ <line num="192" count="6" type="stmt"/>
60
+ <line num="195" count="1" type="stmt"/>
61
+ <line num="197" count="7" type="stmt"/>
62
+ <line num="200" count="1" type="stmt"/>
63
+ <line num="201" count="1" type="stmt"/>
64
+ <line num="210" count="26" type="stmt"/>
65
+ <line num="211" count="61" type="stmt"/>
66
+ <line num="223" count="33" type="cond" truecount="4" falsecount="0"/>
67
+ <line num="224" count="9" type="stmt"/>
68
+ <line num="240" count="24" type="cond" truecount="2" falsecount="0"/>
69
+ <line num="241" count="23" type="cond" truecount="2" falsecount="0"/>
70
+ <line num="242" count="21" type="stmt"/>
71
+ <line num="243" count="21" type="stmt"/>
72
+ <line num="244" count="21" type="stmt"/>
73
+ <line num="255" count="38" type="stmt"/>
74
+ <line num="256" count="38" type="cond" truecount="2" falsecount="0"/>
75
+ <line num="258" count="37" type="stmt"/>
76
+ <line num="259" count="37" type="cond" truecount="1" falsecount="1"/>
77
+ <line num="261" count="37" type="stmt"/>
78
+ <line num="262" count="36" type="stmt"/>
79
+ <line num="264" count="36" type="cond" truecount="2" falsecount="0"/>
80
+ <line num="265" count="2" type="stmt"/>
81
+ <line num="273" count="34" type="stmt"/>
82
+ <line num="282" count="34" type="stmt"/>
83
+ <line num="285" count="34" type="stmt"/>
84
+ <line num="286" count="34" type="stmt"/>
85
+ <line num="288" count="34" type="stmt"/>
86
+ <line num="289" count="34" type="stmt"/>
87
+ <line num="292" count="9" type="stmt"/>
88
+ <line num="293" count="9" type="stmt"/>
89
+ <line num="294" count="9" type="stmt"/>
90
+ <line num="297" count="25" type="stmt"/>
91
+ <line num="308" count="6" type="stmt"/>
92
+ <line num="309" count="6" type="cond" truecount="2" falsecount="0"/>
93
+ <line num="311" count="4" type="stmt"/>
94
+ <line num="312" count="4" type="cond" truecount="1" falsecount="1"/>
95
+ <line num="315" count="40" type="stmt"/>
96
+ <line num="316" count="4" type="stmt"/>
97
+ <line num="317" count="4" type="cond" truecount="1" falsecount="1"/>
98
+ <line num="318" count="4" type="stmt"/>
99
+ <line num="321" count="4" type="stmt"/>
100
+ <line num="322" count="4" type="stmt"/>
101
+ <line num="323" count="26" type="stmt"/>
102
+ <line num="326" count="26" type="stmt"/>
103
+ <line num="327" count="26" type="cond" truecount="4" falsecount="0"/>
104
+ <line num="328" count="22" type="stmt"/>
105
+ <line num="329" count="22" type="cond" truecount="4" falsecount="0"/>
106
+ <line num="330" count="18" type="stmt"/>
107
+ <line num="334" count="26" type="stmt"/>
108
+ <line num="345" count="4" type="stmt"/>
109
+ <line num="352" count="127" type="stmt"/>
110
+ <line num="353" count="127" type="cond" truecount="2" falsecount="0"/>
111
+ <line num="355" count="1124" type="stmt"/>
112
+ <line num="356" count="126" type="cond" truecount="3" falsecount="1"/>
113
+ <line num="358" count="126" type="stmt"/>
114
+ <line num="365" count="780" type="stmt"/>
115
+ <line num="366" count="109" type="cond" truecount="2" falsecount="0"/>
116
+ <line num="373" count="228" type="stmt"/>
117
+ <line num="374" count="36" type="cond" truecount="3" falsecount="1"/>
118
+ <line num="375" count="36" type="stmt"/>
119
+ <line num="382" count="438" type="stmt"/>
120
+ <line num="383" count="58" type="cond" truecount="2" falsecount="0"/>
121
+ <line num="390" count="36" type="stmt"/>
122
+ <line num="399" count="360" type="stmt"/>
123
+ <line num="400" count="30" type="stmt"/>
124
+ <line num="413" count="5" type="stmt"/>
125
+ <line num="414" count="5" type="stmt"/>
126
+ <line num="415" count="27" type="stmt"/>
127
+ <line num="416" count="27" type="cond" truecount="4" falsecount="0"/>
128
+ <line num="417" count="4" type="stmt"/>
129
+ <line num="418" count="4" type="cond" truecount="1" falsecount="1"/>
130
+ <line num="419" count="4" type="stmt"/>
131
+ <line num="423" count="1" type="stmt"/>
132
+ <line num="430" count="4" type="stmt"/>
133
+ <line num="431" count="4" type="stmt"/>
134
+ <line num="433" count="4" type="stmt"/>
135
+ <line num="434" count="40" type="stmt"/>
136
+ <line num="435" count="40" type="cond" truecount="1" falsecount="1"/>
137
+ <line num="436" count="40" type="stmt"/>
138
+ <line num="437" count="40" type="cond" truecount="4" falsecount="0"/>
139
+ <line num="438" count="4" type="stmt"/>
140
+ <line num="446" count="4" type="stmt"/>
141
+ <line num="454" count="54" type="stmt"/>
142
+ <line num="455" count="6" type="cond" truecount="3" falsecount="1"/>
143
+ <line num="456" count="6" type="stmt"/>
144
+ <line num="457" count="6" type="stmt"/>
145
+ <line num="458" count="6" type="cond" truecount="2" falsecount="0"/>
146
+ <line num="459" count="4" type="stmt"/>
147
+ <line num="467" count="8" type="stmt"/>
148
+ <line num="468" count="8" type="cond" truecount="2" falsecount="0"/>
149
+ <line num="470" count="7" type="stmt"/>
150
+ <line num="471" count="7" type="cond" truecount="1" falsecount="1"/>
151
+ <line num="473" count="7" type="stmt"/>
152
+ <line num="474" count="7" type="stmt"/>
153
+ <line num="477" count="7" type="stmt"/>
154
+ <line num="487" count="7" type="cond" truecount="2" falsecount="0"/>
155
+ <line num="488" count="1" type="stmt"/>
156
+ <line num="489" count="1" type="stmt"/>
157
+ <line num="493" count="60" type="stmt"/>
158
+ <line num="496" count="6" type="stmt"/>
159
+ <line num="497" count="54" type="stmt"/>
160
+ <line num="502" count="6" type="cond" truecount="1" falsecount="1"/>
161
+ <line num="503" count="6" type="stmt"/>
162
+ <line num="504" count="6" type="stmt"/>
163
+ <line num="506" count="54" type="stmt"/>
164
+ <line num="508" count="6" type="cond" truecount="2" falsecount="0"/>
165
+ <line num="509" count="6" type="stmt"/>
166
+ <line num="518" count="6" type="stmt"/>
167
+ <line num="519" count="0" type="cond" truecount="0" falsecount="2"/>
168
+ <line num="521" count="0" type="stmt"/>
169
+ <line num="528" count="0" type="stmt"/>
170
+ <line num="530" count="0" type="stmt"/>
171
+ <line num="534" count="6" type="stmt"/>
172
+ <line num="535" count="12" type="stmt"/>
173
+ <line num="538" count="6" type="stmt"/>
174
+ <line num="544" count="25" type="cond" truecount="2" falsecount="0"/>
175
+ <line num="545" count="25" type="stmt"/>
176
+ <line num="546" count="25" type="stmt"/>
177
+ <line num="551" count="25" type="stmt"/>
178
+ <line num="552" count="25" type="cond" truecount="2" falsecount="0"/>
179
+ <line num="553" count="23" type="stmt"/>
180
+ <line num="554" count="23" type="cond" truecount="2" falsecount="0"/>
181
+ <line num="555" count="17" type="stmt"/>
182
+ <line num="559" count="6" type="stmt"/>
183
+ <line num="565" count="25" type="cond" truecount="1" falsecount="1"/>
184
+ <line num="566" count="25" type="stmt"/>
185
+ <line num="570" count="1" type="stmt"/>
186
+ </file>
187
+ <file name="islamicCalendar.js" path="/Users/mac/Projects/IslamicDateAdjustment/src/islamicCalendar.js">
188
+ <metrics statements="24" coveredstatements="24" conditionals="13" coveredconditionals="13" methods="12" coveredmethods="12"/>
189
+ <line num="16" count="2" type="stmt"/>
190
+ <line num="35" count="65" type="cond" truecount="2" falsecount="0"/>
191
+ <line num="36" count="586" type="cond" truecount="2" falsecount="0"/>
192
+ <line num="38" count="2" type="stmt"/>
193
+ <line num="39" count="2" type="stmt"/>
194
+ <line num="40" count="21" type="cond" truecount="2" falsecount="0"/>
195
+ <line num="48" count="2" type="stmt"/>
196
+ <line num="78" count="1338" type="cond" truecount="2" falsecount="0"/>
197
+ <line num="85" count="20" type="stmt"/>
198
+ <line num="96" count="1108" type="stmt"/>
199
+ <line num="97" count="1108" type="cond" truecount="5" falsecount="0"/>
200
+ <line num="98" count="1105" type="stmt"/>
201
+ <line num="105" count="350" type="stmt"/>
202
+ <line num="106" count="350" type="stmt"/>
203
+ <line num="107" count="350" type="stmt"/>
204
+ <line num="108" count="350" type="stmt"/>
205
+ <line num="115" count="2394" type="stmt"/>
206
+ <line num="116" count="2394" type="stmt"/>
207
+ <line num="117" count="2394" type="stmt"/>
208
+ <line num="124" count="172" type="stmt"/>
209
+ <line num="125" count="172" type="stmt"/>
210
+ <line num="132" count="1" type="stmt"/>
211
+ <line num="133" count="1" type="stmt"/>
212
+ <line num="136" count="2" type="stmt"/>
213
+ </file>
214
+ </project>
215
+ </coverage>