UNPKG

read-gedcom

Version:
83 lines 4.21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildTree = void 0; const error_1 = require("./error"); const PROGRESS_INTERVAL = 50000; /** * Builds a tree from tokenized Gedcom lines. * @param lines An iterable of regular expression matches, which format is defined in {@link tokenize} * @param noInlineContinuations See {@link GedcomReadingOptions.noInlineContinuations} * @param progressCallback See {@link GedcomReadingPhase.progressCallback} */ const buildTree = (lines, noInlineContinuations = false, progressCallback = null) => { if (progressCallback) { progressCallback(0); } let i = 0; let charsRead = 0; let currentLevel = -1; // Current level const stack = [{ tag: null, pointer: null, value: null, indexSource: -1, indexRelative: 0, children: [] }]; for (const line of lines) { const [lineStr, levelStr, pointer, tag, value] = line; // There is an unsolvable ambiguity here, so we just try our best and assume it is correct const valueUnescaped = value ? value.replace(/@@/g, '@') : value; charsRead += lineStr.length; const level = parseInt(levelStr); const isSameOrUpperLevel = level <= currentLevel, isDownLevel = level === currentLevel + 1; if (level < 0 || (!isSameOrUpperLevel && !isDownLevel)) { throw new error_1.ErrorInvalidNesting(`Illegal nesting level at line ${i + 1} (current is ${currentLevel}, got ${level})`, i + 1, currentLevel, level); } const levelDifference = currentLevel - level + 1; for (let j = 0; j < levelDifference; j++) { // Go up stack.pop(); } const parent = stack[stack.length - 1]; const siblings = parent.children; if (tag === "CONC" /* Tag.Concatenation */ && !noInlineContinuations) { // TODO: (potentially) inefficient string concatenation if (pointer) { throw new error_1.ErrorInvalidConcatenation(`Illegal concatenation format at line ${i + 1}`, i + 1, "CONC" /* Tag.Concatenation */); } if (!parent) { throw new error_1.ErrorInvalidConcatenation(`Concatenation with no parent at line ${i + 1}`, i + 1, "CONC" /* Tag.Concatenation */); } if (parent.value == null) { parent.value = ''; } parent.value += valueUnescaped !== null && valueUnescaped !== void 0 ? valueUnescaped : ''; currentLevel = level - 1; } else if (tag === "CONT" /* Tag.Continuation */ && !noInlineContinuations) { if (pointer) { throw new error_1.ErrorInvalidConcatenation(`Illegal continuation format at line ${i + 1}`, i + 1, "CONT" /* Tag.Continuation */); } if (!parent) { throw new error_1.ErrorInvalidConcatenation(`Continuation with no parent at line ${i + 1}`, i + 1, "CONT" /* Tag.Continuation */); } const separator = '\n'; // TODO: hardcoded separator if (parent.value == null) { parent.value = ''; } parent.value += separator + (valueUnescaped !== null && valueUnescaped !== void 0 ? valueUnescaped : ''); currentLevel = level - 1; } else { const child = { tag, pointer: pointer !== null && pointer !== void 0 ? pointer : null, value: valueUnescaped !== null && valueUnescaped !== void 0 ? valueUnescaped : null, indexSource: i, indexRelative: parent.children.length, children: [] }; siblings.push(child); if (pointer && level > 0) { throw new error_1.ErrorInvalidRecordDefinition(`Record must be a top-level definition at line ${i + 1}`, i + 1); } stack.push(child); currentLevel = level; } i++; if (progressCallback && i % PROGRESS_INTERVAL === 0) { progressCallback(charsRead); } } if (progressCallback) { progressCallback(charsRead); } return stack[0]; // The top of the stack is the root node }; exports.buildTree = buildTree; //# sourceMappingURL=structurer.js.map