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.
- package/README.md +103 -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 +10 -6
- package/dist/config/ChartSettings.js +22 -11
- package/dist/constants.d.ts +17 -2
- package/dist/constants.js +303 -34
- package/dist/core/analysis.d.ts +6 -0
- package/dist/core/analysis.js +237 -0
- package/dist/core/aspectPatterns.d.ts +8 -3
- package/dist/core/aspectPatterns.js +234 -218
- package/dist/core/aspects.d.ts +14 -11
- package/dist/core/aspects.js +49 -32
- package/dist/core/dignities.d.ts +2 -27
- package/dist/core/dignities.js +56 -121
- package/dist/core/dispositors.d.ts +7 -19
- package/dist/core/dispositors.js +152 -126
- package/dist/core/grouping.d.ts +9 -0
- package/dist/core/grouping.js +45 -0
- package/dist/core/signDistributions.d.ts +20 -30
- package/dist/core/signDistributions.js +25 -122
- package/dist/core/stelliums.d.ts +10 -0
- package/dist/core/stelliums.js +108 -0
- package/dist/formatters/text/sections/aspectPatterns.d.ts +3 -1
- package/dist/formatters/text/sections/aspectPatterns.js +118 -94
- package/dist/formatters/text/sections/aspects.d.ts +3 -6
- package/dist/formatters/text/sections/aspects.js +35 -52
- package/dist/formatters/text/sections/dispositors.d.ts +4 -3
- package/dist/formatters/text/sections/dispositors.js +12 -8
- package/dist/formatters/text/sections/houseOverlays.d.ts +11 -6
- package/dist/formatters/text/sections/houseOverlays.js +37 -44
- 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 +11 -22
- package/dist/formatters/text/sections/signDistributions.d.ts +9 -25
- package/dist/formatters/text/sections/signDistributions.js +9 -55
- package/dist/formatters/text/textFormatter.d.ts +4 -5
- package/dist/formatters/text/textFormatter.js +86 -142
- package/dist/index.d.ts +7 -4
- package/dist/index.js +11 -6
- package/dist/types.d.ts +102 -15
- package/dist/types.js +15 -0
- package/dist/utils/formatting.d.ts +4 -0
- package/dist/utils/formatting.js +43 -0
- package/dist/utils/houseCalculations.d.ts +10 -13
- package/dist/utils/houseCalculations.js +15 -57
- package/package.json +1 -1
package/dist/core/dispositors.js
CHANGED
|
@@ -1,143 +1,169 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const dignities_1 = require("./dignities");
|
|
3
|
+
exports.calculateDispositors = calculateDispositors;
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
const formatting_1 = require("../utils/formatting");
|
|
7
6
|
/**
|
|
8
|
-
*
|
|
9
|
-
* @param
|
|
10
|
-
* @returns
|
|
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.
|
|
11
10
|
*/
|
|
12
|
-
function
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
planets.forEach((planet) => {
|
|
17
|
-
const sign = (0, astrology_1.getDegreeSign)(planet.degree);
|
|
18
|
-
const rulers = (0, dignities_1.getSignRulers)(sign);
|
|
19
|
-
dispositorMap.set(planet.name, rulers);
|
|
20
|
-
rulers.forEach((ruler) => {
|
|
21
|
-
if (!disposedByMap.has(ruler)) {
|
|
22
|
-
disposedByMap.set(ruler, []);
|
|
23
|
-
}
|
|
24
|
-
disposedByMap.get(ruler).push(planet.name);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
// Find final dispositors - these are the roots of dispositor trees
|
|
28
|
-
const finalDispositors = [];
|
|
29
|
-
const planetNames = new Set(planets.map((p) => p.name));
|
|
30
|
-
planets.forEach((planet) => {
|
|
31
|
-
const rulers = dispositorMap.get(planet.name) || [];
|
|
32
|
-
const isRuledBySelf = rulers.includes(planet.name);
|
|
33
|
-
const isRuledByPlanetNotInChart = rulers.length > 0 && !rulers.some((ruler) => planetNames.has(ruler));
|
|
34
|
-
// A planet is a final dispositor if:
|
|
35
|
-
// 1. It rules itself (traditional dignity)
|
|
36
|
-
// 2. It's ruled by a planet not in the chart
|
|
37
|
-
if (isRuledBySelf || isRuledByPlanetNotInChart) {
|
|
38
|
-
finalDispositors.push(planet.name);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
// Build chains
|
|
42
|
-
const chains = planets.map((planet) => ({
|
|
43
|
-
planet: planet.name,
|
|
44
|
-
disposedBy: dispositorMap.get(planet.name) || [],
|
|
45
|
-
disposes: disposedByMap.get(planet.name) || [],
|
|
46
|
-
}));
|
|
47
|
-
return {
|
|
48
|
-
chains,
|
|
49
|
-
finalDispositors,
|
|
50
|
-
};
|
|
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';
|
|
51
15
|
}
|
|
52
16
|
/**
|
|
53
|
-
*
|
|
17
|
+
* Analyzes the dispositor graph for a single planet, using memoization to avoid re-computation.
|
|
18
|
+
* @param startPlanet - The planet to begin the analysis from.
|
|
19
|
+
* @param dispositorMap - A map of each planet to its direct dispositor.
|
|
20
|
+
* @param cache - A cache of already computed results to avoid redundant work.
|
|
21
|
+
* @returns The analysis result for the starting planet.
|
|
54
22
|
*/
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
23
|
+
function analyzePlanetChain(startPlanet, dispositorMap, cache) {
|
|
24
|
+
if (cache[startPlanet]) {
|
|
25
|
+
return cache[startPlanet];
|
|
26
|
+
}
|
|
27
|
+
const path = [startPlanet];
|
|
28
|
+
let current = startPlanet;
|
|
29
|
+
// eslint-disable-next-line no-constant-condition
|
|
30
|
+
while (true) {
|
|
31
|
+
const nextDispositor = dispositorMap[current];
|
|
32
|
+
if (!nextDispositor || !dispositorMap.hasOwnProperty(nextDispositor)) {
|
|
33
|
+
// Chain is broken (dispositor not in the chart)
|
|
34
|
+
const result = {
|
|
35
|
+
path: [...path, nextDispositor],
|
|
36
|
+
isCycle: false,
|
|
37
|
+
isFinal: false,
|
|
38
|
+
isBroken: true,
|
|
39
|
+
};
|
|
40
|
+
return (cache[startPlanet] = result);
|
|
71
41
|
}
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
for (const ruler of inChartRulers) {
|
|
82
|
-
dfs(ruler, [...currentPath]);
|
|
83
|
-
}
|
|
42
|
+
if (nextDispositor === current) {
|
|
43
|
+
// Final dispositor
|
|
44
|
+
const result = {
|
|
45
|
+
path,
|
|
46
|
+
isCycle: false,
|
|
47
|
+
isFinal: true,
|
|
48
|
+
isBroken: false,
|
|
49
|
+
};
|
|
50
|
+
return (cache[startPlanet] = result);
|
|
84
51
|
}
|
|
85
|
-
path.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
52
|
+
if (path.includes(nextDispositor)) {
|
|
53
|
+
// Cycle detected
|
|
54
|
+
const cycleStartIndex = path.indexOf(nextDispositor);
|
|
55
|
+
const cyclePath = path.slice(cycleStartIndex);
|
|
56
|
+
const result = {
|
|
57
|
+
path: [...path, nextDispositor],
|
|
58
|
+
isCycle: true,
|
|
59
|
+
isFinal: false,
|
|
60
|
+
isBroken: false,
|
|
61
|
+
};
|
|
62
|
+
// Cache the result for all members of the cycle
|
|
63
|
+
cyclePath.forEach((planet) => {
|
|
64
|
+
cache[planet] = result;
|
|
65
|
+
});
|
|
66
|
+
return result;
|
|
92
67
|
}
|
|
93
|
-
|
|
94
|
-
|
|
68
|
+
// If we've hit a node that's already been analyzed, we can use its result
|
|
69
|
+
if (cache[nextDispositor]) {
|
|
70
|
+
const nestedResult = cache[nextDispositor];
|
|
71
|
+
const combinedPath = [...path, ...nestedResult.path];
|
|
72
|
+
const result = { ...nestedResult, path: combinedPath };
|
|
73
|
+
return (cache[startPlanet] = result);
|
|
74
|
+
}
|
|
75
|
+
path.push(nextDispositor);
|
|
76
|
+
current = nextDispositor;
|
|
77
|
+
}
|
|
95
78
|
}
|
|
96
79
|
/**
|
|
97
|
-
*
|
|
98
|
-
* @param
|
|
99
|
-
* @param
|
|
100
|
-
* @
|
|
101
|
-
* @returns Array of planets in the chain (excluding the starting planet)
|
|
80
|
+
* Calculates the full dispositor chain for each planet in the chart.
|
|
81
|
+
* @param planets The list of planets in the chart.
|
|
82
|
+
* @param mode Controls which dispositor chains to include: true (all), false (none), 'finals' (only final dispositors and cycles).
|
|
83
|
+
* @returns A map of each planet to its full dispositor chain string, or a summary in 'finals' mode.
|
|
102
84
|
*/
|
|
103
|
-
function
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return ['(final)'];
|
|
85
|
+
function calculateDispositors(planets, mode = true) {
|
|
86
|
+
if (mode === false) {
|
|
87
|
+
return {};
|
|
107
88
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
89
|
+
const dispositorMap = {};
|
|
90
|
+
planets.forEach((p) => {
|
|
91
|
+
dispositorMap[p.name] = getDispositor(p);
|
|
92
|
+
});
|
|
93
|
+
const analysisCache = {};
|
|
94
|
+
planets.forEach((p) => {
|
|
95
|
+
if (!analysisCache[p.name]) {
|
|
96
|
+
analyzePlanetChain(p.name, dispositorMap, analysisCache);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
if (mode === 'finals') {
|
|
100
|
+
const finalDispositors = new Set();
|
|
101
|
+
const cycles = new Map();
|
|
102
|
+
planets.forEach((p) => {
|
|
103
|
+
if (dispositorMap[p.name] === p.name) {
|
|
104
|
+
finalDispositors.add(p.name);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
for (const planetName in analysisCache) {
|
|
108
|
+
const result = analysisCache[planetName];
|
|
109
|
+
if (result.isCycle) {
|
|
110
|
+
const lastPlanetInPath = result.path[result.path.length - 1];
|
|
111
|
+
const cycleStartIndex = result.path.indexOf(lastPlanetInPath);
|
|
112
|
+
const cyclePlanets = result.path.slice(cycleStartIndex, -1);
|
|
113
|
+
const canonicalKey = [...new Set(cyclePlanets)].sort().join('|');
|
|
114
|
+
if (!cycles.has(canonicalKey)) {
|
|
115
|
+
cycles.set(canonicalKey, cyclePlanets);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const summaryParts = [];
|
|
120
|
+
if (finalDispositors.size > 0) {
|
|
121
|
+
summaryParts.push(`Final dispositors: ${[...finalDispositors].sort().join(', ')}`);
|
|
122
|
+
}
|
|
123
|
+
if (cycles.size > 0) {
|
|
124
|
+
const formattedCycles = [...cycles.values()]
|
|
125
|
+
.map((cycle) => {
|
|
126
|
+
const uniqueCyclePlanets = [...new Set(cycle)];
|
|
127
|
+
const startNode = uniqueCyclePlanets.sort()[0];
|
|
128
|
+
const startIndex = cycle.indexOf(startNode);
|
|
129
|
+
const reordered = [
|
|
130
|
+
...cycle.slice(startIndex),
|
|
131
|
+
...cycle.slice(0, startIndex),
|
|
132
|
+
];
|
|
133
|
+
return [...reordered, startNode].join(' → ');
|
|
134
|
+
})
|
|
135
|
+
.sort();
|
|
136
|
+
summaryParts.push(`Cycles: ${formattedCycles.join(', ')}`);
|
|
137
|
+
}
|
|
138
|
+
if (summaryParts.length === 0) {
|
|
139
|
+
return { summary: 'No final dispositors or cycles found' };
|
|
140
|
+
}
|
|
141
|
+
return { summary: summaryParts.join('; ') };
|
|
121
142
|
}
|
|
122
|
-
//
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
143
|
+
// Default mode: return all chains
|
|
144
|
+
const chains = {};
|
|
145
|
+
planets.forEach((p) => {
|
|
146
|
+
const planetName = p.name;
|
|
147
|
+
const path = [planetName];
|
|
148
|
+
let current = planetName;
|
|
149
|
+
// eslint-disable-next-line no-constant-condition
|
|
150
|
+
while (true) {
|
|
151
|
+
const nextDispositor = dispositorMap[current];
|
|
152
|
+
if (!nextDispositor || !dispositorMap.hasOwnProperty(nextDispositor)) {
|
|
153
|
+
chains[planetName] = `${path.join(' → ')} → ${nextDispositor} (not in chart)`;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
if (nextDispositor === current) {
|
|
157
|
+
chains[planetName] = `${path.join(' → ')} → (final)`;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
if (path.includes(nextDispositor)) {
|
|
161
|
+
chains[planetName] = `${path.join(' → ')} → ${nextDispositor} (cycle)`;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
path.push(nextDispositor);
|
|
165
|
+
current = nextDispositor;
|
|
166
|
+
}
|
|
141
167
|
});
|
|
142
|
-
return
|
|
168
|
+
return chains;
|
|
143
169
|
}
|
|
@@ -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
|
+
}
|
|
@@ -1,31 +1,21 @@
|
|
|
1
1
|
import { Point } from '../types';
|
|
2
|
-
export
|
|
3
|
-
elements:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export declare function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export declare function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
* @param modalities Modality distribution data
|
|
23
|
-
* @returns Array of formatted strings
|
|
24
|
-
*/
|
|
25
|
-
export declare function formatModalityDistribution(modalities: Record<string, number>): string[];
|
|
26
|
-
/**
|
|
27
|
-
* Formats polarity distribution for display
|
|
28
|
-
* @param polarities Polarity distribution data
|
|
29
|
-
* @returns Array of formatted strings
|
|
30
|
-
*/
|
|
31
|
-
export declare function formatPolarityDistribution(polarities: Record<string, number>): string[];
|
|
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[];
|
|
@@ -1,60 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.calculateSignDistributions = calculateSignDistributions;
|
|
4
4
|
exports.formatElementDistribution = formatElementDistribution;
|
|
5
5
|
exports.formatModalityDistribution = formatModalityDistribution;
|
|
6
6
|
exports.formatPolarityDistribution = formatPolarityDistribution;
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Virgo: 'Earth',
|
|
15
|
-
Capricorn: 'Earth',
|
|
16
|
-
Gemini: 'Air',
|
|
17
|
-
Libra: 'Air',
|
|
18
|
-
Aquarius: 'Air',
|
|
19
|
-
Cancer: 'Water',
|
|
20
|
-
Scorpio: 'Water',
|
|
21
|
-
Pisces: 'Water',
|
|
22
|
-
};
|
|
23
|
-
const SIGN_MODALITIES = {
|
|
24
|
-
Aries: 'Cardinal',
|
|
25
|
-
Cancer: 'Cardinal',
|
|
26
|
-
Libra: 'Cardinal',
|
|
27
|
-
Capricorn: 'Cardinal',
|
|
28
|
-
Taurus: 'Fixed',
|
|
29
|
-
Leo: 'Fixed',
|
|
30
|
-
Scorpio: 'Fixed',
|
|
31
|
-
Aquarius: 'Fixed',
|
|
32
|
-
Gemini: 'Mutable',
|
|
33
|
-
Virgo: 'Mutable',
|
|
34
|
-
Sagittarius: 'Mutable',
|
|
35
|
-
Pisces: 'Mutable',
|
|
36
|
-
};
|
|
37
|
-
const SIGN_POLARITIES = {
|
|
38
|
-
Aries: 'Masculine',
|
|
39
|
-
Gemini: 'Masculine',
|
|
40
|
-
Leo: 'Masculine',
|
|
41
|
-
Libra: 'Masculine',
|
|
42
|
-
Sagittarius: 'Masculine',
|
|
43
|
-
Aquarius: 'Masculine',
|
|
44
|
-
Taurus: 'Feminine',
|
|
45
|
-
Cancer: 'Feminine',
|
|
46
|
-
Virgo: 'Feminine',
|
|
47
|
-
Scorpio: 'Feminine',
|
|
48
|
-
Capricorn: 'Feminine',
|
|
49
|
-
Pisces: 'Feminine',
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Analyzes the distribution of planets across elements, modalities, and polarities
|
|
53
|
-
* @param planets Array of planet points
|
|
54
|
-
* @param includeAscendant Optional ascendant degree to include in analysis
|
|
55
|
-
* @returns Sign distribution analysis
|
|
56
|
-
*/
|
|
57
|
-
function analyzeSignDistributions(planets, includeAscendant) {
|
|
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
|
+
}
|
|
58
14
|
const elements = {
|
|
59
15
|
Fire: [],
|
|
60
16
|
Earth: [],
|
|
@@ -66,85 +22,32 @@ function analyzeSignDistributions(planets, includeAscendant) {
|
|
|
66
22
|
Fixed: 0,
|
|
67
23
|
Mutable: 0,
|
|
68
24
|
};
|
|
69
|
-
const polarities = {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const modality = SIGN_MODALITIES[sign];
|
|
78
|
-
const polarity = SIGN_POLARITIES[sign];
|
|
79
|
-
if (element) {
|
|
80
|
-
elements[element].push(planet.name);
|
|
81
|
-
}
|
|
82
|
-
if (modality) {
|
|
83
|
-
modalities[modality]++;
|
|
84
|
-
}
|
|
85
|
-
if (polarity) {
|
|
86
|
-
polarities[polarity]++;
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
// Process ascendant if provided
|
|
90
|
-
if (includeAscendant !== undefined) {
|
|
91
|
-
const ascSign = (0, astrology_1.getDegreeSign)(includeAscendant);
|
|
92
|
-
const ascElement = SIGN_ELEMENTS[ascSign];
|
|
93
|
-
const ascModality = SIGN_MODALITIES[ascSign];
|
|
94
|
-
const ascPolarity = SIGN_POLARITIES[ascSign];
|
|
95
|
-
if (ascElement) {
|
|
96
|
-
elements[ascElement].push('Ascendant');
|
|
97
|
-
}
|
|
98
|
-
if (ascModality) {
|
|
99
|
-
modalities[ascModality]++;
|
|
100
|
-
}
|
|
101
|
-
if (ascPolarity) {
|
|
102
|
-
polarities[ascPolarity]++;
|
|
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]++;
|
|
103
33
|
}
|
|
104
34
|
}
|
|
105
35
|
return { elements, modalities, polarities };
|
|
106
36
|
}
|
|
107
|
-
/**
|
|
108
|
-
* Formats element distribution for display
|
|
109
|
-
* @param elements Element distribution data
|
|
110
|
-
* @returns Array of formatted strings
|
|
111
|
-
*/
|
|
112
37
|
function formatElementDistribution(elements) {
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const planetList = planets.join(', ');
|
|
117
|
-
output.push(`${element}: ${planets.length} (${planetList})`);
|
|
38
|
+
const parts = Object.entries(elements).map(([element, planets]) => {
|
|
39
|
+
if (planets.length === 0) {
|
|
40
|
+
return `${element}: 0`;
|
|
118
41
|
}
|
|
42
|
+
return `${element}: ${planets.length} (${planets.join(', ')})`;
|
|
119
43
|
});
|
|
120
|
-
return
|
|
44
|
+
return [parts.join(' | ')];
|
|
121
45
|
}
|
|
122
|
-
/**
|
|
123
|
-
* Formats modality distribution for display
|
|
124
|
-
* @param modalities Modality distribution data
|
|
125
|
-
* @returns Array of formatted strings
|
|
126
|
-
*/
|
|
127
46
|
function formatModalityDistribution(modalities) {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
if (count > 0) {
|
|
131
|
-
output.push(`${modality}: ${count}`);
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
return output;
|
|
47
|
+
const parts = Object.entries(modalities).map(([modality, count]) => `${modality}: ${count}`);
|
|
48
|
+
return [parts.join(' | ')];
|
|
135
49
|
}
|
|
136
|
-
/**
|
|
137
|
-
* Formats polarity distribution for display
|
|
138
|
-
* @param polarities Polarity distribution data
|
|
139
|
-
* @returns Array of formatted strings
|
|
140
|
-
*/
|
|
141
50
|
function formatPolarityDistribution(polarities) {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
output.push(`Masculine (Active): ${polarities['Masculine']}`);
|
|
145
|
-
}
|
|
146
|
-
if (polarities['Feminine'] > 0) {
|
|
147
|
-
output.push(`Feminine (Receptive): ${polarities['Feminine']}`);
|
|
148
|
-
}
|
|
149
|
-
return output;
|
|
51
|
+
const parts = Object.entries(polarities).map(([polarity, count]) => `${polarity}: ${count}`);
|
|
52
|
+
return [parts.join(' | ')];
|
|
150
53
|
}
|
|
@@ -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[];
|