gedcom-d3 2.0.9 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(chmod:*)",
5
+ "Bash(./publish.sh:*)"
6
+ ]
7
+ }
8
+ }
package/d3ize.js CHANGED
@@ -1,622 +1,623 @@
1
1
  const d3ize = (tree) => {
2
- const notes = tree.filter(hasTag('NOTE'))
3
- let surnameList = []
4
- const peopleNodes = tree
5
- .filter(hasTag('INDI'))
6
- .map((p) => toNode(p, notes, surnameList))
7
- const families = tree.filter(hasTag('FAM'))
8
- const links = families.reduce((memo, family) => {
9
- return memo.concat(familyLinks(family, peopleNodes))
10
- }, [])
11
- assignFy(peopleNodes, links)
12
- return {
13
- nodes: peopleNodes,
14
- links: links,
15
- families: families,
16
- surnameList: surnameList,
17
- }
18
- }
2
+ const notes = tree.filter(hasTag("NOTE"));
3
+ let surnameList = [];
4
+ const peopleNodes = tree
5
+ .filter(hasTag("INDI"))
6
+ .map((p) => toNode(p, notes, surnameList));
7
+ const families = tree.filter(hasTag("FAM"));
8
+ const links = families.reduce((memo, family) => {
9
+ return memo.concat(familyLinks(family, peopleNodes));
10
+ }, []);
11
+ assignFy(peopleNodes, links);
12
+ return {
13
+ nodes: peopleNodes,
14
+ links: links,
15
+ families: families,
16
+ surnameList: surnameList,
17
+ };
18
+ };
19
19
 
20
20
  // Tag search function
21
21
  const hasTag = (val) => {
22
- return (node) => {
23
- return node.tag === val
24
- }
25
- }
22
+ return (node) => {
23
+ return node.tag === val;
24
+ };
25
+ };
26
26
 
27
27
  // Data search function
28
28
  const hasData = (val) => {
29
- return (node) => {
30
- return node.data === val
31
- }
32
- }
29
+ return (node) => {
30
+ return node.data === val;
31
+ };
32
+ };
33
33
 
34
34
  // ID search function
35
35
  const hasID = (val) => {
36
- return (node) => {
37
- return node.id === val
38
- }
39
- }
36
+ return (node) => {
37
+ return node.id === val;
38
+ };
39
+ };
40
40
 
