@gracefullight/saju 0.1.1 → 0.3.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.
Files changed (55) hide show
  1. package/README.en.md +314 -28
  2. package/README.md +314 -28
  3. package/dist/__tests__/four-pillars.test.js +52 -40
  4. package/dist/__tests__/luck.test.d.ts +2 -0
  5. package/dist/__tests__/luck.test.d.ts.map +1 -0
  6. package/dist/__tests__/luck.test.js +33 -0
  7. package/dist/__tests__/lunar.test.d.ts +2 -0
  8. package/dist/__tests__/lunar.test.d.ts.map +1 -0
  9. package/dist/__tests__/lunar.test.js +83 -0
  10. package/dist/__tests__/relations.test.d.ts +2 -0
  11. package/dist/__tests__/relations.test.d.ts.map +1 -0
  12. package/dist/__tests__/relations.test.js +90 -0
  13. package/dist/__tests__/saju.test.d.ts +2 -0
  14. package/dist/__tests__/saju.test.d.ts.map +1 -0
  15. package/dist/__tests__/saju.test.js +133 -0
  16. package/dist/__tests__/solar-terms.test.d.ts +2 -0
  17. package/dist/__tests__/solar-terms.test.d.ts.map +1 -0
  18. package/dist/__tests__/solar-terms.test.js +121 -0
  19. package/dist/__tests__/strength.test.d.ts +2 -0
  20. package/dist/__tests__/strength.test.d.ts.map +1 -0
  21. package/dist/__tests__/strength.test.js +44 -0
  22. package/dist/__tests__/ten-gods.test.d.ts +2 -0
  23. package/dist/__tests__/ten-gods.test.d.ts.map +1 -0
  24. package/dist/__tests__/ten-gods.test.js +119 -0
  25. package/dist/__tests__/yongshen.test.d.ts +2 -0
  26. package/dist/__tests__/yongshen.test.d.ts.map +1 -0
  27. package/dist/__tests__/yongshen.test.js +62 -0
  28. package/dist/core/four-pillars.d.ts +2 -0
  29. package/dist/core/four-pillars.d.ts.map +1 -1
  30. package/dist/core/four-pillars.js +7 -4
  31. package/dist/core/luck.d.ts +41 -0
  32. package/dist/core/luck.d.ts.map +1 -0
  33. package/dist/core/luck.js +96 -0
  34. package/dist/core/lunar.d.ts +13 -0
  35. package/dist/core/lunar.d.ts.map +1 -0
  36. package/dist/core/lunar.js +24 -0
  37. package/dist/core/relations.d.ts +94 -0
  38. package/dist/core/relations.d.ts.map +1 -0
  39. package/dist/core/relations.js +305 -0
  40. package/dist/core/solar-terms.d.ts +155 -0
  41. package/dist/core/solar-terms.d.ts.map +1 -0
  42. package/dist/core/solar-terms.js +266 -0
  43. package/dist/core/strength.d.ts +18 -0
  44. package/dist/core/strength.d.ts.map +1 -0
  45. package/dist/core/strength.js +255 -0
  46. package/dist/core/ten-gods.d.ts +130 -0
  47. package/dist/core/ten-gods.d.ts.map +1 -0
  48. package/dist/core/ten-gods.js +335 -0
  49. package/dist/core/yongshen.d.ts +20 -0
  50. package/dist/core/yongshen.d.ts.map +1 -0
  51. package/dist/core/yongshen.js +216 -0
  52. package/dist/index.d.ts +54 -0
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +48 -0
  55. package/package.json +15 -12
package/README.en.md CHANGED
@@ -15,7 +15,13 @@
15
15
  - **Solar Time Correction** - Optional mean solar time adjustment based on longitude
16
16
  - **Tree-shakeable** - Import only what you need
17
17
  - **Fully Typed** - Complete TypeScript definitions
18
- - **Well Tested** - 85+ tests with 91%+ coverage
18
+ - **Well Tested** - 180+ tests with 91%+ coverage
19
+ - **Ten Gods Analysis** - Detailed ten gods and five elements distribution with hidden stems
20
+ - **Strength Assessment** - 9-level strength analysis with monthly strength (得令), root strength (通根), transparency (透干), and hidden stem weights (本中餘氣)
21
+ - **Relations Analysis** - Combinations, clashes, harms, punishments with transformation (化) status and conditions
22
+ - **Major/Yearly Luck** - Solar term (節氣) based accurate luck start calculation, major luck and yearly luck based on gender and year pillar
23
+ - **Yongshen Extraction** - Favorable element recommendation following 格局→抑扶→調候 priority with fortune enhancement guide
24
+ - **Solar Terms Analysis** - Current/next solar term info with elapsed days calculation
19
25
 
