@orrery/core 0.3.0 → 0.4.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.
@@ -3,19 +3,28 @@ import {
3
3
  BRANCH_BREAKS,
4
4
  BRANCH_CLASHES,
5
5
  BRANCH_COMBINES_6,
6
+ BRANCH_GWIMUN,
6
7
  BRANCH_HARMS,
7
8
  BRANCH_PUNISHMENTS,
8
9
  BRANCH_SELF_PUNISHMENTS,
10
+ BRANCH_WONJIN,
11
+ CHEONDUK_MAP,
12
+ CHEONUL_MAP,
9
13
  DIRECTIONAL_COMPOSES,
10
14
  DIRECTIONAL_COMPOSE_ELEMENTS,
15
+ DOHWA_MAP,
11
16
  EARTH,
12
17
  EARTH_KR,
18
+ GEUMYEO_MAP,
13
19
  GOEGANG_PILLARS,
20
+ GONGMANG_TABLE,
14
21
  HALF_COMPOSES,
15
22
  HGANJI,
23
+ HONGYEOM_PILLARS,
16
24
  JIJANGGAN,
17
25
  METEORS_12,
18
26
  METEOR_LOOKUP,
27
+ MUNCHANG_MAP,
19
28
  PILLAR_NAMES,
20
29
  RELATIONS,
21
30
  SKY,
@@ -26,9 +35,10 @@ import {
26
35
  STEM_INFO,
27
36
  TRIPLE_COMPOSES,
28
37
  TRIPLE_COMPOSE_ELEMENTS,
38
+ WOLDUK_MAP,
29
39
  YANGGAN,
30
40
  YANGIN_MAP
31
- } from "./chunk-VJDUZB5T.js";
41
+ } from "./chunk-EXYPMSUR.js";
32
42
 
33
43
  // src/pillars.ts
34
44
  function div(a, b) {
@@ -253,7 +263,7 @@ function dateFromMinutes(tmin, uyear, umonth, uday, uhour, umin) {
253
263
  }
254
264
  return [y1, mo1, d1, h1, mi1];
255
265
  }