41
41
  const assignFy = (peopleNodes, links) => {
42
- // YOB known
43
- let yesyob = peopleNodes.filter((p) => {
44
- return p.yob !== '?' && !isNaN(+p.yob)
45
- })
46
-
47
- yesyob.forEach((p) => (p.fy = +p.yob))
48
-
49
- // YOB unknown
50
- let noyob = peopleNodes.filter((p) => {
51
- return p.yob === '?'
52
- })
53
-
54
- let count = 10
55
-
56
- // Cycle through list, adding fy until all complete
57
- while (noyob.length > 0 && count > 0) {
58
- let tempnoyob = noyob.slice()
59
-
60
- tempnoyob.forEach((p, index) => {
61
- // Build array of family
62
- let tpFamily = []
63
-
64
- links.forEach((link) => {
65
- if (link.source == p.id) {
66
- tpFamily.push({
67
- pRole: 'source',
68
- pType: link.sourceType,
69
- other: link.target,
70
- oType: link.targetType,
71
- })
72
- } else if (link.target == p.id) {
73
- tpFamily.push({
74
- pRole: 'target',
75
- pType: link.targetType,
76
- other: link.source,
77
- oType: link.sourceType,
78
- })
79
- }
80
- })
81
-
82
- // Check family for YOB
83
- tpFamily.forEach((member) => {
84
- // USE SOME() INSTEAD OF FOREACH!!!
85
- peopleNodes.forEach((person) => {
86
- // USE SOME() INSTEAD OF FOREACH!!!
87
- if (person.id == member.other && person.fy !== undefined) {
88
- // Person is source
89
- if (member.pRole === 'source') {
90
- // Person is husband
91
- if (member.pType === 'HUSB' && member.oType === 'WIFE') {
92
- p.fy = +person.fy - 3
93
-
94
- // Person is father
95
- } else if (member.pType === 'HUSB' && member.oType === 'CHIL') {
96
- p.fy = +person.fy - 30
97
-
98
- // Person is mother
99
- } else if (member.pType === 'WIFE') {
100
- p.fy = +person.fy - 27
101
- }
102
-
103
- // Person is target
104
- } else if (member.pRole === 'target') {
105
- // Person is wife
106
- if (member.pType === 'WIFE' && member.oType === 'HUSB') {
107
- p.fy = +person.fy + 3
108
-
109
- // Person is child of father
110
- } else if (member.pType === 'CHIL' && member.oType === 'HUSB') {
111
- p.fy = +person.fy + 30
112
-
113
- // Person is child of mother
114
- } else if (member.pType === 'CHIL' && member.oType === 'WIFE') {
115
- p.fy = +person.fy + 27
116
- }
117
- }
118
- }
119
- })
120
- })
121
- if (p.fy !== undefined) {
122
- noyob.splice(index, index + 1)
123
- }
124
- })
125
- count -= 1
126
- }
127
-
128
- const convertFy = (peopleNodes) => {
129
- const fyRatio = (peopleNodes) => {
130
- if (peopleNodes.length <= 50) {
131
- return 3
132
- } else if (peopleNodes.length > 50 && peopleNodes.length <= 150) {
133
- return 4
134
- } else if (peopleNodes.length > 150 && peopleNodes.length <= 250) {
135
- return 5
136
- } else if (peopleNodes.length > 250) {
137
- return 6
138
- }
139
- }
140
- let allFy = []
141
- peopleNodes.forEach((p) => {
142
- if (p.fy !== undefined) {
143
- p.fy = p.fy * fyRatio(peopleNodes)
144
- allFy.push(p.fy)
145
- }
146
- })
147
-
148
- let total = 0
149
- allFy.forEach((fy) => (total += fy))
150
- let average = total / allFy.length
151
-
152
- peopleNodes.forEach((p) => {
153
- if (p.fy !== undefined) {
154
- p.fy = -(p.fy - average)
155
- }
156
- })
157
- }
158
- convertFy(peopleNodes)
159
- }
42
+ // YOB known
43
+ let yesyob = peopleNodes.filter((p) => {
44
+ return p.yob !== "?" && !isNaN(+p.yob);
45
+ });
46
+
47
+ yesyob.forEach((p) => (p.fy = +p.yob));
48
+
49
+ // YOB unknown
50
+ let noyob = peopleNodes.filter((p) => {
51
+ return p.yob === "?";
52
+ });
53
+
54
+ let count = 10;
55
+
56
+ // Cycle through list, adding fy until all complete
57
+ while (noyob.length > 0 && count > 0) {
58
+ let tempnoyob = noyob.slice();
59
+
60
+ tempnoyob.forEach((p, index) => {
61
+ // Build array of family
62
+ let tpFamily = [];
63
+
64
+ links.forEach((link) => {
65
+ if (link.source == p.id) {
66
+ tpFamily.push({
67
+ pRole: "source",
68
+ pType: link.sourceType,
69
+ other: link.target,
70
+ oType: link.targetType,
71
+ });
72
+ } else if (link.target == p.id) {
73
+ tpFamily.push({
74
+ pRole: "target",
75
+ pType: link.targetType,
76
+ other: link.source,
77
+ oType: link.sourceType,
78
+ });
79
+ }
80
+ });
81
+
82
+ // Check family for YOB
83
+ tpFamily.forEach((member) => {
84
+ // USE SOME() INSTEAD OF FOREACH!!!
85
+ peopleNodes.forEach((person) => {
86
+ // USE SOME() INSTEAD OF FOREACH!!!
87
+ if (person.id == member.other && person.fy !== undefined) {
88
+ // Person is source
89
+ if (member.pRole === "source") {
90
+ // Person is husband
91
+ if (member.pType === "HUSB" && member.oType === "WIFE") {
92
+ p.fy = +person.fy - 3;
93
+
94
+ // Person is father
95
+ } else if (member.pType === "HUSB" && member.oType === "CHIL") {
96
+ p.fy = +person.fy - 30;
97
+
98
+ // Person is mother
99
+ } else if (member.pType === "WIFE") {
100
+ p.fy = +person.fy - 27;
101
+ }
102
+
103
+ // Person is target
104
+ } else if (member.pRole === "target") {
105
+ // Person is wife
106
+ if (member.pType === "WIFE" && member.oType === "HUSB") {
107
+ p.fy = +person.fy + 3;
108
+
109
+ // Person is child of father
110
+ } else if (member.pType === "CHIL" && member.oType === "HUSB") {
111
+ p.fy = +person.fy + 30;
112
+
113
+ // Person is child of mother
114
+ } else if (member.pType === "CHIL" && member.oType === "WIFE") {
115
+ p.fy = +person.fy + 27;
116
+ }
117
+ }
118
+ }
119
+ });
120
+ });
121
+ if (p.fy !== undefined) {
122
+ noyob.splice(index, index + 1);
123
+ }
124
+ });
125
+ count -= 1;
126
+ }
127
+
128
+ const convertFy = (peopleNodes) => {
129
+ const fyRatio = (peopleNodes) => {
130
+ if (peopleNodes.length <= 50) {
131
+ return 3;
132
+ } else if (peopleNodes.length > 50 && peopleNodes.length <= 150) {
133
+ return 4;
134
+ } else if (peopleNodes.length > 150 && peopleNodes.length <= 250) {
135
+ return 5;
136
+ } else if (peopleNodes.length > 250) {
137
+ return 6;
138
+ }
139
+ };
140
+ let allFy = [];
141
+ peopleNodes.forEach((p) => {
142
+ if (p.fy !== undefined) {
143
+ p.fy = p.fy * fyRatio(peopleNodes);
144
+ allFy.push(p.fy);
145
+ }
146
+ });
147
+
148
+ let total = 0;
149
+ allFy.forEach((fy) => (total += fy));
150
+ let average = total / allFy.length;
151
+
152
+ peopleNodes.forEach((p) => {
153
+ if (p.fy !== undefined) {
154
+ p.fy = -(p.fy - average);
155
+ }
156
+ });
157
+ };
158
+ convertFy(peopleNodes);
159
+ };
160
160
 
161
161
  // Get title
162
162
  const getTitle = (p) => {
163
- const title = p.tree.filter(hasTag('TITL')) || []
164
- if (title.length > 0) {
165
- return title[title.length - 1].data
166
- }
167
- }
163
+ const title = p.tree.filter(hasTag("TITL")) || [];
164
+ if (title.length > 0) {
165
+ return title[title.length - 1].data;
166
+ }
167
+ };
168
168
 
169
169
  // Get full name
