ether-to-astro 1.0.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/.env.example +13 -0
- package/.github/pull_request_template.md +16 -0
- package/.github/workflows/release.yml +35 -0
- package/.github/workflows/test.yml +32 -0
- package/AGENTS.md +99 -0
- package/LICENSE +18 -0
- package/NOTICE.md +45 -0
- package/README.md +301 -0
- package/SETUP.md +70 -0
- package/TESTING_SUMMARY.md +238 -0
- package/TEST_SUITE_STATUS.md +218 -0
- package/biome.json +48 -0
- package/dist/astro-service.d.ts +98 -0
- package/dist/astro-service.js +496 -0
- package/dist/chart-types.d.ts +52 -0
- package/dist/chart-types.js +51 -0
- package/dist/charts.d.ts +125 -0
- package/dist/charts.js +324 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.js +472 -0
- package/dist/constants.d.ts +81 -0
- package/dist/constants.js +76 -0
- package/dist/eclipses.d.ts +85 -0
- package/dist/eclipses.js +184 -0
- package/dist/ephemeris.d.ts +120 -0
- package/dist/ephemeris.js +379 -0
- package/dist/formatter.d.ts +2 -0
- package/dist/formatter.js +22 -0
- package/dist/houses.d.ts +82 -0
- package/dist/houses.js +169 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +150 -0
- package/dist/loader.d.ts +2 -0
- package/dist/loader.js +31 -0
- package/dist/logger.d.ts +25 -0
- package/dist/logger.js +73 -0
- package/dist/profile-store.d.ts +48 -0
- package/dist/profile-store.js +156 -0
- package/dist/riseset.d.ts +82 -0
- package/dist/riseset.js +185 -0
- package/dist/storage.d.ts +10 -0
- package/dist/storage.js +40 -0
- package/dist/time-utils.d.ts +68 -0
- package/dist/time-utils.js +136 -0
- package/dist/tool-registry.d.ts +35 -0
- package/dist/tool-registry.js +307 -0
- package/dist/tool-result.d.ts +175 -0
- package/dist/tool-result.js +188 -0
- package/dist/transits.d.ts +108 -0
- package/dist/transits.js +263 -0
- package/dist/types.d.ts +450 -0
- package/dist/types.js +161 -0
- package/example-usage.md +131 -0
- package/natal-chart.json +187 -0
- package/package.json +61 -0
- package/scripts/download-ephemeris.js +115 -0
- package/setup.sh +21 -0
- package/src/astro-service.ts +710 -0
- package/src/chart-types.ts +125 -0
- package/src/charts.ts +399 -0
- package/src/cli.ts +694 -0
- package/src/constants.ts +89 -0
- package/src/eclipses.ts +226 -0
- package/src/ephemeris.ts +437 -0
- package/src/formatter.ts +25 -0
- package/src/houses.ts +202 -0
- package/src/index.ts +170 -0
- package/src/loader.ts +36 -0
- package/src/logger.ts +104 -0
- package/src/profile-store.ts +285 -0
- package/src/riseset.ts +229 -0
- package/src/time-utils.ts +167 -0
- package/src/tool-registry.ts +357 -0
- package/src/tool-result.ts +283 -0
- package/src/transits.ts +352 -0
- package/src/types.ts +547 -0
- package/tests/README.md +173 -0
- package/tests/TESTING_STRATEGY.md +178 -0
- package/tests/fixtures/bowen-yang-chart.ts +69 -0
- package/tests/fixtures/calculate-expected.ts +81 -0
- package/tests/fixtures/expected-results.ts +117 -0
- package/tests/fixtures/generate-expected-simple.ts +94 -0
- package/tests/helpers/date-fixtures.ts +15 -0
- package/tests/helpers/ephem.ts +11 -0
- package/tests/helpers/temp.ts +9 -0
- package/tests/setup.ts +11 -0
- package/tests/unit/astro-service.test.ts +323 -0
- package/tests/unit/chart-types.test.ts +18 -0
- package/tests/unit/charts-errors.test.ts +42 -0
- package/tests/unit/charts.test.ts +157 -0
- package/tests/unit/cli-commands.test.ts +82 -0
- package/tests/unit/cli-profiles.test.ts +128 -0
- package/tests/unit/cli.test.ts +191 -0
- package/tests/unit/constants.test.ts +26 -0
- package/tests/unit/correctness-critical.test.ts +408 -0
- package/tests/unit/eclipses.test.ts +108 -0
- package/tests/unit/ephemeris.test.ts +213 -0
- package/tests/unit/error-handling.test.ts +116 -0
- package/tests/unit/formatter.test.ts +29 -0
- package/tests/unit/houses-errors.test.ts +27 -0
- package/tests/unit/houses-validation.test.ts +164 -0
- package/tests/unit/houses.test.ts +205 -0
- package/tests/unit/profile-store.test.ts +163 -0
- package/tests/unit/real-user-charts.test.ts +148 -0
- package/tests/unit/riseset.test.ts +106 -0
- package/tests/unit/solver-edges.test.ts +197 -0
- package/tests/unit/time-utils-temporal.test.ts +303 -0
- package/tests/unit/time-utils.test.ts +173 -0
- package/tests/unit/tool-registry.test.ts +222 -0
- package/tests/unit/tool-result.test.ts +45 -0
- package/tests/unit/transit-correctness.test.ts +78 -0
- package/tests/unit/transits.test.ts +238 -0
- package/tests/validation/README.md +32 -0
- package/tests/validation/adapters/astrolog.ts +306 -0
- package/tests/validation/adapters/internal.ts +184 -0
- package/tests/validation/compare/eclipses.ts +47 -0
- package/tests/validation/compare/houses.ts +76 -0
- package/tests/validation/compare/positions.ts +104 -0
- package/tests/validation/compare/riseSet.ts +48 -0
- package/tests/validation/compare/roots.ts +90 -0
- package/tests/validation/compare/transits.ts +69 -0
- package/tests/validation/fixtures/astrolog-parity/core.ts +194 -0
- package/tests/validation/fixtures/eclipses/core.ts +14 -0
- package/tests/validation/fixtures/houses/core.ts +47 -0
- package/tests/validation/fixtures/positions/core.ts +159 -0
- package/tests/validation/fixtures/rise-set/core.ts +20 -0
- package/tests/validation/fixtures/roots/core.ts +47 -0
- package/tests/validation/fixtures/transits/core.ts +61 -0
- package/tests/validation/fixtures/transits/dst.ts +21 -0
- package/tests/validation/oracle.spec.ts +129 -0
- package/tests/validation/utils/denseRootOracle.ts +269 -0
- package/tests/validation/utils/fixtureTypes.ts +146 -0
- package/tests/validation/utils/report.ts +60 -0
- package/tests/validation/utils/tolerances.ts +23 -0
- package/tests/validation/validation.spec.ts +836 -0
- package/tools/color-picker.html +388 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +31 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { NormalizedBody } from '../utils/fixtureTypes.js';
|
|
2
|
+
import type { ValidationReport } from '../utils/report.js';
|
|
3
|
+
import { TOLERANCES } from '../utils/tolerances.js';
|
|
4
|
+
|
|
5
|
+
function sortBodies(rows: NormalizedBody[]): NormalizedBody[] {
|
|
6
|
+
return [...rows].sort((a, b) => String(a.body).localeCompare(String(b.body)));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function comparePositions(
|
|
10
|
+
fixtureName: string,
|
|
11
|
+
expected: NormalizedBody[],
|
|
12
|
+
actual: NormalizedBody[],
|
|
13
|
+
report: ValidationReport,
|
|
14
|
+
subsystem = 'positions'
|
|
15
|
+
): void {
|
|
16
|
+
const expectedSorted = sortBodies(expected);
|
|
17
|
+
const actualSorted = sortBodies(actual);
|
|
18
|
+
|
|
19
|
+
if (expectedSorted.length !== actualSorted.length) {
|
|
20
|
+
report.addHard({
|
|
21
|
+
fixture: fixtureName,
|
|
22
|
+
subsystem,
|
|
23
|
+
expected: expectedSorted.length,
|
|
24
|
+
actual: actualSorted.length,
|
|
25
|
+
delta: actualSorted.length - expectedSorted.length,
|
|
26
|
+
tolerance: 0,
|
|
27
|
+
message: 'Body count mismatch',
|
|
28
|
+
});
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < expectedSorted.length; i++) {
|
|
33
|
+
const e = expectedSorted[i];
|
|
34
|
+
const a = actualSorted[i];
|
|
35
|
+
|
|
36
|
+
if (e.body !== a.body) {
|
|
37
|
+
report.addHard({
|
|
38
|
+
fixture: fixtureName,
|
|
39
|
+
subsystem,
|
|
40
|
+
expected: e.body,
|
|
41
|
+
actual: a.body,
|
|
42
|
+
delta: null,
|
|
43
|
+
tolerance: 'exact',
|
|
44
|
+
message: 'Body mismatch at sorted index',
|
|
45
|
+
});
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const lonDelta = Math.abs(e.longitude - a.longitude);
|
|
50
|
+
if (lonDelta > TOLERANCES.positionLongitudeDeg) {
|
|
51
|
+
report.addHard({
|
|
52
|
+
fixture: fixtureName,
|
|
53
|
+
subsystem,
|
|
54
|
+
expected: e.longitude,
|
|
55
|
+
actual: a.longitude,
|
|
56
|
+
delta: lonDelta,
|
|
57
|
+
tolerance: TOLERANCES.positionLongitudeDeg,
|
|
58
|
+
message: `${e.body} longitude delta exceeds tolerance`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (e.latitude != null && a.latitude != null) {
|
|
63
|
+
const latDelta = Math.abs(e.latitude - a.latitude);
|
|
64
|
+
if (latDelta > TOLERANCES.positionLatitudeDeg) {
|
|
65
|
+
report.addHard({
|
|
66
|
+
fixture: fixtureName,
|
|
67
|
+
subsystem,
|
|
68
|
+
expected: e.latitude,
|
|
69
|
+
actual: a.latitude,
|
|
70
|
+
delta: latDelta,
|
|
71
|
+
tolerance: TOLERANCES.positionLatitudeDeg,
|
|
72
|
+
message: `${e.body} latitude delta exceeds tolerance`,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (e.speed != null && a.speed != null) {
|
|
78
|
+
const speedDelta = Math.abs(e.speed - a.speed);
|
|
79
|
+
if (speedDelta > TOLERANCES.positionSpeedDegPerDay) {
|
|
80
|
+
report.addHard({
|
|
81
|
+
fixture: fixtureName,
|
|
82
|
+
subsystem,
|
|
83
|
+
expected: e.speed,
|
|
84
|
+
actual: a.speed,
|
|
85
|
+
delta: speedDelta,
|
|
86
|
+
tolerance: TOLERANCES.positionSpeedDegPerDay,
|
|
87
|
+
message: `${e.body} speed delta exceeds tolerance`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (e.retrograde != null && a.retrograde != null && e.retrograde !== a.retrograde) {
|
|
93
|
+
report.addHard({
|
|
94
|
+
fixture: fixtureName,
|
|
95
|
+
subsystem,
|
|
96
|
+
expected: e.retrograde,
|
|
97
|
+
actual: a.retrograde,
|
|
98
|
+
delta: null,
|
|
99
|
+
tolerance: 'exact',
|
|
100
|
+
message: `${e.body} retrograde flag mismatch`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { NormalizedRiseSet } from '../utils/fixtureTypes.js';
|
|
2
|
+
import type { ValidationReport } from '../utils/report.js';
|
|
3
|
+
import { minutesBetweenIso, TOLERANCES } from '../utils/tolerances.js';
|
|
4
|
+
|
|
5
|
+
export function compareRiseSet(
|
|
6
|
+
fixtureName: string,
|
|
7
|
+
expected: NormalizedRiseSet,
|
|
8
|
+
actual: NormalizedRiseSet,
|
|
9
|
+
report: ValidationReport
|
|
10
|
+
): void {
|
|
11
|
+
const fields: Array<keyof Omit<NormalizedRiseSet, 'body'>> = [
|
|
12
|
+
'rise',
|
|
13
|
+
'set',
|
|
14
|
+
'upperMeridianTransit',
|
|
15
|
+
'lowerMeridianTransit',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
for (const field of fields) {
|
|
19
|
+
const e = expected[field];
|
|
20
|
+
const a = actual[field];
|
|
21
|
+
if (e == null && a == null) continue;
|
|
22
|
+
if ((e == null) !== (a == null)) {
|
|
23
|
+
report.addHard({
|
|
24
|
+
fixture: fixtureName,
|
|
25
|
+
subsystem: 'rise-set',
|
|
26
|
+
expected: e,
|
|
27
|
+
actual: a,
|
|
28
|
+
delta: null,
|
|
29
|
+
tolerance: 'exact',
|
|
30
|
+
message: `${field} presence mismatch`,
|
|
31
|
+
});
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const delta = minutesBetweenIso(e as string, a as string);
|
|
36
|
+
if (delta > TOLERANCES.riseSetMinutes) {
|
|
37
|
+
report.addHard({
|
|
38
|
+
fixture: fixtureName,
|
|
39
|
+
subsystem: 'rise-set',
|
|
40
|
+
expected: e,
|
|
41
|
+
actual: a,
|
|
42
|
+
delta,
|
|
43
|
+
tolerance: TOLERANCES.riseSetMinutes,
|
|
44
|
+
message: `${field} timing exceeds tolerance`,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { NormalizedRoot } from '../utils/fixtureTypes.js';
|
|
2
|
+
import type { ValidationReport } from '../utils/report.js';
|
|
3
|
+
import { minutesBetweenIso, TOLERANCES } from '../utils/tolerances.js';
|
|
4
|
+
|
|
5
|
+
function dedupeRootsByMinutes(roots: NormalizedRoot[], minutes: number): NormalizedRoot[] {
|
|
6
|
+
const sorted = [...roots].sort((a, b) => a.jd - b.jd);
|
|
7
|
+
const deduped: NormalizedRoot[] = [];
|
|
8
|
+
for (const r of sorted) {
|
|
9
|
+
const last = deduped[deduped.length - 1];
|
|
10
|
+
if (!last || minutesBetweenIso(last.isoUtc, r.isoUtc) > minutes) {
|
|
11
|
+
deduped.push(r);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return deduped;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function compareRoots(
|
|
18
|
+
fixtureName: string,
|
|
19
|
+
productionRoots: NormalizedRoot[],
|
|
20
|
+
oracleRoots: NormalizedRoot[],
|
|
21
|
+
report: ValidationReport,
|
|
22
|
+
details?: unknown
|
|
23
|
+
): void {
|
|
24
|
+
const dedupeMinutes = TOLERANCES.dedupeMinutes;
|
|
25
|
+
const normalizedProduction = dedupeRootsByMinutes(productionRoots, dedupeMinutes);
|
|
26
|
+
const normalizedOracle = dedupeRootsByMinutes(oracleRoots, dedupeMinutes);
|
|
27
|
+
|
|
28
|
+
if (normalizedProduction.length !== normalizedOracle.length) {
|
|
29
|
+
report.addHard({
|
|
30
|
+
fixture: fixtureName,
|
|
31
|
+
subsystem: 'roots',
|
|
32
|
+
expected: normalizedOracle.length,
|
|
33
|
+
actual: normalizedProduction.length,
|
|
34
|
+
delta: normalizedProduction.length - normalizedOracle.length,
|
|
35
|
+
tolerance: 0,
|
|
36
|
+
message: 'Root count mismatch (production vs dense-scan oracle, deduped)',
|
|
37
|
+
details,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const n = Math.min(normalizedProduction.length, normalizedOracle.length);
|
|
42
|
+
for (let i = 0; i < n; i++) {
|
|
43
|
+
const prod = normalizedProduction[i];
|
|
44
|
+
const oracle = normalizedOracle[i];
|
|
45
|
+
const deltaMinutes = minutesBetweenIso(prod.isoUtc, oracle.isoUtc);
|
|
46
|
+
|
|
47
|
+
if (deltaMinutes > TOLERANCES.rootHardMinutes) {
|
|
48
|
+
report.addHard({
|
|
49
|
+
fixture: fixtureName,
|
|
50
|
+
subsystem: 'roots',
|
|
51
|
+
expected: oracle.isoUtc,
|
|
52
|
+
actual: prod.isoUtc,
|
|
53
|
+
delta: deltaMinutes,
|
|
54
|
+
tolerance: TOLERANCES.rootHardMinutes,
|
|
55
|
+
message: `Root ${i} timing exceeds hard threshold`,
|
|
56
|
+
details,
|
|
57
|
+
});
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (deltaMinutes > TOLERANCES.rootPreferredMinutes) {
|
|
62
|
+
report.addWarning({
|
|
63
|
+
fixture: fixtureName,
|
|
64
|
+
subsystem: 'roots',
|
|
65
|
+
expected: oracle.isoUtc,
|
|
66
|
+
actual: prod.isoUtc,
|
|
67
|
+
delta: deltaMinutes,
|
|
68
|
+
tolerance: TOLERANCES.rootPreferredMinutes,
|
|
69
|
+
message: `Root ${i} timing exceeds preferred threshold`,
|
|
70
|
+
details,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for (let i = 1; i < normalizedProduction.length; i++) {
|
|
76
|
+
if (normalizedProduction[i].jd < normalizedProduction[i - 1].jd) {
|
|
77
|
+
report.addHard({
|
|
78
|
+
fixture: fixtureName,
|
|
79
|
+
subsystem: 'roots',
|
|
80
|
+
expected: 'sorted ascending',
|
|
81
|
+
actual: normalizedProduction.map((r) => r.jd),
|
|
82
|
+
delta: null,
|
|
83
|
+
tolerance: 'exact',
|
|
84
|
+
message: 'Production roots are not sorted earliest-first',
|
|
85
|
+
details,
|
|
86
|
+
});
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { NormalizedTransit } from '../utils/fixtureTypes.js';
|
|
2
|
+
import type { ValidationReport } from '../utils/report.js';
|
|
3
|
+
|
|
4
|
+
export function findTransit(
|
|
5
|
+
transits: NormalizedTransit[],
|
|
6
|
+
transitingPlanet: string,
|
|
7
|
+
natalPlanet: string,
|
|
8
|
+
aspect: string
|
|
9
|
+
): NormalizedTransit | undefined {
|
|
10
|
+
return transits.find(
|
|
11
|
+
(t) =>
|
|
12
|
+
t.transitingPlanet === transitingPlanet &&
|
|
13
|
+
t.natalPlanet === natalPlanet &&
|
|
14
|
+
t.aspect === aspect
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function assertTransitStatus(
|
|
19
|
+
fixtureName: string,
|
|
20
|
+
transit: NormalizedTransit | undefined,
|
|
21
|
+
expectedStatus:
|
|
22
|
+
| 'within_preview'
|
|
23
|
+
| 'outside_preview'
|
|
24
|
+
| 'not_found'
|
|
25
|
+
| 'unsupported_body'
|
|
26
|
+
| 'undefined',
|
|
27
|
+
report: ValidationReport
|
|
28
|
+
): void {
|
|
29
|
+
if (!transit) {
|
|
30
|
+
report.addHard({
|
|
31
|
+
fixture: fixtureName,
|
|
32
|
+
subsystem: 'transits',
|
|
33
|
+
expected: 'transit exists',
|
|
34
|
+
actual: 'not found',
|
|
35
|
+
delta: null,
|
|
36
|
+
tolerance: 'exact',
|
|
37
|
+
message: 'Expected transit was not found',
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const actual = transit.exactTimeStatus;
|
|
43
|
+
if (expectedStatus === 'undefined') {
|
|
44
|
+
if (actual !== undefined) {
|
|
45
|
+
report.addHard({
|
|
46
|
+
fixture: fixtureName,
|
|
47
|
+
subsystem: 'transits',
|
|
48
|
+
expected: undefined,
|
|
49
|
+
actual,
|
|
50
|
+
delta: null,
|
|
51
|
+
tolerance: 'exact',
|
|
52
|
+
message: 'Expected exactTimeStatus to be undefined',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (actual !== expectedStatus) {
|
|
59
|
+
report.addHard({
|
|
60
|
+
fixture: fixtureName,
|
|
61
|
+
subsystem: 'transits',
|
|
62
|
+
expected: expectedStatus,
|
|
63
|
+
actual,
|
|
64
|
+
delta: null,
|
|
65
|
+
tolerance: 'exact',
|
|
66
|
+
message: 'Exact-time status mismatch',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { PLANETS } from '../../../../src/types.js';
|
|
2
|
+
import type {
|
|
3
|
+
AstrologEdgeParityFixture,
|
|
4
|
+
AstrologHouseParityFixture,
|
|
5
|
+
AstrologPositionParityFixture,
|
|
6
|
+
AstrologTransitSnapshotFixture,
|
|
7
|
+
} from '../../utils/fixtureTypes.js';
|
|
8
|
+
|
|
9
|
+
const CORE_PARITY_PLANET_IDS = [
|
|
10
|
+
PLANETS.SUN,
|
|
11
|
+
PLANETS.MOON,
|
|
12
|
+
PLANETS.MERCURY,
|
|
13
|
+
PLANETS.VENUS,
|
|
14
|
+
PLANETS.MARS,
|
|
15
|
+
PLANETS.JUPITER,
|
|
16
|
+
PLANETS.SATURN,
|
|
17
|
+
PLANETS.URANUS,
|
|
18
|
+
PLANETS.NEPTUNE,
|
|
19
|
+
PLANETS.PLUTO,
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
export const astrologPositionParityFixtures: AstrologPositionParityFixture[] = [
|
|
23
|
+
{
|
|
24
|
+
name: 'positions-modern-baseline-noon',
|
|
25
|
+
isoUtc: '2024-03-26T12:00:00Z',
|
|
26
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'positions-modern-baseline-midnight',
|
|
30
|
+
isoUtc: '2024-03-26T00:00:00Z',
|
|
31
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'positions-leap-day-2024-02-29',
|
|
35
|
+
isoUtc: '2024-02-29T12:00:00Z',
|
|
36
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'positions-year-boundary-dec31',
|
|
40
|
+
isoUtc: '2024-12-31T23:59:00Z',
|
|
41
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'positions-spring-equinox-window',
|
|
45
|
+
isoUtc: '2024-03-20T12:00:00Z',
|
|
46
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'positions-autumn-equinox-window',
|
|
50
|
+
isoUtc: '2024-09-22T12:00:00Z',
|
|
51
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'positions-mercury-retrograde',
|
|
55
|
+
isoUtc: '2024-04-10T12:00:00Z',
|
|
56
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'positions-venus-retrograde',
|
|
60
|
+
isoUtc: '2023-08-10T12:00:00Z',
|
|
61
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'positions-mars-station-window',
|
|
65
|
+
isoUtc: '2024-12-08T12:00:00Z',
|
|
66
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'positions-pluto-or-uranus-station-window',
|
|
70
|
+
isoUtc: '2024-09-02T12:00:00Z',
|
|
71
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'positions-far-past-date',
|
|
75
|
+
isoUtc: '1905-06-15T12:00:00Z',
|
|
76
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'positions-near-future-date',
|
|
80
|
+
isoUtc: '2035-05-10T12:00:00Z',
|
|
81
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
export const astrologHouseParityFixtures: AstrologHouseParityFixture[] = [
|
|
86
|
+
{
|
|
87
|
+
name: 'houses-whole-sign-midlat-north',
|
|
88
|
+
isoUtc: '2024-03-26T12:00:00Z',
|
|
89
|
+
latitude: 40.7128,
|
|
90
|
+
longitude: -74.006,
|
|
91
|
+
houseSystem: 'W',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'houses-whole-sign-southern-hemisphere',
|
|
95
|
+
isoUtc: '2024-09-01T00:00:00Z',
|
|
96
|
+
latitude: -33.8688,
|
|
97
|
+
longitude: 151.2093,
|
|
98
|
+
houseSystem: 'W',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'houses-whole-sign-date-line-ish-longitude',
|
|
102
|
+
isoUtc: '2024-06-01T12:00:00Z',
|
|
103
|
+
latitude: -18.1248,
|
|
104
|
+
longitude: 178.4501,
|
|
105
|
+
houseSystem: 'W',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'houses-placidus-midlat-sanity',
|
|
109
|
+
isoUtc: '2024-03-26T12:00:00Z',
|
|
110
|
+
latitude: 51.5072,
|
|
111
|
+
longitude: -0.1276,
|
|
112
|
+
houseSystem: 'P',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'houses-high-latitude-fallback',
|
|
116
|
+
isoUtc: '2024-12-21T00:00:00Z',
|
|
117
|
+
latitude: 78.2232,
|
|
118
|
+
longitude: 15.6267,
|
|
119
|
+
houseSystem: 'P',
|
|
120
|
+
expectFallbackToWholeSign: true,
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
export const astrologTransitSnapshotFixtures: AstrologTransitSnapshotFixture[] = [
|
|
125
|
+
{
|
|
126
|
+
name: 'transits-mercury-retrograde-snapshot',
|
|
127
|
+
currentIsoUtc: '2024-04-10T12:00:00Z',
|
|
128
|
+
transitingPlanetId: PLANETS.MERCURY,
|
|
129
|
+
natalPlanetId: PLANETS.VENUS,
|
|
130
|
+
natalOffsetDegrees: 92,
|
|
131
|
+
expectedAspect: 'square',
|
|
132
|
+
maxOrb: 8,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: 'transits-moon-fast-motion-snapshot',
|
|
136
|
+
currentIsoUtc: '2024-03-26T12:00:00Z',
|
|
137
|
+
transitingPlanetId: PLANETS.MOON,
|
|
138
|
+
natalPlanetId: PLANETS.MARS,
|
|
139
|
+
natalOffsetDegrees: 120,
|
|
140
|
+
expectedAspect: 'trine',
|
|
141
|
+
maxOrb: 8,
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'transits-square-dual-target',
|
|
145
|
+
currentIsoUtc: '2024-03-15T00:00:00Z',
|
|
146
|
+
transitingPlanetId: PLANETS.MARS,
|
|
147
|
+
natalPlanetId: PLANETS.VENUS,
|
|
148
|
+
natalOffsetDegrees: 90,
|
|
149
|
+
expectedAspect: 'square',
|
|
150
|
+
maxOrb: 8,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: 'transits-trine-or-sextile-dual-target',
|
|
154
|
+
currentIsoUtc: '2024-03-15T00:00:00Z',
|
|
155
|
+
transitingPlanetId: PLANETS.JUPITER,
|
|
156
|
+
natalPlanetId: PLANETS.SUN,
|
|
157
|
+
natalOffsetDegrees: 60,
|
|
158
|
+
expectedAspect: 'sextile',
|
|
159
|
+
maxOrb: 8,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'transits-slow-mover-in-orb',
|
|
163
|
+
currentIsoUtc: '2024-10-01T00:00:00Z',
|
|
164
|
+
transitingPlanetId: PLANETS.PLUTO,
|
|
165
|
+
natalPlanetId: PLANETS.MARS,
|
|
166
|
+
natalOffsetDegrees: 180,
|
|
167
|
+
expectedAspect: 'opposition',
|
|
168
|
+
maxOrb: 8,
|
|
169
|
+
},
|
|
170
|
+
];
|
|
171
|
+
|
|
172
|
+
export const astrologEdgeParityFixtures: AstrologEdgeParityFixture[] = [
|
|
173
|
+
{
|
|
174
|
+
name: 'edge-longitude-wrap-near-zero',
|
|
175
|
+
isoUtc: '2024-03-20T03:06:00Z',
|
|
176
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: 'edge-dst-ambiguous-local-time',
|
|
180
|
+
isoUtc: '2024-11-03T08:30:00.000Z',
|
|
181
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
182
|
+
local: { year: 2024, month: 11, day: 3, hour: 1, minute: 30 },
|
|
183
|
+
timezone: 'America/Los_Angeles',
|
|
184
|
+
disambiguation: 'earlier',
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: 'edge-dst-nonexistent-local-time',
|
|
188
|
+
isoUtc: '2024-03-10T10:30:00.000Z',
|
|
189
|
+
planetIds: CORE_PARITY_PLANET_IDS,
|
|
190
|
+
local: { year: 2024, month: 3, day: 10, hour: 2, minute: 30 },
|
|
191
|
+
timezone: 'America/Los_Angeles',
|
|
192
|
+
disambiguation: 'compatible',
|
|
193
|
+
},
|
|
194
|
+
];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EclipseFixture } from '../../utils/fixtureTypes.js';
|
|
2
|
+
|
|
3
|
+
export const eclipseFixtures: EclipseFixture[] = [
|
|
4
|
+
{
|
|
5
|
+
name: 'next-solar-eclipse-sanity',
|
|
6
|
+
startIsoUtc: '2024-03-26T00:00:00Z',
|
|
7
|
+
type: 'solar',
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
name: 'next-lunar-eclipse-sanity',
|
|
11
|
+
startIsoUtc: '2024-03-26T00:00:00Z',
|
|
12
|
+
type: 'lunar',
|
|
13
|
+
},
|
|
14
|
+
];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { HouseFixture } from '../../utils/fixtureTypes.js';
|
|
2
|
+
|
|
3
|
+
export const houseFixtures: HouseFixture[] = [
|
|
4
|
+
{
|
|
5
|
+
name: 'nyc-placidus',
|
|
6
|
+
isoUtc: '2024-03-26T12:00:00Z',
|
|
7
|
+
latitude: 40.7128,
|
|
8
|
+
longitude: -74.006,
|
|
9
|
+
houseSystem: 'P',
|
|
10
|
+
expected: {
|
|
11
|
+
system: 'P',
|
|
12
|
+
ascendant: 33.98295887285655,
|
|
13
|
+
mc: 288.8571573752222,
|
|
14
|
+
cusps: [
|
|
15
|
+
33.98295887285655, 65.33379924755742, 87.90228930026863, 108.85715737522219,
|
|
16
|
+
132.88655769961264, 166.17376459102024, 213.98295887285656, 245.3337992475574,
|
|
17
|
+
267.90228930026865, 288.8571573752222, 312.88655769961264, 346.1737645910202,
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'svalbard-polar-fallback',
|
|
23
|
+
isoUtc: '2024-03-26T12:00:00Z',
|
|
24
|
+
latitude: 78.2232,
|
|
25
|
+
longitude: 15.6267,
|
|
26
|
+
houseSystem: 'P',
|
|
27
|
+
expected: {
|
|
28
|
+
system: 'W',
|
|
29
|
+
ascendant: 157.0869567445154,
|
|
30
|
+
mc: 21.69267914127279,
|
|
31
|
+
cusps: [150, 180, 210, 240, 270, 300, 330, 0, 30, 60, 90, 120],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'sydney-whole-sign',
|
|
36
|
+
isoUtc: '2024-09-01T00:00:00Z',
|
|
37
|
+
latitude: -33.8688,
|
|
38
|
+
longitude: 151.2093,
|
|
39
|
+
houseSystem: 'W',
|
|
40
|
+
expected: {
|
|
41
|
+
system: 'W',
|
|
42
|
+
ascendant: 238.03867274058655,
|
|
43
|
+
mc: 129.421733545281,
|
|
44
|
+
cusps: [210, 240, 270, 300, 330, 0, 30, 60, 90, 120, 150, 180],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
];
|