Files
TaroTime/app/data-service.js

379 lines
11 KiB
JavaScript

(function () {
let magickManifestCache = null;
let magickDataCache = null;
const DATA_ROOT = "data";
const MAGICK_ROOT = DATA_ROOT;
const TAROT_TRUMP_NUMBER_BY_NAME = {
"the fool": 0,
fool: 0,
"the magus": 1,
magus: 1,
magician: 1,
"the high priestess": 2,
"high priestess": 2,
"the empress": 3,
empress: 3,
"the emperor": 4,
emperor: 4,
"the hierophant": 5,
hierophant: 5,
"the lovers": 6,
lovers: 6,
"the chariot": 7,
chariot: 7,
strength: 8,
lust: 8,
"the hermit": 9,
hermit: 9,
fortune: 10,
"wheel of fortune": 10,
justice: 11,
"the hanged man": 12,
"hanged man": 12,
death: 13,
temperance: 14,
art: 14,
"the devil": 15,
devil: 15,
"the tower": 16,
tower: 16,
"the star": 17,
star: 17,
"the moon": 18,
moon: 18,
"the sun": 19,
sun: 19,
aeon: 20,
judgement: 20,
judgment: 20,
universe: 21,
world: 21,
"the world": 21
};
const HEBREW_BY_TRUMP_NUMBER = {
0: { hebrewLetterId: "alef", kabbalahPathNumber: 11 },
1: { hebrewLetterId: "bet", kabbalahPathNumber: 12 },
2: { hebrewLetterId: "gimel", kabbalahPathNumber: 13 },
3: { hebrewLetterId: "dalet", kabbalahPathNumber: 14 },
4: { hebrewLetterId: "he", kabbalahPathNumber: 15 },
5: { hebrewLetterId: "vav", kabbalahPathNumber: 16 },
6: { hebrewLetterId: "zayin", kabbalahPathNumber: 17 },
7: { hebrewLetterId: "het", kabbalahPathNumber: 18 },
8: { hebrewLetterId: "tet", kabbalahPathNumber: 19 },
9: { hebrewLetterId: "yod", kabbalahPathNumber: 20 },
10: { hebrewLetterId: "kaf", kabbalahPathNumber: 21 },
11: { hebrewLetterId: "lamed", kabbalahPathNumber: 22 },
12: { hebrewLetterId: "mem", kabbalahPathNumber: 23 },
13: { hebrewLetterId: "nun", kabbalahPathNumber: 24 },
14: { hebrewLetterId: "samekh", kabbalahPathNumber: 25 },
15: { hebrewLetterId: "ayin", kabbalahPathNumber: 26 },
16: { hebrewLetterId: "pe", kabbalahPathNumber: 27 },
17: { hebrewLetterId: "tsadi", kabbalahPathNumber: 28 },
18: { hebrewLetterId: "qof", kabbalahPathNumber: 29 },
19: { hebrewLetterId: "resh", kabbalahPathNumber: 30 },
20: { hebrewLetterId: "shin", kabbalahPathNumber: 31 },
21: { hebrewLetterId: "tav", kabbalahPathNumber: 32 }
};
const ICHING_PLANET_BY_PLANET_ID = {
sol: "Sun",
luna: "Moon",
mercury: "Mercury",
venus: "Venus",
mars: "Mars",
jupiter: "Jupiter",
saturn: "Saturn",
earth: "Earth",
uranus: "Uranus",
neptune: "Neptune",
pluto: "Pluto"
};
async function fetchJson(path) {
const response = await fetch(path);
if (!response.ok) {
throw new Error(`Failed to load ${path} (${response.status})`);
}
return response.json();
}
function buildObjectPath(target, pathParts, value) {
let cursor = target;
for (let index = 0; index < pathParts.length - 1; index += 1) {
const part = pathParts[index];
if (!cursor[part] || typeof cursor[part] !== "object") {
cursor[part] = {};
}
cursor = cursor[part];
}
cursor[pathParts[pathParts.length - 1]] = value;
}
function normalizeTarotName(value) {
return String(value || "")
.trim()
.toLowerCase()
.replace(/\s+/g, " ");
}
function resolveTarotTrumpNumber(cardName) {
const key = normalizeTarotName(cardName);
if (!key) {
return null;
}
if (Object.prototype.hasOwnProperty.call(TAROT_TRUMP_NUMBER_BY_NAME, key)) {
return TAROT_TRUMP_NUMBER_BY_NAME[key];
}
const withoutLeadingThe = key.replace(/^the\s+/, "");
if (Object.prototype.hasOwnProperty.call(TAROT_TRUMP_NUMBER_BY_NAME, withoutLeadingThe)) {
return TAROT_TRUMP_NUMBER_BY_NAME[withoutLeadingThe];
}
return null;
}
function enrichAssociation(associations) {
if (!associations || typeof associations !== "object") {
return associations;
}
const next = { ...associations };
if (next.tarotCard) {
const trumpNumber = resolveTarotTrumpNumber(next.tarotCard);
if (trumpNumber != null) {
if (!Number.isFinite(Number(next.tarotTrumpNumber))) {
next.tarotTrumpNumber = trumpNumber;
}
const hebrew = HEBREW_BY_TRUMP_NUMBER[trumpNumber];
if (hebrew) {
if (!next.hebrewLetterId) {
next.hebrewLetterId = hebrew.hebrewLetterId;
}
if (!Number.isFinite(Number(next.kabbalahPathNumber))) {
next.kabbalahPathNumber = hebrew.kabbalahPathNumber;
}
}
}
}
const planetId = String(next.planetId || "").trim().toLowerCase();
if (!next.iChingPlanetaryInfluence && planetId) {
const influence = ICHING_PLANET_BY_PLANET_ID[planetId];
if (influence) {
next.iChingPlanetaryInfluence = influence;
}
}
return next;
}
function enrichCalendarMonth(month) {
const events = Array.isArray(month?.events)
? month.events.map((event) => ({
...event,
associations: enrichAssociation(event?.associations)
}))
: [];
return {
...month,
associations: enrichAssociation(month?.associations),
events
};
}
function enrichCelestialHoliday(holiday) {
return {
...holiday,
associations: enrichAssociation(holiday?.associations)
};
}
function enrichCalendarHoliday(holiday) {
return {
...holiday,
associations: enrichAssociation(holiday?.associations)
};
}
async function loadMagickManifest() {
if (magickManifestCache) {
return magickManifestCache;
}
magickManifestCache = await fetchJson(`${MAGICK_ROOT}/MANIFEST.json`);
return magickManifestCache;
}
async function loadMagickDataset() {
if (magickDataCache) {
return magickDataCache;
}
const manifest = await loadMagickManifest();
const files = Array.isArray(manifest?.files) ? manifest.files : [];
const jsonFiles = files.filter((file) => file.endsWith(".json"));
const entries = await Promise.all(
jsonFiles.map(async (relativePath) => {
const data = await fetchJson(`${MAGICK_ROOT}/${relativePath}`);
return [relativePath, data];
})
);
const grouped = {};
entries.forEach(([relativePath, data]) => {
const noExtensionPath = relativePath.replace(/\.json$/i, "");
const pathParts = noExtensionPath.split("/").filter(Boolean);
if (!pathParts.length) {
return;
}
buildObjectPath(grouped, pathParts, data);
});
magickDataCache = {
manifest,
grouped,
files: Object.fromEntries(entries)
};
return magickDataCache;
}
async function loadReferenceData() {
const { groupDecansBySign } = window.TarotCalc;
const [
planetsJson,
signsJson,
decansJson,
sabianJson,
planetScienceJson,
gematriaCiphersJson,
iChingJson,
calendarMonthsJson,
celestialHolidaysJson,
calendarHolidaysJson,
astronomyCyclesJson,
tarotDatabaseJson,
hebrewCalendarJson,
islamicCalendarJson,
wheelOfYearJson
] = await Promise.all([
fetchJson(`${DATA_ROOT}/planetary-correspondences.json`),
fetchJson(`${DATA_ROOT}/signs.json`),
fetchJson(`${DATA_ROOT}/decans.json`),
fetchJson(`${DATA_ROOT}/sabian-symbols.json`),
fetchJson(`${DATA_ROOT}/planet-science.json`),
fetchJson(`${DATA_ROOT}/gematria-ciphers.json`).catch(() => ({})),
fetchJson(`${DATA_ROOT}/i-ching.json`),
fetchJson(`${DATA_ROOT}/calendar-months.json`),
fetchJson(`${DATA_ROOT}/celestial-holidays.json`),
fetchJson(`${DATA_ROOT}/calendar-holidays.json`).catch(() => ({})),
fetchJson(`${DATA_ROOT}/astronomy-cycles.json`).catch(() => ({})),
fetchJson(`${DATA_ROOT}/tarot-database.json`).catch(() => ({})),
fetchJson(`${DATA_ROOT}/hebrew-calendar.json`).catch(() => ({})),
fetchJson(`${DATA_ROOT}/islamic-calendar.json`).catch(() => ({})),
fetchJson(`${DATA_ROOT}/wheel-of-year.json`).catch(() => ({}))
]);
const planets = planetsJson.planets || {};
const signs = signsJson.signs || [];
const decans = decansJson.decans || [];
const sabianSymbols = Array.isArray(sabianJson?.symbols) ? sabianJson.symbols : [];
const planetScience = Array.isArray(planetScienceJson?.planets)
? planetScienceJson.planets
: [];
const gematriaCiphers = gematriaCiphersJson && typeof gematriaCiphersJson === "object"
? gematriaCiphersJson
: {};
const iChing = {
trigrams: Array.isArray(iChingJson?.trigrams) ? iChingJson.trigrams : [],
hexagrams: Array.isArray(iChingJson?.hexagrams) ? iChingJson.hexagrams : [],
correspondences: {
meta: iChingJson?.correspondences?.meta && typeof iChingJson.correspondences.meta === "object"
? iChingJson.correspondences.meta
: {},
tarotToTrigram: Array.isArray(iChingJson?.correspondences?.tarotToTrigram)
? iChingJson.correspondences.tarotToTrigram
: []
}
};
const calendarMonths = Array.isArray(calendarMonthsJson?.months)
? calendarMonthsJson.months.map((month) => enrichCalendarMonth(month))
: [];
const celestialHolidays = Array.isArray(celestialHolidaysJson?.holidays)
? celestialHolidaysJson.holidays.map((holiday) => enrichCelestialHoliday(holiday))
: [];
const calendarHolidays = Array.isArray(calendarHolidaysJson?.holidays)
? calendarHolidaysJson.holidays.map((holiday) => enrichCalendarHoliday(holiday))
: [];
const astronomyCycles = astronomyCyclesJson && typeof astronomyCyclesJson === "object"
? astronomyCyclesJson
: {};
const tarotDatabase = tarotDatabaseJson && typeof tarotDatabaseJson === "object"
? tarotDatabaseJson
: {};
const sourceMeanings = tarotDatabase.meanings && typeof tarotDatabase.meanings === "object"
? tarotDatabase.meanings
: {};
if (!sourceMeanings.majorByTrumpNumber || typeof sourceMeanings.majorByTrumpNumber !== "object") {
sourceMeanings.majorByTrumpNumber = {};
}
const existingByCardName = sourceMeanings.byCardName && typeof sourceMeanings.byCardName === "object"
? sourceMeanings.byCardName
: {};
sourceMeanings.byCardName = existingByCardName;
tarotDatabase.meanings = sourceMeanings;
const hebrewCalendar = hebrewCalendarJson && typeof hebrewCalendarJson === "object"
? hebrewCalendarJson
: {};
const islamicCalendar = islamicCalendarJson && typeof islamicCalendarJson === "object"
? islamicCalendarJson
: {};
const wheelOfYear = wheelOfYearJson && typeof wheelOfYearJson === "object"
? wheelOfYearJson
: {};
return {
planets,
signs,
decansBySign: groupDecansBySign(decans),
sabianSymbols,
planetScience,
gematriaCiphers,
iChing,
calendarMonths,
celestialHolidays,
calendarHolidays,
astronomyCycles,
tarotDatabase,
hebrewCalendar,
islamicCalendar,
wheelOfYear
};
}
window.TarotDataService = {
loadReferenceData,
loadMagickManifest,
loadMagickDataset
};
})();