170
170
  const getName = (p) => {
171
- let nameNode = (p.tree.filter(hasTag('NAME')) || [])[0]
172
- if (nameNode) {
173
- return nameNode.data.replace(/\//g, '')
174
- } else {
175
- return '?'
176
- }
177
- }
171
+ let nameNode = (p.tree.filter(hasTag("NAME")) || [])[0];
172
+ if (nameNode) {
173
+ return nameNode.data.replace(/\//g, "");
174
+ } else {
175
+ return "?";
176
+ }
177
+ };
178
178
 
179
179
  // Get first name
180
180
  const getFirstName = (p) => {
181
- // Find 'NAME' tag
182
- const nameNode = (p.tree.filter(hasTag('NAME')) || [])[0]
183
- if (nameNode) {
184
- // Find 'GIVN' tag
185
- let firstNameNode = (nameNode.tree.filter(hasTag('GIVN')) || [])[0]
186
- if (firstNameNode) {
187
- // Remove middle name
188
- if (firstNameNode.data.search(' ') !== -1) {
189
- return firstNameNode.data.slice(0, firstNameNode.data.search(' '))
190
- } else {
191
- return firstNameNode.data
192
- }
193
- } else {
194
- return '?'
195
- }
196
- } else {
197
- return '?'
198
- }
199
- }
181
+ // Find 'NAME' tag
182
+ const nameNode = (p.tree.filter(hasTag("NAME")) || [])[0];
183
+ if (nameNode) {
184
+ // Find 'GIVN' tag
185
+ let firstNameNode = (nameNode.tree.filter(hasTag("GIVN")) || [])[0];
186
+ if (firstNameNode) {
187
+ // Remove middle name
188
+ if (firstNameNode.data.search(" ") !== -1) {
189
+ return firstNameNode.data.slice(0, firstNameNode.data.search(" "));
190
+ } else {
191
+ return firstNameNode.data;
192
+ }
193
+ } else {
194
+ return "?";
195
+ }
196
+ } else {
197
+ return "?";
198
+ }
199
+ };
200
200
 
201
201
  // Get surname
202
202
  const getSurname = (p) => {
203
- // Find 'NAME' tag
204
- const nameNode = (p.tree.filter(hasTag('NAME')) || [])[0]
205
- if (nameNode) {
206
- // Find 'SURN' tag
207
- const surnameNode = (nameNode.tree.filter(hasTag('SURN')) || [])[0]
208
-
209
- // If surname listed
210
- if (surnameNode) {
211
- // Remove alternate surnames
212
- if (surnameNode.data.search(',') !== -1) {
213
- return surnameNode.data.slice(0, surnameNode.data.search(','))
214
- } else {
215
- return surnameNode.data
216
- }
217
-
218
- // Derive surname from name
219
- } else {
220
- nameArr = nameNode.data.split(' ')
221
-
222
- // Look for forward slashes
223
- let isSlashes = nameArr.some((str) => str[0] === '/')
224
- if (isSlashes) {
225
- return nameArr.find((str) => str[0] === '/').replace(/\//g, '')
226
-
227
- // no slashes, use final item in array
228
- } else {
229
- nameArr[nameArr.length - 1] = nameArr[nameArr.length - 1].replace(
230
- /\//g,
231
- ''
232
- )
233
- return nameArr.length > 1 ? nameArr[nameArr.length - 1] : 'Hrm'
234
- }
235
- }
236
- } else {
237
- return '?'
238
- }
239
- }
203
+ // Find 'NAME' tag
204
+ const nameNode = (p.tree.filter(hasTag("NAME")) || [])[0];
205
+ if (nameNode) {
206
+ // Find 'SURN' tag
207
+ const surnameNode = (nameNode.tree.filter(hasTag("SURN")) || [])[0];
208
+
209
+ // If surname listed
210
+ if (surnameNode) {
211
+ // Remove alternate surnames
212
+ if (surnameNode.data.search(",") !== -1) {
213
+ return surnameNode.data.slice(0, surnameNode.data.search(","));
214
+ } else {
215
+ return surnameNode.data;
216
+ }
217
+
218
+ // Derive surname from name
219
+ } else {
220
+ nameArr = nameNode.data.split(" ");
221
+
222
+ // Look for forward slashes
223
+ let isSlashes = nameArr.some((str) => str[0] === "/");
224
+ if (isSlashes) {
225
+ return nameArr.find((str) => str[0] === "/").replace(/\//g, "");
226
+
227
+ // no slashes, use final item in array
228
+ } else {
229
+ nameArr[nameArr.length - 1] = nameArr[nameArr.length - 1].replace(
230
+ /\//g,
231
+ "",
232
+ );
233
+ return nameArr.length > 1 ? nameArr[nameArr.length - 1] : "Hrm";
234
+ }
235
+ }
236
+ } else {
237
+ return "?";
238
+ }
239
+ };
240
240
 
241
241
  // Get gender
242
242
  const getGender = (p) => {
243
- // Find 'SEX' tag
244
- let genderNode = (p.tree.filter(hasTag('SEX')) || [])[0]
245
- if (genderNode) {
246
- return genderNode.data
247
- } else {
248
- return 'Unknown'
249
- }
250
- }
243
+ // Find 'SEX' tag
244
+ let genderNode = (p.tree.filter(hasTag("SEX")) || [])[0];
245
+ if (genderNode) {
246
+ return genderNode.data;
247
+ } else {
248
+ return "Unknown";
249
+ }
250
+ };
251
251
 
252
252
  // Get date of birth
