@treeviz/gedcom-parser 1.0.1

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.
Files changed (321) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +954 -0
  3. package/dist/classes/common.d.ts +87 -0
  4. package/dist/classes/common.d.ts.map +1 -0
  5. package/dist/classes/common.js +481 -0
  6. package/dist/classes/date.d.ts +26 -0
  7. package/dist/classes/date.d.ts.map +1 -0
  8. package/dist/classes/date.js +176 -0
  9. package/dist/classes/fam.d.ts +19 -0
  10. package/dist/classes/fam.d.ts.map +1 -0
  11. package/dist/classes/fam.js +38 -0
  12. package/dist/classes/fams.d.ts +16 -0
  13. package/dist/classes/fams.d.ts.map +1 -0
  14. package/dist/classes/fams.js +41 -0
  15. package/dist/classes/gedcom.d.ts +89 -0
  16. package/dist/classes/gedcom.d.ts.map +1 -0
  17. package/dist/classes/gedcom.js +421 -0
  18. package/dist/classes/index.d.ts +19 -0
  19. package/dist/classes/index.d.ts.map +1 -0
  20. package/dist/classes/index.js +19 -0
  21. package/dist/classes/indi.d.ts +298 -0
  22. package/dist/classes/indi.d.ts.map +1 -0
  23. package/dist/classes/indi.js +2049 -0
  24. package/dist/classes/indis.d.ts +54 -0
  25. package/dist/classes/indis.d.ts.map +1 -0
  26. package/dist/classes/indis.js +439 -0
  27. package/dist/classes/list.d.ts +55 -0
  28. package/dist/classes/list.d.ts.map +1 -0
  29. package/dist/classes/list.js +440 -0
  30. package/dist/classes/name.d.ts +20 -0
  31. package/dist/classes/name.d.ts.map +1 -0
  32. package/dist/classes/name.js +48 -0
  33. package/dist/classes/note.d.ts +12 -0
  34. package/dist/classes/note.d.ts.map +1 -0
  35. package/dist/classes/note.js +46 -0
  36. package/dist/classes/obje.d.ts +12 -0
  37. package/dist/classes/obje.d.ts.map +1 -0
  38. package/dist/classes/obje.js +81 -0
  39. package/dist/classes/objes.d.ts +8 -0
  40. package/dist/classes/objes.d.ts.map +1 -0
  41. package/dist/classes/objes.js +13 -0
  42. package/dist/classes/repo.d.ts +11 -0
  43. package/dist/classes/repo.d.ts.map +1 -0
  44. package/dist/classes/repo.js +6 -0
  45. package/dist/classes/repos.d.ts +8 -0
  46. package/dist/classes/repos.d.ts.map +1 -0
  47. package/dist/classes/repos.js +13 -0
  48. package/dist/classes/sour.d.ts +11 -0
  49. package/dist/classes/sour.d.ts.map +1 -0
  50. package/dist/classes/sour.js +6 -0
  51. package/dist/classes/sours.d.ts +8 -0
  52. package/dist/classes/sours.d.ts.map +1 -0
  53. package/dist/classes/sours.js +13 -0
  54. package/dist/classes/subm.d.ts +10 -0
  55. package/dist/classes/subm.d.ts.map +1 -0
  56. package/dist/classes/subm.js +6 -0
  57. package/dist/classes/subms.d.ts +8 -0
  58. package/dist/classes/subms.d.ts.map +1 -0
  59. package/dist/classes/subms.js +13 -0
  60. package/dist/constants/constants.d.ts +14 -0
  61. package/dist/constants/constants.d.ts.map +1 -0
  62. package/dist/constants/constants.js +13 -0
  63. package/dist/constants/filters.d.ts +17 -0
  64. package/dist/constants/filters.d.ts.map +1 -0
  65. package/dist/constants/filters.js +44 -0
  66. package/dist/constants/index.d.ts +4 -0
  67. package/dist/constants/index.d.ts.map +1 -0
  68. package/dist/constants/index.js +4 -0
  69. package/dist/constants/orders.d.ts +17 -0
  70. package/dist/constants/orders.d.ts.map +1 -0
  71. package/dist/constants/orders.js +240 -0
  72. package/dist/factories/cache-factory.d.ts +30 -0
  73. package/dist/factories/cache-factory.d.ts.map +1 -0
  74. package/dist/factories/cache-factory.js +43 -0
  75. package/dist/factories/date-locale-factory.d.ts +30 -0
  76. package/dist/factories/date-locale-factory.d.ts.map +1 -0
  77. package/dist/factories/date-locale-factory.js +34 -0
  78. package/dist/factories/i18n-factory.d.ts +40 -0
  79. package/dist/factories/i18n-factory.d.ts.map +1 -0
  80. package/dist/factories/i18n-factory.js +44 -0
  81. package/dist/factories/index.d.ts +5 -0
  82. package/dist/factories/index.d.ts.map +1 -0
  83. package/dist/factories/index.js +5 -0
  84. package/dist/factories/kinship-factory.d.ts +38 -0
  85. package/dist/factories/kinship-factory.d.ts.map +1 -0
  86. package/dist/factories/kinship-factory.js +35 -0
  87. package/dist/factories/place-parser-provider.d.ts +32 -0
  88. package/dist/factories/place-parser-provider.d.ts.map +1 -0
  89. package/dist/factories/place-parser-provider.js +35 -0
  90. package/dist/factories/place-translator-provider.d.ts +32 -0
  91. package/dist/factories/place-translator-provider.d.ts.map +1 -0
  92. package/dist/factories/place-translator-provider.js +35 -0
  93. package/dist/index.d.ts +78 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +44 -0
  96. package/dist/interfaces/common.d.ts +43 -0
  97. package/dist/interfaces/common.d.ts.map +1 -0
  98. package/dist/interfaces/common.js +1 -0
  99. package/dist/interfaces/fam.d.ts +11 -0
  100. package/dist/interfaces/fam.d.ts.map +1 -0
  101. package/dist/interfaces/fam.js +1 -0
  102. package/dist/interfaces/fams.d.ts +9 -0
  103. package/dist/interfaces/fams.d.ts.map +1 -0
  104. package/dist/interfaces/fams.js +1 -0
  105. package/dist/interfaces/gedcom.d.ts +30 -0
  106. package/dist/interfaces/gedcom.d.ts.map +1 -0
  107. package/dist/interfaces/gedcom.js +1 -0
  108. package/dist/interfaces/index.d.ts +12 -0
  109. package/dist/interfaces/index.d.ts.map +1 -0
  110. package/dist/interfaces/index.js +1 -0
  111. package/dist/interfaces/indi.d.ts +109 -0
  112. package/dist/interfaces/indi.d.ts.map +1 -0
  113. package/dist/interfaces/indi.js +1 -0
  114. package/dist/interfaces/indis.d.ts +31 -0
  115. package/dist/interfaces/indis.d.ts.map +1 -0
  116. package/dist/interfaces/indis.js +1 -0
  117. package/dist/interfaces/list.d.ts +52 -0
  118. package/dist/interfaces/list.d.ts.map +1 -0
  119. package/dist/interfaces/list.js +1 -0
  120. package/dist/interfaces/obje.d.ts +7 -0
  121. package/dist/interfaces/obje.d.ts.map +1 -0
  122. package/dist/interfaces/obje.js +1 -0
  123. package/dist/interfaces/repo.d.ts +7 -0
  124. package/dist/interfaces/repo.d.ts.map +1 -0
  125. package/dist/interfaces/repo.js +1 -0
  126. package/dist/interfaces/sour.d.ts +7 -0
  127. package/dist/interfaces/sour.d.ts.map +1 -0
  128. package/dist/interfaces/sour.js +1 -0
  129. package/dist/interfaces/subm.d.ts +6 -0
  130. package/dist/interfaces/subm.d.ts.map +1 -0
  131. package/dist/interfaces/subm.js +1 -0
  132. package/dist/kinship-translator/index.d.ts +11 -0
  133. package/dist/kinship-translator/index.d.ts.map +1 -0
  134. package/dist/kinship-translator/index.js +10 -0
  135. package/dist/kinship-translator/kinship-translator.basic.d.ts +30 -0
  136. package/dist/kinship-translator/kinship-translator.basic.d.ts.map +1 -0
  137. package/dist/kinship-translator/kinship-translator.basic.js +74 -0
  138. package/dist/kinship-translator/kinship-translator.d.ts +26 -0
  139. package/dist/kinship-translator/kinship-translator.d.ts.map +1 -0
  140. package/dist/kinship-translator/kinship-translator.de.d.ts +18 -0
  141. package/dist/kinship-translator/kinship-translator.de.d.ts.map +1 -0
  142. package/dist/kinship-translator/kinship-translator.de.js +180 -0
  143. package/dist/kinship-translator/kinship-translator.en.d.ts +18 -0
  144. package/dist/kinship-translator/kinship-translator.en.d.ts.map +1 -0
  145. package/dist/kinship-translator/kinship-translator.en.js +182 -0
  146. package/dist/kinship-translator/kinship-translator.es.d.ts +18 -0
  147. package/dist/kinship-translator/kinship-translator.es.d.ts.map +1 -0
  148. package/dist/kinship-translator/kinship-translator.es.js +181 -0
  149. package/dist/kinship-translator/kinship-translator.fr.d.ts +18 -0
  150. package/dist/kinship-translator/kinship-translator.fr.d.ts.map +1 -0
  151. package/dist/kinship-translator/kinship-translator.fr.js +181 -0
  152. package/dist/kinship-translator/kinship-translator.hu.d.ts +19 -0
  153. package/dist/kinship-translator/kinship-translator.hu.d.ts.map +1 -0
  154. package/dist/kinship-translator/kinship-translator.hu.js +226 -0
  155. package/dist/kinship-translator/kinship-translator.interface.d.ts +19 -0
  156. package/dist/kinship-translator/kinship-translator.interface.d.ts.map +1 -0
  157. package/dist/kinship-translator/kinship-translator.interface.js +1 -0
  158. package/dist/kinship-translator/kinship-translator.js +103 -0
  159. package/dist/kinship-translator/patterns.de.d.ts +2 -0
  160. package/dist/kinship-translator/patterns.de.d.ts.map +1 -0
  161. package/dist/kinship-translator/patterns.de.js +14 -0
  162. package/dist/kinship-translator/patterns.en.d.ts +2 -0
  163. package/dist/kinship-translator/patterns.en.d.ts.map +1 -0
  164. package/dist/kinship-translator/patterns.en.js +14 -0
  165. package/dist/kinship-translator/patterns.es.d.ts +2 -0
  166. package/dist/kinship-translator/patterns.es.d.ts.map +1 -0
  167. package/dist/kinship-translator/patterns.es.js +14 -0
  168. package/dist/kinship-translator/patterns.fr.d.ts +2 -0
  169. package/dist/kinship-translator/patterns.fr.d.ts.map +1 -0
  170. package/dist/kinship-translator/patterns.fr.js +14 -0
  171. package/dist/kinship-translator/patterns.hu.d.ts +6 -0
  172. package/dist/kinship-translator/patterns.hu.d.ts.map +1 -0
  173. package/dist/kinship-translator/patterns.hu.js +97 -0
  174. package/dist/kinship-translator/translators.d.ts +6 -0
  175. package/dist/kinship-translator/translators.d.ts.map +1 -0
  176. package/dist/kinship-translator/translators.js +5 -0
  177. package/dist/kinship-translator/types.d.ts +9 -0
  178. package/dist/kinship-translator/types.d.ts.map +1 -0
  179. package/dist/kinship-translator/types.js +1 -0
  180. package/dist/structures/address.d.ts +14 -0
  181. package/dist/structures/address.d.ts.map +1 -0
  182. package/dist/structures/address.js +1 -0
  183. package/dist/structures/association.d.ts +13 -0
  184. package/dist/structures/association.d.ts.map +1 -0
  185. package/dist/structures/association.js +1 -0
  186. package/dist/structures/change-date.d.ts +8 -0
  187. package/dist/structures/change-date.d.ts.map +1 -0
  188. package/dist/structures/change-date.js +1 -0
  189. package/dist/structures/creation-date.d.ts +7 -0
  190. package/dist/structures/creation-date.d.ts.map +1 -0
  191. package/dist/structures/creation-date.js +1 -0
  192. package/dist/structures/date.d.ts +9 -0
  193. package/dist/structures/date.d.ts.map +1 -0
  194. package/dist/structures/date.js +1 -0
  195. package/dist/structures/event-detail-structure.d.ts +25 -0
  196. package/dist/structures/event-detail-structure.d.ts.map +1 -0
  197. package/dist/structures/event-detail-structure.js +1 -0
  198. package/dist/structures/family.d.ts +34 -0
  199. package/dist/structures/family.d.ts.map +1 -0
  200. package/dist/structures/family.js +1 -0
  201. package/dist/structures/gedcom.d.ts +60 -0
  202. package/dist/structures/gedcom.d.ts.map +1 -0
  203. package/dist/structures/gedcom.js +1 -0
  204. package/dist/structures/index.d.ts +25 -0
  205. package/dist/structures/index.d.ts.map +1 -0
  206. package/dist/structures/index.js +1 -0
  207. package/dist/structures/individual-event-detail-structure.d.ts +9 -0
  208. package/dist/structures/individual-event-detail-structure.d.ts.map +1 -0
  209. package/dist/structures/individual-event-detail-structure.js +1 -0
  210. package/dist/structures/individual-event-structure.d.ts +83 -0
  211. package/dist/structures/individual-event-structure.d.ts.map +1 -0
  212. package/dist/structures/individual-event-structure.js +1 -0
  213. package/dist/structures/individual.d.ts +40 -0
  214. package/dist/structures/individual.d.ts.map +1 -0
  215. package/dist/structures/individual.js +1 -0
  216. package/dist/structures/lds-ordinance-detail.d.ts +17 -0
  217. package/dist/structures/lds-ordinance-detail.d.ts.map +1 -0
  218. package/dist/structures/lds-ordinance-detail.js +1 -0
  219. package/dist/structures/lds-spouse-sealing.d.ts +7 -0
  220. package/dist/structures/lds-spouse-sealing.d.ts.map +1 -0
  221. package/dist/structures/lds-spouse-sealing.js +1 -0
  222. package/dist/structures/marriage-date.d.ts +11 -0
  223. package/dist/structures/marriage-date.d.ts.map +1 -0
  224. package/dist/structures/marriage-date.js +1 -0
  225. package/dist/structures/multimedia-link.d.ts +16 -0
  226. package/dist/structures/multimedia-link.d.ts.map +1 -0
  227. package/dist/structures/multimedia-link.js +1 -0
  228. package/dist/structures/non-event.d.ts +12 -0
  229. package/dist/structures/non-event.d.ts.map +1 -0
  230. package/dist/structures/non-event.js +1 -0
  231. package/dist/structures/note.d.ts +16 -0
  232. package/dist/structures/note.d.ts.map +1 -0
  233. package/dist/structures/note.js +1 -0
  234. package/dist/structures/personal-name-pieces.d.ts +11 -0
  235. package/dist/structures/personal-name-pieces.d.ts.map +1 -0
  236. package/dist/structures/personal-name-pieces.js +1 -0
  237. package/dist/structures/personal-name.d.ts +16 -0
  238. package/dist/structures/personal-name.d.ts.map +1 -0
  239. package/dist/structures/personal-name.js +1 -0
  240. package/dist/structures/place.d.ts +20 -0
  241. package/dist/structures/place.d.ts.map +1 -0
  242. package/dist/structures/place.js +1 -0
  243. package/dist/structures/repository.d.ts +6 -0
  244. package/dist/structures/repository.d.ts.map +1 -0
  245. package/dist/structures/repository.js +1 -0
  246. package/dist/structures/source-citation.d.ts +27 -0
  247. package/dist/structures/source-citation.d.ts.map +1 -0
  248. package/dist/structures/source-citation.js +1 -0
  249. package/dist/structures/source-repository-citation.d.ts +13 -0
  250. package/dist/structures/source-repository-citation.d.ts.map +1 -0
  251. package/dist/structures/source-repository-citation.js +1 -0
  252. package/dist/structures/source.d.ts +28 -0
  253. package/dist/structures/source.d.ts.map +1 -0
  254. package/dist/structures/source.js +1 -0
  255. package/dist/types/ancestry-media.d.ts +65 -0
  256. package/dist/types/ancestry-media.d.ts.map +1 -0
  257. package/dist/types/ancestry-media.js +1 -0
  258. package/dist/types/index.d.ts +4 -0
  259. package/dist/types/index.d.ts.map +1 -0
  260. package/dist/types/index.js +4 -0
  261. package/dist/types/settings.d.ts +12 -0
  262. package/dist/types/settings.d.ts.map +1 -0
  263. package/dist/types/settings.js +1 -0
  264. package/dist/types/types.d.ts +220 -0
  265. package/dist/types/types.d.ts.map +1 -0
  266. package/dist/types/types.js +26 -0
  267. package/dist/utils/cache.d.ts +22 -0
  268. package/dist/utils/cache.d.ts.map +1 -0
  269. package/dist/utils/cache.js +57 -0
  270. package/dist/utils/common-creator.d.ts +13 -0
  271. package/dist/utils/common-creator.d.ts.map +1 -0
  272. package/dist/utils/common-creator.js +72 -0
  273. package/dist/utils/date-formatter.d.ts +35 -0
  274. package/dist/utils/date-formatter.d.ts.map +1 -0
  275. package/dist/utils/date-formatter.js +207 -0
  276. package/dist/utils/get-all-prop.d.ts +4 -0
  277. package/dist/utils/get-all-prop.d.ts.map +1 -0
  278. package/dist/utils/get-all-prop.js +5 -0
  279. package/dist/utils/get-family-with.d.ts +5 -0
  280. package/dist/utils/get-family-with.d.ts.map +1 -0
  281. package/dist/utils/get-family-with.js +11 -0
  282. package/dist/utils/get-places.d.ts +21 -0
  283. package/dist/utils/get-places.d.ts.map +1 -0
  284. package/dist/utils/get-places.js +77 -0
  285. package/dist/utils/get-product-details.d.ts +4 -0
  286. package/dist/utils/get-product-details.d.ts.map +1 -0
  287. package/dist/utils/get-product-details.js +6 -0
  288. package/dist/utils/get-raw-size.d.ts +2 -0
  289. package/dist/utils/get-raw-size.d.ts.map +1 -0
  290. package/dist/utils/get-raw-size.js +3 -0
  291. package/dist/utils/index.d.ts +17 -0
  292. package/dist/utils/index.d.ts.map +1 -0
  293. package/dist/utils/index.js +18 -0
  294. package/dist/utils/logger.d.ts +3 -0
  295. package/dist/utils/logger.d.ts.map +1 -0
  296. package/dist/utils/logger.js +11 -0
  297. package/dist/utils/name-formatter.d.ts +10 -0
  298. package/dist/utils/name-formatter.d.ts.map +1 -0
  299. package/dist/utils/name-formatter.js +45 -0
  300. package/dist/utils/nested-group.d.ts +4 -0
  301. package/dist/utils/nested-group.d.ts.map +1 -0
  302. package/dist/utils/nested-group.js +34 -0
  303. package/dist/utils/ordinalize.d.ts +3 -0
  304. package/dist/utils/ordinalize.d.ts.map +1 -0
  305. package/dist/utils/ordinalize.js +104 -0
  306. package/dist/utils/parser.d.ts +17 -0
  307. package/dist/utils/parser.d.ts.map +1 -0
  308. package/dist/utils/parser.js +322 -0
  309. package/dist/utils/place-parser.d.ts +16 -0
  310. package/dist/utils/place-parser.d.ts.map +1 -0
  311. package/dist/utils/place-parser.js +46 -0
  312. package/dist/utils/place-translator.d.ts +6 -0
  313. package/dist/utils/place-translator.d.ts.map +1 -0
  314. package/dist/utils/place-translator.js +8 -0
  315. package/dist/utils/place-types.d.ts +27 -0
  316. package/dist/utils/place-types.d.ts.map +1 -0
  317. package/dist/utils/place-types.js +14 -0
  318. package/dist/utils/range.d.ts +19 -0
  319. package/dist/utils/range.d.ts.map +1 -0
  320. package/dist/utils/range.js +265 -0
  321. package/package.json +153 -0
