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