253
253
  const getDOB = (p) => {
254
- // Find 'BIRT' tag
255
- let dobNode = (p.tree.filter(hasTag('BIRT')) || [])[0]
256
- if (dobNode) {
257
- // Find 'DATE' tag
258
- let dateNode = (dobNode.tree.filter(hasTag('DATE')) || [])[0]
259
- if (dateNode) {
260
- return dateNode.data
261
- } else {
262
- return '?'
263
- }
264
- } else {
265
- return '?'
266
- }
267
- }
254
+ // Find 'BIRT' tag
255
+ let dobNode = (p.tree.filter(hasTag("BIRT")) || [])[0];
256
+ if (dobNode) {
257
+ // Find 'DATE' tag
258
+ let dateNode = (dobNode.tree.filter(hasTag("DATE")) || [])[0];
259
+ if (dateNode) {
260
+ return dateNode.data;
261
+ } else {
262
+ return "?";
263
+ }
264
+ } else {
265
+ return "?";
266
+ }
267
+ };
268
268
 
269
269
  // Get year of birth
270
270
  const getYOB = (p) => {
271
- // Find 'BIRT' tag
272
- let dobNode = (p.tree.filter(hasTag('BIRT')) || [])[0]
273
- if (dobNode) {
274
- // Find 'DATE' tag
275
- let dateNode = (dobNode.tree.filter(hasTag('DATE')) || [])[0]
276
- if (dateNode) {
277
- return dateNode.data.slice(-4)
278
- } else {
279
- return '?'
280
- }
281
- } else {
282
- return '?'
283
- }
284
- }
271
+ // Find 'BIRT' tag
272
+ let dobNode = (p.tree.filter(hasTag("BIRT")) || [])[0];
273
+ if (dobNode) {
274
+ // Find 'DATE' tag
275
+ let dateNode = (dobNode.tree.filter(hasTag("DATE")) || [])[0];
276
+ if (dateNode) {
277
+ return dateNode.data.slice(-4);
278
+ } else {
279
+ return "?";
280
+ }
281
+ } else {
282
+ return "?";
283
+ }
284
+ };
285
285
 
286
286
  // Get place of birth
287
287
  const getPOB = (p) => {
288
- // Find 'BIRT' tag
289
- let pobNode = (p.tree.filter(hasTag('BIRT')) || [])[0]
290
- if (pobNode) {
291
- // Find 'DATE' tag
292
- let placeNode = (pobNode.tree.filter(hasTag('PLAC')) || [])[0]
293
- if (placeNode) {
294
- return placeNode.data
295
- } else {
296
- return ''
297
- }
298
- } else {
299
- return ''
300
- }
301
- }
288
+ // Find 'BIRT' tag
289
+ let pobNode = (p.tree.filter(hasTag("BIRT")) || [])[0];
290
+ if (pobNode) {
291
+ // Find 'DATE' tag
292
+ let placeNode = (pobNode.tree.filter(hasTag("PLAC")) || [])[0];
293
+ if (placeNode) {
294
+ return placeNode.data;
295
+ } else {
296
+ return "";
297
+ }
298
+ } else {
299
+ return "";
300
+ }
301
+ };
302
302
 
303
303
  // Get date of death
304
304
  const getDOD = (p) => {
305
- // Find 'DEAT' tag
306
- let dobNode = (p.tree.filter(hasTag('BIRT')) || [])[0]
307
- let dodNode = (p.tree.filter(hasTag('DEAT')) || [])[0]
308
- if (dodNode) {
309
- // Find 'DATE' tag
310
- let dateNode = (dodNode.tree.filter(hasTag('DATE')) || [])[0]
311
- if (dateNode) {
312
- return dateNode.data
313
- } else {
314
- return '?'
315
- }
316
- } else if (dobNode) {
317
- let dateNode = (dobNode.tree.filter(hasTag('DATE')) || [])[0]
318
- if (dateNode) {
319
- return dateNode.data.slice(-4) + 100
320
- } else {
321
- return '?'
322
- }
323
- } else {
324
- return 'Present'
325
- }
326
- }
305
+ // Find 'DEAT' tag
306
+ let dobNode = (p.tree.filter(hasTag("BIRT")) || [])[0];
307
+ let dodNode = (p.tree.filter(hasTag("DEAT")) || [])[0];
308
+ if (dodNode) {
309
+ // Find 'DATE' tag
310
+ let dateNode = (dodNode.tree.filter(hasTag("DATE")) || [])[0];
311
+ if (dateNode) {
312
+ return dateNode.data;
313
+ } else {
314
+ return "?";
315
+ }
316
+ } else if (dobNode) {
317
+ let dateNode = (dobNode.tree.filter(hasTag("DATE")) || [])[0];
318
+ if (dateNode) {
319
+ return dateNode.data.slice(-4) + 100;
320
+ } else {
321
+ return "?";
322
+ }
323
+ } else {
324
+ return "Present";
325
+ }
326
+ };
327
327
 
328
328
  // Get year of death
