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.
- package/README.md +101 -34
- package/dist/chart2txt.d.ts +9 -0
- package/dist/chart2txt.js +30 -0
- package/dist/chart2txt.min.js +1 -1
- package/dist/config/ChartSettings.d.ts +13 -6
- package/dist/config/ChartSettings.js +36 -10
- package/dist/constants.d.ts +17 -2
- package/dist/constants.js +301 -32
- package/dist/core/analysis.d.ts +6 -0
- package/dist/core/analysis.js +235 -0
- package/dist/core/aspectPatterns.d.ts +10 -0
- package/dist/core/aspectPatterns.js +460 -0
- package/dist/core/aspects.d.ts +14 -11
- package/dist/core/aspects.js +142 -40
- package/dist/core/astrology.d.ts +8 -2
- package/dist/core/astrology.js +23 -6
- package/dist/core/dignities.d.ts +2 -0
- package/dist/core/dignities.js +71 -0
- package/dist/core/dispositors.d.ts +9 -0
- package/dist/core/dispositors.js +57 -0
- package/dist/core/grouping.d.ts +9 -0
- package/dist/core/grouping.js +45 -0
- package/dist/core/signDistributions.d.ts +21 -0
- package/dist/core/signDistributions.js +50 -0
- package/dist/core/stelliums.d.ts +10 -0
- package/dist/core/stelliums.js +108 -0
- package/dist/formatters/text/sections/angles.js +4 -4
- package/dist/formatters/text/sections/aspectPatterns.d.ts +9 -0
- package/dist/formatters/text/sections/aspectPatterns.js +199 -0
- package/dist/formatters/text/sections/aspects.d.ts +3 -6
- package/dist/formatters/text/sections/aspects.js +35 -49
- package/dist/formatters/text/sections/birthdata.js +1 -1
- package/dist/formatters/text/sections/dispositors.d.ts +8 -0
- package/dist/formatters/text/sections/dispositors.js +19 -0
- package/dist/formatters/text/sections/houseOverlays.d.ts +11 -6
- package/dist/formatters/text/sections/houseOverlays.js +38 -69
- package/dist/formatters/text/sections/houses.d.ts +6 -0
- package/dist/formatters/text/sections/houses.js +36 -0
- package/dist/formatters/text/sections/metadata.d.ts +2 -0
- package/dist/formatters/text/sections/metadata.js +54 -0
- package/dist/formatters/text/sections/planets.d.ts +3 -5
- package/dist/formatters/text/sections/planets.js +12 -38
- package/dist/formatters/text/sections/signDistributions.d.ts +9 -0
- package/dist/formatters/text/sections/signDistributions.js +21 -0
- package/dist/formatters/text/textFormatter.d.ts +4 -5
- package/dist/formatters/text/textFormatter.js +86 -112
- package/dist/index.d.ts +7 -4
- package/dist/index.js +11 -6
- package/dist/types.d.ts +159 -13
- package/dist/types.js +15 -0
- package/dist/utils/formatting.d.ts +10 -0
- package/dist/utils/formatting.js +56 -0
- package/dist/utils/houseCalculations.d.ts +10 -0
- package/dist/utils/houseCalculations.js +23 -0
- package/dist/utils/precision.d.ts +49 -0
- package/dist/utils/precision.js +71 -0
- package/dist/utils/validation.d.ts +37 -0
- package/dist/utils/validation.js +181 -0
- package/package.json +2 -1
package/dist/core/aspects.js
CHANGED
|
@@ -2,31 +2,130 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.calculateAspects = calculateAspects;
|
|
4
4
|
exports.calculateMultichartAspects = calculateMultichartAspects;
|
|
5
|
-
|
|
6
|
-
|
|
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(
|
|
14
|
-
const planetBSign = Math.floor(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
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,
|
|
144
|
+
function calculateAspects(aspectDefinitions, unionedPlanets, skipOutOfSignAspects = true) {
|
|
43
145
|
const aspects = [];
|
|
44
|
-
if (!
|
|
146
|
+
if (!unionedPlanets || unionedPlanets.length < 2)
|
|
45
147
|
return aspects;
|
|
46
|
-
for (let i = 0; i <
|
|
47
|
-
for (let j = i + 1; j <
|
|
48
|
-
const planetA =
|
|
49
|
-
const planetB =
|
|
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
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* @param
|
|
62
|
-
* @param
|
|
63
|
-
* @param
|
|
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,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
184
|
+
return crossChartAspects;
|
|
83
185
|
}
|
package/dist/core/astrology.d.ts
CHANGED
|
@@ -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 (
|
|
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 (
|
|
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;
|
package/dist/core/astrology.js
CHANGED
|
@@ -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 (
|
|
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
|
|
28
|
+
const normalizedDegree = normalizeDegree(degree);
|
|
29
|
+
const signIndex = Math.floor(normalizedDegree / 30);
|
|
13
30
|
if (signIndex < 0 || signIndex >= constants_1.ZODIAC_SIGNS.length) {
|
|
14
|
-
|
|
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 (
|
|
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
|
-
|
|
42
|
+
const normalizedDegree = normalizeDegree(degree);
|
|
43
|
+
return normalizedDegree % 30;
|
|
27
44
|
}
|
|
@@ -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[];
|