20
26
  ## What is Saju (四柱)?
21
27
 
@@ -56,6 +62,39 @@ pnpm add date-fns date-fns-tz
56
62
 
57
63
  ## Quick Start
58
64
 
65
+ ```typescript
66
+ import { DateTime } from "luxon";
67
+ import { createLuxonAdapter } from "@gracefullight/saju/adapters/luxon";
68
+ import { getSaju, STANDARD_PRESET } from "@gracefullight/saju";
69
+
70
+ const adapter = await createLuxonAdapter();
71
+
72
+ const birthDateTime = DateTime.fromObject(
73
+ { year: 2000, month: 1, day: 1, hour: 18, minute: 0 },
74
+ { zone: "Asia/Seoul" }
75
+ );
76
+
77
+ // getSaju: Calculate pillars, ten gods, strength, relations, yongshen, solar terms, major luck, yearly luck all at once
78
+ const result = getSaju(adapter, birthDateTime, {
79
+ longitudeDeg: 126.9778,
80
+ gender: "male", // Required: needed for major luck calculation
81
+ preset: STANDARD_PRESET,
82
+ currentYear: 2024, // For default yearly luck range (optional)
83
+ yearlyLuckRange: { from: 2024, to: 2030 }, // Specify yearly luck range directly (optional)
84
+ });
85
+
86
+ console.log(result.pillars); // { year: "己卯", month: "丙子", ... }
87
+ console.log(result.tenGods); // Ten gods and hidden stems analysis
88
+ console.log(result.strength); // Strength assessment (e.g., "weak")
89
+ console.log(result.relations); // Relations analysis
90
+ console.log(result.yongShen); // Yongshen and fortune tips
91
+ console.log(result.solarTerms); // Solar term info (current/next term, elapsed days)
92
+ console.log(result.majorLuck); // Major luck info
93
+ console.log(result.yearlyLuck); // Yearly luck info
94
+ ```
95
+
96
+ ### Calculate Four Pillars Only
97
+
59
98
  ```typescript
60
99
  import { DateTime } from "luxon";
61
100
  import { createLuxonAdapter } from "@gracefullight/saju/adapters/luxon";
@@ -74,18 +113,6 @@ const result = getFourPillars(adapter, birthDateTime, {
74
113
  });
75
114
 
76
115
  console.log(result);
77
- // {
78
- // year: "己卯", // Year Pillar (Heavenly Stem + Earthly Branch)
79
- // month: "丙子", // Month Pillar
80
- // day: "庚辰", // Day Pillar
81
- // hour: "辛酉", // Hour Pillar
82
- // meta: {
83
- // solarYear: 1999,
84
- // sunLonDeg: 280.9,
85
- // effectiveDayDate: { year: 2000, month: 1, day: 1 },
86
- // adjustedHour: 18
87
- // }
88
- // }
89
116
  ```
90
117
 
91
118
  ## Usage
@@ -126,7 +153,7 @@ import { getFourPillars, STANDARD_PRESET } from "@gracefullight/saju";
126
153
  const adapter = await createDateFnsAdapter();
127
154
 
128
155
  const dt = {
129
- date: new Date(1992, 9, 12, 19, 16), // Note: month is 0-indexed
156
+ date: new Date(1985, 4, 15, 14, 30), // Note: month is 0-indexed
130
157
  timeZone: "Asia/Seoul",
131
158
  };
132
159
 
@@ -200,12 +227,27 @@ Traditional interpretation with Zi hour (23:00) day boundary and solar time corr
200
227
  }