@@ -0,0 +1,2049 @@
1
+ import * as Filters from "../constants/filters";
2
+ import { BIRTH_ASC, DATE_ASC, getMarriageAscAndChildBirth, } from "../constants/orders";
3
+ import { getKinshipTranslatorClass } from "../factories/kinship-factory";
4
+ import { RelationType, PartnerType } from "../types/types";
5
+ import { pathCache, relativesCache } from "../utils/cache";
6
+ import { dateFormatter } from "../utils/date-formatter";
7
+ import { PlaceType, getPlaces } from "../utils/get-places";
8
+ import { implemented } from "../utils/logger";
9
+ import { Common, createCommon, createProxy } from "./common";
10
+ import { Families } from "./fams";
11
+ import { Individuals } from "./indis";
12
+ import { List } from "./list";
13
+ import { CommonName, createCommonName } from "./name";
14
+ export var Existed;
15
+ (function (Existed) {
16
+ Existed["SPOUSE"] = "spouse";
17
+ Existed["YES"] = "yes";
18
+ })(Existed || (Existed = {}));
19
+ export var CustomTags;
20
+ (function (CustomTags) {
21
+ CustomTags["UnknownGivenname"] = "Unknown givenname";
22
+ CustomTags["UnknownSurname"] = "Unknown surname";
23
+ CustomTags["UnattachedMember"] = "Unattached member";
24
+ CustomTags["IgnoredMember"] = "Ignored member";
25
+ CustomTags["UnknownAncestor"] = "Unknown Ancestor";
26
+ })(CustomTags || (CustomTags = {}));
27
+ const ALLOWED_FACTS = [
28
+ "EVEN",
29
+ "OCCU",
30
+ "OCCUPATIONS",
31
+ "RESI",
32
+ "BAPT",
33
+ "CHRI",
34
+ "CHR",
35
+ "BURI",
36
+ "EDUC",
37
+ "GRAD",
38
+ "DIV",
39
+ "IMMI",
40
+ "RELI",
41
+ "_MILT",
42
+ "_MILTID",
43
+ "FACT",
44
+ "_ORIG",
45
+ ];
46
+ const DISALLOWED_CUSTOM_FACTS = ["DNA Test", "Newspaper"];
47
+ const CustomFactRenderers = {
48
+ AKA: (label, fact, indi) => {
49
+ const originalNameObj = indi?.NAME;
50
+ const note = fact.get("NOTE");
51
+ const factName = note?.toValue();
52
+ const name = createCommonName(fact.getGedcom(), undefined, indi);
53
+ const suffix = originalNameObj?.NSFX?.toValue();
54
+ const surname = originalNameObj?.SURN?.toValue();
55
+ const givenname = originalNameObj?.GIVN?.toValue();
56
+ const nameParts = [
57
+ ...(givenname
58
+ ?.split(" ")
59
+ .map((s) => ({ name: s, givenname: true })) ?? []),
60
+ ...(surname?.split(" ").map((s) => ({ name: s, surname: true })) ??
61
+ []),
62
+ ...(suffix?.split(" ").map((s) => ({ name: s, suffix: true })) ??
63
+ []),
64
+ ].filter(Boolean);
65
+ const factParts = factName?.split(" ");
66
+ if (nameParts.length === factParts?.length &&
67
+ !(note instanceof CommonName)) {
68
+ const guessedSuffix = [];
69
+ const guessedSurname = [];
70
+ const guessedGivenname = [];
71
+ factParts.forEach((f, i) => {
72
+ const namePart = nameParts[i];
73
+ if (!f) {
74
+ return;
75
+ }
76
+ if (namePart.suffix) {
77
+ guessedSuffix.push(f);
78
+ }
79
+ else if (namePart.givenname) {
80
+ guessedGivenname.push(f);
81
+ }
82
+ else if (namePart.surname) {
83
+ guessedSurname.push(f);
84
+ }
85
+ });
86
+ const allNamePart = [];
87
+ if (guessedGivenname.length) {
88
+ allNamePart.push(guessedGivenname.join(" "));
89
+ }
90
+ if (guessedSurname.length) {
91
+ allNamePart.push(`/${guessedSurname.join(" ")}/`);
92
+ }
93
+ if (guessedSuffix.length) {
94
+ allNamePart.push(guessedSuffix.join(" "));
95
+ }
96
+ name.value = allNamePart.join(" ");
97
+ }
98
+ else {
99
+ name.value = factName;
100
+ }
101
+ fact.set("NOTE", name);
102
+ label.value = "AKA";
103
+ fact.set("_LABEL", label);
104
+ },
105
+ };
106
+ const relativesOnLevelCache = relativesCache("relativesOnLevelCache");
107
+ const relativesOnDegreeCache = relativesCache("relativesOnDegreeCache");
108
+ export class Indi extends Common {
109
+ toName() {
110
+ return this.get("NAME")?.toValue();
111
+ }
112
+ toNaturalName() {
113
+ return this.get("NAME")?.toValue()?.replaceAll("/", "");
114
+ }
115
+ toList() {
116
+ return new Individuals().concat(
117
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
+ this.id ? { [this.id]: this } : { ...[this] });
119
+ }
120
+ generateTree(props) {
121
+ const { generations, level, index, showDescendants, offspringSpouses, ancestorSpouses, onlyDescendants, maxLevel, minLevel, drawNonBiologicalAncestors, ancestorSiblings, } = props;
122
+ if (!this.id) {
123
+ throw new Error("Indi must have an id");
124
+ }
125
+ const isMainDescendantLevel = showDescendants && level <= 1;
126
+ const isDescendantLevel = showDescendants && level < 1;
127
+ if (level < 1 && !isDescendantLevel) {
128
+ throw new Error("Arguments 2 must be greater than 0.");
129
+ }
130
+ if ((maxLevel !== undefined && maxLevel < level) ||
131
+ (minLevel !== undefined && minLevel > level)) {
132
+ return this;
133
+ }
134
+ // Only for debug
135
+ // if (level > 3) {
136
+ // return this;
137
+ // }
138
+ const gens = generations ?? {
139
+ existed: {},
140
+ tree: {},
141
+ halves: {},
142
+ lastItems: {},
143
+ };
144
+ const families = this.getFamiliesBiologicalFirst("FAMC");
145
+ const familiesAllMember = families.getParents();
146
+ families.forEach((fam, famKey, famIndex) => {
147
+ if (!this.id) {
148
+ return;
149
+ }
150
+ const id = fam.id;
151
+ let father = isDescendantLevel
152
+ ? undefined
153
+ : fam.getHusband().index(0);
154
+ let mother = isDescendantLevel ? undefined : fam.getWife().index(0);
155
+ const children = isMainDescendantLevel && famIndex > 0
156
+ ? this.getChildren()
157
+ : undefined;
158
+ if (father?.id &&
159
+ (gens.existed[father.id] === Existed.YES ||
160
+ (!drawNonBiologicalAncestors &&
161
+ this.getParentType(father.id) !==
162
+ RelationType.BIOLOGICAL))) {
163
+ // console.info(
164
+ // "Father already in tree",
165
+ // father.toName(),
166
+ // father,
167
+ // gens.existed[father.id]
168
+ // );
169
+ father = undefined;
170
+ }
171
+ if (mother?.id &&
172
+ (gens.existed[mother.id] === Existed.YES ||
173
+ (!drawNonBiologicalAncestors &&
174
+ this.getParentType(mother.id) !==
175
+ RelationType.BIOLOGICAL))) {
176
+ // console.info(
177
+ // "Mother already in tree",
178
+ // mother.toName(),
179
+ // mother,
180
+ // gens.existed[mother.id]
181
+ // );
182
+ mother = undefined;
183
+ }
184
+ if (!id &&
185
+ !father &&
186
+ !mother &&
187
+ (!children?.length || famIndex > 0)) {
188
+ return this;
189
+ }
190
+ let fatherSpouses;
191
+ if (father && ancestorSpouses) {
192
+ fatherSpouses = father
193
+ .getCoParents()
194
+ .orderBy(getMarriageAscAndChildBirth(father.id));
195
+ if (drawNonBiologicalAncestors) {
196
+ fatherSpouses = fatherSpouses
197
+ .copy()
198
+ .exclude(familiesAllMember);
199
+ }
200
+ if (mother) {
201
+ fatherSpouses = fatherSpouses.except(mother);
202
+ }
203
+ }
204
+ let motherSpouses;
205
+ if (mother && ancestorSpouses) {
206
+ motherSpouses = mother
207
+ .getCoParents()
208
+ .orderBy(getMarriageAscAndChildBirth(mother.id));
209
+ if (drawNonBiologicalAncestors) {
210
+ motherSpouses = motherSpouses
211
+ .copy()
212
+ .exclude(familiesAllMember);
213
+ }
214
+ if (father) {
215
+ motherSpouses = motherSpouses.except(father);
216
+ }
217
+ }
218
+ let childIndex = 0;
219
+ const amount = Math.pow(2, level - 1);
220
+ const half = Math.floor(amount / 2);
221
+ const closers = {
222
+ id: id || this.id,
223
+ index,
224
+ father: isDescendantLevel
225
+ ? this.isMale()
226
+ ? this
227
+ : undefined
228
+ : onlyDescendants
229
+ ? undefined
230
+ : father?.generateTree({
231
+ generations: gens,
232
+ level: level + 1,
233
+ famIndex: famIndex * 2,
234
+ index: index * 2,
235
+ ancestorSpouses,
236
+ ancestorSiblings,
237
+ maxLevel,
238
+ minLevel,
239
+ drawNonBiologicalAncestors,
240
+ }),
241
+ fatherSpouses: fatherSpouses &&
242
+ (fatherSpouses.values() ?? []),
243
+ mother: isDescendantLevel
244
+ ? this.isFemale()
245
+ ? this
246
+ : undefined
247
+ : onlyDescendants
248
+ ? undefined
249
+ : mother?.generateTree({
250
+ generations: gens,
251
+ level: level + 1,
252
+ famIndex: famIndex * 2,
253
+ index: index * 2 + (famIndex > 0 ? 0 : 1),
254
+ ancestorSpouses,
255
+ ancestorSiblings,
256
+ maxLevel,
257
+ minLevel,
258
+ drawNonBiologicalAncestors,
259
+ }),
260
+ motherSpouses: motherSpouses &&
261
+ (motherSpouses.values() ?? []),
262
+ children: children
263
+ ?.map((descendant) => {
264
+ const descendantTree = descendant.generateTree({
265
+ generations: gens,
266
+ level: level === 1 ? -1 : level - 1,
267
+ famIndex: 0,
268
+ index: childIndex++,
269
+ showDescendants: true,
270
+ offspringSpouses,
271
+ maxLevel,
272
+ minLevel,
273
+ });
274
+ if (offspringSpouses) {
275
+ const spousesTrees = descendant
276
+ .getCoParents()
277
+ .orderBy(getMarriageAscAndChildBirth(descendant.id))
278
+ .map((spouse) => {
279
+ return spouse.generateTree({
280
+ generations: gens,
281
+ level: level === 1 ? -1 : level - 1,
282
+ famIndex: 0,
283
+ index: childIndex++,
284
+ showDescendants: true,
285
+ offspringSpouses,
286
+ maxLevel,
287
+ minLevel,
288
+ });
289
+ });
290
+ return [descendantTree, ...spousesTrees];
291
+ }
292
+ return [descendantTree];
293
+ })
294
+ .flat(),
295
+ };
296
+ if (!gens.tree[level]) {
297
+ gens.tree[level] = [];
298
+ }
299
+ if (level < 0) {
300
+ gens.tree[level].push(closers);
301
+ }
302
+ else {
303
+ if (index >= half && gens.halves[level] === undefined) {
304
+ gens.halves[level] = gens.tree[level].length;
305
+ }
306
+ gens.tree[level].push(closers);
307
+ gens.lastItems[level] = closers;
308
+ }
309
+ if (father?.id) {
310
+ gens.existed[father.id] = Existed.YES;
311
+ }
312
+ if (mother?.id) {
313
+ gens.existed[mother.id] = Existed.YES;
314
+ }
315
+ closers.children?.forEach(({ id }) => {
316
+ if (id) {
317
+ gens.existed[id] = Existed.YES;
318
+ }
319
+ });
320
+ [
321
+ ...(closers.fatherSpouses ?? []),
322
+ ...(closers.motherSpouses ?? []),
323
+ ]?.forEach(({ id }) => {
324
+ if (id) {
325
+ gens.existed[id] = Existed.SPOUSE;
326
+ }
327
+ });
328
+ });
329
+ return this;
330
+ }
331
+ getPlaces(type = [PlaceType.All], maxLevel = 1) {
332
+ if (!this._gedcom || !this.id) {
333
+ return [];
334
+ }
335
+ const cacheKey = JSON.stringify(type);
336
+ if (this._places?.[cacheKey]) {
337
+ return this._places[cacheKey];
338
+ }
339
+ let marriages;
340
+ if (type?.includes(PlaceType.Marriage) ||
341
+ type?.includes(PlaceType.All)) {
342
+ const families = this.getFamilies("FAMS");
343
+ // if (families.length === 1) {
344
+ // marriages = families.index(0);
345
+ // } else
346
+ if (families.length >= 1) {
347
+ marriages = new List();
348
+ families.forEach((fam) => {
349
+ if (fam.MARR) {
350
+ const newMarr = createCommon(this._gedcom, undefined, this);
351
+ Object.assign(newMarr, fam.MARR);
352
+ newMarr.id = fam.id;
353
+ marriages.append(newMarr);
354
+ }
355
+ });
356
+ }
357
+ }
358
+ let usedIndi;
359
+ // let usedMaxLevel = maxLevel;
360
+ if (marriages) {
361
+ usedIndi = createIndi(this._gedcom, this.id);
362
+ Object.assign(usedIndi, this, {
363
+ MARR: marriages,
364
+ });
365
+ // usedMaxLevel = usedMaxLevel === 1 ? 2 : usedMaxLevel;
366
+ }
367
+ const places = getPlaces(usedIndi || this, type, maxLevel);
368
+ return places;
369
+ }
370
+ getTree(props) {
371
+ const { descendants, offspringSpouses, ancestorSpouses, onlyDescendants, maxGen, minGen, drawNonBiologicalAncestors, ancestorSiblings, } = props ?? {};
372
+ const newGenerations = {
373
+ existed: {},
374
+ tree: {},
375
+ halves: {},
376
+ lastItems: {},
377
+ };
378
+ this.generateTree({
379
+ generations: newGenerations,
380
+ level: 1,
381
+ famIndex: 0,
382
+ index: 0,
383
+ showDescendants: descendants,
384
+ offspringSpouses,
385
+ ancestorSpouses,
386
+ onlyDescendants,
387
+ maxLevel: maxGen,
388
+ minLevel: minGen,
389
+ drawNonBiologicalAncestors,
390
+ ancestorSiblings,
391
+ });
392
+ return Object.keys(newGenerations.tree)
393
+ .toSorted((a, b) => Number(a) - Number(b))
394
+ .map((key) => {
395
+ const gen = Number(key);
396
+ return {
397
+ gen,
398
+ indis: newGenerations.tree[gen],
399
+ half: newGenerations.halves[gen],
400
+ };
401
+ });
402
+ }
403
+ getGenealogy(onlyStraight = false, showDescendants = false) {
404
+ const id = this.get("FAMC")?.toList().index(0)?.toValue();
405
+ if (!id) {
406
+ return;
407
+ }
408
+ const own = this.isMale()
409
+ ? {
410
+ father: this,
411
+ mother: !onlyStraight
412
+ ? this.getCoParents().index(0)
413
+ : undefined,
414
+ }
415
+ : {
416
+ mother: this,
417
+ father: !onlyStraight
418
+ ? this.getCoParents().index(0)
419
+ : undefined,
420
+ };
421
+ const newGenerations = {
422
+ existed: {
423
+ [this.id]: Existed.YES,
424
+ },
425
+ tree: {
426
+ 0: [
427
+ {
428
+ id,
429
+ index: 0,
430
+ ...own,
431
+ },
432
+ ],
433
+ },
434
+ halves: { 0: 0 },
435
+ lastItems: {},
436
+ };
437
+ this.generateTree({
438
+ generations: newGenerations,
439
+ level: 1,
440
+ famIndex: 0,
441
+ index: 0,
442
+ showDescendants,
443
+ });
444
+ const gens = Object.keys(newGenerations.tree).toSorted((a, b) => Number(b) - Number(a));
445
+ const genealogyGenerations = {};
446
+ const genealogyResult = {};
447
+ gens.forEach((genIndex) => {
448
+ const gen = Number(genIndex);
449
+ const generation = newGenerations.tree[gen].flat();
450
+ if (!genealogyGenerations[gen]) {
451
+ genealogyGenerations[gen] = {
452
+ left: [],
453
+ main: { left: [], right: [] },
454
+ right: [],
455
+ };
456
+ }
457
+ else {
458
+ if (!genealogyGenerations[gen].left) {
459
+ genealogyGenerations[gen].left = [];
460
+ }
461
+ if (!genealogyGenerations[gen].main) {
462
+ genealogyGenerations[gen].main = { left: [], right: [] };
463
+ }
464
+ if (!genealogyGenerations[gen].right) {
465
+ genealogyGenerations[gen].right = [];
466
+ }
467
+ }
468
+ generation.forEach((pack, index) => {
469
+ const members = { left: [], right: [] };
470
+ ["father", "mother"].forEach((type, mIndex) => {
471
+ const key = type;
472
+ const typedPack = pack?.[key];
473
+ const validIndex = index * 2 + mIndex;
474
+ const side = validIndex >= generation.length ? "right" : "left";
475
+ if (typedPack) {
476
+ members[side].push(typedPack);
477
+ }
478
+ });
479
+ if (!onlyStraight) {
480
+ ["father", "mother"].forEach((type, mIndex) => {
481
+ const key = type;
482
+ const typedPack = pack?.[key];
483
+ const validIndex = index * 2 + mIndex;
484
+ const side = validIndex >= generation.length ? "right" : "left";
485
+ const spouse = key === "father" ? pack?.mother : pack?.father;
486
+ const spouses = (typedPack?.getCoParents().values() ?? []).filter((item) => {
487
+ if (item?.id === spouse?.id) {
488
+ return false;
489
+ }
490
+ if (item.id && !newGenerations.existed[item.id]) {
491
+ newGenerations.existed[item.id] = Existed.YES;
492
+ return true;
493
+ }
494
+ return false;
495
+ });
496
+ const rawSiblings = typedPack
497
+ ?.getSiblings()
498
+ .orderBy(BIRTH_ASC)
499
+ .values() ?? [];
500
+ const siblings = rawSiblings.reduce((acc, item, index) => {
501
+ if (item.id && !newGenerations.existed[item.id]) {
502
+ newGenerations.existed[item.id] = Existed.YES;
503
+ const siblingSpouses = (item?.getCoParents().values() ?? []).filter((siblingSpouse) => {
504
+ if (siblingSpouse.id &&
505
+ !newGenerations.existed[siblingSpouse.id]) {
506
+ newGenerations.existed[siblingSpouse.id] = Existed.YES;
507
+ return true;
508
+ }
509
+ return false;
510
+ });
511
+ if (siblingSpouses.length) {
512
+ const newValue = item?.isMale()
513
+ ? [item, ...siblingSpouses]
514
+ : [...siblingSpouses, item];
515
+ return [
516
+ ...acc,
517
+ ...(index > 0 &&
518
+ newValue.length > 1 &&
519
+ acc[acc.length - 1] !== undefined
520
+ ? [undefined]
521
+ : []),
522
+ ...newValue,
523
+ ...(index < rawSiblings.length - 1 &&
524
+ newValue.length > 1
525
+ ? [undefined]
526
+ : []),
527
+ ];
528
+ }
529
+ return [...acc, item];
530
+ }
531
+ return acc;
532
+ }, []);
533
+ const spouseMethod = key === "father" ? "unshift" : "push";
534
+ const siblingMethod = side === "left" ? "unshift" : "push";
535
+ members[side][spouseMethod](...spouses);
536
+ if (siblings.length) {
537
+ if ((key === "father" && pack?.mother) ||
538
+ (key === "mother" && pack?.father)) {
539
+ members[side][siblingMethod](undefined);
540
+ }
541
+ members[side][siblingMethod](...siblings);
542
+ }
543
+ });
544
+ }
545
+ genealogyGenerations[gen].main.left.push(members.left.length ? members.left : undefined);
546
+ genealogyGenerations[gen].main.right.push(members.right.length ? members.right : undefined);
547
+ });
548
+ });
549
+ gens.forEach((genIndex) => {
550
+ const gen = Number(genIndex);
551
+ const prevGen = gen - 1;
552
+ if (!genealogyGenerations[prevGen]) {
553
+ genealogyGenerations[prevGen] = {
554
+ left: [],
555
+ main: { left: [], right: [] },
556
+ right: [],
557
+ };
558
+ }
559
+ ["left", "right"].forEach((s) => {
560
+ const side = s;
561
+ if (!onlyStraight) {
562
+ genealogyGenerations[gen].main[side].forEach((pack) => {
563
+ if (!pack) {
564
+ return;
565
+ }
566
+ const toRight = side === "right";
567
+ const orderedPack = pack;
568
+ orderedPack.forEach((indi) => {
569
+ if (!indi) {
570
+ return;
571
+ }
572
+ const rawChildren = indi
573
+ ?.getChildren()
574
+ .orderBy(BIRTH_ASC)
575
+ .values() ?? [];
576
+ const children = rawChildren.reduce((acc, item, index) => {
577
+ if (item.id &&
578
+ !newGenerations.existed[item.id]) {
579
+ newGenerations.existed[item.id] =
580
+ Existed.YES;
581
+ const childSpouses = (item?.getCoParents().values() ?? []).filter((childSpouse) => {
582
+ if (childSpouse.id &&
583
+ !newGenerations.existed[childSpouse.id]) {
584
+ newGenerations.existed[childSpouse.id] = Existed.YES;
585
+ return true;
586
+ }
587
+ return false;
588
+ });
589
+ if (childSpouses.length) {
590
+ const newValue = item?.isMale()
591
+ ? [item, ...childSpouses]
592
+ : [...childSpouses, item];
593
+ return [
594
+ ...acc,
595
+ ...(index > 0 &&
596
+ newValue.length > 1 &&
597
+ acc[acc.length - 1] !== undefined
598
+ ? [undefined]
599
+ : []),
600
+ ...newValue,
601
+ ...(index <
602
+ rawChildren.length - 1 &&
603
+ newValue.length > 1
604
+ ? [undefined]
605
+ : []),
606
+ ];
607
+ }
608
+ return [...acc, item];
609
+ }
610
+ return acc;
611
+ }, []);
612
+ const childMethod = "push";
613
+ const members = [];
614
+ if (children.length) {
615
+ members[childMethod](children);
616
+ }
617
+ if (toRight) {
618
+ genealogyGenerations[prevGen].right.push(...members);
619
+ }
620
+ else {
621
+ genealogyGenerations[prevGen].left.push(...members);
622
+ }
623
+ });
624
+ });
625
+ }
626
+ if (genealogyGenerations[prevGen]) {
627
+ genealogyGenerations[prevGen] = {
628
+ left: [],
629
+ main: {
630
+ left: [
631
+ ...(genealogyGenerations[prevGen]?.left ?? []),
632
+ ...(genealogyGenerations[prevGen]?.main.left ??
633
+ []),
634
+ ],
635
+ right: [
636
+ ...(genealogyGenerations[prevGen]?.main.right ??
637
+ []),
638
+ ...(genealogyGenerations[prevGen]?.right ?? []),
639
+ ],
640
+ },
641
+ right: [],
642
+ };
643
+ }
644
+ genealogyResult[gen] = {
645
+ left: [
646
+ ...(genealogyGenerations[gen]?.left ?? []),
647
+ ...(genealogyGenerations[gen]?.main.left ?? []),
648
+ ],
649
+ right: [
650
+ ...(genealogyGenerations[gen]?.main.right ?? []),
651
+ ...(genealogyGenerations[gen]?.right ?? []),
652
+ ],
653
+ };
654
+ });
655
+ });
656
+ const result = [];
657
+ gens.forEach((genIndex) => {
658
+ result.unshift({
659
+ gen: Number(genIndex),
660
+ ...genealogyResult[Number(genIndex)],
661
+ });
662
+ });
663
+ return result;
664
+ }
665
+ ancestryLink() {
666
+ const www = this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
667
+ const tree = this.getAncestryTreeId();
668
+ if (this.id) {
669
+ return `https://${www}/family-tree/person/tree/${tree}/person/${this.id.replace(/@|I/g, "")}/facts`;
670
+ }
671
+ }
672
+ async ancestryMedia(namespace) {
673
+ const list = {};
674
+ const objIds = this.get("OBJE")?.toValueList().keys() ?? [];
675
+ const www = this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
676
+ const tree = this.getAncestryTreeId();
677
+ await Promise.all(objIds.map(async (objId) => {
678
+ const key = objId;
679
+ const obje = this._gedcom
680
+ ?.obje(key)
681
+ ?.standardizeMedia(namespace, true, (ns, iId) => {
682
+ return ns && iId
683
+ ? `https://mediasvc.ancestry.com/v2/image/namespaces/${ns}/media/${iId}?client=trees-mediaservice&imageQuality=hq`
684
+ : undefined;
685
+ });
686
+ const media = obje?.RIN?.value;
687
+ const clone = obje?.get("_CLON._OID")?.toValue();
688
+ const mser = obje?.get("_MSER._LKID")?.toValue();
689
+ let url = obje?.get("FILE")?.toValue();
690
+ const title = obje?.get("TITL")?.toValue() ?? "";
691
+ const type = obje?.get("FORM")?.toValue() ??
692
+ "raw";
693
+ const imgId = clone || mser;
694
+ if (!www || !tree || !this.id) {
695
+ return;
696
+ }
697
+ if (!namespace && !url) {
698
+ try {
699
+ const mediaDetailsResponse = await fetch(`https://www.ancestry.com/api/media/viewer/v2/trees/${tree}/media?id=${media}`);
700
+ const mediaDetails = (await mediaDetailsResponse.json());
701
+ if (mediaDetails.url) {
702
+ url = `${mediaDetails.url}&imageQuality=hq`;
703
+ }
704
+ }
705
+ catch (_e) {
706
+ //
707
+ }
708
+ url =
709
+ url ||
710
+ `https://${www}/mediaui-viewer/tree/${tree}/media/${media}`;
711
+ }
712
+ if (url && imgId) {
713
+ const id = `${tree}-${this.id}-${imgId}`;
714
+ list[id] = {
715
+ key,
716
+ id,
717
+ tree,
718
+ imgId,
719
+ person: this.id,
720
+ title: title,
721
+ url,
722
+ contentType: type,
723
+ downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName().replaceAll(" ", "-") || ""}_${(title ||
724
+ key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`,
725
+ };
726
+ }
727
+ }));
728
+ return list;
729
+ }
730
+ myheritageLink(poolId = 0) {
731
+ const www = this._gedcom?.HEAD?.SOUR?.CORP?.value
732
+ ?.toLowerCase()
733
+ .replace(/^www\./gi, "");
734
+ const site = this.getMyHeritageTreeId();
735
+ const file = this._gedcom?.HEAD?.get("FILE")?.toValue()?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)
736
+ ?.groups?.site;
737
+ const normalizedFile = file
738
+ ?.normalize("NFD")
739
+ .replace(/[\u0300-\u036f]/g, "")
740
+ .toLowerCase()
741
+ .replace(/[^a-z0-9]+/g, "-");
742
+ if (normalizedFile && this.id) {
743
+ const id = Number(this.id.replace(/@|I/g, "")) + poolId;
744
+ return `https://www.${www}/site-family-tree-${site}/${normalizedFile}#!profile-${id}-info`;
745
+ }
746
+ }
747
+ myheritageMedia() {
748
+ const list = {};
749
+ const tree = this.getMyHeritageTreeId();
750
+ if (!tree) {
751
+ return;
752
+ }
753
+ const birthObj = this.get("BIRT.OBJE")?.toList().values();
754
+ const deathObj = this.get("DEAT.OBJE")?.toValueList().values();
755
+ const familiesObj = (this.get("FAMS")?.toValueList().values() ?? [])
756
+ .concat(this.get("FAMC")?.toValueList().values() ?? [])
757
+ .map((fam) => {
758
+ return fam?.get("MARR.OBJE");
759
+ });
760
+ (birthObj ?? [])
761
+ .concat(deathObj ?? [])
762
+ .concat(familiesObj ?? [])
763
+ .forEach((o, index) => {
764
+ if (!o) {
765
+ return;
766
+ }
767
+ const obje = o;
768
+ const key = `@O${index}@`;
769
+ obje.standardizeMedia();
770
+ const url = obje?.get("FILE")?.toValue();
771
+ const title = obje?.get("NOTE")?.toValue() ?? "";
772
+ const type = obje?.get("FORM")?.toValue() ??
773
+ "raw";
774
+ const imgId = obje?.get("_PHOTO_RIN")?.toValue();
775
+ if (url && imgId) {
776
+ const id = `${tree}-${this.id}-${imgId}`;
777
+ list[id] = {
778
+ key,
779
+ id,
780
+ tree,
781
+ imgId,
782
+ person: this.id,
783
+ title: title,
784
+ url,
785
+ contentType: type,
786
+ downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName().replaceAll(" ", "-") || ""}_${(title ||
787
+ key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`,
788
+ };
789
+ }
790
+ });
791
+ return list;
792
+ }
793
+ familySearchLink() {
794
+ // Get the _FS_LINK custom tag value and return it as-is
795
+ return this.get("_FS_LINK")?.toValue();
796
+ }
797
+ async multimedia(namespace) {
798
+ if (this?.isAncestry()) {
799
+ return await this.ancestryMedia(namespace);
800
+ }
801
+ if (this?.isMyHeritage()) {
802
+ return this.myheritageMedia();
803
+ }
804
+ return undefined;
805
+ }
806
+ link(poolId) {
807
+ if (this?.isAncestry()) {
808
+ return this.ancestryLink();
809
+ }
810
+ if (this?.isMyHeritage()) {
811
+ return this.myheritageLink(poolId);
812
+ }
813
+ if (this?.isFamilySearch()) {
814
+ return this.familySearchLink();
815
+ }
816
+ return undefined;
817
+ }
818
+ toFamilies(list) {
819
+ const families = new Families();
820
+ list?.forEach((fam, famId) => {
821
+ const family = fam?.ref;
822
+ if (family) {
823
+ families.item(famId, family);
824
+ }
825
+ });
826
+ return families;
827
+ }
828
+ getFamilies(type) {
829
+ return this.toFamilies(this.get(type)?.toValueList());
830
+ }
831
+ getFamiliesBiologicalFirst(type) {
832
+ const families = this.toFamilies(this.get(type)?.toValueList());
833
+ return families.orderBy((famB, _famBKey, famA) => {
834
+ const husbA = famA.getHusband().index(0);
835
+ const wifeA = famA.getWife().index(0);
836
+ const husbAType = husbA && this.getParentType(husbA);
837
+ const wifeAType = wifeA && this.getParentType(wifeA);
838
+ const husbB = famB.getHusband().index(0);
839
+ const wifeB = famB.getWife().index(0);
840
+ const husbBType = husbB && this.getParentType(husbB);
841
+ const wifeBType = wifeB && this.getParentType(wifeB);
842
+ if (husbAType === RelationType.BIOLOGICAL &&
843
+ wifeAType === RelationType.BIOLOGICAL) {
844
+ if (husbBType === RelationType.BIOLOGICAL &&
845
+ wifeBType === RelationType.BIOLOGICAL) {
846
+ return 0;
847
+ }
848
+ return 1;
849
+ }
850
+ else if (husbAType === RelationType.BIOLOGICAL) {
851
+ if (husbBType === RelationType.BIOLOGICAL &&
852
+ wifeBType === RelationType.BIOLOGICAL) {
853
+ return -1;
854
+ }
855
+ else if (husbBType === RelationType.BIOLOGICAL) {
856
+ return 0;
857
+ }
858
+ return 1;
859
+ }
860
+ else if (wifeAType === RelationType.BIOLOGICAL) {
861
+ if (husbBType === RelationType.BIOLOGICAL &&
862
+ wifeBType === RelationType.BIOLOGICAL) {
863
+ return -1;
864
+ }
865
+ else if (husbBType === RelationType.BIOLOGICAL) {
866
+ return -1;
867
+ }
868
+ return 0;
869
+ }
870
+ if (husbBType === RelationType.BIOLOGICAL ||
871
+ wifeBType === RelationType.BIOLOGICAL) {
872
+ return -1;
873
+ }
874
+ return 0;
875
+ });
876
+ }
877
+ isDead() {
878
+ return (this.get("DEAT.DATE")?.toValue() !== undefined ||
879
+ this.get("DEAT.PLAC")?.toValue() !== undefined);
880
+ }
881
+ isEmpty() {
882
+ if (this._isEmpty !== undefined) {
883
+ return this._isEmpty;
884
+ }
885
+ const keysLength = Object.keys(this).filter((key) => {
886
+ return (!key.startsWith("_") &&
887
+ !["gedcom", "isListable", "refType"].includes(key));
888
+ }).length;
889
+ this._isEmpty = !keysLength;
890
+ return this._isEmpty;
891
+ }
892
+ isUnknownAncestor() {
893
+ if (this._isUnknownAncestor !== undefined) {
894
+ return this._isUnknownAncestor;
895
+ }
896
+ this._isUnknownAncestor = !!this.get("_MTTAG")
897
+ ?.toList()
898
+ ?.values()
899
+ .find((tag) => tag?.get("NAME")?.toValue() === CustomTags.UnknownAncestor);
900
+ return this._isUnknownAncestor;
901
+ }
902
+ isIgnoredMember() {
903
+ if (this._isIgnoredPerson !== undefined) {
904
+ return this._isIgnoredPerson;
905
+ }
906
+ this._isIgnoredPerson = !!this.get("_MTTAG")
907
+ ?.toList()
908
+ ?.values()
909
+ .find((tag) => tag?.get("NAME")?.toValue() === CustomTags.IgnoredMember);
910
+ return this._isIgnoredPerson;
911
+ }
912
+ isUnattachedMember() {
913
+ if (this._isUnattachedMember !== undefined) {
914
+ return this._isUnattachedMember;
915
+ }
916
+ this._isUnattachedMember = !!this.get("_MTTAG")
917
+ ?.toList()
918
+ ?.values()
919
+ .find((tag) => tag?.get("NAME")?.toValue() === CustomTags.UnattachedMember);
920
+ return this._isUnattachedMember;
921
+ }
922
+ isOrphanFamilyMember() {
923
+ if (this._isOrphanFamilyMember !== undefined) {
924
+ return this._isOrphanFamilyMember;
925
+ }
926
+ // Check if any of the person's families (FAMC or FAMS) has the _IS_ORPHAN_FAMILY tag
927
+ const famcFamilies = this.getFamilies("FAMC");
928
+ const famsFamilies = this.getFamilies("FAMS");
929
+ this._isOrphanFamilyMember = false;
930
+ // Check FAMC families
931
+ famcFamilies.forEach((fam) => {
932
+ if (fam._IS_ORPHAN_FAMILY?.value === "Y") {
933
+ this._isOrphanFamilyMember = true;
934
+ }
935
+ });
936
+ // Check FAMS families if not already found
937
+ if (!this._isOrphanFamilyMember) {
938
+ famsFamilies.forEach((fam) => {
939
+ if (fam._IS_ORPHAN_FAMILY?.value === "Y") {
940
+ this._isOrphanFamilyMember = true;
941
+ }
942
+ });
943
+ }
944
+ return this._isOrphanFamilyMember;
945
+ }
946
+ isUnknownGivenname() {
947
+ if (this._isUnknownGivenname !== undefined) {
948
+ return this._isUnknownGivenname;
949
+ }
950
+ this._isUnknownGivenname = !!this.get("_MTTAG")
951
+ ?.toList()
952
+ ?.values()
953
+ .find((tag) => tag?.get("NAME")?.toValue() === CustomTags.UnknownGivenname);
954
+ return this._isUnknownGivenname;
955
+ }
956
+ isUnknownSurname() {
957
+ if (this._isUnknownSurname !== undefined) {
958
+ return this._isUnknownSurname;
959
+ }
960
+ this._isUnknownSurname = !!this.get("_MTTAG")
961
+ ?.toList()
962
+ ?.values()
963
+ .find((tag) => tag?.get("NAME")?.toValue() === CustomTags.UnknownSurname);
964
+ return this._isUnknownSurname;
965
+ }
966
+ isNonRelevantMember() {
967
+ return this.isUnknownAncestor() || this.isUnattachedMember();
968
+ }
969
+ isMale() {
970
+ return this.get("SEX")?.toValue() === "M";
971
+ }
972
+ isFemale() {
973
+ return this.get("SEX")?.toValue() === "F";
974
+ }
975
+ isUnknownSex() {
976
+ return !this.isMale() && !this.isFemale();
977
+ }
978
+ getParentType(id) {
979
+ let indi;
980
+ if (typeof id === "string" || typeof id === "number") {
981
+ indi = this._gedcom?.indi(id);
982
+ }
983
+ else {
984
+ indi = id;
985
+ }
986
+ if (!indi?.id || !this.id) {
987
+ return;
988
+ }
989
+ const parents = this.getParents();
990
+ let parent = parents.item(indi.id) ? indi : undefined;
991
+ let child = this._gedcom?.indi(this.id);
992
+ if (!parent?.id) {
993
+ const children = this.getChildren();
994
+ if (children.item(indi.id)) {
995
+ parent = this._gedcom?.indi(this.id);
996
+ child = indi;
997
+ }
998
+ }
999
+ const familiesOfChildren = child?.get("FAMC")?.toValueList();
1000
+ if (!parent?.id || !child?.id || !familiesOfChildren) {
1001
+ return;
1002
+ }
1003
+ const families = this.toFamilies(familiesOfChildren);
1004
+ let childType = "";
1005
+ families.forEach((family) => {
1006
+ if (childType) {
1007
+ return;
1008
+ }
1009
+ const fatherId = family.get("HUSB")?.toValue();
1010
+ const motherId = family.get("WIFE")?.toValue();
1011
+ const usedRel = parent?.id === fatherId
1012
+ ? "_FREL"
1013
+ : parent?.id === motherId
1014
+ ? "_MREL"
1015
+ : undefined;
1016
+ if (!usedRel || !child?.id) {
1017
+ return;
1018
+ }
1019
+ const famChild = this.id && family.CHIL?.toValueList().item(child.id);
1020
+ if (!famChild) {
1021
+ const childIndi = this._gedcom?.indi(child.id);
1022
+ const childState = childIndi
1023
+ ?.get("FAMC")
1024
+ ?.toList()
1025
+ ?.filter((item) => item.value === family.id)
1026
+ .index(0);
1027
+ childType =
1028
+ childState?.get("PEDI")?.toValue() ||
1029
+ RelationType.BIOLOGICAL;
1030
+ }
1031
+ else {
1032
+ childType =
1033
+ famChild.get(usedRel)?.toValue() ||
1034
+ RelationType.BIOLOGICAL;
1035
+ }
1036
+ });
1037
+ return (childType || RelationType.BIOLOGICAL).toLowerCase();
1038
+ }
1039
+ hasFacts() {
1040
+ const dates = dateFormatter(this, true);
1041
+ if (dates.inArray.length) {
1042
+ return true;
1043
+ }
1044
+ const facts = this.getFacts(1);
1045
+ return !!facts.length;
1046
+ }
1047
+ getLinks() {
1048
+ return this.get("_WLNK")?.toList();
1049
+ }
1050
+ getAkas(limit) {
1051
+ return this.getFacts(limit, "AKA");
1052
+ }
1053
+ getFacts(limit, filter) {
1054
+ const filters = (Array.isArray(filter) ? filter : [filter]).filter(Boolean);
1055
+ const facts = new List();
1056
+ let id = 0;
1057
+ ALLOWED_FACTS.forEach((fact) => {
1058
+ const isCustom = ["EVEN", "FACT"].includes(fact);
1059
+ if (filters.length && !filters.includes(fact) && !isCustom) {
1060
+ return;
1061
+ }
1062
+ const factCommon = this.get(fact);
1063
+ const factCommons = factCommon?.toList();
1064
+ factCommons?.forEach((common, _, index) => {
1065
+ if (limit !== undefined && index >= limit) {
1066
+ return;
1067
+ }
1068
+ if (!common) {
1069
+ return;
1070
+ }
1071
+ const newCommon = createCommon(this._gedcom, `${id}`, this);
1072
+ Object.assign(newCommon, common, { id: id });
1073
+ const type = (isCustom ? newCommon.get("TYPE")?.toValue() : fact);
1074
+ if (!type || DISALLOWED_CUSTOM_FACTS.includes(type)) {
1075
+ return;
1076
+ }
1077
+ if (filters.length && !filters.includes(type) && isCustom) {
1078
+ return;
1079
+ }
1080
+ const label = createCommon(this._gedcom, undefined, this);
1081
+ const customRenderer = CustomFactRenderers[type];
1082
+ if (customRenderer) {
1083
+ customRenderer(label, newCommon, this);
1084
+ }
1085
+ else {
1086
+ label.value = type;
1087
+ newCommon.set("_LABEL", label);
1088
+ }
1089
+ // common.id = common.id || (`${id}` as IdType);
1090
+ id++;
1091
+ facts.append(newCommon);
1092
+ });
1093
+ });
1094
+ return facts.orderBy(DATE_ASC);
1095
+ }
1096
+ commonAncestor(person, options) {
1097
+ const path = this.path(person, options);
1098
+ let wentUp = false;
1099
+ const wentDown = false;
1100
+ let lastItem;
1101
+ let ancestor;
1102
+ path?.forEach((item) => {
1103
+ if (wentDown) {
1104
+ return;
1105
+ }
1106
+ if (lastItem) {
1107
+ if (item.level > lastItem.level) {
1108
+ wentUp = true;
1109
+ }
1110
+ if (item.level < lastItem.level) {
1111
+ wentUp = true;
1112
+ if (wentUp && !ancestor) {
1113
+ ancestor = lastItem.indi;
1114
+ }
1115
+ }
1116
+ }
1117
+ lastItem = item;
1118
+ });
1119
+ return ancestor;
1120
+ }
1121
+ path(person, options) {
1122
+ const { breakAfterSpouse = true, breakAfterNonBiological } = options ?? {};
1123
+ const usedIndi = typeof person === "string" ? this._gedcom?.indi(person) : person;
1124
+ if (!this.id || !usedIndi?.id) {
1125
+ return;
1126
+ }
1127
+ const cacheKey = `${this.id}|${usedIndi.id}`;
1128
+ const cache = pathCache(cacheKey);
1129
+ if (cache) {
1130
+ return cache;
1131
+ }
1132
+ const visited = new Individuals().append(this);
1133
+ const mainItem = {
1134
+ indi: this,
1135
+ level: 0,
1136
+ levelUp: 0,
1137
+ levelDown: 0,
1138
+ degree: 0,
1139
+ kinship: "self",
1140
+ };
1141
+ const path = [mainItem];
1142
+ if (this.id === usedIndi.id) {
1143
+ return path;
1144
+ }
1145
+ const queue = [
1146
+ {
1147
+ ...mainItem,
1148
+ path,
1149
+ },
1150
+ ];
1151
+ // Breadth-first search to find the shortest path
1152
+ let helper = 0;
1153
+ while (queue.length > 0) {
1154
+ if (helper++ > 1000000) {
1155
+ break;
1156
+ }
1157
+ const { indi, path, kinship, relation, level, levelUp, levelDown, degree, breakOnNext, breakAfterNext, inLaw, } = queue.shift();
1158
+ if (usedIndi.id === indi.id) {
1159
+ if (breakOnNext) {
1160
+ return undefined;
1161
+ }
1162
+ pathCache(cacheKey, path);
1163
+ return path;
1164
+ }
1165
+ visited.append(indi);
1166
+ const additional = {};
1167
+ if (breakOnNext || breakAfterNext) {
1168
+ additional.breakOnNext = breakOnNext || breakAfterNext;
1169
+ }
1170
+ if (inLaw) {
1171
+ additional.inLaw = inLaw;
1172
+ }
1173
+ if (kinship === "spouse" && breakAfterSpouse) {
1174
+ if (path.length <= 2) {
1175
+ additional.inLaw = true;
1176
+ }
1177
+ else {
1178
+ additional.breakOnNext = true;
1179
+ }
1180
+ }
1181
+ // Direct relatives: Parents and Children
1182
+ if (kinship !== "child" || !breakAfterSpouse) {
1183
+ indi.getBiologicalFathers()
1184
+ .copy()
1185
+ .merge(indi.getBiologicalMothers())
1186
+ .merge(indi.getFathers().copy().merge(indi.getMothers()))
1187
+ .forEach((relative) => {
1188
+ if (!visited.has(relative)) {
1189
+ const currentRelation = indi.getParentType(relative);
1190
+ if (breakAfterNonBiological &&
1191
+ currentRelation !== RelationType.BIOLOGICAL) {
1192
+ additional.breakAfterNext = true;
1193
+ }
1194
+ const newItem = {
1195
+ indi: relative,
1196
+ kinship: "parent",
1197
+ relation: currentRelation &&
1198
+ currentRelation !== RelationType.BIOLOGICAL
1199
+ ? currentRelation
1200
+ : relation,
1201
+ level: level + 1,
1202
+ levelUp: levelUp + 1,
1203
+ levelDown,
1204
+ degree,
1205
+ ...additional,
1206
+ };
1207
+ queue.push({
1208
+ ...newItem,
1209
+ path: [...path, newItem],
1210
+ });
1211
+ }
1212
+ });
1213
+ }
1214
+ indi.getChildren().forEach((relative) => {
1215
+ if (!visited.has(relative)) {
1216
+ const currentRelation = relative.getParentType(indi);
1217
+ if (breakAfterNonBiological &&
1218
+ currentRelation !== RelationType.BIOLOGICAL) {
1219
+ additional.breakAfterNext = true;
1220
+ }
1221
+ const newItem = {
1222
+ indi: relative,
1223
+ kinship: "child",
1224
+ relation: currentRelation &&
1225
+ currentRelation !== RelationType.BIOLOGICAL
1226
+ ? currentRelation
1227
+ : relation,
1228
+ level: level - 1,
1229
+ levelUp,
1230
+ levelDown: levelDown + 1,
1231
+ degree: levelUp
1232
+ ? level > 0
1233
+ ? levelUp - level + 1
1234
+ : levelDown - Math.abs(level)
1235
+ : 0,
1236
+ ...additional,
1237
+ };
1238
+ queue.push({
1239
+ ...newItem,
1240
+ path: [...path, newItem],
1241
+ });
1242
+ }
1243
+ });
1244
+ // Spouses
1245
+ indi.getCoParents().forEach((relative) => {
1246
+ if (!visited.has(relative)) {
1247
+ const currentAddition = {};
1248
+ if (relation && relation !== RelationType.BIOLOGICAL) {
1249
+ currentAddition.relation = relation;
1250
+ }
1251
+ if (inLaw) {
1252
+ currentAddition.breakOnNext = true;
1253
+ }
1254
+ const newItem = {
1255
+ indi: relative,
1256
+ kinship: "spouse",
1257
+ level,
1258
+ levelUp,
1259
+ levelDown,
1260
+ degree,
1261
+ ...additional,
1262
+ ...currentAddition,
1263
+ };
1264
+ queue.push({
1265
+ ...newItem,
1266
+ path: [...path, newItem],
1267
+ });
1268
+ }
1269
+ });
1270
+ }
1271
+ return undefined;
1272
+ }
1273
+ kinship(other, showMainPerson, lang = "en", entirePath, displayName = "givenname") {
1274
+ const KinshipTranslatorClass = getKinshipTranslatorClass();
1275
+ const translator = new KinshipTranslatorClass(this, other, lang, entirePath, showMainPerson ? displayName : undefined);
1276
+ return translator.translate(!!showMainPerson);
1277
+ }
1278
+ isRelativeOf(type, indi) {
1279
+ const usedIndi = typeof indi === "string" ? this._gedcom?.indi(indi) : indi;
1280
+ let getter;
1281
+ if (type === "fullsibling") {
1282
+ getter = "getFullSiblings";
1283
+ }
1284
+ if (type === "halfsibling") {
1285
+ getter = "getHalfSiblings";
1286
+ }
1287
+ if (type === "sibling") {
1288
+ getter = "getSiblings";
1289
+ }
1290
+ if (type === "parent") {
1291
+ getter = "getParents";
1292
+ }
1293
+ if (type === "child") {
1294
+ getter = "getChildren";
1295
+ }
1296
+ if (type === "spouse") {
1297
+ getter = "getCoParents";
1298
+ }
1299
+ if (type === "siblingInLaw") {
1300
+ getter = "getSiblingsInLaw";
1301
+ }
1302
+ if (type === "parentInLaw") {
1303
+ getter = "getParentsInLaw";
1304
+ }
1305
+ if (type === "childInLaw") {
1306
+ getter = "getChildrenInLaw";
1307
+ }
1308
+ if (!usedIndi || !getter) {
1309
+ return false;
1310
+ }
1311
+ const relatives = usedIndi[getter]();
1312
+ return Boolean(this.id && relatives.item(this.id)
1313
+ ? relatives.index(0)?.id || true
1314
+ : false);
1315
+ }
1316
+ isSiblingOf(indi) {
1317
+ return this.isRelativeOf("sibling", indi);
1318
+ }
1319
+ isFullSiblingOf(indi) {
1320
+ return this.isRelativeOf("fullsibling", indi);
1321
+ }
1322
+ isHalfSiblingOf(indi) {
1323
+ return this.isRelativeOf("halfsibling", indi);
1324
+ }
1325
+ isSpouseOf(indi) {
1326
+ return this.isRelativeOf("spouse", indi);
1327
+ }
1328
+ isParentOf(indi) {
1329
+ return this.isRelativeOf("parent", indi);
1330
+ }
1331
+ isChildOf(indi) {
1332
+ return this.isRelativeOf("child", indi);
1333
+ }
1334
+ isSiblingInLawOf(indi) {
1335
+ return this.isRelativeOf("siblingInLaw", indi);
1336
+ }
1337
+ isParentInLawOf(indi) {
1338
+ return this.isRelativeOf("parentInLaw", indi);
1339
+ }
1340
+ isChildInLawOf(indi) {
1341
+ return this.isRelativeOf("childInLaw", indi);
1342
+ }
1343
+ getRelativesOnDegree(degree = 0) {
1344
+ this.id = this.id || `@I${Math.random()}@`;
1345
+ const cache = relativesOnDegreeCache(this.id, degree);
1346
+ if (cache) {
1347
+ return cache;
1348
+ }
1349
+ let persons = this.getRelativesOnLevel(1)
1350
+ .getRelativesOnDegree(-1)
1351
+ .copy();
1352
+ const excludes = persons;
1353
+ if (!Math.abs(degree)) {
1354
+ return relativesOnDegreeCache(this.id, degree, persons.except(this));
1355
+ }
1356
+ for (let i = 1; i < Math.abs(degree) + 1; i++) {
1357
+ const validDegree = i + 1;
1358
+ excludes.merge(persons);
1359
+ persons = this.getRelativesOnLevel(validDegree)
1360
+ .getRelativesOnDegree(-validDegree)
1361
+ .copy()
1362
+ .exclude(excludes);
1363
+ }
1364
+ return relativesOnDegreeCache(this.id, degree, persons);
1365
+ }
1366
+ getRelativesOnLevel(level = 0, filter) {
1367
+ this.id = this.id || `@I${Math.random()}@`;
1368
+ const cache = relativesOnLevelCache(this.id, level);
1369
+ if (cache) {
1370
+ return cache;
1371
+ }
1372
+ let persons = new Individuals();
1373
+ const config = {
1374
+ isAscendant: level < 0,
1375
+ direction: level < 0 ? -1 : 1,
1376
+ key: level <= 0 ? "FAMS" : "FAMC",
1377
+ };
1378
+ let families = this.get(config.key)?.toValueList();
1379
+ if (!families) {
1380
+ return relativesOnLevelCache(this.id, level, persons);
1381
+ }
1382
+ if (filter) {
1383
+ families = families.filter(filter);
1384
+ }
1385
+ if (config.isAscendant) {
1386
+ persons = this.toFamilies(families).getChildren();
1387
+ }
1388
+ else {
1389
+ persons = this.toFamilies(families).getParents();
1390
+ }
1391
+ if (level >= -1 && level <= 1) {
1392
+ return relativesOnLevelCache(this.id, level, persons.except(this));
1393
+ }
1394
+ for (let i = 1; i < Math.abs(level); i++) {
1395
+ if (config.isAscendant) {
1396
+ persons = persons.getChildren();
1397
+ }
1398
+ else {
1399
+ persons = persons.getParents();
1400
+ }
1401
+ }
1402
+ return relativesOnLevelCache(this.id, level, persons.except(this));
1403
+ }
1404
+ getAscendants(level = 0, filter) {
1405
+ if (!level) {
1406
+ return new Individuals();
1407
+ }
1408
+ return this.getRelativesOnLevel(level, filter);
1409
+ }
1410
+ getDescendants(level = 0, filter) {
1411
+ if (!level) {
1412
+ return new Individuals();
1413
+ }
1414
+ return this.getRelativesOnLevel(-level, filter);
1415
+ }
1416
+ getAllDescendantsRaw(individuals, containDescendantsInLaw = false) {
1417
+ this.id = this.id || `@I${Math.random()}@`;
1418
+ let ownGeneration = new Individuals();
1419
+ if (individuals) {
1420
+ ownGeneration = individuals;
1421
+ ownGeneration.merge(this.getCoParents());
1422
+ }
1423
+ ownGeneration.append(this);
1424
+ const relatives = new Individuals();
1425
+ relatives.merge(ownGeneration);
1426
+ const generations = {
1427
+ 0: ownGeneration,
1428
+ };
1429
+ let currentGen = 0;
1430
+ const maxGenCheck = 100;
1431
+ while (currentGen < maxGenCheck) {
1432
+ const descentants = generations[currentGen]?.getChildren().copy();
1433
+ if (!descentants?.length) {
1434
+ break;
1435
+ }
1436
+ if (containDescendantsInLaw) {
1437
+ descentants?.merge(descentants?.getCoParents());
1438
+ }
1439
+ currentGen++;
1440
+ generations[currentGen] = descentants;
1441
+ relativesOnLevelCache(this.id, -currentGen, descentants);
1442
+ descentants && relatives.merge(descentants);
1443
+ }
1444
+ return { relatives, generations };
1445
+ }
1446
+ getAllDescendants(individuals, containDescendantsInLaw = false) {
1447
+ const raw = this.getAllDescendantsRaw(individuals, containDescendantsInLaw);
1448
+ return raw.relatives;
1449
+ }
1450
+ getAllAscendantsRaw(individuals) {
1451
+ this.id = this.id || `@I${Math.random()}@`;
1452
+ let ownGeneration = new Individuals();
1453
+ if (individuals) {
1454
+ ownGeneration = individuals;
1455
+ }
1456
+ ownGeneration.append(this);
1457
+ const relatives = new Individuals();
1458
+ relatives.merge(ownGeneration);
1459
+ const generations = {
1460
+ 0: ownGeneration,
1461
+ };
1462
+ let currentGen = 0;
1463
+ const maxGenCheck = 100;
1464
+ while (currentGen < maxGenCheck) {
1465
+ const parents = generations[currentGen]?.getParents().copy();
1466
+ if (!parents?.length) {
1467
+ break;
1468
+ }
1469
+ currentGen++;
1470
+ generations[currentGen] = parents;
1471
+ relativesOnLevelCache(this.id, currentGen, parents);
1472
+ parents && relatives.merge(parents);
1473
+ }
1474
+ return { relatives, generations };
1475
+ }
1476
+ getAllAscendants(individuals) {
1477
+ const raw = this.getAllAscendantsRaw(individuals);
1478
+ return raw.relatives;
1479
+ }
1480
+ getHalfSiblings() {
1481
+ const siblings = this.getSiblings();
1482
+ const ownParents = this.getBiologicalParents();
1483
+ const halfSiblings = new Individuals();
1484
+ siblings.forEach((sibling) => {
1485
+ const siblingsParents = sibling.getBiologicalParents();
1486
+ const inter = ownParents.intersection(siblingsParents);
1487
+ if (inter.length < ownParents.length) {
1488
+ halfSiblings.append(sibling);
1489
+ }
1490
+ });
1491
+ return halfSiblings;
1492
+ }
1493
+ getFullSiblings() {
1494
+ const siblings = this.getSiblings();
1495
+ const ownParents = this.getBiologicalParents();
1496
+ const fullSiblings = new Individuals();
1497
+ siblings.forEach((sibling) => {
1498
+ const siblingsParents = sibling.getBiologicalParents();
1499
+ const inter = ownParents.intersection(siblingsParents);
1500
+ if (inter.length === ownParents.length) {
1501
+ fullSiblings.append(sibling);
1502
+ }
1503
+ });
1504
+ return fullSiblings;
1505
+ }
1506
+ getSiblings() {
1507
+ implemented("getSiblings");
1508
+ return this.getRelativesOnDegree(0);
1509
+ }
1510
+ getBrothers() {
1511
+ implemented("getBrothers");
1512
+ return this.getSiblings().filter(Filters.MALE);
1513
+ }
1514
+ getSisters() {
1515
+ implemented("getSisters");
1516
+ return this.getSiblings().filter(Filters.MALE);
1517
+ }
1518
+ getChildren(filter) {
1519
+ implemented("getChildren");
1520
+ return this.getDescendants(1, filter);
1521
+ }
1522
+ getChildrenFilteredByPedigree(filter) {
1523
+ const children = new Individuals();
1524
+ const familiesOfChildrens = this.get("FAMS")?.toValueList();
1525
+ if (!familiesOfChildrens || !this.id) {
1526
+ return children;
1527
+ }
1528
+ const families = this.toFamilies(familiesOfChildrens);
1529
+ families.forEach((family) => {
1530
+ const fatherId = family.get("HUSB")?.toValue();
1531
+ const motherId = family.get("WIFE")?.toValue();
1532
+ const usedRel = this.id === fatherId
1533
+ ? "_FREL"
1534
+ : this.id === motherId
1535
+ ? "_MREL"
1536
+ : undefined;
1537
+ if (!usedRel) {
1538
+ return;
1539
+ }
1540
+ const famChildren = this.id && family.CHIL?.toValueList();
1541
+ famChildren?.forEach((child) => {
1542
+ const childType = child.get(usedRel)?.toValue();
1543
+ if ((!childType && filter.PEDI === RelationType.BIOLOGICAL) ||
1544
+ childType?.toLowerCase() === filter.PEDI.toLowerCase()) {
1545
+ const childId = child?.toValue();
1546
+ const childIndi = childId && this._gedcom?.indi(childId);
1547
+ if (childIndi) {
1548
+ children.append(childIndi);
1549
+ }
1550
+ }
1551
+ });
1552
+ if (!famChildren?.length) {
1553
+ this.getChildren().forEach((child) => {
1554
+ if (!child) {
1555
+ return;
1556
+ }
1557
+ const childState = child
1558
+ ?.get("FAMC")
1559
+ ?.toList()
1560
+ ?.filter((item) => item.value === family.id)
1561
+ .index(0);
1562
+ const childType = childState?.get("PEDI")?.toValue() ||
1563
+ RelationType.BIOLOGICAL;
1564
+ if ((!childType &&
1565
+ filter.PEDI === RelationType.BIOLOGICAL) ||
1566
+ childType?.toLowerCase() === filter.PEDI.toLowerCase()) {
1567
+ children.append(child);
1568
+ }
1569
+ });
1570
+ }
1571
+ });
1572
+ return children;
1573
+ }
1574
+ getBiologicalChildren() {
1575
+ implemented("getBiologicalChildren");
1576
+ return this.getChildrenFilteredByPedigree(Filters.BIOLOGICAL);
1577
+ }
1578
+ getAdoptedChildren() {
1579
+ implemented("getAdoptedChildren");
1580
+ return this.getChildrenFilteredByPedigree(Filters.ADOPTED);
1581
+ }
1582
+ getBirthChildren() {
1583
+ implemented("getBirthChildren");
1584
+ return this.getChildrenFilteredByPedigree(Filters.BIRTH);
1585
+ }
1586
+ getFosterChildren() {
1587
+ implemented("getFosterChildren");
1588
+ return this.getChildrenFilteredByPedigree(Filters.FOSTER);
1589
+ }
1590
+ getSealingChildren() {
1591
+ implemented("getSealingChildren");
1592
+ return this.getChildrenFilteredByPedigree(Filters.SEALING);
1593
+ }
1594
+ getStepChildren() {
1595
+ implemented("getStepChildren");
1596
+ return this.getChildrenFilteredByPedigree(Filters.STEP);
1597
+ }
1598
+ getSons() {
1599
+ implemented("getSons");
1600
+ return this.getChildren().filter(Filters.MALE);
1601
+ }
1602
+ getBiologicalSons() {
1603
+ implemented("getBiologicalSons");
1604
+ return this.getChildrenFilteredByPedigree(Filters.BIOLOGICAL).filter(Filters.MALE);
1605
+ }
1606
+ getAdoptedSons() {
1607
+ implemented("getAdoptedSons");
1608
+ return this.getAdoptedChildren().filter(Filters.MALE);
1609
+ }
1610
+ getBirthSons() {
1611
+ implemented("getBirthSons");
1612
+ return this.getBirthChildren().filter(Filters.MALE);
1613
+ }
1614
+ getFosterSons() {
1615
+ implemented("getFosterSons");
1616
+ return this.getFosterChildren().filter(Filters.MALE);
1617
+ }
1618
+ getSealingSons() {
1619
+ implemented("getSealingSons");
1620
+ return this.getSealingChildren().filter(Filters.MALE);
1621
+ }
1622
+ getStepSons() {
1623
+ implemented("getStepSons");
1624
+ return this.getStepChildren().filter(Filters.MALE);
1625
+ }
1626
+ getDaughters() {
1627
+ implemented("getDaughters");
1628
+ return this.getChildren().filter(Filters.FEMALE);
1629
+ }
1630
+ getBiologicalDaugthers() {
1631
+ implemented("getBiologicalDaugthers");
1632
+ return this.getChildrenFilteredByPedigree(Filters.BIOLOGICAL).filter(Filters.FEMALE);
1633
+ }
1634
+ getAdoptedDaughters() {
1635
+ implemented("getAdoptedDaughters");
1636
+ return this.getAdoptedChildren().filter(Filters.FEMALE);
1637
+ }
1638
+ getBirthDaughters() {
1639
+ implemented("getBirthDaughters");
1640
+ return this.getBirthChildren().filter(Filters.FEMALE);
1641
+ }
1642
+ getFosterDaughters() {
1643
+ implemented("getFosterDaughters");
1644
+ return this.getFosterChildren().filter(Filters.FEMALE);
1645
+ }
1646
+ getSealingDaughters() {
1647
+ implemented("getSealingDaughters");
1648
+ return this.getSealingChildren().filter(Filters.FEMALE);
1649
+ }
1650
+ getStepDaughters() {
1651
+ implemented("getStepDaughters");
1652
+ return this.getStepChildren().filter(Filters.FEMALE);
1653
+ }
1654
+ getParents(filter) {
1655
+ implemented("getParents");
1656
+ return this.getAscendants(1, filter);
1657
+ }
1658
+ getParentsFilteredByPedigree(filter) {
1659
+ const parents = new Individuals();
1660
+ const familiesOfParents = this.get("FAMC")?.toValueList();
1661
+ if (!familiesOfParents || !this.id) {
1662
+ return parents;
1663
+ }
1664
+ const families = this.toFamilies(familiesOfParents);
1665
+ families.forEach((family) => {
1666
+ const child = this.id && family.CHIL?.toValueList()?.item(this.id);
1667
+ if (!child) {
1668
+ const childState = this?.get("FAMC")
1669
+ ?.toList()
1670
+ ?.filter((item) => item.value === family.id)
1671
+ .index(0);
1672
+ const parentType = childState?.get("PEDI")?.toValue() ||
1673
+ RelationType.BIOLOGICAL;
1674
+ if ((!parentType && filter.PEDI === RelationType.BIOLOGICAL) ||
1675
+ parentType?.toLowerCase() === filter.PEDI.toLowerCase()) {
1676
+ parents.merge(family.getParents());
1677
+ }
1678
+ return;
1679
+ }
1680
+ const fatherType = child.get("_FREL")?.toValue();
1681
+ const motherType = child.get("_MREL")?.toValue();
1682
+ if ((!fatherType && filter.PEDI === RelationType.BIOLOGICAL) ||
1683
+ fatherType?.toLowerCase() === filter.PEDI.toLowerCase()) {
1684
+ const fatherId = family.get("HUSB")?.toValue();
1685
+ const father = fatherId && this._gedcom?.indi(fatherId);
1686
+ if (father) {
1687
+ parents.append(father);
1688
+ }
1689
+ }
1690
+ if ((!motherType && filter.PEDI === RelationType.BIOLOGICAL) ||
1691
+ motherType?.toLowerCase() === filter.PEDI.toLowerCase()) {
1692
+ const motherId = family.get("WIFE")?.toValue();
1693
+ const mother = motherId && this._gedcom?.indi(motherId);
1694
+ if (mother) {
1695
+ parents.append(mother);
1696
+ }
1697
+ }
1698
+ });
1699
+ return parents;
1700
+ }
1701
+ getSpousesFilteredByPartner(filter) {
1702
+ const spouses = new Individuals();
1703
+ const familiesOfSpouses = this.get("FAMS")?.toValueList();
1704
+ if (!familiesOfSpouses || !this.id) {
1705
+ return spouses;
1706
+ }
1707
+ const families = this.toFamilies(familiesOfSpouses);
1708
+ families.forEach((family) => {
1709
+ const spouseType = family.get("_SREL")?.toValue();
1710
+ if ((!spouseType && filter.PART === PartnerType.SPOUSE) ||
1711
+ spouseType?.toLowerCase() === filter.PART.toLowerCase()) {
1712
+ const spouse = family.getParents().copy().except(this).index(0);
1713
+ if (spouse) {
1714
+ spouses.append(spouse);
1715
+ }
1716
+ }
1717
+ });
1718
+ return spouses;
1719
+ }
1720
+ getBiologicalParents() {
1721
+ implemented("getBiologicalParents");
1722
+ return this.getParentsFilteredByPedigree(Filters.BIOLOGICAL);
1723
+ }
1724
+ getAdoptedParents() {
1725
+ implemented("getAdoptedParents");
1726
+ return this.getParentsFilteredByPedigree(Filters.ADOPTED);
1727
+ }
1728
+ getBirthParents() {
1729
+ implemented("getBirthParents");
1730
+ return this.getParentsFilteredByPedigree(Filters.BIRTH);
1731
+ }
1732
+ getFosterParents() {
1733
+ implemented("getFosterParents");
1734
+ return this.getParentsFilteredByPedigree(Filters.FOSTER);
1735
+ }
1736
+ getSealingParents() {
1737
+ implemented("getSealingParents");
1738
+ return this.getParentsFilteredByPedigree(Filters.SEALING);
1739
+ }
1740
+ getStepParents() {
1741
+ implemented("getStepParents");
1742
+ return this.getParentsFilteredByPedigree(Filters.STEP);
1743
+ }
1744
+ getFathers() {
1745
+ implemented("getFathers");
1746
+ return this.getParents().filter(Filters.MALE);
1747
+ }
1748
+ getBiologicalFathers() {
1749
+ implemented("getBiologicalFathers");
1750
+ return this.getParentsFilteredByPedigree(Filters.BIOLOGICAL).filter(Filters.MALE);
1751
+ }
1752
+ getAdoptedFathers() {
1753
+ implemented("getAdoptedFathers");
1754
+ return this.getParentsFilteredByPedigree(Filters.ADOPTED).filter(Filters.MALE);
1755
+ }
1756
+ getBirthFathers() {
1757
+ implemented("getBirthFathers");
1758
+ return this.getParentsFilteredByPedigree(Filters.BIRTH).filter(Filters.MALE);
1759
+ }
1760
+ getFosterFathers() {
1761
+ implemented("getFosterFathers");
1762
+ return this.getParentsFilteredByPedigree(Filters.FOSTER).filter(Filters.MALE);
1763
+ }
1764
+ getSealingFathers() {
1765
+ implemented("getSealingFathers");
1766
+ return this.getParentsFilteredByPedigree(Filters.SEALING).filter(Filters.MALE);
1767
+ }
1768
+ getStepFathers() {
1769
+ implemented("getStepFathers");
1770
+ return this.getParentsFilteredByPedigree(Filters.STEP).filter(Filters.MALE);
1771
+ }
1772
+ getMothers() {
1773
+ implemented("getMothers");
1774
+ return this.getParents().filter(Filters.FEMALE);
1775
+ }
1776
+ getBiologicalMothers() {
1777
+ implemented("getBiologicalMothers");
1778
+ return this.getParentsFilteredByPedigree(Filters.BIOLOGICAL).filter(Filters.FEMALE);
1779
+ }
1780
+ getAdoptedMothers() {
1781
+ implemented("getAdoptedMothers");
1782
+ return this.getParentsFilteredByPedigree(Filters.ADOPTED).filter(Filters.FEMALE);
1783
+ }
1784
+ getBirthMothers() {
1785
+ implemented("getBirthMothers");
1786
+ return this.getParentsFilteredByPedigree(Filters.BIRTH).filter(Filters.FEMALE);
1787
+ }
1788
+ getFosterMothers() {
1789
+ implemented("getFosterMothers");
1790
+ return this.getParentsFilteredByPedigree(Filters.FOSTER).filter(Filters.FEMALE);
1791
+ }
1792
+ getSealingMothers() {
1793
+ implemented("getSealingMothers");
1794
+ return this.getParentsFilteredByPedigree(Filters.SEALING).filter(Filters.FEMALE);
1795
+ }
1796
+ getStepMothers() {
1797
+ implemented("getStepMothers");
1798
+ return this.getParentsFilteredByPedigree(Filters.STEP).filter(Filters.FEMALE);
1799
+ }
1800
+ getCoParents() {
1801
+ implemented("getCoParents");
1802
+ return this.getRelativesOnLevel(0);
1803
+ }
1804
+ getSpouses() {
1805
+ implemented("getCertifiedSpouses");
1806
+ return this.getSpousesFilteredByPartner(Filters.SPOUSE);
1807
+ }
1808
+ getPartners() {
1809
+ implemented("getPartners");
1810
+ return this.getSpousesFilteredByPartner(Filters.PARTNER);
1811
+ }
1812
+ getFriends() {
1813
+ implemented("getFriends");
1814
+ return this.getSpousesFilteredByPartner(Filters.FRIEND);
1815
+ }
1816
+ getWives() {
1817
+ implemented("getWives");
1818
+ return this.getCoParents().filter(Filters.FEMALE);
1819
+ }
1820
+ getHusbands() {
1821
+ implemented("getHusbands");
1822
+ return this.getCoParents().filter(Filters.MALE);
1823
+ }
1824
+ getCousins() {
1825
+ implemented("getCousins");
1826
+ return this.getRelativesOnDegree(1);
1827
+ }
1828
+ getGrandParents() {
1829
+ implemented("getGrandParents");
1830
+ return this.getAscendants(2);
1831
+ }
1832
+ getGrandFathers() {
1833
+ implemented("getGrandFathers");
1834
+ return this.getGrandParents().filter(Filters.MALE);
1835
+ }
1836
+ getGrandMothers() {
1837
+ implemented("getGrandMothers");
1838
+ return this.getGrandParents().filter(Filters.FEMALE);
1839
+ }
1840
+ getGrandChildren() {
1841
+ implemented("getGrandChildren");
1842
+ return this.getDescendants(2);
1843
+ }
1844
+ getGrandSons() {
1845
+ implemented("getGrandSons");
1846
+ return this.getGrandChildren().filter(Filters.MALE);
1847
+ }
1848
+ getGrandDaughters() {
1849
+ implemented("getGrandDaughters");
1850
+ return this.getGrandChildren().filter(Filters.FEMALE);
1851
+ }
1852
+ getGreatGrandParents() {
1853
+ implemented("getGreatGrandParents");
1854
+ return this.getAscendants(3);
1855
+ }
1856
+ getGreatGrandFathers() {
1857
+ implemented("getGreatGrandFathers");
1858
+ return this.getGreatGrandParents().filter(Filters.MALE);
1859
+ }
1860
+ getGreatGrandMothers() {
1861
+ implemented("getGreatGrandMothers");
1862
+ return this.getGreatGrandParents().filter(Filters.FEMALE);
1863
+ }
1864
+ getGreatGrandChildren() {
1865
+ implemented("getGreatGrandChildren");
1866
+ return this.getDescendants(3);
1867
+ }
1868
+ getGreatGrandSons() {
1869
+ implemented("getGreatGrandSons");
1870
+ return this.getGreatGrandChildren().filter(Filters.MALE);
1871
+ }
1872
+ getGreatGrandDaughters() {
1873
+ implemented("getGreatGrandDaughters");
1874
+ return this.getGreatGrandChildren().filter(Filters.FEMALE);
1875
+ }
1876
+ getAuncles() {
1877
+ implemented("getAuncles");
1878
+ return this.getParents().getSiblings();
1879
+ }
1880
+ getAunts() {
1881
+ implemented("getAunts");
1882
+ return this.getAuncles().filter(Filters.FEMALE);
1883
+ }
1884
+ getUncles() {
1885
+ implemented("getUncles");
1886
+ return this.getAuncles().filter(Filters.MALE);
1887
+ }
1888
+ getNiblings() {
1889
+ implemented("getNiblings");
1890
+ return this.getSiblings().getChildren();
1891
+ }
1892
+ getNieces() {
1893
+ implemented("getNieces");
1894
+ return this.getNiblings().filter(Filters.FEMALE);
1895
+ }
1896
+ getNephews() {
1897
+ implemented("getNephews");
1898
+ return this.getNiblings().filter(Filters.MALE);
1899
+ }
1900
+ getParentsInLaw() {
1901
+ implemented("getParentsInLaw");
1902
+ return this.getCoParents().getParents();
1903
+ }
1904
+ getFathersInLaw() {
1905
+ implemented("getFathersInLaw");
1906
+ return this.getParentsInLaw().filter(Filters.MALE);
1907
+ }
1908
+ getMothersInLaw() {
1909
+ implemented("getMothersInLaw");
1910
+ return this.getParentsInLaw().filter(Filters.FEMALE);
1911
+ }
1912
+ getSiblingsInLaw() {
1913
+ implemented("getSiblingsInLaw");
1914
+ return this.getCoParents()
1915
+ .copy()
1916
+ .getSiblings()
1917
+ .copy()
1918
+ .merge(this.getSiblings().getCoParents());
1919
+ }
1920
+ getBrothersInLaw() {
1921
+ implemented("getBrothersInLaw");
1922
+ return this.getSiblingsInLaw().filter(Filters.MALE);
1923
+ }
1924
+ getSistersInLaw() {
1925
+ implemented("getSistersInLaw");
1926
+ return this.getSiblingsInLaw().filter(Filters.FEMALE);
1927
+ }
1928
+ getChildrenInLaw() {
1929
+ implemented("getChildrenInLaw");
1930
+ return this.getChildren().getCoParents();
1931
+ }
1932
+ getSonsInLaw() {
1933
+ implemented("getSonsInLaw");
1934
+ return this.getChildrenInLaw().filter(Filters.MALE);
1935
+ }
1936
+ getDaughtersInLaw() {
1937
+ implemented("getDaughtersInLaw");
1938
+ return this.getChildrenInLaw().filter(Filters.FEMALE);
1939
+ }
1940
+ // These are generated automatically
1941
+ get2ndCousins() {
1942
+ return new Individuals();
1943
+ }
1944
+ get2ndGreatGrandParents() {
1945
+ return new Individuals();
1946
+ }
1947
+ get2ndGreatGrandChildren() {
1948
+ return new Individuals();
1949
+ }
1950
+ get3rdCousins() {
1951
+ return new Individuals();
1952
+ }
1953
+ get3rdGreatGrandParents() {
1954
+ return new Individuals();
1955
+ }
1956
+ get3rdGreatGrandChildren() {
1957
+ return new Individuals();
1958
+ }
1959
+ get4thCousins() {
1960
+ return new Individuals();
1961
+ }
1962
+ get4thGreatGrandParents() {
1963
+ return new Individuals();
1964
+ }
1965
+ get4thGreatGrandChildren() {
1966
+ return new Individuals();
1967
+ }
1968
+ get5thCousins() {
1969
+ return new Individuals();
1970
+ }
1971
+ get5thGreatGrandParents() {
1972
+ return new Individuals();
1973
+ }
1974
+ get5thGreatGrandChildren() {
1975
+ return new Individuals();
1976
+ }
1977
+ get6thCousins() {
1978
+ return new Individuals();
1979
+ }
1980
+ get6thGreatGrandParents() {
1981
+ return new Individuals();
1982
+ }
1983
+ get6thGreatGrandChildren() {
1984
+ return new Individuals();
1985
+ }
1986
+ get7thCousins() {
1987
+ return new Individuals();
1988
+ }
1989
+ get7thGreatGrandParents() {
1990
+ return new Individuals();
1991
+ }
1992
+ get7thGreatGrandChildren() {
1993
+ return new Individuals();
1994
+ }
1995
+ get8thCousins() {
1996
+ return new Individuals();
1997
+ }
1998
+ get8thGreatGrandParents() {
1999
+ return new Individuals();
2000
+ }
2001
+ get8thGreatGrandChildren() {
2002
+ return new Individuals();
2003
+ }
2004
+ get9thCousins() {
2005
+ return new Individuals();
2006
+ }
2007
+ get9thGreatGrandParents() {
2008
+ return new Individuals();
2009
+ }
2010
+ get9thGreatGrandChildren() {
2011
+ return new Individuals();
2012
+ }
2013
+ }
2014
+ const generateFunctions = () => {
2015
+ const levels = [2, 3, 4, 5, 6, 7, 8, 9];
2016
+ const types = [
2017
+ ["Cousins", 0, "degree"],
2018
+ ["GreatGrandParents", 2, "level"],
2019
+ ["GreatGrandChildren", -2, "level"],
2020
+ ];
2021
+ levels.forEach((level) => {
2022
+ types.forEach(([type, starting, direction]) => {
2023
+ let validLevel;
2024
+ if (level === 2) {
2025
+ validLevel = "2nd";
2026
+ }
2027
+ else if (level === 3) {
2028
+ validLevel = "3rd";
2029
+ }
2030
+ else {
2031
+ validLevel = `${level}th`;
2032
+ }
2033
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
2034
+ Indi.prototype[`get${validLevel}${type}`] = function (filter) {
2035
+ if (direction === "level" && starting < 0) {
2036
+ return this.getRelativesOnLevel(-level + starting, filter);
2037
+ }
2038
+ else if (direction === "level" && starting > 0) {
2039
+ return this.getRelativesOnLevel(level + starting, filter);
2040
+ }
2041
+ return this.getRelativesOnDegree(level + starting);
2042
+ };
2043
+ });
2044
+ });
2045
+ };
2046
+ generateFunctions();
2047
+ export const createIndi = (gedcom, id, main, parent) => {
2048
+ return createProxy(new Indi(gedcom, id, main, parent));
2049
+ };