chart2txt 0.5.2 → 0.7.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 (59) hide show
  1. package/README.md +101 -34
  2. package/dist/chart2txt.d.ts +9 -0
  3. package/dist/chart2txt.js +30 -0
  4. package/dist/chart2txt.min.js +1 -1
  5. package/dist/config/ChartSettings.d.ts +13 -6
  6. package/dist/config/ChartSettings.js +36 -10
  7. package/dist/constants.d.ts +17 -2
  8. package/dist/constants.js +301 -32
  9. package/dist/core/analysis.d.ts +6 -0
  10. package/dist/core/analysis.js +235 -0
  11. package/dist/core/aspectPatterns.d.ts +10 -0
  12. package/dist/core/aspectPatterns.js +460 -0
  13. package/dist/core/aspects.d.ts +14 -11
  14. package/dist/core/aspects.js +142 -40
  15. package/dist/core/astrology.d.ts +8 -2
  16. package/dist/core/astrology.js +23 -6
  17. package/dist/core/dignities.d.ts +2 -0
  18. package/dist/core/dignities.js +71 -0
  19. package/dist/core/dispositors.d.ts +9 -0
  20. package/dist/core/dispositors.js +57 -0
  21. package/dist/core/grouping.d.ts +9 -0
  22. package/dist/core/grouping.js +45 -0
  23. package/dist/core/signDistributions.d.ts +21 -0
  24. package/dist/core/signDistributions.js +50 -0
  25. package/dist/core/stelliums.d.ts +10 -0
  26. package/dist/core/stelliums.js +108 -0
  27. package/dist/formatters/text/sections/angles.js +4 -4
  28. package/dist/formatters/text/sections/aspectPatterns.d.ts +9 -0
  29. package/dist/formatters/text/sections/aspectPatterns.js +199 -0
  30. package/dist/formatters/text/sections/aspects.d.ts +3 -6
  31. package/dist/formatters/text/sections/aspects.js +35 -49
  32. package/dist/formatters/text/sections/birthdata.js +1 -1
  33. package/dist/formatters/text/sections/dispositors.d.ts +8 -0
  34. package/dist/formatters/text/sections/dispositors.js +19 -0
  35. package/dist/formatters/text/sections/houseOverlays.d.ts +11 -6
  36. package/dist/formatters/text/sections/houseOverlays.js +38 -69
  37. package/dist/formatters/text/sections/houses.d.ts +6 -0
  38. package/dist/formatters/text/sections/houses.js +36 -0
  39. package/dist/formatters/text/sections/metadata.d.ts +2 -0
  40. package/dist/formatters/text/sections/metadata.js +54 -0
  41. package/dist/formatters/text/sections/planets.d.ts +3 -5
  42. package/dist/formatters/text/sections/planets.js +12 -38
  43. package/dist/formatters/text/sections/signDistributions.d.ts +9 -0
  44. package/dist/formatters/text/sections/signDistributions.js +21 -0
  45. package/dist/formatters/text/textFormatter.d.ts +4 -5
  46. package/dist/formatters/text/textFormatter.js +86 -112
  47. package/dist/index.d.ts +7 -4
  48. package/dist/index.js +11 -6
  49. package/dist/types.d.ts +159 -13
  50. package/dist/types.js +15 -0
  51. package/dist/utils/formatting.d.ts +10 -0
  52. package/dist/utils/formatting.js +56 -0
  53. package/dist/utils/houseCalculations.d.ts +10 -0
  54. package/dist/utils/houseCalculations.js +23 -0
  55. package/dist/utils/precision.d.ts +49 -0
  56. package/dist/utils/precision.js +71 -0
  57. package/dist/utils/validation.d.ts +37 -0
  58. package/dist/utils/validation.js +181 -0
  59. package/package.json +2 -1
@@ -2,31 +2,130 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.calculateAspects = calculateAspects;
4
4
  exports.calculateMultichartAspects = calculateMultichartAspects;