256
- function calcPillarIndices(year, month, day, hour, min) {
266
+ function calcPillarIndices(year, month, day, hour, min, jasiMethod) {
257
267
  const displ2min = minutesBetween(
258
268
  UNIT.year,
259
269
  UNIT.month,
@@ -325,11 +335,16 @@ function calcPillarIndices(year, month, day, hour, min) {
325
335
  } else if (hour === 21 && min >= 30 || hour === 22 || hour === 23 && min < 30) {
326
336
  i = 11;
327
337
  } else {
328
- so24day += 1;
329
- if (so24day === 60) so24day = 0;
330
338
  i = 0;
339
+ const method = jasiMethod ?? "unified";
340
+ if (method === "unified") {
341
+ so24day += 1;
342
+ if (so24day === 60) so24day = 0;
343
+ }
331
344
  }
332
- t = so24day % 10;
345
+ const isYajasi = i === 0 && hour === 23 && jasiMethod === "split";
346
+ const dayForHour = isYajasi ? (so24day + 1) % 60 : so24day;
347
+ t = dayForHour % 10;
333
348
  t = t % 5;
334
349
  t = t * 12 + i;
335
350
  const so24hour = t;
@@ -407,12 +422,12 @@ function calcSolarTerms(year, month, day, hour, min) {
407
422
  outgiMin
408
423
  };
409
424
  }
410
- function getFourPillars(year, month, day, hour, minute) {
411
- const [, y, m, d, h] = calcPillarIndices(year, month, day, hour, minute);
425
+ function getFourPillars(year, month, day, hour, minute, jasiMethod) {
426
+ const [, y, m, d, h] = calcPillarIndices(year, month, day, hour, minute, jasiMethod);
412
427
  return [HGANJI[y], HGANJI[m], HGANJI[d], HGANJI[h]];
413
428
  }
414
- function getDaewoon(isMale, year, month, day, hour, minute) {
415
- const [, sy, sm] = calcPillarIndices(year, month, day, hour, minute);
429
+ function getDaewoon(isMale, year, month, day, hour, minute, jasiMethod) {
430
+ const [, sy, sm] = calcPillarIndices(year, month, day, hour, minute, jasiMethod);
416
431
  const yearStem = HGANJI[sy][0];
417
432
  const isYangGan = YANGGAN.includes(yearStem);
418
433
  const order = isMale && isYangGan || !isMale && !isYangGan;
@@ -512,6 +527,62 @@ function getTwelveSpirit(yearBranch, targetBranch) {
512
527
  const offset = ((targetIdx - start) % 12 + 12) % 12;
513
528
  return SPIRITS_12[offset].hanja;
514
529
  }
530
+ var YANG_STEM_OF = {
531
+ tree: "\u7532",
532
+ fire: "\u4E19",
533
+ earth: "\u620A",
534
+ metal: "\u5E9A",
535
+ water: "\u58EC"
536
+ };
537
+ var SIPSIN_CATEGORIES = [
538
+ { name: "\u6BD4\u52AB", interactions: ["same"] },
539
+ { name: "\u98DF\u50B7", interactions: ["output"] },
540
+ { name: "\u8CA1\u661F", interactions: ["sword"] },
541
+ { name: "\u5B98\u661F", interactions: ["shield"] },
542
+ { name: "\u5370\u661F", interactions: ["input"] }
543
+ ];
544
+ function calculateJwabeop(dayStem, branches, dayBranch) {
545
+ return branches.map((branch) => {
546
+ const hidden = getHiddenStems(branch).replace(/ /g, "");
547
+ return [...hidden].map((stem) => {
548
+ const rel = getRelation(dayStem, stem);
549
+ const sipsin = rel ? rel.hanja : "?";
550
+ const unseong = getTwelveMeteor(stem, dayBranch);
551
+ return { stem, sipsin, unseong };
552
+ });
553
+ });
554
+ }
555
+ function calculateInjongbeop(dayStem, dayBranch) {
556
+ const dayInfo = STEM_INFO[dayStem];
557
+ if (!dayInfo) return [];
558
+ const hidden = getHiddenStems(dayBranch).replace(/ /g, "");
559
+ const presentInteractions = /* @__PURE__ */ new Set();
560
+ for (const stem of hidden) {
561
+ const info = STEM_INFO[stem];
562
+ if (!info) continue;
563
+ const interaction = getInteraction(dayInfo.element, info.element);
564
+ if (interaction) presentInteractions.add(interaction);
565
+ }
566
+ const result = [];
567
+ for (const cat of SIPSIN_CATEGORIES) {
568
+ const missing = cat.interactions.every((i) => !presentInteractions.has(i));
569
+ if (!missing) continue;
570
+ let targetElement = null;
571
+ for (const [el, info] of Object.entries(STEM_INFO)) {
572
+ if (info.yinyang !== "+") continue;
573
+ const inter = getInteraction(dayInfo.element, info.element);
574
+ if (inter && cat.interactions.includes(inter)) {
575
+ targetElement = info.element;
576
+ break;
577
+ }
578
+ }
579
+ if (!targetElement) continue;
580
+ const yangStem = YANG_STEM_OF[targetElement];
581
+ const unseong = getTwelveMeteor(yangStem, dayBranch);
582
+ result.push({ category: cat.name, yangStem, unseong });
583
+ }
584
+ return result;
585
+ }
515
586
  function lookupPair(table, a, b) {
516
587
  return table[`${a},${b}`] ?? table[`${b},${a}`];
517
588
  }
@@ -547,6 +618,10 @@ function getBranchRelation(branch1, branch2) {
547
618
  if (branch1 === branch2 && BRANCH_SELF_PUNISHMENTS.has(branch1)) {
548
619
  results.push({ type: "\u5211", detail: "\u81EA\u5211" });
549
620
  }
621
+ const wonjin = lookupPair(BRANCH_WONJIN, branch1, branch2);
622
+ if (wonjin) results.push({ type: wonjin, detail: null });
623
+ const gwimun = lookupPair(BRANCH_GWIMUN, branch1, branch2);
624
+ if (gwimun) results.push({ type: gwimun, detail: null });
550
625
  return results;
551
626
  }
552
627
  function analyzePillarRelations(pillar1, pillar2) {
@@ -594,18 +669,66 @@ function analyzeAllRelations(pillars) {
594
669
  directional: checkDirectionalCompose(branches)
595
670
  };
596
671
  }
597
- function getSpecialSals(dayStem, dayPillar, branches) {
672
+ function getSpecialSals(stems, branches, dayPillar) {
673
+ const dayStem = stems[1];
674
+ const dayBranch = branches[1];
675
+ const monthBranch = branches[2];
598
676
  const yanginBranch = YANGIN_MAP[dayStem];
599
677
  const yangin = yanginBranch ? branches.reduce((acc, b, i) => {
600
678
  if (b === yanginBranch) acc.push(i);
601
679
  return acc;
602
680
  }, []) : [];
681
+ const dohwaBranch = DOHWA_MAP[dayBranch];
682
+ const dohwa = dohwaBranch ? branches.reduce((acc, b, i) => {
683
+ if (i !== 1 && b === dohwaBranch) acc.push(i);
684
+ return acc;
685
+ }, []) : [];
686
+ const cheonulBranches = CHEONUL_MAP[dayStem] ?? [];
687
+ const cheonul = branches.reduce((acc, b, i) => {
688
+ if (cheonulBranches.includes(b)) acc.push(i);
689
+ return acc;
690
+ }, []);
691
+ const cheondukChar = CHEONDUK_MAP[monthBranch];
692
+ const cheonduk = cheondukChar ? [...stems, ...branches].reduce((acc, ch, i) => {
693
+ if (ch === cheondukChar) acc.push(i % 4);
694
+ return acc;
695
+ }, []).filter((v, i, a) => a.indexOf(v) === i) : [];
696
+ const woldukChar = WOLDUK_MAP[monthBranch];
697
+ const wolduk = woldukChar ? stems.reduce((acc, s, i) => {
698
+ if (s === woldukChar) acc.push(i);
699
+ return acc;
700
+ }, []) : [];
701
+ const munchangBranch = MUNCHANG_MAP[dayStem];
702
+ const munchang = munchangBranch ? branches.reduce((acc, b, i) => {
703
+ if (b === munchangBranch) acc.push(i);
704
+ return acc;
705
+ }, []) : [];
706
+ const geumyeoBranch = GEUMYEO_MAP[dayStem];
707
+ const geumyeo = geumyeoBranch ? branches.reduce((acc, b, i) => {
708
+ if (b === geumyeoBranch) acc.push(i);
709
+ return acc;
710
+ }, []) : [];
603
711
  return {
604
712
  yangin,
605
713
  baekho: BAEKHO_PILLARS.has(dayPillar),
606
- goegang: GOEGANG_PILLARS.has(dayPillar)
714
+ goegang: GOEGANG_PILLARS.has(dayPillar),
715
+ dohwa,
716
+ cheonul,
717
+ cheonduk,
718
+ wolduk,
719
+ munchang,
720
+ hongyeom: HONGYEOM_PILLARS.has(dayPillar),
721
+ geumyeo
607
722
  };
608
723
  }
724
+ function getYearGanzi(year) {
725
+ return HGANJI[((12 + (year - 1996)) % 60 + 60) % 60];
726
+ }
727
+ function getGongmang(dayGanzi) {
728
+ const idx = HGANJI.indexOf(dayGanzi);
729
+ if (idx < 0) return ["", ""];
730
+ return GONGMANG_TABLE[Math.trunc(idx / 10)];
731
+ }
609
732
  var IMPORTANT_RELATIONS = /* @__PURE__ */ new Set(["\u5408", "\u6C96", "\u5211"]);
610
733
  function findTransits(natalPillars, months = 1, backward = false) {
611
734
  const results = [];
@@ -687,6 +810,8 @@ export {
687
810
  toHangul,
688
811
  getTwelveMeteor,
689
812
  getTwelveSpirit,
813
+ calculateJwabeop,
814
+ calculateInjongbeop,
690
815
  getStemRelation,
691
816
  getBranchRelation,
692
817
  analyzePillarRelations,
@@ -694,5 +819,7 @@ export {
694
819
  checkDirectionalCompose,
695
820
  analyzeAllRelations,
696
821
  getSpecialSals,
822
+ getYearGanzi,
823
+ getGongmang,
697
824
  findTransits
698
825
  };
@@ -41832,7 +41832,8 @@ var PLANET_SYMBOLS = {
41832
41832
  Pluto: "\u2647",
41833
41833
  Chiron: "\u26B7",
41834
41834
  NorthNode: "\u260A",
41835
- SouthNode: "\u260B"
41835
+ SouthNode: "\u260B",
41836
+ Fortuna: "\u2295"
41836
41837
  };
41837
41838
  var PLANET_KO = {
41838
41839
  Sun: "\uD0DC\uC591",
@@ -41847,7 +41848,8 @@ var PLANET_KO = {
41847
41848
  Pluto: "\uBA85\uC655\uC131",
41848
41849
  Chiron: "\uD0A4\uB860",
41849
41850
  NorthNode: "\uBD81\uAD50\uC810",
41850
- SouthNode: "\uB0A8\uAD50\uC810"
41851
+ SouthNode: "\uB0A8\uAD50\uC810",
41852
+ Fortuna: "\uD589\uC6B4\uC810"
41851
41853
  };
41852
41854
  var PLANET_BODIES = [
41853
41855
  ["Sun", 0],
@@ -41972,14 +41974,17 @@ function calculateAspects(planets) {
41972
41974
  async function calculateNatal(input, houseSystem = "P") {
41973
41975
  const lat = input.latitude ?? DEFAULT_LAT;
41974
41976
  const lon = input.longitude ?? DEFAULT_LON;
41977
+ const unknownTime = !!input.unknownTime;
41978
+ const hour = unknownTime ? 12 : input.hour;
41979
+ const minute = unknownTime ? 0 : input.minute;
41975
41980
  const offsetHours = getSeoulUtcOffsetHours(
41976
41981
  input.year,
41977
41982
  input.month,
41978
41983
  input.day,
41979
- input.hour,
41980
- input.minute
41984
+ hour,
41985
+ minute
41981
41986
  );
41982
- const utHourDecimal = input.hour + input.minute / 60 - offsetHours;
41987
+ const utHourDecimal = hour + minute / 60 - offsetHours;
41983
41988
  let utYear = input.year;
41984
41989
  let utMonth = input.month;
41985
41990
  let utDay = input.day;
@@ -41998,7 +42003,13 @@ async function calculateNatal(input, houseSystem = "P") {
41998
42003
  utDay = d.getDate();
41999
42004
  }
42000
42005
  const jd = julday2(utYear, utMonth, utDay, utHour);
42001
- const { cusps, ascmc } = calcHouses(jd, lat, lon, houseSystem);
42006
+ let cusps = null;
42007
+ let ascmc = null;
42008
+ if (!unknownTime) {
42009
+ const houseResult = calcHouses(jd, lat, lon, houseSystem);
42010
+ cusps = Array.from(houseResult.cusps);
42011
+ ascmc = Array.from(houseResult.ascmc);
42012
+ }
42002
42013
  const planets = [];
42003
42014
  for (const [id, bodyNum] of PLANET_BODIES) {
42004
42015
  const pos = calcPlanet(jd, bodyNum);
@@ -42010,7 +42021,7 @@ async function calculateNatal(input, houseSystem = "P") {
42010
42021
  sign: lonToSign(pos.longitude),
42011
42022
  degreeInSign: degreeInSign(pos.longitude),
42012
42023
  isRetrograde: pos.longitudeSpeed < 0,
42013
- house: findHouse(pos.longitude, cusps)
42024
+ ...cusps ? { house: findHouse(pos.longitude, cusps) } : {}
42014
42025
  });
42015
42026
  }
42016
42027
  const northNode = planets.find((p) => p.id === "NorthNode");
@@ -42023,29 +42034,51 @@ async function calculateNatal(input, houseSystem = "P") {
42023
42034
  sign: lonToSign(southLon),
42024
42035
  degreeInSign: degreeInSign(southLon),
42025
42036
  isRetrograde: false,
42026
- house: findHouse(southLon, cusps)
42037
+ ...cusps ? { house: findHouse(southLon, cusps) } : {}
42027
42038
  });
42028
- const houses = [];
42029
- for (let i = 1; i <= 12; i++) {
42030
- const cuspLon = cusps[i];
42031
- houses.push({
42032
- number: i,
42033
- cuspLongitude: cuspLon,
42034
- sign: lonToSign(cuspLon),
42035
- degreeInSign: degreeInSign(cuspLon)
42039
+ if (ascmc) {
42040
+ const ascLon = ascmc[0];
42041
+ const sun = planets.find((p) => p.id === "Sun");
42042
+ const moon = planets.find((p) => p.id === "Moon");
42043
+ const isDayChart = sun.house >= 7;
42044
+ const fortunaLon = isDayChart ? normalizeDeg(ascLon + moon.longitude - sun.longitude) : normalizeDeg(ascLon + sun.longitude - moon.longitude);
42045
+ planets.push({
42046
+ id: "Fortuna",
42047
+ longitude: fortunaLon,
42048
+ latitude: 0,
42049
+ speed: 0,
42050
+ sign: lonToSign(fortunaLon),
42051
+ degreeInSign: degreeInSign(fortunaLon),
42052
+ isRetrograde: false,
42053
+ house: findHouse(fortunaLon, cusps)
42036
42054
  });
42037
42055
  }
42038
- const ascLon = ascmc[0];
42039
- const mcLon = ascmc[1];
42040
- const descLon = normalizeDeg(ascLon + 180);
42041
- const icLon = normalizeDeg(mcLon + 180);
42042
- const angles = {
42043
- asc: { longitude: ascLon, sign: lonToSign(ascLon), degreeInSign: degreeInSign(ascLon) },
42044
- mc: { longitude: mcLon, sign: lonToSign(mcLon), degreeInSign: degreeInSign(mcLon) },
42045
- desc: { longitude: descLon, sign: lonToSign(descLon), degreeInSign: degreeInSign(descLon) },
42046
- ic: { longitude: icLon, sign: lonToSign(icLon), degreeInSign: degreeInSign(icLon) }
42047
- };
42048
- const aspectPlanets = planets.filter((p) => p.id !== "SouthNode");
42056
+ const houses = [];
42057
+ if (cusps) {
42058
+ for (let i = 1; i <= 12; i++) {
42059
+ const cuspLon = cusps[i];
42060
+ houses.push({
42061
+ number: i,
42062
+ cuspLongitude: cuspLon,
42063
+ sign: lonToSign(cuspLon),
42064
+ degreeInSign: degreeInSign(cuspLon)
42065
+ });
42066
+ }
42067
+ }
42068
+ let angles = null;
42069
+ if (ascmc) {
42070
+ const ascLon = ascmc[0];
42071
+ const mcLon = ascmc[1];
42072
+ const descLon = normalizeDeg(ascLon + 180);
42073
+ const icLon = normalizeDeg(mcLon + 180);
42074
+ angles = {
42075
+ asc: { longitude: ascLon, sign: lonToSign(ascLon), degreeInSign: degreeInSign(ascLon) },
42076
+ mc: { longitude: mcLon, sign: lonToSign(mcLon), degreeInSign: degreeInSign(mcLon) },
42077
+ desc: { longitude: descLon, sign: lonToSign(descLon), degreeInSign: degreeInSign(descLon) },
42078
+ ic: { longitude: icLon, sign: lonToSign(icLon), degreeInSign: degreeInSign(icLon) }
42079
+ };
42080
+ }
42081
+ const aspectPlanets = planets.filter((p) => p.id !== "SouthNode" && p.id !== "Fortuna");
42049
42082
  const aspects = calculateAspects(aspectPlanets);
42050
42083
  return { input, planets, houses, angles, aspects };
42051
42084
  }
@@ -47,60 +47,75 @@ function matchChosung(name, query) {
47
47
  }
48
48
  var KOREAN_CITIES = [
49
49
  // 특별/광역시
50
- { name: "\uC11C\uC6B8", lat: 37.5665, lon: 126.978 },
51
- { name: "\uBD80\uC0B0", lat: 35.1796, lon: 129.0756 },
52
- { name: "\uC778\uCC9C", lat: 37.4563, lon: 126.7052 },
53
- { name: "\uB300\uAD6C", lat: 35.8714, lon: 128.6014 },
54
- { name: "\uB300\uC804", lat: 36.3504, lon: 127.3845 },
55
- { name: "\uAD11\uC8FC", lat: 35.1595, lon: 126.8526 },
56
- { name: "\uC6B8\uC0B0", lat: 35.5384, lon: 129.3114 },
57
- { name: "\uC138\uC885", lat: 36.48, lon: 127.259 },
50
+ { name: "\uC11C\uC6B8", region: "\uC11C\uC6B8\uD2B9\uBCC4\uC2DC", lat: 37.5665, lon: 126.978 },
51
+ { name: "\uBD80\uC0B0", region: "\uBD80\uC0B0\uAD11\uC5ED\uC2DC", lat: 35.1796, lon: 129.0756 },
52
+ { name: "\uC778\uCC9C", region: "\uC778\uCC9C\uAD11\uC5ED\uC2DC", lat: 37.4563, lon: 126.7052 },
53
+ { name: "\uB300\uAD6C", region: "\uB300\uAD6C\uAD11\uC5ED\uC2DC", lat: 35.8714, lon: 128.6014 },
54
+ { name: "\uB300\uC804", region: "\uB300\uC804\uAD11\uC5ED\uC2DC", lat: 36.3504, lon: 127.3845 },
55
+ { name: "\uAD11\uC8FC", region: "\uAD11\uC8FC\uAD11\uC5ED\uC2DC", lat: 35.1595, lon: 126.8526 },
56
+ { name: "\uC6B8\uC0B0", region: "\uC6B8\uC0B0\uAD11\uC5ED\uC2DC", lat: 35.5384, lon: 129.3114 },
57
+ { name: "\uC138\uC885", region: "\uC138\uC885\uD2B9\uBCC4\uC790\uCE58\uC2DC", lat: 36.48, lon: 127.259 },
58
58
  // 경기도
59
- { name: "\uC218\uC6D0", lat: 37.2636, lon: 127.0286 },
60
- { name: "\uACE0\uC591", lat: 37.6584, lon: 126.832 },
61
- { name: "\uC6A9\uC778", lat: 37.2411, lon: 127.1776 },
62
- { name: "\uC131\uB0A8", lat: 37.4386, lon: 127.1378 },
63
- { name: "\uBD80\uCC9C", lat: 37.5034, lon: 126.766 },
64
- { name: "\uC548\uC0B0", lat: 37.3219, lon: 126.8309 },
65
- { name: "\uC548\uC591", lat: 37.3943, lon: 126.9568 },
66
- { name: "\uB0A8\uC591\uC8FC", lat: 37.636, lon: 127.2165 },
67
- { name: "\uD654\uC131", lat: 37.1996, lon: 126.8312 },
68
- { name: "\uD3C9\uD0DD", lat: 36.9921, lon: 127.0857 },
69
- { name: "\uC758\uC815\uBD80", lat: 37.7381, lon: 127.0338 },
70
- { name: "\uC2DC\uD765", lat: 37.3801, lon: 126.8032 },
71
- { name: "\uD30C\uC8FC", lat: 37.759, lon: 126.7802 },
72
- { name: "\uAE40\uD3EC", lat: 37.6153, lon: 126.7156 },
73
- { name: "\uAD11\uBA85", lat: 37.4786, lon: 126.8646 },
74
- { name: "\uC774\uCC9C", lat: 37.272, lon: 127.435 },
59
+ { name: "\uC218\uC6D0", region: "\uACBD\uAE30\uB3C4", lat: 37.2636, lon: 127.0286 },
60
+ { name: "\uACE0\uC591", region: "\uACBD\uAE30\uB3C4", lat: 37.6584, lon: 126.832 },
61
+ { name: "\uC6A9\uC778", region: "\uACBD\uAE30\uB3C4", lat: 37.2411, lon: 127.1776 },
62
+ { name: "\uC131\uB0A8", region: "\uACBD\uAE30\uB3C4", lat: 37.4386, lon: 127.1378 },
63
+ { name: "\uBD80\uCC9C", region: "\uACBD\uAE30\uB3C4", lat: 37.5034, lon: 126.766 },
64
+ { name: "\uC548\uC0B0", region: "\uACBD\uAE30\uB3C4", lat: 37.3219, lon: 126.8309 },
65
+ { name: "\uC548\uC591", region: "\uACBD\uAE30\uB3C4", lat: 37.3943, lon: 126.9568 },
66
+ { name: "\uB0A8\uC591\uC8FC", region: "\uACBD\uAE30\uB3C4", lat: 37.636, lon: 127.2165 },
67
+ { name: "\uD654\uC131", region: "\uACBD\uAE30\uB3C4", lat: 37.1996, lon: 126.8312 },
68
+ { name: "\uD3C9\uD0DD", region: "\uACBD\uAE30\uB3C4", lat: 36.9921, lon: 127.0857 },
69
+ { name: "\uC758\uC815\uBD80", region: "\uACBD\uAE30\uB3C4", lat: 37.7381, lon: 127.0338 },
70
+ { name: "\uC2DC\uD765", region: "\uACBD\uAE30\uB3C4", lat: 37.3801, lon: 126.8032 },
71
+ { name: "\uD30C\uC8FC", region: "\uACBD\uAE30\uB3C4", lat: 37.759, lon: 126.7802 },
72
+ { name: "\uAE40\uD3EC", region: "\uACBD\uAE30\uB3C4", lat: 37.6153, lon: 126.7156 },
73
+ { name: "\uAD11\uBA85", region: "\uACBD\uAE30\uB3C4", lat: 37.4786, lon: 126.8646 },
74
+ { name: "\uC774\uCC9C", region: "\uACBD\uAE30\uB3C4", lat: 37.272, lon: 127.435 },
75
+ { name: "\uAD70\uD3EC", region: "\uACBD\uAE30\uB3C4", lat: 37.3616, lon: 126.9351 },
76
+ { name: "\uD558\uB0A8", region: "\uACBD\uAE30\uB3C4", lat: 37.5393, lon: 127.2148 },
77
+ { name: "\uC624\uC0B0", region: "\uACBD\uAE30\uB3C4", lat: 37.1499, lon: 127.077 },
78
+ { name: "\uC591\uC8FC", region: "\uACBD\uAE30\uB3C4", lat: 37.7853, lon: 127.0456 },
79
+ { name: "\uAD6C\uB9AC", region: "\uACBD\uAE30\uB3C4", lat: 37.5943, lon: 127.1297 },
80
+ { name: "\uC548\uC131", region: "\uACBD\uAE30\uB3C4", lat: 37.008, lon: 127.2798 },
81
+ { name: "\uD3EC\uCC9C", region: "\uACBD\uAE30\uB3C4", lat: 37.8949, lon: 127.2003 },
82
+ { name: "\uC758\uC655", region: "\uACBD\uAE30\uB3C4", lat: 37.3449, lon: 126.9685 },
83
+ { name: "\uC5EC\uC8FC", region: "\uACBD\uAE30\uB3C4", lat: 37.2984, lon: 127.6373 },
84
+ { name: "\uC591\uD3C9", region: "\uACBD\uAE30\uB3C4", lat: 37.4914, lon: 127.4875 },
85
+ { name: "\uB3D9\uB450\uCC9C", region: "\uACBD\uAE30\uB3C4", lat: 37.9034, lon: 127.0606 },
86
+ { name: "\uACFC\uCC9C", region: "\uACBD\uAE30\uB3C4", lat: 37.4292, lon: 126.9876 },
87
+ { name: "\uAD11\uC8FC", region: "\uACBD\uAE30\uB3C4", lat: 37.4095, lon: 127.255 },
88
+ { name: "\uC5F0\uCC9C", region: "\uACBD\uAE30\uB3C4", lat: 38.0965, lon: 127.075 },
89
+ { name: "\uAC00\uD3C9", region: "\uACBD\uAE30\uB3C4", lat: 37.8315, lon: 127.5095 },
75
90
  // 강원도
76
- { name: "\uCD98\uCC9C", lat: 37.8813, lon: 127.7299 },
77
- { name: "\uC6D0\uC8FC", lat: 37.3422, lon: 127.9202 },
78
- { name: "\uAC15\uB989", lat: 37.7519, lon: 128.8761 },
79
- { name: "\uC18D\uCD08", lat: 38.207, lon: 128.5918 },
91
+ { name: "\uCD98\uCC9C", region: "\uAC15\uC6D0\uB3C4", lat: 37.8813, lon: 127.7299 },
92
+ { name: "\uC6D0\uC8FC", region: "\uAC15\uC6D0\uB3C4", lat: 37.3422, lon: 127.9202 },
93
+ { name: "\uAC15\uB989", region: "\uAC15\uC6D0\uB3C4", lat: 37.7519, lon: 128.8761 },
94
+ { name: "\uC18D\uCD08", region: "\uAC15\uC6D0\uB3C4", lat: 38.207, lon: 128.5918 },
80
95
  // 충청도
81
- { name: "\uCCAD\uC8FC", lat: 36.6424, lon: 127.489 },
82
- { name: "\uCC9C\uC548", lat: 36.8152, lon: 127.1139 },
83
- { name: "\uCDA9\uC8FC", lat: 36.991, lon: 127.9259 },
84
- { name: "\uC81C\uCC9C", lat: 37.1326, lon: 128.191 },
85
- { name: "\uC544\uC0B0", lat: 36.7898, lon: 127.0018 },
96
+ { name: "\uCCAD\uC8FC", region: "\uCDA9\uCCAD\uBD81\uB3C4", lat: 36.6424, lon: 127.489 },
97
+ { name: "\uCC9C\uC548", region: "\uCDA9\uCCAD\uB0A8\uB3C4", lat: 36.8152, lon: 127.1139 },
98
+ { name: "\uCDA9\uC8FC", region: "\uCDA9\uCCAD\uBD81\uB3C4", lat: 36.991, lon: 127.9259 },
99
+ { name: "\uC81C\uCC9C", region: "\uCDA9\uCCAD\uBD81\uB3C4", lat: 37.1326, lon: 128.191 },
100
+ { name: "\uC544\uC0B0", region: "\uCDA9\uCCAD\uB0A8\uB3C4", lat: 36.7898, lon: 127.0018 },
86
101
  // 전라도
87
- { name: "\uC804\uC8FC", lat: 35.8242, lon: 127.148 },
88
- { name: "\uBAA9\uD3EC", lat: 34.8118, lon: 126.3922 },
89
- { name: "\uC5EC\uC218", lat: 34.7604, lon: 127.6622 },
90
- { name: "\uC21C\uCC9C", lat: 34.9505, lon: 127.4873 },
91
- { name: "\uAD70\uC0B0", lat: 35.9677, lon: 126.737 },
92
- { name: "\uC775\uC0B0", lat: 35.9483, lon: 126.9576 },
102
+ { name: "\uC804\uC8FC", region: "\uC804\uB77C\uBD81\uB3C4", lat: 35.8242, lon: 127.148 },
103
+ { name: "\uBAA9\uD3EC", region: "\uC804\uB77C\uB0A8\uB3C4", lat: 34.8118, lon: 126.3922 },
104
+ { name: "\uC5EC\uC218", region: "\uC804\uB77C\uB0A8\uB3C4", lat: 34.7604, lon: 127.6622 },
105
+ { name: "\uC21C\uCC9C", region: "\uC804\uB77C\uB0A8\uB3C4", lat: 34.9505, lon: 127.4873 },
106
+ { name: "\uAD70\uC0B0", region: "\uC804\uB77C\uBD81\uB3C4", lat: 35.9677, lon: 126.737 },
107
+ { name: "\uC775\uC0B0", region: "\uC804\uB77C\uBD81\uB3C4", lat: 35.9483, lon: 126.9576 },
93
108
  // 경상도
94
- { name: "\uD3EC\uD56D", lat: 36.019, lon: 129.3435 },
95
- { name: "\uACBD\uC8FC", lat: 35.8562, lon: 129.2247 },
96
- { name: "\uAE40\uD574", lat: 35.2285, lon: 128.8894 },
97
- { name: "\uCC3D\uC6D0", lat: 35.2281, lon: 128.6811 },
98
- { name: "\uC9C4\uC8FC", lat: 35.1798, lon: 128.1076 },
99
- { name: "\uAD6C\uBBF8", lat: 36.1197, lon: 128.3446 },
100
- { name: "\uC548\uB3D9", lat: 36.5684, lon: 128.7294 },
109
+ { name: "\uD3EC\uD56D", region: "\uACBD\uC0C1\uBD81\uB3C4", lat: 36.019, lon: 129.3435 },
110
+ { name: "\uACBD\uC8FC", region: "\uACBD\uC0C1\uBD81\uB3C4", lat: 35.8562, lon: 129.2247 },
111
+ { name: "\uAE40\uD574", region: "\uACBD\uC0C1\uB0A8\uB3C4", lat: 35.2285, lon: 128.8894 },
112
+ { name: "\uCC3D\uC6D0", region: "\uACBD\uC0C1\uB0A8\uB3C4", lat: 35.2281, lon: 128.6811 },
113
+ { name: "\uC9C4\uC8FC", region: "\uACBD\uC0C1\uB0A8\uB3C4", lat: 35.1798, lon: 128.1076 },
114
+ { name: "\uAD6C\uBBF8", region: "\uACBD\uC0C1\uBD81\uB3C4", lat: 36.1197, lon: 128.3446 },
115
+ { name: "\uC548\uB3D9", region: "\uACBD\uC0C1\uBD81\uB3C4", lat: 36.5684, lon: 128.7294 },
101
116
  // 제주도
102
- { name: "\uC81C\uC8FC", lat: 33.4996, lon: 126.5312 },
103
- { name: "\uC11C\uADC0\uD3EC", lat: 33.2542, lon: 126.56 }
117
+ { name: "\uC81C\uC8FC", region: "\uC81C\uC8FC\uD2B9\uBCC4\uC790\uCE58\uB3C4", lat: 33.4996, lon: 126.5312 },
118
+ { name: "\uC11C\uADC0\uD3EC", region: "\uC81C\uC8FC\uD2B9\uBCC4\uC790\uCE58\uB3C4", lat: 33.2542, lon: 126.56 }
104
119
  ];
105
120
  var WORLD_CITIES = [
106
121
  // ── 동아시아 ──
@@ -297,8 +312,13 @@ var WORLD_CITIES = [
297
312
  { name: "\uC624\uD074\uB79C\uB4DC", country: "\uB274\uC9C8\uB79C\uB4DC", lat: -36.8485, lon: 174.7633 }
298
313
  ];
299
314
  var SEOUL = KOREAN_CITIES[0];
315
+ var AMBIGUOUS_NAMES = new Set(
316
+ KOREAN_CITIES.map((c) => c.name).filter((name, _, arr) => arr.indexOf(name) !== arr.lastIndexOf(name))
317
+ );
300
318
  function formatCityName(city) {
301
- return city.country ? `${city.name}, ${city.country}` : city.name;
319
+ if (city.country) return `${city.name}, ${city.country}`;
320
+ if (city.region && AMBIGUOUS_NAMES.has(city.name)) return `${city.name} (${city.region})`;
321
+ return city.name;
302
322
  }
303
323
  function filterCities(query) {
304
324
  const q = query.trim();
@@ -307,7 +327,7 @@ function filterCities(query) {
307
327
  const koreanResults = [];
308
328
  const worldResults = [];
309
329
  for (const city of KOREAN_CITIES) {
310
- if (chosung ? matchChosung(city.name, q) : city.name.includes(q)) {
330
+ if (chosung ? matchChosung(city.name, q) || city.region != null && matchChosung(city.region, q) : city.name.includes(q) || city.region != null && city.region.includes(q)) {
311
331
  koreanResults.push(city);
312
332
  }
313
333
  }
@@ -319,7 +339,7 @@ function filterCities(query) {
319
339
  if (label.includes(q)) worldResults.push(city);
320
340
  }
321
341
  }
322
- return [...koreanResults, ...worldResults].slice(0, 8);
342
+ return [...koreanResults, ...worldResults].slice(0, 20);
323
343
  }
324
344
 
325
345
  export {
package/dist/cities.d.ts CHANGED
@@ -4,6 +4,8 @@ interface City {
4
4
  name: string;
5
5
  /** 한국어 국가명 (국내 도시는 생략) */
6
6
  country?: string;
7
+ /** 한국어 광역 지역명 (예: '경기도', '강원도') */
8
+ region?: string;
7
9
  lat: number;
8
10
  lon: number;
9
11
  }
@@ -11,9 +13,9 @@ declare const KOREAN_CITIES: readonly City[];
11
13
  declare const WORLD_CITIES: readonly City[];
12
14
  /** 기본값: 서울 */
13
15
  declare const SEOUL: City;
14
- /** 도시 표시명 (예: "서울", "도쿄, 일본") */
16
+ /** 도시 표시명 (예: "서울", "광주 (경기도)", "도쿄, 일본") */
15
17
  declare function formatCityName(city: City): string;
16
- /** 쿼리로 도시 필터링 (최대 8개, 한국 도시 우선) */
18
+ /** 쿼리로 도시 필터링 (최대 20개, 한국 도시 우선) */
17
19
  declare function filterCities(query: string): City[];
18
20
 
19
21
  export { type City, KOREAN_CITIES, SEOUL, WORLD_CITIES, filterCities, formatCityName };
package/dist/cities.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  WORLD_CITIES,
5
5
  filterCities,
6
6
  formatCityName
7
- } from "./chunk-OCPJGMZC.js";
7
+ } from "./chunk-WOQT7EBV.js";
8
8
  import "./chunk-JSBRDJBE.js";
9
9
  export {
10
10
  KOREAN_CITIES,
@@ -27,11 +27,22 @@ declare const BRANCH_BREAKS: Record<string, string>;
27
27
  declare const BRANCH_HARMS: Record<string, string>;
28
28
  declare const BRANCH_PUNISHMENTS: Record<string, [string, string]>;
29
29
  declare const BRANCH_SELF_PUNISHMENTS: Set<string>;
30
+ declare const BRANCH_WONJIN: Record<string, string>;
31
+ declare const BRANCH_GWIMUN: Record<string, string>;
30
32
  declare const YANGIN_MAP: Record<string, string>;
31
33
  declare const BAEKHO_PILLARS: Set<string>;
32
34
  declare const GOEGANG_PILLARS: Set<string>;
35
+ declare const DOHWA_MAP: Record<string, string>;
36
+ declare const CHEONUL_MAP: Record<string, string[]>;
37
+ declare const CHEONDUK_MAP: Record<string, string>;
38
+ declare const WOLDUK_MAP: Record<string, string>;
39
+ declare const MUNCHANG_MAP: Record<string, string>;
40
+ declare const HONGYEOM_PILLARS: Set<string>;
41
+ declare const GEUMYEO_MAP: Record<string, string>;
33
42
  declare const METEOR_LOOKUP: Record<string, number>;
34
43
  declare const JIJANGGAN: Record<string, string>;
44
+ /** 6순(旬)별 공망 지지 쌍. 인덱스 = Math.trunc(HGANJI index / 10) */
45
+ declare const GONGMANG_TABLE: [string, string][];
35
46
  declare const HGANJI: string[];
36
47
  declare const PILLAR_NAMES: string[];
37
48
  declare const TIAN_GAN = "\u7532\u4E59\u4E19\u4E01\u620A\u5DF1\u5E9A\u8F9B\u58EC\u7678";
@@ -54,4 +65,4 @@ declare const BRIGHTNESS_TABLE: Record<string, Record<string, string>>;
54
65
  declare const CHANGSHENG_START: Record<string, string>;
55
66
  declare const WU_HU_DUN_GAN: Record<string, string>;
56
67
 
57
- export { BAEKHO_PILLARS, BRANCH_BREAKS, BRANCH_CLASHES, BRANCH_COMBINES_6, BRANCH_ELEMENT, BRANCH_HARMS, BRANCH_PUNISHMENTS, BRANCH_SELF_PUNISHMENTS, BRIGHTNESS_TABLE, CHANGSHENG_START, DIRECTIONAL_COMPOSES, DIRECTIONAL_COMPOSE_ELEMENTS, DI_ZHI, EARTH, EARTH_KR, ELEMENT_HANJA, GOEGANG_PILLARS, HALF_COMPOSES, HGANJI, HUO_XING_START, JIJANGGAN, KUI_YUE_TABLE, LING_XING_START, LUCKY_STAR_NAMES, LU_CUN_TABLE, MAIN_STAR_NAMES, METEORS_12, METEOR_LOOKUP, NAYIN_TABLE, PALACE_NAMES, PILLAR_NAMES, RELATIONS, SHA_STAR_NAMES, SI_HUA_TABLE, SKY, SKY_KR, SPIRITS_12, STEM_CLASHES, STEM_COMBINES, STEM_INFO, TIANFU_SERIES_OFFSETS, TIAN_GAN, TIAN_MA_TABLE, TRIPLE_COMPOSES, TRIPLE_COMPOSE_ELEMENTS, WU_HU_DUN_GAN, WU_XING_JU_MAP, YANGGAN, YANGIN_MAP, ZIWEI_SERIES_OFFSETS };
68
+ export { BAEKHO_PILLARS, BRANCH_BREAKS, BRANCH_CLASHES, BRANCH_COMBINES_6, BRANCH_ELEMENT, BRANCH_GWIMUN, BRANCH_HARMS, BRANCH_PUNISHMENTS, BRANCH_SELF_PUNISHMENTS, BRANCH_WONJIN, BRIGHTNESS_TABLE, CHANGSHENG_START, CHEONDUK_MAP, CHEONUL_MAP, DIRECTIONAL_COMPOSES, DIRECTIONAL_COMPOSE_ELEMENTS, DI_ZHI, DOHWA_MAP, EARTH, EARTH_KR, ELEMENT_HANJA, GEUMYEO_MAP, GOEGANG_PILLARS, GONGMANG_TABLE, HALF_COMPOSES, HGANJI, HONGYEOM_PILLARS, HUO_XING_START, JIJANGGAN, KUI_YUE_TABLE, LING_XING_START, LUCKY_STAR_NAMES, LU_CUN_TABLE, MAIN_STAR_NAMES, METEORS_12, METEOR_LOOKUP, MUNCHANG_MAP, NAYIN_TABLE, PALACE_NAMES, PILLAR_NAMES, RELATIONS, SHA_STAR_NAMES, SI_HUA_TABLE, SKY, SKY_KR, SPIRITS_12, STEM_CLASHES, STEM_COMBINES, STEM_INFO, TIANFU_SERIES_OFFSETS, TIAN_GAN, TIAN_MA_TABLE, TRIPLE_COMPOSES, TRIPLE_COMPOSE_ELEMENTS, WOLDUK_MAP, WU_HU_DUN_GAN, WU_XING_JU_MAP, YANGGAN, YANGIN_MAP, ZIWEI_SERIES_OFFSETS };