329
329
  const getYOD = (p) => {
330
- let thisYear = new Date().getFullYear()
331
-
332
- // Find 'DEAT' tag
333
- let dobNode = (p.tree.filter(hasTag('BIRT')) || [])[0]
334
- let dodNode = (p.tree.filter(hasTag('DEAT')) || [])[0]
335
-
336
- // If DEATH tag
337
- if (dodNode) {
338
- // Find 'DATE' tag
339
- let dateNode = (dodNode.tree.filter(hasTag('DATE')) || [])[0]
340
-
341
- // If death date listed
342
- if (dateNode) {
343
- return dateNode.data.slice(-4)
344
- } else {
345
- return '?'
346
- }
347
-
348
- // BIRT tag, but no DEAT tag
349
- } else if (dobNode && !dodNode) {
350
- let dateNode = (dobNode.tree.filter(hasTag('DATE')) || [])[0]
351
-
352
- // If DOB listed
353
- if (dateNode) {
354
- // If born > 100 yrs ago, call dead
355
- if (dateNode.data.slice(-4) < thisYear - 100) {
356
- return '?'
357
- } else {
358
- return 'Present'
359
- }
360
- } else {
361
- return '?'
362
- }
363
-
364
- // no DEAT or BIRT tag
365
- } else {
366
- return '?'
367
- }
368
- }
330
+ let thisYear = new Date().getFullYear();
331
+
332
+ // Find 'DEAT' tag
333
+ let dobNode = (p.tree.filter(hasTag("BIRT")) || [])[0];
334
+ let dodNode = (p.tree.filter(hasTag("DEAT")) || [])[0];
335
+
336
+ // If DEATH tag
337
+ if (dodNode) {
338
+ // Find 'DATE' tag
339
+ let dateNode = (dodNode.tree.filter(hasTag("DATE")) || [])[0];
340
+
341
+ // If death date listed
342
+ if (dateNode) {
343
+ return dateNode.data.slice(-4);
344
+ } else {
345
+ return "?";
346
+ }
347
+
348
+ // BIRT tag, but no DEAT tag
349
+ } else if (dobNode && !dodNode) {
350
+ let dateNode = (dobNode.tree.filter(hasTag("DATE")) || [])[0];
351
+
352
+ // If DOB listed
353
+ if (dateNode) {
354
+ // If born > 100 yrs ago, call dead
355
+ if (dateNode.data.slice(-4) < thisYear - 100) {
356
+ return "?";
357
+ } else {
358
+ return "Present";
359
+ }
360
+ } else {
361
+ return "?";
362
+ }
363
+
364
+ // no DEAT or BIRT tag
365
+ } else {
366
+ return "?";
367
+ }
368
+ };
369
369
 
370
370
  // Get place of birth
371
371
  const getPOD = (p) => {
372
- // Find 'BIRT' tag
373
- let podNode = (p.tree.filter(hasTag('DEAT')) || [])[0]
374
- if (podNode) {
375
- // Find 'DATE' tag
376
- let placeNode = (podNode.tree.filter(hasTag('PLAC')) || [])[0]
377
- if (placeNode) {
378
- return placeNode.data
379
- } else {
380
- return ''
381
- }
382
- } else {
383
- return ''
384
- }
385
- }
372
+ // Find 'BIRT' tag
373
+ let podNode = (p.tree.filter(hasTag("DEAT")) || [])[0];
374
+ if (podNode) {
375
+ // Find 'DATE' tag
376
+ let placeNode = (podNode.tree.filter(hasTag("PLAC")) || [])[0];
377
+ if (placeNode) {
378
+ return placeNode.data;
379
+ } else {
380
+ return "";
381
+ }
382
+ } else {
383
+ return "";
384
+ }
385
+ };
386
386
 
387
387
  // Get relatives
388
388
  const getFamilies = (p) => {
389
- let families = []
390
- let pediInfo
391
- // If child
392
- let familyNode1 = p.tree.filter(hasTag('FAMC')) || []
393
- if (familyNode1) {
394
- for (let i = 0; i < familyNode1.length; i++) {
395
- if (familyNode1[i].tree.length > 0) {
396
- // Get pedigree info
397
- if (familyNode1[i].tree[0].tag == 'PEDI') {
398
- pediInfo = {
399
- frel: familyNode1[i].tree[0].data,
400
- mrel: familyNode1[i].tree[0].data,
401
- }
402
- } else if (familyNode1[i].tree[0].tag == '_FREL') {
403
- pediInfo = {
404
- frel: familyNode1[i].tree[0].data,
405
- mrel: familyNode1[i].tree[1].data,
406
- }
407
- }
408
- }
409
-
410
- families.push({ id: familyNode1[i].data, pedi: pediInfo })
411
- }
412
- }
413
- let familyNode2 = p.tree.filter(hasTag('FAMS')) || []
414
- if (familyNode2) {
415
- for (let i = 0; i < familyNode2.length; i++) {
416
- families.push({ id: familyNode2[i].data })
417
- }
418
- }
419
- return families
420
- }
389
+ let families = [];
390
+ let pediInfo;
391
+ // If child
392
+ let familyNode1 = p.tree.filter(hasTag("FAMC")) || [];
393
+ if (familyNode1) {
394
+ for (let i = 0; i < familyNode1.length; i++) {
395
+ if (familyNode1[i].tree.length > 0) {
396
+ // Get pedigree info
397
+ if (familyNode1[i].tree[0].tag == "PEDI") {
398
+ pediInfo = {
399
+ frel: familyNode1[i].tree[0].data,
400
+ mrel: familyNode1[i].tree[0].data,
401
+ };
402
+ } else if (familyNode1[i].tree[0].tag == "_FREL") {
403
+ pediInfo = {
404
+ frel: familyNode1[i].tree[0].data,
405
+ mrel: familyNode1[i].tree[1].data,
406
+ };
407
+ }
408
+ }
409
+
410
+ families.push({ id: familyNode1[i].data, pedi: pediInfo });
411
+ }
412
+ }
413
+ let familyNode2 = p.tree.filter(hasTag("FAMS")) || [];
414
+ if (familyNode2) {
415
+ for (let i = 0; i < familyNode2.length; i++) {
416
+ families.push({ id: familyNode2[i].data });
417
+ }
418
+ }
419
+ return families;
420
+ };
421
421
 
