@gracefullight/saju 0.4.2 → 0.6.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 (39) hide show
  1. package/dist/__tests__/relations.test.js +6 -6
  2. package/dist/__tests__/saju.test.js +3 -3
  3. package/dist/__tests__/sinsals.test.js +5 -5
  4. package/dist/__tests__/solar-terms.test.js +26 -16
  5. package/dist/__tests__/strength.test.js +2 -2
  6. package/dist/__tests__/ten-gods.test.js +52 -38
  7. package/dist/__tests__/twelve-stages.test.js +55 -51
  8. package/dist/__tests__/yongshen.test.js +3 -3
  9. package/dist/core/luck.d.ts.map +1 -1
  10. package/dist/core/luck.js +2 -1
  11. package/dist/core/relations.d.ts +35 -20
  12. package/dist/core/relations.d.ts.map +1 -1
  13. package/dist/core/relations.js +105 -33
  14. package/dist/core/sinsals.d.ts +12 -6
  15. package/dist/core/sinsals.d.ts.map +1 -1
  16. package/dist/core/sinsals.js +19 -8
  17. package/dist/core/solar-terms.d.ts +19 -105
  18. package/dist/core/solar-terms.d.ts.map +1 -1
  19. package/dist/core/solar-terms.js +56 -29
  20. package/dist/core/strength.d.ts +7 -3
  21. package/dist/core/strength.d.ts.map +1 -1
  22. package/dist/core/strength.js +52 -28
  23. package/dist/core/ten-gods.d.ts +27 -64
  24. package/dist/core/ten-gods.d.ts.map +1 -1
  25. package/dist/core/ten-gods.js +65 -119
  26. package/dist/core/twelve-stages.d.ts +12 -12
  27. package/dist/core/twelve-stages.d.ts.map +1 -1
  28. package/dist/core/twelve-stages.js +28 -24
  29. package/dist/core/yongshen.d.ts +15 -6
  30. package/dist/core/yongshen.d.ts.map +1 -1
  31. package/dist/core/yongshen.js +67 -38
  32. package/dist/index.d.ts +7 -7
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +6 -6
  35. package/dist/types/common.d.ts +8 -0
  36. package/dist/types/common.d.ts.map +1 -1
  37. package/dist/types/index.d.ts +1 -1
  38. package/dist/types/index.d.ts.map +1 -1
  39. package/package.json +1 -1
@@ -1,44 +1,44 @@
1
1
  import { ELEMENTS } from "../utils";
2
2
  export { ELEMENTS };
