chart2txt 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # chart2txt
2
+
3
+ A TypeScript library that converts astrological chart data to human-readable text.
4
+
5
+ ## Features
6
+
7
+ - Convert planet positions to text descriptions of their zodiac signs
8
+ - Calculate and describe house placements when an ascendant is provided
9
+ - Calculate and describe aspects between planets
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install chart2txt
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```typescript
20
+ import { chart2txt } from 'chart2txt';
21
+
22
+ const chartData = {
23
+ planets: [
24
+ { name: 'Sun', longitude: 35 }, // 5° Taurus
25
+ { name: 'Moon', longitude: 120 }, // 0° Leo
26
+ { name: 'Mercury', longitude: 75 } // 15° Gemini
27
+ ],
28
+ ascendant: 0 // 0° Aries
29
+ };
30
+
31
+ const settings = {
32
+ // modified settings go here
33
+ };
34
+
35
+ const textDescription = chart2txt(chartData, settings);
36
+ console.log(textDescription);
37
+ ```
38
+
39
+ ### Settings
40
+
41
+ The conversion to text is configurable through the settings object. Any number of provided settings can be specified, and will overwrite the defaults when provided. Explanations of each setting can be found in the [types.ts](src/types.ts) file, and the default settings can be found in the [constants.ts](src/constants.ts) file. See the [tests file](tests/index.test.ts) for example uses of each setting.
42
+
43
+ **NOTE**: Overriding aspects must be done by replacing the entire object, i.e. by modifying the following data object to suit your needs:
44
+
45
+ ```javascript
46
+ [
47
+ { name: 'conjunction', angle: 0, orb: 5 },
48
+ { name: 'opposition', angle: 180, orb: 5 },
49
+ { name: 'trine', angle: 120, orb: 5 },
50
+ { name: 'square', angle: 90, orb: 5 },
51
+ { name: 'sextile', angle: 60, orb: 3 },
52
+ ]
53
+ ```
54
+
55
+ ## Development
56
+
57
+ ```bash
58
+ # Install dependencies
59
+ npm install
60
+
61
+ # Run tests
62
+ npm test
63
+
64
+ # Build the library
65
+ npm run build
66
+
67
+ # Lint code
68
+ npm run lint
69
+
70
+ # Format code
71
+ npm run format
72
+ ```
73
+
74
+ ## License
75
+
76
+ MIT
@@ -0,0 +1,4 @@
1
+ import { Aspect, Settings } from './types';
2
+ export declare const ZODIAC_SIGNS: string[];
3
+ export declare const DEFAULT_ASPECTS: Aspect[];
4
+ export declare const DEFAULT_SETTINGS: Settings;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_SETTINGS = 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',
17
+ ];
18
+ exports.DEFAULT_ASPECTS = [
19
+ { name: 'conjunction', angle: 0, orb: 5 },
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 },
24
+ ];
25
+ exports.DEFAULT_SETTINGS = {
26
+ // sign settings
27
+ includeSignDegree: true,
28
+ omitSigns: false,
29
+ // house settings
30
+ houseSystem: 'equal',
31
+ includeHouseDegree: false,
32
+ omitHouses: false,
33
+ // point settings
34
+ includeAscendant: true,
35
+ omitPoints: false,
36
+ // orb + aspect settings
37
+ aspectDefinitions: exports.DEFAULT_ASPECTS,
38
+ omitAspects: false,
39
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * chart2txt
3
+ * A library to convert astrological chart data to human-readable text
4
+ */
5
+ import type { Point, ChartData, Settings } from './types';
6
+ /**
7
+ * Main function to convert chart data to text
8
+ */
9
+ export declare function chart2txt(data: ChartData, settings?: Partial<Settings>): string;
10
+ export { ChartData, Point, Settings };
package/dist/index.js ADDED
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ /**
3
+ * chart2txt
4
+ * A library to convert astrological chart data to human-readable text
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.chart2txt = chart2txt;
8
+ const constants_1 = require("./constants");
9
+ /**
10
+ * Determines the zodiac sign for a given longitude
11
+ */
12
+ function getLongitudeSign(longitude) {
13
+ const signIndex = Math.floor(longitude / 30) % 12;
14
+ return constants_1.ZODIAC_SIGNS[signIndex];
15
+ }
16
+ /**
17
+ * Calculates the house for a given longitude, based on the ascendant
18
+ */
19
+ function getHousePosition(houseSystem, longitude, ascendant) {
20
+ switch (houseSystem) {
21
+ case 'equal': {
22
+ // House 1 starts at the ascendant
23
+ const housePosition = (longitude - ascendant + 360) % 360;
24
+ const house = Math.floor(housePosition / 30) + 1;
25
+ const degree = housePosition % 30;
26
+ return { house, degree };
27
+ }
28
+ case 'whole_sign': {
29
+ // House 1 starts at beginning of ascendant sign
30
+ const house1SignCusp = (Math.floor(ascendant / 30) % 12) * 30;
31
+ // Computation proceeds same as equal, using sign cusp
32
+ const housePosition = (longitude - house1SignCusp + 360) % 360;
33
+ const house = Math.floor(housePosition / 30) + 1;
34
+ const degree = housePosition % 30;
35
+ return { house, degree };
36
+ }
37
+ }
38
+ }
39
+ /**
40
+ * Identifies aspects between planets
41
+ */
42
+ function calculateAspects(aspectDefinitions, planets) {
43
+ const aspects = [];
44
+ // Compare each planet with every other planet
45
+ for (let i = 0; i < planets.length; i++) {
46
+ for (let j = i + 1; j < planets.length; j++) {
47
+ const planetA = planets[i];
48
+ const planetB = planets[j];
49
+ // Calculate the angular difference
50
+ let diff = Math.abs(planetA.longitude - planetB.longitude);
51
+ if (diff > 180)
52
+ diff = 360 - diff;
53
+ // Check against each aspect type
54
+ for (const aspectType of aspectDefinitions) {
55
+ const orb = Math.abs(diff - aspectType.angle);
56
+ if (orb <= aspectType.orb) {
57
+ aspects.push({
58
+ planetA: planetA.name,
59
+ planetB: planetB.name,
60
+ aspectType: aspectType.name,
61
+ orb,
62
+ });
63
+ break; // Only record the strongest aspect between two planets
64
+ }
65
+ }
66
+ }
67
+ }
68
+ return aspects;
69
+ }
70
+ /**
71
+ * Formats planet sign positions as text
72
+ */
73
+ function formatPlanetSigns(planets, ascendant, points = [], includeDegree = constants_1.DEFAULT_SETTINGS.includeSignDegree) {
74
+ const ascPoint = ascendant
75
+ ? [{ name: 'Ascendant', longitude: ascendant }]
76
+ : [];
77
+ const output = [...ascPoint, ...planets, ...points]
78
+ .map((planet) => {
79
+ const sign = getLongitudeSign(planet.longitude);
80
+ if (includeDegree) {
81
+ const degree = Math.floor(planet.longitude % 30);
82
+ return `${planet.name} is at ${degree}° ${sign}`;
83
+ }
84
+ else {
85
+ return `${planet.name} is in ${sign}`;
86
+ }
87
+ })
88
+ .join('. ');
89
+ return output ? `${output}.` : '';
90
+ }
91
+ /**
92
+ * Formats planet house positions as text
93
+ */
94
+ function formatPlanetHouses(houseSystem, ascendant, planets, points = [], includeDegree = constants_1.DEFAULT_SETTINGS.includeHouseDegree) {
95
+ // TODO: house systems
96
+ const output = [...planets, ...points]
97
+ .map((planet) => {
98
+ const houseData = getHousePosition(houseSystem, planet.longitude, ascendant);
99
+ if (includeDegree) {
100
+ return `${planet.name} is at ${houseData.degree}° in house ${houseData.house}`;
101
+ }
102
+ else {
103
+ return `${planet.name} is in house ${houseData.house}`;
104
+ }
105
+ })
106
+ .join('. ');
107
+ return output ? `${output}.` : '';
108
+ }
109
+ /**
110
+ * Formats aspects between planets as text
111
+ */
112
+ function formatAspects(aspects) {
113
+ const output = aspects
114
+ .map((aspect) => {
115
+ return `${aspect.planetA} is in ${aspect.aspectType} with ${aspect.planetB} (orb: ${aspect.orb.toFixed(1)}°)`;
116
+ })
117
+ .join('. ');
118
+ return output ? `${output}.` : '';
119
+ }
120
+ /**
121
+ * Formats provided location and time, if present, as text
122
+ */
123
+ function formatLocationAndDate(location, timestamp) {
124
+ const locationString = location ? `location: ${location}` : '';
125
+ const timestampString = timestamp ? `at: ${timestamp.toISOString()}` : '';
126
+ return [locationString, timestampString].filter((s) => s !== '').join(', ');
127
+ }
128
+ /**
129
+ * Main function to convert chart data to text
130
+ */
131
+ function chart2txt(data, settings = {}) {
132
+ // override default settings with any provided settings data
133
+ const fullSettings = Object.assign({}, constants_1.DEFAULT_SETTINGS, settings);
134
+ // format header
135
+ let result = 'Astrology Chart';
136
+ const locationAndDate = formatLocationAndDate(data.location, data.timestamp);
137
+ if (locationAndDate) {
138
+ result += ` (${locationAndDate})`;
139
+ }
140
+ result += ':\n\n';
141
+ // format planets
142
+ if (!fullSettings.omitSigns) {
143
+ result += formatPlanetSigns(data.planets, fullSettings.includeAscendant && data.ascendant
144
+ ? data.ascendant
145
+ : undefined, fullSettings.omitPoints ? [] : data.points, fullSettings.includeSignDegree);
146
+ }
147
+ // format houses
148
+ if (!fullSettings.omitHouses && data.ascendant !== undefined) {
149
+ result +=
150
+ '\n\n' +
151
+ formatPlanetHouses(fullSettings.houseSystem, data.ascendant, data.planets, fullSettings.omitPoints ? [] : data.points, fullSettings.includeHouseDegree);
152
+ }
153
+ // format aspects
154
+ if (!fullSettings.omitAspects) {
155
+ const aspects = calculateAspects(fullSettings.aspectDefinitions, data.planets);
156
+ if (aspects.length > 0) {
157
+ result += '\n\n' + formatAspects(aspects);
158
+ }
159
+ }
160
+ return result;
161
+ }
@@ -0,0 +1,34 @@
1
+ export interface Point {
2
+ name: string;
3
+ longitude: number;
4
+ }
5
+ export interface ChartData {
6
+ planets: Point[];
7
+ ascendant?: number;
8
+ points?: Point[];
9
+ timestamp?: Date;
10
+ location?: string;
11
+ }
12
+ export interface Aspect {
13
+ name: string;
14
+ angle: number;
15
+ orb: number;
16
+ }
17
+ export interface AspectData {
18
+ planetA: string;
19
+ planetB: string;
20
+ aspectType: string;
21
+ orb: number;
22
+ }
23
+ export type HouseSystem = 'whole_sign' | 'equal';
24
+ export interface Settings {
25
+ includeSignDegree: boolean;
26
+ omitSigns: boolean;
27
+ includeAscendant: boolean;
28
+ omitPoints: boolean;
29
+ includeHouseDegree: boolean;
30
+ houseSystem: HouseSystem;
31
+ omitHouses: boolean;
32
+ aspectDefinitions: Aspect[];
33
+ omitAspects: boolean;
34
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "chart2txt",
3
+ "version": "0.1.0",
4
+ "description": "Convert astrological chart data to human-readable text",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "test": "jest",
10
+ "lint": "eslint src/**/*.ts",
11
+ "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\""
12
+ },
13
+ "keywords": [
14
+ "astrology",
15
+ "chart",
16
+ "text"
17
+ ],
18
+ "homepage": "https://github.com/simpolism/chart2txt",
19
+ "author": "simpolism <simpolism@gmail.com>",
20
+ "license": "MIT",
21
+ "devDependencies": {
22
+ "@types/jest": "^29.5.0",
23
+ "@types/node": "^18.0.0",
24
+ "@typescript-eslint/eslint-plugin": "^5.0.0",
25
+ "@typescript-eslint/parser": "^5.0.0",
26
+ "eslint": "^8.0.0",
27
+ "eslint-config-prettier": "^8.0.0",
28
+ "jest": "^29.0.0",
29
+ "prettier": "^2.0.0",
30
+ "ts-jest": "^29.1.0",
31
+ "typescript": "^5.0.0"
32
+ }
33
+ }