422
422
  // Get color
423
423
  const getColor = (p, surnameList) => {
424
- const colorList = [
425
- '#ef8a65', // coral
426
- '#00b4ff', // sky blue
427
- '#fac641', // mexican egg yolk
428
- '#c8d84c', // olive
429
- '#e1b386', // light brown
430
- '#a5c2cc', // light blue grey
431
- '#e87c76', // soft pink
432
- '#d0a8ec', // soft royal purple
433
- '#8ad5b2', // grass & sage
434
- '#f8a7d0', // dry wine
435
- '#6e90e6', // ligt purple blue
436
- '#a6e9e6', // sea foam
437
- '#df9ac1', // magenta
438
- '#4ae9bc', // forest
439
- '#e08e79', // blush
440
- '#80d152', // neon green
441
- '#e7c34e', // tangerine
442
- '#7ff0ca', // light sea foam
443
- '#ff835a', // burnt orange
444
- '#eebd6e', // chocolate
445
- '#a6b890', // olive sage
446
- '#c44d58', // rouge
447
- '#e8b28e', // peach
448
- '#d4ee5e', // lime
449
- '#f3f621', // light yellow
450
- '#e887aa', // newborn pink
451
- '#c4a8f6', // royal purple
452
- '#71cfde', // baby foam
453
- '#ccc', // light grey
454
- ]
455
-
456
- // If color description listed in GEDCOM
457
- const dscr = (p.tree.filter(hasTag('DSCR')) || [])[0]
458
-
459
- const foundName = surnameList.find((sName) => sName.surname === p.surname)
460
-
461
- // If surname already in list
462
- if (foundName) {
463
- foundName.count = foundName.count + 1
464
- } else {
465
- surnameList.push({
466
- surname: p.surname,
467
- count: 1,
468
- color: colorList[surnameList.length % colorList.length],
469
- })
470
- }
471
-
472
- // surnameList.color = surnameList.length % colorList.length});
473
-
474
- // If color listed assign that
475
- if (dscr) {
476
- return dscr.data
477
-
478
- // else assign color from colorList
479
- } else {
480
- return surnameList.find((sName) => sName.surname === p.surname).color
481
- }
482
- }
424
+ const colorList = [
425
+ "#f6edd0", // cream
426
+ "#ef8a65", // coral
427
+ "#00b4ff", // sky blue
428
+ "#fac641", // mexican egg yolk
429
+ "#c8d84c", // olive
430
+ "#e1b386", // light brown
431
+ "#a5c2cc", // light blue grey
432
+ "#e87c76", // soft pink
433
+ "#d0a8ec", // soft royal purple
434
+ "#8ad5b2", // grass & sage
435
+ "#f8a7d0", // dry wine
436
+ "#6e90e6", // ligt purple blue
437
+ "#a6e9e6", // sea foam
438
+ "#df9ac1", // magenta
439
+ "#4ae9bc", // forest
440
+ "#e08e79", // blush
441
+ "#80d152", // neon green
442
+ "#e7c34e", // tangerine
443
+ "#7ff0ca", // light sea foam
444
+ "#ff835a", // burnt orange
445
+ "#eebd6e", // chocolate
446
+ "#a6b890", // olive sage
447
+ "#c44d58", // rouge
448
+ "#e8b28e", // peach
449
+ "#d4ee5e", // lime
450
+ "#f3f621", // light yellow
451
+ "#e887aa", // newborn pink
452
+ "#c4a8f6", // royal purple
453
+ "#71cfde", // baby foam
454
+ "#ccc", // light grey
455
+ ];
456
+
457
+ // If color description listed in GEDCOM
458
+ const dscr = (p.tree.filter(hasTag("DSCR")) || [])[0];
459
+
460
+ const foundName = surnameList.find((sName) => sName.surname === p.surname);
461
+
462
+ // If surname already in list
463
+ if (foundName) {
464
+ foundName.count = foundName.count + 1;
465
+ } else {
466
+ surnameList.push({
467
+ surname: p.surname,
468
+ count: 1,
469
+ color: colorList[surnameList.length % colorList.length],
470
+ });
471
+ }
472
+
473
+ // surnameList.color = surnameList.length % colorList.length});
474
+
475
+ // If color listed assign that
476
+ if (dscr) {
477
+ return dscr.data;
478
+
479
+ // else assign color from colorList
480
+ } else {
481
+ return surnameList.find((sName) => sName.surname === p.surname).color;
482
+ }
483
+ };
483
484
 
484
485
  // Get person notes
485
486
  const getNotes = (p) => {
486
- return p.tree.filter(hasTag('NOTE'))
487
- }
487
+ return p.tree.filter(hasTag("NOTE"));
488
+ };
488
489
 
489
490
  // Get Bio