201
228
  ```
202
229
 
203
- #### Deprecated Aliases
204
- - `presetA` → Use `STANDARD_PRESET`
205
- - `presetB` → Use `TRADITIONAL_PRESET`
206
-
207
230
  ### Core Functions
208
231
 
232
+ #### `getSaju(adapter, datetime, options)`
233
+
234
+ Calculate all saju analysis results (pillars, ten gods, strength, relations, yongshen, solar terms, major luck, yearly luck) at once.
235
+
236
+ ```typescript
237
+ function getSaju<T>(
238
+ adapter: DateAdapter<T>,
239
+ dtLocal: T,
240
+ options: {
241
+ longitudeDeg: number;
242
+ gender: "male" | "female"; // Required
243
+ tzOffsetHours?: number;
244
+ preset?: typeof STANDARD_PRESET;
245
+ currentYear?: number; // For default yearly luck range
246
+ yearlyLuckRange?: { from: number; to: number }; // Specify yearly luck range directly
247
+ }
248
+ ): SajuResult;
249
+ ```
250
+
209
251
  #### `getFourPillars(adapter, datetime, options)`
210
252
 
211
253
  Calculate all four pillars (year, month, day, hour).
@@ -228,11 +270,17 @@ function getFourPillars<T>(
228
270
  month: string;
229
271
  day: string;
230
272
  hour: string;
273
+ lunar: {
274
+ lunarYear: number;
275
+ lunarMonth: number;
276
+ lunarDay: number;
277
+ isLeapMonth: boolean;
278
+ };
231
279
  meta: {
232
- solarYear: number;
280
+ solarYearUsed: number;
233
281
  sunLonDeg: number;
234
282
  effectiveDayDate: { year: number; month: number; day: number };
235
- adjustedHour: number;
283
+ adjustedDtForHour: string;
236
284
  };
237
285
  }
238
286
  ```
