gedcom-d3
Version:
A GEDCOM parser, which translates GEDCOM (.ged) files into D3 capable JSON. This package is specifically designed to prepare data for use in https://github.com/oh-kay-blanket/blood-lines
82 lines (70 loc) • 2.67 kB
JavaScript
var crawl = require('tree-crawl');
// from https://github.com/madprime/python-gedcom/blob/master/gedcom/__init__.py
// * Level must start with nonnegative int, no leading zeros.
// * Pointer optional, if it exists it must be flanked by '@'
// * Tag must be alphanumeric string
// * Value optional, consists of anything after a space to end of line
// End of line defined by \n or \r
var lineRe = /\s*(0|[1-9]+[0-9]*) (@[^@]+@ |)([A-Za-z0-9_]+)( [^\n\r]*|)/;
function parse(input) {
var start = { root: { tree: [] }, level: 0 };
start.pointer = start.root;
var data = input
.split('\n')
.map(mapLine)
.filter(function(_) { return _; })
.reduce(buildTree, start)
.root;
crawl(data, cleanUp, { getChildren });
//console.log(data);
//var cleanTree = data.tree.filter(hasTag('INDI'));
//console.log(cleanTree);
return data.tree;
// the basic trick of this module is turning the suggested tree
// structure of a GEDCOM file into a tree in JSON. This reduction
// does that. The only real trick is the `.up` member of objects
// that points to a level up in the structure. This we have to
// censor before JSON.stringify since it creates circular references.
function buildTree(memo, data) {
if (data.level === memo.level) {
memo.pointer.tree.push(data);
} else if (data.level > memo.level) {
var up = memo.pointer;
memo.pointer = memo.pointer.tree[
memo.pointer.tree.length - 1];
memo.pointer.tree.push(data);
memo.pointer.up = up;
memo.level = data.level;
} else if (data.level < memo.level) {
// the jump up in the stack may be by more than one, so ascend
// until we're at the right level.
while (data.level <= memo.pointer.level && memo.pointer.up) {
memo.pointer = memo.pointer.up;
}
memo.pointer.tree.push(data);
memo.level = data.level;
}
return memo;
}
function mapLine(data) {
var match = data.match(lineRe);
if (!match) return null;
return {
level: parseInt(match[1], 10),
pointer: match[2].trim(),
tag: match[3].trim(),
data: match[4].trimLeft(),
tree: []
};
}
function cleanUp(node) {
delete node.up;
delete node.level;
}
function getChildren(node) {
//console.log(node.tree);
return node.tree;
}
}
module.exports.parse = parse;
module.exports.d3ize = require('./d3ize');