Add JSON output format and a separate interpreter binary
deck-engine gains --format json (language-independent, slug-based) so a new dist/interpreter-cli can score how significant a day's transits are without linking the engine itself — it depends only on the JSON shape, via its own minimal parser. Also documents the full reading pipeline end to end (CLAUDE.md, README, docs/) and adds docs/reading.md, a non-technical explanation of what a daily reading contains and means.
This commit is contained in:
@@ -142,3 +142,55 @@ void reading_print_html(const DailyReading *r, FILE *out) {
|
||||
}
|
||||
fprintf(out, "</div>\n</body></html>\n");
|
||||
}
|
||||
|
||||
static void print_body_position_json(FILE *out, const char *indent, Body body,
|
||||
const PlanetPosition *p) {
|
||||
fprintf(out,
|
||||
"%s{\"body\": \"%s\", \"sign\": \"%s\", \"degree_in_sign\": %.4f, "
|
||||
"\"ecliptic_longitude\": %.4f, \"house\": %d}",
|
||||
indent, astro_body_slug(body), astro_sign_slug(p->sign),
|
||||
p->degree_in_sign, p->ecliptic_longitude, p->house);
|
||||
}
|
||||
|
||||
void reading_print_json(const DailyReading *r, FILE *out) {
|
||||
fprintf(out, "{\n");
|
||||
|
||||
fprintf(out, " \"natal\": {\n \"bodies\": [\n");
|
||||
for (int b = 0; b < NUM_BODIES; b++) {
|
||||
print_body_position_json(out, " ", (Body)b, &r->natal.bodies[b]);
|
||||
fprintf(out, "%s\n", b + 1 < NUM_BODIES ? "," : "");
|
||||
}
|
||||
fprintf(out, " ],\n \"ascendant_longitude\": %.4f,\n \"houses\": [",
|
||||
r->natal.ascendant_longitude);
|
||||
for (int h = 0; h < 12; h++) {
|
||||
fprintf(out, "\"%s\"%s", astro_sign_slug(r->natal.houses[h]), h + 1 < 12 ? ", " : "");
|
||||
}
|
||||
fprintf(out, "]\n },\n");
|
||||
|
||||
fprintf(out, " \"transits\": {\n \"bodies\": [\n");
|
||||
for (int b = 0; b < NUM_BODIES; b++) {
|
||||
print_body_position_json(out, " ", (Body)b, &r->transits.bodies[b]);
|
||||
fprintf(out, "%s\n", b + 1 < NUM_BODIES ? "," : "");
|
||||
}
|
||||
fprintf(out, " ],\n \"moon_phase\": \"%s\",\n \"aspects\": [\n",
|
||||
astro_moon_phase_slug(r->transits.moon_phase));
|
||||
for (int i = 0; i < r->transits.aspect_count; i++) {
|
||||
const Aspect *a = &r->transits.aspects[i];
|
||||
fprintf(out,
|
||||
" {\"transiting_planet\": \"%s\", \"natal_planet\": \"%s\", "
|
||||
"\"type\": \"%s\", \"orb\": %.4f}%s\n",
|
||||
astro_body_slug(a->transiting_planet), astro_body_slug(a->natal_planet),
|
||||
astro_aspect_slug(a->type), a->orb,
|
||||
i + 1 < r->transits.aspect_count ? "," : "");
|
||||
}
|
||||
fprintf(out, " ]\n },\n");
|
||||
|
||||
fprintf(out, " \"spread\": {\n \"positions\": [\n");
|
||||
for (int i = 0; i < TAROT_SPREAD_SIZE; i++) {
|
||||
const TarotDraw *draw = &r->spread.positions[i];
|
||||
fprintf(out, " {\"position\": \"%s\", \"card\": \"%s\", \"reversed\": %s}%s\n",
|
||||
tarot_position_slug((CelticCrossPosition)i), tarot_card_slug(draw->card),
|
||||
draw->reversed ? "true" : "false", i + 1 < TAROT_SPREAD_SIZE ? "," : "");
|
||||
}
|
||||
fprintf(out, " ]\n }\n}\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user