490
491
  const getBio = (p, notes) => {
491
- if (p.notes.length != 0) {
492
- let bio = ''
493
-
494
- // Notes for person
495
- p.notes.forEach((personNote) => {
496
- // personNote.data points to NOTE object
497
- if (notes.length > 0) {
498
- notes.forEach((note) => {
499
- if (personNote.data === note.pointer) {
500
- bio += note.data
501
-
502
- // Concat broken up note
503
- if (note.tree.length > 0) {
504
- note.tree.forEach((fragment) => (bio += fragment.data))
505
- }
506
- }
507
- })
508
-
509
- // personNote.data is actual note
510
- } else {
511
- bio += personNote.data
512
- }
513
- })
514
- return bio
515
- }
516
- }
492
+ if (p.notes.length != 0) {
493
+ let bio = "";
494
+
495
+ // Notes for person
496
+ p.notes.forEach((personNote) => {
497
+ // personNote.data points to NOTE object
498
+ if (notes.length > 0) {
499
+ notes.forEach((note) => {
500
+ if (personNote.data === note.pointer) {
501
+ bio += note.data;
502
+
503
+ // Concat broken up note
504
+ if (note.tree.length > 0) {
505
+ note.tree.forEach((fragment) => (bio += fragment.data));
506
+ }
507
+ }
508
+ });
509
+
510
+ // personNote.data is actual note
511
+ } else {
512
+ bio += personNote.data;
513
+ }
514
+ });
515
+ return bio;
516
+ }
517
+ };
517
518
 
518
519
  const getFy = (p) => {
519
- if (p.yob === '?') {
520
- return 0
521
- } else {
522
- return +(-p.yob * 3 + 6000)
523
- }
524
- }
520
+ if (p.yob === "?") {
521
+ return 0;
522
+ } else {
523
+ return +(-p.yob * 3 + 6000);
524
+ }
525
+ };
525
526
 
526
527
  const toNode = (p, notes, surnameList) => {
527
- p.id = p.pointer
528
- p.title = getTitle(p)
529
- p.name = getName(p)
530
- p.firstName = getFirstName(p)
531
- p.surname = getSurname(p)
532
- p.gender = getGender(p)
533
- p.dob = getDOB(p)
534
- p.yob = getYOB(p)
535
- p.pob = getPOB(p)
536
- p.dod = getDOD(p)
537
- p.yod = getYOD(p)
538
- p.pod = getPOD(p)
539
- p.families = getFamilies(p)
540
- p.color = getColor(p, surnameList)
541
- p.notes = getNotes(p)
542
- p.bio = getBio(p, notes)
543
- return p
544
- }
528
+ p.id = p.pointer;
529
+ p.title = getTitle(p);
530
+ p.name = getName(p);
531
+ p.firstName = getFirstName(p);
532
+ p.surname = getSurname(p);
533
+ p.gender = getGender(p);
534
+ p.dob = getDOB(p);
535
+ p.yob = getYOB(p);
536
+ p.pob = getPOB(p);
537
+ p.dod = getDOD(p);
538
+ p.yod = getYOD(p);
539
+ p.pod = getPOD(p);
540
+ p.families = getFamilies(p);
541
+ p.color = getColor(p, surnameList);
542
+ p.notes = getNotes(p);
543
+ p.bio = getBio(p, notes);
544
+ return p;
545
+ };
545
546
 
