read-gedcom
Version:
Gedcom file reader
83 lines • 4.21 kB
JavaScript
;
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