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
package/dist/constants.js CHANGED
@@ -1,42 +1,311 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_SETTINGS = exports.DEFAULT_ASPECT_CATEGORIES = exports.DEFAULT_ASPECTS = exports.ZODIAC_SIGNS = void 0;
4
- exports.ZODIAC_SIGNS = [
5
- 'Aries',
6
- 'Taurus',
7
- 'Gemini',
8
- 'Cancer',
9
- 'Leo',
10
- 'Virgo',
11
- 'Libra',
12
- 'Scorpio',
13
- 'Sagittarius',
14
- 'Capricorn',
15
- 'Aquarius',
16
- 'Pisces',
3
+ exports.DEFAULT_SETTINGS = exports.DEFAULT_ASPECT_STRENGTH_THRESHOLDS = exports.WIDE_ASPECTS = exports.TIGHT_ASPECTS = exports.MODERN_ASPECTS = exports.TRADITIONAL_ASPECTS = exports.SIMPLE_WIDE_ORBS = exports.SIMPLE_TIGHT_ORBS = exports.SIMPLE_MODERN_ORBS = exports.SIMPLE_TRADITIONAL_ORBS = exports.DEFAULT_ASPECTS = exports.ZODIAC_SIGNS = exports.ZODIAC_SIGN_DATA = void 0;
4
+ const types_1 = require("./types");
5
+ exports.ZODIAC_SIGN_DATA = [
6
+ {
7
+ name: 'Aries',
8
+ element: 'Fire',
9
+ modality: 'Cardinal',
10
+ polarity: 'Masculine',
11
+ ruler: 'Mars',
12
+ },
13
+ {
14
+ name: 'Taurus',
15
+ element: 'Earth',
16
+ modality: 'Fixed',
17
+ polarity: 'Feminine',
18
+ ruler: 'Venus',
19
+ },
20
+ {
21
+ name: 'Gemini',
22
+ element: 'Air',
23
+ modality: 'Mutable',
24
+ polarity: 'Masculine',
25
+ ruler: 'Mercury',
26
+ },
27
+ {
28
+ name: 'Cancer',
29
+ element: 'Water',
30
+ modality: 'Cardinal',
31
+ polarity: 'Feminine',
32
+ ruler: 'Moon',
33
+ },
34
+ {
35
+ name: 'Leo',
36
+ element: 'Fire',
37
+ modality: 'Fixed',
38
+ polarity: 'Masculine',
39
+ ruler: 'Sun',
40
+ },
41
+ {
42
+ name: 'Virgo',
43
+ element: 'Earth',
44
+ modality: 'Mutable',
45
+ polarity: 'Feminine',
46
+ ruler: 'Mercury',
47
+ },
48
+ {
49
+ name: 'Libra',
50
+ element: 'Air',
51
+ modality: 'Fixed',
52
+ polarity: 'Masculine',
53
+ ruler: 'Venus',
54
+ },
55
+ {
56
+ name: 'Scorpio',
57
+ element: 'Water',
58
+ modality: 'Fixed',
59
+ polarity: 'Feminine',
60
+ ruler: 'Mars',
61
+ },
62
+ {
63
+ name: 'Sagittarius',
64
+ element: 'Fire',
65
+ modality: 'Mutable',
66
+ polarity: 'Masculine',
67
+ ruler: 'Jupiter',
68
+ },
69
+ {
70
+ name: 'Capricorn',
71
+ element: 'Earth',
72
+ modality: 'Cardinal',
73
+ polarity: 'Feminine',
74
+ ruler: 'Saturn',
75
+ },
76
+ {
77
+ name: 'Aquarius',
78
+ element: 'Air',
79
+ modality: 'Fixed',
80
+ polarity: 'Masculine',
81
+ ruler: 'Saturn',
82
+ },
83
+ {
84
+ name: 'Pisces',
85
+ element: 'Water',
86
+ modality: 'Mutable',
87
+ polarity: 'Feminine',
88
+ ruler: 'Jupiter',
89
+ },
17
90
  ];
91
+ exports.ZODIAC_SIGNS = exports.ZODIAC_SIGN_DATA.map((s) => s.name);
18
92
  exports.DEFAULT_ASPECTS = [
19
- { name: 'conjunction', angle: 0, orb: 5 }, // Max orb for this aspect to be considered
20
- { name: 'opposition', angle: 180, orb: 5 },
21
- { name: 'trine', angle: 120, orb: 5 },
22
- { name: 'square', angle: 90, orb: 5 },
23
- { name: 'sextile', angle: 60, orb: 3 },
93
+ {
94
+ name: 'conjunction',
95
+ angle: 0,
96
+ orb: 5,
97
+ classification: types_1.AspectClassification.Major,
98
+ },
99
+ {
100
+ name: 'opposition',
101
+ angle: 180,
102
+ orb: 5,
103
+ classification: types_1.AspectClassification.Major,
104
+ },
105
+ {
106
+ name: 'trine',
107
+ angle: 120,
108
+ orb: 5,
109
+ classification: types_1.AspectClassification.Major,
110
+ },
111
+ {
112
+ name: 'square',
113
+ angle: 90,
114
+ orb: 5,
115
+ classification: types_1.AspectClassification.Major,
116
+ },
117
+ {
118
+ name: 'sextile',
119
+ angle: 60,
120
+ orb: 3,
121
+ classification: types_1.AspectClassification.Minor,
122
+ },
123
+ {
124
+ name: 'quincunx',
125
+ angle: 150,
126
+ orb: 2,
127
+ classification: types_1.AspectClassification.Minor,
128
+ },
24
129
  ];
25
- exports.DEFAULT_ASPECT_CATEGORIES = [
26
- { name: 'MAJOR', maxOrb: 2 }, // Orb < 2°
27
- { name: 'MODERATE', minOrb: 2, maxOrb: 4 }, // Orb 2-4°
130
+ // Simple Orb Presets - generous orbs for detection, classification handled separately
131
+ exports.SIMPLE_TRADITIONAL_ORBS = [
132
+ {
133
+ name: 'conjunction',
134
+ angle: 0,
135
+ orb: 10,
136
+ classification: types_1.AspectClassification.Major,
137
+ },
138
+ {
139
+ name: 'opposition',
140
+ angle: 180,
141
+ orb: 10,
142
+ classification: types_1.AspectClassification.Major,
143
+ },
144
+ {
145
+ name: 'trine',
146
+ angle: 120,
147
+ orb: 8,
148
+ classification: types_1.AspectClassification.Major,
149
+ },
150
+ {
151
+ name: 'square',
152
+ angle: 90,
153
+ orb: 8,
154
+ classification: types_1.AspectClassification.Major,
155
+ },
156
+ {
157
+ name: 'sextile',
158
+ angle: 60,
159
+ orb: 6,
160
+ classification: types_1.AspectClassification.Minor,
161
+ },
162
+ {
163
+ name: 'quincunx',
164
+ angle: 150,
165
+ orb: 4,
166
+ classification: types_1.AspectClassification.Minor,
167
+ },
28
168
  ];
169
+ exports.SIMPLE_MODERN_ORBS = [
170
+ {
171
+ name: 'conjunction',
172
+ angle: 0,
173
+ orb: 8,
174
+ classification: types_1.AspectClassification.Major,
175
+ },
176
+ {
177
+ name: 'opposition',
178
+ angle: 180,
179
+ orb: 8,
180
+ classification: types_1.AspectClassification.Major,
181
+ },
182
+ {
183
+ name: 'trine',
184
+ angle: 120,
185
+ orb: 6,
186
+ classification: types_1.AspectClassification.Major,
187
+ },
188
+ {
189
+ name: 'square',
190
+ angle: 90,
191
+ orb: 6,
192
+ classification: types_1.AspectClassification.Major,
193
+ },
194
+ {
195
+ name: 'sextile',
196
+ angle: 60,
197
+ orb: 4,
198
+ classification: types_1.AspectClassification.Minor,
199
+ },
200
+ {
201
+ name: 'quincunx',
202
+ angle: 150,
203
+ orb: 3,
204
+ classification: types_1.AspectClassification.Minor,
205
+ },
206
+ ];
207
+ exports.SIMPLE_TIGHT_ORBS = [
208
+ {
209
+ name: 'conjunction',
210
+ angle: 0,
211
+ orb: 4,
212
+ classification: types_1.AspectClassification.Major,
213
+ },
214
+ {
215
+ name: 'opposition',
216
+ angle: 180,
217
+ orb: 4,
218
+ classification: types_1.AspectClassification.Major,
219
+ },
220
+ {
221
+ name: 'trine',
222
+ angle: 120,
223
+ orb: 3,
224
+ classification: types_1.AspectClassification.Major,
225
+ },
226
+ {
227
+ name: 'square',
228
+ angle: 90,
229
+ orb: 3,
230
+ classification: types_1.AspectClassification.Major,
231
+ },
232
+ {
233
+ name: 'sextile',
234
+ angle: 60,
235
+ orb: 2,
236
+ classification: types_1.AspectClassification.Minor,
237
+ },
238
+ {
239
+ name: 'quincunx',
240
+ angle: 150,
241
+ orb: 1,
242
+ classification: types_1.AspectClassification.Minor,
243
+ },
244
+ ];
245
+ exports.SIMPLE_WIDE_ORBS = [
246
+ {
247
+ name: 'conjunction',
248
+ angle: 0,
249
+ orb: 12,
250
+ classification: types_1.AspectClassification.Major,
251
+ },
252
+ {
253
+ name: 'opposition',
254
+ angle: 180,
255
+ orb: 12,
256
+ classification: types_1.AspectClassification.Major,
257
+ },
258
+ {
259
+ name: 'trine',
260
+ angle: 120,
261
+ orb: 10,
262
+ classification: types_1.AspectClassification.Major,
263
+ },
264
+ {
265
+ name: 'square',
266
+ angle: 90,
267
+ orb: 10,
268
+ classification: types_1.AspectClassification.Major,
269
+ },
270
+ {
271
+ name: 'sextile',
272
+ angle: 60,
273
+ orb: 8,
274
+ classification: types_1.AspectClassification.Minor,
275
+ },
276
+ {
277
+ name: 'quincunx',
278
+ angle: 150,
279
+ orb: 6,
280
+ classification: types_1.AspectClassification.Minor,
281
+ },
282
+ {
283
+ name: 'semi-sextile',
284
+ angle: 30,
285
+ orb: 4,
286
+ classification: types_1.AspectClassification.Minor,
287
+ },
288
+ ];
289
+ // Legacy aliases for backwards compatibility
290
+ exports.TRADITIONAL_ASPECTS = exports.SIMPLE_TRADITIONAL_ORBS;
291
+ // Legacy aliases for backwards compatibility
292
+ exports.MODERN_ASPECTS = exports.SIMPLE_MODERN_ORBS;
293
+ exports.TIGHT_ASPECTS = exports.SIMPLE_TIGHT_ORBS;
294
+ exports.WIDE_ASPECTS = exports.SIMPLE_WIDE_ORBS;
295
+ // Default aspect strength thresholds
296
+ exports.DEFAULT_ASPECT_STRENGTH_THRESHOLDS = {
297
+ tight: 2.0, // Aspects with orb <= 2° are classified as tight
298
+ moderate: 4.0, // Aspects with orb 2-4° are moderate, >4° are wide
299
+ };
29
300
  exports.DEFAULT_SETTINGS = {
30
- // sign settings
31
- includeSignDegree: true, // For planets list: "Sun: 8° Cancer" vs "Sun: Cancer"
32
- // house settings
33
- houseSystemName: 'whole_sign',
34
- includeHouseDegree: false, // New format shows "House X", not degree in house for planets list
35
- // point settings
36
- includeAscendant: true, // Legacy, ASC/MC now have dedicated [ANGLES] section
37
- // orb + aspect settings
301
+ // Analysis settings
38
302
  aspectDefinitions: exports.DEFAULT_ASPECTS,
39
- aspectCategories: exports.DEFAULT_ASPECT_CATEGORIES,
40
303
  skipOutOfSignAspects: true,
41
- dateFormat: 'MM/DD/YYYY', // As per example output
304
+ includeAspectPatterns: false,
305
+ includeSignDistributions: true,
306
+ // Grouping settings
307
+ aspectStrengthThresholds: exports.DEFAULT_ASPECT_STRENGTH_THRESHOLDS,
308
+ // Formatting settings
309
+ houseSystemName: 'whole_sign',
310
+ dateFormat: 'MM/DD/YYYY',
42
311
  };
@@ -0,0 +1,6 @@
1
+ import { ChartData, MultiChartData, AstrologicalReport, PartialSettings } from '../types';
2
+ /**
3
+ * Analyzes single or multiple chart data and returns a structured report
4
+ * containing all detected astrological configurations without any formatting.
5
+ */
6
+ export declare function analyzeCharts(data: ChartData | MultiChartData, partialSettings?: PartialSettings): AstrologicalReport;
@@ -0,0 +1,235 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.analyzeCharts = analyzeCharts;
4
+ const types_1 = require("../types");
5
+ const ChartSettings_1 = require("../config/ChartSettings");
6
+ const validation_1 = require("../utils/validation");
7
+ const aspects_1 = require("./aspects");
8
+ const aspectPatterns_1 = require("./aspectPatterns");
9
+ const stelliums_1 = require("./stelliums");
10
+ const formatting_1 = require("../utils/formatting");
11
+ const signDistributions_1 = require("./signDistributions");
12
+ const dispositors_1 = require("./dispositors");
13
+ const houseCalculations_1 = require("../utils/houseCalculations");
14
+ // Helper functions
15
+ function getAllPointsFromChart(chartData) {
16
+ const allPoints = [...chartData.planets];
17
+ if (chartData.ascendant !== undefined) {
18
+ allPoints.push({ name: 'Ascendant', degree: chartData.ascendant });
19
+ }
20
+ if (chartData.midheaven !== undefined) {
21
+ allPoints.push({ name: 'Midheaven', degree: chartData.midheaven });
22
+ }
23
+ return allPoints;
24
+ }
25
+ function getPointsForPatternDetection(chartData) {
26
+ // Exclude angles and nodes from pattern detection
27
+ const excludedNames = ['Ascendant', 'Midheaven', 'North Node', 'South Node'];
28
+ return chartData.planets.filter((point) => !excludedNames.includes(point.name));
29
+ }
30
+ function getUnionedPoints(charts, forPatternDetection = false) {
31
+ return charts.flatMap((chart) => {
32
+ const points = forPatternDetection
33
+ ? getPointsForPatternDetection(chart)
34
+ : getAllPointsFromChart(chart);
35
+ return points.map((p) => [p, chart.name]);
36
+ });
37
+ }
38
+ function getChartNamesFromPattern(pattern) {
39
+ const chartNames = new Set();
40
+ const planetsToVisit = [];
41
+ const addPlanet = (p) => {
42
+ if (p)
43
+ planetsToVisit.push(p);
44
+ };
45
+ switch (pattern.type) {
46
+ case 'T-Square':
47
+ addPlanet(pattern.apex);
48
+ pattern.opposition.forEach(addPlanet);
49
+ break;
50
+ case 'Grand Trine':
51
+ pattern.planets.forEach(addPlanet);
52
+ break;
53
+ case 'Grand Cross':
54
+ pattern.planets.forEach(addPlanet);
55
+ break;
56
+ case 'Yod':
57
+ addPlanet(pattern.apex);
58
+ pattern.base.forEach(addPlanet);
59
+ break;
60
+ case 'Mystic Rectangle':
61
+ pattern.oppositions.flat().forEach(addPlanet);
62
+ break;
63
+ case 'Kite':
64
+ pattern.grandTrine.forEach(addPlanet);
65
+ addPlanet(pattern.opposition);
66
+ break;
67
+ }
68
+ planetsToVisit.forEach((p) => {
69
+ if (p.chartName) {
70
+ chartNames.add(p.chartName);
71
+ }
72
+ });
73
+ return chartNames;
74
+ }
75
+ function countUniqueCharts(pattern) {
76
+ return getChartNamesFromPattern(pattern).size;
77
+ }
78
+ function patternInvolvesChart(pattern, chartName) {
79
+ return getChartNamesFromPattern(pattern).has(chartName);
80
+ }
81
+ function filterPatternsByChartCount(patterns, minCharts, maxCharts = Infinity) {
82
+ return patterns.filter((pattern) => {
83
+ const count = countUniqueCharts(pattern);
84
+ return count >= minCharts && count <= maxCharts;
85
+ });
86
+ }
87
+ function filterPatternsByChartInvolvement(patterns, requiredChartNames) {
88
+ return patterns.filter((pattern) => {
89
+ return requiredChartNames.some((chartName) => patternInvolvesChart(pattern, chartName));
90
+ });
91
+ }
92
+ /**
93
+ * Analyzes single or multiple chart data and returns a structured report
94
+ * containing all detected astrological configurations without any formatting.
95
+ */
96
+ function analyzeCharts(data, partialSettings = {}) {
97
+ const validationError = (0, validation_1.validateInputData)(data);
98
+ if (validationError) {
99
+ throw new Error(`Invalid chart data: ${validationError}`);
100
+ }
101
+ const settings = new ChartSettings_1.ChartSettings(partialSettings);
102
+ const rawCharts = (0, types_1.isMultiChartData)(data) ? data : [data];
103
+ const nonTransitCharts = rawCharts.filter((c) => c.chartType !== 'transit');
104
+ const transitChart = rawCharts.find((c) => c.chartType === 'transit');
105
+ const allCharts = [
106
+ ...nonTransitCharts,
107
+ ...(transitChart ? [transitChart] : []),
108
+ ];
109
+ // === Unified Aspect Calculation ===
110
+ const allAspects = [];
111
+ const allUnionedPointsForPatterns = getUnionedPoints(allCharts, true);
112
+ // 1. Individual chart aspects
113
+ for (const chart of allCharts) {
114
+ const points = getUnionedPoints([chart]);
115
+ const aspects = (0, aspects_1.calculateAspects)(settings.resolvedAspectDefinitions, points, settings.skipOutOfSignAspects);
116
+ allAspects.push(...aspects);
117
+ }
118
+ // 2. Pairwise aspects (Synastry, Natal-Transit, etc.)
119
+ for (let i = 0; i < allCharts.length; i++) {
120
+ for (let j = i + 1; j < allCharts.length; j++) {
121
+ const chart1 = allCharts[i];
122
+ const chart2 = allCharts[j];
123
+ // Get unioned points from both charts for multi-chart analysis
124
+ const unionedPoints = [
125
+ ...getUnionedPoints([chart1]),
126
+ ...getUnionedPoints([chart2]),
127
+ ];
128
+ const aspects = (0, aspects_1.calculateMultichartAspects)(settings.resolvedAspectDefinitions, unionedPoints, settings.skipOutOfSignAspects);
129
+ allAspects.push(...aspects);
130
+ }
131
+ }
132
+ // === Unified Pattern Detection ===
133
+ const allPatterns = settings.includeAspectPatterns
134
+ ? (0, aspectPatterns_1.detectAspectPatterns)(allUnionedPointsForPatterns, allAspects)
135
+ : [];
136
+ // === Analysis Structuring ===
137
+ const chartAnalyses = [];
138
+ const pairwiseAnalyses = [];
139
+ const transitAnalyses = [];
140
+ let globalAnalysis;
141
+ let globalTransitAnalysis;
142
+ // Tier 1: Individual Chart Analysis
143
+ for (const chart of allCharts) {
144
+ const individualAspects = allAspects.filter((a) => a.p1ChartName === chart.name && a.p2ChartName === chart.name);
145
+ const individualPatterns = filterPatternsByChartCount(allPatterns, 1, 1).filter((p) => patternInvolvesChart(p, chart.name));
146
+ const stelliums = settings.includeAspectPatterns
147
+ ? (0, stelliums_1.detectStelliums)(getPointsForPatternDetection(chart), chart.houseCusps)
148
+ : [];
149
+ chartAnalyses.push({
150
+ chart: chart,
151
+ placements: {
152
+ planets: (0, formatting_1.getPlanetPositions)(chart.planets, chart.houseCusps),
153
+ },
154
+ aspects: individualAspects,
155
+ patterns: individualPatterns,
156
+ stelliums: stelliums,
157
+ signDistributions: settings.includeSignDistributions
158
+ ? (0, signDistributions_1.calculateSignDistributions)(chart.planets, chart.ascendant)
159
+ : { elements: {}, modalities: {}, polarities: {} },
160
+ dispositors: chart.chartType !== 'transit'
161
+ ? (0, dispositors_1.calculateDispositors)(chart.planets)
162
+ : {},
163
+ });
164
+ }
165
+ // Tier 2: Pairwise Synastry Analysis (non-transit charts)
166
+ if (nonTransitCharts.length >= 2) {
167
+ for (let i = 0; i < nonTransitCharts.length; i++) {
168
+ for (let j = i + 1; j < nonTransitCharts.length; j++) {
169
+ const chart1 = nonTransitCharts[i];
170
+ const chart2 = nonTransitCharts[j];
171
+ const synastryAspects = allAspects.filter((a) => (a.p1ChartName === chart1.name && a.p2ChartName === chart2.name) ||
172
+ (a.p1ChartName === chart2.name && a.p2ChartName === chart1.name));
173
+ const compositePatterns = filterPatternsByChartCount(allPatterns, 2, 2).filter((p) => patternInvolvesChart(p, chart1.name) &&
174
+ patternInvolvesChart(p, chart2.name));
175
+ pairwiseAnalyses.push({
176
+ chart1: chart1,
177
+ chart2: chart2,
178
+ synastryAspects: synastryAspects,
179
+ compositePatterns: compositePatterns,
180
+ houseOverlays: (0, houseCalculations_1.calculateHouseOverlays)(chart1, chart2),
181
+ });
182
+ }
183
+ }
184
+ }
185
+ // Tier 3: Global Analysis (3+ non-transit charts)
186
+ if (nonTransitCharts.length > 2) {
187
+ const globalPatterns = filterPatternsByChartCount(allPatterns, 3).filter((p) => {
188
+ // Ensure no transit charts are involved
189
+ const involvedCharts = getChartNamesFromPattern(p);
190
+ return !involvedCharts.has(transitChart?.name || 'TRANSIT_PLACEHOLDER');
191
+ });
192
+ if (globalPatterns.length > 0) {
193
+ globalAnalysis = {
194
+ charts: nonTransitCharts,
195
+ patterns: globalPatterns,
196
+ };
197
+ }
198
+ }
199
+ // Tier 4: Transit Analysis
200
+ if (transitChart) {
201
+ for (const natalChart of nonTransitCharts) {
202
+ const transitAspects = allAspects.filter((a) => (a.p1ChartName === natalChart.name &&
203
+ a.p2ChartName === transitChart.name) ||
204
+ (a.p1ChartName === transitChart.name &&
205
+ a.p2ChartName === natalChart.name));
206
+ const transitPatterns = filterPatternsByChartCount(allPatterns, 2, 2).filter((p) => patternInvolvesChart(p, natalChart.name) &&
207
+ patternInvolvesChart(p, transitChart.name));
208
+ transitAnalyses.push({
209
+ natalChart: natalChart,
210
+ transitChart: transitChart,
211
+ aspects: transitAspects,
212
+ patterns: transitPatterns,
213
+ });
214
+ }
215
+ // Tier 5: Global Transit Analysis (if there are natal charts)
216
+ if (nonTransitCharts.length > 0) {
217
+ const globalTransitPatterns = filterPatternsByChartInvolvement(allPatterns, [transitChart.name]).filter((p) => countUniqueCharts(p) >= 3); // Must involve transit + at least two other charts
218
+ if (globalTransitPatterns.length > 0) {
219
+ globalTransitAnalysis = {
220
+ charts: allCharts,
221
+ patterns: globalTransitPatterns,
222
+ };
223
+ }
224
+ }
225
+ }
226
+ const report = {
227
+ settings: settings,
228
+ chartAnalyses,
229
+ pairwiseAnalyses,
230
+ globalAnalysis,
231
+ transitAnalyses,
232
+ globalTransitAnalysis,
233
+ };
234
+ return report;
235
+ }
@@ -0,0 +1,10 @@
1
+ import { AspectData, AspectPattern, UnionedPoint } from '../types';
2
+ /**
3
+ * Main function to detect aspect patterns (excluding stelliums which are handled separately)
4
+ * This function works with both single-chart and multi-chart scenarios
5
+ * @param planets Array of planets to analyze
6
+ * @param aspects Pre-calculated aspects between planets
7
+ * @param houseCusps Optional house cusps for single-chart reference
8
+ * @param planetChartMap Optional mapping from planet name to chart name for multichart ownership context
9
+ */
10
+ export declare function detectAspectPatterns(unionedPoints: UnionedPoint[], aspects: AspectData[], houseCusps?: number[]): AspectPattern[];