546
547
  const familyLinks = (family, peopleNodes) => {
547
- let memberLinks = []
548
- let maritalStatus = null
549
- let pedigree
550
-
551
- // Filter only individual objects from family tree
552
- let memberSet = family.tree.filter(function (member) {
553
- return (
554
- member.tag &&
555
- (member.tag === 'HUSB' || member.tag === 'WIFE' || member.tag === 'CHIL')
556
- )
557
- })
558
-
559
- // Filter marital status events
560
- family.tree.filter((event) => {
561
- if (event.tag === 'DIV' || event.tag === 'MARR') {
562
- if (maritalStatus !== 'DIV') {
563
- maritalStatus = event.tag
564
- }
565
- }
566
- })
567
-
568
- // Iterate over each member of set to connect with other members
569
- while (memberSet.length > 1) {
570
- for (let i = 1; i < memberSet.length; i++) {
571
- // Exclude sibling relationships
572
- if (memberSet[0].tag != 'CHIL') {
573
- // If marital status listed
574
- if (memberSet[0].tag == 'HUSB' && memberSet[i].tag == 'WIFE') {
575
- memberLinks.push({
576
- source: memberSet[0].data,
577
- target: memberSet[i].data,
578
- sourceType: memberSet[0].tag,
579
- targetType: memberSet[i].tag,
580
- type: maritalStatus,
581
- })
582
- } else {
583
- // Filter pedigree info
584
- function getPedigree(personID, parentType, relInfo) {
585
- // GRAMPS
586
- let person = peopleNodes.filter(hasID(personID))
587
- let personFamily = person[0].families.filter(hasID(family.pointer))
588
- if (parentType == 'HUSB') {
589
- if (personFamily[0].pedi) {
590
- return personFamily[0].pedi.frel
591
- } else if (relInfo.some((parent) => parent.tag === '_FREL')) {
592
- return relInfo.find((parent) => parent.tag === '_FREL').data
593
- }
594
- } else {
595
- if (personFamily[0].pedi) {
596
- return personFamily[0].pedi.mrel
597
- } else if (relInfo.some((parent) => parent.tag === '_MREL')) {
598
- return relInfo.find((parent) => parent.tag === '_MREL').data
599
- }
600
- }
601
- }
602
-
603
- memberLinks.push({
604
- source: memberSet[0].data,
605
- target: memberSet[i].data,
606
- sourceType: memberSet[0].tag,
607
- targetType: memberSet[i].tag,
608
- type: getPedigree(
609
- memberSet[i].data,
610
- memberSet[0].tag,
611
- memberSet[i].tree
612
- ),
613
- })
614
- }
615
- }
616
- }
617
- memberSet.splice(0, 1)
618
- }
619
- return memberLinks
620
- }
621
-
622
- module.exports = d3ize
548
+ let memberLinks = [];
549
+ let maritalStatus = null;
550
+ let pedigree;
551
+
552
+ // Filter only individual objects from family tree
553
+ let memberSet = family.tree.filter(function (member) {
554
+ return (
555
+ member.tag &&
556
+ (member.tag === "HUSB" || member.tag === "WIFE" || member.tag === "CHIL")
557
+ );
558
+ });
559
+
560
+ // Filter marital status events
561
+ family.tree.filter((event) => {
562
+ if (event.tag === "DIV" || event.tag === "MARR") {
563
+ if (maritalStatus !== "DIV") {
564
+ maritalStatus = event.tag;
565
+ }
566
+ }
567
+ });
568
+
569
+ // Iterate over each member of set to connect with other members
570
+ while (memberSet.length > 1) {
571
+ for (let i = 1; i < memberSet.length; i++) {
572
+ // Exclude sibling relationships
573
+ if (memberSet[0].tag != "CHIL") {
574
+ // If marital status listed
575
+ if (memberSet[0].tag == "HUSB" && memberSet[i].tag == "WIFE") {
576
+ memberLinks.push({
577
+ source: memberSet[0].data,
578
+ target: memberSet[i].data,
579
+ sourceType: memberSet[0].tag,
580
+ targetType: memberSet[i].tag,
581
+ type: maritalStatus,
582
+ });
583
+ } else {
584
+ // Filter pedigree info
585
+ function getPedigree(personID, parentType, relInfo) {
586
+ // GRAMPS
587
+ let person = peopleNodes.filter(hasID(personID));
588
+ let personFamily = person[0].families.filter(hasID(family.pointer));
589
+ if (parentType == "HUSB") {
590
+ if (personFamily[0].pedi) {
591
+ return personFamily[0].pedi.frel;
592
+ } else if (relInfo.some((parent) => parent.tag === "_FREL")) {
593
+ return relInfo.find((parent) => parent.tag === "_FREL").data;
594
+ }
595
+ } else {
596
+ if (personFamily[0].pedi) {
597
+ return personFamily[0].pedi.mrel;
598
+ } else if (relInfo.some((parent) => parent.tag === "_MREL")) {
599
+ return relInfo.find((parent) => parent.tag === "_MREL").data;
600
+ }
601
+ }
602
+ }
603
+
604
+ memberLinks.push({
605
+ source: memberSet[0].data,
606
+ target: memberSet[i].data,
607
+ sourceType: memberSet[0].tag,
608
+ targetType: memberSet[i].tag,
609
+ type: getPedigree(
610
+ memberSet[i].data,
611
+ memberSet[0].tag,
612
+ memberSet[i].tree,
613
+ ),
614
+ });
615
+ }
616
+ }
617
+ }
618
+ memberSet.splice(0, 1);
619
+ }
620
+ return memberLinks;
621
+ };
622
+
623
+ module.exports = d3ize;
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "gedcom-d3",
3
- "version": "2.0.9",
3
+ "version": "2.3.0",
4
4
  "description": "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",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "publish": "./publish.sh minor"
8
9
  },
9
10
  "keywords": [
10
11
  "gedcom",
package/publish.sh ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Publish a new version of gedcom-d3 to NPM
5
+ # Usage: ./publish.sh [major|minor|patch]
6
+ # Default: patch
7
+
8
+ VERSION_TYPE="${1:-patch}"
9
+
10
+ if [[ "$VERSION_TYPE" != "major" && "$VERSION_TYPE" != "minor" && "$VERSION_TYPE" != "patch" ]]; then
11
+ echo "Usage: ./publish.sh [major|minor|patch]"
12
+ exit 1
13
+ fi
14
+
15
+ # Ensure working directory is clean
16
+ if [[ -n "$(git status --porcelain)" ]]; then
17
+ echo "Error: Working directory is not clean. Commit or stash changes first."
18
+ exit 1
19
+ fi
20
+
21
+ # Ensure we're on master
22
+ BRANCH="$(git rev-parse --abbrev-ref HEAD)"
23
+ if [[ "$BRANCH" != "master" ]]; then
24
+ echo "Error: Must be on master branch to publish. Currently on '$BRANCH'."
25
+ exit 1
26
+ fi
27
+
28
+ # Ensure we're up to date with remote
29
+ git fetch origin master
30
+ LOCAL="$(git rev-parse master)"
31
+ REMOTE="$(git rev-parse origin/master)"
32
+ if [[ "$LOCAL" != "$REMOTE" ]]; then
33
+ echo "Error: Local master is not up to date with origin. Pull or push first."
34
+ exit 1
35
+ fi
36
+
37
+ # Bump version (this updates package.json and creates a git tag)
38
+ echo "Bumping $VERSION_TYPE version..."
39
+ npm version "$VERSION_TYPE" -m "v%s"
40
+
41
+ # Push commit and tag
42
+ echo "Pushing to origin..."
43
+ git push origin master --tags
44
+
45
+ # Publish to NPM
46
+ echo "Publishing to NPM..."
47
+ npm publish
48
+
49
+ NEW_VERSION="$(node -p "require('./package.json').version")"
50
+ echo "Successfully published gedcom-d3@$NEW_VERSION"