-
Notifications
You must be signed in to change notification settings - Fork 2
/
ged2Json.js
144 lines (136 loc) · 3.87 KB
/
ged2Json.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
var util = require('util');
var Transform = require('stream').Transform;
util.inherits(Ged2Json, Transform);
/**
* Stream JSON objects out of GEDCOM file
*
* Given an object stream that's passing along lines from a GEDCOM file,
* this Transform Stream will collect them into JSON objects and emit them.
*
* As GEDCOM data structures allow some data at the root node as well as
* child elements on that same node, that data is moved into the `GEDVALUE`
* property of the object assigned to that root node, along with any child elements.
*
* @param {Object} options
*/
function Ged2Json(options) {
if (!(this instanceof Ged2Json)) return new Ged2Json(options);
Transform.call(this, { objectMode: true });
if (typeof options === 'undefined') {
options = {};
}
this.currentObject = false;
this.lastLevels = {};
}
Ged2Json.prototype.simplify = function simplify(obj) {
var keys = Object.keys(obj);
var parsed;
var out = {};
if (keys.length == 1 && keys[0] == 'GEDVALUE') {
return obj['GEDVALUE'];
}
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (!Array.isArray(obj[key])) {
obj[key] = [obj[key]];
}
if (key == 'ADDR') {
out[key] = obj[key].map(function(el) {
if (typeof el['CONT'] !== 'undefined') {
el['GEDVALUE'] += '\n'+el['CONT']['GEDVALUE'];
delete el['CONT'];
}
return this.simplify(el);
}.bind(this));
} else if (key == 'DATE') {
out[key] = obj[key].map(function(el) {
if (typeof el['TIME'] !== 'undefined') {
el['GEDVALUE'] += ' '+el['TIME']['GEDVALUE'];
delete el['TIME'];
}
return this.simplify(el);
}.bind(this));
} else {
out[key] = obj[key].map(function(el) {
if (typeof el == 'string') {
return el;
}
return this.simplify(el);
}.bind(this));
}
if (out[key].length === 1) {
out[key] = out[key][0];
}
if (out[key] === '') {
delete out[key];
}
}
return out;
};
Ged2Json.prototype._transform = function(line, encoding, callback) {
var s = line.indexOf(' ');
var level = parseInt(line.slice(0,s));
var s2 = line.indexOf(' ', s+1);
var code, value;
if (s2 !== -1) {
code = line.slice(s+1, s2);
value = line.slice(s2+1);
} else {
code = line.slice(s+1);
value = '';
}
if (level == 0) {
// Start new object
if (this.currentObject !== false) {
var out = this.simplify(this.currentObject);
this.push(out); // Pass out of transformer
}
this.currentObject = {};
this.currentObject['GEDVALUE'] = line.slice(s+1);
this.lastLevels = {};
this.lastLevels[0] = this.currentObject;
} else {
var parent = this.lastLevels[level-1];
if (typeof parent === 'undefined') {
console.log(JSON.stringify(this.lastLevels, null, 2));
console.log(line);
throw new Error('No parent for level '+level);
}
var newItem = { 'GEDVALUE': value };
if (typeof parent[code] === 'undefined') {
parent[code] = newItem;
} else {
if (!Array.isArray(parent[code])) {
parent[code] = [parent[code]];
}
parent[code].push(newItem);
}
this.lastLevels[level] = newItem;
}
callback();
};
Ged2Json.prototype._flush = function(callback) {
if (this.currentObject !== false) {
this.push(this.simplify(this.currentObject));
}
callback();
};
if (require.main == module) {
// Called from command line
var fileName = process.argv[2];
if (typeof fileName == 'undefined' || fileName == '') {
console.log("No file name specified");
process.exit();
}
var fs = require('fs');
var FileLines = require('./fileLines');
var fs = fs
.createReadStream(fileName)
.pipe(new FileLines())
.pipe(new Ged2Json());
fs.on('data', function(obj) {
console.log(JSON.stringify(obj, null, 2));
});
} else {
module.exports = Ged2Json;
}