Initial commit
This commit is contained in:
372
app/data-service.js
Normal file
372
app/data-service.js
Normal file
@@ -0,0 +1,372 @@
|
||||
(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,
|
||||
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}/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 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,
|
||||
iChing,
|
||||
calendarMonths,
|
||||
celestialHolidays,
|
||||
calendarHolidays,
|
||||
astronomyCycles,
|
||||
tarotDatabase,
|
||||
hebrewCalendar,
|
||||
islamicCalendar,
|
||||
wheelOfYear
|
||||
};
|
||||
}
|
||||
|
||||
window.TarotDataService = {
|
||||
loadReferenceData,
|
||||
loadMagickManifest,
|
||||
loadMagickDataset
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user