@jager-ai/holy-editor
Version:
Rich text editor with Bible verse slash commands and PWA keyboard tracking, extracted from Holy Habit project
247 lines β’ 8.86 kB
JavaScript
;
/**
* Bible Verse Engine
*
* Core engine for Bible verse slash commands and API integration
* Extracted from Holy Habit holy-editor-pro.js
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BibleVerseEngine = void 0;
const Editor_1 = require("../types/Editor");
class BibleVerseEngine {
constructor(apiEndpoint, debounceMs) {
this.cache = {};
this.lastInsertedRef = '';
this.lastInsertedTime = 0;
this.debounceMs = 300;
this.apiEndpoint = '/api/bible_verse_full.php';
if (apiEndpoint) {
this.apiEndpoint = apiEndpoint;
}
if (debounceMs !== undefined) {
this.debounceMs = debounceMs;
}
}
/**
* Get singleton instance
*/
static getInstance(apiEndpoint, debounceMs) {
if (!BibleVerseEngine.instance) {
BibleVerseEngine.instance = new BibleVerseEngine(apiEndpoint, debounceMs);
}
return BibleVerseEngine.instance;
}
/**
* Parse slash commands from text
*/
parseSlashCommands(text) {
const matches = [];
for (const match of text.matchAll(BibleVerseEngine.CMD_RE)) {
const ref = match[1].replace(/\u00A0/g, ''); // Remove NBSP
const position = match.index || 0;
if (this.isValidBibleRef(ref)) {
matches.push({
ref,
position,
fullMatch: match[0]
});
}
}
return matches;
}
/**
* Validate Bible reference format (supports range verses)
*/
isValidBibleRef(ref) {
// Format check
const match = ref.match(BibleVerseEngine.BIBLE_REF_RE);
if (!match)
return false;
const [, , , fromVerse, toVerse] = match;
// Range verse validation
if (toVerse) {
const from = parseInt(fromVerse);
const to = parseInt(toVerse);
// End verse must be greater than start verse
if (to < from) {
return false;
}
// Limit range to 10 verses maximum
if (to - from > 10) {
console.warn('π Range too large (max 10 verses):', ref);
return false;
}
}
// Book name validation
const bookAbbr = ref.replace(/\s*\d.*$/, '').trim();
if (!BibleVerseEngine.ALL_BOOKS[bookAbbr]) {
console.warn('π Unsupported Bible book:', bookAbbr);
return false;
}
// Duplicate prevention (debouncing)
const now = Date.now();
if (ref === this.lastInsertedRef && now - this.lastInsertedTime < this.debounceMs) {
console.log('π Duplicate insertion prevented:', ref);
return false;
}
console.log('π Valid Bible reference:', ref);
return true;
}
/**
* Load verse from API with caching and error handling
*/
async loadVerse(ref) {
// Check memory cache first
const cachedVerse = this.cache[ref];
if (cachedVerse) {
console.log('π Loading verse from cache:', ref, cachedVerse);
return cachedVerse;
}
// API call if not cached
try {
const url = `${this.apiEndpoint}?query=${encodeURIComponent(ref)}`;
const response = await fetch(url, { cache: 'force-cache' });
if (!response.ok) {
// Handle different error status codes
await response.json().catch(() => ({}));
switch (response.status) {
case 404:
throw new Editor_1.BibleApiError('Verse not found', 404);
case 422:
throw new Editor_1.BibleApiError('Invalid verse format', 422);
case 500:
throw new Editor_1.BibleApiError('Server error', 500);
default:
throw new Editor_1.BibleApiError('Network error', response.status);
}
}
const data = await response.json();
// Handle new API response format (supports range verses)
if (data.success && data.verses && data.verses.length > 0) {
const verseData = {
verses: data.verses,
isRange: data.verses.length > 1
};
// Cache the result
this.cache[ref] = verseData;
console.log('π Verse loaded successfully:', ref, verseData);
return verseData;
}
else {
console.warn('π Verse not found:', ref);
return null;
}
}
catch (error) {
if (error instanceof Editor_1.BibleApiError) {
throw error;
}
console.error('π Network connection error:', ref, error);
throw new Editor_1.BibleApiError('Network connection failed', undefined, error);
}
}
/**
* Get book name from abbreviation
*/
getBookName(abbr) {
return BibleVerseEngine.ALL_BOOKS[abbr];
}
/**
* Get all supported book abbreviations
*/
getSupportedBooks() {
return Object.keys(BibleVerseEngine.ALL_BOOKS);
}
/**
* Update duplicate prevention state
*/
updateInsertionState(ref) {
this.lastInsertedRef = ref;
this.lastInsertedTime = Date.now();
}
/**
* Clear cache
*/
clearCache() {
this.cache = {};
console.log('π Bible verse cache cleared');
}
/**
* Get cache stats
*/
getCacheStats() {
const keys = Object.keys(this.cache);
return {
size: keys.length,
keys
};
}
/**
* Set API endpoint
*/
setApiEndpoint(endpoint) {
this.apiEndpoint = endpoint;
}
/**
* Set debounce time
*/
setDebounceMs(ms) {
this.debounceMs = ms;
}
/**
* Extract book abbreviation from reference
*/
extractBookAbbr(ref) {
return ref.replace(/\s*\d.*$/, '').trim();
}
/**
* Check if reference is a range verse
*/
isRangeVerse(ref) {
const match = ref.match(BibleVerseEngine.BIBLE_REF_RE);
return match ? !!match[4] : false;
}
/**
* Parse verse numbers from reference
*/
parseVerseNumbers(ref) {
const match = ref.match(BibleVerseEngine.BIBLE_REF_RE);
if (!match)
return null;
const [, , chapter, startVerse, endVerse] = match;
return {
chapter: parseInt(chapter) || 1,
startVerse: parseInt(startVerse),
endVerse: endVerse ? parseInt(endVerse) : undefined
};
}
}
exports.BibleVerseEngine = BibleVerseEngine;
// Bible book mappings (66 books total)
BibleVerseEngine.OLD_TESTAMENT_BOOKS = {
μ°½: 'μ°½μΈκΈ°', μΆ: 'μΆμ κ΅½κΈ°', λ : 'λ μκΈ°', λ―Ό: 'λ―ΌμκΈ°', μ : 'μ λͺ
κΈ°',
μ: 'μ¬νΈμμ', μΏ: 'μ¬μ¬κΈ°', λ£»: 'λ£»κΈ°', μΌμ: 'μ¬λ¬΄μμ', μΌν: 'μ¬λ¬΄μν',
μμ: 'μ΄μκΈ°μ', μν: 'μ΄μκΈ°ν', λμ: 'μλμ', λν: 'μλν',
μ€: 'μμ€λΌ', λ: 'λν€λ―ΈμΌ', μ: 'μμ€λ', μ₯: 'μ₯κΈ°', μ: 'μνΈ',
μ : 'μ μΈ', μ : 'μ λμ', μ: 'μκ°', μ¬: 'μ΄μ¬μΌ', λ : 'μλ λ―ΈμΌ',
μ : 'μλ λ―ΈμΌμ κ°', κ²: 'μμ€κ²', λ¨: 'λ€λμ', νΈ: 'νΈμΈμ', μ: 'μμ',
μ: 'μλͺ¨μ€', μ΅: 'μ€λ°λ', μ: 'μλ', λ―Έ: 'λ―Έκ°', λ: 'λν',
ν©: 'νλ°κ΅', μ΅: 'μ€λ°λ', ν: 'νκ°', μ₯: 'μ€κ°λ΄', λ§: 'λ§λΌκΈ°'
};
BibleVerseEngine.NEW_TESTAMENT_BOOKS = {
λ§: 'λ§ν볡μ', λ§: 'λ§κ°λ³΅μ', λ
: 'λκ°λ³΅μ', μ: 'μν볡μ',
ν: 'μ¬λνμ ', 둬: 'λ‘λ§μ', κ³ μ : 'κ³ λ¦°λμ μ', κ³ ν: 'κ³ λ¦°λνμ',
κ°: 'κ°λΌλμμ', μ‘: 'μλ² μμ', λΉ: 'λΉλ¦½λ³΄μ', 골: '골λ‘μμ',
μ΄μ : 'λ°μ΄λ‘λκ°μ μ', μ΄ν: 'λ°μ΄λ‘λκ°νμ', λ€μ : 'λλͺ¨λ°μ μ',
λ€ν: 'λλͺ¨λ°νμ', λ: 'λλμ', λͺ¬: 'λΉλ λͺ¬μ', ν: 'νλΈλ¦¬μ',
μ½: 'μΌκ³ 보μ', λ²§μ : 'λ² λλ‘μ μ', λ²§ν: 'λ² λλ‘νμ',
μμΌ: 'μνμΌμ', μμ΄: 'μνμ΄μ', μμΌ: 'μνμΌμ', μ : 'μ λ€μ', κ³: 'μνκ³μλ‘'
};
BibleVerseEngine.ALL_BOOKS = {
...BibleVerseEngine.OLD_TESTAMENT_BOOKS,
...BibleVerseEngine.NEW_TESTAMENT_BOOKS
};
// Regular expressions
BibleVerseEngine.CMD_RE = /\/([^\s/]{1,24})/ug;
BibleVerseEngine.BIBLE_REF_RE = /^([κ°-ν£A-Za-z]{1,6})(\d{0,3}):(\d{1,3})(?:-(\d{1,3}))?$/u;
//# sourceMappingURL=BibleVerseEngine.js.map