@@ -245,7 +293,7 @@ function getFourPillars<T>(
245
293
  - `preset`: Configuration preset (use `STANDARD_PRESET` or `TRADITIONAL_PRESET`)
246
294
  - `tzOffsetHours`: Optional timezone offset in hours (default: 9 for KST)
247
295
 
248
- **Returns:** Object with year, month, day, hour pillars and metadata
296
+ **Returns:** Object with year, month, day, hour pillars, lunar date, and metadata
249
297
 
250
298
  #### `yearPillar(adapter, datetime)`
251
299
 
@@ -291,6 +339,58 @@ function dayPillarFromDate(date: {
291
339
  }
292
340
  ```
293
341
 
342
+ ### Lunar Conversion Functions
343
+
344
+ #### `getLunarDate(year, month, day)`
345
+
346
+ Convert a solar (Gregorian) date to a lunar date.
347
+
348
+ ```typescript
349
+ function getLunarDate(
350
+ year: number,
351
+ month: number,
352
+ day: number
353
+ ): {
354
+ lunarYear: number;
355
+ lunarMonth: number;
356
+ lunarDay: number;
357
+ isLeapMonth: boolean;
358
+ }
359
+ ```
360
+
361
+ **Example:**
362
+ ```typescript
363
+ import { getLunarDate } from "@gracefullight/saju";
364
+
365
+ const lunar = getLunarDate(2000, 1, 1);
366
+ // { lunarYear: 1999, lunarMonth: 11, lunarDay: 25, isLeapMonth: false }
367
+ ```
368
+
369
+ #### `getSolarDate(lunarYear, lunarMonth, lunarDay, isLeapMonth)`
370
+
371
+ Convert a lunar date to a solar (Gregorian) date.
372
+
373
+ ```typescript
374
+ function getSolarDate(
375
+ lunarYear: number,
376
+ lunarMonth: number,
377
+ lunarDay: number,
378
+ isLeapMonth?: boolean
379
+ ): {
380
+ year: number;
381
+ month: number;
382
+ day: number;
383
+ }
384
+ ```
385
+
386
+ **Example:**
387
+ ```typescript
388
+ import { getSolarDate } from "@gracefullight/saju";
389
+
390
+ const solar = getSolarDate(1999, 11, 25, false);
391
+ // { year: 2000, month: 1, day: 1 }
392
+ ```
393
+
294
394
  #### `hourPillar(adapter, datetime, options)`
295
395
 
296
396
  Calculate only the hour pillar with optional solar time correction.
@@ -361,6 +461,109 @@ function effectiveDayDate<T>(
361
461
  }
362
462
  ```
363
463
 
464
+ ### Analysis Functions
465
+
466
+ #### `analyzeTenGods(year, month, day, hour)`
467
+
468
+ Analyzes ten gods and hidden stems of the four pillars.
469
+
470
+ ```typescript
471
+ function analyzeTenGods(
472
+ year: string,
473
+ month: string,
474
+ day: string,
475
+ hour: string
476
+ ): FourPillarsTenGods;
477
+ ```
478
+
479
+ #### `analyzeStrength(year, month, day, hour)`
480
+
481
+ Assesses the strength of the day master on a 7-level scale.
482
+
483
+ ```typescript
484
+ function analyzeStrength(
485
+ year: string,
486
+ month: string,
487
+ day: string,
488
+ hour: string
489
+ ): StrengthResult;
490
+ ```
491
+
492
+ #### `analyzeRelations(year, month, day, hour)`
493
+
494
+ Analyzes combinations, clashes, harms, and punishments between stems and branches.
495
+
496
+ ```typescript
497
+ function analyzeRelations(
498
+ year: string,
499
+ month: string,
500
+ day: string,
501
+ hour: string
502
+ ): RelationsResult;
503
+ ```
504
+
505
+ #### `calculateMajorLuck(adapter, datetime, gender, year, month)`
506
+
507
+ Calculates major luck periods and starting age.
508
+
509
+ ```typescript
510
+ function calculateMajorLuck<T>(
511
+ adapter: DateAdapter<T>,
512
+ birthDateTime: T,
513
+ gender: "male" | "female",
514
+ yearPillar: string,
515
+ monthPillar: string
516
+ ): MajorLuckResult;
517
+ ```
518
+
519
+ #### `analyzeYongShen(year, month, day, hour)`
520
+
521
+ Extracts favorable elements considering suppression and climate adjustment.
522
+
523
+ ```typescript
524
+ function analyzeYongShen(
525
+ year: string,
526
+ month: string,
527
+ day: string,
528
+ hour: string
529
+ ): YongShenResult;
530
+ ```
531
+
532
+ #### `analyzeSolarTerms(adapter, datetime)`
533
+
534
+ Calculates current and next solar term info with elapsed days.
535
+
536
+ ```typescript
537
+ function analyzeSolarTerms<T>(
538
+ adapter: DateAdapter<T>,
539
+ dtLocal: T
540
+ ): SolarTermInfo;
541
+ ```
542
+
543
+ **Returns:**
544
+ ```typescript
545
+ {
546
+ current: { name: "소한", hanja: "小寒", longitude: 285 },
547
+ currentDate: { year: 2024, month: 1, day: 6, hour: 5, minute: 30 },
548
+ daysSinceCurrent: 5,
549
+ next: { name: "대한", hanja: "大寒", longitude: 300 },
550
+ nextDate: { year: 2024, month: 1, day: 20, hour: 12, minute: 15 },
551
+ daysUntilNext: 10
552
+ }
553
+ ```
554
+
555
+ #### `getSolarTermsForYear(adapter, year, timezone)`
556
+
557
+ Calculates all 24 solar terms for a specific year.
558
+
559
+ ```typescript
560
+ function getSolarTermsForYear<T>(
561
+ adapter: DateAdapter<T>,
562
+ year: number,
563
+ timezone: string
564
+ ): Array<{ term: SolarTerm; date: {...} }>;
565
+ ```
566
+
364
567
  ## Advanced Usage
365
568
 
366
569
  ### Solar Time Correction
@@ -435,6 +638,85 @@ Common city longitudes for reference:
435
638
 
436
639
  ## Examples
437
640
 
641
+ ### Major and Yearly Luck Calculation
642
+
643
+ ```typescript
644
+ const saju = getSaju(adapter, dt, {
645
+ longitudeDeg: 126.9778,
646
+ gender: "female",
647
+ yearlyLuckRange: { from: 2024, to: 2030 }
648
+ });
649
+
650
+ // Check major luck
651
+ console.log(saju.majorLuck.pillars); // Major luck pillars list
652
+ console.log(saju.majorLuck.startAge); // Starting age for major luck
653
+
654
+ // Check yearly luck
655
+ saju.yearlyLuck.forEach(luck => {
656
+ console.log(`Year ${luck.year} (${luck.pillar}): Age ${luck.age}`);
657
+ });
658
+ ```
659
+
660
+ ### Solar Terms Info
661
+
662
+ ```typescript
663
+ const saju = getSaju(adapter, dt, {
664
+ longitudeDeg: 126.9778,
665
+ gender: "male",
666
+ });
667
+
668
+ // Current solar term
669
+ console.log(saju.solarTerms.current.name); // "소한"
670
+ console.log(saju.solarTerms.current.hanja); // "小寒"
671
+ console.log(saju.solarTerms.daysSinceCurrent); // 5 (days since term started)
672
+
673
+ // Next solar term
674
+ console.log(saju.solarTerms.next.name); // "대한"
675
+ console.log(saju.solarTerms.daysUntilNext); // 10 (days until next term)
676
+
677
+ // Solar term dates
678
+ console.log(saju.solarTerms.currentDate); // { year: 2024, month: 1, day: 6, ... }
679
+ console.log(saju.solarTerms.nextDate); // { year: 2024, month: 1, day: 20, ... }
680
+ ```
681
+
682
+ ### Ten Gods and Five Elements Analysis
683
+
684
+ ```typescript
685
+ import { analyzeTenGods, countElements } from "@gracefullight/saju";
686
+
687
+ const tenGods = analyzeTenGods("己卯", "丙子", "辛巳", "戊戌");
688
+ console.log(tenGods.dayMaster); // "辛"
689
+
690
+ const elements = countElements(tenGods);
691
+ console.log(elements); // { wood: 1, fire: 1, earth: 3, metal: 1, water: 2 }
692
+ ```
693
+
694
+ ### Strength and Yongshen Analysis
695
+
696
+ ```typescript
697
+ import { analyzeStrength, analyzeYongShen, getElementRecommendations } from "@gracefullight/saju";
698
+
699
+ const strength = analyzeStrength("己卯", "丙子", "辛巳", "戊戌");
700
+ console.log(strength.level); // "weak"
701
+
702
+ const yongShen = analyzeYongShen("己卯", "丙子", "辛巳", "戊戌");
703
+ console.log(yongShen.primary); // Favorable element (e.g., "earth")
704
+
705
+ const tips = getElementRecommendations(yongShen);
706
+ console.log(tips.colors); // Lucky colors
707
+ ```
708
+
709
+ ### Relations Analysis
710
+
711
+ ```typescript
712
+ import { analyzeRelations } from "@gracefullight/saju";
713
+
714
+ const relations = analyzeRelations("己卯", "丙子", "辛巳", "戊戌");
715
+ relations.clashes.forEach(c => {
716
+ console.log(`${c.positions[0]}-${c.positions[1]} branch clash: ${c.pair[0]}-${c.pair[1]}`);
717
+ });
718
+ ```
719
+
438
720
  ### Calculate for Different Timezones
439
721
 
440
722
  ```typescript
@@ -445,7 +727,7 @@ const adapter = await createLuxonAdapter();
445
727
 
446
728
  // New York birth time
447
729
  const nyTime = DateTime.fromObject(
448
- { year: 1992, month: 10, day: 12, hour: 6, minute: 16 },
730
+ { year: 1985, month: 5, day: 15, hour: 6, minute: 30 },
449
731
  { zone: "America/New_York" }
450
732
  );
451
733
 
@@ -470,7 +752,7 @@ const month = monthPillar(adapter, dt);
470
752
  console.log(month.pillar, month.sunLonDeg);
471
753
 
472
754
  // Day pillar (no adapter needed)
473
- const day = dayPillarFromDate({ year: 1992, month: 10, day: 12 });
755
+ const day = dayPillarFromDate({ year: 1985, month: 5, day: 15 });
474
756
  console.log(day.pillar);
475
757
 
476
758
  // Hour pillar with solar time
@@ -542,7 +824,15 @@ packages/saju/
542
824
  │ │ ├── luxon.ts # Luxon adapter
543
825
  │ │ └── date-fns.ts # date-fns adapter
544
826
  │ ├── core/ # Core calculation logic
545
- │ │ └── four-pillars.ts # Main algorithms
827
+ │ │ ├── four-pillars.ts # Four pillars calculation
828
+ │ │ ├── ten-gods.ts # Ten gods analysis
829
+ │ │ ├── strength.ts # Strength assessment
830
+ │ │ ├── relations.ts # Relations analysis
831
+ │ │ ├── luck.ts # Major/yearly luck
832
+ │ │ ├── yongshen.ts # Yongshen extraction
833
+ │ │ ├── solar-terms.ts # Solar terms calculation
834
+ │ │ └── lunar.ts # Lunar conversion
835
+ │ ├── types/ # Type definitions
546
836
  │ ├── __tests__/ # Test suites
547
837
  │ └── index.ts # Public API
548
838
  ├── dist/ # Compiled output
@@ -659,7 +949,3 @@ This library is based on traditional Chinese calendar algorithms and astronomica
659
949
  - [Documentation](https://github.com/gracefullight/saju#readme)
660
950
  - [Issue Tracker](https://github.com/gracefullight/saju/issues)
661
951
  - [Discussions](https://github.com/gracefullight/saju/discussions)
662
-
663
- ---
664
-
665
- Made by [gracefullight](https://github.com/gracefullight)