Created
          August 21, 2025 18:05 
        
      - 
      
- 
        Save eldhosejoys/e4d4dfa277bc46d2380d25ec5b3c47a4 to your computer and use it in GitHub Desktop. 
    To convert openbible.info cross-references to json files (https://www.openbible.info/labs/cross-references/)
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | { | |
| "Genesis": 1, "Gen": 1, "Ge": 1, "Gn": 1, | |
| "Exodus": 2, "Exod": 2, "Exo": 2, "Ex": 2, | |
| "Leviticus": 3, "Lev": 3, "Le": 3, "Lv": 3, | |
| "Numbers": 4, "Num": 4, "Nu": 4, "Nm": 4, "Nb": 4, | |
| "Deuteronomy": 5, "Deut": 5, "De": 5, "Dt": 5, | |
| "Joshua": 6, "Josh": 6, "Jos": 6, "Jsh": 6, | |
| "Judges": 7, "Judg": 7, "Jdg": 7, "Jg": 7, "Jdgs": 7, | |
| "Ruth": 8, "Rth": 8, "Ru": 8, | |
| "1 Samuel": 9, "1 Sam": 9, "1Sam": 9, "1S": 9, "1Sm": 9, "1Sa": 9, | |
| "2 Samuel": 10, "2 Sam": 10, "2Sam": 10, "2S": 10, "2Sm": 10, "2Sa": 10, | |
| "1 Kings": 11, "1 Kgs": 11, "1Kgs": 11, "1K": 11, "1Ki": 11, | |
| "2 Kings": 12, "2 Kgs": 12, "2Kgs": 12, "2K": 12, "2Ki": 12, | |
| "1 Chronicles": 13, "1 Chr": 13, "1Chr": 13, "1Ch": 13, | |
| "2 Chronicles": 14, "2 Chr": 14, "2Chr": 14, "2Ch": 14, | |
| "Ezra": 15, "Ezr": 15, "Ez": 15, | |
| "Nehemiah": 16, "Neh": 16, "Ne": 16, | |
| "Esther": 17, "Esth": 17, "Es": 17, "Est": 17, | |
| "Job": 18, "Jb": 18, | |
| "Psalms": 19, "Psalm": 19, "Ps": 19, "Psa": 19, "Psm": 19, "Pss": 19, | |
| "Proverbs": 20, "Prov": 20, "Pro": 20, "Prv": 20, "Pr": 20, | |
| "Ecclesiastes": 21, "Eccl": 21, "Ecc": 21, "Ec": 21, "Qoh": 21, | |
| "Song of Solomon": 22, "Song of Songs": 22, "Song": 22, "So": 22, "SOS": 22, "Cant": 22, | |
| "Isaiah": 23, "Isa": 23, "Is": 23, | |
| "Jeremiah": 24, "Jer": 24, "Je": 24, "Jr": 24, | |
| "Lamentations": 25, "Lam": 25, "La": 25, | |
| "Ezekiel": 26, "Ezek": 26, "Eze": 26, "Ezk": 26, | |
| "Daniel": 27, "Dan": 27, "Da": 27, "Dn": 27, | |
| "Hosea": 28, "Hos": 28, "Ho": 28, | |
| "Joel": 29, "Joe": 29, "Jl": 29, | |
| "Amos": 30, "Am": 30, | |
| "Obadiah": 31, "Obad": 31, "Ob": 31, | |
| "Jonah": 32, "Jnh": 32, "Jon": 32, | |
| "Micah": 33, "Mic": 33, "Mi": 33, | |
| "Nahum": 34, "Nah": 34, "Na": 34, | |
| "Habakkuk": 35, "Hab": 35, "Hb": 35, | |
| "Zephaniah": 36, "Zeph": 36, "Zep": 36, "Zp": 36, | |
| "Haggai": 37, "Hag": 37, "Hg": 37, | |
| "Zechariah": 38, "Zech": 38, "Zec": 38, "Zc": 38, | |
| "Malachi": 39, "Mal": 39, "Ml": 39, | |
| "Matthew": 40, "Matt": 40, "Mat": 40, "Mt": 40, | |
| "Mark": 41, "Mrk": 41, "Mar": 41, "Mk": 41, "Mr": 41, | |
| "Luke": 42, "Luk": 42, "Lk": 42, | |
| "John": 43, "Jhn": 43, "Jn": 43, | |
| "Acts": 44, "Act": 44, "Ac": 44, | |
| "Romans": 45, "Rom": 45, "Ro": 45, "Rm": 45, | |
| "1 Corinthians": 46, "1 Cor": 46, "1Cor": 46, "1Co": 46, | |
| "2 Corinthians": 47, "2 Cor": 47, "2Cor": 47, "2Co": 47, | |
| "Galatians": 48, "Gal": 48, "Ga": 48, | |
| "Ephesians": 49, "Eph": 49, "Ep": 49, | |
| "Philippians": 50, "Phil": 50, "Php": 50, "Pp": 50, | |
| "Colossians": 51, "Col": 51, "Co": 51, | |
| "1 Thessalonians": 52, "1 Thess": 52, "1Thess": 52, "1Th": 52, | |
| "2 Thessalonians": 53, "2 Thess": 53, "2Thess": 53, "2Th": 53, | |
| "1 Timothy": 54, "1 Tim": 54, "1Tim": 54, "1Ti": 54, | |
| "2 Timothy": 55, "2 Tim": 55, "2Tim": 55, "2Ti": 55, | |
| "Titus": 56, "Tit": 56, "Ti": 56, | |
| "Philemon": 57, "Phlm": 57, "Phm": 57, "Pm": 57, | |
| "Hebrews": 58, "Heb": 58, | |
| "James": 59, "Jas": 59, "Jm": 59, | |
| "1 Peter": 60, "1 Pet": 60, "1Pet": 60, "1P": 60, "1Pt": 60, | |
| "2 Peter": 61, "2 Pet": 61, "2Pet": 61, "2P": 61, "2Pt": 61, | |
| "1 John": 62, "1 John": 62, "1John": 62, "1Jn": 62, | |
| "2 John": 63, "2 John": 63, "2John": 63, "2Jn": 63, | |
| "3 John": 64, "3 John": 64, "3John": 64, "3Jn": 64, | |
| "Jude": 65, "Jud": 65, "Jd": 65, | |
| "Revelation": 66, "Rev": 66, "Re": 66, "The Rev": 66 | |
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | const fs = require('fs'); | |
| const path = require('path'); | |
| // --- CONFIGURATION --- | |
| const abbrevsFilePath = path.join(__dirname, 'abbrevs.json'); | |
| const inputFilePath = path.join(__dirname, 'cross_references.txt'); | |
| const outputDir = path.join(__dirname, 'books-cross'); | |
| // A Set to store all unique unknown abbreviations we find | |
| const unknownAbbrevs = new Set(); | |
| /** | |
| * Parses a verse reference string (e.g., "Gen.1.1") into its components. | |
| */ | |
| function parseVerse(verseString, abbrevsMap, lineNumber) { | |
| const match = verseString.match(/^(.+?)\.(\d+)\.(\d+)$/); | |
| if (!match) { | |
| console.warn(`[Line ${lineNumber}] Could not parse verse format: ${verseString}`); | |
| return null; | |
| } | |
| const [, bookAbbrev, chapter, verse] = match; | |
| const bookNum = abbrevsMap[bookAbbrev]; | |
| if (!bookNum) { | |
| if (!unknownAbbrevs.has(bookAbbrev)) { | |
| console.warn(`[Line ${lineNumber}] Unknown book abbreviation found: '${bookAbbrev}'`); | |
| unknownAbbrevs.add(bookAbbrev); | |
| } | |
| return null; | |
| } | |
| return { | |
| book: bookAbbrev, | |
| bookNum: bookNum, | |
| chapter: parseInt(chapter, 10), | |
| verse: parseInt(verse, 10) | |
| }; | |
| } | |
| /** | |
| * Parses a 'toVerse' string. | |
| * If it's a single verse, returns an array with one element. | |
| * If it's a range, returns an array with the start and end verses. | |
| */ | |
| function formatToVerse(toVerseString, abbrevsMap, lineNumber) { | |
| // If it's NOT a range, handle it as a single verse. | |
| if (!toVerseString.includes('-')) { | |
| const parsed = parseVerse(toVerseString, abbrevsMap, lineNumber); | |
| return parsed ? [`${parsed.bookNum}/${parsed.chapter}/${parsed.verse}`] : []; | |
| } | |
| // --- THIS IS THE MODIFIED LOGIC FOR HANDLING RANGES --- | |
| const [startVerseStr, endVerseStr] = toVerseString.split('-'); | |
| const startVerse = parseVerse(startVerseStr, abbrevsMap, lineNumber); | |
| if (!startVerse) return []; | |
| let endVerse; | |
| // Handle ranges where the end is just a number (e.g., "Gen.1.1-5") | |
| if (endVerseStr.includes('.')) { | |
| endVerse = parseVerse(endVerseStr, abbrevsMap, lineNumber); | |
| } else { | |
| // Re-use the book and chapter from the start verse | |
| endVerse = { ...startVerse, verse: parseInt(endVerseStr, 10) }; | |
| } | |
| if (!endVerse || isNaN(endVerse.verse)) { | |
| console.warn(`[Line ${lineNumber}] Could not parse range's end verse: ${toVerseString}`); | |
| return []; | |
| } | |
| const startVerseFormatted = `${startVerse.bookNum}/${startVerse.chapter}/${startVerse.verse}`; | |
| const endVerseFormatted = `${endVerse.bookNum}/${endVerse.chapter}/${endVerse.verse}`; | |
| // If start and end are identical (e.g., from a malformed range "Gen.1.1-1"), just return one. | |
| if (startVerseFormatted === endVerseFormatted) { | |
| return [startVerseFormatted]; | |
| } | |
| // Return an array with only the start and end of the range. | |
| return [startVerseFormatted, endVerseFormatted]; | |
| } | |
| // --- Main Execution --- | |
| try { | |
| const abbrevsMap = JSON.parse(fs.readFileSync(abbrevsFilePath, 'utf8')); | |
| const fileContent = fs.readFileSync(inputFilePath, 'utf8'); | |
| const lines = fileContent.trim().split('\n'); | |
| if (lines.length <= 1) { | |
| console.log('The file is empty or contains only a header.'); | |
| return; | |
| } | |
| const groupedData = {}; | |
| for (let i = 1; i < lines.length; i++) { | |
| const lineNumber = i + 1; | |
| const line = lines[i]; | |
| const columns = line.split('\t'); | |
| if (columns.length < 3) continue; | |
| const fromVerse = parseVerse(columns[0], abbrevsMap, lineNumber); | |
| if (!fromVerse) continue; | |
| const toVerses = formatToVerse(columns[1], abbrevsMap, lineNumber); | |
| if (toVerses.length === 0) continue; | |
| const crossRefObject = { | |
| b: fromVerse.bookNum, | |
| c: fromVerse.chapter, | |
| v: fromVerse.verse, | |
| to: toVerses, | |
| votes: parseInt(columns[2], 10) | |
| }; | |
| if (!groupedData[fromVerse.bookNum]) { | |
| groupedData[fromVerse.bookNum] = []; | |
| } | |
| groupedData[fromVerse.bookNum].push(crossRefObject); | |
| } | |
| // --- Final Report and File Writing --- | |
| if (unknownAbbrevs.size > 0) { | |
| console.error("\n--- DEBUG SUMMARY ---"); | |
| console.error("Conversion failed. Found unknown abbreviations:"); | |
| console.error(Array.from(unknownAbbrevs).join(', ')); | |
| console.error(`\nPlease add these to '${path.basename(abbrevsFilePath)}' and run again.`); | |
| } else { | |
| if (!fs.existsSync(outputDir)) { | |
| fs.mkdirSync(outputDir, { recursive: true }); | |
| } | |
| let filesWritten = 0; | |
| for (const bookNumber in groupedData) { | |
| const bookData = groupedData[bookNumber]; | |
| const outputFilePath = path.join(outputDir, `${bookNumber}.json`); | |
| const jsonString = JSON.stringify(bookData, null, 2); | |
| fs.writeFileSync(outputFilePath, jsonString, 'utf8'); | |
| filesWritten++; | |
| } | |
| console.log(`\nSuccess! Conversion complete.`); | |
| console.log(`${filesWritten} files were written to the '${outputDir}' directory.`); | |
| } | |
| } catch (error) { | |
| console.error('An error occurred:', error); | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment