chart2txt 0.6.0 → 0.7.1

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 (49) hide show
  1. package/README.md +103 -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 +10 -6
  6. package/dist/config/ChartSettings.js +22 -11
  7. package/dist/constants.d.ts +17 -2
  8. package/dist/constants.js +303 -34
  9. package/dist/core/analysis.d.ts +6 -0
  10. package/dist/core/analysis.js +237 -0
  11. package/dist/core/aspectPatterns.d.ts +8 -3
  12. package/dist/core/aspectPatterns.js +234 -218
  13. package/dist/core/aspects.d.ts +14 -11
  14. package/dist/core/aspects.js +49 -32
  15. package/dist/core/dignities.d.ts +2 -27
  16. package/dist/core/dignities.js +56 -121
  17. package/dist/core/dispositors.d.ts +7 -19
  18. package/dist/core/dispositors.js +152 -126
  19. package/dist/core/grouping.d.ts +9 -0
  20. package/dist/core/grouping.js +45 -0
  21. package/dist/core/signDistributions.d.ts +20 -30
  22. package/dist/core/signDistributions.js +25 -122
  23. package/dist/core/stelliums.d.ts +10 -0
  24. package/dist/core/stelliums.js +108 -0
  25. package/dist/formatters/text/sections/aspectPatterns.d.ts +3 -1
  26. package/dist/formatters/text/sections/aspectPatterns.js +118 -94
  27. package/dist/formatters/text/sections/aspects.d.ts +3 -6
  28. package/dist/formatters/text/sections/aspects.js +35 -52
  29. package/dist/formatters/text/sections/dispositors.d.ts +4 -3
  30. package/dist/formatters/text/sections/dispositors.js +12 -8
  31. package/dist/formatters/text/sections/houseOverlays.d.ts +11 -6
  32. package/dist/formatters/text/sections/houseOverlays.js +37 -44
  33. package/dist/formatters/text/sections/metadata.d.ts +2 -0
  34. package/dist/formatters/text/sections/metadata.js +54 -0
  35. package/dist/formatters/text/sections/planets.d.ts +3 -5
  36. package/dist/formatters/text/sections/planets.js +11 -22
  37. package/dist/formatters/text/sections/signDistributions.d.ts +9 -25
  38. package/dist/formatters/text/sections/signDistributions.js +9 -55
  39. package/dist/formatters/text/textFormatter.d.ts +4 -5
  40. package/dist/formatters/text/textFormatter.js +86 -142
  41. package/dist/index.d.ts +7 -4
  42. package/dist/index.js +11 -6
  43. package/dist/types.d.ts +102 -15
  44. package/dist/types.js +15 -0
  45. package/dist/utils/formatting.d.ts +4 -0
  46. package/dist/utils/formatting.js +43 -0
  47. package/dist/utils/houseCalculations.d.ts +10 -13
  48. package/dist/utils/houseCalculations.js +15 -57
  49. package/package.json +1 -1
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectStelliums = detectStelliums;
4
+ exports.formatStellium = formatStellium;
5
+ const astrology_1 = require("./astrology");
6
+ const houseCalculations_1 = require("../utils/houseCalculations");
7
+ const formatting_1 = require("../utils/formatting");
8
+ /**
9
+ * Convert Point to PlanetPosition
10
+ */
11
+ function pointToPlanetPosition(point, houseCusps) {
12
+ const sign = (0, astrology_1.getDegreeSign)(point.degree);
13
+ const house = houseCusps
14
+ ? (0, houseCalculations_1.getHouseForPoint)(point.degree, houseCusps) || undefined
15
+ : undefined;
16
+ return {
17
+ name: point.name,
18
+ degree: point.degree,
19
+ sign,
20
+ house,
21
+ };
22
+ }
23
+ /**
24
+ * Detect Stellium patterns (3+ planets in same sign or adjacent houses)
25
+ * This function requires house information and is specific to single-chart analysis
26
+ */
27
+ function detectStelliums(planets, houseCusps, minPlanets = 3) {
28
+ const patterns = [];
29
+ // Group by sign
30
+ const signGroups = new Map();
31
+ planets.forEach((planet) => {
32
+ const sign = (0, astrology_1.getDegreeSign)(planet.degree);
33
+ if (!signGroups.has(sign)) {
34
+ signGroups.set(sign, []);
35
+ }
36
+ signGroups.get(sign).push(planet);
37
+ });
38
+ // Check sign-based stelliums
39
+ signGroups.forEach((planetsInSign, sign) => {
40
+ if (planetsInSign.length >= minPlanets) {
41
+ const planetPositions = planetsInSign.map((p) => pointToPlanetPosition(p, houseCusps));
42
+ const houses = planetPositions
43
+ .map((p) => p.house)
44
+ .filter((h) => h !== undefined);
45
+ const degrees = planetsInSign.map((p) => p.degree);
46
+ const span = Math.max(...degrees) - Math.min(...degrees);
47
+ patterns.push({
48
+ type: 'Stellium',
49
+ planets: planetPositions,
50
+ sign,
51
+ houses: [...new Set(houses)].sort(),
52
+ span,
53
+ });
54
+ }
55
+ });
56
+ // Check house-based stelliums (if house cusps available)
57
+ if (houseCusps) {
58
+ const houseGroups = new Map();
59
+ planets.forEach((planet) => {
60
+ const house = (0, houseCalculations_1.getHouseForPoint)(planet.degree, houseCusps);
61
+ if (house) {
62
+ if (!houseGroups.has(house)) {
63
+ houseGroups.set(house, []);
64
+ }
65
+ houseGroups.get(house).push(planet);
66
+ }
67
+ });
68
+ houseGroups.forEach((planetsInHouse, house) => {
69
+ if (planetsInHouse.length >= minPlanets) {
70
+ const planetPositions = planetsInHouse.map((p) => pointToPlanetPosition(p, houseCusps));
71
+ const degrees = planetsInHouse.map((p) => p.degree);
72
+ const span = Math.max(...degrees) - Math.min(...degrees);
73
+ // Only add if not already covered by sign stellium
74
+ const existingSignStellium = patterns.find((p) => p.type === 'Stellium' &&
75
+ p.planets.some((planet) => planetPositions.some((pp) => pp.name === planet.name)));
76
+ if (!existingSignStellium) {
77
+ patterns.push({
78
+ type: 'Stellium',
79
+ planets: planetPositions,
80
+ houses: [house],
81
+ span,
82
+ });
83
+ }
84
+ }
85
+ });
86
+ }
87
+ return patterns;
88
+ }
89
+ /**
90
+ * Format a Stellium pattern for display in compact format
91
+ */
92
+ function formatStellium(pattern) {
93
+ const planetNames = pattern.planets.map((p) => p.name).join(', ');
94
+ let location = '';
95
+ if (pattern.sign) {
96
+ location = pattern.sign;
97
+ }
98
+ if (pattern.houses && pattern.houses.length > 0) {
99
+ const houseStr = pattern.houses.length === 1
100
+ ? `${(0, formatting_1.getOrdinal)(pattern.houses[0])} House`
101
+ : pattern.houses.map((h) => `${(0, formatting_1.getOrdinal)(h)} House`).join('-');
102
+ location += location ? ` (${houseStr})` : houseStr;
103
+ }
104
+ const locationStr = location ? ` in ${location}` : '';
105
+ return [
106
+ `Stellium (${pattern.span.toFixed(1)}°): ${planetNames}${locationStr}`,
107
+ ];
108
+ }
@@ -2,6 +2,8 @@ import { AspectPattern } from '../../../types';
2
2
  /**
3
3
  * Generates the [ASPECT PATTERNS] section of the chart output.
4
4
  * @param patterns Array of detected aspect patterns
5
+ * @param customTitle Optional custom title for the section
6
+ * @param showChartNames Whether to show chart names for planets (false for single charts, true for multi-chart)
5
7
  * @returns An array of strings for the output.
6
8
  */