3
- export const TEN_GODS = [
4
- "비견",
5
- "겁재",
6
- "식신",
7
- "상관",
8
- "편재",
9
- "정재",
10
- "편관",
11
- "정관",
12
- "편인",
13
- "정인",
14
- ];
15
- // 십신 한자 매핑
16
- export const TEN_GOD_HANJA = {
17
- 비견: "比肩",
18
- 겁재: "劫財",
19
- 식신: "食神",
20
- 상관: "傷官",
21
- 편재: "偏財",
22
- 정재: "正財",
23
- 편관: "偏官",
24
- 정관: "正官",
25
- 편인: "偏印",
26
- 정인: "正印",
3
+ const ELEMENT_DATA = {
4
+ wood: { korean: "", hanja: "木" },
5
+ fire: { korean: "", hanja: "火" },
6
+ earth: { korean: "", hanja: "土" },
7
+ metal: { korean: "", hanja: "金" },
8
+ water: { korean: "", hanja: "水" },
27
9
  };
28
- // 십신 영문 매핑
29
- export const TEN_GOD_ENGLISH = {
30
- 비견: "Companion",
31
- 겁재: "Rob Wealth",
32
- 식신: "Eating God",
33
- 상관: "Hurting Officer",
34
- 편재: "Indirect Wealth",
35
- 정재: "Direct Wealth",
36
- 편관: "Seven Killings",
37
- 정관: "Direct Officer",
38
- 편인: "Indirect Seal",
39
- 정인: "Direct Seal",
10
+ export function getElementLabel(key) {
11
+ const data = ELEMENT_DATA[key];
12
+ return { key, ...data };
13
+ }
14
+ export const TEN_GOD_KEYS = [
15
+ "companion",
16
+ "robWealth",
17
+ "eatingGod",
18
+ "hurtingOfficer",
19
+ "indirectWealth",
20
+ "directWealth",
21
+ "sevenKillings",
22
+ "directOfficer",
23
+ "indirectSeal",
24
+ "directSeal",
25
+ ];
26
+ const TEN_GOD_DATA = {
27
+ companion: { korean: "비견", hanja: "比肩" },
28
+ robWealth: { korean: "겁재", hanja: "劫財" },
29
+ eatingGod: { korean: "식신", hanja: "食神" },
30
+ hurtingOfficer: { korean: "상관", hanja: "傷官" },
31
+ indirectWealth: { korean: "편재", hanja: "偏財" },
32
+ directWealth: { korean: "정재", hanja: "正財" },
33
+ sevenKillings: { korean: "편관", hanja: "偏官" },
34
+ directOfficer: { korean: "정관", hanja: "正官" },
35
+ indirectSeal: { korean: "편인", hanja: "偏印" },
36
+ directSeal: { korean: "정인", hanja: "正印" },
40
37
  };
41
- // 천간별 오행
38
+ export function getTenGodLabel(key) {
39
+ const data = TEN_GOD_DATA[key];
40
+ return { key, ...data };
41
+ }
42
42
  const STEM_ELEMENT = {
43
43
  甲: "wood",
44
44
  乙: "wood",
@@ -51,7 +51,6 @@ const STEM_ELEMENT = {
51
51
  壬: "water",
52
52
  癸: "water",
53
53
  };
54
- // 천간별 음양
55
54
  const STEM_POLARITY = {
56
55
  甲: "yang",
57
56
  乙: "yin",
@@ -64,7 +63,6 @@ const STEM_POLARITY = {
64
63
  壬: "yang",
65
64
  癸: "yin",
66
65
  };
67
- // 지지별 오행
68
66
  const BRANCH_ELEMENT = {
69
67
  子: "water",
70
68
  丑: "earth",
@@ -79,7 +77,6 @@ const BRANCH_ELEMENT = {
79
77
  戌: "earth",
80
78
  亥: "water",
81
79
  };
82
- // 지지별 음양
83
80
  const BRANCH_POLARITY = {
84
81
  子: "yang",
85
82
  丑: "yin",
@@ -94,8 +91,6 @@ const BRANCH_POLARITY = {
94
91
  戌: "yang",
95
92
  亥: "yin",
96
93
  };
97
- // 장간(藏干) - 지지 속에 숨은 천간들
98
- // 순서: [본기(本氣), 중기(中氣)?, 여기(餘氣)?]
99
94
  export const HIDDEN_STEMS = {
100
95
  子: ["癸"],
101
96
  丑: ["己", "癸", "辛"],
@@ -110,8 +105,6 @@ export const HIDDEN_STEMS = {
110
105
  戌: ["戊", "辛", "丁"],
111
106
  亥: ["壬", "甲"],
112
107
  };
113
- // 오행 상생 관계 (A가 B를 생함)
114
- // 목생화, 화생토, 토생금, 금생수, 수생목
115
108
  const GENERATES = {
116
109
  wood: "fire",
117
110
  fire: "earth",
@@ -119,8 +112,6 @@ const GENERATES = {
119
112
  metal: "water",
120
113
  water: "wood",
121
114
  };
122
- // 오행 상극 관계 (A가 B를 극함)
123
- // 목극토, 토극수, 수극화, 화극금, 금극목
124
115
  const CONTROLS = {
125
116
  wood: "earth",
126
117
  earth: "water",
@@ -128,112 +119,77 @@ const CONTROLS = {
128
119
  fire: "metal",
129
120
  metal: "wood",
130
121
  };
131
- /**
132
- * 천간의 오행을 반환
133
- */
134
122
  export function getStemElement(stem) {
135
123
  const element = STEM_ELEMENT[stem];
136
124
  if (!element)
137
125
  throw new Error(`Invalid stem: ${stem}`);
138
126
  return element;
139
127
  }
140
- /**
141
- * 천간의 음양을 반환
142
- */
143
128
  export function getStemPolarity(stem) {
144
129
  const polarity = STEM_POLARITY[stem];
145
130
  if (!polarity)
146
131
  throw new Error(`Invalid stem: ${stem}`);
147
132
  return polarity;
148
133
  }
149
- /**
150
- * 지지의 오행을 반환
151
- */
152
134
  export function getBranchElement(branch) {
153
135
  const element = BRANCH_ELEMENT[branch];
154
136
  if (!element)
155
137
  throw new Error(`Invalid branch: ${branch}`);
156
138
  return element;
157
139
  }
158
- /**
159
- * 지지의 음양을 반환
160
- */
161
140
  export function getBranchPolarity(branch) {
162
141
  const polarity = BRANCH_POLARITY[branch];
163
142
  if (!polarity)
164
143
  throw new Error(`Invalid branch: ${branch}`);
165
144
  return polarity;
166
145
  }
167
- /**
168
- * 지지의 장간(숨은 천간들)을 반환
169
- */
170
146
  export function getHiddenStems(branch) {
171
147
  const hidden = HIDDEN_STEMS[branch];
172
148
  if (!hidden)
173
149
  throw new Error(`Invalid branch: ${branch}`);
174
150
  return [...hidden];
175
151
  }
176
- /**
177
- * 일간(Day Master)과 다른 천간의 관계에서 십신을 판정
178
- * @param dayMaster 일간 (예: "甲")
179
- * @param targetStem 비교 대상 천간
180
- * @returns 십신
181
- */
182
- export function getTenGod(dayMaster, targetStem) {
152
+ export function getTenGodKey(dayMaster, targetStem) {
183
153
  const dmElement = getStemElement(dayMaster);
184
154
  const dmPolarity = getStemPolarity(dayMaster);
185
155
  const targetElement = getStemElement(targetStem);
186
156
  const targetPolarity = getStemPolarity(targetStem);
187
157
  const samePolarity = dmPolarity === targetPolarity;
188
- // 같은 오행
189
158
  if (dmElement === targetElement) {
190
- return samePolarity ? "비견" : "겁재";
159
+ return samePolarity ? "companion" : "robWealth";
191
160
  }
192
- // 내가 생하는 오행 (식상)
193
161
  if (GENERATES[dmElement] === targetElement) {
194
- return samePolarity ? "식신" : "상관";
162
+ return samePolarity ? "eatingGod" : "hurtingOfficer";
195
163
  }
196
- // 내가 극하는 오행 (재성)
197
164
  if (CONTROLS[dmElement] === targetElement) {
198
- return samePolarity ? "편재" : "정재";
165
+ return samePolarity ? "indirectWealth" : "directWealth";
199
166
  }
200
- // 나를 극하는 오행 (관성)
201
167
  if (CONTROLS[targetElement] === dmElement) {
202
- return samePolarity ? "편관" : "정관";
168
+ return samePolarity ? "sevenKillings" : "directOfficer";
203
169
  }
204
- // 나를 생하는 오행 (인성)
205
170
  if (GENERATES[targetElement] === dmElement) {
206
- return samePolarity ? "편인" : "정인";
171
+ return samePolarity ? "indirectSeal" : "directSeal";
207
172
  }
208
173
  throw new Error(`Unable to determine ten god relationship: ${dayMaster} -> ${targetStem}`);
209
174
  }
210
- /**
211
- * 지지에 대한 십신 판정 (본기 기준)
212
- */
213
175
  export function getTenGodForBranch(dayMaster, branch) {
214
176
  const hiddenStems = getHiddenStems(branch);
215
- // 본기( 번째 장간)를 기준으로 판정
216
- return getTenGod(dayMaster, hiddenStems[0]);
177
+ return getTenGodLabel(getTenGodKey(dayMaster, hiddenStems[0]));
217
178
  }
218
- /**
219
- * 지지의 모든 장간에 대한 십신 분석
220
- */
221
179
  export function getTenGodsForBranch(dayMaster, branch) {
222
180
  const hiddenStems = getHiddenStems(branch);
223
181
  const types = ["본기", "중기", "여기"];
224
182
  return hiddenStems.map((stem, i) => ({
225
183
  stem,
226
- tenGod: getTenGod(dayMaster, stem),
184
+ tenGod: getTenGodLabel(getTenGodKey(dayMaster, stem)),
227
185
  type: types[i],
228
186
  }));
229
187
  }
230
- /**
231
- * 사주 팔자에서 십신 분석
232
- * @param yearPillar 연주 (예: "甲子")
233
- * @param monthPillar 월주
234
- * @param dayPillar 일주
235
- * @param hourPillar 시주
236
- */
188
+ const DAY_MASTER_LABEL = {
189
+ key: "dayMaster",
190
+ korean: "일간",
191
+ hanja: "日干",
192
+ };
237
193
  export function analyzeTenGods(yearPillar, monthPillar, dayPillar, hourPillar) {
238
194
  const dayMaster = dayPillar[0];
239
195
  const analyzePillar = (pillar, isDayPillar = false) => {
@@ -241,16 +197,16 @@ export function analyzeTenGods(yearPillar, monthPillar, dayPillar, hourPillar) {
241
197
  const branch = pillar[1];
242
198
  const hiddenStems = getHiddenStems(branch).map((hs) => ({
243
199
  stem: hs,
244
- tenGod: getTenGod(dayMaster, hs),
200
+ tenGod: getTenGodLabel(getTenGodKey(dayMaster, hs)),
245
201
  }));
246
202
  return {
247
203
  stem: {
248
204
  char: stem,
249
- tenGod: isDayPillar ? "일간" : getTenGod(dayMaster, stem),
205
+ tenGod: isDayPillar ? DAY_MASTER_LABEL : getTenGodLabel(getTenGodKey(dayMaster, stem)),
250
206
  },
251
207
  branch: {
252
208
  char: branch,
253
- tenGod: getTenGod(dayMaster, hiddenStems[0].stem),
209
+ tenGod: getTenGodLabel(getTenGodKey(dayMaster, hiddenStems[0].stem)),
254
210
  hiddenStems,
255
211
  },
256
212
  };
@@ -263,28 +219,23 @@ export function analyzeTenGods(yearPillar, monthPillar, dayPillar, hourPillar) {
263
219
  dayMaster,
264
220
  };
265
221
  }
266
- /**
267
- * 십신 통계 (각 십신이 몇 개 있는지)
268
- */
269
222
  export function countTenGods(analysis) {
270
223
  const counts = {
271
- 비견: 0,
272
- 겁재: 0,
273
- 식신: 0,
274
- 상관: 0,
275
- 편재: 0,
276
- 정재: 0,
277
- 편관: 0,
278
- 정관: 0,
279
- 편인: 0,
280
- 정인: 0,
224
+ companion: 0,
225
+ robWealth: 0,
226
+ eatingGod: 0,
227
+ hurtingOfficer: 0,
228
+ indirectWealth: 0,
229
+ directWealth: 0,
230
+ sevenKillings: 0,
231
+ directOfficer: 0,
232
+ indirectSeal: 0,
233
+ directSeal: 0,
281
234
  };
282
- // 천간 십신 카운트 (일간 제외)
283
235
  const stems = [analysis.year.stem, analysis.month.stem, analysis.hour.stem];
284
236
  for (const s of stems) {
285
- counts[s.tenGod]++;
237
+ counts[s.tenGod.key]++;
286
238
  }
287
- // 지지 본기 십신 카운트
288
239
  const branches = [
289
240
  analysis.year.branch,
290
241
  analysis.month.branch,
@@ -292,13 +243,10 @@ export function countTenGods(analysis) {
292
243
  analysis.hour.branch,
293
244
  ];
294
245
  for (const b of branches) {
295
- counts[b.tenGod]++;
246
+ counts[b.tenGod.key]++;
296
247
  }
297
248
  return counts;
298
249
  }
299
- /**
300
- * 오행별 개수 (천간 + 지지 본기)
301
- */
302
250
  export function countElements(analysis) {
303
251
  const counts = {
304
252
  wood: 0,
@@ -307,7 +255,6 @@ export function countElements(analysis) {
307
255
  metal: 0,
308
256
  water: 0,
309
257
  };
310
- // 모든 천간의 오행
311
258
  const stems = [
312
259
  analysis.year.stem.char,
313
260
  analysis.month.stem.char,
@@ -317,7 +264,6 @@ export function countElements(analysis) {
317
264
  for (const s of stems) {
318
265
  counts[getStemElement(s)]++;
319
266
  }
320
- // 모든 지지의 오행
321
267
  const branches = [
322
268
  analysis.year.branch.char,
323
269
  analysis.month.branch.char,
@@ -1,17 +1,17 @@
1
+ import type { Label } from "../types/common";
1
2
  export declare const TWELVE_STAGES: readonly ["longLife", "bathing", "crownBelt", "establishment", "imperial", "decline", "illness", "death", "tomb", "extinction", "conception", "nurturing"];
2
- export type TwelveStage = (typeof TWELVE_STAGES)[number];
3
- export declare function getTwelveStage(stem: string, branch: string): TwelveStage;
3
+ export type TwelveStageKey = (typeof TWELVE_STAGES)[number];
4
+ export type TwelveStageStrength = "strong" | "neutral" | "weak";
5
+ export interface TwelveStageLabel extends Label<TwelveStageKey> {
6
+ meaning: string;
7
+ strength: TwelveStageStrength;
8
+ }
9
+ export declare function getTwelveStageLabel(key: TwelveStageKey): TwelveStageLabel;
4
10
  export interface TwelveStagesResult {
5
- year: TwelveStage;
6
- month: TwelveStage;
7
- day: TwelveStage;
8
- hour: TwelveStage;
11
+ year: TwelveStageLabel;
12
+ month: TwelveStageLabel;
13
+ day: TwelveStageLabel;
14
+ hour: TwelveStageLabel;
9
15
  }
10
16
  export declare function analyzeTwelveStages(yearPillar: string, monthPillar: string, dayPillar: string, hourPillar: string): TwelveStagesResult;
11
- export declare const STAGE_INFO: Record<TwelveStage, {
12
- korean: string;
13
- hanja: string;
14
- meaning: string;
15
- strength: "strong" | "neutral" | "weak";
16
- }>;
17
17
  //# sourceMappingURL=twelve-stages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"twelve-stages.d.ts","sourceRoot":"","sources":["../../src/core/twelve-stages.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,4JAahB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAkBzD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAwBxE;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,WAAW,CAAC;IACnB,GAAG,EAAE,WAAW,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,kBAAkB,CASpB;AAED,eAAO,MAAM,UAAU,EAAE,MAAM,CAC7B,WAAW,EACX;IACE,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;CACzC,CAmBF,CAAC"}
1
+ {"version":3,"file":"twelve-stages.d.ts","sourceRoot":"","sources":["../../src/core/twelve-stages.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,eAAO,MAAM,aAAa,4JAahB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAEhE,MAAM,WAAW,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAyCD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,cAAc,GAAG,gBAAgB,CAGzE;AA4BD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,gBAAgB,CAAC;IACxB,GAAG,EAAE,gBAAgB,CAAC;IACtB,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,kBAAkB,CASpB"}
@@ -27,7 +27,30 @@ const YIN_STEM_BIRTH_BRANCH = {
27
27
  辛: "子",
28
28
  癸: "卯",
29
29
  };
30
- export function getTwelveStage(stem, branch) {
30
+ const STAGE_DATA = {
31
+ longLife: {
32
+ korean: "장생",
33
+ hanja: "長生",
34
+ meaning: "새로운 시작, 성장의 기운",
35
+ strength: "strong",
36
+ },
37
+ bathing: { korean: "목욕", hanja: "沐浴", meaning: "불안정, 변화, 도화", strength: "neutral" },
38
+ crownBelt: { korean: "관대", hanja: "冠帶", meaning: "성장, 준비, 학업", strength: "strong" },
39
+ establishment: { korean: "건록", hanja: "建祿", meaning: "안정, 직업, 녹봉", strength: "strong" },
40
+ imperial: { korean: "제왕", hanja: "帝旺", meaning: "최고 전성기, 권력", strength: "strong" },
41
+ decline: { korean: "쇠", hanja: "衰", meaning: "기운 약화, 후퇴", strength: "weak" },
42
+ illness: { korean: "병", hanja: "病", meaning: "질병, 곤란", strength: "weak" },
43
+ death: { korean: "사", hanja: "死", meaning: "끝, 전환점", strength: "weak" },
44
+ tomb: { korean: "묘", hanja: "墓", meaning: "저장, 숨김, 보관", strength: "neutral" },
45
+ extinction: { korean: "절", hanja: "絶", meaning: "단절, 새로운 국면", strength: "weak" },
46
+ conception: { korean: "태", hanja: "胎", meaning: "잉태, 계획, 구상", strength: "neutral" },
47
+ nurturing: { korean: "양", hanja: "養", meaning: "양육, 준비, 축적", strength: "neutral" },
48
+ };
49
+ export function getTwelveStageLabel(key) {
50
+ const data = STAGE_DATA[key];
51
+ return { key, ...data };
52
+ }
53
+ function getTwelveStageKey(stem, branch) {
31
54
  const isYang = isYangStem(stem);
32
55
  const birthBranch = isYang ? YANG_STEM_BIRTH_BRANCH[stem] : YIN_STEM_BIRTH_BRANCH[stem];
33
56
  if (!birthBranch) {
@@ -50,28 +73,9 @@ export function getTwelveStage(stem, branch) {
50
73
  export function analyzeTwelveStages(yearPillar, monthPillar, dayPillar, hourPillar) {
51
74
  const dayMaster = dayPillar[0];
52
75
  return {
53
- year: getTwelveStage(dayMaster, yearPillar[1]),
54
- month: getTwelveStage(dayMaster, monthPillar[1]),
55
- day: getTwelveStage(dayMaster, dayPillar[1]),
56
- hour: getTwelveStage(dayMaster, hourPillar[1]),
76
+ year: getTwelveStageLabel(getTwelveStageKey(dayMaster, yearPillar[1])),
77
+ month: getTwelveStageLabel(getTwelveStageKey(dayMaster, monthPillar[1])),
78
+ day: getTwelveStageLabel(getTwelveStageKey(dayMaster, dayPillar[1])),
79
+ hour: getTwelveStageLabel(getTwelveStageKey(dayMaster, hourPillar[1])),
57
80
  };
58
81
  }
59
- export const STAGE_INFO = {
60
- longLife: {
61
- korean: "장생",
62
- hanja: "長生",
63
- meaning: "새로운 시작, 성장의 기운",
64
- strength: "strong",
65
- },
66
- bathing: { korean: "목욕", hanja: "沐浴", meaning: "불안정, 변화, 도화", strength: "neutral" },
67
- crownBelt: { korean: "관대", hanja: "冠帶", meaning: "성장, 준비, 학업", strength: "strong" },
68
- establishment: { korean: "건록", hanja: "建祿", meaning: "안정, 직업, 녹봉", strength: "strong" },
69
- imperial: { korean: "제왕", hanja: "帝旺", meaning: "최고 전성기, 권력", strength: "strong" },
70
- decline: { korean: "쇠", hanja: "衰", meaning: "기운 약화, 후퇴", strength: "weak" },
71
- illness: { korean: "병", hanja: "病", meaning: "질병, 곤란", strength: "weak" },
72
- death: { korean: "사", hanja: "死", meaning: "끝, 전환점", strength: "weak" },
73
- tomb: { korean: "묘", hanja: "墓", meaning: "저장, 숨김, 보관", strength: "neutral" },
74
- extinction: { korean: "절", hanja: "絶", meaning: "단절, 새로운 국면", strength: "weak" },
75
- conception: { korean: "태", hanja: "胎", meaning: "잉태, 계획, 구상", strength: "neutral" },
76
- nurturing: { korean: "양", hanja: "養", meaning: "양육, 준비, 축적", strength: "neutral" },
77
- };
@@ -1,16 +1,25 @@
1
- import { type Element } from "./ten-gods";
2
- export type YongShenMethod = "격국" | "억부" | "조후" | "통관" | "병약";
1
+ import { type Element, type ElementLabel } from "./ten-gods";
2
+ export type YongShenMethodKey = "formation" | "balance" | "climate" | "bridge" | "disease";
3
+ export interface YongShenMethodLabel extends Label<YongShenMethodKey> {
4
+ }
5
+ export declare function getYongShenMethodLabel(key: YongShenMethodKey): YongShenMethodLabel;
3
6
  export interface YongShenResult {
4
- primary: Element;
5
- secondary: Element | null;
6
- method: YongShenMethod;
7
+ primary: ElementLabel;
8
+ secondary: ElementLabel | null;
9
+ method: YongShenMethodLabel;
7
10
  reasoning: string;
8
11
  allElements: Record<Element, {
9
12
  isYongShen: boolean;
10
13
  isKiShen: boolean;
11
14
  }>;
12
- johuAdjustment: Element | null;
15
+ johuAdjustment: ElementLabel | null;
16
+ /** 종격 성립 시 억부 기준 용신도 함께 제공 */
17
+ alternativeBalance?: {
18
+ primary: ElementLabel;
19
+ secondary: ElementLabel | null;
20
+ };
13
21
  }
22
+ import type { Label } from "../types";
14
23
  export declare function analyzeYongShen(yearPillar: string, monthPillar: string, dayPillar: string, hourPillar: string): YongShenResult;
15
24
  export declare function getElementRecommendations(yongShen: YongShenResult): {
16
25
  colors: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"yongshen.d.ts","sourceRoot":"","sources":["../../src/core/yongshen.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,OAAO,EAAoC,MAAM,YAAY,CAAC;AAEtF,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzE,cAAc,EAAE,OAAO,GAAG,IAAI,CAAC;CAChC;AAmJD,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,cAAc,CA+EhB;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,cAAc,GAAG;IACnE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CA0BA"}
1
+ {"version":3,"file":"yongshen.d.ts","sourceRoot":"","sources":["../../src/core/yongshen.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,YAAY,EAIlB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE3F,MAAM,WAAW,mBAAoB,SAAQ,KAAK,CAAC,iBAAiB,CAAC;CAAG;AAUxE,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,iBAAiB,GAAG,mBAAmB,CAGlF;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzE,cAAc,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,8BAA8B;IAC9B,kBAAkB,CAAC,EAAE;QACnB,OAAO,EAAE,YAAY,CAAC;QACtB,SAAS,EAAE,YAAY,GAAG,IAAI,CAAC;KAChC,CAAC;CACH;AAED,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AA0JrC,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,cAAc,CA2FhB;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,cAAc,GAAG;IACnE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CA0BA"}
@@ -1,5 +1,16 @@
1
1
  import { analyzeStrength } from "./strength";
2
- import { ELEMENTS, getBranchElement, getStemElement } from "./ten-gods";
2
+ import { ELEMENTS, getBranchElement, getElementLabel, getStemElement, } from "./ten-gods";
3
+ const YONGSHEN_METHOD_DATA = {
4
+ formation: { korean: "격국", hanja: "格局" },
5
+ balance: { korean: "억부", hanja: "抑扶" },
6
+ climate: { korean: "조후", hanja: "調候" },
7
+ bridge: { korean: "통관", hanja: "通關" },
8
+ disease: { korean: "병약", hanja: "病藥" },
9
+ };
10
+ export function getYongShenMethodLabel(key) {
11
+ const data = YONGSHEN_METHOD_DATA[key];
12
+ return { key, ...data };
13
+ }
3
14
  const SEASON_MONTH_BRANCHES = {
4
15
  spring: ["寅", "卯", "辰"],
5
16
  summer: ["巳", "午", "未"],
@@ -72,10 +83,18 @@ const CONTROLLED_BY = {
72
83
  metal: "fire",
73
84
  wood: "metal",
74
85
  };
75
- function getYokbuYongShen(dayMasterElement, strengthLevel) {
76
- const isStrong = ["신강", "태강", "극왕", "중화신강"].includes(strengthLevel);
77
- if (isStrong) {
78
- const primary = CONTROLS[dayMasterElement];
86
+ const STRONG_LEVEL_KEYS = [
87
+ "strong",
88
+ "veryStrong",
89
+ "extremelyStrong",
90
+ "neutralStrong",
91
+ ];
92
+ function isStrongLevel(level) {
93
+ return STRONG_LEVEL_KEYS.includes(level.key);
94
+ }
95
+ function getYokbuYongShen(dayMasterElement, level) {
96
+ if (isStrongLevel(level)) {
97
+ const primary = CONTROLLED_BY[dayMasterElement];
79
98
  const secondary = GENERATES[dayMasterElement];
80
99
  return { primary, secondary };
81
100
  }
@@ -83,9 +102,8 @@ function getYokbuYongShen(dayMasterElement, strengthLevel) {
83
102
  const secondary = dayMasterElement;
84
103
  return { primary, secondary };
85
104
  }
86
- function hasSpecialFormation(dayMasterElement, strengthLevel, allElements) {
87
- const _isExtreme = ["극약", "극왕"].includes(strengthLevel);
88
- if (strengthLevel === "극약") {
105
+ function hasSpecialFormation(dayMasterElement, level, allElements) {
106
+ if (level.key === "extremelyWeak") {
89
107
  const elementCounts = {
90
108
  wood: 0,
91
109
  fire: 0,
@@ -127,32 +145,35 @@ export function analyzeYongShen(yearPillar, monthPillar, dayPillar, hourPillar)
127
145
  const allBranches = [yearPillar[1], monthPillar[1], dayPillar[1], hourPillar[1]];
128
146
  const allBranchElements = allBranches.map((b) => getBranchElement(b));
129
147
  const specialFormation = hasSpecialFormation(dayMasterElement, strength.level, allBranchElements);
130
- let primary;
131
- let secondary = null;
132
- let method;
148
+ let primaryKey;
149
+ let secondaryKey = null;
150
+ let methodKey;
133
151
  let reasoning;
134
- let johuAdjustment = null;
152
+ let johuAdjustmentKey = null;
153
+ let alternativeBalance;
135
154
  if (specialFormation.isSpecial && specialFormation.followElement) {
136
- primary = specialFormation.followElement;
137
- secondary = GENERATES[specialFormation.followElement];
138
- method = "격국";
139
- reasoning = `${specialFormation.type} 성립. ${specialFormation.followElement} 세력을 따름`;
155
+ primaryKey = specialFormation.followElement;
156
+ secondaryKey = GENERATES[specialFormation.followElement];
157
+ methodKey = "formation";
158
+ reasoning = `종격 성립. ${getElementLabel(specialFormation.followElement).korean} 세력을 따름`;
159
+ const yokbu = getYokbuYongShen(dayMasterElement, strength.level);
160
+ alternativeBalance = { primary: yokbu.primary, secondary: yokbu.secondary };
140
161
  }
141
162
  else {
142
163
  const yokbu = getYokbuYongShen(dayMasterElement, strength.level);
143
- primary = yokbu.primary;
144
- secondary = yokbu.secondary;
145
- method = "억부";
146
- const isStrong = ["신강", "태강", "극왕", "중화신강"].includes(strength.level);
147
- if (isStrong) {
148
- reasoning = `${strength.level} 상태로 설기(洩氣) 필요. ${primary}로 기운을 발산`;
164
+ primaryKey = yokbu.primary;
165
+ secondaryKey = yokbu.secondary;
166
+ methodKey = "balance";
167
+ const strong = isStrongLevel(strength.level);
168
+ if (strong) {
169
+ reasoning = `${strength.level.korean} 상태로 설기(洩氣) 필요. ${getElementLabel(primaryKey).korean}로 기운을 발산`;
149
170
  }
150
171
  else {
151
- reasoning = `${strength.level} 상태로 부조(扶助) 필요. ${primary}로 일간을 생조`;
172
+ reasoning = `${strength.level.korean} 상태로 부조(扶助) 필요. ${getElementLabel(primaryKey).korean}로 일간을 생조`;
152
173
  }
153
- johuAdjustment = getJohuAdjustment(dayMasterElement, season, primary);
154
- if (johuAdjustment) {
155
- reasoning += `. 조후 보정: ${season} 계절에 ${johuAdjustment} 참고`;
174
+ johuAdjustmentKey = getJohuAdjustment(dayMasterElement, season, primaryKey);
175
+ if (johuAdjustmentKey) {
176
+ reasoning += `. 조후 보정: ${season} 계절에 ${getElementLabel(johuAdjustmentKey).korean} 참고`;
156
177
  }
157
178
  }
158
179
  const allElements = {
@@ -162,12 +183,12 @@ export function analyzeYongShen(yearPillar, monthPillar, dayPillar, hourPillar)
162
183
  metal: { isYongShen: false, isKiShen: false },
163
184
  water: { isYongShen: false, isKiShen: false },
164
185
  };
165
- allElements[primary].isYongShen = true;
166
- if (secondary)
167
- allElements[secondary].isYongShen = true;
168
- const isStrong = ["신강", "태강", "극왕", "중화신강"].includes(strength.level);
169
- if (method !== "격국") {
170
- if (isStrong) {
186
+ allElements[primaryKey].isYongShen = true;
187
+ if (secondaryKey)
188
+ allElements[secondaryKey].isYongShen = true;
189
+ const strong = isStrongLevel(strength.level);
190
+ if (methodKey !== "formation") {
191
+ if (strong) {
171
192
  allElements[dayMasterElement].isKiShen = true;
172
193
  allElements[GENERATED_BY[dayMasterElement]].isKiShen = true;
173
194
  }
@@ -182,12 +203,20 @@ export function analyzeYongShen(yearPillar, monthPillar, dayPillar, hourPillar)
182
203
  }
183
204
  }
184
205
  return {
185
- primary,
186
- secondary,
187
- method,
206
+ primary: getElementLabel(primaryKey),
207
+ secondary: secondaryKey ? getElementLabel(secondaryKey) : null,
208
+ method: getYongShenMethodLabel(methodKey),
188
209
  reasoning,
189
210
  allElements,
190
- johuAdjustment,
211
+ johuAdjustment: johuAdjustmentKey ? getElementLabel(johuAdjustmentKey) : null,
212
+ alternativeBalance: alternativeBalance
213
+ ? {
214
+ primary: getElementLabel(alternativeBalance.primary),
215
+ secondary: alternativeBalance.secondary
216
+ ? getElementLabel(alternativeBalance.secondary)
217
+ : null,
218
+ }
219
+ : undefined,
191
220
  };
192
221
  }
193
222
  export function getElementRecommendations(yongShen) {
@@ -198,12 +227,12 @@ export function getElementRecommendations(yongShen) {
198
227
  metal: { colors: ["백색", "금색"], direction: "서", numbers: [4, 9] },
199
228
  water: { colors: ["흑색", "남색"], direction: "북", numbers: [1, 6] },
200
229
  };
201
- const primary = elementData[yongShen.primary];
230
+ const primary = elementData[yongShen.primary.key];
202
231
  const colors = [...primary.colors];
203
232
  const directions = [primary.direction];
204
233
  const numbers = [...primary.numbers];
205
234
  if (yongShen.secondary) {
206
- const secondary = elementData[yongShen.secondary];
235
+ const secondary = elementData[yongShen.secondary.key];
207
236
  colors.push(...secondary.colors);
208
237
  directions.push(secondary.direction);
209
238
  numbers.push(...secondary.numbers);