numerology/core-calculator.ts
rpriven fd6e171586
Add comprehensive numerology calculator with 10 specialized tools
- Core calculations (Life Path, Expression, Soul Urge, Birthday)
- Advanced numbers (Maturity, Personality, Hidden Passion, Karmic Lessons)
- Timing cycles and optimal days finder
- Compatibility analysis and name optimizer
- Telos integration for personal development
- Professional PDF report generation
- Profile management system
- Security fix: Add .claude/ to .gitignore

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 14:00:15 -06:00

175 lines
4.7 KiB
TypeScript

/**
* Core Numerology Calculator
* Shared functions for calculating Life Path, Expression, Soul Urge, Birthday
*/
const MASTER_NUMBERS = [11, 22, 33];
export function reduce(n: number): number {
if (MASTER_NUMBERS.includes(n)) return n;
const total = String(n).split('').reduce((sum, digit) => sum + parseInt(digit), 0);
return total < 10 ? total : reduce(total);
}
function nameToNumber(name: string): number {
const cleaned = name.toLowerCase().replace(/[^a-z]/g, '');
let total = 0;
for (const char of cleaned) {
const value = char.charCodeAt(0) - 96;
total += value < 10 ? value : reduce(value);
}
return total;
}
function masterCheck(total: number): number {
if (MASTER_NUMBERS.includes(total)) return total;
const reduced = String(total).split('').reduce((sum, digit) => sum + parseInt(digit), 0);
return reduced < 10 ? reduced : reduce(reduced);
}
function extractVowels(name: string): string {
return name.toLowerCase().replace(/[^aeiou]/g, '');
}
function extractConsonants(name: string): string {
return name.toLowerCase().replace(/[^bcdfghjklmnpqrstvwxyz]/g, '');
}
function letterToNumber(letter: string): number {
const value = letter.toLowerCase().charCodeAt(0) - 96;
return value;
}
export interface CoreNumbers {
lifePath: number;
expression: number;
soulUrge: number;
birthday: number;
}
export interface AdditionalNumbers {
maturity: number;
personality: number;
hiddenPassion: number | null;
hiddenPassionCount: number;
karmicLessons: number[];
balance: number;
}
export function calculateCoreNumbers(name: string, birthdate: string): CoreNumbers {
// Parse birthdate
const parts = birthdate.split('/');
const month = parseInt(parts[0]);
const day = parseInt(parts[1]);
const year = parseInt(parts[2]);
// Life Path
const monthReduced = reduce(month);
const dayReduced = reduce(day);
const yearReduced = reduce(year);
const birthDateSum = monthReduced + dayReduced + yearReduced;
const lifePath = reduce(birthDateSum);
// Birthday
const birthday = reduce(day);
// Expression (from full name)
const nameParts = name.trim().split(/\s+/);
const namesToUse = nameParts.length > 4
? [nameParts[0], nameParts[nameParts.length - 1]]
: nameParts;
let expressionTotal = 0;
for (const part of namesToUse) {
const value = nameToNumber(part);
const checked = masterCheck(value);
expressionTotal += checked;
}
const expression = masterCheck(reduce(expressionTotal));
// Soul Urge (from vowels)
let soulUrgeTotal = 0;
for (const part of nameParts) {
const vowels = extractVowels(part);
if (vowels) {
const value = nameToNumber(vowels);
const checked = masterCheck(value);
soulUrgeTotal += checked;
}
}
const soulUrge = masterCheck(reduce(soulUrgeTotal));
return { lifePath, expression, soulUrge, birthday };
}
export function calculateAdditionalNumbers(
name: string,
coreNumbers: CoreNumbers
): AdditionalNumbers {
const nameParts = name.trim().split(/\s+/);
const fullName = name.trim();
// 1. Maturity Number (Life Path + Expression)
const maturitySum = coreNumbers.lifePath + coreNumbers.expression;
const maturity = reduce(maturitySum);
// 2. Personality Number (consonants in full name)
let personalityTotal = 0;
for (const part of nameParts) {
const consonants = extractConsonants(part);
if (consonants) {
const value = nameToNumber(consonants);
const checked = masterCheck(value);
personalityTotal += checked;
}
}
const personality = masterCheck(reduce(personalityTotal));
// 3. Hidden Passion Number (most frequent letter value)
const letterCounts: Record<number, number> = {};
const cleanedName = fullName.toLowerCase().replace(/[^a-z]/g, '');
for (const char of cleanedName) {
const num = letterToNumber(char);
const reduced = reduce(num);
letterCounts[reduced] = (letterCounts[reduced] || 0) + 1;
}
let hiddenPassion: number | null = null;
let hiddenPassionCount = 0;
for (const [num, count] of Object.entries(letterCounts)) {
if (count > hiddenPassionCount) {
hiddenPassionCount = count;
hiddenPassion = parseInt(num);
}
}
// 4. Karmic Lessons (missing numbers 1-9)
const karmicLessons: number[] = [];
for (let i = 1; i <= 9; i++) {
if (!letterCounts[i]) {
karmicLessons.push(i);
}
}
// 5. Balance Number (first letter of each name part)
let balanceTotal = 0;
for (const part of nameParts) {
if (part.length > 0) {
const firstLetter = part[0];
const num = letterToNumber(firstLetter);
balanceTotal += num;
}
}
const balance = reduce(balanceTotal);
return {
maturity,
personality,
hiddenPassion,
hiddenPassionCount,
karmicLessons,
balance
};
}