UNPKG

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
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');