379 lines
11 KiB
JavaScript
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
|
|
};
|
|
})();
|