@gracefullight/saju 0.6.0 → 1.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.en.md +54 -43
- package/README.md +54 -43
- package/dist/__tests__/four-pillars.test.js +55 -37
- package/dist/__tests__/saju.test.js +19 -9
- package/dist/__tests__/sinsals.test.js +367 -0
- package/dist/__tests__/solar-terms.test.js +12 -12
- package/dist/core/four-pillars.d.ts +12 -5
- package/dist/core/four-pillars.d.ts.map +1 -1
- package/dist/core/four-pillars.js +14 -11
- package/dist/core/luck.d.ts +2 -1
- package/dist/core/luck.d.ts.map +1 -1
- package/dist/core/luck.js +2 -2
- package/dist/core/sinsals.d.ts +1 -1
- package/dist/core/sinsals.d.ts.map +1 -1
- package/dist/core/sinsals.js +510 -7
- package/dist/core/solar-terms.d.ts +7 -2
- package/dist/core/solar-terms.d.ts.map +1 -1
- package/dist/core/solar-terms.js +2 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -4
- package/package.json +1 -1
|
@@ -39,6 +39,373 @@ describe("sinsals", () => {
|
|
|
39
39
|
const skyNobles = result.matches.filter((m) => m.sinsal.key === "skyNoble");
|
|
40
40
|
expect(skyNobles.length).toBeGreaterThan(0);
|
|
41
41
|
});
|
|
42
|
+
describe("case 1: 丙子 壬辰 丙申 乙未", () => {
|
|
43
|
+
const result = analyzeSinsals("丙子", "壬辰", "丙申", "乙未");
|
|
44
|
+
it("should detect 괴강살 (kuiGang) on month pillar (壬辰)", () => {
|
|
45
|
+
expect(result.summary.kuiGang).toContain("month");
|
|
46
|
+
});
|
|
47
|
+
it("should detect 화개살 (floweryCanopy) on month pillar", () => {
|
|
48
|
+
expect(result.summary.floweryCanopy).toContain("month");
|
|
49
|
+
});
|
|
50
|
+
it("should detect 문창귀인 (literaryNoble) on day pillar", () => {
|
|
51
|
+
expect(result.summary.literaryNoble).toContain("day");
|
|
52
|
+
});
|
|
53
|
+
it("should detect 암록 (hiddenWealth) on day pillar", () => {
|
|
54
|
+
expect(result.summary.hiddenWealth).toContain("day");
|
|
55
|
+
});
|
|
56
|
+
it("should detect 관귀학관 (officialAcademicHall) on day pillar", () => {
|
|
57
|
+
expect(result.summary.officialAcademicHall).toContain("day");
|
|
58
|
+
});
|
|
59
|
+
it("should detect 현침살 (suspendedNeedle) on month and day pillars", () => {
|
|
60
|
+
expect(result.summary.suspendedNeedle).toContain("month");
|
|
61
|
+
expect(result.summary.suspendedNeedle).toContain("day");
|
|
62
|
+
});
|
|
63
|
+
it("should detect 금여성 (goldenCarriage) on hour pillar", () => {
|
|
64
|
+
expect(result.summary.goldenCarriage).toContain("hour");
|
|
65
|
+
});
|
|
66
|
+
it("should detect 백호대살 (whiteTiger) on hour pillar (乙未)", () => {
|
|
67
|
+
expect(result.summary.whiteTiger).toContain("hour");
|
|
68
|
+
});
|
|
69
|
+
it("should detect 천문성 (heavenlyGate) on year pillar", () => {
|
|
70
|
+
expect(result.summary.heavenlyGate).toContain("year");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe("case 2: 壬申 庚戌 辛酉 丁酉", () => {
|
|
74
|
+
const result = analyzeSinsals("壬申", "庚戌", "辛酉", "丁酉");
|
|
75
|
+
it("should detect 현침살 (suspendedNeedle) on year and day pillars", () => {
|
|
76
|
+
expect(result.summary.suspendedNeedle).toContain("year");
|
|
77
|
+
expect(result.summary.suspendedNeedle).toContain("day");
|
|
78
|
+
});
|
|
79
|
+
it("should detect 괴강살 (kuiGang) on month pillar (庚戌)", () => {
|
|
80
|
+
expect(result.summary.kuiGang).toContain("month");
|
|
81
|
+
});
|
|
82
|
+
it("should detect 양인살 (sheepBlade) on month pillar", () => {
|
|
83
|
+
expect(result.summary.sheepBlade).toContain("month");
|
|
84
|
+
});
|
|
85
|
+
it("should detect 건록 (officialStar) on day and hour pillars", () => {
|
|
86
|
+
expect(result.summary.officialStar).toContain("day");
|
|
87
|
+
expect(result.summary.officialStar).toContain("hour");
|
|
88
|
+
});
|
|
89
|
+
it("should detect 천의성 (heavenlyDoctor) on day and hour pillars", () => {
|
|
90
|
+
expect(result.summary.heavenlyDoctor).toContain("day");
|
|
91
|
+
expect(result.summary.heavenlyDoctor).toContain("hour");
|
|
92
|
+
});
|
|
93
|
+
it("should detect 홍염살 (redFlame) on day and hour pillars", () => {
|
|
94
|
+
expect(result.summary.redFlame).toContain("day");
|
|
95
|
+
expect(result.summary.redFlame).toContain("hour");
|
|
96
|
+
});
|
|
97
|
+
it("should detect 도화살 (peachBlossom) on day and hour pillars", () => {
|
|
98
|
+
expect(result.summary.peachBlossom).toContain("day");
|
|
99
|
+
expect(result.summary.peachBlossom).toContain("hour");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe("case 3: 庚午 己丑 乙巳 辛巳", () => {
|
|
103
|
+
// 경오년 기축월 을사일 신사시
|
|
104
|
+
const result = analyzeSinsals("庚午", "己丑", "乙巳", "辛巳");
|
|
105
|
+
it("should detect 천덕귀인 (heavenlyVirtue) on year pillar", () => {
|
|
106
|
+
expect(result.summary.heavenlyVirtue).toContain("year");
|
|
107
|
+
});
|
|
108
|
+
it("should detect 월덕귀인 (monthlyVirtue) on year pillar", () => {
|
|
109
|
+
expect(result.summary.monthlyVirtue).toContain("year");
|
|
110
|
+
});
|
|
111
|
+
it("should detect 문창귀인 (literaryNoble) on year pillar", () => {
|
|
112
|
+
expect(result.summary.literaryNoble).toContain("year");
|
|
113
|
+
});
|
|
114
|
+
it("should detect 학당귀인 (academicHall) on year pillar", () => {
|
|
115
|
+
expect(result.summary.academicHall).toContain("year");
|
|
116
|
+
});
|
|
117
|
+
it("should detect 태극귀인 (taijiNoble) on year pillar", () => {
|
|
118
|
+
expect(result.summary.taijiNoble).toContain("year");
|
|
119
|
+
});
|
|
120
|
+
it("should detect 홍염살 (redFlame) on year pillar", () => {
|
|
121
|
+
expect(result.summary.redFlame).toContain("year");
|
|
122
|
+
});
|
|
123
|
+
it("should detect 도화살 (peachBlossom) on year pillar", () => {
|
|
124
|
+
expect(result.summary.peachBlossom).toContain("year");
|
|
125
|
+
});
|
|
126
|
+
it("should detect 화개살 (floweryCanopy) on month pillar", () => {
|
|
127
|
+
expect(result.summary.floweryCanopy).toContain("month");
|
|
128
|
+
});
|
|
129
|
+
it("should detect 금여성 (goldenCarriage) on day and hour pillars", () => {
|
|
130
|
+
expect(result.summary.goldenCarriage).toContain("day");
|
|
131
|
+
expect(result.summary.goldenCarriage).toContain("hour");
|
|
132
|
+
});
|
|
133
|
+
it("should detect 관귀학관 (officialAcademicHall) on day and hour pillars", () => {
|
|
134
|
+
expect(result.summary.officialAcademicHall).toContain("day");
|
|
135
|
+
expect(result.summary.officialAcademicHall).toContain("hour");
|
|
136
|
+
});
|
|
137
|
+
it("should detect 현침살 (suspendedNeedle) on year and hour pillars", () => {
|
|
138
|
+
expect(result.summary.suspendedNeedle).toContain("year");
|
|
139
|
+
expect(result.summary.suspendedNeedle).toContain("hour");
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
describe("case 4: 癸酉 庚申 己卯 己巳", () => {
|
|
143
|
+
// 계유년 경신월 기묘일 기사시
|
|
144
|
+
const result = analyzeSinsals("癸酉", "庚申", "己卯", "己巳");
|
|
145
|
+
it("should detect 천덕귀인 (heavenlyVirtue) on year pillar", () => {
|
|
146
|
+
// 월지 申 → 천덕 癸, 년간이 癸이므로 year position
|
|
147
|
+
expect(result.summary.heavenlyVirtue).toContain("year");
|
|
148
|
+
});
|
|
149
|
+
it("should detect 문창귀인 (literaryNoble) on year pillar", () => {
|
|
150
|
+
// 일간 己 → 문창 酉, 년지가 酉이므로 year position
|
|
151
|
+
expect(result.summary.literaryNoble).toContain("year");
|
|
152
|
+
});
|
|
153
|
+
it("should detect 학당귀인 (academicHall) on year pillar", () => {
|
|
154
|
+
// 일간 己 → 학당 酉, 년지가 酉이므로 year position
|
|
155
|
+
expect(result.summary.academicHall).toContain("year");
|
|
156
|
+
});
|
|
157
|
+
it("should detect 천주귀인 (heavenlyKitchen) on year pillar", () => {
|
|
158
|
+
// 일간 己 → 천주 酉, 년지가 酉이므로 year position
|
|
159
|
+
expect(result.summary.heavenlyKitchen).toContain("year");
|
|
160
|
+
});
|
|
161
|
+
it("should detect 문곡귀인 (literaryCurve) on day pillar", () => {
|
|
162
|
+
// 일간 己 → 문곡 卯, 일지가 卯이므로 day position
|
|
163
|
+
expect(result.summary.literaryCurve).toContain("day");
|
|
164
|
+
});
|
|
165
|
+
it("should detect 천을귀인 (skyNoble) on month pillar", () => {
|
|
166
|
+
// 일간 己 → 천을 [子,申], 월지가 申이므로 month position
|
|
167
|
+
expect(result.summary.skyNoble).toContain("month");
|
|
168
|
+
});
|
|
169
|
+
it("should detect 금여성 (goldenCarriage) on month pillar", () => {
|
|
170
|
+
// 일간 己 → 금여 申, 월지가 申이므로 month position
|
|
171
|
+
expect(result.summary.goldenCarriage).toContain("month");
|
|
172
|
+
});
|
|
173
|
+
it("should detect 현침살 (suspendedNeedle) on month and day pillars", () => {
|
|
174
|
+
// 월지 申, 일지 卯는 현침 지지
|
|
175
|
+
expect(result.summary.suspendedNeedle).toContain("month");
|
|
176
|
+
expect(result.summary.suspendedNeedle).toContain("day");
|
|
177
|
+
});
|
|
178
|
+
it("should detect 귀문관살 (ghostGate) on month pillar", () => {
|
|
179
|
+
// 일지 卯 → 귀문 子 (해당 없음), 년지 酉 → 귀문 午 (해당 없음)
|
|
180
|
+
// 실제로 귀문관살은 사이트와 계산 방식이 다를 수 있음
|
|
181
|
+
// 이 테스트는 사이트 결과와 일치하지 않을 수 있어 skip
|
|
182
|
+
});
|
|
183
|
+
it("should detect 역마살 (skyHorse) on hour pillar", () => {
|
|
184
|
+
// 일지 卯 → 亥卯未 그룹 → 역마는 巳, 시지가 巳이므로 hour position
|
|
185
|
+
expect(result.summary.skyHorse).toContain("hour");
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
describe("case 5: 己巳 丁丑 丁酉 丙午", () => {
|
|
189
|
+
// 기사년 정축월 정유일 병오시
|
|
190
|
+
const result = analyzeSinsals("己巳", "丁丑", "丁酉", "丙午");
|
|
191
|
+
it("should detect 백호대살 (whiteTiger) on month pillar (丁丑)", () => {
|
|
192
|
+
expect(result.summary.whiteTiger).toContain("month");
|
|
193
|
+
});
|
|
194
|
+
it("should detect 화개살 (floweryCanopy) on month pillar", () => {
|
|
195
|
+
// 년지/일지 巳酉丑 → 화개 丑, 월지가 丑이므로 month position
|
|
196
|
+
expect(result.summary.floweryCanopy).toContain("month");
|
|
197
|
+
});
|
|
198
|
+
it("should detect 천을귀인 (skyNoble) on day pillar", () => {
|
|
199
|
+
// 일간 丁 → 천을 [亥,酉], 일지가 酉이므로 day position
|
|
200
|
+
expect(result.summary.skyNoble).toContain("day");
|
|
201
|
+
});
|
|
202
|
+
it("should detect 문창귀인 (literaryNoble) on day pillar", () => {
|
|
203
|
+
// 일간 丁 → 문창 酉, 일지가 酉이므로 day position
|
|
204
|
+
expect(result.summary.literaryNoble).toContain("day");
|
|
205
|
+
});
|
|
206
|
+
it("should detect 학당귀인 (academicHall) on day pillar", () => {
|
|
207
|
+
// 일간 丁 → 학당 酉, 일지가 酉이므로 day position
|
|
208
|
+
expect(result.summary.academicHall).toContain("day");
|
|
209
|
+
});
|
|
210
|
+
it("should detect 태극귀인 (taijiNoble) on day pillar", () => {
|
|
211
|
+
// 일간 丁 → 태극 [卯,酉], 일지가 酉이므로 day position
|
|
212
|
+
expect(result.summary.taijiNoble).toContain("day");
|
|
213
|
+
});
|
|
214
|
+
it("should detect 건록 (officialStar) on hour pillar", () => {
|
|
215
|
+
// 일간 丁 → 건록 午, 시지가 午이므로 hour position (사이트에서는 정록으로 표시)
|
|
216
|
+
expect(result.summary.officialStar).toContain("hour");
|
|
217
|
+
});
|
|
218
|
+
it("should detect 현침살 (suspendedNeedle) on hour pillar", () => {
|
|
219
|
+
// 시지 午는 현침 지지
|
|
220
|
+
expect(result.summary.suspendedNeedle).toContain("hour");
|
|
221
|
+
});
|
|
222
|
+
it("should detect 도화살 (peachBlossom) on hour pillar", () => {
|
|
223
|
+
// 년지/일지 巳酉丑 → 도화 午, 시지가 午이므로 hour position
|
|
224
|
+
expect(result.summary.peachBlossom).toContain("hour");
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
describe("case 6: 己巳 癸酉 庚子 戊寅", () => {
|
|
228
|
+
// 기사년 계유월 경자일 무인시
|
|
229
|
+
const result = analyzeSinsals("己巳", "癸酉", "庚子", "戊寅");
|
|
230
|
+
it("should detect 학당귀인 (academicHall) on year pillar", () => {
|
|
231
|
+
// 일간 庚 → 학당 巳, 년지가 巳이므로 year position
|
|
232
|
+
expect(result.summary.academicHall).toContain("year");
|
|
233
|
+
});
|
|
234
|
+
it("should detect 문곡귀인 (literaryCurve) on year pillar", () => {
|
|
235
|
+
// 일간 庚 → 문곡 巳, 년지가 巳이므로 year position
|
|
236
|
+
expect(result.summary.literaryCurve).toContain("year");
|
|
237
|
+
});
|
|
238
|
+
it("should detect 관귀학관 (officialAcademicHall) on hour pillar", () => {
|
|
239
|
+
// 일간 庚 → 관귀학관 寅, 시지가 寅이므로 hour position
|
|
240
|
+
expect(result.summary.officialAcademicHall).toContain("hour");
|
|
241
|
+
});
|
|
242
|
+
it("should detect 태극귀인 (taijiNoble) on hour pillar", () => {
|
|
243
|
+
// 일간 庚 → 태극 [寅,亥], 시지가 寅이므로 hour position
|
|
244
|
+
expect(result.summary.taijiNoble).toContain("hour");
|
|
245
|
+
});
|
|
246
|
+
it("should detect 양인살 (sheepBlade) on month pillar", () => {
|
|
247
|
+
// 일간 庚 → 양인 酉, 월지가 酉이므로 month position
|
|
248
|
+
expect(result.summary.sheepBlade).toContain("month");
|
|
249
|
+
});
|
|
250
|
+
it("should detect 월덕귀인 (monthlyVirtue) on day pillar", () => {
|
|
251
|
+
// 월지 酉 → 월덕 庚, 일간이 庚이므로 day position
|
|
252
|
+
expect(result.summary.monthlyVirtue).toContain("day");
|
|
253
|
+
});
|
|
254
|
+
it("should detect 천덕귀인 (heavenlyVirtue) on hour pillar", () => {
|
|
255
|
+
// 월지 酉 → 천덕 寅, 시지가 寅이므로 hour position
|
|
256
|
+
expect(result.summary.heavenlyVirtue).toContain("hour");
|
|
257
|
+
});
|
|
258
|
+
it("should detect 역마살 (skyHorse) on hour pillar", () => {
|
|
259
|
+
// 일지 子 → 申子辰 그룹 → 역마는 寅, 시지가 寅이므로 hour position
|
|
260
|
+
expect(result.summary.skyHorse).toContain("hour");
|
|
261
|
+
});
|
|
262
|
+
it("should detect 도화살 (peachBlossom) on month pillar", () => {
|
|
263
|
+
// 일지 子 → 申子辰 그룹 → 도화는 酉, 월지가 酉이므로 month position
|
|
264
|
+
expect(result.summary.peachBlossom).toContain("month");
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
describe("case 7: 甲戌 丁卯 丙申 壬辰", () => {
|
|
268
|
+
// 갑술년 정묘월 병신일 임진시
|
|
269
|
+
const result = analyzeSinsals("甲戌", "丁卯", "丙申", "壬辰");
|
|
270
|
+
it("should detect 월덕귀인 (monthlyVirtue) on year pillar", () => {
|
|
271
|
+
// 월지 卯 → 월덕 甲, 년간이 甲이므로 year position
|
|
272
|
+
expect(result.summary.monthlyVirtue).toContain("year");
|
|
273
|
+
});
|
|
274
|
+
it("should detect 현침살 (suspendedNeedle) on year, month and day pillars", () => {
|
|
275
|
+
// 년간 甲, 월지 卯, 일지 申은 현침살
|
|
276
|
+
expect(result.summary.suspendedNeedle).toContain("year");
|
|
277
|
+
expect(result.summary.suspendedNeedle).toContain("month");
|
|
278
|
+
expect(result.summary.suspendedNeedle).toContain("day");
|
|
279
|
+
});
|
|
280
|
+
it("should detect 화개살 (floweryCanopy) on year and hour pillars", () => {
|
|
281
|
+
// 년지/일지 申子辰 → 화개 辰, 시지가 辰 / 년지 戌도 화개
|
|
282
|
+
expect(result.summary.floweryCanopy).toContain("hour");
|
|
283
|
+
});
|
|
284
|
+
it("should detect 괴강살 (kuiGang) on hour pillar (壬辰)", () => {
|
|
285
|
+
expect(result.summary.kuiGang).toContain("hour");
|
|
286
|
+
});
|
|
287
|
+
it("should detect 태극귀인 (taijiNoble) on month pillar", () => {
|
|
288
|
+
// 일간 丙 → 태극 [卯,酉], 월지가 卯이므로 month position
|
|
289
|
+
expect(result.summary.taijiNoble).toContain("month");
|
|
290
|
+
});
|
|
291
|
+
it("should detect 도화살 (peachBlossom) on month pillar", () => {
|
|
292
|
+
// 년지 戌 → 寅午戌 그룹 → 도화 卯, 월지가 卯이므로 month position
|
|
293
|
+
expect(result.summary.peachBlossom).toContain("month");
|
|
294
|
+
});
|
|
295
|
+
it("should detect 문창귀인 (literaryNoble) on day pillar", () => {
|
|
296
|
+
// 일간 丙 → 문창 申, 일지가 申이므로 day position
|
|
297
|
+
expect(result.summary.literaryNoble).toContain("day");
|
|
298
|
+
});
|
|
299
|
+
it("should detect 암록 (hiddenWealth) on day pillar", () => {
|
|
300
|
+
// 일간 丙 → 암록 申, 일지가 申이므로 day position
|
|
301
|
+
expect(result.summary.hiddenWealth).toContain("day");
|
|
302
|
+
});
|
|
303
|
+
it("should detect 관귀학관 (officialAcademicHall) on day pillar", () => {
|
|
304
|
+
// 일간 丙 → 관귀학관 申, 일지가 申이므로 day position
|
|
305
|
+
expect(result.summary.officialAcademicHall).toContain("day");
|
|
306
|
+
});
|
|
307
|
+
it("should detect 역마살 (skyHorse) on day pillar", () => {
|
|
308
|
+
// 년지 戌 → 寅午戌 그룹 → 역마는 申, 일지가 申이므로 day position
|
|
309
|
+
expect(result.summary.skyHorse).toContain("day");
|
|
310
|
+
});
|
|
311
|
+
it("should detect 천문성 (heavenlyGate) on year pillar", () => {
|
|
312
|
+
// 월지 卯 → 천문 亥... 확인 필요
|
|
313
|
+
// 실제 HEAVENLY_GATE_MAP[卯] = 亥, 戌은 없으므로 다른 로직일 수 있음
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
describe("case 8: 己卯 癸酉 丙戌 甲午", () => {
|
|
317
|
+
// 기묘년 계유월 병술일 갑오시
|
|
318
|
+
const result = analyzeSinsals("己卯", "癸酉", "丙戌", "甲午");
|
|
319
|
+
it("should detect 태극귀인 (taijiNoble) on year and month pillars", () => {
|
|
320
|
+
// 일간 丙 → 태극 [卯,酉], 년지 卯, 월지 酉
|
|
321
|
+
expect(result.summary.taijiNoble).toContain("year");
|
|
322
|
+
expect(result.summary.taijiNoble).toContain("month");
|
|
323
|
+
});
|
|
324
|
+
it("should detect 현침살 (suspendedNeedle) on year, hour stem and hour branch", () => {
|
|
325
|
+
// 년지 卯, 시간 甲(현침 천간), 시지 午는 현침 지지
|
|
326
|
+
expect(result.summary.suspendedNeedle).toContain("year");
|
|
327
|
+
expect(result.summary.suspendedNeedle).toContain("hour");
|
|
328
|
+
});
|
|
329
|
+
it("should detect 천을귀인 (skyNoble) on month pillar", () => {
|
|
330
|
+
// 일간 丙 → 천을 [亥,酉], 월지가 酉이므로 month position
|
|
331
|
+
expect(result.summary.skyNoble).toContain("month");
|
|
332
|
+
});
|
|
333
|
+
it("should detect 백호대살 (whiteTiger) on day pillar (丙戌)", () => {
|
|
334
|
+
expect(result.summary.whiteTiger).toContain("day");
|
|
335
|
+
});
|
|
336
|
+
it("should detect 화개살 (floweryCanopy) on day pillar", () => {
|
|
337
|
+
// 년지 卯 (亥卯未) → 화개 未 / 일지 戌 (寅午戌) → 화개 戌
|
|
338
|
+
expect(result.summary.floweryCanopy).toContain("day");
|
|
339
|
+
});
|
|
340
|
+
it("should detect 양인살 (sheepBlade) on hour pillar", () => {
|
|
341
|
+
// 일간 丙 → 양인 午, 시지가 午이므로 hour position
|
|
342
|
+
expect(result.summary.sheepBlade).toContain("hour");
|
|
343
|
+
});
|
|
344
|
+
it("should detect 황은대사 (imperialPardon) on hour pillar", () => {
|
|
345
|
+
// 월지 酉 → 황은대사 午, 시지가 午이므로 hour position
|
|
346
|
+
expect(result.summary.imperialPardon).toContain("hour");
|
|
347
|
+
});
|
|
348
|
+
it("should detect 도화살 (peachBlossom) on various positions", () => {
|
|
349
|
+
// 일지 戌 (寅午戌) → 도화 卯, 년지가 卯
|
|
350
|
+
// 년지 卯 (亥卯未) → 도화 子 (없음)
|
|
351
|
+
expect(result.summary.peachBlossom).toContain("year");
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
describe("New Sinsals (Gongmang, Wonjin, etc.)", () => {
|
|
355
|
+
it("should detect 공망 (gongmang) correctly", () => {
|
|
356
|
+
// 甲子 일주 (0, 0) -> 공망 戌(10), 亥(11)
|
|
357
|
+
// 년지에 戌이 있는 경우
|
|
358
|
+
const result = analyzeSinsals("甲戌", "丙寅", "甲子", "庚午");
|
|
359
|
+
expect(result.summary.gongmang).toContain("year");
|
|
360
|
+
});
|
|
361
|
+
it("should detect 원진살 (wonjin) correctly", () => {
|
|
362
|
+
// 일지 子(쥐) <-> 월지 未(양) 원진
|
|
363
|
+
const result = analyzeSinsals("甲申", "乙未", "甲子", "庚午");
|
|
364
|
+
expect(result.summary.wonjin).toContain("month");
|
|
365
|
+
});
|
|
366
|
+
it("should detect 망신살 (lostSpirit) correctly", () => {
|
|
367
|
+
// 일지 寅 (寅午戌 화국) -> 망신 巳
|
|
368
|
+
// 년지 巳
|
|
369
|
+
const result = analyzeSinsals("己巳", "丙寅", "甲寅", "庚午");
|
|
370
|
+
expect(result.summary.lostSpirit).toContain("year");
|
|
371
|
+
});
|
|
372
|
+
it("should detect 겁살 (robbery) correctly", () => {
|
|
373
|
+
// 일지 寅 (寅午戌 화국) -> 겁살 亥
|
|
374
|
+
// 시지 亥
|
|
375
|
+
const result = analyzeSinsals("己巳", "丙寅", "甲寅", "乙亥");
|
|
376
|
+
expect(result.summary.robbery).toContain("hour");
|
|
377
|
+
});
|
|
378
|
+
it("should detect 재살 (disaster) correctly", () => {
|
|
379
|
+
// 일지 寅 (寅午戌 화국) -> 재살 子
|
|
380
|
+
// 월지 子
|
|
381
|
+
const result = analyzeSinsals("己巳", "戊子", "甲寅", "庚午");
|
|
382
|
+
expect(result.summary.disaster).toContain("month");
|
|
383
|
+
});
|
|
384
|
+
it("should detect 장성살 (generalStar) correctly", () => {
|
|
385
|
+
// 일지 寅 (寅午戌 화국) -> 장성 午
|
|
386
|
+
// 시지 午
|
|
387
|
+
const result = analyzeSinsals("己巳", "丙寅", "甲寅", "庚午");
|
|
388
|
+
expect(result.summary.generalStar).toContain("hour");
|
|
389
|
+
});
|
|
390
|
+
it("should detect 반안살 (saddleMount) correctly", () => {
|
|
391
|
+
// 일지 寅 (寅午戌 화국) -> 반안 未
|
|
392
|
+
// 월지 未
|
|
393
|
+
const result = analyzeSinsals("己巳", "辛未", "甲寅", "庚午");
|
|
394
|
+
expect(result.summary.saddleMount).toContain("month");
|
|
395
|
+
});
|
|
396
|
+
it("should detect 홍란살 (redPhoenix) correctly", () => {
|
|
397
|
+
// 년지 子 -> 홍란 卯
|
|
398
|
+
// 월지 卯
|
|
399
|
+
const result = analyzeSinsals("甲子", "丁卯", "甲申", "庚午");
|
|
400
|
+
expect(result.summary.redPhoenix).toContain("month");
|
|
401
|
+
});
|
|
402
|
+
it("should detect 천희살 (heavenlyJoy) correctly", () => {
|
|
403
|
+
// 년지 子 -> 천희 酉
|
|
404
|
+
// 시지 酉
|
|
405
|
+
const result = analyzeSinsals("甲子", "丙寅", "甲申", "癸酉");
|
|
406
|
+
expect(result.summary.heavenlyJoy).toContain("hour");
|
|
407
|
+
});
|
|
408
|
+
});
|
|
42
409
|
});
|
|
43
410
|
describe("SINSAL_INFO", () => {
|
|
44
411
|
it("should have info for all sinsals", () => {
|
|
@@ -35,7 +35,7 @@ describe("solar-terms", async () => {
|
|
|
35
35
|
describe("analyzeSolarTerms", () => {
|
|
36
36
|
it("should return current and next solar terms for mid-January", () => {
|
|
37
37
|
const dt = DateTime.fromObject({ year: 2024, month: 1, day: 15 }, { zone: "Asia/Seoul" });
|
|
38
|
-
const result = analyzeSolarTerms(
|
|
38
|
+
const result = analyzeSolarTerms(dt, { adapter });
|
|
39
39
|
expect(result.current.korean).toBe("소한");
|
|
40
40
|
expect(result.next.korean).toBe("대한");
|
|
41
41
|
expect(result.daysSinceCurrent).toBeGreaterThanOrEqual(0);
|
|
@@ -43,39 +43,39 @@ describe("solar-terms", async () => {
|
|
|
43
43
|
});
|
|
44
44
|
it("should return current and next solar terms for early February", () => {
|
|
45
45
|
const dt = DateTime.fromObject({ year: 2024, month: 2, day: 3 }, { zone: "Asia/Seoul" });
|
|
46
|
-
const result = analyzeSolarTerms(
|
|
46
|
+
const result = analyzeSolarTerms(dt, { adapter });
|
|
47
47
|
expect(result.current.korean).toBe("대한");
|
|
48
48
|
expect(result.next.korean).toBe("입춘");
|
|
49
49
|
});
|
|
50
50
|
it("should return current and next solar terms for summer solstice period", () => {
|
|
51
51
|
const dt = DateTime.fromObject({ year: 2024, month: 6, day: 25 }, { zone: "Asia/Seoul" });
|
|
52
|
-
const result = analyzeSolarTerms(
|
|
52
|
+
const result = analyzeSolarTerms(dt, { adapter });
|
|
53
53
|
expect(result.current.korean).toBe("하지");
|
|
54
54
|
expect(result.next.korean).toBe("소서");
|
|
55
55
|
});
|
|
56
56
|
it("should return current and next solar terms for winter solstice period", () => {
|
|
57
57
|
const dt = DateTime.fromObject({ year: 2024, month: 12, day: 25 }, { zone: "Asia/Seoul" });
|
|
58
|
-
const result = analyzeSolarTerms(
|
|
58
|
+
const result = analyzeSolarTerms(dt, { adapter });
|
|
59
59
|
expect(result.current.korean).toBe("동지");
|
|
60
60
|
expect(result.next.korean).toBe("소한");
|
|
61
61
|
});
|
|
62
62
|
it("should calculate days since current term correctly", () => {
|
|
63
63
|
const dt = DateTime.fromObject({ year: 2024, month: 3, day: 25 }, { zone: "Asia/Seoul" });
|
|
64
|
-
const result = analyzeSolarTerms(
|
|
64
|
+
const result = analyzeSolarTerms(dt, { adapter });
|
|
65
65
|
expect(result.current.korean).toBe("춘분");
|
|
66
66
|
expect(result.daysSinceCurrent).toBeGreaterThanOrEqual(0);
|
|
67
67
|
expect(result.daysSinceCurrent).toBeLessThan(16);
|
|
68
68
|
});
|
|
69
69
|
it("should calculate days until next term correctly", () => {
|
|
70
70
|
const dt = DateTime.fromObject({ year: 2024, month: 4, day: 1 }, { zone: "Asia/Seoul" });
|
|
71
|
-
const result = analyzeSolarTerms(
|
|
71
|
+
const result = analyzeSolarTerms(dt, { adapter });
|
|
72
72
|
expect(result.next.korean).toBe("청명");
|
|
73
73
|
expect(result.daysUntilNext).toBeGreaterThan(0);
|
|
74
74
|
expect(result.daysUntilNext).toBeLessThan(16);
|
|
75
75
|
});
|
|
76
76
|
it("should include date information for current and next terms", () => {
|
|
77
77
|
const dt = DateTime.fromObject({ year: 2024, month: 5, day: 10 }, { zone: "Asia/Seoul" });
|
|
78
|
-
const result = analyzeSolarTerms(
|
|
78
|
+
const result = analyzeSolarTerms(dt, { adapter });
|
|
79
79
|
expect(result.currentDate).toHaveProperty("year");
|
|
80
80
|
expect(result.currentDate).toHaveProperty("month");
|
|
81
81
|
expect(result.currentDate).toHaveProperty("day");
|
|
@@ -90,11 +90,11 @@ describe("solar-terms", async () => {
|
|
|
90
90
|
});
|
|
91
91
|
describe("getSolarTermsForYear", () => {
|
|
92
92
|
it("should return 24 terms for a year", () => {
|
|
93
|
-
const terms = getSolarTermsForYear(
|
|
93
|
+
const terms = getSolarTermsForYear(2024, { adapter, timezone: "Asia/Seoul" });
|
|
94
94
|
expect(terms).toHaveLength(24);
|
|
95
95
|
});
|
|
96
96
|
it("should have all terms in order", () => {
|
|
97
|
-
const terms = getSolarTermsForYear(
|
|
97
|
+
const terms = getSolarTermsForYear(2024, { adapter, timezone: "Asia/Seoul" });
|
|
98
98
|
const names = terms.map((t) => t.term.korean);
|
|
99
99
|
expect(names[0]).toBe("소한");
|
|
100
100
|
expect(names[2]).toBe("입춘");
|
|
@@ -104,7 +104,7 @@ describe("solar-terms", async () => {
|
|
|
104
104
|
expect(names[23]).toBe("동지");
|
|
105
105
|
});
|
|
106
106
|
it("should have dates in chronological order within months", () => {
|
|
107
|
-
const terms = getSolarTermsForYear(
|
|
107
|
+
const terms = getSolarTermsForYear(2024, { adapter, timezone: "Asia/Seoul" });
|
|
108
108
|
for (const term of terms) {
|
|
109
109
|
expect(term.date.year).toBe(2024);
|
|
110
110
|
expect(term.date.month).toBeGreaterThanOrEqual(1);
|
|
@@ -114,14 +114,14 @@ describe("solar-terms", async () => {
|
|
|
114
114
|
}
|
|
115
115
|
});
|
|
116
116
|
it("should have 입춘 around February 4", () => {
|
|
117
|
-
const terms = getSolarTermsForYear(
|
|
117
|
+
const terms = getSolarTermsForYear(2024, { adapter, timezone: "Asia/Seoul" });
|
|
118
118
|
const ipchun = terms.find((t) => t.term.korean === "입춘");
|
|
119
119
|
expect(ipchun?.date.month).toBe(2);
|
|
120
120
|
expect(ipchun?.date.day).toBeGreaterThanOrEqual(3);
|
|
121
121
|
expect(ipchun?.date.day).toBeLessThanOrEqual(5);
|
|
122
122
|
});
|
|
123
123
|
it("should have 하지 around June 21", () => {
|
|
124
|
-
const terms = getSolarTermsForYear(
|
|
124
|
+
const terms = getSolarTermsForYear(2024, { adapter, timezone: "Asia/Seoul" });
|
|
125
125
|
const haji = terms.find((t) => t.term.korean === "하지");
|
|
126
126
|
expect(haji?.date.month).toBe(6);
|
|
127
127
|
expect(haji?.date.day).toBeGreaterThanOrEqual(20);
|
|
@@ -31,16 +31,21 @@ export declare function dayPillarFromDate({ year, month, day, }: {
|
|
|
31
31
|
pillar: string;
|
|
32
32
|
};
|
|
33
33
|
export declare function applyMeanSolarTime<T>(adapter: DateAdapter<T>, dtLocal: T, longitudeDeg: number, tzOffsetHours?: number): T;
|
|
34
|
-
export declare function yearPillar<T>(
|
|
34
|
+
export declare function yearPillar<T>(dtLocal: T, { adapter }: {
|
|
35
|
+
adapter: DateAdapter<T>;
|
|
36
|
+
}): {
|
|
35
37
|
idx60: number;
|
|
36
38
|
pillar: string;
|
|
37
39
|
solarYear: number;
|
|
38
40
|
};
|
|
39
|
-
export declare function monthPillar<T>(
|
|
41
|
+
export declare function monthPillar<T>(dtLocal: T, { adapter }: {
|
|
42
|
+
adapter: DateAdapter<T>;
|
|
43
|
+
}): {
|
|
40
44
|
pillar: string;
|
|
41
45
|
sunLonDeg: number;
|
|
42
46
|
};
|
|
43
|
-
export declare function effectiveDayDate<T>(
|
|
47
|
+
export declare function effectiveDayDate<T>(dtLocal: T, { adapter, dayBoundary, longitudeDeg, tzOffsetHours, useMeanSolarTimeForBoundary, }: {
|
|
48
|
+
adapter: DateAdapter<T>;
|
|
44
49
|
dayBoundary?: "midnight" | "zi23";
|
|
45
50
|
longitudeDeg?: number;
|
|
46
51
|
tzOffsetHours?: number;
|
|
@@ -50,7 +55,8 @@ export declare function effectiveDayDate<T>(adapter: DateAdapter<T>, dtLocal: T,
|
|
|
50
55
|
month: number;
|
|
51
56
|
day: number;
|
|
52
57
|
};
|
|
53
|
-
export declare function hourPillar<T>(
|
|
58
|
+
export declare function hourPillar<T>(dtLocal: T, { adapter, longitudeDeg, tzOffsetHours, useMeanSolarTimeForHour, dayBoundary, useMeanSolarTimeForBoundary, }: {
|
|
59
|
+
adapter: DateAdapter<T>;
|
|
54
60
|
longitudeDeg?: number;
|
|
55
61
|
tzOffsetHours?: number;
|
|
56
62
|
useMeanSolarTimeForHour?: boolean;
|
|
@@ -65,7 +71,8 @@ export declare function hourPillar<T>(adapter: DateAdapter<T>, dtLocal: T, { lon
|
|
|
65
71
|
day: number;
|
|
66
72
|
};
|
|
67
73
|
};
|
|
68
|
-
export declare function getFourPillars<T>(
|
|
74
|
+
export declare function getFourPillars<T>(dtLocal: T, { adapter, longitudeDeg, tzOffsetHours, preset, }: {
|
|
75
|
+
adapter: DateAdapter<T>;
|
|
69
76
|
longitudeDeg?: number;
|
|
70
77
|
tzOffsetHours?: number;
|
|
71
78
|
preset?: typeof presetA | typeof presetB;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"four-pillars.d.ts","sourceRoot":"","sources":["../../src/core/four-pillars.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAgC,KAAK,EAAE,MAAM,SAAS,CAAC;AAExE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAE3B,eAAO,MAAM,eAAe;;;;CAI3B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;CAI9B,CAAC;AAEF,eAAO,MAAM,OAAO;;;;CAAkB,CAAC;AACvC,eAAO,MAAM,OAAO;;;;CAAqB,CAAC;AAO1C,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,KAAK,EACL,GAAG,GACJ,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb,GAAG;IACF,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAIA;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,EACvB,OAAO,EAAE,CAAC,EACV,YAAY,EAAE,MAAM,EACpB,aAAa,SAAI,GAChB,CAAC,CAGH;AAiFD,wBAAgB,UAAU,CAAC,CAAC,EAC1B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"four-pillars.d.ts","sourceRoot":"","sources":["../../src/core/four-pillars.ts"],"names":[],"mappings":"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"}
|
|
@@ -91,7 +91,7 @@ function lichunUtc(adapter, year) {
|
|
|
91
91
|
const end = adapter.createUTC(year, 2, 7, 0, 0, 0);
|
|
92
92
|
return findTermUtc(adapter, 315.0, start, end);
|
|
93
93
|
}
|
|
94
|
-
export function yearPillar(
|
|
94
|
+
export function yearPillar(dtLocal, { adapter }) {
|
|
95
95
|
const y = adapter.getYear(dtLocal);
|
|
96
96
|
const lichunLocal = adapter.setZone(lichunUtc(adapter, y), adapter.getZoneName(dtLocal));
|
|
97
97
|
const solarYear = adapter.isGreaterThanOrEqual(dtLocal, lichunLocal) ? y : y - 1;
|
|
@@ -116,8 +116,8 @@ function firstMonthStemIndex(yearStemIdx) {
|
|
|
116
116
|
]);
|
|
117
117
|
return map.get(yearStemIdx) ?? 0;
|
|
118
118
|
}
|
|
119
|
-
export function monthPillar(
|
|
120
|
-
const { idx60: yIdx60 } = yearPillar(
|
|
119
|
+
export function monthPillar(dtLocal, { adapter }) {
|
|
120
|
+
const { idx60: yIdx60 } = yearPillar(dtLocal, { adapter });
|
|
121
121
|
const yearStemIdx = yIdx60 % 10;
|
|
122
122
|
const lon = sunApparentLongitude(adapter, adapter.toUTC(dtLocal));
|
|
123
123
|
const mBranchIdx = monthBranchIndexFromSunLon(lon);
|
|
@@ -125,7 +125,7 @@ export function monthPillar(adapter, dtLocal) {
|
|
|
125
125
|
const mStemIdx = (firstMonthStemIndex(yearStemIdx) + monthNo) % 10;
|
|
126
126
|
return { pillar: STEMS[mStemIdx] + BRANCHES[mBranchIdx], sunLonDeg: lon };
|
|
127
127
|
}
|
|
128
|
-
export function effectiveDayDate(
|
|
128
|
+
export function effectiveDayDate(dtLocal, { adapter, dayBoundary = "midnight", longitudeDeg, tzOffsetHours = 9, useMeanSolarTimeForBoundary = false, }) {
|
|
129
129
|
let dtChk = dtLocal;
|
|
130
130
|
if (useMeanSolarTimeForBoundary) {
|
|
131
131
|
if (typeof longitudeDeg !== "number")
|
|
@@ -150,14 +150,15 @@ function hourBranchIndexFromHour(h) {
|
|
|
150
150
|
// Examples: 0->0(子), 1->1(丑), 3->2(寅), 23->0(子)
|
|
151
151
|
return Math.floor((h + 1) / 2) % 12;
|
|
152
152
|
}
|
|
153
|
-
export function hourPillar(
|
|
153
|
+
export function hourPillar(dtLocal, { adapter, longitudeDeg, tzOffsetHours = 9, useMeanSolarTimeForHour = false, dayBoundary = "midnight", useMeanSolarTimeForBoundary = false, }) {
|
|
154
154
|
let dtUsed = dtLocal;
|
|
155
155
|
if (useMeanSolarTimeForHour) {
|
|
156
156
|
if (typeof longitudeDeg !== "number")
|
|
157
157
|
throw new Error("longitudeDeg required when useMeanSolarTimeForHour=true");
|
|
158
158
|
dtUsed = applyMeanSolarTime(adapter, dtLocal, longitudeDeg, tzOffsetHours);
|
|
159
159
|
}
|
|
160
|
-
const effDate = effectiveDayDate(
|
|
160
|
+
const effDate = effectiveDayDate(dtLocal, {
|
|
161
|
+
adapter,
|
|
161
162
|
dayBoundary,
|
|
162
163
|
longitudeDeg,
|
|
163
164
|
tzOffsetHours,
|
|
@@ -169,21 +170,23 @@ export function hourPillar(adapter, dtLocal, { longitudeDeg, tzOffsetHours = 9,
|
|
|
169
170
|
const hs = (dayStemIdx * 2 + hb) % 10;
|
|
170
171
|
return { pillar: STEMS[hs] + BRANCHES[hb], adjustedDt: dtUsed, effectiveDate: effDate };
|
|
171
172
|
}
|
|
172
|
-
export function getFourPillars(
|
|
173
|
+
export function getFourPillars(dtLocal, { adapter, longitudeDeg, tzOffsetHours = 9, preset = presetA, }) {
|
|
173
174
|
const effectiveLongitude = longitudeDeg ?? tzOffsetHours * 15;
|
|
174
175
|
const dayBoundary = preset.dayBoundary ?? "midnight";
|
|
175
176
|
const useMeanSolarTimeForHour = preset.useMeanSolarTimeForHour ?? false;
|
|
176
177
|
const useMeanSolarTimeForBoundary = preset.useMeanSolarTimeForBoundary ?? false;
|
|
177
|
-
const y = yearPillar(
|
|
178
|
-
const m = monthPillar(
|
|
179
|
-
const effDate = effectiveDayDate(
|
|
178
|
+
const y = yearPillar(dtLocal, { adapter });
|
|
179
|
+
const m = monthPillar(dtLocal, { adapter });
|
|
180
|
+
const effDate = effectiveDayDate(dtLocal, {
|
|
181
|
+
adapter,
|
|
180
182
|
dayBoundary,
|
|
181
183
|
longitudeDeg: effectiveLongitude,
|
|
182
184
|
tzOffsetHours,
|
|
183
185
|
useMeanSolarTimeForBoundary,
|
|
184
186
|
});
|
|
185
187
|
const d = dayPillarFromDate(effDate);
|
|
186
|
-
const h = hourPillar(
|
|
188
|
+
const h = hourPillar(dtLocal, {
|
|
189
|
+
adapter,
|
|
187
190
|
longitudeDeg: effectiveLongitude,
|
|
188
191
|
tzOffsetHours,
|
|
189
192
|
useMeanSolarTimeForHour,
|
package/dist/core/luck.d.ts
CHANGED
|
@@ -23,7 +23,8 @@ export interface MajorLuckResult {
|
|
|
23
23
|
daysToTerm: number;
|
|
24
24
|
pillars: LuckPillar[];
|
|
25
25
|
}
|
|
26
|
-
export declare function calculateMajorLuck<T>(
|
|
26
|
+
export declare function calculateMajorLuck<T>(birthDateTime: T, gender: Gender, yearPillar: string, monthPillar: string, options: {
|
|
27
|
+
adapter: DateAdapter<T>;
|
|
27
28
|
count?: number;
|
|
28
29
|
nextJieMillis?: number;
|
|
29
30
|
prevJieMillis?: number;
|
package/dist/core/luck.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"luck.d.ts","sourceRoot":"","sources":["../../src/core/luck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGhD,YAAY,EAAE,MAAM,EAAE,CAAC;AAEvB,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,QAAQ,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,
|
|
1
|
+
{"version":3,"file":"luck.d.ts","sourceRoot":"","sources":["../../src/core/luck.ts"],"names":[],"mappings":"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"}
|
package/dist/core/luck.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getStemPolarity } from "../core/ten-gods";
|
|
2
2
|
import { BRANCHES, getPillarIndex, jdnFromDate, pillarFromIndex, STEMS } from "../utils";
|
|
3
|
-
export function calculateMajorLuck(
|
|
4
|
-
const { count = 8 } = options;
|
|
3
|
+
export function calculateMajorLuck(birthDateTime, gender, yearPillar, monthPillar, options) {
|
|
4
|
+
const { adapter, count = 8 } = options;
|
|
5
5
|
const yearStem = yearPillar[0];
|
|
6
6
|
const yearStemPolarity = getStemPolarity(yearStem);
|
|
7
7
|
const isForward = (yearStemPolarity === "yang" && gender === "male") ||
|