@treeviz/gedcom-parser 2.1.12 → 2.1.16

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.
@@ -9,11 +9,12 @@ var __export = (target, all) => {
9
9
 
10
10
  // src/kinship-translator/kinship-translator.basic.ts
11
11
  var KinshipTranslatorBasic = class {
12
- constructor(path, displayName = "givenname") {
12
+ constructor(path, displayName = "givenname", nameOrder = "first-last") {
13
13
  this.isOfSpouse = false;
14
14
  this.isSpouseOf = false;
15
15
  this._path = path;
16
16
  this.displayName = displayName;
17
+ this.nameOrder = nameOrder;
17
18
  }
18
19
  get path() {
19
20
  return this._path;
@@ -608,7 +609,7 @@ var KinshipTranslatorHU = class extends KinshipTranslatorBasic {
608
609
  }
609
610
  of(relation) {
610
611
  const formattedName = nameFormatter(this.path?.[0]?.indi, {
611
- nameOrder: "last-first"
612
+ nameOrder: this.nameOrder
612
613
  });
613
614
  let name = formattedName.inOrder.filter(Boolean).join(" ");
614
615
  if (this.displayName === "none") {
@@ -822,7 +823,7 @@ var KinshipTranslatorEn = class extends KinshipTranslatorBasic {
822
823
  }
823
824
  of(relation) {
824
825
  const formattedName = nameFormatter(this.path?.[0]?.indi, {
825
- nameOrder: "first-last"
826
+ nameOrder: this.nameOrder
826
827
  });
827
828
  let name = formattedName.inOrder.filter(Boolean).join(" ");
828
829
  if (this.displayName === "none") {
@@ -1032,7 +1033,7 @@ var KinshipTranslatorFr = class extends KinshipTranslatorBasic {
1032
1033
  }
1033
1034
  of(relation) {
1034
1035
  const formattedName = nameFormatter(this.path?.[0]?.indi, {
1035
- nameOrder: "first-last"
1036
+ nameOrder: this.nameOrder
1036
1037
  });
1037
1038
  let name = formattedName.inOrder.filter(Boolean).join(" ");
1038
1039
  if (this.displayName === "none") {
@@ -1370,7 +1371,7 @@ var KinshipTranslatorEs = class extends KinshipTranslatorBasic {
1370
1371
  }
1371
1372
  of(relation) {
1372
1373
  const formattedName = nameFormatter(this.path?.[0]?.indi, {
1373
- nameOrder: "first-last"
1374
+ nameOrder: this.nameOrder
1374
1375
  });
1375
1376
  let name = formattedName.inOrder.filter(Boolean).join(" ");
1376
1377
  if (this.displayName === "none") {
@@ -1677,7 +1678,7 @@ var KinshipTranslatorRu = class extends KinshipTranslatorBasic {
1677
1678
  }
1678
1679
  of(relation) {
1679
1680
  const formattedName = nameFormatter(this.path?.[0]?.indi, {
1680
- nameOrder: "first-last"
1681
+ nameOrder: this.nameOrder
1681
1682
  });
1682
1683
  let name = formattedName.inOrder.filter(Boolean).join(" ");
1683
1684
  if (this.displayName === "none") {
@@ -1913,7 +1914,7 @@ var KinshipTranslatorJa = class extends KinshipTranslatorBasic {
1913
1914
  }
1914
1915
  of(relation) {
1915
1916
  const formattedName = nameFormatter(this.path?.[0]?.indi, {
1916
- nameOrder: "last-first"
1917
+ nameOrder: this.nameOrder
1917
1918
  });
1918
1919
  let name = formattedName.inOrder.filter(Boolean).join(" ");
1919
1920
  if (this.displayName === "none") {
@@ -2162,7 +2163,7 @@ var KinshipTranslatorZh = class extends KinshipTranslatorBasic {
2162
2163
  }
2163
2164
  of(relation) {
2164
2165
  const formattedName = nameFormatter(this.path?.[0]?.indi, {
2165
- nameOrder: "last-first"
2166
+ nameOrder: this.nameOrder
2166
2167
  });
2167
2168
  let name = formattedName.inOrder.filter(Boolean).join(" ");
2168
2169
  if (this.displayName === "none") {
@@ -2231,22 +2232,30 @@ var KinshipTranslatorZh = class extends KinshipTranslatorBasic {
2231
2232
  };
2232
2233
 
2233
2234
  // src/kinship-translator/kinship-translator.ts
2235
+ var nameOrderForLang = (lang) => lang === "hu" || lang === "ja" || lang === "zh" ? "last-first" : "first-last";
2234
2236
  var KinshipTranslator = class {
2235
- constructor(person1, person2, lang = "en", entirePath, displayName = "givenname") {
2237
+ constructor(person1, person2, lang = "en", entirePath, displayName = "givenname", nameOrder) {
2236
2238
  this.displayName = displayName;
2237
2239
  this.lang = lang;
2238
2240
  this.entirePath = entirePath;
2239
2241
  this.person1 = person1;
2240
2242
  this.person2 = typeof person2 === "string" ? this.person1.getGedcom()?.indi(person2) : person2;
2241
2243
  this.path = this.person1.path(this.person2);
2244
+ const order = nameOrder ?? nameOrderForLang(lang);
2245
+ this.nameOrder = order;
2242
2246
  if (translators_exports[lang]) {
2243
2247
  this.translator = new translators_exports[lang](
2244
2248
  this.path ?? [],
2245
- displayName
2249
+ displayName,
2250
+ order
2246
2251
  );
2247
2252
  }
2248
2253
  if (!this.translator) {
2249
- this.translator = new KinshipTranslatorEn(this.path ?? [], displayName);
2254
+ this.translator = new KinshipTranslatorEn(
2255
+ this.path ?? [],
2256
+ displayName,
2257
+ order
2258
+ );
2250
2259
  }
2251
2260
  }
2252
2261
  get path0() {
@@ -2291,14 +2300,16 @@ var KinshipTranslator = class {
2291
2300
  showMainPerson,
2292
2301
  this.lang,
2293
2302
  false,
2294
- this.displayName
2303
+ this.displayName,
2304
+ this.nameOrder
2295
2305
  ),
2296
2306
  relative: this.path?.[index - 1]?.indi.kinship(
2297
2307
  path2.indi.id,
2298
2308
  showMainPerson,
2299
2309
  this.lang,
2300
2310
  false,
2301
- this.displayName
2311
+ this.displayName,
2312
+ this.nameOrder
2302
2313
  )
2303
2314
  }));
2304
2315
  return path;
@@ -2344,244 +2355,6 @@ var getKinshipTranslatorClass = () => {
2344
2355
  return KinshipTranslatorClass;
2345
2356
  };
2346
2357
 
2347
- // src/utils/get-all-prop.ts
2348
- var getAllProp = (indi, prop) => {
2349
- return prop && (indi?.get(prop)?.toList().values() ?? []).filter(Boolean) || [];
2350
- };
2351
-
2352
- // src/utils/date-formatter.ts
2353
- var ACCEPTED_DATE_FORMATS = [
2354
- "yyyy.MM.dd.",
2355
- "yyyy-MM-dd",
2356
- "MM/dd/yyyy"
2357
- ];
2358
- var ACCEPTED_DATE_FORMATS_REGEX = new RegExp(
2359
- `(${ACCEPTED_DATE_FORMATS.map(
2360
- (acceptedFormat) => acceptedFormat.replace(/[^.\-/]/g, "\\d")
2361
- ).join("|")})`,
2362
- "gi"
2363
- );
2364
- var commonDateFormatter = (date, format2 = "yyyy", prefix = "") => {
2365
- const formattedDate = date?.toValue(format2);
2366
- if (!formattedDate) {
2367
- return void 0;
2368
- }
2369
- return `${prefix}${formattedDate}`.trim();
2370
- };
2371
- var noteDateFormatter = (date, format2 = "yyyy", prefix = "", shortNote = true, showNote = true) => {
2372
- const rawDate = commonDateFormatter(date, format2, "");
2373
- if (!rawDate) {
2374
- return void 0;
2375
- }
2376
- const note = date?.toNote(shortNote) ?? "";
2377
- return `${prefix}${note && showNote ? i18n.t(`${note} {{date}}`, { date: rawDate }) : rawDate}`;
2378
- };
2379
- var marriageDateFormatter = (fam, showDays = false, showPlaces = false, shortNote = true, showNote = true, showDisplayTextIfNoDate = true, showAllEvents = false, dateFormatPattern) => {
2380
- const fullDateFormat = i18n.t("dateFormat");
2381
- const marriageDates = [];
2382
- const marriagePlaces = [];
2383
- const marriages = (fam?.toValueList().values() ?? []).flatMap((fam2) => {
2384
- const family = fam2;
2385
- const marrEvents = (family?.MARR?.toList().values() ?? []).filter(
2386
- Boolean
2387
- );
2388
- if (marrEvents.length === 0) {
2389
- const displayText = family?.get("DISPLAYTEXT")?.toValue() ?? "";
2390
- if (showDisplayTextIfNoDate && displayText) {
2391
- const displayDate = displayText.match(
2392
- ACCEPTED_DATE_FORMATS_REGEX
2393
- )?.[0];
2394
- if (displayDate) {
2395
- marriagePlaces.push(displayText.replace(displayDate, ""));
2396
- const marriageDate = createCommonDate(
2397
- fam2?.getGedcom(),
2398
- void 0,
2399
- family
2400
- );
2401
- marriageDate.value = displayDate;
2402
- marriageDates.push(marriageDate);
2403
- } else {
2404
- marriagePlaces.push(displayText);
2405
- marriageDates.push(void 0);
2406
- return ["\u221E"];
2407
- }
2408
- }
2409
- return [];
2410
- }
2411
- const eventsToProcess = showAllEvents ? marrEvents : marrEvents.slice(0, 1);
2412
- return eventsToProcess.map((marrEvent) => {
2413
- const marriageEventDetail = marrEvent;
2414
- const marriageDate = marriageEventDetail?.DATE;
2415
- const marriagePlace = showPlaces ? marriageEventDetail?.PLAC?.value : void 0;
2416
- marriagePlaces.push(marriagePlace);
2417
- marriageDates.push(marriageDate);
2418
- const formattedDate = noteDateFormatter(
2419
- marriageDate,
2420
- showDays ? fullDateFormat : "yyyy",
2421
- "\u221E",
2422
- shortNote,
2423
- showNote
2424
- );
2425
- return formattedDate ? formattedDate : void 0;
2426
- });
2427
- });
2428
- const marriageArray = marriages.length ? marriages.filter(Boolean) : [];
2429
- const datesArray = marriageArray.filter(Boolean);
2430
- const placesArray = marriagePlaces.filter(Boolean);
2431
- const dates = datesArray.join(" ").trim();
2432
- return {
2433
- rawArray: marriageDates,
2434
- inArray: datesArray,
2435
- inOrder: dates,
2436
- places: placesArray,
2437
- marriage: marriageArray,
2438
- ...showPlaces ? {
2439
- marriages,
2440
- marriagePlaces
2441
- } : {}
2442
- };
2443
- };
2444
- var dateFormatter = (indi, showMarriages = false, showDays = false, showPlaces = false, shortNote = true, showNote = true, isOnStage, showAllEvents = false, dateFormatPattern) => {
2445
- const fullDateFormat = i18n.t("dateFormat");
2446
- const birthEvents = getAllProp(indi, "BIRT");
2447
- const firstBirthValue = birthEvents[0];
2448
- const deathEvents = getAllProp(indi, "DEAT");
2449
- const firstDeathValue = deathEvents[0];
2450
- const birth = commonDateFormatter(
2451
- firstBirthValue?.DATE,
2452
- showDays ? fullDateFormat : "yyyy"
2453
- );
2454
- const birthPlace = showPlaces ? firstBirthValue?.PLAC?.value : void 0;
2455
- const death = commonDateFormatter(
2456
- firstDeathValue?.DATE,
2457
- showDays ? fullDateFormat : "yyyy"
2458
- );
2459
- const deathPlace = showPlaces ? firstDeathValue?.PLAC?.value : void 0;
2460
- const marriagePlaces = [];
2461
- const marriages = [];
2462
- if (showMarriages || isOnStage) {
2463
- (indi?.get("FAMS")?.toValueList().values() ?? []).forEach((fam) => {
2464
- const famRef = fam?.ref;
2465
- const marriageDates = marriageDateFormatter(
2466
- famRef,
2467
- showDays,
2468
- showPlaces,
2469
- shortNote,
2470
- showNote,
2471
- true,
2472
- showAllEvents);
2473
- marriages.push(...marriageDates?.marriage ?? []);
2474
- marriagePlaces.push(...marriageDates?.marriagePlaces ?? []);
2475
- });
2476
- }
2477
- const birthStrings = [];
2478
- const birthPlaces = [];
2479
- const eventsToProcess = showAllEvents ? birthEvents : birthEvents.slice(0, 1);
2480
- eventsToProcess.forEach((birthEvent) => {
2481
- const birthDate = commonDateFormatter(
2482
- birthEvent?.DATE,
2483
- showDays ? fullDateFormat : "yyyy"
2484
- );
2485
- const birthEventNote = birthEvent?.DATE?.toNote(shortNote) ?? "";
2486
- const birthEventPlace = showPlaces ? birthEvent?.PLAC?.value : void 0;
2487
- if (birthDate) {
2488
- birthStrings.push(
2489
- `*${birthEventNote && showNote ? i18n.t(`${birthEventNote} {{date}}`, {
2490
- date: birthDate
2491
- }) : birthDate}`
2492
- );
2493
- }
2494
- birthPlaces.push(birthEventPlace);
2495
- });
2496
- const deathStrings = [];
2497
- const deathPlaces = [];
2498
- const deathEventsToProcess = showAllEvents ? deathEvents : deathEvents.slice(0, 1);
2499
- deathEventsToProcess.forEach((deathEvent) => {
2500
- const deathDate = commonDateFormatter(
2501
- deathEvent?.DATE,
2502
- showDays ? fullDateFormat : "yyyy"
2503
- );
2504
- const deathEventNote = deathEvent?.DATE?.toNote(shortNote) ?? "";
2505
- const deathEventPlace = showPlaces ? deathEvent?.PLAC?.value : void 0;
2506
- if (deathDate) {
2507
- deathStrings.push(
2508
- `\u2020${deathEventNote && showNote ? i18n.t(`${deathEventNote} {{date}}`, {
2509
- date: deathDate
2510
- }) : deathDate}`
2511
- );
2512
- }
2513
- deathPlaces.push(deathEventPlace);
2514
- });
2515
- const birthString = birthStrings[0] ?? "";
2516
- const deathString = deathStrings[0] ?? "";
2517
- const marriageArray = marriages.length ? marriages.filter(Boolean) : [];
2518
- const datesArray = !birth && !death ? marriageArray : [...birthStrings, ...marriageArray, ...deathStrings];
2519
- const placesArray = !birth && !death ? marriagePlaces : [...birthPlaces, ...marriagePlaces, ...deathPlaces];
2520
- const nonNullDatesArray = datesArray.filter(Boolean);
2521
- const dates = nonNullDatesArray.join(" ").trim();
2522
- return {
2523
- inArray: nonNullDatesArray,
2524
- inOrder: dates,
2525
- places: placesArray,
2526
- birth: birthString,
2527
- marriage: marriageArray,
2528
- death: deathString,
2529
- ...showPlaces ? {
2530
- birthPlace,
2531
- deathPlace,
2532
- ...showMarriages ? { marriages, marriagePlaces } : {}
2533
- } : {},
2534
- ...showAllEvents ? {
2535
- births: birthStrings,
2536
- birthPlaces,
2537
- deaths: deathStrings,
2538
- deathPlaces
2539
- } : {}
2540
- };
2541
- };
2542
-
2543
- // src/utils/range.ts
2544
- var toTuple = (r) => {
2545
- if (Array.isArray(r)) {
2546
- const [s2, e2] = r;
2547
- return [
2548
- s2 === void 0 ? void 0 : Number(s2),
2549
- e2 === void 0 ? void 0 : Number(e2)
2550
- ];
2551
- }
2552
- if (r === "-" || r === "") return [void 0, void 0];
2553
- const [s, e] = r.split("-");
2554
- return [s ? Number(s) : void 0, e ? Number(e) : void 0];
2555
- };
2556
- var isValidRange = (range) => {
2557
- if (!Array.isArray(range) && range !== "" && range !== "-" && !/^\d*-\d*$/.test(range)) {
2558
- return false;
2559
- }
2560
- if (Array.isArray(range) && range.some((r) => typeof r === "string" && isNaN(Number(r)))) {
2561
- return false;
2562
- }
2563
- return true;
2564
- };
2565
- var inRange = (year, range, trueIfNoYear = false) => {
2566
- if (!isValidRange(range)) {
2567
- return false;
2568
- }
2569
- if (!year) {
2570
- return trueIfNoYear;
2571
- }
2572
- const [start = -Infinity, end = Infinity] = toTuple(range);
2573
- if (!start && !end) {
2574
- return true;
2575
- }
2576
- if (start && !end) {
2577
- return Number(year) >= Number(start);
2578
- }
2579
- if (!start && end) {
2580
- return Number(year) <= Number(end);
2581
- }
2582
- return Number(start) <= Number(year) && Number(year) <= Number(end);
2583
- };
2584
-
2585
2358
  // src/constants/constants.ts
2586
2359
  var ID_REG = /^@[_a-zA-Z0-9]+@/;
2587
2360
  var ID_GETTER_REG = /^(?<at>@)?(?<letter>[A-Z])?/i;
@@ -2666,1087 +2439,1355 @@ var objeXrefKey = (obje, fallback = 0) => {
2666
2439
  return `@O${fallback}@`;
2667
2440
  };
2668
2441
  var objeNoteValue = (obje) => mediaIdValue(obje, "FILE.NOTE") || mediaIdValue(obje, "NOTE") || "";
2669
- var List = class _List {
2670
- // length = 0;
2671
- constructor(items) {
2672
- this.items = {};
2442
+
2443
+ // src/classes/common.ts
2444
+ var Common = class _Common {
2445
+ constructor(gedcom, id, main, parent) {
2673
2446
  this.isListable = true;
2674
- this.marker = void 0;
2675
- if (items) {
2676
- this.concat(items);
2447
+ this._gedcom = gedcom;
2448
+ this._main = main;
2449
+ this._parent = parent;
2450
+ this.initUniqueId();
2451
+ if (id) {
2452
+ this._id = id;
2453
+ } else {
2454
+ delete this._id;
2677
2455
  }
2678
2456
  }
2679
- get length() {
2680
- return this.values().length;
2681
- }
2682
- has(indi) {
2683
- return !!this.item(
2684
- typeof indi === "string" ? indi : indi?.id ?? ""
2685
- );
2457
+ set type(type) {
2458
+ if (type) {
2459
+ this.uniqueId = this.uniqueId?.replace(/^[^:]+/, `~${type}`);
2460
+ }
2461
+ this._type = type;
2686
2462
  }
2687
- get(name) {
2688
- const propList = new _List();
2689
- this.entries().forEach(([key, item]) => {
2690
- propList.item(key, item.get(name));
2691
- });
2692
- return propList;
2463
+ get type() {
2464
+ return this._type;
2693
2465
  }
2694
- getIf(name, condition, name2) {
2695
- const propList = new _List();
2696
- this.entries().forEach(([key, item]) => {
2697
- const passedItem = item.getIf(name, condition, name2);
2698
- if (passedItem) {
2699
- propList.item(key, passedItem);
2466
+ initUniqueId() {
2467
+ if (this._gedcom) {
2468
+ this.uniqueId = `~Common:${this._gedcom.refcount++}`;
2469
+ }
2470
+ }
2471
+ set uniqueId(id) {
2472
+ const currentId = this._uniqueId;
2473
+ if (this._gedcom?.reflist && id) {
2474
+ this._uniqueId = id;
2475
+ if (currentId && this._gedcom.reflist[currentId]) {
2476
+ delete this._gedcom.reflist[currentId];
2700
2477
  }
2701
- });
2702
- return propList;
2478
+ this._gedcom.reflist[id] = this;
2479
+ }
2703
2480
  }
2704
- keys() {
2705
- return Object.keys(this.items);
2481
+ get uniqueId() {
2482
+ return this._uniqueId;
2706
2483
  }
2707
- values() {
2708
- return Object.values(this.items);
2484
+ set id(id) {
2485
+ this._id = idGetter(id);
2709
2486
  }
2710
- entries() {
2711
- return Object.entries(this.items);
2487
+ get id() {
2488
+ return idGetter(this._id);
2712
2489
  }
2713
- setLength(_type) {
2490
+ set value(value) {
2491
+ this._value = value;
2714
2492
  }
2715
- first() {
2716
- return this.index(0);
2493
+ get value() {
2494
+ return this._value;
2717
2495
  }
2718
- last() {
2719
- return this.index(this.keys().length - 1);
2496
+ /**
2497
+ * Set the gedcom reference for this object
2498
+ * @param gedcom - The GedComType to set as the gedcom reference
2499
+ */
2500
+ setGedcom(gedcom) {
2501
+ this._gedcom = gedcom;
2720
2502
  }
2721
- index(index) {
2722
- const keys = this.keys();
2723
- const key = keys[index];
2724
- return key && this.items[key];
2503
+ // avoid to override
2504
+ get originalValue() {
2505
+ return this._value;
2725
2506
  }
2726
- item(name, value) {
2727
- if (arguments.length > 1) {
2728
- set(this.items, name, value);
2729
- this.setLength();
2507
+ get ref() {
2508
+ if (typeof this.value === "string" && isId(this.value) && this.refType) {
2509
+ return this._gedcom?.[getListTag(this.refType)]?.item(
2510
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2511
+ this.value
2512
+ );
2730
2513
  }
2731
- return get(this.items, name);
2514
+ return this;
2732
2515
  }
2733
- removeItem(name) {
2734
- unset(this.items, name);
2735
- this.setLength();
2516
+ get main() {
2517
+ return this._main;
2736
2518
  }
2737
- exclude(excludedList) {
2738
- excludedList.keys().forEach((itemId) => {
2739
- delete this.items[itemId];
2740
- });
2741
- this.setLength();
2742
- return this;
2519
+ get parent() {
2520
+ return this._parent;
2743
2521
  }
2744
- concat(items) {
2745
- if (Array.isArray(items)) {
2746
- items.forEach((item) => {
2747
- this.append(item);
2748
- });
2749
- } else {
2750
- Object.assign(this.items, items ?? {});
2522
+ addRef(refNode) {
2523
+ if (typeof refNode.value === "string" && isId(refNode.value) && refNode.refType) {
2524
+ if (!this._refs) {
2525
+ this._refs = new List();
2526
+ }
2527
+ this._refs.item(refNode.value, refNode);
2751
2528
  }
2752
- this.setLength();
2753
- return this;
2754
2529
  }
2755
- merge(mergedList) {
2756
- this.concat(mergedList?.items);
2757
- return this;
2530
+ getRefs() {
2531
+ return this._refs;
2758
2532
  }
2759
- intersection(mergedList) {
2760
- const inter = intersectionBy(
2761
- this.values(),
2762
- mergedList?.values() ?? [],
2763
- "id"
2764
- );
2765
- return new _List(inter);
2533
+ exportValue() {
2534
+ return this.value;
2766
2535
  }
2767
- difference(mergedList) {
2768
- const inter = differenceBy(
2769
- this.values(),
2770
- mergedList?.values() ?? [],
2771
- "id"
2772
- );
2773
- return new _List(inter);
2536
+ removeValue() {
2537
+ delete this._value;
2774
2538
  }
2775
- prepend(item) {
2776
- if (item.id) {
2777
- let increase = true;
2778
- if (this.items[item.id]) {
2779
- delete this.items[item.id];
2780
- increase = false;
2781
- }
2782
- this.items = Object.assign(
2783
- {
2784
- [item.id]: item
2785
- },
2786
- this.items
2787
- );
2788
- if (increase) {
2789
- this.setLength("increase");
2790
- }
2539
+ set(name, value) {
2540
+ if (isGedcomTrailerTag(name)) {
2541
+ return void 0;
2791
2542
  }
2792
- return this;
2543
+ if (typeof value === "string") {
2544
+ const usedValue = createCommon(this._gedcom, void 0, this.main);
2545
+ usedValue.value = value;
2546
+ set(this, name, usedValue);
2547
+ } else {
2548
+ set(this, name, value);
2549
+ }
2550
+ return get(this, name);
2793
2551
  }
2794
- append(item) {
2795
- if (item.id) {
2796
- let increase = true;
2797
- if (this.items[item.id]) {
2798
- delete this.items[item.id];
2799
- increase = false;
2800
- }
2801
- this.items[item.id] = item;
2802
- if (increase) {
2803
- this.setLength("increase");
2552
+ assign(name, value, unique = false) {
2553
+ if (isGedcomTrailerTag(name)) {
2554
+ return void 0;
2555
+ }
2556
+ let curValue = this.get(name);
2557
+ if (curValue?.isListable) {
2558
+ if (curValue instanceof _Common) {
2559
+ curValue = new List().concat({ ...[curValue] });
2560
+ this.set(name, curValue);
2804
2561
  }
2562
+ const values = [
2563
+ ...curValue.values(),
2564
+ ...value instanceof List ? value.values() : [value]
2565
+ ];
2566
+ curValue.concat({
2567
+ ...!unique ? values : uniqBy(
2568
+ values,
2569
+ (value2) => value2 instanceof _Common ? value2?.value : void 0
2570
+ )
2571
+ });
2572
+ } else {
2573
+ this.set(name, value);
2805
2574
  }
2806
- return this;
2575
+ return get(this, name);
2807
2576
  }
2808
- delete(item) {
2809
- if (item.id && this.items[item.id]) {
2810
- delete this.items[item.id];
2811
- this.setLength("decrease");
2577
+ get(name) {
2578
+ if (!name.includes(".")) {
2579
+ return get(this, name);
2812
2580
  }
2813
- return this;
2814
- }
2815
- copy(ClassName = _List) {
2816
- const newList = new ClassName();
2817
- Object.assign(newList.items, this.items);
2818
- newList.setLength();
2819
- return newList;
2820
- }
2821
- except(item, ClassName = _List) {
2822
- return this.copy(ClassName).delete(item);
2581
+ const nameParts = name.split(".");
2582
+ let last = this;
2583
+ for (const part of nameParts) {
2584
+ const indexPart = Number(part);
2585
+ const itemIndex = part.match(/items\[(?<itemIndex>\d+)\]/)?.groups?.itemIndex;
2586
+ const itemId = part.match(/items\[(?<itemId>@[A-Z]+\d+@)\]/)?.groups?.itemId;
2587
+ const usedPart = itemId || itemIndex;
2588
+ if (last instanceof List) {
2589
+ if (!isNaN(indexPart)) {
2590
+ last = last.index(indexPart);
2591
+ } else {
2592
+ if (usedPart) {
2593
+ last = last.item(usedPart);
2594
+ } else {
2595
+ last = last?.index(0)?.get(part);
2596
+ }
2597
+ }
2598
+ } else {
2599
+ const usedIndex = Number(itemIndex ?? indexPart);
2600
+ if (!isNaN(usedIndex)) {
2601
+ last = last?.toList().index(usedIndex);
2602
+ } else {
2603
+ last = last?.get(itemId ?? part);
2604
+ }
2605
+ }
2606
+ if (!last) {
2607
+ break;
2608
+ }
2609
+ }
2610
+ return last;
2823
2611
  }
2824
- forEach(iterate) {
2825
- this.entries().forEach(([key, item], index) => {
2826
- iterate(item, key, index);
2827
- });
2612
+ remove(name) {
2613
+ unset(this, name);
2828
2614
  }
2829
- map(iterate) {
2830
- return this.entries().map(([key, item], index) => {
2831
- return iterate(item, key, index);
2832
- });
2615
+ getGedcom() {
2616
+ return this._gedcom;
2833
2617
  }
2834
- reduce(iterate, initialValue) {
2835
- return this.entries().reduce((acc, [key, item], index) => {
2836
- return iterate(acc, item, key, index);
2837
- }, initialValue);
2618
+ getIf(name, condition, name2) {
2619
+ const nameParts = name.split(".");
2620
+ const name2Parts = name2.split(".");
2621
+ if (nameParts.length !== name2Parts.length) {
2622
+ throw new Error("Tag pathes must be of the same depth");
2623
+ }
2624
+ if (nameParts.length > 1 && nameParts[0] !== name2Parts[0]) {
2625
+ throw new Error("Final tags must be siblings");
2626
+ }
2627
+ const valueCommon = this.get(name);
2628
+ if (valueCommon instanceof _Common) {
2629
+ return valueCommon?.toValue() !== condition ? void 0 : this.get(name2);
2630
+ }
2631
+ const valueCommon2 = this.get(name2)?.toList();
2632
+ const ifList = new List();
2633
+ valueCommon?.forEach((item, key) => {
2634
+ const pair = valueCommon2?.item(key);
2635
+ ifList.item(key, item?.toValue() !== condition ? void 0 : pair);
2636
+ });
2637
+ return ifList;
2838
2638
  }
2839
- filter(filters, ClassName = _List) {
2840
- const newList = new ClassName();
2841
- const isIterator = typeof filters === "function";
2842
- this.entries().forEach(([itemId, item], index) => {
2843
- if (isIterator) {
2844
- filters(item, itemId, index) && newList.item(itemId, item);
2639
+ toString() {
2640
+ return this.value?.toString() || "";
2641
+ }
2642
+ toValue() {
2643
+ return this.value;
2644
+ }
2645
+ toProp(tag) {
2646
+ const prop = this.get(tag);
2647
+ return prop;
2648
+ }
2649
+ toList() {
2650
+ return new List().concat(
2651
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2652
+ this.id ? { [this.id]: this } : { ...[this] }
2653
+ );
2654
+ }
2655
+ index(i) {
2656
+ return this.toList()?.index(i);
2657
+ }
2658
+ toValueList() {
2659
+ return new List().concat(
2660
+ this.value ? { [this.value]: this } : (
2661
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2662
+ { ...[this] }
2663
+ )
2664
+ );
2665
+ }
2666
+ standardizeObject(tag, options) {
2667
+ if (tag === "OBJE" && options?.obje?.standardize && "standardizeMedia" in this) {
2668
+ const standardize = this.standardizeMedia;
2669
+ return standardize.call(
2670
+ this,
2671
+ options.obje.namespace,
2672
+ options.obje.override,
2673
+ this.isAncestry() ? ancestryMediaFileUrl : void 0,
2674
+ options.gedcomVersion
2675
+ );
2676
+ }
2677
+ }
2678
+ toJson(tag, options) {
2679
+ const json = this.toObject(tag, options);
2680
+ return JSON.stringify(json);
2681
+ }
2682
+ toObject(tag, options) {
2683
+ this.standardizeObject(tag, options);
2684
+ const validKeys = getValidKeys(this);
2685
+ let json = {};
2686
+ validKeys.forEach((key) => {
2687
+ if (options?.persist && (key === "DAY" || key === "MONTH" || key === "YEAR")) {
2845
2688
  return;
2846
2689
  }
2847
- if (!Object.keys(filters).length || Object.entries(filters).every(([key, value]) => {
2848
- let itemValue;
2849
- if (key === "id") {
2850
- itemValue = item.toProp("id");
2851
- } else {
2852
- itemValue = item.toProp(key)?.toValue();
2853
- }
2854
- if (Array.isArray(value)) {
2855
- return value.includes(itemValue);
2690
+ if (key === "id" && this.id !== void 0) {
2691
+ json.id = this.id;
2692
+ } else if (key === "_id" && this._id !== void 0) {
2693
+ json.id = this._id;
2694
+ } else if (key === "value" && this.value !== void 0) {
2695
+ json.value = this.value;
2696
+ } else if (key === "_value" && this._value !== void 0) {
2697
+ json.value = this._value;
2698
+ } else {
2699
+ const validKey = key;
2700
+ const prop = this.get(validKey);
2701
+ if (typeof prop?.toObject === "function") {
2702
+ if (prop instanceof _Common) {
2703
+ json[validKey] = prop.toObject(validKey, options);
2704
+ } else if (prop instanceof List) {
2705
+ json = {
2706
+ ...json,
2707
+ ...prop.toObject(validKey, options)
2708
+ };
2709
+ }
2856
2710
  }
2857
- return itemValue === value;
2858
- })) {
2859
- newList.item(itemId, item);
2860
2711
  }
2861
2712
  });
2862
- return newList;
2713
+ return json;
2863
2714
  }
2864
- find(filters, _ClassName = _List) {
2865
- let foundItem;
2866
- const isIterator = typeof filters === "function";
2867
- this.entries().find(([itemId, item], index) => {
2868
- if (isIterator) {
2869
- if (filters(item, itemId, index)) {
2870
- foundItem = item;
2871
- return true;
2872
- }
2873
- return false;
2715
+ merge(other, override = false, avoidKeys = []) {
2716
+ if (!other) {
2717
+ return this;
2718
+ }
2719
+ const validKeys = getValidKeys(other);
2720
+ validKeys.forEach((validKey) => {
2721
+ if (avoidKeys.includes(validKey)) {
2722
+ return;
2874
2723
  }
2875
- if (!Object.keys(filters).length || Object.entries(filters).every(([key, value]) => {
2876
- let itemValue;
2877
- if (key === "id") {
2878
- itemValue = item.toProp("id");
2879
- } else {
2880
- itemValue = item.toProp(key)?.toValue();
2881
- }
2882
- if (Array.isArray(value)) {
2883
- return value.includes(itemValue);
2724
+ const current = this.get(validKey);
2725
+ const mergeValue = other.get(validKey);
2726
+ if (mergeValue) {
2727
+ if (current instanceof _Common && !current.isListable) {
2728
+ if (override) {
2729
+ this.set(validKey, mergeValue);
2730
+ }
2731
+ } else if (current instanceof _Common || current instanceof List) {
2732
+ this.assign(validKey, mergeValue, true);
2733
+ } else if (!current || override && validKey !== "id" && validKey !== "_id") {
2734
+ this.set(validKey, mergeValue);
2884
2735
  }
2885
- return itemValue === value;
2886
- })) {
2887
- foundItem = item;
2888
- return true;
2889
2736
  }
2890
- return false;
2891
2737
  });
2892
- return foundItem;
2738
+ return this;
2893
2739
  }
2894
- orderBy(orders, ClassName = _List) {
2895
- const newList = new ClassName();
2896
- const isIterator = typeof orders === "function";
2897
- if (!isIterator && (!orders || !Object.keys(orders).length)) {
2898
- return newList.merge(this);
2740
+ clone(newId = false, avoidKeys = []) {
2741
+ const ctor = this.constructor;
2742
+ const instance = new ctor(
2743
+ this._gedcom,
2744
+ this._id,
2745
+ this._main,
2746
+ this._parent
2747
+ );
2748
+ if (newId && this._id) {
2749
+ instance.id = `IFT${this._id.replace(/[^0-9]/g, "")}`;
2899
2750
  }
2900
- const sortedItems = this.entries().toSorted(
2901
- ([itemAId, itemA], [itemBId, itemB]) => {
2902
- if (isIterator) {
2903
- return orders(itemA, itemAId, itemB, itemBId);
2904
- }
2905
- const [key, { direction, getter }] = Object.entries(
2906
- typeof orders === "string" ? { [orders]: { direction: "ASC" } } : orders
2907
- )[0];
2908
- const rawA = itemA.get(key);
2909
- const rawB = itemB.get(key);
2910
- let valueA = rawA?.toValue();
2911
- let valueB = rawB?.toValue();
2912
- if (getter && typeof getter === "function") {
2913
- valueA = getter(valueA, rawA);
2914
- valueB = getter(valueB, rawB);
2915
- }
2916
- let sortValue = 0;
2917
- if (!valueA && valueA !== 0 && !valueB && valueB !== 0) {
2918
- sortValue = 0;
2919
- } else if (!valueB && valueB !== 0) {
2920
- sortValue = 1;
2921
- } else if (!valueA && valueA !== 0) {
2922
- sortValue = -1;
2923
- } else if (valueA < valueB) {
2924
- sortValue = -1;
2925
- } else if (valueA > valueB) {
2926
- sortValue = 1;
2751
+ const cloned = createProxy(instance);
2752
+ cloned.merge(this, true, avoidKeys);
2753
+ return cloned;
2754
+ }
2755
+ // fromGedcom<T = typeof this>(value: string) {
2756
+ fromGedcom(_value) {
2757
+ }
2758
+ toGedcom(tag, level = 0, options) {
2759
+ const gedcom = this.toGedcomLines(tag, level, options);
2760
+ return gedcom.join("\n");
2761
+ }
2762
+ toGedcomLines(tag, level = 0, options) {
2763
+ this.standardizeObject(tag, options);
2764
+ const validKeys = getValidKeys(this);
2765
+ const gedcom = [];
2766
+ const isGedcom7Export = options?.gedcomVersion === "7.0";
2767
+ validKeys.forEach((key) => {
2768
+ const validKey = key;
2769
+ if (isGedcom7Export && validKey === "CONC") {
2770
+ return;
2771
+ }
2772
+ const prop = this.get(validKey);
2773
+ if (typeof prop?.toGedcomLines === "function") {
2774
+ if (prop instanceof _Common) {
2775
+ const value = prop.exportValue();
2776
+ gedcom.push(
2777
+ `${level} ${validKey}${value ? ` ${value}` : ""}`
2778
+ );
2779
+ gedcom.push(
2780
+ ...prop.toGedcomLines(validKey, level + 1, options)
2781
+ );
2782
+ } else if (prop instanceof List) {
2783
+ gedcom.push(
2784
+ ...prop.toGedcomLines(validKey, level, options)
2785
+ );
2927
2786
  }
2928
- return sortValue * (direction === "DESC" ? -1 : 1);
2929
2787
  }
2930
- );
2931
- sortedItems.forEach(([key, value]) => {
2932
- newList.item(key, value);
2933
2788
  });
2934
- return newList;
2789
+ return gedcom;
2935
2790
  }
2936
- groupBy(groups, sort, minOccurance = -1, lessOccuranceLabel = "Appearing less than 5 times", ClassName = _List) {
2937
- const groupped = {};
2938
- const isIterator = typeof groups === "function";
2939
- if (!isIterator && (!groups || !Object.keys(groups).length)) {
2940
- groupped.Unknown = new ClassName().merge(this);
2941
- groupped.Unknown.marker = "Unknown";
2942
- return groupped;
2943
- }
2944
- this.forEach((item, itemId) => {
2945
- const group = [];
2946
- if (isIterator) {
2947
- const newGroups = groups(item, itemId);
2948
- group.push(
2949
- ...Array.isArray(newGroups) ? newGroups : [newGroups]
2950
- );
2951
- } else {
2952
- const [key, { getter }] = Object.entries(
2953
- typeof groups === "string" ? { [groups]: {} } : groups
2954
- )[0];
2955
- const raw = item.get(key)?.index(0);
2956
- let value = raw?.toValue();
2957
- if (getter && typeof getter === "function") {
2958
- value = getter(value, raw);
2959
- }
2960
- if (value) {
2961
- group.push(value);
2962
- }
2963
- }
2964
- if (!group.length) {
2965
- group.push("Unknown");
2966
- }
2967
- group.forEach((g) => {
2968
- const newGroup = typeof g === "string" ? { group: g } : g;
2969
- if (!groupped[newGroup.group]) {
2970
- groupped[newGroup.group] = new ClassName();
2971
- groupped[newGroup.group].marker = newGroup.marker ?? newGroup.group;
2972
- }
2973
- groupped[newGroup.group]?.append(item);
2974
- });
2975
- });
2976
- if (sort) {
2977
- return Object.entries(groupped).toSorted(([ak, a], [bk, b]) => {
2978
- if (typeof sort === "function") {
2979
- return sort(a, ak, b, bk);
2980
- }
2981
- if (ak === "Unknown") {
2982
- return 1;
2983
- }
2984
- if (bk === "Unknown") {
2985
- return -1;
2986
- }
2987
- if (sort === "group") {
2988
- return ak.localeCompare(bk);
2989
- }
2990
- return (b?.length ?? 0) - (a?.length ?? 0);
2991
- }).reduce((acc, [key, value]) => {
2992
- if (minOccurance > -1 && (value?.length ?? 0) < minOccurance) {
2993
- const otherKey = lessOccuranceLabel;
2994
- acc[otherKey] = acc[otherKey] && value ? acc[otherKey].merge(value) : value;
2995
- } else {
2996
- acc[key] = value;
2997
- }
2998
- return acc;
2999
- }, {});
3000
- }
3001
- return groupped;
3002
- }
3003
- findIndex(item) {
3004
- if (!item?.id) {
3005
- return -1;
3006
- }
3007
- return this.keys().findIndex((key) => key === item.id);
2791
+ getHeadRecord() {
2792
+ return get(this, "HEAD") || get(this.getGedcom(), "HEAD");
3008
2793
  }
3009
- getItems() {
3010
- return this.items;
2794
+ getOriginalHeadRecord() {
2795
+ return get(this, ORIG_HEAD_TAG) || get(this.getGedcom(), ORIG_HEAD_TAG) || get(this.getHeadRecord(), ORIG_HEAD_TAG);
3011
2796
  }
3012
- toJson(tag, options) {
3013
- const json = this.toObject(tag, options);
3014
- return JSON.stringify(json);
2797
+ getSourceHeads() {
2798
+ const heads = [this.getOriginalHeadRecord(), this.getHeadRecord()];
2799
+ return heads.filter((head, index) => {
2800
+ return Boolean(head && heads.indexOf(head) === index);
2801
+ });
3015
2802
  }
3016
- toObject(tag, options) {
3017
- const json = {};
3018
- this.entries().forEach(([_, item]) => {
3019
- const validTag = getValidTag(tag);
3020
- if (json[validTag]) {
3021
- if (!Array.isArray(json[validTag])) {
3022
- json[validTag] = [json[validTag]];
3023
- }
3024
- json[validTag].push(
3025
- item.toObject(validTag, options)
3026
- );
3027
- } else {
3028
- json[validTag] = item.toObject(
3029
- validTag,
3030
- options
3031
- );
2803
+ getFromSourceHeads(path) {
2804
+ for (const head of this.getSourceHeads()) {
2805
+ const value = get(head, path);
2806
+ if (value !== void 0 && value !== null && value !== "") {
2807
+ return value;
3032
2808
  }
2809
+ }
2810
+ return void 0;
2811
+ }
2812
+ sourStartsWith(prefix) {
2813
+ return this.getSourceHeads().some((head) => {
2814
+ const sour = get(head, "SOUR.value");
2815
+ return !!sour?.toLowerCase()?.startsWith(prefix);
3033
2816
  });
3034
- return json;
3035
2817
  }
3036
- toGedcom(tag, level = 0, options) {
3037
- const gedcom = this.toGedcomLines(tag, level, options);
3038
- return gedcom.join("\n");
2818
+ isGenoPro() {
2819
+ return this.sourStartsWith("genopro");
3039
2820
  }
3040
- toGedcomLines(tag, level = 0, options) {
3041
- const gedcom = [];
3042
- this.entries().forEach(([_, item]) => {
3043
- const validTag = getValidTag(tag);
3044
- const xref = item.id;
3045
- const payload = item.exportValue?.();
3046
- if (xref) {
3047
- gedcom.push(
3048
- `${level} ${xref} ${validTag}${payload ? ` ${payload}` : ""}`
3049
- );
3050
- } else {
3051
- gedcom.push(
3052
- `${level} ${validTag}${payload ? ` ${payload}` : ""}`
3053
- );
3054
- }
3055
- gedcom.push(
3056
- ...item.toGedcomLines(
3057
- validTag,
3058
- level + 1,
3059
- options
3060
- )
3061
- );
3062
- });
3063
- return gedcom;
2821
+ isAhnenblatt() {
2822
+ return this.sourStartsWith("ahnenblatt");
3064
2823
  }
3065
- toValue() {
3066
- const propList = new _List();
3067
- this.entries().forEach(([key, item]) => {
3068
- propList.item(key, item?.toValue());
3069
- });
3070
- return propList;
2824
+ isGeni() {
2825
+ return this.sourStartsWith("geni");
3071
2826
  }
3072
- // @deprecated use get instead
3073
- toProp(tag) {
3074
- return this.get(tag);
2827
+ isAncestry() {
2828
+ return this.sourStartsWith("ancestry");
3075
2829
  }
3076
- toList() {
3077
- return new _List().concat(this.items);
2830
+ isMyHeritage() {
2831
+ return this.sourStartsWith("myheritage");
3078
2832
  }
3079
- toValueList() {
3080
- const newList = new _List();
3081
- this.values().forEach((value) => {
3082
- value.value && newList.item(value.value, value);
2833
+ /**
2834
+ * Get the source type as a string (for prefixing tree IDs and names)
2835
+ * Returns the detected source type or undefined if unknown
2836
+ */
2837
+ getSourceType() {
2838
+ if (this.isAncestry()) return "Ancestry";
2839
+ if (this.isMyHeritage()) return "MyHeritage";
2840
+ if (this.isFamilySearch()) return "FamilySearch";
2841
+ if (this.isGNO2GED()) return "GNO2GED";
2842
+ if (this.isGenoPro()) return "GenoPro";
2843
+ if (this.isAhnenblatt()) return "Ahnenblatt";
2844
+ if (this.isGeni()) return "Geni";
2845
+ return void 0;
2846
+ }
2847
+ isFamilySearch() {
2848
+ return this.getSourceHeads().some((head) => {
2849
+ const sourName = get(head, "SOUR.NAME.value");
2850
+ return sourName === "FamilySearch API";
3083
2851
  });
3084
- return newList;
3085
2852
  }
3086
- };
3087
-
3088
- // src/classes/common.ts
3089
- var Common = class _Common {
3090
- constructor(gedcom, id, main, parent) {
3091
- this.isListable = true;
3092
- this._gedcom = gedcom;
3093
- this._main = main;
3094
- this._parent = parent;
3095
- this.initUniqueId();
3096
- if (id) {
3097
- this._id = id;
3098
- } else {
3099
- delete this._id;
3100
- }
2853
+ isGNO2GED() {
2854
+ return this.getSourceHeads().some((head) => {
2855
+ const sour = get(head, "SOUR.value");
2856
+ return sour === "GNO2GED";
2857
+ });
3101
2858
  }
3102
- set type(type) {
3103
- if (type) {
3104
- this.uniqueId = this.uniqueId?.replace(/^[^:]+/, `~${type}`);
3105
- }
3106
- this._type = type;
2859
+ getAncestryTreeId() {
2860
+ return this.getFromSourceHeads("SOUR._TREE.RIN.value") || (get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value"));
3107
2861
  }
3108
- get type() {
3109
- return this._type;
2862
+ getMyHeritageTreeId() {
2863
+ return this.getFromSourceHeads("_EXPORTED_FROM_SITE_ID.value") || (get(this, "HEAD._EXPORTED_FROM_SITE_ID.value") || get(this.getGedcom(), "HEAD._EXPORTED_FROM_SITE_ID.value"));
3110
2864
  }
3111
- initUniqueId() {
3112
- if (this._gedcom) {
3113
- this.uniqueId = `~Common:${this._gedcom.refcount++}`;
2865
+ getTreeId() {
2866
+ if (this?.isAncestry()) {
2867
+ const id = this.getAncestryTreeId();
2868
+ if (id !== void 0) return id;
3114
2869
  }
3115
- }
3116
- set uniqueId(id) {
3117
- const currentId = this._uniqueId;
3118
- if (this._gedcom?.reflist && id) {
3119
- this._uniqueId = id;
3120
- if (currentId && this._gedcom.reflist[currentId]) {
3121
- delete this._gedcom.reflist[currentId];
3122
- }
3123
- this._gedcom.reflist[id] = this;
2870
+ if (this?.isMyHeritage()) {
2871
+ const id = this.getMyHeritageTreeId();
2872
+ if (id !== void 0) return id;
2873
+ }
2874
+ if (this?.isFamilySearch()) {
2875
+ const id = this.getFamilySearchTreeId();
2876
+ if (id !== void 0) return id;
2877
+ }
2878
+ if (this?.isGNO2GED()) {
2879
+ const id = this.getGNO2GEDTreeId();
2880
+ if (id !== void 0) return id;
2881
+ }
2882
+ if (this?.isAhnenblatt()) {
2883
+ const id = this.getAhnenblattTreeId();
2884
+ if (id !== void 0) return id;
2885
+ }
2886
+ if (this?.isGeni()) {
2887
+ const id = this.getGeniTreeId();
2888
+ if (id !== void 0) return id;
2889
+ }
2890
+ if (this?.isGenoPro()) {
2891
+ const id = this.getGenoProTreeId();
2892
+ if (id !== void 0) return id;
3124
2893
  }
2894
+ return this.getUniversalTreeId();
3125
2895
  }
3126
- get uniqueId() {
3127
- return this._uniqueId;
2896
+ getAncestryTreeName() {
2897
+ return this.getFromSourceHeads("SOUR._TREE.value") || (get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value"));
3128
2898
  }
3129
- set id(id) {
3130
- this._id = idGetter(id);
2899
+ getMyHeritageTreeName() {
2900
+ const path = "HEAD.FILE.value";
2901
+ const treeDetails = get(this, path) || get(this.getGedcom(), path);
2902
+ return treeDetails?.match(
2903
+ /Exported by MyHeritage.com from (?<tree>.+) in.+$/
2904
+ )?.groups?.tree;
3131
2905
  }
3132
- get id() {
3133
- return idGetter(this._id);
2906
+ getFamilySearchTreeId() {
2907
+ const rin = this.getFromSourceHeads("SOUR._TREE.RIN.value") || get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value");
2908
+ if (rin) {
2909
+ return rin;
2910
+ }
2911
+ return "familysearch";
3134
2912
  }
3135
- set value(value) {
3136
- this._value = value;
3137
- }
3138
- get value() {
3139
- return this._value;
3140
- }
3141
- /**
3142
- * Set the gedcom reference for this object
3143
- * @param gedcom - The GedComType to set as the gedcom reference
3144
- */
3145
- setGedcom(gedcom) {
3146
- this._gedcom = gedcom;
3147
- }
3148
- // avoid to override
3149
- get originalValue() {
3150
- return this._value;
3151
- }
3152
- get ref() {
3153
- if (typeof this.value === "string" && isId(this.value) && this.refType) {
3154
- return this._gedcom?.[getListTag(this.refType)]?.item(
3155
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3156
- this.value
3157
- );
2913
+ getFamilySearchTreeName() {
2914
+ const treeName = this.getFromSourceHeads("SOUR._TREE.value") || get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value");
2915
+ if (treeName) {
2916
+ return treeName;
3158
2917
  }
3159
- return this;
2918
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
2919
+ return fileName || "FamilySearch Import";
3160
2920
  }
3161
- get main() {
3162
- return this._main;
2921
+ getAhnenblattTreeId() {
2922
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
2923
+ if (fileName) {
2924
+ const idMatch = fileName.match(/_(\d+)/);
2925
+ if (idMatch) {
2926
+ return idMatch[1];
2927
+ }
2928
+ }
2929
+ return void 0;
3163
2930
  }
3164
- get parent() {
3165
- return this._parent;
2931
+ getAhnenblattTreeName() {
2932
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
2933
+ return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
3166
2934
  }
3167
- addRef(refNode) {
3168
- if (typeof refNode.value === "string" && isId(refNode.value) && refNode.refType) {
3169
- if (!this._refs) {
3170
- this._refs = new List();
2935
+ getGeniTreeId() {
2936
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
2937
+ if (fileName) {
2938
+ const idMatch = fileName.match(/_(\d+)/);
2939
+ if (idMatch) {
2940
+ return idMatch[1];
3171
2941
  }
3172
- this._refs.item(refNode.value, refNode);
3173
2942
  }
2943
+ return void 0;
3174
2944
  }
3175
- getRefs() {
3176
- return this._refs;
2945
+ getGeniTreeName() {
2946
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
2947
+ return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
3177
2948
  }
3178
- exportValue() {
3179
- return this.value;
2949
+ getGenoProTreeId() {
2950
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
2951
+ if (fileName) {
2952
+ const idMatch = fileName.match(/_(\d+)/);
2953
+ if (idMatch) {
2954
+ return idMatch[1];
2955
+ }
2956
+ }
2957
+ return void 0;
3180
2958
  }
3181
- removeValue() {
3182
- delete this._value;
2959
+ getGenoProTreeName() {
2960
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
2961
+ return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
3183
2962
  }
3184
- set(name, value) {
3185
- if (isGedcomTrailerTag(name)) {
3186
- return void 0;
3187
- }
3188
- if (typeof value === "string") {
3189
- const usedValue = createCommon(this._gedcom, void 0, this.main);
3190
- usedValue.value = value;
3191
- set(this, name, usedValue);
3192
- } else {
3193
- set(this, name, value);
2963
+ getGNO2GEDTreeId() {
2964
+ const rin = get(this, "HEAD._TREE.RIN.value") || get(this.getGedcom(), "HEAD._TREE.RIN.value");
2965
+ if (rin) {
2966
+ return rin;
3194
2967
  }
3195
- return get(this, name);
2968
+ return `gno_${this._gedcom?.refcount || "unknown"}`;
3196
2969
  }
3197
- assign(name, value, unique = false) {
3198
- if (isGedcomTrailerTag(name)) {
3199
- return void 0;
2970
+ getGNO2GEDTreeName() {
2971
+ const treeName = get(this, "HEAD._TREE.value") || get(this.getGedcom(), "HEAD._TREE.value");
2972
+ if (treeName) {
2973
+ return treeName;
3200
2974
  }
3201
- let curValue = this.get(name);
3202
- if (curValue?.isListable) {
3203
- if (curValue instanceof _Common) {
3204
- curValue = new List().concat({ ...[curValue] });
3205
- this.set(name, curValue);
2975
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
2976
+ return fileName || "GNO2GED Export";
2977
+ }
2978
+ /**
2979
+ * Universal tree ID getter for unknown/unrecognized GEDCOM sources
2980
+ * Tries to extract an ID from various common locations
2981
+ */
2982
+ getUniversalTreeId() {
2983
+ const sourceType = this.getSourceType();
2984
+ const prefix = sourceType ? sourceType.toLowerCase() : "tree";
2985
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
2986
+ if (fileName) {
2987
+ const idMatch = fileName.match(/_(\d+)/);
2988
+ if (idMatch) {
2989
+ return `${prefix}_${idMatch[1]}`;
3206
2990
  }
3207
- const values = [
3208
- ...curValue.values(),
3209
- ...value instanceof List ? value.values() : [value]
3210
- ];
3211
- curValue.concat({
3212
- ...!unique ? values : uniqBy(
3213
- values,
3214
- (value2) => value2 instanceof _Common ? value2?.value : void 0
3215
- )
3216
- });
3217
- } else {
3218
- this.set(name, value);
3219
2991
  }
3220
- return get(this, name);
2992
+ return `${prefix}_${this._gedcom?.refcount || "unknown"}`;
3221
2993
  }
3222
- get(name) {
3223
- if (!name.includes(".")) {
3224
- return get(this, name);
2994
+ /**
2995
+ * Universal tree name getter for unknown/unrecognized GEDCOM sources
2996
+ * Tries to extract a name from various common locations
2997
+ */
2998
+ getUniversalTreeName() {
2999
+ const sourceType = this.getSourceType();
3000
+ const prefix = sourceType ? `${sourceType}-` : "";
3001
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
3002
+ if (fileName) {
3003
+ const cleanName = fileName.replace(/\.ged$/i, "").replace(/_/g, " ");
3004
+ return `${prefix}${cleanName}`;
3225
3005
  }
3226
- const nameParts = name.split(".");
3227
- let last = this;
3228
- for (const part of nameParts) {
3229
- const indexPart = Number(part);
3230
- const itemIndex = part.match(/items\[(?<itemIndex>\d+)\]/)?.groups?.itemIndex;
3231
- const itemId = part.match(/items\[(?<itemId>@[A-Z]+\d+@)\]/)?.groups?.itemId;
3232
- const usedPart = itemId || itemIndex;
3233
- if (last instanceof List) {
3234
- if (!isNaN(indexPart)) {
3235
- last = last.index(indexPart);
3236
- } else {
3237
- if (usedPart) {
3238
- last = last.item(usedPart);
3239
- } else {
3240
- last = last?.index(0)?.get(part);
3241
- }
3242
- }
3243
- } else {
3244
- const usedIndex = Number(itemIndex ?? indexPart);
3245
- if (!isNaN(usedIndex)) {
3246
- last = last?.toList().index(usedIndex);
3247
- } else {
3248
- last = last?.get(itemId ?? part);
3249
- }
3250
- }
3251
- if (!last) {
3252
- break;
3253
- }
3006
+ const sourName = this.getFromSourceHeads("SOUR.NAME.value") || get(this, "HEAD.SOUR.NAME.value") || get(this.getGedcom(), "HEAD.SOUR.NAME.value");
3007
+ if (sourName) {
3008
+ return `${prefix}${sourName}`;
3254
3009
  }
3255
- return last;
3256
- }
3257
- remove(name) {
3258
- unset(this, name);
3259
- }
3260
- getGedcom() {
3261
- return this._gedcom;
3010
+ const sourValue = this.getFromSourceHeads("SOUR.value") || get(this, "HEAD.SOUR.value") || get(this.getGedcom(), "HEAD.SOUR.value");
3011
+ if (sourValue) {
3012
+ return `${prefix}${sourValue}`;
3013
+ }
3014
+ return `${prefix}Unknown Tree`;
3262
3015
  }
3263
- getIf(name, condition, name2) {
3264
- const nameParts = name.split(".");
3265
- const name2Parts = name2.split(".");
3266
- if (nameParts.length !== name2Parts.length) {
3267
- throw new Error("Tag pathes must be of the same depth");
3016
+ getTreeName() {
3017
+ if (this?.isAncestry()) {
3018
+ const name = this.getAncestryTreeName();
3019
+ if (name) return name;
3268
3020
  }
3269
- if (nameParts.length > 1 && nameParts[0] !== name2Parts[0]) {
3270
- throw new Error("Final tags must be siblings");
3021
+ if (this?.isMyHeritage()) {
3022
+ const name = this.getMyHeritageTreeName();
3023
+ if (name) return name;
3271
3024
  }
3272
- const valueCommon = this.get(name);
3273
- if (valueCommon instanceof _Common) {
3274
- return valueCommon?.toValue() !== condition ? void 0 : this.get(name2);
3025
+ if (this?.isFamilySearch()) {
3026
+ const name = this.getFamilySearchTreeName();
3027
+ if (name) return name;
3275
3028
  }
3276
- const valueCommon2 = this.get(name2)?.toList();
3277
- const ifList = new List();
3278
- valueCommon?.forEach((item, key) => {
3279
- const pair = valueCommon2?.item(key);
3280
- ifList.item(key, item?.toValue() !== condition ? void 0 : pair);
3281
- });
3282
- return ifList;
3283
- }
3284
- toString() {
3285
- return this.value?.toString() || "";
3286
- }
3287
- toValue() {
3288
- return this.value;
3289
- }
3290
- toProp(tag) {
3291
- const prop = this.get(tag);
3292
- return prop;
3293
- }
3294
- toList() {
3295
- return new List().concat(
3296
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3297
- this.id ? { [this.id]: this } : { ...[this] }
3298
- );
3299
- }
3300
- index(i) {
3301
- return this.toList()?.index(i);
3029
+ if (this?.isGNO2GED()) {
3030
+ const name = this.getGNO2GEDTreeName();
3031
+ if (name) return name;
3032
+ }
3033
+ if (this?.isAhnenblatt()) {
3034
+ const name = this.getAhnenblattTreeName();
3035
+ if (name) return name;
3036
+ }
3037
+ if (this?.isGeni()) {
3038
+ const name = this.getGeniTreeName();
3039
+ if (name) return name;
3040
+ }
3041
+ if (this?.isGenoPro()) {
3042
+ const name = this.getGenoProTreeName();
3043
+ if (name) return name;
3044
+ }
3045
+ return this.getUniversalTreeName();
3302
3046
  }
3303
- toValueList() {
3304
- return new List().concat(
3305
- this.value ? { [this.value]: this } : (
3306
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3307
- { ...[this] }
3308
- )
3309
- );
3310
- }
3311
- standardizeObject(tag, options) {
3312
- if (tag === "OBJE" && options?.obje?.standardize && "standardizeMedia" in this) {
3313
- const standardize = this.standardizeMedia;
3314
- return standardize.call(
3315
- this,
3316
- options.obje.namespace,
3317
- options.obje.override,
3318
- this.isAncestry() ? ancestryMediaFileUrl : void 0,
3319
- options.gedcomVersion
3320
- );
3321
- }
3322
- }
3323
- toJson(tag, options) {
3324
- const json = this.toObject(tag, options);
3325
- return JSON.stringify(json);
3326
- }
3327
- toObject(tag, options) {
3328
- this.standardizeObject(tag, options);
3329
- const validKeys = getValidKeys(this);
3330
- let json = {};
3331
- validKeys.forEach((key) => {
3332
- if (options?.persist && (key === "DAY" || key === "MONTH" || key === "YEAR")) {
3333
- return;
3334
- }
3335
- if (key === "id" && this.id !== void 0) {
3336
- json.id = this.id;
3337
- } else if (key === "_id" && this._id !== void 0) {
3338
- json.id = this._id;
3339
- } else if (key === "value" && this.value !== void 0) {
3340
- json.value = this.value;
3341
- } else if (key === "_value" && this._value !== void 0) {
3342
- json.value = this._value;
3343
- } else {
3344
- const validKey = key;
3345
- const prop = this.get(validKey);
3346
- if (typeof prop?.toObject === "function") {
3347
- if (prop instanceof _Common) {
3348
- json[validKey] = prop.toObject(validKey, options);
3349
- } else if (prop instanceof List) {
3350
- json = {
3351
- ...json,
3352
- ...prop.toObject(validKey, options)
3353
- };
3354
- }
3355
- }
3047
+ };
3048
+ var createProxy = (target) => {
3049
+ return new Proxy(target, {
3050
+ get(t, prop, receiver) {
3051
+ if (prop === "unwrapped") {
3052
+ return target;
3356
3053
  }
3357
- });
3358
- return json;
3359
- }
3360
- merge(other, override = false, avoidKeys = []) {
3361
- if (!other) {
3362
- return this;
3363
- }
3364
- const validKeys = getValidKeys(other);
3365
- validKeys.forEach((validKey) => {
3366
- if (avoidKeys.includes(validKey)) {
3367
- return;
3054
+ if (prop in t) {
3055
+ return Reflect.get(t, prop, receiver);
3368
3056
  }
3369
- const current = this.get(validKey);
3370
- const mergeValue = other.get(validKey);
3371
- if (mergeValue) {
3372
- if (current instanceof _Common || current instanceof List) {
3373
- this.assign(validKey, mergeValue, true);
3374
- } else if (!current || override && validKey !== "id" && validKey !== "_id") {
3375
- this.set(validKey, mergeValue);
3057
+ if (!isOnlyMainProp(prop)) {
3058
+ const ref = t.ref;
3059
+ if (ref && prop in ref) {
3060
+ return Reflect.get(ref, prop, receiver);
3376
3061
  }
3377
3062
  }
3378
- });
3379
- return this;
3380
- }
3381
- clone(newId = false, avoidKeys = []) {
3382
- const ctor = this.constructor;
3383
- const instance = new ctor(
3384
- this._gedcom,
3385
- this._id,
3386
- this._main,
3387
- this._parent
3388
- );
3389
- if (newId && this._id) {
3390
- instance.id = `IFT${this._id.replace(/[^0-9]/g, "")}`;
3391
3063
  }
3392
- const cloned = createProxy(instance);
3393
- cloned.merge(this, true, avoidKeys);
3394
- return cloned;
3064
+ });
3065
+ };
3066
+ var createCommon = (gedcom, id, main, parent) => {
3067
+ return createProxy(
3068
+ new Common(gedcom, id, main, parent)
3069
+ );
3070
+ };
3071
+ var isOnlyMainProp = (key) => {
3072
+ return key === "_gedcom" || key === "_main" || key === "_parent" || key === "_uniqueId" || key === "_type" || key === "_refs" || key === "id" || key === "_id";
3073
+ };
3074
+ var isValidKey = (common, key) => {
3075
+ const prop = get(common, key);
3076
+ return key !== "_gedcom" && key !== "_main" && key !== "_parent" && key !== "_uniqueId" && key !== "_refs" && key !== "_type" && !(typeof key === "string" && isGedcomTrailerTag(key)) && (key === "id" || key === "_id" || key === "value" || key === "_value" || prop instanceof Common || prop instanceof List);
3077
+ };
3078
+ var getValidKeys = (common) => {
3079
+ return Object.keys(common).filter((key) => {
3080
+ return isValidKey(common, key);
3081
+ });
3082
+ };
3083
+ var getValidTag = (tag) => {
3084
+ return tag.replace(/^@@/, "");
3085
+ };
3086
+ var getListTag = (tag) => {
3087
+ return `@@${tag}`;
3088
+ };
3089
+ var isId = (string) => {
3090
+ return ID_REG.test(string);
3091
+ };
3092
+ var idGetter = (id) => {
3093
+ if (id === void 0) {
3094
+ return void 0;
3395
3095
  }
3396
- // fromGedcom<T = typeof this>(value: string) {
3397
- fromGedcom(_value) {
3096
+ let newId = `${id}`;
3097
+ const parts = newId?.match(ID_GETTER_REG)?.groups;
3098
+ if (!parts?.at && !parts?.letter) {
3099
+ newId = `@U${newId}`;
3100
+ } else if (!parts.at) {
3101
+ newId = `@${newId}`;
3102
+ } else if (!parts.letter) {
3103
+ newId = newId.replace(/^@/, "@U");
3398
3104
  }
3399
- toGedcom(tag, level = 0, options) {
3400
- const gedcom = this.toGedcomLines(tag, level, options);
3401
- return gedcom.join("\n");
3105
+ if (!newId.endsWith("@")) {
3106
+ newId = `${newId}@`;
3402
3107
  }
3403
- toGedcomLines(tag, level = 0, options) {
3404
- this.standardizeObject(tag, options);
3405
- const validKeys = getValidKeys(this);
3406
- const gedcom = [];
3407
- const isGedcom7Export = options?.gedcomVersion === "7.0";
3408
- validKeys.forEach((key) => {
3409
- const validKey = key;
3410
- if (isGedcom7Export && validKey === "CONC") {
3411
- return;
3412
- }
3413
- const prop = this.get(validKey);
3414
- if (typeof prop?.toGedcomLines === "function") {
3415
- if (prop instanceof _Common) {
3416
- const value = prop.exportValue();
3417
- gedcom.push(
3418
- `${level} ${validKey}${value ? ` ${value}` : ""}`
3419
- );
3420
- gedcom.push(
3421
- ...prop.toGedcomLines(validKey, level + 1, options)
3422
- );
3423
- } else if (prop instanceof List) {
3424
- gedcom.push(
3425
- ...prop.toGedcomLines(validKey, level, options)
3426
- );
3427
- }
3428
- }
3429
- });
3430
- return gedcom;
3108
+ return newId;
3109
+ };
3110
+
3111
+ // src/classes/list.ts
3112
+ var List = class _List {
3113
+ // length = 0;
3114
+ constructor(items) {
3115
+ this.items = {};
3116
+ this.isListable = true;
3117
+ this.marker = void 0;
3118
+ if (items) {
3119
+ this.concat(items);
3120
+ }
3431
3121
  }
3432
- getHeadRecord() {
3433
- return get(this, "HEAD") || get(this.getGedcom(), "HEAD");
3122
+ get length() {
3123
+ return this.values().length;
3434
3124
  }
3435
- getOriginalHeadRecord() {
3436
- return get(this, ORIG_HEAD_TAG) || get(this.getGedcom(), ORIG_HEAD_TAG) || get(this.getHeadRecord(), ORIG_HEAD_TAG);
3125
+ has(indi) {
3126
+ return !!this.item(
3127
+ typeof indi === "string" ? indi : indi?.id ?? ""
3128
+ );
3437
3129
  }
3438
- getSourceHeads() {
3439
- const heads = [this.getOriginalHeadRecord(), this.getHeadRecord()];
3440
- return heads.filter((head, index) => {
3441
- return Boolean(head && heads.indexOf(head) === index);
3130
+ get(name) {
3131
+ const propList = new _List();
3132
+ this.entries().forEach(([key, item]) => {
3133
+ propList.item(key, item.get(name));
3442
3134
  });
3135
+ return propList;
3443
3136
  }
3444
- getFromSourceHeads(path) {
3445
- for (const head of this.getSourceHeads()) {
3446
- const value = get(head, path);
3447
- if (value !== void 0 && value !== null && value !== "") {
3448
- return value;
3137
+ getIf(name, condition, name2) {
3138
+ const propList = new _List();
3139
+ this.entries().forEach(([key, item]) => {
3140
+ const passedItem = item.getIf(name, condition, name2);
3141
+ if (passedItem) {
3142
+ propList.item(key, passedItem);
3449
3143
  }
3450
- }
3451
- return void 0;
3452
- }
3453
- sourStartsWith(prefix) {
3454
- return this.getSourceHeads().some((head) => {
3455
- const sour = get(head, "SOUR.value");
3456
- return !!sour?.toLowerCase()?.startsWith(prefix);
3457
3144
  });
3145
+ return propList;
3458
3146
  }
3459
- isGenoPro() {
3460
- return this.sourStartsWith("genopro");
3147
+ keys() {
3148
+ return Object.keys(this.items);
3461
3149
  }
3462
- isAhnenblatt() {
3463
- return this.sourStartsWith("ahnenblatt");
3150
+ values() {
3151
+ return Object.values(this.items);
3464
3152
  }
3465
- isGeni() {
3466
- return this.sourStartsWith("geni");
3153
+ entries() {
3154
+ return Object.entries(this.items);
3467
3155
  }
3468
- isAncestry() {
3469
- return this.sourStartsWith("ancestry");
3156
+ setLength(_type) {
3470
3157
  }
3471
- isMyHeritage() {
3472
- return this.sourStartsWith("myheritage");
3158
+ first() {
3159
+ return this.index(0);
3473
3160
  }
3474
- /**
3475
- * Get the source type as a string (for prefixing tree IDs and names)
3476
- * Returns the detected source type or undefined if unknown
3477
- */
3478
- getSourceType() {
3479
- if (this.isAncestry()) return "Ancestry";
3480
- if (this.isMyHeritage()) return "MyHeritage";
3481
- if (this.isFamilySearch()) return "FamilySearch";
3482
- if (this.isGNO2GED()) return "GNO2GED";
3483
- if (this.isGenoPro()) return "GenoPro";
3484
- if (this.isAhnenblatt()) return "Ahnenblatt";
3485
- if (this.isGeni()) return "Geni";
3486
- return void 0;
3161
+ last() {
3162
+ return this.index(this.keys().length - 1);
3487
3163
  }
3488
- isFamilySearch() {
3489
- return this.getSourceHeads().some((head) => {
3490
- const sourName = get(head, "SOUR.NAME.value");
3491
- return sourName === "FamilySearch API";
3492
- });
3164
+ index(index) {
3165
+ const keys = this.keys();
3166
+ const key = keys[index];
3167
+ return key && this.items[key];
3493
3168
  }
3494
- isGNO2GED() {
3495
- return this.getSourceHeads().some((head) => {
3496
- const sour = get(head, "SOUR.value");
3497
- return sour === "GNO2GED";
3498
- });
3169
+ item(name, value) {
3170
+ if (arguments.length > 1) {
3171
+ set(this.items, name, value);
3172
+ this.setLength();
3173
+ }
3174
+ return get(this.items, name);
3499
3175
  }
3500
- getAncestryTreeId() {
3501
- return this.getFromSourceHeads("SOUR._TREE.RIN.value") || (get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value"));
3176
+ removeItem(name) {
3177
+ unset(this.items, name);
3178
+ this.setLength();
3502
3179
  }
3503
- getMyHeritageTreeId() {
3504
- return this.getFromSourceHeads("_EXPORTED_FROM_SITE_ID.value") || (get(this, "HEAD._EXPORTED_FROM_SITE_ID.value") || get(this.getGedcom(), "HEAD._EXPORTED_FROM_SITE_ID.value"));
3180
+ exclude(excludedList) {
3181
+ excludedList.keys().forEach((itemId) => {
3182
+ delete this.items[itemId];
3183
+ });
3184
+ this.setLength();
3185
+ return this;
3505
3186
  }
3506
- getTreeId() {
3507
- if (this?.isAncestry()) {
3508
- const id = this.getAncestryTreeId();
3509
- if (id !== void 0) return id;
3510
- }
3511
- if (this?.isMyHeritage()) {
3512
- const id = this.getMyHeritageTreeId();
3513
- if (id !== void 0) return id;
3514
- }
3515
- if (this?.isFamilySearch()) {
3516
- const id = this.getFamilySearchTreeId();
3517
- if (id !== void 0) return id;
3518
- }
3519
- if (this?.isGNO2GED()) {
3520
- const id = this.getGNO2GEDTreeId();
3521
- if (id !== void 0) return id;
3522
- }
3523
- if (this?.isAhnenblatt()) {
3524
- const id = this.getAhnenblattTreeId();
3525
- if (id !== void 0) return id;
3526
- }
3527
- if (this?.isGeni()) {
3528
- const id = this.getGeniTreeId();
3529
- if (id !== void 0) return id;
3530
- }
3531
- if (this?.isGenoPro()) {
3532
- const id = this.getGenoProTreeId();
3533
- if (id !== void 0) return id;
3187
+ concat(items) {
3188
+ if (Array.isArray(items)) {
3189
+ items.forEach((item) => {
3190
+ this.append(item);
3191
+ });
3192
+ } else {
3193
+ Object.assign(this.items, items ?? {});
3534
3194
  }
3535
- return this.getUniversalTreeId();
3195
+ this.setLength();
3196
+ return this;
3536
3197
  }
3537
- getAncestryTreeName() {
3538
- return this.getFromSourceHeads("SOUR._TREE.value") || (get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value"));
3198
+ merge(mergedList) {
3199
+ this.concat(mergedList?.items);
3200
+ return this;
3539
3201
  }
3540
- getMyHeritageTreeName() {
3541
- const path = "HEAD.FILE.value";
3542
- const treeDetails = get(this, path) || get(this.getGedcom(), path);
3543
- return treeDetails?.match(
3544
- /Exported by MyHeritage.com from (?<tree>.+) in.+$/
3545
- )?.groups?.tree;
3202
+ intersection(mergedList) {
3203
+ const inter = intersectionBy(
3204
+ this.values(),
3205
+ mergedList?.values() ?? [],
3206
+ "id"
3207
+ );
3208
+ return new _List(inter);
3546
3209
  }
3547
- getFamilySearchTreeId() {
3548
- const rin = this.getFromSourceHeads("SOUR._TREE.RIN.value") || get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value");
3549
- if (rin) {
3550
- return rin;
3551
- }
3552
- return "familysearch";
3210
+ difference(mergedList) {
3211
+ const inter = differenceBy(
3212
+ this.values(),
3213
+ mergedList?.values() ?? [],
3214
+ "id"
3215
+ );
3216
+ return new _List(inter);
3553
3217
  }
3554
- getFamilySearchTreeName() {
3555
- const treeName = this.getFromSourceHeads("SOUR._TREE.value") || get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value");
3556
- if (treeName) {
3557
- return treeName;
3218
+ prepend(item) {
3219
+ if (item.id) {
3220
+ let increase = true;
3221
+ if (this.items[item.id]) {
3222
+ delete this.items[item.id];
3223
+ increase = false;
3224
+ }
3225
+ this.items = Object.assign(
3226
+ {
3227
+ [item.id]: item
3228
+ },
3229
+ this.items
3230
+ );
3231
+ if (increase) {
3232
+ this.setLength("increase");
3233
+ }
3558
3234
  }
3559
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
3560
- return fileName || "FamilySearch Import";
3235
+ return this;
3561
3236
  }
3562
- getAhnenblattTreeId() {
3563
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
3564
- if (fileName) {
3565
- const idMatch = fileName.match(/_(\d+)/);
3566
- if (idMatch) {
3567
- return idMatch[1];
3237
+ append(item) {
3238
+ if (item.id) {
3239
+ let increase = true;
3240
+ if (this.items[item.id]) {
3241
+ delete this.items[item.id];
3242
+ increase = false;
3243
+ }
3244
+ this.items[item.id] = item;
3245
+ if (increase) {
3246
+ this.setLength("increase");
3568
3247
  }
3569
3248
  }
3570
- return void 0;
3571
- }
3572
- getAhnenblattTreeName() {
3573
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
3574
- return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
3249
+ return this;
3575
3250
  }
3576
- getGeniTreeId() {
3577
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
3578
- if (fileName) {
3579
- const idMatch = fileName.match(/_(\d+)/);
3580
- if (idMatch) {
3581
- return idMatch[1];
3582
- }
3251
+ delete(item) {
3252
+ if (item.id && this.items[item.id]) {
3253
+ delete this.items[item.id];
3254
+ this.setLength("decrease");
3583
3255
  }
3584
- return void 0;
3256
+ return this;
3585
3257
  }
3586
- getGeniTreeName() {
3587
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
3588
- return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
3258
+ copy(ClassName = _List) {
3259
+ const newList = new ClassName();
3260
+ Object.assign(newList.items, this.items);
3261
+ newList.setLength();
3262
+ return newList;
3589
3263
  }
3590
- getGenoProTreeId() {
3591
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
3592
- if (fileName) {
3593
- const idMatch = fileName.match(/_(\d+)/);
3594
- if (idMatch) {
3595
- return idMatch[1];
3596
- }
3597
- }
3598
- return void 0;
3264
+ except(item, ClassName = _List) {
3265
+ return this.copy(ClassName).delete(item);
3599
3266
  }
3600
- getGenoProTreeName() {
3601
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
3602
- return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
3267
+ forEach(iterate) {
3268
+ this.entries().forEach(([key, item], index) => {
3269
+ iterate(item, key, index);
3270
+ });
3603
3271
  }
3604
- getGNO2GEDTreeId() {
3605
- const rin = get(this, "HEAD._TREE.RIN.value") || get(this.getGedcom(), "HEAD._TREE.RIN.value");
3606
- if (rin) {
3607
- return rin;
3608
- }
3609
- return `gno_${this._gedcom?.refcount || "unknown"}`;
3272
+ map(iterate) {
3273
+ return this.entries().map(([key, item], index) => {
3274
+ return iterate(item, key, index);
3275
+ });
3610
3276
  }
3611
- getGNO2GEDTreeName() {
3612
- const treeName = get(this, "HEAD._TREE.value") || get(this.getGedcom(), "HEAD._TREE.value");
3613
- if (treeName) {
3614
- return treeName;
3615
- }
3616
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
3617
- return fileName || "GNO2GED Export";
3277
+ reduce(iterate, initialValue) {
3278
+ return this.entries().reduce((acc, [key, item], index) => {
3279
+ return iterate(acc, item, key, index);
3280
+ }, initialValue);
3618
3281
  }
3619
- /**
3620
- * Universal tree ID getter for unknown/unrecognized GEDCOM sources
3621
- * Tries to extract an ID from various common locations
3622
- */
3623
- getUniversalTreeId() {
3624
- const sourceType = this.getSourceType();
3625
- const prefix = sourceType ? sourceType.toLowerCase() : "tree";
3626
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
3627
- if (fileName) {
3628
- const idMatch = fileName.match(/_(\d+)/);
3629
- if (idMatch) {
3630
- return `${prefix}_${idMatch[1]}`;
3282
+ filter(filters, ClassName = _List) {
3283
+ const newList = new ClassName();
3284
+ const isIterator = typeof filters === "function";
3285
+ this.entries().forEach(([itemId, item], index) => {
3286
+ if (isIterator) {
3287
+ filters(item, itemId, index) && newList.item(itemId, item);
3288
+ return;
3631
3289
  }
3632
- }
3633
- return `${prefix}_${this._gedcom?.refcount || "unknown"}`;
3290
+ if (!Object.keys(filters).length || Object.entries(filters).every(([key, value]) => {
3291
+ let itemValue;
3292
+ if (key === "id") {
3293
+ itemValue = item.toProp("id");
3294
+ } else {
3295
+ itemValue = item.toProp(key)?.toValue();
3296
+ }
3297
+ if (Array.isArray(value)) {
3298
+ return value.includes(itemValue);
3299
+ }
3300
+ return itemValue === value;
3301
+ })) {
3302
+ newList.item(itemId, item);
3303
+ }
3304
+ });
3305
+ return newList;
3634
3306
  }
3635
- /**
3636
- * Universal tree name getter for unknown/unrecognized GEDCOM sources
3637
- * Tries to extract a name from various common locations
3638
- */
3639
- getUniversalTreeName() {
3640
- const sourceType = this.getSourceType();
3641
- const prefix = sourceType ? `${sourceType}-` : "";
3642
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
3643
- if (fileName) {
3644
- const cleanName = fileName.replace(/\.ged$/i, "").replace(/_/g, " ");
3645
- return `${prefix}${cleanName}`;
3646
- }
3647
- const sourName = this.getFromSourceHeads("SOUR.NAME.value") || get(this, "HEAD.SOUR.NAME.value") || get(this.getGedcom(), "HEAD.SOUR.NAME.value");
3648
- if (sourName) {
3649
- return `${prefix}${sourName}`;
3650
- }
3651
- const sourValue = this.getFromSourceHeads("SOUR.value") || get(this, "HEAD.SOUR.value") || get(this.getGedcom(), "HEAD.SOUR.value");
3652
- if (sourValue) {
3653
- return `${prefix}${sourValue}`;
3654
- }
3655
- return `${prefix}Unknown Tree`;
3307
+ find(filters, _ClassName = _List) {
3308
+ let foundItem;
3309
+ const isIterator = typeof filters === "function";
3310
+ this.entries().find(([itemId, item], index) => {
3311
+ if (isIterator) {
3312
+ if (filters(item, itemId, index)) {
3313
+ foundItem = item;
3314
+ return true;
3315
+ }
3316
+ return false;
3317
+ }
3318
+ if (!Object.keys(filters).length || Object.entries(filters).every(([key, value]) => {
3319
+ let itemValue;
3320
+ if (key === "id") {
3321
+ itemValue = item.toProp("id");
3322
+ } else {
3323
+ itemValue = item.toProp(key)?.toValue();
3324
+ }
3325
+ if (Array.isArray(value)) {
3326
+ return value.includes(itemValue);
3327
+ }
3328
+ return itemValue === value;
3329
+ })) {
3330
+ foundItem = item;
3331
+ return true;
3332
+ }
3333
+ return false;
3334
+ });
3335
+ return foundItem;
3656
3336
  }
3657
- getTreeName() {
3658
- if (this?.isAncestry()) {
3659
- const name = this.getAncestryTreeName();
3660
- if (name) return name;
3661
- }
3662
- if (this?.isMyHeritage()) {
3663
- const name = this.getMyHeritageTreeName();
3664
- if (name) return name;
3665
- }
3666
- if (this?.isFamilySearch()) {
3667
- const name = this.getFamilySearchTreeName();
3668
- if (name) return name;
3669
- }
3670
- if (this?.isGNO2GED()) {
3671
- const name = this.getGNO2GEDTreeName();
3672
- if (name) return name;
3337
+ orderBy(orders, ClassName = _List) {
3338
+ const newList = new ClassName();
3339
+ const isIterator = typeof orders === "function";
3340
+ if (!isIterator && (!orders || !Object.keys(orders).length)) {
3341
+ return newList.merge(this);
3673
3342
  }
3674
- if (this?.isAhnenblatt()) {
3675
- const name = this.getAhnenblattTreeName();
3676
- if (name) return name;
3343
+ const sortedItems = this.entries().toSorted(
3344
+ ([itemAId, itemA], [itemBId, itemB]) => {
3345
+ if (isIterator) {
3346
+ return orders(itemA, itemAId, itemB, itemBId);
3347
+ }
3348
+ const [key, { direction, getter }] = Object.entries(
3349
+ typeof orders === "string" ? { [orders]: { direction: "ASC" } } : orders
3350
+ )[0];
3351
+ const rawA = itemA.get(key);
3352
+ const rawB = itemB.get(key);
3353
+ let valueA = rawA?.toValue();
3354
+ let valueB = rawB?.toValue();
3355
+ if (getter && typeof getter === "function") {
3356
+ valueA = getter(valueA, rawA);
3357
+ valueB = getter(valueB, rawB);
3358
+ }
3359
+ let sortValue = 0;
3360
+ if (!valueA && valueA !== 0 && !valueB && valueB !== 0) {
3361
+ sortValue = 0;
3362
+ } else if (!valueB && valueB !== 0) {
3363
+ sortValue = 1;
3364
+ } else if (!valueA && valueA !== 0) {
3365
+ sortValue = -1;
3366
+ } else if (valueA < valueB) {
3367
+ sortValue = -1;
3368
+ } else if (valueA > valueB) {
3369
+ sortValue = 1;
3370
+ }
3371
+ return sortValue * (direction === "DESC" ? -1 : 1);
3372
+ }
3373
+ );
3374
+ sortedItems.forEach(([key, value]) => {
3375
+ newList.item(key, value);
3376
+ });
3377
+ return newList;
3378
+ }
3379
+ groupBy(groups, sort, minOccurance = -1, lessOccuranceLabel = "Appearing less than 5 times", ClassName = _List) {
3380
+ const groupped = {};
3381
+ const isIterator = typeof groups === "function";
3382
+ if (!isIterator && (!groups || !Object.keys(groups).length)) {
3383
+ groupped.Unknown = new ClassName().merge(this);
3384
+ groupped.Unknown.marker = "Unknown";
3385
+ return groupped;
3677
3386
  }
3678
- if (this?.isGeni()) {
3679
- const name = this.getGeniTreeName();
3680
- if (name) return name;
3387
+ this.forEach((item, itemId) => {
3388
+ const group = [];
3389
+ if (isIterator) {
3390
+ const newGroups = groups(item, itemId);
3391
+ group.push(
3392
+ ...Array.isArray(newGroups) ? newGroups : [newGroups]
3393
+ );
3394
+ } else {
3395
+ const [key, { getter }] = Object.entries(
3396
+ typeof groups === "string" ? { [groups]: {} } : groups
3397
+ )[0];
3398
+ const raw = item.get(key)?.index(0);
3399
+ let value = raw?.toValue();
3400
+ if (getter && typeof getter === "function") {
3401
+ value = getter(value, raw);
3402
+ }
3403
+ if (value) {
3404
+ group.push(value);
3405
+ }
3406
+ }
3407
+ if (!group.length) {
3408
+ group.push("Unknown");
3409
+ }
3410
+ group.forEach((g) => {
3411
+ const newGroup = typeof g === "string" ? { group: g } : g;
3412
+ if (!groupped[newGroup.group]) {
3413
+ groupped[newGroup.group] = new ClassName();
3414
+ groupped[newGroup.group].marker = newGroup.marker ?? newGroup.group;
3415
+ }
3416
+ groupped[newGroup.group]?.append(item);
3417
+ });
3418
+ });
3419
+ if (sort) {
3420
+ return Object.entries(groupped).toSorted(([ak, a], [bk, b]) => {
3421
+ if (typeof sort === "function") {
3422
+ return sort(a, ak, b, bk);
3423
+ }
3424
+ if (ak === "Unknown") {
3425
+ return 1;
3426
+ }
3427
+ if (bk === "Unknown") {
3428
+ return -1;
3429
+ }
3430
+ if (sort === "group") {
3431
+ return ak.localeCompare(bk);
3432
+ }
3433
+ return (b?.length ?? 0) - (a?.length ?? 0);
3434
+ }).reduce((acc, [key, value]) => {
3435
+ if (minOccurance > -1 && (value?.length ?? 0) < minOccurance) {
3436
+ const otherKey = lessOccuranceLabel;
3437
+ acc[otherKey] = acc[otherKey] && value ? acc[otherKey].merge(value) : value;
3438
+ } else {
3439
+ acc[key] = value;
3440
+ }
3441
+ return acc;
3442
+ }, {});
3681
3443
  }
3682
- if (this?.isGenoPro()) {
3683
- const name = this.getGenoProTreeName();
3684
- if (name) return name;
3444
+ return groupped;
3445
+ }
3446
+ findIndex(item) {
3447
+ if (!item?.id) {
3448
+ return -1;
3685
3449
  }
3686
- return this.getUniversalTreeName();
3450
+ return this.keys().findIndex((key) => key === item.id);
3451
+ }
3452
+ getItems() {
3453
+ return this.items;
3454
+ }
3455
+ toJson(tag, options) {
3456
+ const json = this.toObject(tag, options);
3457
+ return JSON.stringify(json);
3458
+ }
3459
+ toObject(tag, options) {
3460
+ const json = {};
3461
+ this.entries().forEach(([_, item]) => {
3462
+ const validTag = getValidTag(tag);
3463
+ if (json[validTag]) {
3464
+ if (!Array.isArray(json[validTag])) {
3465
+ json[validTag] = [json[validTag]];
3466
+ }
3467
+ json[validTag].push(
3468
+ item.toObject(validTag, options)
3469
+ );
3470
+ } else {
3471
+ json[validTag] = item.toObject(
3472
+ validTag,
3473
+ options
3474
+ );
3475
+ }
3476
+ });
3477
+ return json;
3478
+ }
3479
+ toGedcom(tag, level = 0, options) {
3480
+ const gedcom = this.toGedcomLines(tag, level, options);
3481
+ return gedcom.join("\n");
3482
+ }
3483
+ toGedcomLines(tag, level = 0, options) {
3484
+ const gedcom = [];
3485
+ this.entries().forEach(([_, item]) => {
3486
+ const validTag = getValidTag(tag);
3487
+ const xref = item.id;
3488
+ const payload = item.exportValue?.();
3489
+ if (xref) {
3490
+ gedcom.push(
3491
+ `${level} ${xref} ${validTag}${payload ? ` ${payload}` : ""}`
3492
+ );
3493
+ } else {
3494
+ gedcom.push(
3495
+ `${level} ${validTag}${payload ? ` ${payload}` : ""}`
3496
+ );
3497
+ }
3498
+ gedcom.push(
3499
+ ...item.toGedcomLines(
3500
+ validTag,
3501
+ level + 1,
3502
+ options
3503
+ )
3504
+ );
3505
+ });
3506
+ return gedcom;
3507
+ }
3508
+ toValue() {
3509
+ const propList = new _List();
3510
+ this.entries().forEach(([key, item]) => {
3511
+ propList.item(key, item?.toValue());
3512
+ });
3513
+ return propList;
3514
+ }
3515
+ // @deprecated use get instead
3516
+ toProp(tag) {
3517
+ return this.get(tag);
3518
+ }
3519
+ toList() {
3520
+ return new _List().concat(this.items);
3521
+ }
3522
+ toValueList() {
3523
+ const newList = new _List();
3524
+ this.values().forEach((value) => {
3525
+ value.value && newList.item(value.value, value);
3526
+ });
3527
+ return newList;
3528
+ }
3529
+ };
3530
+
3531
+ // src/utils/get-all-prop.ts
3532
+ var getAllProp = (indi, prop) => {
3533
+ return prop && (indi?.get(prop)?.toList().values() ?? []).filter(Boolean) || [];
3534
+ };
3535
+
3536
+ // src/utils/date-formatter.ts
3537
+ var ACCEPTED_DATE_FORMATS = [
3538
+ "yyyy.MM.dd.",
3539
+ "yyyy-MM-dd",
3540
+ "MM/dd/yyyy"
3541
+ ];
3542
+ var ACCEPTED_DATE_FORMATS_REGEX = new RegExp(
3543
+ `(${ACCEPTED_DATE_FORMATS.map(
3544
+ (acceptedFormat) => acceptedFormat.replace(/[^.\-/]/g, "\\d")
3545
+ ).join("|")})`,
3546
+ "gi"
3547
+ );
3548
+ var firstDate = (date) => {
3549
+ if (!date) return void 0;
3550
+ if (isCommonDate(date)) return date;
3551
+ if (date instanceof List) {
3552
+ return firstDate(
3553
+ date.index(0)
3554
+ );
3555
+ }
3556
+ const node = date;
3557
+ if (typeof node.toValue === "function") {
3558
+ return node;
3687
3559
  }
3560
+ return void 0;
3688
3561
  };
3689
- var createProxy = (target) => {
3690
- return new Proxy(target, {
3691
- get(t, prop, receiver) {
3692
- if (prop === "unwrapped") {
3693
- return target;
3694
- }
3695
- if (prop in t) {
3696
- return Reflect.get(t, prop, receiver);
3697
- }
3698
- if (!isOnlyMainProp(prop)) {
3699
- const ref = t.ref;
3700
- if (ref && prop in ref) {
3701
- return Reflect.get(ref, prop, receiver);
3562
+ var dateNote = (date, shortNote = true) => {
3563
+ if (date && typeof date.toNote === "function") {
3564
+ return date.toNote(shortNote) ?? "";
3565
+ }
3566
+ return "";
3567
+ };
3568
+ var commonDateFormatter = (date, format2 = "yyyy", prefix = "") => {
3569
+ const used = firstDate(date);
3570
+ const formattedDate = used?.toValue(format2);
3571
+ if (!formattedDate) {
3572
+ return void 0;
3573
+ }
3574
+ return `${prefix}${formattedDate}`.trim();
3575
+ };
3576
+ var noteDateFormatter = (date, format2 = "yyyy", prefix = "", shortNote = true, showNote = true) => {
3577
+ const used = firstDate(date);
3578
+ const rawDate = commonDateFormatter(used, format2, "");
3579
+ if (!rawDate) {
3580
+ return void 0;
3581
+ }
3582
+ const note = dateNote(used, shortNote);
3583
+ return `${prefix}${note && showNote ? i18n.t(`${note} {{date}}`, { date: rawDate }) : rawDate}`;
3584
+ };
3585
+ var marriageDateFormatter = (fam, showDays = false, showPlaces = false, shortNote = true, showNote = true, showDisplayTextIfNoDate = true, showAllEvents = false, dateFormatPattern) => {
3586
+ const fullDateFormat = i18n.t("dateFormat");
3587
+ const marriageDates = [];
3588
+ const marriagePlaces = [];
3589
+ const marriages = (fam?.toValueList().values() ?? []).flatMap((fam2) => {
3590
+ const family = fam2;
3591
+ const marrEvents = (family?.MARR?.toList().values() ?? []).filter(
3592
+ Boolean
3593
+ );
3594
+ if (marrEvents.length === 0) {
3595
+ const displayText = family?.get("DISPLAYTEXT")?.toValue() ?? "";
3596
+ if (showDisplayTextIfNoDate && displayText) {
3597
+ const displayDate = displayText.match(
3598
+ ACCEPTED_DATE_FORMATS_REGEX
3599
+ )?.[0];
3600
+ if (displayDate) {
3601
+ marriagePlaces.push(displayText.replace(displayDate, ""));
3602
+ const marriageDate = createCommonDate(
3603
+ fam2?.getGedcom(),
3604
+ void 0,
3605
+ family
3606
+ );
3607
+ marriageDate.value = displayDate;
3608
+ marriageDates.push(marriageDate);
3609
+ } else {
3610
+ marriagePlaces.push(displayText);
3611
+ marriageDates.push(void 0);
3612
+ return ["\u221E"];
3702
3613
  }
3703
3614
  }
3615
+ return [];
3704
3616
  }
3617
+ const eventsToProcess = showAllEvents ? marrEvents : marrEvents.slice(0, 1);
3618
+ return eventsToProcess.map((marrEvent) => {
3619
+ const marriageEventDetail = marrEvent;
3620
+ const marriageDate = marriageEventDetail?.DATE;
3621
+ const marriagePlace = showPlaces ? marriageEventDetail?.PLAC?.value : void 0;
3622
+ marriagePlaces.push(marriagePlace);
3623
+ marriageDates.push(marriageDate);
3624
+ const formattedDate = noteDateFormatter(
3625
+ marriageDate,
3626
+ showDays ? fullDateFormat : "yyyy",
3627
+ "\u221E",
3628
+ shortNote,
3629
+ showNote
3630
+ );
3631
+ return formattedDate ? formattedDate : void 0;
3632
+ });
3705
3633
  });
3634
+ const marriageArray = marriages.length ? marriages.filter(Boolean) : [];
3635
+ const datesArray = marriageArray.filter(Boolean);
3636
+ const placesArray = marriagePlaces.filter(Boolean);
3637
+ const dates = datesArray.join(" ").trim();
3638
+ return {
3639
+ rawArray: marriageDates,
3640
+ inArray: datesArray,
3641
+ inOrder: dates,
3642
+ places: placesArray,
3643
+ marriage: marriageArray,
3644
+ ...showPlaces ? {
3645
+ marriages,
3646
+ marriagePlaces
3647
+ } : {}
3648
+ };
3706
3649
  };
3707
- var createCommon = (gedcom, id, main, parent) => {
3708
- return createProxy(
3709
- new Common(gedcom, id, main, parent)
3650
+ var dateFormatter = (indi, showMarriages = false, showDays = false, showPlaces = false, shortNote = true, showNote = true, isOnStage, showAllEvents = false, dateFormatPattern) => {
3651
+ const fullDateFormat = i18n.t("dateFormat");
3652
+ const birthEvents = getAllProp(indi, "BIRT");
3653
+ const firstBirthValue = birthEvents[0];
3654
+ const deathEvents = getAllProp(indi, "DEAT");
3655
+ const firstDeathValue = deathEvents[0];
3656
+ const birth = commonDateFormatter(
3657
+ firstBirthValue?.DATE,
3658
+ showDays ? fullDateFormat : "yyyy"
3710
3659
  );
3711
- };
3712
- var isOnlyMainProp = (key) => {
3713
- return key === "_gedcom" || key === "_main" || key === "_parent" || key === "_uniqueId" || key === "_type" || key === "_refs" || key === "id" || key === "_id";
3714
- };
3715
- var isValidKey = (common, key) => {
3716
- const prop = get(common, key);
3717
- return key !== "_gedcom" && key !== "_main" && key !== "_parent" && key !== "_uniqueId" && key !== "_refs" && key !== "_type" && !(typeof key === "string" && isGedcomTrailerTag(key)) && (key === "id" || key === "_id" || key === "value" || key === "_value" || prop instanceof Common || prop instanceof List);
3718
- };
3719
- var getValidKeys = (common) => {
3720
- return Object.keys(common).filter((key) => {
3721
- return isValidKey(common, key);
3660
+ const birthPlace = showPlaces ? firstBirthValue?.PLAC?.value : void 0;
3661
+ const death = commonDateFormatter(
3662
+ firstDeathValue?.DATE,
3663
+ showDays ? fullDateFormat : "yyyy"
3664
+ );
3665
+ const deathPlace = showPlaces ? firstDeathValue?.PLAC?.value : void 0;
3666
+ const marriagePlaces = [];
3667
+ const marriages = [];
3668
+ if (showMarriages || isOnStage) {
3669
+ (indi?.get("FAMS")?.toValueList().values() ?? []).forEach((fam) => {
3670
+ const famRef = fam?.ref;
3671
+ const marriageDates = marriageDateFormatter(
3672
+ famRef,
3673
+ showDays,
3674
+ showPlaces,
3675
+ shortNote,
3676
+ showNote,
3677
+ true,
3678
+ showAllEvents);
3679
+ marriages.push(...marriageDates?.marriage ?? []);
3680
+ marriagePlaces.push(...marriageDates?.marriagePlaces ?? []);
3681
+ });
3682
+ }
3683
+ const birthStrings = [];
3684
+ const birthPlaces = [];
3685
+ const eventsToProcess = showAllEvents ? birthEvents : birthEvents.slice(0, 1);
3686
+ eventsToProcess.forEach((birthEvent) => {
3687
+ const birthDateNode = firstDate(birthEvent?.DATE);
3688
+ const birthDate = commonDateFormatter(
3689
+ birthDateNode,
3690
+ showDays ? fullDateFormat : "yyyy"
3691
+ );
3692
+ const birthEventNote = dateNote(birthDateNode, shortNote);
3693
+ const birthEventPlace = showPlaces ? birthEvent?.PLAC?.value : void 0;
3694
+ if (birthDate) {
3695
+ birthStrings.push(
3696
+ `*${birthEventNote && showNote ? i18n.t(`${birthEventNote} {{date}}`, {
3697
+ date: birthDate
3698
+ }) : birthDate}`
3699
+ );
3700
+ }
3701
+ birthPlaces.push(birthEventPlace);
3722
3702
  });
3703
+ const deathStrings = [];
3704
+ const deathPlaces = [];
3705
+ const deathEventsToProcess = showAllEvents ? deathEvents : deathEvents.slice(0, 1);
3706
+ deathEventsToProcess.forEach((deathEvent) => {
3707
+ const deathDateNode = firstDate(deathEvent?.DATE);
3708
+ const deathDate = commonDateFormatter(
3709
+ deathDateNode,
3710
+ showDays ? fullDateFormat : "yyyy"
3711
+ );
3712
+ const deathEventNote = dateNote(deathDateNode, shortNote);
3713
+ const deathEventPlace = showPlaces ? deathEvent?.PLAC?.value : void 0;
3714
+ if (deathDate) {
3715
+ deathStrings.push(
3716
+ `\u2020${deathEventNote && showNote ? i18n.t(`${deathEventNote} {{date}}`, {
3717
+ date: deathDate
3718
+ }) : deathDate}`
3719
+ );
3720
+ }
3721
+ deathPlaces.push(deathEventPlace);
3722
+ });
3723
+ const birthString = birthStrings[0] ?? "";
3724
+ const deathString = deathStrings[0] ?? "";
3725
+ const marriageArray = marriages.length ? marriages.filter(Boolean) : [];
3726
+ const datesArray = !birth && !death ? marriageArray : [...birthStrings, ...marriageArray, ...deathStrings];
3727
+ const placesArray = !birth && !death ? marriagePlaces : [...birthPlaces, ...marriagePlaces, ...deathPlaces];
3728
+ const nonNullDatesArray = datesArray.filter(Boolean);
3729
+ const dates = nonNullDatesArray.join(" ").trim();
3730
+ return {
3731
+ inArray: nonNullDatesArray,
3732
+ inOrder: dates,
3733
+ places: placesArray,
3734
+ birth: birthString,
3735
+ marriage: marriageArray,
3736
+ death: deathString,
3737
+ ...showPlaces ? {
3738
+ birthPlace,
3739
+ deathPlace,
3740
+ ...showMarriages ? { marriages, marriagePlaces } : {}
3741
+ } : {},
3742
+ ...showAllEvents ? {
3743
+ births: birthStrings,
3744
+ birthPlaces,
3745
+ deaths: deathStrings,
3746
+ deathPlaces
3747
+ } : {}
3748
+ };
3723
3749
  };
3724
- var getValidTag = (tag) => {
3725
- return tag.replace(/^@@/, "");
3726
- };
3727
- var getListTag = (tag) => {
3728
- return `@@${tag}`;
3750
+
3751
+ // src/utils/range.ts
3752
+ var toTuple = (r) => {
3753
+ if (Array.isArray(r)) {
3754
+ const [s2, e2] = r;
3755
+ return [
3756
+ s2 === void 0 ? void 0 : Number(s2),
3757
+ e2 === void 0 ? void 0 : Number(e2)
3758
+ ];
3759
+ }
3760
+ if (r === "-" || r === "") return [void 0, void 0];
3761
+ const [s, e] = r.split("-");
3762
+ return [s ? Number(s) : void 0, e ? Number(e) : void 0];
3729
3763
  };
3730
- var isId = (string) => {
3731
- return ID_REG.test(string);
3764
+ var isValidRange = (range) => {
3765
+ if (!Array.isArray(range) && range !== "" && range !== "-" && !/^\d*-\d*$/.test(range)) {
3766
+ return false;
3767
+ }
3768
+ if (Array.isArray(range) && range.some((r) => typeof r === "string" && isNaN(Number(r)))) {
3769
+ return false;
3770
+ }
3771
+ return true;
3732
3772
  };
3733
- var idGetter = (id) => {
3734
- if (id === void 0) {
3735
- return void 0;
3773
+ var inRange = (year, range, trueIfNoYear = false) => {
3774
+ if (!isValidRange(range)) {
3775
+ return false;
3736
3776
  }
3737
- let newId = `${id}`;
3738
- const parts = newId?.match(ID_GETTER_REG)?.groups;
3739
- if (!parts?.at && !parts?.letter) {
3740
- newId = `@U${newId}`;
3741
- } else if (!parts.at) {
3742
- newId = `@${newId}`;
3743
- } else if (!parts.letter) {
3744
- newId = newId.replace(/^@/, "@U");
3777
+ if (!year) {
3778
+ return trueIfNoYear;
3745
3779
  }
3746
- if (!newId.endsWith("@")) {
3747
- newId = `${newId}@`;
3780
+ const [start = -Infinity, end = Infinity] = toTuple(range);
3781
+ if (!start && !end) {
3782
+ return true;
3748
3783
  }
3749
- return newId;
3784
+ if (start && !end) {
3785
+ return Number(year) >= Number(start);
3786
+ }
3787
+ if (!start && end) {
3788
+ return Number(year) <= Number(end);
3789
+ }
3790
+ return Number(start) <= Number(year) && Number(year) <= Number(end);
3750
3791
  };
3751
3792
 
3752
3793
  // src/classes/date.ts
@@ -3800,6 +3841,8 @@ var formatDateWithComponents = (date, hasDay, hasMonth, hasYear, noteValue, base
3800
3841
  var CommonDate = class extends Common {
3801
3842
  constructor(gedcom, id, main, parent) {
3802
3843
  super(gedcom, id, main, parent);
3844
+ /** One DATE per event — merge must not turn this into a List. */
3845
+ this.isListable = false;
3803
3846
  delete this.id;
3804
3847
  }
3805
3848
  get calendar() {
@@ -7320,14 +7363,15 @@ var Indi = class extends Common {
7320
7363
  }
7321
7364
  return foundPath;
7322
7365
  }
7323
- kinship(other, showMainPerson, lang = "en", entirePath, displayName = "givenname") {
7366
+ kinship(other, showMainPerson, lang = "en", entirePath, displayName = "givenname", nameOrder) {
7324
7367
  const KinshipTranslatorClass2 = getKinshipTranslatorClass();
7325
7368
  const translator = new KinshipTranslatorClass2(
7326
7369
  this,
7327
7370
  other,
7328
7371
  lang,
7329
7372
  entirePath,
7330
- showMainPerson ? displayName : void 0
7373
+ showMainPerson ? displayName : void 0,
7374
+ nameOrder
7331
7375
  );
7332
7376
  return translator.translate(!!showMainPerson);
7333
7377
  }
@@ -8321,7 +8365,7 @@ var KinshipTranslatorDe = class extends KinshipTranslatorBasic {
8321
8365
  }
8322
8366
  of(relation) {
8323
8367
  const formattedName = nameFormatter(this.path?.[0]?.indi, {
8324
- nameOrder: "first-last"
8368
+ nameOrder: this.nameOrder
8325
8369
  });
8326
8370
  let name = formattedName.inOrder.filter(Boolean).join(" ");
8327
8371
  if (this.displayName === "none") {