@lichta/core 2.1.0 → 2.2.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/dist/index.js CHANGED
@@ -27,12 +27,41 @@ __export(index_exports, {
27
27
  getAuspiciousHours: () => getAuspiciousHours,
28
28
  getCalendarGrid: () => getCalendarGrid,
29
29
  getDayCanChi: () => getDayCanChi,
30
+ getDayElement: () => getDayElement,
31
+ getDayElementIndex: () => getDayElementIndex,
30
32
  getDayName: () => getDayName,
33
+ getElementName: () => getElementName,
34
+ getElementRelation: () => getElementRelation,
35
+ getElementRelationIndex: () => getElementRelationIndex,
36
+ getHaiBranchIndex: () => getHaiBranchIndex,
31
37
  getHourCanChi: () => getHourCanChi,
38
+ getHourElement: () => getHourElement,
39
+ getHourElementIndex: () => getHourElementIndex,
40
+ getISOWeekNumber: () => getISOWeekNumber,
41
+ getInauspiciousHourIndices: () => getInauspiciousHourIndices,
42
+ getInauspiciousHours: () => getInauspiciousHours,
32
43
  getMonthCanChi: () => getMonthCanChi,
44
+ getMonthElement: () => getMonthElement,
45
+ getMonthElementIndex: () => getMonthElementIndex,
33
46
  getMonthName: () => getMonthName,
47
+ getSolarTerm: () => getSolarTerm,
48
+ getSolarTermName: () => getSolarTermName,
49
+ getSolarTermsInYear: () => getSolarTermsInYear,
50
+ getTruc: () => getTruc,
51
+ getTrucIndex: () => getTrucIndex,
52
+ getTrucName: () => getTrucName,
53
+ getTrucQuality: () => getTrucQuality,
54
+ getTrucQualityIndex: () => getTrucQualityIndex,
55
+ getTuHanhXungGroupIndex: () => getTuHanhXungGroupIndex,
56
+ getTuHanhXungGroupMembers: () => getTuHanhXungGroupMembers,
57
+ getWeekDayLabels: () => getWeekDayLabels,
58
+ getXungBranchIndex: () => getXungBranchIndex,
34
59
  getYearDetails: () => getYearDetails,
35
60
  getZodiacAnimal: () => getZodiacAnimal,
61
+ getZodiacConflicts: () => getZodiacConflicts,
62
+ isHai: () => isHai,
63
+ isTuHanhXung: () => isTuHanhXung,
64
+ isXung: () => isXung,
36
65
  jdFromDate: () => jdFromDate,
37
66
  jdToDate: () => jdToDate,
38
67
  t: () => t
@@ -52,9 +81,6 @@ var HEAVENLY_STEMS = [
52
81
  "Nh\xE2m",
53
82
  "Qu\xFD"
54
83
  ];
55
- function getStemWeight(index) {
56
- return Math.floor(index / 2) + 1;
57
- }
58
84
 
59
85
  // src/constants/earthly-branches.ts
60
86
  var EARTHLY_BRANCHES = [
@@ -71,12 +97,8 @@ var EARTHLY_BRANCHES = [
71
97
  "Tu\u1EA5t",
72
98
  "H\u1EE3i"
73
99
  ];
74
- function getBranchWeight(index) {
75
- const normalizedIndex = index % 6;
76
- return Math.floor(normalizedIndex / 2);
77
- }
78
100
 
79
- // src/core/lunar.ts
101
+ // src/core/astronomical.ts
80
102
  var PI = Math.PI;
81
103
  function INT(d) {
82
104
  return Math.floor(d);
@@ -132,7 +154,7 @@ function NewMoon(k) {
132
154
  function getNewMoonDay(k, timeZone) {
133
155
  return INT(NewMoon(k) + 0.5 + timeZone / 24);
134
156
  }
135
- function getSunLongitude(jdn, timeZone) {
157
+ function sunLongitudeDegrees(jdn, timeZone) {
136
158
  const T = (jdn - 24515455e-1 - timeZone / 24) / 36525;
137
159
  const T2 = T * T;
138
160
  const dr = PI / 180;
@@ -142,11 +164,22 @@ function getSunLongitude(jdn, timeZone) {
142
164
  DL = DL + (0.019993 - 101e-6 * T) * Math.sin(dr * 2 * M) + 29e-5 * Math.sin(dr * 3 * M);
143
165
  let L = L0 + DL;
144
166
  L = L - 360 * INT(L / 360);
145
- return INT(L / 30);
167
+ return L;
168
+ }
169
+ function getSunLongitude(jdn, timeZone) {
170
+ return INT(sunLongitudeDegrees(jdn, timeZone) / 30);
171
+ }
172
+ function getSolarTermIndex(jdn, timeZone) {
173
+ return INT(sunLongitudeDegrees(jdn, timeZone) / 15);
174
+ }
175
+
176
+ // src/core/calendar-engine.ts
177
+ function INT2(d) {
178
+ return Math.floor(d);
146
179
  }
147
180
  function getLunarMonth11(yy, timeZone) {
148
181
  const off = jdFromDate(31, 12, yy) - 2415021076998695e-9;
149
- const k = INT(off / 29.530588853);
182
+ const k = INT2(off / 29.530588853);
150
183
  let nm = getNewMoonDay(k, timeZone);
151
184
  const sunLong = getSunLongitude(nm, timeZone);
152
185
  if (sunLong >= 9) {
@@ -155,7 +188,7 @@ function getLunarMonth11(yy, timeZone) {
155
188
  return nm;
156
189
  }
157
190
  function getLeapMonthOffset(a11, timeZone) {
158
- const k = INT((a11 - 2415021076998695e-9) / 29.530588853 + 0.5);
191
+ const k = INT2((a11 - 2415021076998695e-9) / 29.530588853 + 0.5);
159
192
  let last;
160
193
  let i = 1;
161
194
  let arc = getSunLongitude(getNewMoonDay(k + i, timeZone), timeZone);
@@ -219,7 +252,7 @@ var LichTa = class {
219
252
  throw new RangeError(`Lichta: Day must be between 1 and 31, got ${day}`);
220
253
  }
221
254
  const dayNumber = jdFromDate(day, month, year);
222
- const k = INT((dayNumber - 2415021076998695e-9) / 29.530588853);
255
+ const k = INT2((dayNumber - 2415021076998695e-9) / 29.530588853);
223
256
  let monthStart = getNewMoonDay(k + 1, timeZone);
224
257
  if (monthStart > dayNumber) {
225
258
  monthStart = getNewMoonDay(k, timeZone);
@@ -235,7 +268,7 @@ var LichTa = class {
235
268
  b11 = getLunarMonth11(year + 1, timeZone);
236
269
  }
237
270
  const lunarDay = dayNumber - monthStart + 1;
238
- const diff = INT((monthStart - a11) / 29);
271
+ const diff = INT2((monthStart - a11) / 29);
239
272
  let lunarLeap = false;
240
273
  let lunarMonth = diff + 11;
241
274
  if (b11 - a11 > 365) {
@@ -296,7 +329,7 @@ var LichTa = class {
296
329
  a11 = getLunarMonth11(lunarYear, timeZone);
297
330
  b11 = getLunarMonth11(lunarYear + 1, timeZone);
298
331
  }
299
- const k = INT(0.5 + (a11 - 2415021076998695e-9) / 29.530588853);
332
+ const k = INT2(0.5 + (a11 - 2415021076998695e-9) / 29.530588853);
300
333
  let off = lunarMonth - 11;
301
334
  if (off < 0) {
302
335
  off += 12;
@@ -320,9 +353,6 @@ var LichTa = class {
320
353
  }
321
354
  };
322
355
 
323
- // src/constants/five-elements.ts
324
- var FIVE_ELEMENTS = ["Kim", "M\u1ED9c", "Th\u1EE7y", "H\u1ECFa", "Th\u1ED5"];
325
-
326
356
  // src/constants/i18n.ts
327
357
  var translations = {
328
358
  vi: {
@@ -338,7 +368,40 @@ var translations = {
338
368
  leapLabel: "Nhu\u1EADn",
339
369
  yearLabel: "N\u0103m",
340
370
  monthLabel: "Th\xE1ng",
341
- destiny: "M\u1EC7nh"
371
+ destiny: "M\u1EC7nh",
372
+ // Thứ tự bắt đầu từ Xuân Phân (kinh độ Mặt Trời 0°), xem getSolarTermIndex trong lunar.ts
373
+ solarTermNames: [
374
+ "Xu\xE2n Ph\xE2n",
375
+ "Thanh Minh",
376
+ "C\u1ED1c V\u0169",
377
+ "L\u1EADp H\u1EA1",
378
+ "Ti\u1EC3u M\xE3n",
379
+ "Mang Ch\u1EE7ng",
380
+ "H\u1EA1 Ch\xED",
381
+ "Ti\u1EC3u Th\u1EED",
382
+ "\u0110\u1EA1i Th\u1EED",
383
+ "L\u1EADp Thu",
384
+ "X\u1EED Th\u1EED",
385
+ "B\u1EA1ch L\u1ED9",
386
+ "Thu Ph\xE2n",
387
+ "H\xE0n L\u1ED9",
388
+ "S\u01B0\u01A1ng Gi\xE1ng",
389
+ "L\u1EADp \u0110\xF4ng",
390
+ "Ti\u1EC3u Tuy\u1EBFt",
391
+ "\u0110\u1EA1i Tuy\u1EBFt",
392
+ "\u0110\xF4ng Ch\xED",
393
+ "Ti\u1EC3u H\xE0n",
394
+ "\u0110\u1EA1i H\xE0n",
395
+ "L\u1EADp Xu\xE2n",
396
+ "V\u0169 Th\u1EE7y",
397
+ "Kinh Tr\u1EADp"
398
+ ],
399
+ // Thứ tự bắt đầu từ Kiến (0), xem getTrucIndex trong feng-shui.ts
400
+ trucNames: ["Ki\u1EBFn", "Tr\u1EEB", "M\xE3n", "B\xECnh", "\u0110\u1ECBnh", "Ch\u1EA5p", "Ph\xE1", "Nguy", "Th\xE0nh", "Thu", "Khai", "B\u1EBF"],
401
+ // Thứ tự: sinh, được sinh, khắc, bị khắc, hòa — xem getElementRelationIndex trong feng-shui.ts
402
+ elementRelationNames: ["T\u01B0\u01A1ng sinh", "\u0110\u01B0\u1EE3c sinh", "T\u01B0\u01A1ng kh\u1EAFc", "B\u1ECB kh\u1EAFc", "T\u01B0\u01A1ng h\xF2a"],
403
+ // Thứ tự: xấu, trung bình, tốt — xem getTrucQualityIndex trong feng-shui.ts
404
+ trucQualityNames: ["X\u1EA5u", "Trung b\xECnh", "T\u1ED1t"]
342
405
  },
343
406
  en: {
344
407
  heavenlyStems: ["Gi\xE1p", "\u1EA4t", "B\xEDnh", "\u0110inh", "M\u1EADu", "K\u1EF7", "Canh", "T\xE2n", "Nh\xE2m", "Qu\xFD"],
@@ -353,7 +416,36 @@ var translations = {
353
416
  leapLabel: "Leap",
354
417
  yearLabel: "Year",
355
418
  monthLabel: "Month",
356
- destiny: "Destiny"
419
+ destiny: "Destiny",
420
+ solarTermNames: [
421
+ "Spring Equinox",
422
+ "Clear and Bright",
423
+ "Grain Rain",
424
+ "Start of Summer",
425
+ "Grain Full",
426
+ "Grain in Ear",
427
+ "Summer Solstice",
428
+ "Minor Heat",
429
+ "Major Heat",
430
+ "Start of Autumn",
431
+ "End of Heat",
432
+ "White Dew",
433
+ "Autumn Equinox",
434
+ "Cold Dew",
435
+ "Frost's Descent",
436
+ "Start of Winter",
437
+ "Minor Snow",
438
+ "Major Snow",
439
+ "Winter Solstice",
440
+ "Minor Cold",
441
+ "Major Cold",
442
+ "Start of Spring",
443
+ "Rain Water",
444
+ "Awakening of Insects"
445
+ ],
446
+ trucNames: ["Ki\u1EBFn", "Tr\u1EEB", "M\xE3n", "B\xECnh", "\u0110\u1ECBnh", "Ch\u1EA5p", "Ph\xE1", "Nguy", "Th\xE0nh", "Thu", "Khai", "B\u1EBF"],
447
+ elementRelationNames: ["Generates", "Generated By", "Overcomes", "Overcome By", "Same Element"],
448
+ trucQualityNames: ["Bad", "Neutral", "Good"]
357
449
  },
358
450
  ja: {
359
451
  heavenlyStems: ["\u7532", "\u4E59", "\u4E19", "\u4E01", "\u620A", "\u5DF1", "\u5E9A", "\u8F9B", "\u58EC", "\u7678"],
@@ -368,7 +460,36 @@ var translations = {
368
460
  leapLabel: "\u958F",
369
461
  yearLabel: "\u5E74",
370
462
  monthLabel: "\u6708",
371
- destiny: "\u547D"
463
+ destiny: "\u547D",
464
+ solarTermNames: [
465
+ "\u6625\u5206",
466
+ "\u6E05\u660E",
467
+ "\u7A40\u96E8",
468
+ "\u7ACB\u590F",
469
+ "\u5C0F\u6E80",
470
+ "\u8292\u7A2E",
471
+ "\u590F\u81F3",
472
+ "\u5C0F\u6691",
473
+ "\u5927\u6691",
474
+ "\u7ACB\u79CB",
475
+ "\u51E6\u6691",
476
+ "\u767D\u9732",
477
+ "\u79CB\u5206",
478
+ "\u5BD2\u9732",
479
+ "\u971C\u964D",
480
+ "\u7ACB\u51AC",
481
+ "\u5C0F\u96EA",
482
+ "\u5927\u96EA",
483
+ "\u51AC\u81F3",
484
+ "\u5C0F\u5BD2",
485
+ "\u5927\u5BD2",
486
+ "\u7ACB\u6625",
487
+ "\u96E8\u6C34",
488
+ "\u5553\u87C4"
489
+ ],
490
+ trucNames: ["\u5EFA", "\u9664", "\u6E80", "\u5E73", "\u5B9A", "\u57F7", "\u7834", "\u5371", "\u6210", "\u53CE", "\u958B", "\u9589"],
491
+ elementRelationNames: ["\u76F8\u751F", "\u88AB\u751F", "\u76F8\u514B", "\u88AB\u514B", "\u6BD4\u548C"],
492
+ trucQualityNames: ["\u51F6", "\u666E\u901A", "\u5409"]
372
493
  },
373
494
  ko: {
374
495
  heavenlyStems: ["\uAC11", "\uC744", "\uBCD1", "\uC815", "\uBB34", "\uAE30", "\uACBD", "\uC2E0", "\uC784", "\uACC4"],
@@ -383,7 +504,36 @@ var translations = {
383
504
  leapLabel: "\uC724",
384
505
  yearLabel: "\uB144",
385
506
  monthLabel: "\uC6D4",
386
- destiny: "\uBA85"
507
+ destiny: "\uBA85",
508
+ solarTermNames: [
509
+ "\uCD98\uBD84",
510
+ "\uCCAD\uBA85",
511
+ "\uACE1\uC6B0",
512
+ "\uC785\uD558",
513
+ "\uC18C\uB9CC",
514
+ "\uB9DD\uC885",
515
+ "\uD558\uC9C0",
516
+ "\uC18C\uC11C",
517
+ "\uB300\uC11C",
518
+ "\uC785\uCD94",
519
+ "\uCC98\uC11C",
520
+ "\uBC31\uB85C",
521
+ "\uCD94\uBD84",
522
+ "\uD55C\uB85C",
523
+ "\uC0C1\uAC15",
524
+ "\uC785\uB3D9",
525
+ "\uC18C\uC124",
526
+ "\uB300\uC124",
527
+ "\uB3D9\uC9C0",
528
+ "\uC18C\uD55C",
529
+ "\uB300\uD55C",
530
+ "\uC785\uCD98",
531
+ "\uC6B0\uC218",
532
+ "\uACBD\uCE69"
533
+ ],
534
+ trucNames: ["\uAC74", "\uC81C", "\uB9CC", "\uD3C9", "\uC815", "\uC9D1", "\uD30C", "\uC704", "\uC131", "\uC218", "\uAC1C", "\uD3D0"],
535
+ elementRelationNames: ["\uC0C1\uC0DD", "\uD53C\uC0DD", "\uC0C1\uADF9", "\uD53C\uADF9", "\uBE44\uD654"],
536
+ trucQualityNames: ["\uD749", "\uBCF4\uD1B5", "\uAE38"]
387
537
  }
388
538
  };
389
539
  function t(locale) {
@@ -392,28 +542,12 @@ function t(locale) {
392
542
  function getZodiacAnimal(branchIndex, locale = "vi") {
393
543
  return translations[locale].zodiacAnimals[branchIndex % 12];
394
544
  }
395
-
396
- // src/core/feng-shui.ts
397
- function mod(n, m) {
398
- return (n % m + m) % m;
399
- }
400
- function getYearDetails(year) {
401
- const stemIndex = mod(year - 4, 10);
402
- const branchIndex = mod(year - 4, 12);
403
- const stemWeight = getStemWeight(stemIndex);
404
- const branchWeight = getBranchWeight(branchIndex);
405
- let elementValue = stemWeight + branchWeight;
406
- if (elementValue > 5) {
407
- elementValue -= 5;
408
- }
409
- const elementIndex = elementValue - 1;
410
- return {
411
- can: HEAVENLY_STEMS[stemIndex],
412
- chi: EARTHLY_BRANCHES[branchIndex],
413
- menh: FIVE_ELEMENTS[elementIndex],
414
- fullString: `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]} - M\u1EC7nh ${FIVE_ELEMENTS[elementIndex]}`
415
- };
545
+ function getWeekDayLabels(locale, firstDayOfWeek = 0) {
546
+ const { weekDays } = translations[locale];
547
+ return firstDayOfWeek === 0 ? [...weekDays] : [...weekDays.slice(1), weekDays[0]];
416
548
  }
549
+
550
+ // src/core/can-chi.ts
417
551
  function getDayCanChi(jd, locale = "vi") {
418
552
  const stemIndex = (jd + 9) % 10;
419
553
  const branchIndex = (jd + 1) % 12;
@@ -436,6 +570,229 @@ function getHourCanChi(hour, dayJd, locale = "vi") {
436
570
  const { heavenlyStems, earthlyBranches } = t(locale);
437
571
  return `${heavenlyStems[hourStemIndex]} ${earthlyBranches[hourBranchIndex]}`;
438
572
  }
573
+
574
+ // src/utils/math.ts
575
+ function mod(n, m) {
576
+ return (n % m + m) % m;
577
+ }
578
+
579
+ // src/core/ngu-hanh.ts
580
+ var NAP_AM_ELEMENT_INDEX = [
581
+ 0,
582
+ 3,
583
+ 1,
584
+ 4,
585
+ 0,
586
+ 3,
587
+ 2,
588
+ 4,
589
+ 0,
590
+ 1,
591
+ 2,
592
+ 4,
593
+ 3,
594
+ 1,
595
+ 2,
596
+ 0,
597
+ 3,
598
+ 1,
599
+ 4,
600
+ 0,
601
+ 3,
602
+ 2,
603
+ 4,
604
+ 0,
605
+ 1,
606
+ 2,
607
+ 4,
608
+ 3,
609
+ 1,
610
+ 2
611
+ ];
612
+ function getSexagenaryIndex(stemIndex, branchIndex) {
613
+ for (let i = 0; i < 60; i++) {
614
+ if (i % 10 === stemIndex && i % 12 === branchIndex) {
615
+ return i;
616
+ }
617
+ }
618
+ throw new RangeError(`Lichta: Invalid Can Chi combination (stem=${stemIndex}, chi=${branchIndex})`);
619
+ }
620
+ function getNapAmElementIndex(stemIndex, branchIndex) {
621
+ const sexagenaryIndex = getSexagenaryIndex(stemIndex, branchIndex);
622
+ return NAP_AM_ELEMENT_INDEX[Math.floor(sexagenaryIndex / 2)];
623
+ }
624
+ function getElementName(index, locale = "vi") {
625
+ return t(locale).fiveElements[mod(index, 5)];
626
+ }
627
+ function getDayElementIndex(jd) {
628
+ const stemIndex = (jd + 9) % 10;
629
+ const branchIndex = (jd + 1) % 12;
630
+ return getNapAmElementIndex(stemIndex, branchIndex);
631
+ }
632
+ function getDayElement(jd, locale = "vi") {
633
+ return getElementName(getDayElementIndex(jd), locale);
634
+ }
635
+ function getMonthElementIndex(lunarMonth, lunarYear) {
636
+ const yearStemIndex = (lunarYear + 6) % 10;
637
+ const monthStemOffset = yearStemIndex % 5 * 2 + 2;
638
+ const monthStemIndex = (monthStemOffset + lunarMonth - 1) % 10;
639
+ const monthBranchIndex = (lunarMonth + 1) % 12;
640
+ return getNapAmElementIndex(monthStemIndex, monthBranchIndex);
641
+ }
642
+ function getMonthElement(lunarMonth, lunarYear, locale = "vi") {
643
+ return getElementName(getMonthElementIndex(lunarMonth, lunarYear), locale);
644
+ }
645
+ function getHourElementIndex(hour, dayJd) {
646
+ const hourBranchIndex = Math.floor((hour + 1) / 2) % 12;
647
+ const dayStemIndex = (dayJd + 9) % 10;
648
+ const hourStemOffset = dayStemIndex % 5 * 2;
649
+ const hourStemIndex = (hourStemOffset + hourBranchIndex) % 10;
650
+ return getNapAmElementIndex(hourStemIndex, hourBranchIndex);
651
+ }
652
+ function getHourElement(hour, dayJd, locale = "vi") {
653
+ return getElementName(getHourElementIndex(hour, dayJd), locale);
654
+ }
655
+ var ELEMENT_SINH_TARGET = [2, 3, 1, 4, 0];
656
+ var ELEMENT_KHAC_TARGET = [1, 4, 3, 0, 2];
657
+ function getElementRelationIndex(fromIndex, toIndex) {
658
+ const a = mod(fromIndex, 5);
659
+ const b = mod(toIndex, 5);
660
+ if (a === b) return 4;
661
+ if (ELEMENT_SINH_TARGET[a] === b) return 0;
662
+ if (ELEMENT_SINH_TARGET[b] === a) return 1;
663
+ if (ELEMENT_KHAC_TARGET[a] === b) return 2;
664
+ return 3;
665
+ }
666
+ function getElementRelation(fromIndex, toIndex, locale = "vi") {
667
+ const { elementRelationNames } = t(locale);
668
+ return elementRelationNames[getElementRelationIndex(fromIndex, toIndex)];
669
+ }
670
+
671
+ // src/core/tiet-khi.ts
672
+ function getSolarTermName(index, locale = "vi") {
673
+ const { solarTermNames } = t(locale);
674
+ return solarTermNames[(index % 24 + 24) % 24];
675
+ }
676
+ function getSolarTerm(day, month, year, timeZone = 7, locale = "vi") {
677
+ const jd = jdFromDate(day, month, year);
678
+ const index = getSolarTermIndex(jd + 1, timeZone);
679
+ return { index, name: getSolarTermName(index, locale), date: { day, month, year }, jd };
680
+ }
681
+ var occurrencesCache = /* @__PURE__ */ new Map();
682
+ function getSolarTermOccurrencesInYear(year, timeZone) {
683
+ const cacheKey = `${year}:${timeZone}`;
684
+ const cached = occurrencesCache.get(cacheKey);
685
+ if (cached) return cached;
686
+ const startJd = jdFromDate(1, 1, year) - 5;
687
+ const endJd = jdFromDate(31, 12, year) + 5;
688
+ const occurrences = [];
689
+ let prevIndex = getSolarTermIndex(startJd, timeZone);
690
+ for (let jd = startJd + 1; jd <= endJd; jd++) {
691
+ const index = getSolarTermIndex(jd, timeZone);
692
+ if (index !== prevIndex) {
693
+ const termJd = jd - 1;
694
+ const [, , jdYear] = jdToDate(termJd);
695
+ if (jdYear === year) {
696
+ occurrences.push({ index, jd: termJd });
697
+ }
698
+ prevIndex = index;
699
+ }
700
+ }
701
+ occurrencesCache.set(cacheKey, occurrences);
702
+ return occurrences;
703
+ }
704
+ function getSolarTermsInYear(year, timeZone = 7, locale = "vi") {
705
+ return getSolarTermOccurrencesInYear(year, timeZone).map(({ index, jd }) => {
706
+ const [day, month, jdYear] = jdToDate(jd);
707
+ return { index, name: getSolarTermName(index, locale), date: { day, month, year: jdYear }, jd };
708
+ });
709
+ }
710
+
711
+ // src/core/truc-zodiac.ts
712
+ var TRUC_COUNT = 12;
713
+ function getTrucIndex(jd, timeZone = 7) {
714
+ const [, , year] = jdToDate(jd);
715
+ const tietTerms = [year - 1, year, year + 1].flatMap((y) => getSolarTermOccurrencesInYear(y, timeZone)).filter((term) => term.index % 2 === 1);
716
+ let governingTietJd = -Infinity;
717
+ for (const term of tietTerms) {
718
+ if (term.jd <= jd && term.jd > governingTietJd) {
719
+ governingTietJd = term.jd;
720
+ }
721
+ }
722
+ return mod(jd - governingTietJd, TRUC_COUNT);
723
+ }
724
+ function getTrucName(index, locale = "vi") {
725
+ const { trucNames } = t(locale);
726
+ return trucNames[mod(index, TRUC_COUNT)];
727
+ }
728
+ function getTruc(jd, timeZone = 7, locale = "vi") {
729
+ return getTrucName(getTrucIndex(jd, timeZone), locale);
730
+ }
731
+ var TRUC_QUALITY_INDEX = [1, 1, 1, 1, 1, 1, 0, 0, 2, 1, 2, 1];
732
+ function getTrucQualityIndex(trucIndex) {
733
+ return TRUC_QUALITY_INDEX[mod(trucIndex, TRUC_COUNT)];
734
+ }
735
+ function getTrucQuality(trucIndex, locale = "vi") {
736
+ const { trucQualityNames } = t(locale);
737
+ return trucQualityNames[getTrucQualityIndex(trucIndex)];
738
+ }
739
+ function getXungBranchIndex(branchIndex) {
740
+ return mod(branchIndex + 6, 12);
741
+ }
742
+ function isXung(branchIndexA, branchIndexB) {
743
+ return getXungBranchIndex(mod(branchIndexA, 12)) === mod(branchIndexB, 12);
744
+ }
745
+ var HAI_BRANCH_TARGET = [7, 6, 5, 4, 3, 2, 1, 0, 11, 10, 9, 8];
746
+ function getHaiBranchIndex(branchIndex) {
747
+ return HAI_BRANCH_TARGET[mod(branchIndex, 12)];
748
+ }
749
+ function isHai(branchIndexA, branchIndexB) {
750
+ return getHaiBranchIndex(mod(branchIndexA, 12)) === mod(branchIndexB, 12);
751
+ }
752
+ var TU_HANH_XUNG_GROUP = [0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1];
753
+ var TU_HANH_XUNG_MEMBERS = [
754
+ [0, 3, 6, 9],
755
+ // Tý, Mão, Ngọ, Dậu
756
+ [2, 5, 8, 11],
757
+ // Dần, Tỵ, Thân, Hợi
758
+ [1, 4, 7, 10]
759
+ // Sửu, Thìn, Mùi, Tuất
760
+ ];
761
+ function getTuHanhXungGroupIndex(branchIndex) {
762
+ return TU_HANH_XUNG_GROUP[mod(branchIndex, 12)];
763
+ }
764
+ function getTuHanhXungGroupMembers(branchIndex) {
765
+ return [...TU_HANH_XUNG_MEMBERS[getTuHanhXungGroupIndex(branchIndex)]];
766
+ }
767
+ function isTuHanhXung(branchIndexA, branchIndexB) {
768
+ const a = mod(branchIndexA, 12);
769
+ const b = mod(branchIndexB, 12);
770
+ return a !== b && getTuHanhXungGroupIndex(a) === getTuHanhXungGroupIndex(b);
771
+ }
772
+ function getZodiacConflicts(branchIndexA, branchIndexB) {
773
+ return {
774
+ xung: isXung(branchIndexA, branchIndexB),
775
+ hai: isHai(branchIndexA, branchIndexB),
776
+ tuHanhXung: isTuHanhXung(branchIndexA, branchIndexB)
777
+ };
778
+ }
779
+
780
+ // src/constants/five-elements.ts
781
+ var FIVE_ELEMENTS = ["Kim", "M\u1ED9c", "Th\u1EE7y", "H\u1ECFa", "Th\u1ED5"];
782
+
783
+ // src/core/almanac.ts
784
+ function getYearDetails(year) {
785
+ const stemIndex = mod(year - 4, 10);
786
+ const branchIndex = mod(year - 4, 12);
787
+ const elementIndex = getNapAmElementIndex(stemIndex, branchIndex);
788
+ return {
789
+ can: HEAVENLY_STEMS[stemIndex],
790
+ chi: EARTHLY_BRANCHES[branchIndex],
791
+ menh: FIVE_ELEMENTS[elementIndex],
792
+ menhIndex: elementIndex,
793
+ fullString: `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]} - M\u1EC7nh ${FIVE_ELEMENTS[elementIndex]}`
794
+ };
795
+ }
439
796
  var AUSPICIOUS_HOURS_TABLE = [
440
797
  [0, 1, 3, 6, 7, 9],
441
798
  // Ngày Tý (0) / Ngọ (6)
@@ -462,6 +819,18 @@ function getAuspiciousHourIndices(dayJd) {
462
819
  const groupIndex = branchIndex % 6;
463
820
  return [...AUSPICIOUS_HOURS_TABLE[groupIndex]];
464
821
  }
822
+ function getInauspiciousHourIndices(dayJd) {
823
+ const auspicious = new Set(getAuspiciousHourIndices(dayJd));
824
+ const inauspicious = [];
825
+ for (let i = 0; i < 12; i++) {
826
+ if (!auspicious.has(i)) inauspicious.push(i);
827
+ }
828
+ return inauspicious;
829
+ }
830
+ function getInauspiciousHours(dayJd, locale = "vi") {
831
+ const { earthlyBranches } = t(locale);
832
+ return getInauspiciousHourIndices(dayJd).map((i) => earthlyBranches[i]);
833
+ }
465
834
 
466
835
  // src/utils/format.ts
467
836
  var MONTH_NAMES = [
@@ -545,11 +914,20 @@ function formatTraditional(lunar) {
545
914
  function dateKey(date) {
546
915
  return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
547
916
  }
548
- function getCalendarGrid(month, year, selectedDate) {
917
+ function getISOWeekNumber(date) {
918
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
919
+ const dayNum = (d.getUTCDay() + 6) % 7;
920
+ d.setUTCDate(d.getUTCDate() - dayNum + 3);
921
+ const firstThursday = new Date(Date.UTC(d.getUTCFullYear(), 0, 4));
922
+ const firstThursdayDayNum = (firstThursday.getUTCDay() + 6) % 7;
923
+ firstThursday.setUTCDate(firstThursday.getUTCDate() - firstThursdayDayNum + 3);
924
+ return 1 + Math.round((d.getTime() - firstThursday.getTime()) / 6048e5);
925
+ }
926
+ function getCalendarGrid(month, year, selectedDate, firstDayOfWeek = 0) {
549
927
  const grid = [];
550
928
  const firstDay = new Date(year, month - 1, 1);
551
929
  const lastDay = new Date(year, month, 0);
552
- const startingDayOfWeek = firstDay.getDay();
930
+ const startingDayOfWeek = (firstDay.getDay() - firstDayOfWeek + 7) % 7;
553
931
  const daysInMonth = lastDay.getDate();
554
932
  const todayKey = dateKey(/* @__PURE__ */ new Date());
555
933
  const selectedKey = selectedDate ? dateKey(selectedDate) : "";
@@ -560,7 +938,9 @@ function getCalendarGrid(month, year, selectedDate) {
560
938
  lunar: LichTa.toLunar(d, m, y),
561
939
  isToday: dateKey(solar) === todayKey,
562
940
  isSelected: dateKey(solar) === selectedKey,
563
- isCurrentMonth
941
+ isCurrentMonth,
942
+ weekNumber: 0
943
+ // gán lại theo từng hàng ở bước cuối, xem vòng lặp bên dưới
564
944
  });
565
945
  };
566
946
  for (let i = startingDayOfWeek - 1; i >= 0; i--) {
@@ -578,6 +958,13 @@ function getCalendarGrid(month, year, selectedDate) {
578
958
  const y = month + 1 > 12 ? year + 1 : year;
579
959
  pushCell(new Date(y, m - 1, d), d, m, y, false);
580
960
  }
961
+ const thursdayOffset = (4 - firstDayOfWeek + 7) % 7;
962
+ for (let row = 0; row < grid.length; row += 7) {
963
+ const weekNumber = getISOWeekNumber(grid[row + thursdayOffset].solar);
964
+ for (let i = row; i < row + 7; i++) {
965
+ grid[i].weekNumber = weekNumber;
966
+ }
967
+ }
581
968
  return grid;
582
969
  }
583
970
  // Annotate the CommonJS export names for ESM import in node:
@@ -589,12 +976,41 @@ function getCalendarGrid(month, year, selectedDate) {
589
976
  getAuspiciousHours,
590
977
  getCalendarGrid,
591
978
  getDayCanChi,
979
+ getDayElement,
980
+ getDayElementIndex,
592
981
  getDayName,
982
+ getElementName,
983
+ getElementRelation,
984
+ getElementRelationIndex,
985
+ getHaiBranchIndex,
593
986
  getHourCanChi,
987
+ getHourElement,
988
+ getHourElementIndex,
989
+ getISOWeekNumber,
990
+ getInauspiciousHourIndices,
991
+ getInauspiciousHours,
594
992
  getMonthCanChi,
993
+ getMonthElement,
994
+ getMonthElementIndex,
595
995
  getMonthName,
996
+ getSolarTerm,
997
+ getSolarTermName,
998
+ getSolarTermsInYear,
999
+ getTruc,
1000
+ getTrucIndex,
1001
+ getTrucName,
1002
+ getTrucQuality,
1003
+ getTrucQualityIndex,
1004
+ getTuHanhXungGroupIndex,
1005
+ getTuHanhXungGroupMembers,
1006
+ getWeekDayLabels,
1007
+ getXungBranchIndex,
596
1008
  getYearDetails,
597
1009
  getZodiacAnimal,
1010
+ getZodiacConflicts,
1011
+ isHai,
1012
+ isTuHanhXung,
1013
+ isXung,
598
1014
  jdFromDate,
599
1015
  jdToDate,
600
1016
  t