5
- function findTightestAspect(aspectDefinitions, planetA, planetB, skipOutOfSignAspects) {
6
- let diff = Math.abs(planetA.degree - planetB.degree);
5
+ const astrology_1 = require("./astrology");
6
+ const precision_1 = require("../utils/precision");
7
+ /**
8
+ * Gets the expected sign difference for a given aspect angle
9
+ * @param aspectAngle The aspect angle in degrees
10
+ * @returns The expected sign difference
11
+ */
12
+ function getExpectedSignDifference(aspectAngle) {
13
+ // Normalize aspect angle to 0-180 range for sign difference calculation
14
+ const normalizedAngle = aspectAngle <= 180 ? aspectAngle : 360 - aspectAngle;
15
+ // Calculate how many 30-degree signs this aspect spans
16
+ switch (normalizedAngle) {
17
+ case 0:
18
+ return 0; // Conjunction: same sign
19
+ case 30:
20
+ return 1; // Semi-sextile: 1 sign apart
21
+ case 60:
22
+ return 2; // Sextile: 2 signs apart
23
+ case 90:
24
+ return 3; // Square: 3 signs apart
25
+ case 120:
26
+ return 4; // Trine: 4 signs apart
27
+ case 150:
28
+ return 5; // Quincunx: 5 signs apart
29
+ case 180:
30
+ return 6; // Opposition: 6 signs apart
31
+ default:
32
+ // For non-standard aspects, calculate based on 30-degree segments
33
+ return Math.round(normalizedAngle / 30);
34
+ }
35
+ }
36
+ /**
37
+ * Determines if an aspect is applying or separating based on planet speeds
38
+ * @param planetA First planet
39
+ * @param planetB Second planet
40
+ * @param aspectAngle The aspect angle (0, 60, 90, 120, 180, etc.)
41
+ * @returns 'applying', 'separating', or 'exact'
42
+ */
43
+ function determineAspectApplication(planetA, planetB, aspectAngle) {
44
+ // If either planet doesn't have speed data, we can't determine application
45
+ if (planetA.speed === undefined || planetB.speed === undefined) {
46
+ return 'exact';
47
+ }
48
+ const speedA = planetA.speed;
49
+ const speedB = planetB.speed;
50
+ // Calculate current angular distance (handle wraparound properly)
51
+ const degreeA = (0, astrology_1.normalizeDegree)(planetA.degree);
52
+ const degreeB = (0, astrology_1.normalizeDegree)(planetB.degree);
53
+ let currentDistance = Math.abs(degreeA - degreeB);
54
+ if (currentDistance > 180) {
55
+ currentDistance = 360 - currentDistance;
56
+ }
57
+ // If very close to exact, consider it exact
58
+ const orbFromExact = Math.abs(currentDistance - aspectAngle);
59
+ if ((0, precision_1.isExactAspect)(orbFromExact)) {
60
+ return 'exact';
61
+ }
62
+ // Calculate relative speed (how fast the angle between planets is changing)
63
+ const relativeSpeed = speedA - speedB;
64
+ if (relativeSpeed === 0) {
65
+ return 'exact'; // Planets moving at same speed
66
+ }
67
+ // Use a small, consistent time increment (e.g., 0.1 days) rather than degree-based increment
68
+ const timeIncrement = 0.1; // days
69
+ // Calculate future positions after the same time period for both planets
70
+ const futureA = (0, astrology_1.normalizeDegree)(degreeA + speedA * timeIncrement);
71
+ const futureB = (0, astrology_1.normalizeDegree)(degreeB + speedB * timeIncrement);
72
+ // Calculate current and future angular distances for this aspect
73
+ const currentAspectDistance = Math.abs(currentDistance - aspectAngle);
74
+ let futureSeparation = Math.abs(futureA - futureB);
75
+ if (futureSeparation > 180) {
76
+ futureSeparation = 360 - futureSeparation;
77
+ }
78
+ const futureAspectDistance = Math.abs(futureSeparation - aspectAngle);
79
+ // If future distance to exact aspect is smaller, it's applying
80
+ // If future distance to exact aspect is larger, it's separating
81
+ const isApplying = futureAspectDistance < currentAspectDistance;
82
+ return isApplying ? 'applying' : 'separating';
83
+ }
84
+ /**
85
+ * Finds the tightest aspect between two planets using simple orb detection
86
+ * @param aspectDefinitions Array of aspect types to check for
87
+ * @param planetA First planet
88
+ * @param planetB Second planet
89
+ * @param skipOutOfSignAspects Whether to skip aspects that cross sign boundaries
90
+ * @param aspectStrengthThresholds Thresholds for classifying aspect strength
91
+ * @param p1ChartName Optional chart name for planetA
92
+ * @param p2ChartName Optional chart name for planetB
93
+ * @returns The tightest aspect found, or null if none
94
+ */
95
+ function findTightestAspect(aspectDefinitions, planetA, planetB, skipOutOfSignAspects, p1ChartName, p2ChartName) {
96
+ const degreeA = (0, precision_1.roundDegrees)((0, astrology_1.normalizeDegree)(planetA.degree));
97
+ const degreeB = (0, precision_1.roundDegrees)((0, astrology_1.normalizeDegree)(planetB.degree));
98
+ let diff = Math.abs(degreeA - degreeB);
7
99
  if (diff > 180)
8
100
  diff = 360 - diff;
9
101
  let tightestAspect = null;
10
102
  for (const aspectType of aspectDefinitions) {
11
- const orb = Math.abs(diff - aspectType.angle);
103
+ const orb = (0, precision_1.roundDegrees)(Math.abs(diff - aspectType.angle));
12
104
  if (skipOutOfSignAspects) {
13
- const planetASign = Math.floor(planetA.degree / 30);
14
- const planetBSign = Math.floor(planetB.degree / 30);
15
- const aspectSignDiff = Math.floor(aspectType.angle / 30);
16
- let signDiff = Math.abs(planetASign - planetBSign);
17
- if (signDiff > 6)
18
- signDiff = 12 - signDiff;
19
- if (signDiff !== aspectSignDiff) {
105
+ const planetASign = Math.floor(degreeA / 30);
106
+ const planetBSign = Math.floor(degreeB / 30);
107
+ // Calculate expected sign difference for this aspect
108
+ const expectedSignDiff = getExpectedSignDifference(aspectType.angle);
109
+ let actualSignDiff = Math.abs(planetASign - planetBSign);
110
+ if (actualSignDiff > 6)
111
+ actualSignDiff = 12 - actualSignDiff;
112
+ if (actualSignDiff !== expectedSignDiff) {
20
113
  continue;
21
114
  }
22
115
  }
23
- if (orb <= aspectType.orb) {
116
+ // Use simple orb from aspect definition
117
+ const maxAllowedOrb = aspectType.orb;
118
+ if (orb <= maxAllowedOrb) {
24
119
  if (!tightestAspect || orb < tightestAspect.orb) {
120
+ const application = determineAspectApplication(planetA, planetB, aspectType.angle);
25
121
  tightestAspect = {
26
122
  planetA: planetA.name,
27
123
  planetB: planetB.name,
124
+ p1ChartName,
125
+ p2ChartName,
28
126
  aspectType: aspectType.name,
29
127
  orb,
128
+ application,
30
129
  };
31
130
  }
32
131
  }
@@ -34,20 +133,23 @@ function findTightestAspect(aspectDefinitions, planetA, planetB, skipOutOfSignAs
34
133
  return tightestAspect;
35
134
  }
36
135
  /**
37
- * Identifies aspects between planets in a single chart.
136
+ * Unified aspect calculation function that handles both single-chart and multi-chart scenarios
38
137
  * @param aspectDefinitions Array of aspect types to check for.
39
- * @param planets Array of planet points.
138
+ * @param unionedPlanets Array of UnionedPoint pairs to analyze.
139
+ * @param skipOutOfSignAspects Whether to skip aspects that cross sign boundaries.
140
+ * @param aspectStrengthThresholds Thresholds for classifying aspect strength.
141
+ * @param forceChartType Optional override for chart type determination.
40
142
  * @returns Array of found aspects.
41
143
  */
42
- function calculateAspects(aspectDefinitions, planets, skipOutOfSignAspects = true) {
144
+ function calculateAspects(aspectDefinitions, unionedPlanets, skipOutOfSignAspects = true) {
43
145
  const aspects = [];
44
- if (!planets || planets.length < 2)
146
+ if (!unionedPlanets || unionedPlanets.length < 2)
45
147
  return aspects;
46
- for (let i = 0; i < planets.length; i++) {
47
- for (let j = i + 1; j < planets.length; j++) {
48
- const planetA = planets[i];
49
- const planetB = planets[j];
50
- const aspect = findTightestAspect(aspectDefinitions, planetA, planetB, skipOutOfSignAspects);
148
+ for (let i = 0; i < unionedPlanets.length; i++) {
149
+ for (let j = i + 1; j < unionedPlanets.length; j++) {
150
+ const [planetA, chartNameA] = unionedPlanets[i];
151
+ const [planetB, chartNameB] = unionedPlanets[j];
152
+ const aspect = findTightestAspect(aspectDefinitions, planetA, planetB, skipOutOfSignAspects, chartNameA, chartNameB);
51
153
  if (aspect) {
52
154
  aspects.push(aspect);
53
155
  }
@@ -56,28 +158,28 @@ function calculateAspects(aspectDefinitions, planets, skipOutOfSignAspects = tru
56
158
  return aspects;
57
159
  }
58
160
  /**
59
- * Identifies aspects between planets across two charts.
60
- * PlanetA is always from chart1Planets, PlanetB always from chart2Planets.
61
- * @param aspectDefinitions Array of aspect types to check for.
62
- * @param chart1Planets Array of planet points for the first chart.
63
- * @param chart2Planets Array of planet points for the second chart.
64
- * @returns Array of found aspects.
161
+ * Calculates aspects in a multi-chart context (synastry, transits, etc.)
162
+ * @param aspectDefinitions Array of aspect types to check for
163
+ * @param unionedPlanets Array of UnionedPoint pairs to analyze
164
+ * @param skipOutOfSignAspects Whether to skip aspects that cross sign boundaries
165
+ * @param aspectStrengthThresholds Thresholds for classifying aspect strength
166
+ * @returns Array of found aspects
65
167
  */
66
- function calculateMultichartAspects(aspectDefinitions, chart1Planets, chart2Planets, skipOutOfSignAspects = true) {
67
- const aspects = [];
68
- if (!chart1Planets ||
69
- !chart2Planets ||
70
- chart1Planets.length === 0 ||
71
- chart2Planets.length === 0) {
72
- return aspects;
73
- }
74
- for (const p1 of chart1Planets) {
75
- for (const p2 of chart2Planets) {
76
- const aspect = findTightestAspect(aspectDefinitions, p1, p2, skipOutOfSignAspects);
77
- if (aspect) {
78
- aspects.push(aspect);
168
+ function calculateMultichartAspects(aspectDefinitions, unionedPlanets, skipOutOfSignAspects = true) {
169
+ // Filter to only cross-chart aspects
170
+ const crossChartAspects = [];
171
+ for (let i = 0; i < unionedPlanets.length; i++) {
172
+ for (let j = i + 1; j < unionedPlanets.length; j++) {
173
+ const [planetA, chartNameA] = unionedPlanets[i];
174
+ const [planetB, chartNameB] = unionedPlanets[j];
175
+ // Only calculate aspects between planets from different charts
176
+ if (chartNameA !== chartNameB) {
177
+ const aspect = findTightestAspect(aspectDefinitions, planetA, planetB, skipOutOfSignAspects, chartNameA, chartNameB);
178
+ if (aspect) {
179
+ crossChartAspects.push(aspect);
180
+ }
79
181
  }
80
182
  }
81
183
  }
82
- return aspects;
184
+ return crossChartAspects;
83
185
  }
@@ -1,12 +1,18 @@
1
+ /**
2
+ * Normalizes a degree value to the 0-359.999... range.
3
+ * @param degree The degree value to normalize.
4
+ * @returns The normalized degree value.
5
+ */
6
+ export declare function normalizeDegree(degree: number): number;
1
7
  /**
2
8
  * Determines the zodiac sign for a given degree.
3
- * @param degree The absolute degree (0-359.99...).
9
+ * @param degree The absolute degree (any value, will be normalized).
4
10
  * @returns The zodiac sign name.
5
11
  */
6
12
  export declare function getDegreeSign(degree: number): string;
7
13
  /**
8
14
  * Calculates the degree within its 30-degree sign (0-29.99...).
9
- * @param degree The absolute degree (0-359.99...).
15
+ * @param degree The absolute degree (any value, will be normalized).
10
16
  * @returns The degree within the sign.
11
17
  */
12
18
  export declare function getDegreeInSign(degree: number): number;
@@ -1,27 +1,44 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeDegree = normalizeDegree;
3
4
  exports.getDegreeSign = getDegreeSign;
4
5
  exports.getDegreeInSign = getDegreeInSign;
5
6
  const constants_1 = require("../constants");
7
+ /**
8
+ * Normalizes a degree value to the 0-359.999... range.
9
+ * @param degree The degree value to normalize.
10
+ * @returns The normalized degree value.
11
+ */
12
+ function normalizeDegree(degree) {
13
+ if (!isFinite(degree)) {
14
+ throw new Error(`Invalid degree value: ${degree}`);
15
+ }
16
+ let normalized = degree % 360;
17
+ if (normalized < 0) {
18
+ normalized += 360;
19
+ }
20
+ return normalized;
21
+ }
6
22
  /**
7
23
  * Determines the zodiac sign for a given degree.
8
- * @param degree The absolute degree (0-359.99...).
24
+ * @param degree The absolute degree (any value, will be normalized).
9
25
  * @returns The zodiac sign name.
10
26
  */
11
27
  function getDegreeSign(degree) {
12
- const signIndex = Math.floor(degree / 30) % 12;
28
+ const normalizedDegree = normalizeDegree(degree);
29
+ const signIndex = Math.floor(normalizedDegree / 30);
13
30
  if (signIndex < 0 || signIndex >= constants_1.ZODIAC_SIGNS.length) {
14
- // This should ideally not happen with degree % 12 logic if degree is positive
15
- console.error(`Invalid sign index computed: ${signIndex} for degree ${degree}`);
31
+ console.error(`Invalid sign index computed: ${signIndex} for normalized degree ${normalizedDegree}`);
16
32
  return 'Unknown Sign';
17
33
  }
18
34
  return constants_1.ZODIAC_SIGNS[signIndex];
19
35
  }
20
36
  /**
21
37
  * Calculates the degree within its 30-degree sign (0-29.99...).
22
- * @param degree The absolute degree (0-359.99...).
38
+ * @param degree The absolute degree (any value, will be normalized).
23
39
  * @returns The degree within the sign.
24
40
  */
25
41
  function getDegreeInSign(degree) {
26
- return degree % 30;
42
+ const normalizedDegree = normalizeDegree(degree);
43
+ return normalizedDegree % 30;
27
44
  }
@@ -0,0 +1,2 @@
1
+ import { PlanetPosition } from '../types';
2
+ export declare function formatPlanetWithDignities(planet: PlanetPosition): string;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatPlanetWithDignities = formatPlanetWithDignities;
4
+ const constants_1 = require("../constants");
5
+ const DIGNITY_MAP = {
6
+ Sun: {
7
+ Leo: ['Domicile'],
8
+ Aries: ['Exaltation'],
9
+ Aquarius: ['Detriment'],
10
+ Libra: ['Fall'],
11
+ },
12
+ Moon: {
13
+ Cancer: ['Domicile'],
14
+ Taurus: ['Exaltation'],
15
+ Capricorn: ['Detriment'],
16
+ Scorpio: ['Fall'],
17
+ },
18
+ Mercury: {
19
+ Gemini: ['Domicile'],
20
+ Virgo: ['Domicile', 'Exaltation'],
21
+ Pisces: ['Detriment', 'Fall'],
22
+ Sagittarius: ['Detriment'],
23
+ },
24
+ Venus: {
25
+ Taurus: ['Domicile'],
26
+ Libra: ['Domicile'],
27
+ Scorpio: ['Detriment'],
28
+ Aries: ['Fall'],
29
+ Virgo: ['Fall'],
30
+ },
31
+ Mars: {
32
+ Aries: ['Domicile'],
33
+ Scorpio: ['Domicile'],
34
+ Libra: ['Detriment'],
35
+ Cancer: ['Fall'],
36
+ },
37
+ Jupiter: {
38
+ Sagittarius: ['Domicile'],
39
+ Pisces: ['Domicile'],
40
+ Gemini: ['Detriment'],
41
+ Virgo: ['Fall'],
42
+ },
43
+ Saturn: {
44
+ Capricorn: ['Domicile'],
45
+ Aquarius: ['Domicile'],
46
+ Cancer: ['Detriment'],
47
+ Leo: ['Fall'],
48
+ },
49
+ };
50
+ function formatPlanetWithDignities(planet) {
51
+ const sign = planet.sign;
52
+ const dignities = DIGNITY_MAP[planet.name];
53
+ const ruler = constants_1.ZODIAC_SIGN_DATA.find((s) => s.name === sign)?.ruler;
54
+ const dignityParts = [];
55
+ if (dignities && dignities[sign]) {
56
+ dignityParts.push(...dignities[sign]);
57
+ }
58
+ let dignityString = dignityParts.join(', ');
59
+ if (ruler && planet.name !== ruler) {
60
+ if (dignityString) {
61
+ dignityString += ` | Ruler: ${ruler}`;
62
+ }
63
+ else {
64
+ dignityString = `Ruler: ${ruler}`;
65
+ }
66
+ }
67
+ if (dignityString) {
68
+ return `[${dignityString}]`;
69
+ }
70
+ return '';
71
+ }
@@ -0,0 +1,9 @@
1
+ import { Point } from '../types';
2
+ /**
3
+ * Calculates the full dispositor chain for each planet in the chart.
4
+ * @param planets The list of planets in the chart.
5
+ * @returns A map of each planet to its full dispositor chain string.
6
+ */
7
+ export declare function calculateDispositors(planets: Point[]): {
8
+ [key: string]: string;
9
+ };
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calculateDispositors = calculateDispositors;
4
+ const constants_1 = require("../constants");
5
+ const formatting_1 = require("../utils/formatting");
6
+ /**
7
+ * Calculates the dispositor for a single planet.
8
+ * @param planet The planet to find the dispositor for.
9
+ * @returns The name of the dispositor planet.
10
+ */
11
+ function getDispositor(planet) {
12
+ const sign = (0, formatting_1.getSign)(planet.degree);
13
+ const signData = constants_1.ZODIAC_SIGN_DATA.find((s) => s.name === sign);
14
+ return signData ? signData.ruler : 'Unknown';
15
+ }
16
+ /**
17
+ * Calculates the full dispositor chain for each planet in the chart.
18
+ * @param planets The list of planets in the chart.
19
+ * @returns A map of each planet to its full dispositor chain string.
20
+ */
21
+ function calculateDispositors(planets) {
22
+ const dispositorMap = {};
23
+ planets.forEach((p) => {
24
+ dispositorMap[p.name] = getDispositor(p);
25
+ });
26
+ const chains = {};
27
+ planets.forEach((planet) => {
28
+ const path = [planet.name];
29
+ let current = planet.name;
30
+ let chain = `${current}`;
31
+ // eslint-disable-next-line no-constant-condition
32
+ while (true) {
33
+ const nextDispositor = dispositorMap[current];
34
+ // eslint-disable-next-line no-prototype-builtins
35
+ if (!nextDispositor || !dispositorMap.hasOwnProperty(nextDispositor)) {
36
+ // Dispositor is not in the chart, so the chain ends.
37
+ chain += ` → ${nextDispositor} (not in chart)`;
38
+ break;
39
+ }
40
+ if (nextDispositor === current) {
41
+ // Planet is its own dispositor (final dispositor).
42
+ chain += ` → (final)`;
43
+ break;
44
+ }
45
+ if (path.includes(nextDispositor)) {
46
+ // A loop is detected.
47
+ chain += ` → ${nextDispositor} (cycle)`;
48
+ break;
49
+ }
50
+ path.push(nextDispositor);
51
+ chain += ` → ${nextDispositor}`;
52
+ current = nextDispositor;
53
+ }
54
+ chains[planet.name] = chain;
55
+ });
56
+ return chains;
57
+ }
@@ -0,0 +1,9 @@
1
+ import { AspectData, Settings } from '../types';
2
+ /**
3
+ * Provides a default grouping of aspects into "Tight", "Moderate", and "Wide" categories
4
+ * based on orb thresholds. This is used by the simple chart2txt() function.
5
+ * @param aspects The raw list of aspects to group.
6
+ * @param settings The chart settings, containing aspectStrengthThresholds.
7
+ * @returns A map of category names to aspect data arrays.
8
+ */
9
+ export declare function groupAspects(aspects: AspectData[], settings: Settings): Map<string, AspectData[]>;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.groupAspects = groupAspects;
4
+ /**
5
+ * Provides a default grouping of aspects into "Tight", "Moderate", and "Wide" categories
6
+ * based on orb thresholds. This is used by the simple chart2txt() function.
7
+ * @param aspects The raw list of aspects to group.
8
+ * @param settings The chart settings, containing aspectStrengthThresholds.
9
+ * @returns A map of category names to aspect data arrays.
10
+ */
11
+ function groupAspects(aspects, settings) {
12
+ const grouped = new Map();
13
+ const thresholds = settings.aspectStrengthThresholds;
14
+ const tight = [];
15
+ const moderate = [];
16
+ const wide = [];
17
+ aspects.forEach((aspect) => {
18
+ if (aspect.orb <= thresholds.tight) {
19
+ tight.push(aspect);
20
+ }
21
+ else if (aspect.orb <= thresholds.moderate) {
22
+ moderate.push(aspect);
23
+ }
24
+ else {
25
+ wide.push(aspect);
26
+ }
27
+ });
28
+ // Sort each category by orb tightness
29
+ tight.sort((a, b) => a.orb - b.orb);
30
+ moderate.sort((a, b) => a.orb - b.orb);
31
+ wide.sort((a, b) => a.orb - b.orb);
32
+ if (tight.length > 0) {
33
+ const title = `[TIGHT ASPECTS: orb under ${thresholds.tight.toFixed(1)}°]`;
34
+ grouped.set(title, tight);
35
+ }
36
+ if (moderate.length > 0) {
37
+ const title = `[MODERATE ASPECTS: orb ${thresholds.tight.toFixed(1)}-${thresholds.moderate.toFixed(1)}°]`;
38
+ grouped.set(title, moderate);
39
+ }
40
+ if (wide.length > 0) {
41
+ const title = `[WIDE ASPECTS: orb over ${thresholds.moderate.toFixed(1)}°]`;
42
+ grouped.set(title, wide);
43
+ }
44
+ return grouped;
45
+ }
@@ -0,0 +1,21 @@
1
+ import { Point } from '../types';
2
+ export declare function calculateSignDistributions(planets: Point[], ascendant?: number): {
3
+ elements: {
4
+ [key: string]: string[];
5
+ };
6
+ modalities: {
7
+ [key: string]: number;
8
+ };
9
+ polarities: {
10
+ [key: string]: number;
11
+ };
12
+ };
13
+ export declare function formatElementDistribution(elements: {
14
+ [key: string]: string[];
15
+ }): string[];
16
+ export declare function formatModalityDistribution(modalities: {
17
+ [key: string]: number;
18
+ }): string[];
19
+ export declare function formatPolarityDistribution(polarities: {
20
+ [key: string]: number;
21
+ }): string[];
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calculateSignDistributions = calculateSignDistributions;
4
+ exports.formatElementDistribution = formatElementDistribution;
5
+ exports.formatModalityDistribution = formatModalityDistribution;
6
+ exports.formatPolarityDistribution = formatPolarityDistribution;
7
+ const formatting_1 = require("../utils/formatting");
8
+ const constants_1 = require("../constants");
9
+ function calculateSignDistributions(planets, ascendant) {
10
+ const points = [...planets];
11
+ if (ascendant !== undefined) {
12
+ points.push({ name: 'Ascendant', degree: ascendant });
13
+ }
14
+ const elements = {
15
+ Fire: [],
16
+ Earth: [],
17
+ Air: [],
18
+ Water: [],
19
+ };
20
+ const modalities = {
21
+ Cardinal: 0,
22
+ Fixed: 0,
23
+ Mutable: 0,
24
+ };
25
+ const polarities = { Masculine: 0, Feminine: 0 };
26
+ for (const point of points) {
27
+ const sign = (0, formatting_1.getSign)(point.degree);
28
+ const signInfo = constants_1.ZODIAC_SIGN_DATA.find((s) => s.name === sign);
29
+ if (signInfo) {
30
+ elements[signInfo.element].push(point.name);
31
+ modalities[signInfo.modality]++;
32
+ polarities[signInfo.polarity]++;
33
+ }
34
+ }
35
+ return { elements, modalities, polarities };
36
+ }
37
+ function formatElementDistribution(elements) {
38
+ return Object.entries(elements).map(([element, planets]) => {
39
+ if (planets.length === 0) {
40
+ return `${element}: 0`;
41
+ }
42
+ return `${element}: ${planets.length} (${planets.join(', ')})`;
43
+ });
44
+ }
45
+ function formatModalityDistribution(modalities) {
46
+ return Object.entries(modalities).map(([modality, count]) => `${modality}: ${count}`);
47
+ }
48
+ function formatPolarityDistribution(polarities) {
49
+ return Object.entries(polarities).map(([polarity, count]) => `${polarity}: ${count}`);
50
+ }
@@ -0,0 +1,10 @@
1
+ import { Point, Stellium } from '../types';
2
+ /**
3
+ * Detect Stellium patterns (3+ planets in same sign or adjacent houses)
4
+ * This function requires house information and is specific to single-chart analysis
5
+ */
6
+ export declare function detectStelliums(planets: Point[], houseCusps?: number[], minPlanets?: number): Stellium[];
7
+ /**
8
+ * Format a Stellium pattern for display in compact format
9
+ */
10
+ export declare function formatStellium(pattern: Stellium): string[];