7
- export declare function generateAspectPatternsOutput(patterns: AspectPattern[]): string[];
9
+ export declare function generateAspectPatternsOutput(patterns: AspectPattern[], customTitle?: string, showChartNames?: boolean): string[];
@@ -6,164 +6,188 @@ const formatting_1 = require("../../../utils/formatting");
6
6
  /**
7
7
  * Format a planet position for display
8
8
  */
9
- function formatPlanetPosition(planet) {
9
+ function formatPlanetPosition(planet, includeHouse = false, showChartNames = true) {
10
10
  const degInSign = Math.floor((0, astrology_1.getDegreeInSign)(planet.degree));
11
- const houseStr = planet.house ? ` (${(0, formatting_1.getOrdinal)(planet.house)} house)` : '';
12
- return `${planet.name} ${degInSign}° ${planet.sign}${houseStr}`;
11
+ const houseStr = includeHouse && planet.house ? ` (${(0, formatting_1.getOrdinal)(planet.house)} house)` : '';
12
+ const chartPrefix = showChartNames && planet.chartName ? `${planet.chartName}'s ` : '';
13
+ return `${chartPrefix}${planet.name} ${degInSign}° ${planet.sign}${houseStr}`;
13
14
  }
14
15
  /**
15
- * Format a T-Square pattern
16
+ * Format a T-Square pattern in compact format
16
17
  */
17
- function formatTSquare(pattern) {
18
+ function formatTSquare(pattern, showChartNames = true) {
18
19
  if (pattern.type !== 'T-Square')
19
20
  return [];
20
- const output = ['T-Square:'];
21
- output.push(` - Apex: ${formatPlanetPosition(pattern.apex)}`);
22
- output.push(` - Opposition: ${formatPlanetPosition(pattern.opposition[0])} - ${formatPlanetPosition(pattern.opposition[1])}`);
23
- output.push(` - Mode: ${pattern.mode}`);
24
- output.push(` - Average orb: ${pattern.averageOrb.toFixed(1)}°`);
25
- output.push('');
26
- return output;
21
+ const apex = formatPlanetPosition(pattern.apex, false, showChartNames);
22
+ const opp1 = formatPlanetPosition(pattern.opposition[0], false, showChartNames);
23
+ const opp2 = formatPlanetPosition(pattern.opposition[1], false, showChartNames);
24
+ return [
25
+ `T-Square (${pattern.mode}, ${pattern.averageOrb.toFixed(1)}°): ${apex} ← ${opp1} ↔ ${opp2}`,
26
+ ];
27
27
  }
28
28
  /**
29
- * Format a Grand Trine pattern
29
+ * Format a Grand Trine pattern in compact format
30
30
  */
31
- function formatGrandTrine(pattern) {
31
+ function formatGrandTrine(pattern, showChartNames = true) {
32
32
  if (pattern.type !== 'Grand Trine')
33
33
  return [];
34
- const output = ['Grand Trine:'];
35
- pattern.planets.forEach((planet, index) => {
36
- output.push(` - Planet ${index + 1}: ${formatPlanetPosition(planet)}`);
37
- });
38
- output.push(` - Element: ${pattern.element}`);
39
- output.push(` - Average orb: ${pattern.averageOrb.toFixed(1)}°`);
40
- output.push('');
41
- return output;
42
- }
43
- /**
44
- * Format a Stellium pattern
45
- */
46
- function formatStellium(pattern) {
47
- if (pattern.type !== 'Stellium')
48
- return [];
49
- const output = ['Stellium:'];
50
- const planetNames = pattern.planets.map((p) => p.name).join(', ');
51
- output.push(` - Planets: ${planetNames}`);
52
- if (pattern.sign) {
53
- output.push(` - Sign: ${pattern.sign}`);
54
- }
55
- if (pattern.houses.length > 0) {
56
- const houseStr = pattern.houses.length === 1
57
- ? `${(0, formatting_1.getOrdinal)(pattern.houses[0])}`
58
- : pattern.houses.map((h) => (0, formatting_1.getOrdinal)(h)).join('-');
59
- output.push(` - Houses: ${houseStr}`);
60
- }
61
- output.push(` - Span: ${pattern.span.toFixed(1)}°`);
62
- output.push('');
63
- return output;
34
+ const planets = pattern.planets
35
+ .map((p) => formatPlanetPosition(p, false, showChartNames))
36
+ .join(' ');
37
+ return [
38
+ `Grand Trine (${pattern.element}, ${pattern.averageOrb.toFixed(1)}°): ${planets}`,
39
+ ];
64
40
  }
65
41
  /**
66
- * Format a Grand Cross pattern
42
+ * Format a Grand Cross pattern in compact format
67
43
  */
68
- function formatGrandCross(pattern) {
44
+ function formatGrandCross(pattern, showChartNames = true) {
69
45
  if (pattern.type !== 'Grand Cross')
70
46
  return [];
71
- const output = ['Grand Cross:'];
72
- pattern.planets.forEach((planet, index) => {
73
- output.push(` - Planet ${index + 1}: ${formatPlanetPosition(planet)}`);
74
- });
75
- output.push(` - Mode: ${pattern.mode}`);
76
- output.push(` - Average orb: ${pattern.averageOrb.toFixed(1)}°`);
77
- output.push('');
78
- return output;
47
+ const planets = pattern.planets
48
+ .map((p) => formatPlanetPosition(p, false, showChartNames))
49
+ .join(' ');
50
+ return [
51
+ `Grand Cross (${pattern.mode}, ${pattern.averageOrb.toFixed(1)}°): ${planets}`,
52
+ ];
79
53
  }
80
54
  /**
81
- * Format a Yod pattern
55
+ * Format a Yod pattern in compact format
82
56
  */
83
- function formatYod(pattern) {
57
+ function formatYod(pattern, showChartNames = true) {
84
58
  if (pattern.type !== 'Yod')
85
59
  return [];
86
- const output = ['Yod:'];
87
- output.push(` - Apex: ${formatPlanetPosition(pattern.apex)}`);
88
- output.push(` - Base planet 1: ${formatPlanetPosition(pattern.base[0])}`);
89
- output.push(` - Base planet 2: ${formatPlanetPosition(pattern.base[1])}`);
90
- output.push(` - Average orb: ${pattern.averageOrb.toFixed(1)}°`);
91
- output.push('');
92
- return output;
60
+ const apex = formatPlanetPosition(pattern.apex, false, showChartNames);
61
+ const base1 = formatPlanetPosition(pattern.base[0], false, showChartNames);
62
+ const base2 = formatPlanetPosition(pattern.base[1], false, showChartNames);
63
+ return [
64
+ `Yod (${pattern.averageOrb.toFixed(1)}°): ${apex} ← ${base1} • ${base2}`,
65
+ ];
93
66
  }
94
67
  /**
95
- * Format a Mystic Rectangle pattern
68
+ * Format a Mystic Rectangle pattern in compact format
96
69
  */
97
- function formatMysticRectangle(pattern) {
70
+ function formatMysticRectangle(pattern, showChartNames = true) {
98
71
  if (pattern.type !== 'Mystic Rectangle')
99
72
  return [];
100
- const output = ['Mystic Rectangle:'];
101
- output.push(` - Opposition 1: ${formatPlanetPosition(pattern.oppositions[0][0])} - ${formatPlanetPosition(pattern.oppositions[0][1])}`);
102
- output.push(` - Opposition 2: ${formatPlanetPosition(pattern.oppositions[1][0])} - ${formatPlanetPosition(pattern.oppositions[1][1])}`);
103
- output.push(` - Average orb: ${pattern.averageOrb.toFixed(1)}°`);
104
- output.push('');
105
- return output;
73
+ const opp1_1 = formatPlanetPosition(pattern.oppositions[0][0], false, showChartNames);
74
+ const opp1_2 = formatPlanetPosition(pattern.oppositions[0][1], false, showChartNames);
75
+ const opp2_1 = formatPlanetPosition(pattern.oppositions[1][0], false, showChartNames);
76
+ const opp2_2 = formatPlanetPosition(pattern.oppositions[1][1], false, showChartNames);
77
+ return [
78
+ `Mystic Rectangle (${pattern.averageOrb.toFixed(1)}°): ${opp1_1} ↔ ${opp1_2} | ${opp2_1} ↔ ${opp2_2}`,
79
+ ];
106
80
  }
107
81
  /**
108
- * Format a Kite pattern
82
+ * Format a Kite pattern in compact format
109
83
  */
110
- function formatKite(pattern) {
84
+ function formatKite(pattern, showChartNames = true) {
111
85
  if (pattern.type !== 'Kite')
112
86
  return [];
113
- const output = ['Kite:'];
114
- const grandTrineStr = pattern.grandTrine.map((p) => p.name).join(', ');
115
- output.push(` - Grand Trine planets: ${grandTrineStr}`);
116
- output.push(` - Opposition planet: ${formatPlanetPosition(pattern.opposition)}`);
117
- output.push(` - Average orb: ${pattern.averageOrb.toFixed(1)}°`);
118
- output.push('');
119
- return output;
87
+ const grandTrineStr = pattern.grandTrine
88
+ .map((p) => formatPlanetPosition(p, false, showChartNames))
89
+ .join(' ');
90
+ const oppositionPlanet = formatPlanetPosition(pattern.opposition, false, showChartNames);
91
+ // Get the element from the first planet's sign for context
92
+ const element = pattern.grandTrine[0].sign
93
+ ? getElementFromSign(pattern.grandTrine[0].sign)
94
+ : '';
95
+ const elementStr = element ? `${element}, ` : '';
96
+ return [
97
+ `Kite (${elementStr}${pattern.averageOrb.toFixed(1)}°): [${grandTrineStr}] ← ${oppositionPlanet}`,
98
+ ];
99
+ }
100
+ /**
101
+ * Helper function to get element from sign
102
+ */
103
+ function getElementFromSign(sign) {
104
+ const fireSigns = ['Aries', 'Leo', 'Sagittarius'];
105
+ const earthSigns = ['Taurus', 'Virgo', 'Capricorn'];
106
+ const airSigns = ['Gemini', 'Libra', 'Aquarius'];
107
+ const waterSigns = ['Cancer', 'Scorpio', 'Pisces'];
108
+ if (fireSigns.includes(sign))
109
+ return 'Fire';
110
+ if (earthSigns.includes(sign))
111
+ return 'Earth';
112
+ if (airSigns.includes(sign))
113
+ return 'Air';
114
+ if (waterSigns.includes(sign))
115
+ return 'Water';
116
+ return '';
117
+ }
118
+ /**
119
+ * Check if a Grand Trine is part of any Kite pattern within the same analysis context
120
+ * Uses exact planet identity matching (chart name + planet name + degree)
121
+ */
122
+ function isGrandTrinePartOfKite(grandTrine, patterns) {
123
+ if (grandTrine.type !== 'Grand Trine')
124
+ return false;
125
+ return patterns.some((pattern) => {
126
+ if (pattern.type !== 'Kite')
127
+ return false;
128
+ // Create unique identifiers for exact planet identity matching
129
+ const createPlanetId = (p) => `${p.chartName || ''}-${p.name}-${p.degree}`;
130
+ const kiteGrandTrinePlanets = pattern.grandTrine.map(createPlanetId);
131
+ const grandTrinePlanets = grandTrine.planets.map(createPlanetId);
132
+ // Check if the sets of planets are identical (same planets, same count)
133
+ return (kiteGrandTrinePlanets.length === grandTrinePlanets.length &&
134
+ kiteGrandTrinePlanets.every((kp) => grandTrinePlanets.includes(kp)));
135
+ });
120
136
  }
121
137
  /**
122
138
  * Generates the [ASPECT PATTERNS] section of the chart output.
123
139
  * @param patterns Array of detected aspect patterns
140
+ * @param customTitle Optional custom title for the section
141
+ * @param showChartNames Whether to show chart names for planets (false for single charts, true for multi-chart)
124
142
  * @returns An array of strings for the output.
125
143
  */
126
- function generateAspectPatternsOutput(patterns) {
127
- const output = ['[ASPECT PATTERNS]'];
144
+ function generateAspectPatternsOutput(patterns, customTitle, showChartNames = true) {
145
+ const output = [
146
+ customTitle ? `[ASPECT PATTERNS: ${customTitle}]` : '[ASPECT PATTERNS]',
147
+ ];
128
148
  if (patterns.length === 0) {
129
- output.push('No aspect patterns detected.');
149
+ output.push('No T-Squares detected.');
150
+ output.push('No Grand Trines detected.');
130
151
  return output;
131
152
  }
153
+ // Filter out Grand Trines that are part of Kites to avoid duplication
154
+ const filteredPatterns = patterns.filter((pattern) => {
155
+ if (pattern.type === 'Grand Trine') {
156
+ return !isGrandTrinePartOfKite(pattern, patterns);
157
+ }
158
+ return true;
159
+ });
132
160
  // Sort patterns by type for consistent output
133
161
  const sortOrder = [
134
162
  'T-Square',
135
163
  'Grand Trine',
136
164
  'Grand Cross',
137
- 'Stellium',
138
165
  'Yod',
139
166
  'Mystic Rectangle',
140
167
  'Kite',
141
168
  ];
142
- const sortedPatterns = patterns.sort((a, b) => {
169
+ const sortedPatterns = filteredPatterns.sort((a, b) => {
143
170
  return sortOrder.indexOf(a.type) - sortOrder.indexOf(b.type);
144
171
  });
145
172
  sortedPatterns.forEach((pattern) => {
146
173
  switch (pattern.type) {
147
174
  case 'T-Square':
148
- output.push(...formatTSquare(pattern));
175
+ output.push(...formatTSquare(pattern, showChartNames));
149
176
  break;
150
177
  case 'Grand Trine':
151
- output.push(...formatGrandTrine(pattern));
152
- break;
153
- case 'Stellium':
154
- output.push(...formatStellium(pattern));
178
+ output.push(...formatGrandTrine(pattern, showChartNames));
155
179
  break;
156
180
  case 'Grand Cross':
157
- output.push(...formatGrandCross(pattern));
181
+ output.push(...formatGrandCross(pattern, showChartNames));
158
182
  break;
159
183
  case 'Yod':
160
- output.push(...formatYod(pattern));
184
+ output.push(...formatYod(pattern, showChartNames));
161
185
  break;
162
186
  case 'Mystic Rectangle':
163
- output.push(...formatMysticRectangle(pattern));
187
+ output.push(...formatMysticRectangle(pattern, showChartNames));
164
188
  break;
165
189
  case 'Kite':
166
- output.push(...formatKite(pattern));
190
+ output.push(...formatKite(pattern, showChartNames));
167
191
  break;
168
192
  }
169
193
  });
@@ -1,14 +1,11 @@
1
1
  import { AspectData } from '../../../types';
2
- import { ChartSettings } from '../../../config/ChartSettings';
3
2
  /**
4
- * Generates aspect sections (e.g., [ASPECTS], [PLANET-PLANET ASPECTS], [TRANSIT ASPECTS: Name]).
3
+ * Generates aspect sections from a pre-grouped map of aspects.
5
4
  * @param title The main title for this aspect block (e.g., "[ASPECTS]").
6
- * @param aspects Array of calculated aspect data.
7
- * @param settings The chart settings, containing aspect categories.
5
+ * @param groupedAspects A map of category names to aspect data arrays.
8
6
  * @param p1ChartName Optional: Name of the first chart/entity for synastry/transit aspects.
9
7
  * @param p2ChartName Optional: Name of the second chart/entity for synastry aspects.
10
8
  * @param p2IsTransit Optional: Boolean indicating if p2 represents transiting points.
11
9
  * @returns An array of strings for the output.
12
10
  */
13
- export declare function generateAspectsOutput(title: string, aspects: AspectData[], settings: ChartSettings, p1ChartName?: string, p2ChartName?: string, // For synastry, this is the second person's name. For transits, it could be "Current" or the transit chart name.
14
- p2IsTransit?: boolean): string[];
11
+ export declare function generateAspectsOutput(title: string, groupedAspects?: Map<string, AspectData[]>, p1ChartName?: string, p2ChartName?: string, p2IsTransit?: boolean): string[];
@@ -2,66 +2,49 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateAspectsOutput = generateAspectsOutput;
4
4
  /**
5
- * Generates aspect sections (e.g., [ASPECTS], [PLANET-PLANET ASPECTS], [TRANSIT ASPECTS: Name]).
5
+ * Generates the output for a single aspect line.
6
+ * @param asp The aspect data.
7
+ * @param p1ChartName Optional name of the first chart.
8
+ * @param p2ChartName Optional name of the second chart.
9
+ * @param p2IsTransit Optional flag if the second chart is for transits.
10
+ * @returns A formatted string for the aspect.
11
+ */
12
+ function formatAspectLine(asp, p1ChartName, p2ChartName, p2IsTransit = false) {
13
+ const p1NameStr = p1ChartName
14
+ ? `${p1ChartName}'s ${asp.planetA}`
15
+ : asp.planetA;
16
+ let p2NameStr = asp.planetB;
17
+ if (p2IsTransit) {
18
+ p2NameStr = `transiting ${asp.planetB}`;
19
+ }
20
+ else if (p2ChartName) {
21
+ p2NameStr = `${p2ChartName}'s ${asp.planetB}`;
22
+ }
23
+ const applicationStr = asp.application && asp.application !== 'exact'
24
+ ? ` (${asp.application})`
25
+ : '';
26
+ return `${p1NameStr} ${asp.aspectType} ${p2NameStr}: ${asp.orb.toFixed(1)}°${applicationStr}`;
27
+ }
28
+ /**
29
+ * Generates aspect sections from a pre-grouped map of aspects.
6
30
  * @param title The main title for this aspect block (e.g., "[ASPECTS]").
7
- * @param aspects Array of calculated aspect data.
8
- * @param settings The chart settings, containing aspect categories.
31
+ * @param groupedAspects A map of category names to aspect data arrays.
9
32
  * @param p1ChartName Optional: Name of the first chart/entity for synastry/transit aspects.
10
33
  * @param p2ChartName Optional: Name of the second chart/entity for synastry aspects.
11
34
  * @param p2IsTransit Optional: Boolean indicating if p2 represents transiting points.
12
35
  * @returns An array of strings for the output.
13
36
  */
14
- function generateAspectsOutput(title, aspects, settings, p1ChartName, p2ChartName, // For synastry, this is the second person's name. For transits, it could be "Current" or the transit chart name.
15
- p2IsTransit = false) {
37
+ function generateAspectsOutput(title, groupedAspects, p1ChartName, p2ChartName, p2IsTransit = false) {
16
38
  const output = [title];
17
- let aspectsFoundInAnyCategory = false;
18
- settings.aspectCategories.forEach((category) => {
19
- const categoryAspects = aspects.filter((asp) => {
20
- const orb = asp.orb;
21
- const minOrbCheck = category.minOrb === undefined ? true : orb > category.minOrb;
22
- const maxOrbCheck = orb <= category.maxOrb;
23
- return minOrbCheck && maxOrbCheck;
24
- });
25
- if (categoryAspects.length > 0) {
26
- aspectsFoundInAnyCategory = true;
27
- let orbRangeStr = `orb under ${category.maxOrb.toFixed(1)}°`;
28
- if (category.minOrb !== undefined) {
29
- // Ensure minOrb is less than maxOrb for sensible range string
30
- orbRangeStr =
31
- category.minOrb < category.maxOrb
32
- ? `orb ${category.minOrb.toFixed(1)}-${category.maxOrb.toFixed(1)}°`
33
- : `orb over ${category.minOrb.toFixed(1)}° & under ${category.maxOrb.toFixed(1)}°`; // Fallback for unusual category def
34
- }
35
- output.push(`[${category.name}: ${orbRangeStr}]`);
36
- categoryAspects.sort((a, b) => a.orb - b.orb); // Sort by orb tightness
37
- categoryAspects.forEach((asp) => {
38
- const p1NameStr = p1ChartName
39
- ? `${p1ChartName}'s ${asp.planetA}`
40
- : asp.planetA;
41
- let p2NameStr = asp.planetB;
42
- if (p2IsTransit) {
43
- // For "Transit Aspects: Alice", p1 is Alice, p2 is the transiting planet.
44
- // Example: "Alice's Mercury opposition transiting Neptune: 0.3°" - here p2ChartName is not used for the planet itself.
45
- p2NameStr = `transiting ${asp.planetB}`;
46
- }
47
- else if (p2ChartName) {
48
- // For "Synastry: Alice-Bob", "Planet-Planet Aspects"
49
- // Example: "Alice's Mercury opposition Bob's Neptune: 0.3°"
50
- p2NameStr = `${p2ChartName}'s ${asp.planetB}`;
51
- }
52
- // If neither p2IsTransit nor p2ChartName, it's a natal chart aspect, e.g. "Venus opposition Pluto: 1.2°"
53
- const applicationStr = asp.application && asp.application !== 'exact'
54
- ? ` (${asp.application})`
55
- : '';
56
- output.push(`${p1NameStr} ${asp.aspectType} ${p2NameStr}: ${asp.orb.toFixed(1)}°${applicationStr}`);
57
- });
58
- }
59
- });
60
- if (!aspectsFoundInAnyCategory && aspects.length > 0) {
61
- output.push('No aspects within defined categories.');
62
- }
63
- else if (aspects.length === 0) {
39
+ if (!groupedAspects || groupedAspects.size === 0) {
64
40
  output.push('None');
41
+ return output;
65
42
  }
43
+ groupedAspects.forEach((categoryAspects, categoryName) => {
44
+ output.push(categoryName); // The category name is the pre-formatted key from the map
45
+ categoryAspects.forEach((asp) => {
46
+ output.push(formatAspectLine(asp, p1ChartName, p2ChartName, p2IsTransit));
47
+ });
48
+ });
66
49
  return output;
67
50
  }
@@ -1,7 +1,8 @@
1
- import { Point } from '../../../types';
2
1
  /**
3
2
  * Generates the [DISPOSITOR TREE] section of the chart output.
4
- * @param planets Array of planet points.
3
+ * @param dispositors A map of planet names to their full dispositor chain string, or summary data.
5
4
  * @returns An array of strings for the output.
6
5
  */
7
- export declare function generateDispositorsOutput(planets: Point[]): string[];
6
+ export declare function generateDispositorsOutput(dispositors: {
7
+ [key: string]: string;
8
+ }): string[];
@@ -1,20 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateDispositorsOutput = generateDispositorsOutput;
4
- const dispositors_1 = require("../../../core/dispositors");
5
4
  /**
6
5
  * Generates the [DISPOSITOR TREE] section of the chart output.
7
- * @param planets Array of planet points.
6
+ * @param dispositors A map of planet names to their full dispositor chain string, or summary data.
8
7
  * @returns An array of strings for the output.
9
8
  */
10
- function generateDispositorsOutput(planets) {
9
+ function generateDispositorsOutput(dispositors) {
10
+ // Check if this is summary format (finals mode)
11
+ if (dispositors['summary']) {
12
+ return [`[DISPOSITORS] ${dispositors['summary']}`];
13
+ }
14
+ // Traditional format
11
15
  const output = ['[DISPOSITOR TREE]'];
12
- if (planets.length === 0) {
13
- output.push('No planets available for dispositor analysis.');
16
+ if (Object.keys(dispositors).length === 0) {
17
+ output.push('No dispositor data available.');
14
18
  return output;
15
19
  }
16
- const analysis = (0, dispositors_1.analyzeDispositors)(planets);
17
- const formattedAnalysis = (0, dispositors_1.formatDispositorAnalysis)(analysis);
18
- output.push(...formattedAnalysis);
20
+ for (const planet in dispositors) {
21
+ output.push(dispositors[planet]);
22
+ }
19
23
  return output;
20
24
  }
@@ -1,10 +1,15 @@
1
- import { ChartData } from '../../../types';
2
- import { ChartSettings } from '../../../config/ChartSettings';
3
1
  /**
4
2
  * Generates the [HOUSE OVERLAYS] section for synastry.
5
- * @param chart1 The first chart data.
6
- * @param chart2 The second chart data.
7
- * @param settings The chart settings, containing the house system calculator.
3
+ * @param overlays The pre-calculated house overlay data.
4
+ * @param chart1Name The name of the first chart.
5
+ * @param chart2Name The name of the second chart.
8
6
  * @returns An array of strings for the output.
9
7
  */
10
- export declare function generateHouseOverlaysOutput(chart1: ChartData, chart2: ChartData, settings: ChartSettings): string[];
8
+ export declare function generateHouseOverlaysOutput(overlays: {
9
+ chart1InChart2Houses: {
10
+ [key: string]: number;
11
+ };
12
+ chart2InChart1Houses: {
13
+ [key: string]: number;
14
+ };
15
+ }, chart1Name: string, chart2Name: string): string[];