@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.
@@ -353,202 +353,6 @@ var cacheDiscoveredPath = (gedcom, path) => {
353
353
  }
354
354
  };
355
355
 
356
- // src/utils/get-all-prop.ts
357
- var getAllProp = (indi, prop) => {
358
- return prop && (indi?.get(prop)?.toList().values() ?? []).filter(Boolean) || [];
359
- };
360
-
361
- // src/utils/date-formatter.ts
362
- var ACCEPTED_DATE_FORMATS = [
363
- "yyyy.MM.dd.",
364
- "yyyy-MM-dd",
365
- "MM/dd/yyyy"
366
- ];
367
- var ACCEPTED_DATE_FORMATS_REGEX = new RegExp(
368
- `(${ACCEPTED_DATE_FORMATS.map(
369
- (acceptedFormat) => acceptedFormat.replace(/[^.\-/]/g, "\\d")
370
- ).join("|")})`,
371
- "gi"
372
- );
373
- var commonDateFormatter = (date, format2 = "yyyy", prefix = "") => {
374
- const formattedDate = date?.toValue(format2);
375
- if (!formattedDate) {
376
- return void 0;
377
- }
378
- return `${prefix}${formattedDate}`.trim();
379
- };
380
- var noteDateFormatter = (date, format2 = "yyyy", prefix = "", shortNote = true, showNote = true) => {
381
- const rawDate = commonDateFormatter(date, format2, "");
382
- if (!rawDate) {
383
- return void 0;
384
- }
385
- const note = date?.toNote(shortNote) ?? "";
386
- return `${prefix}${note && showNote ? i18n.t(`${note} {{date}}`, { date: rawDate }) : rawDate}`;
387
- };
388
- var marriageDateFormatter = (fam, showDays = false, showPlaces = false, shortNote = true, showNote = true, showDisplayTextIfNoDate = true, showAllEvents = false, dateFormatPattern) => {
389
- const fullDateFormat = i18n.t("dateFormat");
390
- const marriageDates = [];
391
- const marriagePlaces = [];
392
- const marriages = (fam?.toValueList().values() ?? []).flatMap((fam2) => {
393
- const family = fam2;
394
- const marrEvents = (family?.MARR?.toList().values() ?? []).filter(
395
- Boolean
396
- );
397
- if (marrEvents.length === 0) {
398
- const displayText = family?.get("DISPLAYTEXT")?.toValue() ?? "";
399
- if (showDisplayTextIfNoDate && displayText) {
400
- const displayDate = displayText.match(
401
- ACCEPTED_DATE_FORMATS_REGEX
402
- )?.[0];
403
- if (displayDate) {
404
- marriagePlaces.push(displayText.replace(displayDate, ""));
405
- const marriageDate = createCommonDate(
406
- fam2?.getGedcom(),
407
- void 0,
408
- family
409
- );
410
- marriageDate.value = displayDate;
411
- marriageDates.push(marriageDate);
412
- } else {
413
- marriagePlaces.push(displayText);
414
- marriageDates.push(void 0);
415
- return ["\u221E"];
416
- }
417
- }
418
- return [];
419
- }
420
- const eventsToProcess = showAllEvents ? marrEvents : marrEvents.slice(0, 1);
421
- return eventsToProcess.map((marrEvent) => {
422
- const marriageEventDetail = marrEvent;
423
- const marriageDate = marriageEventDetail?.DATE;
424
- const marriagePlace = showPlaces ? marriageEventDetail?.PLAC?.value : void 0;
425
- marriagePlaces.push(marriagePlace);
426
- marriageDates.push(marriageDate);
427
- const formattedDate = noteDateFormatter(
428
- marriageDate,
429
- showDays ? fullDateFormat : "yyyy",
430
- "\u221E",
431
- shortNote,
432
- showNote
433
- );
434
- return formattedDate ? formattedDate : void 0;
435
- });
436
- });
437
- const marriageArray = marriages.length ? marriages.filter(Boolean) : [];
438
- const datesArray = marriageArray.filter(Boolean);
439
- const placesArray = marriagePlaces.filter(Boolean);
440
- const dates = datesArray.join(" ").trim();
441
- return {
442
- rawArray: marriageDates,
443
- inArray: datesArray,
444
- inOrder: dates,
445
- places: placesArray,
446
- marriage: marriageArray,
447
- ...showPlaces ? {
448
- marriages,
449
- marriagePlaces
450
- } : {}
451
- };
452
- };
453
- var dateFormatter = (indi, showMarriages = false, showDays = false, showPlaces = false, shortNote = true, showNote = true, isOnStage, showAllEvents = false, dateFormatPattern) => {
454
- const fullDateFormat = i18n.t("dateFormat");
455
- const birthEvents = getAllProp(indi, "BIRT");
456
- const firstBirthValue = birthEvents[0];
457
- const deathEvents = getAllProp(indi, "DEAT");
458
- const firstDeathValue = deathEvents[0];
459
- const birth = commonDateFormatter(
460
- firstBirthValue?.DATE,
461
- showDays ? fullDateFormat : "yyyy"
462
- );
463
- const birthPlace = showPlaces ? firstBirthValue?.PLAC?.value : void 0;
464
- const death = commonDateFormatter(
465
- firstDeathValue?.DATE,
466
- showDays ? fullDateFormat : "yyyy"
467
- );
468
- const deathPlace = showPlaces ? firstDeathValue?.PLAC?.value : void 0;
469
- const marriagePlaces = [];
470
- const marriages = [];
471
- if (showMarriages || isOnStage) {
472
- (indi?.get("FAMS")?.toValueList().values() ?? []).forEach((fam) => {
473
- const famRef = fam?.ref;
474
- const marriageDates = marriageDateFormatter(
475
- famRef,
476
- showDays,
477
- showPlaces,
478
- shortNote,
479
- showNote,
480
- true,
481
- showAllEvents);
482
- marriages.push(...marriageDates?.marriage ?? []);
483
- marriagePlaces.push(...marriageDates?.marriagePlaces ?? []);
484
- });
485
- }
486
- const birthStrings = [];
487
- const birthPlaces = [];
488
- const eventsToProcess = showAllEvents ? birthEvents : birthEvents.slice(0, 1);
489
- eventsToProcess.forEach((birthEvent) => {
490
- const birthDate = commonDateFormatter(
491
- birthEvent?.DATE,
492
- showDays ? fullDateFormat : "yyyy"
493
- );
494
- const birthEventNote = birthEvent?.DATE?.toNote(shortNote) ?? "";
495
- const birthEventPlace = showPlaces ? birthEvent?.PLAC?.value : void 0;
496
- if (birthDate) {
497
- birthStrings.push(
498
- `*${birthEventNote && showNote ? i18n.t(`${birthEventNote} {{date}}`, {
499
- date: birthDate
500
- }) : birthDate}`
501
- );
502
- }
503
- birthPlaces.push(birthEventPlace);
504
- });
505
- const deathStrings = [];
506
- const deathPlaces = [];
507
- const deathEventsToProcess = showAllEvents ? deathEvents : deathEvents.slice(0, 1);
508
- deathEventsToProcess.forEach((deathEvent) => {
509
- const deathDate = commonDateFormatter(
510
- deathEvent?.DATE,
511
- showDays ? fullDateFormat : "yyyy"
512
- );
513
- const deathEventNote = deathEvent?.DATE?.toNote(shortNote) ?? "";
514
- const deathEventPlace = showPlaces ? deathEvent?.PLAC?.value : void 0;
515
- if (deathDate) {
516
- deathStrings.push(
517
- `\u2020${deathEventNote && showNote ? i18n.t(`${deathEventNote} {{date}}`, {
518
- date: deathDate
519
- }) : deathDate}`
520
- );
521
- }
522
- deathPlaces.push(deathEventPlace);
523
- });
524
- const birthString = birthStrings[0] ?? "";
525
- const deathString = deathStrings[0] ?? "";
526
- const marriageArray = marriages.length ? marriages.filter(Boolean) : [];
527
- const datesArray = !birth && !death ? marriageArray : [...birthStrings, ...marriageArray, ...deathStrings];
528
- const placesArray = !birth && !death ? marriagePlaces : [...birthPlaces, ...marriagePlaces, ...deathPlaces];
529
- const nonNullDatesArray = datesArray.filter(Boolean);
530
- const dates = nonNullDatesArray.join(" ").trim();
531
- return {
532
- inArray: nonNullDatesArray,
533
- inOrder: dates,
534
- places: placesArray,
535
- birth: birthString,
536
- marriage: marriageArray,
537
- death: deathString,
538
- ...showPlaces ? {
539
- birthPlace,
540
- deathPlace,
541
- ...showMarriages ? { marriages, marriagePlaces } : {}
542
- } : {},
543
- ...showAllEvents ? {
544
- births: birthStrings,
545
- birthPlaces,
546
- deaths: deathStrings,
547
- deathPlaces
548
- } : {}
549
- };
550
- };
551
-
552
356
  // src/utils/gedcom-trailer.ts
553
357
  var GEDCOM_TRAILER_TAG = "TRLR";
554
358
  var isGedcomTrailerTag = (tag) => tag === GEDCOM_TRAILER_TAG;
@@ -628,1087 +432,1313 @@ var objeXrefKey = (obje, fallback = 0) => {
628
432
  return `@O${fallback}@`;
629
433
  };
630
434
  var objeNoteValue = (obje) => mediaIdValue(obje, "FILE.NOTE") || mediaIdValue(obje, "NOTE") || "";
631
- var List = class _List {
632
- // length = 0;
633
- constructor(items) {
634
- this.items = {};
435
+
436
+ // src/classes/common.ts
437
+ var Common = class _Common {
438
+ constructor(gedcom, id, main, parent) {
635
439
  this.isListable = true;
636
- this.marker = void 0;
637
- if (items) {
638
- this.concat(items);
440
+ this._gedcom = gedcom;
441
+ this._main = main;
442
+ this._parent = parent;
443
+ this.initUniqueId();
444
+ if (id) {
445
+ this._id = id;
446
+ } else {
447
+ delete this._id;
639
448
  }
640
449
  }
641
- get length() {
642
- return this.values().length;
450
+ set type(type) {
451
+ if (type) {
452
+ this.uniqueId = this.uniqueId?.replace(/^[^:]+/, `~${type}`);
453
+ }
454
+ this._type = type;
643
455
  }
644
- has(indi) {
645
- return !!this.item(
646
- typeof indi === "string" ? indi : indi?.id ?? ""
647
- );
456
+ get type() {
457
+ return this._type;
648
458
  }
649
- get(name) {
650
- const propList = new _List();
651
- this.entries().forEach(([key, item]) => {
652
- propList.item(key, item.get(name));
653
- });
654
- return propList;
459
+ initUniqueId() {
460
+ if (this._gedcom) {
461
+ this.uniqueId = `~Common:${this._gedcom.refcount++}`;
462
+ }
655
463
  }
656
- getIf(name, condition, name2) {
657
- const propList = new _List();
658
- this.entries().forEach(([key, item]) => {
659
- const passedItem = item.getIf(name, condition, name2);
660
- if (passedItem) {
661
- propList.item(key, passedItem);
464
+ set uniqueId(id) {
465
+ const currentId = this._uniqueId;
466
+ if (this._gedcom?.reflist && id) {
467
+ this._uniqueId = id;
468
+ if (currentId && this._gedcom.reflist[currentId]) {
469
+ delete this._gedcom.reflist[currentId];
662
470
  }
663
- });
664
- return propList;
471
+ this._gedcom.reflist[id] = this;
472
+ }
665
473
  }
666
- keys() {
667
- return Object.keys(this.items);
474
+ get uniqueId() {
475
+ return this._uniqueId;
668
476
  }
669
- values() {
670
- return Object.values(this.items);
477
+ set id(id) {
478
+ this._id = idGetter(id);
671
479
  }
672
- entries() {
673
- return Object.entries(this.items);
480
+ get id() {
481
+ return idGetter(this._id);
674
482
  }
675
- setLength(_type) {
483
+ set value(value) {
484
+ this._value = value;
676
485
  }
677
- first() {
678
- return this.index(0);
486
+ get value() {
487
+ return this._value;
679
488
  }
680
- last() {
681
- return this.index(this.keys().length - 1);
489
+ /**
490
+ * Set the gedcom reference for this object
491
+ * @param gedcom - The GedComType to set as the gedcom reference
492
+ */
493
+ setGedcom(gedcom) {
494
+ this._gedcom = gedcom;
682
495
  }
683
- index(index) {
684
- const keys = this.keys();
685
- const key = keys[index];
686
- return key && this.items[key];
496
+ // avoid to override
497
+ get originalValue() {
498
+ return this._value;
687
499
  }
688
- item(name, value) {
689
- if (arguments.length > 1) {
690
- set(this.items, name, value);
691
- this.setLength();
500
+ get ref() {
501
+ if (typeof this.value === "string" && isId(this.value) && this.refType) {
502
+ return this._gedcom?.[getListTag(this.refType)]?.item(
503
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
504
+ this.value
505
+ );
692
506
  }
693
- return get(this.items, name);
507
+ return this;
694
508
  }
695
- removeItem(name) {
696
- unset(this.items, name);
697
- this.setLength();
509
+ get main() {
510
+ return this._main;
698
511
  }
699
- exclude(excludedList) {
700
- excludedList.keys().forEach((itemId) => {
701
- delete this.items[itemId];
702
- });
703
- this.setLength();
704
- return this;
512
+ get parent() {
513
+ return this._parent;
705
514
  }
706
- concat(items) {
707
- if (Array.isArray(items)) {
708
- items.forEach((item) => {
709
- this.append(item);
710
- });
711
- } else {
712
- Object.assign(this.items, items ?? {});
515
+ addRef(refNode) {
516
+ if (typeof refNode.value === "string" && isId(refNode.value) && refNode.refType) {
517
+ if (!this._refs) {
518
+ this._refs = new List();
519
+ }
520
+ this._refs.item(refNode.value, refNode);
713
521
  }
714
- this.setLength();
715
- return this;
716
522
  }
717
- merge(mergedList) {
718
- this.concat(mergedList?.items);
719
- return this;
523
+ getRefs() {
524
+ return this._refs;
720
525
  }
721
- intersection(mergedList) {
722
- const inter = intersectionBy(
723
- this.values(),
724
- mergedList?.values() ?? [],
725
- "id"
726
- );
727
- return new _List(inter);
526
+ exportValue() {
527
+ return this.value;
728
528
  }
729
- difference(mergedList) {
730
- const inter = differenceBy(
731
- this.values(),
732
- mergedList?.values() ?? [],
733
- "id"
734
- );
735
- return new _List(inter);
529
+ removeValue() {
530
+ delete this._value;
736
531
  }
737
- prepend(item) {
738
- if (item.id) {
739
- let increase = true;
740
- if (this.items[item.id]) {
741
- delete this.items[item.id];
742
- increase = false;
743
- }
744
- this.items = Object.assign(
745
- {
746
- [item.id]: item
747
- },
748
- this.items
749
- );
750
- if (increase) {
751
- this.setLength("increase");
532
+ set(name, value) {
533
+ if (isGedcomTrailerTag(name)) {
534
+ return void 0;
535
+ }
536
+ if (typeof value === "string") {
537
+ const usedValue = createCommon(this._gedcom, void 0, this.main);
538
+ usedValue.value = value;
539
+ set(this, name, usedValue);
540
+ } else {
541
+ set(this, name, value);
542
+ }
543
+ return get(this, name);
544
+ }
545
+ assign(name, value, unique = false) {
546
+ if (isGedcomTrailerTag(name)) {
547
+ return void 0;
548
+ }
549
+ let curValue = this.get(name);
550
+ if (curValue?.isListable) {
551
+ if (curValue instanceof _Common) {
552
+ curValue = new List().concat({ ...[curValue] });
553
+ this.set(name, curValue);
752
554
  }
555
+ const values = [
556
+ ...curValue.values(),
557
+ ...value instanceof List ? value.values() : [value]
558
+ ];
559
+ curValue.concat({
560
+ ...!unique ? values : uniqBy(
561
+ values,
562
+ (value2) => value2 instanceof _Common ? value2?.value : void 0
563
+ )
564
+ });
565
+ } else {
566
+ this.set(name, value);
753
567
  }
754
- return this;
568
+ return get(this, name);
755
569
  }
756
- append(item) {
757
- if (item.id) {
758
- let increase = true;
759
- if (this.items[item.id]) {
760
- delete this.items[item.id];
761
- increase = false;
570
+ get(name) {
571
+ if (!name.includes(".")) {
572
+ return get(this, name);
573
+ }
574
+ const nameParts = name.split(".");
575
+ let last = this;
576
+ for (const part of nameParts) {
577
+ const indexPart = Number(part);
578
+ const itemIndex = part.match(/items\[(?<itemIndex>\d+)\]/)?.groups?.itemIndex;
579
+ const itemId = part.match(/items\[(?<itemId>@[A-Z]+\d+@)\]/)?.groups?.itemId;
580
+ const usedPart = itemId || itemIndex;
581
+ if (last instanceof List) {
582
+ if (!isNaN(indexPart)) {
583
+ last = last.index(indexPart);
584
+ } else {
585
+ if (usedPart) {
586
+ last = last.item(usedPart);
587
+ } else {
588
+ last = last?.index(0)?.get(part);
589
+ }
590
+ }
591
+ } else {
592
+ const usedIndex = Number(itemIndex ?? indexPart);
593
+ if (!isNaN(usedIndex)) {
594
+ last = last?.toList().index(usedIndex);
595
+ } else {
596
+ last = last?.get(itemId ?? part);
597
+ }
762
598
  }
763
- this.items[item.id] = item;
764
- if (increase) {
765
- this.setLength("increase");
599
+ if (!last) {
600
+ break;
766
601
  }
767
602
  }
768
- return this;
603
+ return last;
769
604
  }
770
- delete(item) {
771
- if (item.id && this.items[item.id]) {
772
- delete this.items[item.id];
773
- this.setLength("decrease");
605
+ remove(name) {
606
+ unset(this, name);
607
+ }
608
+ getGedcom() {
609
+ return this._gedcom;
610
+ }
611
+ getIf(name, condition, name2) {
612
+ const nameParts = name.split(".");
613
+ const name2Parts = name2.split(".");
614
+ if (nameParts.length !== name2Parts.length) {
615
+ throw new Error("Tag pathes must be of the same depth");
774
616
  }
775
- return this;
617
+ if (nameParts.length > 1 && nameParts[0] !== name2Parts[0]) {
618
+ throw new Error("Final tags must be siblings");
619
+ }
620
+ const valueCommon = this.get(name);
621
+ if (valueCommon instanceof _Common) {
622
+ return valueCommon?.toValue() !== condition ? void 0 : this.get(name2);
623
+ }
624
+ const valueCommon2 = this.get(name2)?.toList();
625
+ const ifList = new List();
626
+ valueCommon?.forEach((item, key) => {
627
+ const pair = valueCommon2?.item(key);
628
+ ifList.item(key, item?.toValue() !== condition ? void 0 : pair);
629
+ });
630
+ return ifList;
776
631
  }
777
- copy(ClassName = _List) {
778
- const newList = new ClassName();
779
- Object.assign(newList.items, this.items);
780
- newList.setLength();
781
- return newList;
632
+ toString() {
633
+ return this.value?.toString() || "";
782
634
  }
783
- except(item, ClassName = _List) {
784
- return this.copy(ClassName).delete(item);
635
+ toValue() {
636
+ return this.value;
785
637
  }
786
- forEach(iterate) {
787
- this.entries().forEach(([key, item], index) => {
788
- iterate(item, key, index);
789
- });
638
+ toProp(tag) {
639
+ const prop = this.get(tag);
640
+ return prop;
790
641
  }
791
- map(iterate) {
792
- return this.entries().map(([key, item], index) => {
793
- return iterate(item, key, index);
794
- });
642
+ toList() {
643
+ return new List().concat(
644
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
645
+ this.id ? { [this.id]: this } : { ...[this] }
646
+ );
795
647
  }
796
- reduce(iterate, initialValue) {
797
- return this.entries().reduce((acc, [key, item], index) => {
798
- return iterate(acc, item, key, index);
799
- }, initialValue);
648
+ index(i) {
649
+ return this.toList()?.index(i);
800
650
  }
801
- filter(filters, ClassName = _List) {
802
- const newList = new ClassName();
803
- const isIterator = typeof filters === "function";
804
- this.entries().forEach(([itemId, item], index) => {
805
- if (isIterator) {
806
- filters(item, itemId, index) && newList.item(itemId, item);
807
- return;
808
- }
809
- if (!Object.keys(filters).length || Object.entries(filters).every(([key, value]) => {
810
- let itemValue;
811
- if (key === "id") {
812
- itemValue = item.toProp("id");
813
- } else {
814
- itemValue = item.toProp(key)?.toValue();
815
- }
816
- if (Array.isArray(value)) {
817
- return value.includes(itemValue);
818
- }
819
- return itemValue === value;
820
- })) {
821
- newList.item(itemId, item);
822
- }
823
- });
824
- return newList;
651
+ toValueList() {
652
+ return new List().concat(
653
+ this.value ? { [this.value]: this } : (
654
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
655
+ { ...[this] }
656
+ )
657
+ );
825
658
  }
826
- find(filters, _ClassName = _List) {
827
- let foundItem;
828
- const isIterator = typeof filters === "function";
829
- this.entries().find(([itemId, item], index) => {
830
- if (isIterator) {
831
- if (filters(item, itemId, index)) {
832
- foundItem = item;
833
- return true;
834
- }
835
- return false;
659
+ standardizeObject(tag, options) {
660
+ if (tag === "OBJE" && options?.obje?.standardize && "standardizeMedia" in this) {
661
+ const standardize = this.standardizeMedia;
662
+ return standardize.call(
663
+ this,
664
+ options.obje.namespace,
665
+ options.obje.override,
666
+ this.isAncestry() ? ancestryMediaFileUrl : void 0,
667
+ options.gedcomVersion
668
+ );
669
+ }
670
+ }
671
+ toJson(tag, options) {
672
+ const json = this.toObject(tag, options);
673
+ return JSON.stringify(json);
674
+ }
675
+ toObject(tag, options) {
676
+ this.standardizeObject(tag, options);
677
+ const validKeys = getValidKeys(this);
678
+ let json = {};
679
+ validKeys.forEach((key) => {
680
+ if (options?.persist && (key === "DAY" || key === "MONTH" || key === "YEAR")) {
681
+ return;
836
682
  }
837
- if (!Object.keys(filters).length || Object.entries(filters).every(([key, value]) => {
838
- let itemValue;
839
- if (key === "id") {
840
- itemValue = item.toProp("id");
841
- } else {
842
- itemValue = item.toProp(key)?.toValue();
843
- }
844
- if (Array.isArray(value)) {
845
- return value.includes(itemValue);
683
+ if (key === "id" && this.id !== void 0) {
684
+ json.id = this.id;
685
+ } else if (key === "_id" && this._id !== void 0) {
686
+ json.id = this._id;
687
+ } else if (key === "value" && this.value !== void 0) {
688
+ json.value = this.value;
689
+ } else if (key === "_value" && this._value !== void 0) {
690
+ json.value = this._value;
691
+ } else {
692
+ const validKey = key;
693
+ const prop = this.get(validKey);
694
+ if (typeof prop?.toObject === "function") {
695
+ if (prop instanceof _Common) {
696
+ json[validKey] = prop.toObject(validKey, options);
697
+ } else if (prop instanceof List) {
698
+ json = {
699
+ ...json,
700
+ ...prop.toObject(validKey, options)
701
+ };
702
+ }
846
703
  }
847
- return itemValue === value;
848
- })) {
849
- foundItem = item;
850
- return true;
851
704
  }
852
- return false;
853
705
  });
854
- return foundItem;
706
+ return json;
855
707
  }
856
- orderBy(orders, ClassName = _List) {
857
- const newList = new ClassName();
858
- const isIterator = typeof orders === "function";
859
- if (!isIterator && (!orders || !Object.keys(orders).length)) {
860
- return newList.merge(this);
708
+ merge(other, override = false, avoidKeys = []) {
709
+ if (!other) {
710
+ return this;
861
711
  }
862
- const sortedItems = this.entries().toSorted(
863
- ([itemAId, itemA], [itemBId, itemB]) => {
864
- if (isIterator) {
865
- return orders(itemA, itemAId, itemB, itemBId);
866
- }
867
- const [key, { direction, getter }] = Object.entries(
868
- typeof orders === "string" ? { [orders]: { direction: "ASC" } } : orders
869
- )[0];
870
- const rawA = itemA.get(key);
871
- const rawB = itemB.get(key);
872
- let valueA = rawA?.toValue();
873
- let valueB = rawB?.toValue();
874
- if (getter && typeof getter === "function") {
875
- valueA = getter(valueA, rawA);
876
- valueB = getter(valueB, rawB);
877
- }
878
- let sortValue2 = 0;
879
- if (!valueA && valueA !== 0 && !valueB && valueB !== 0) {
880
- sortValue2 = 0;
881
- } else if (!valueB && valueB !== 0) {
882
- sortValue2 = 1;
883
- } else if (!valueA && valueA !== 0) {
884
- sortValue2 = -1;
885
- } else if (valueA < valueB) {
886
- sortValue2 = -1;
887
- } else if (valueA > valueB) {
888
- sortValue2 = 1;
889
- }
890
- return sortValue2 * (direction === "DESC" ? -1 : 1);
712
+ const validKeys = getValidKeys(other);
713
+ validKeys.forEach((validKey) => {
714
+ if (avoidKeys.includes(validKey)) {
715
+ return;
891
716
  }
892
- );
893
- sortedItems.forEach(([key, value]) => {
894
- newList.item(key, value);
895
- });
896
- return newList;
897
- }
898
- groupBy(groups, sort, minOccurance = -1, lessOccuranceLabel = "Appearing less than 5 times", ClassName = _List) {
899
- const groupped = {};
900
- const isIterator = typeof groups === "function";
901
- if (!isIterator && (!groups || !Object.keys(groups).length)) {
902
- groupped.Unknown = new ClassName().merge(this);
903
- groupped.Unknown.marker = "Unknown";
904
- return groupped;
905
- }
906
- this.forEach((item, itemId) => {
907
- const group = [];
908
- if (isIterator) {
909
- const newGroups = groups(item, itemId);
910
- group.push(
911
- ...Array.isArray(newGroups) ? newGroups : [newGroups]
912
- );
913
- } else {
914
- const [key, { getter }] = Object.entries(
915
- typeof groups === "string" ? { [groups]: {} } : groups
916
- )[0];
917
- const raw = item.get(key)?.index(0);
918
- let value = raw?.toValue();
919
- if (getter && typeof getter === "function") {
920
- value = getter(value, raw);
921
- }
922
- if (value) {
923
- group.push(value);
717
+ const current = this.get(validKey);
718
+ const mergeValue = other.get(validKey);
719
+ if (mergeValue) {
720
+ if (current instanceof _Common && !current.isListable) {
721
+ if (override) {
722
+ this.set(validKey, mergeValue);
723
+ }
724
+ } else if (current instanceof _Common || current instanceof List) {
725
+ this.assign(validKey, mergeValue, true);
726
+ } else if (!current || override && validKey !== "id" && validKey !== "_id") {
727
+ this.set(validKey, mergeValue);
924
728
  }
925
729
  }
926
- if (!group.length) {
927
- group.push("Unknown");
928
- }
929
- group.forEach((g) => {
930
- const newGroup = typeof g === "string" ? { group: g } : g;
931
- if (!groupped[newGroup.group]) {
932
- groupped[newGroup.group] = new ClassName();
933
- groupped[newGroup.group].marker = newGroup.marker ?? newGroup.group;
934
- }
935
- groupped[newGroup.group]?.append(item);
936
- });
937
730
  });
938
- if (sort) {
939
- return Object.entries(groupped).toSorted(([ak, a], [bk, b]) => {
940
- if (typeof sort === "function") {
941
- return sort(a, ak, b, bk);
942
- }
943
- if (ak === "Unknown") {
944
- return 1;
945
- }
946
- if (bk === "Unknown") {
947
- return -1;
948
- }
949
- if (sort === "group") {
950
- return ak.localeCompare(bk);
951
- }
952
- return (b?.length ?? 0) - (a?.length ?? 0);
953
- }).reduce((acc, [key, value]) => {
954
- if (minOccurance > -1 && (value?.length ?? 0) < minOccurance) {
955
- const otherKey = lessOccuranceLabel;
956
- acc[otherKey] = acc[otherKey] && value ? acc[otherKey].merge(value) : value;
957
- } else {
958
- acc[key] = value;
959
- }
960
- return acc;
961
- }, {});
962
- }
963
- return groupped;
731
+ return this;
964
732
  }
965
- findIndex(item) {
966
- if (!item?.id) {
967
- return -1;
733
+ clone(newId = false, avoidKeys = []) {
734
+ const ctor = this.constructor;
735
+ const instance = new ctor(
736
+ this._gedcom,
737
+ this._id,
738
+ this._main,
739
+ this._parent
740
+ );
741
+ if (newId && this._id) {
742
+ instance.id = `IFT${this._id.replace(/[^0-9]/g, "")}`;
968
743
  }
969
- return this.keys().findIndex((key) => key === item.id);
970
- }
971
- getItems() {
972
- return this.items;
973
- }
974
- toJson(tag, options) {
975
- const json = this.toObject(tag, options);
976
- return JSON.stringify(json);
744
+ const cloned = createProxy(instance);
745
+ cloned.merge(this, true, avoidKeys);
746
+ return cloned;
977
747
  }
978
- toObject(tag, options) {
979
- const json = {};
980
- this.entries().forEach(([_, item]) => {
981
- const validTag = getValidTag(tag);
982
- if (json[validTag]) {
983
- if (!Array.isArray(json[validTag])) {
984
- json[validTag] = [json[validTag]];
985
- }
986
- json[validTag].push(
987
- item.toObject(validTag, options)
988
- );
989
- } else {
990
- json[validTag] = item.toObject(
991
- validTag,
992
- options
993
- );
994
- }
995
- });
996
- return json;
748
+ // fromGedcom<T = typeof this>(value: string) {
749
+ fromGedcom(_value) {
997
750
  }
998
751
  toGedcom(tag, level = 0, options) {
999
752
  const gedcom = this.toGedcomLines(tag, level, options);
1000
753
  return gedcom.join("\n");
1001
754
  }
1002
755
  toGedcomLines(tag, level = 0, options) {
756
+ this.standardizeObject(tag, options);
757
+ const validKeys = getValidKeys(this);
1003
758
  const gedcom = [];
1004
- this.entries().forEach(([_, item]) => {
1005
- const validTag = getValidTag(tag);
1006
- const xref = item.id;
1007
- const payload = item.exportValue?.();
1008
- if (xref) {
1009
- gedcom.push(
1010
- `${level} ${xref} ${validTag}${payload ? ` ${payload}` : ""}`
1011
- );
1012
- } else {
1013
- gedcom.push(
1014
- `${level} ${validTag}${payload ? ` ${payload}` : ""}`
1015
- );
759
+ const isGedcom7Export = options?.gedcomVersion === "7.0";
760
+ validKeys.forEach((key) => {
761
+ const validKey = key;
762
+ if (isGedcom7Export && validKey === "CONC") {
763
+ return;
764
+ }
765
+ const prop = this.get(validKey);
766
+ if (typeof prop?.toGedcomLines === "function") {
767
+ if (prop instanceof _Common) {
768
+ const value = prop.exportValue();
769
+ gedcom.push(
770
+ `${level} ${validKey}${value ? ` ${value}` : ""}`
771
+ );
772
+ gedcom.push(
773
+ ...prop.toGedcomLines(validKey, level + 1, options)
774
+ );
775
+ } else if (prop instanceof List) {
776
+ gedcom.push(
777
+ ...prop.toGedcomLines(validKey, level, options)
778
+ );
779
+ }
1016
780
  }
1017
- gedcom.push(
1018
- ...item.toGedcomLines(
1019
- validTag,
1020
- level + 1,
1021
- options
1022
- )
1023
- );
1024
781
  });
1025
782
  return gedcom;
1026
783
  }
1027
- toValue() {
1028
- const propList = new _List();
1029
- this.entries().forEach(([key, item]) => {
1030
- propList.item(key, item?.toValue());
1031
- });
1032
- return propList;
1033
- }
1034
- // @deprecated use get instead
1035
- toProp(tag) {
1036
- return this.get(tag);
784
+ getHeadRecord() {
785
+ return get(this, "HEAD") || get(this.getGedcom(), "HEAD");
1037
786
  }
1038
- toList() {
1039
- return new _List().concat(this.items);
787
+ getOriginalHeadRecord() {
788
+ return get(this, ORIG_HEAD_TAG) || get(this.getGedcom(), ORIG_HEAD_TAG) || get(this.getHeadRecord(), ORIG_HEAD_TAG);
1040
789
  }
1041
- toValueList() {
1042
- const newList = new _List();
1043
- this.values().forEach((value) => {
1044
- value.value && newList.item(value.value, value);
790
+ getSourceHeads() {
791
+ const heads = [this.getOriginalHeadRecord(), this.getHeadRecord()];
792
+ return heads.filter((head, index) => {
793
+ return Boolean(head && heads.indexOf(head) === index);
1045
794
  });
1046
- return newList;
1047
- }
1048
- };
1049
-
1050
- // src/classes/common.ts
1051
- var Common = class _Common {
1052
- constructor(gedcom, id, main, parent) {
1053
- this.isListable = true;
1054
- this._gedcom = gedcom;
1055
- this._main = main;
1056
- this._parent = parent;
1057
- this.initUniqueId();
1058
- if (id) {
1059
- this._id = id;
1060
- } else {
1061
- delete this._id;
1062
- }
1063
- }
1064
- set type(type) {
1065
- if (type) {
1066
- this.uniqueId = this.uniqueId?.replace(/^[^:]+/, `~${type}`);
1067
- }
1068
- this._type = type;
1069
- }
1070
- get type() {
1071
- return this._type;
1072
- }
1073
- initUniqueId() {
1074
- if (this._gedcom) {
1075
- this.uniqueId = `~Common:${this._gedcom.refcount++}`;
1076
- }
1077
795
  }
1078
- set uniqueId(id) {
1079
- const currentId = this._uniqueId;
1080
- if (this._gedcom?.reflist && id) {
1081
- this._uniqueId = id;
1082
- if (currentId && this._gedcom.reflist[currentId]) {
1083
- delete this._gedcom.reflist[currentId];
796
+ getFromSourceHeads(path) {
797
+ for (const head of this.getSourceHeads()) {
798
+ const value = get(head, path);
799
+ if (value !== void 0 && value !== null && value !== "") {
800
+ return value;
1084
801
  }
1085
- this._gedcom.reflist[id] = this;
1086
802
  }
803
+ return void 0;
1087
804
  }
1088
- get uniqueId() {
1089
- return this._uniqueId;
805
+ sourStartsWith(prefix) {
806
+ return this.getSourceHeads().some((head) => {
807
+ const sour = get(head, "SOUR.value");
808
+ return !!sour?.toLowerCase()?.startsWith(prefix);
809
+ });
1090
810
  }
1091
- set id(id) {
1092
- this._id = idGetter(id);
811
+ isGenoPro() {
812
+ return this.sourStartsWith("genopro");
1093
813
  }
1094
- get id() {
1095
- return idGetter(this._id);
814
+ isAhnenblatt() {
815
+ return this.sourStartsWith("ahnenblatt");
1096
816
  }
1097
- set value(value) {
1098
- this._value = value;
817
+ isGeni() {
818
+ return this.sourStartsWith("geni");
1099
819
  }
1100
- get value() {
1101
- return this._value;
820
+ isAncestry() {
821
+ return this.sourStartsWith("ancestry");
822
+ }
823
+ isMyHeritage() {
824
+ return this.sourStartsWith("myheritage");
1102
825
  }
1103
826
  /**
1104
- * Set the gedcom reference for this object
1105
- * @param gedcom - The GedComType to set as the gedcom reference
827
+ * Get the source type as a string (for prefixing tree IDs and names)
828
+ * Returns the detected source type or undefined if unknown
1106
829
  */
1107
- setGedcom(gedcom) {
1108
- this._gedcom = gedcom;
830
+ getSourceType() {
831
+ if (this.isAncestry()) return "Ancestry";
832
+ if (this.isMyHeritage()) return "MyHeritage";
833
+ if (this.isFamilySearch()) return "FamilySearch";
834
+ if (this.isGNO2GED()) return "GNO2GED";
835
+ if (this.isGenoPro()) return "GenoPro";
836
+ if (this.isAhnenblatt()) return "Ahnenblatt";
837
+ if (this.isGeni()) return "Geni";
838
+ return void 0;
1109
839
  }
1110
- // avoid to override
1111
- get originalValue() {
1112
- return this._value;
840
+ isFamilySearch() {
841
+ return this.getSourceHeads().some((head) => {
842
+ const sourName = get(head, "SOUR.NAME.value");
843
+ return sourName === "FamilySearch API";
844
+ });
1113
845
  }
1114
- get ref() {
1115
- if (typeof this.value === "string" && isId(this.value) && this.refType) {
1116
- return this._gedcom?.[getListTag(this.refType)]?.item(
1117
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1118
- this.value
1119
- );
1120
- }
1121
- return this;
846
+ isGNO2GED() {
847
+ return this.getSourceHeads().some((head) => {
848
+ const sour = get(head, "SOUR.value");
849
+ return sour === "GNO2GED";
850
+ });
1122
851
  }
1123
- get main() {
1124
- return this._main;
852
+ getAncestryTreeId() {
853
+ return this.getFromSourceHeads("SOUR._TREE.RIN.value") || (get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value"));
1125
854
  }
1126
- get parent() {
1127
- return this._parent;
855
+ getMyHeritageTreeId() {
856
+ 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"));
1128
857
  }
1129
- addRef(refNode) {
1130
- if (typeof refNode.value === "string" && isId(refNode.value) && refNode.refType) {
1131
- if (!this._refs) {
1132
- this._refs = new List();
1133
- }
1134
- this._refs.item(refNode.value, refNode);
858
+ getTreeId() {
859
+ if (this?.isAncestry()) {
860
+ const id = this.getAncestryTreeId();
861
+ if (id !== void 0) return id;
1135
862
  }
863
+ if (this?.isMyHeritage()) {
864
+ const id = this.getMyHeritageTreeId();
865
+ if (id !== void 0) return id;
866
+ }
867
+ if (this?.isFamilySearch()) {
868
+ const id = this.getFamilySearchTreeId();
869
+ if (id !== void 0) return id;
870
+ }
871
+ if (this?.isGNO2GED()) {
872
+ const id = this.getGNO2GEDTreeId();
873
+ if (id !== void 0) return id;
874
+ }
875
+ if (this?.isAhnenblatt()) {
876
+ const id = this.getAhnenblattTreeId();
877
+ if (id !== void 0) return id;
878
+ }
879
+ if (this?.isGeni()) {
880
+ const id = this.getGeniTreeId();
881
+ if (id !== void 0) return id;
882
+ }
883
+ if (this?.isGenoPro()) {
884
+ const id = this.getGenoProTreeId();
885
+ if (id !== void 0) return id;
886
+ }
887
+ return this.getUniversalTreeId();
1136
888
  }
1137
- getRefs() {
1138
- return this._refs;
1139
- }
1140
- exportValue() {
1141
- return this.value;
889
+ getAncestryTreeName() {
890
+ return this.getFromSourceHeads("SOUR._TREE.value") || (get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value"));
1142
891
  }
1143
- removeValue() {
1144
- delete this._value;
892
+ getMyHeritageTreeName() {
893
+ const path = "HEAD.FILE.value";
894
+ const treeDetails = get(this, path) || get(this.getGedcom(), path);
895
+ return treeDetails?.match(
896
+ /Exported by MyHeritage.com from (?<tree>.+) in.+$/
897
+ )?.groups?.tree;
1145
898
  }
1146
- set(name, value) {
1147
- if (isGedcomTrailerTag(name)) {
1148
- return void 0;
899
+ getFamilySearchTreeId() {
900
+ const rin = this.getFromSourceHeads("SOUR._TREE.RIN.value") || get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value");
901
+ if (rin) {
902
+ return rin;
1149
903
  }
1150
- if (typeof value === "string") {
1151
- const usedValue = createCommon(this._gedcom, void 0, this.main);
1152
- usedValue.value = value;
1153
- set(this, name, usedValue);
1154
- } else {
1155
- set(this, name, value);
904
+ return "familysearch";
905
+ }
906
+ getFamilySearchTreeName() {
907
+ const treeName = this.getFromSourceHeads("SOUR._TREE.value") || get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value");
908
+ if (treeName) {
909
+ return treeName;
1156
910
  }
1157
- return get(this, name);
911
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
912
+ return fileName || "FamilySearch Import";
1158
913
  }
1159
- assign(name, value, unique = false) {
1160
- if (isGedcomTrailerTag(name)) {
1161
- return void 0;
914
+ getAhnenblattTreeId() {
915
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
916
+ if (fileName) {
917
+ const idMatch = fileName.match(/_(\d+)/);
918
+ if (idMatch) {
919
+ return idMatch[1];
920
+ }
1162
921
  }
1163
- let curValue = this.get(name);
1164
- if (curValue?.isListable) {
1165
- if (curValue instanceof _Common) {
1166
- curValue = new List().concat({ ...[curValue] });
1167
- this.set(name, curValue);
1168
- }
1169
- const values = [
1170
- ...curValue.values(),
1171
- ...value instanceof List ? value.values() : [value]
1172
- ];
1173
- curValue.concat({
1174
- ...!unique ? values : uniqBy(
1175
- values,
1176
- (value2) => value2 instanceof _Common ? value2?.value : void 0
1177
- )
1178
- });
1179
- } else {
1180
- this.set(name, value);
1181
- }
1182
- return get(this, name);
922
+ return void 0;
1183
923
  }
1184
- get(name) {
1185
- if (!name.includes(".")) {
1186
- return get(this, name);
1187
- }
1188
- const nameParts = name.split(".");
1189
- let last = this;
1190
- for (const part of nameParts) {
1191
- const indexPart = Number(part);
1192
- const itemIndex = part.match(/items\[(?<itemIndex>\d+)\]/)?.groups?.itemIndex;
1193
- const itemId = part.match(/items\[(?<itemId>@[A-Z]+\d+@)\]/)?.groups?.itemId;
1194
- const usedPart = itemId || itemIndex;
1195
- if (last instanceof List) {
1196
- if (!isNaN(indexPart)) {
1197
- last = last.index(indexPart);
1198
- } else {
1199
- if (usedPart) {
1200
- last = last.item(usedPart);
1201
- } else {
1202
- last = last?.index(0)?.get(part);
1203
- }
1204
- }
1205
- } else {
1206
- const usedIndex = Number(itemIndex ?? indexPart);
1207
- if (!isNaN(usedIndex)) {
1208
- last = last?.toList().index(usedIndex);
1209
- } else {
1210
- last = last?.get(itemId ?? part);
1211
- }
1212
- }
1213
- if (!last) {
1214
- break;
924
+ getAhnenblattTreeName() {
925
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
926
+ return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
927
+ }
928
+ getGeniTreeId() {
929
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
930
+ if (fileName) {
931
+ const idMatch = fileName.match(/_(\d+)/);
932
+ if (idMatch) {
933
+ return idMatch[1];
1215
934
  }
1216
935
  }
1217
- return last;
1218
- }
1219
- remove(name) {
1220
- unset(this, name);
936
+ return void 0;
1221
937
  }
1222
- getGedcom() {
1223
- return this._gedcom;
938
+ getGeniTreeName() {
939
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
940
+ return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
1224
941
  }
1225
- getIf(name, condition, name2) {
1226
- const nameParts = name.split(".");
1227
- const name2Parts = name2.split(".");
1228
- if (nameParts.length !== name2Parts.length) {
1229
- throw new Error("Tag pathes must be of the same depth");
1230
- }
1231
- if (nameParts.length > 1 && nameParts[0] !== name2Parts[0]) {
1232
- throw new Error("Final tags must be siblings");
1233
- }
1234
- const valueCommon = this.get(name);
1235
- if (valueCommon instanceof _Common) {
1236
- return valueCommon?.toValue() !== condition ? void 0 : this.get(name2);
942
+ getGenoProTreeId() {
943
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
944
+ if (fileName) {
945
+ const idMatch = fileName.match(/_(\d+)/);
946
+ if (idMatch) {
947
+ return idMatch[1];
948
+ }
1237
949
  }
1238
- const valueCommon2 = this.get(name2)?.toList();
1239
- const ifList = new List();
1240
- valueCommon?.forEach((item, key) => {
1241
- const pair = valueCommon2?.item(key);
1242
- ifList.item(key, item?.toValue() !== condition ? void 0 : pair);
1243
- });
1244
- return ifList;
1245
- }
1246
- toString() {
1247
- return this.value?.toString() || "";
1248
- }
1249
- toValue() {
1250
- return this.value;
950
+ return void 0;
1251
951
  }
1252
- toProp(tag) {
1253
- const prop = this.get(tag);
1254
- return prop;
952
+ getGenoProTreeName() {
953
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
954
+ return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
1255
955
  }
1256
- toList() {
1257
- return new List().concat(
1258
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1259
- this.id ? { [this.id]: this } : { ...[this] }
1260
- );
956
+ getGNO2GEDTreeId() {
957
+ const rin = get(this, "HEAD._TREE.RIN.value") || get(this.getGedcom(), "HEAD._TREE.RIN.value");
958
+ if (rin) {
959
+ return rin;
960
+ }
961
+ return `gno_${this._gedcom?.refcount || "unknown"}`;
1261
962
  }
1262
- index(i) {
1263
- return this.toList()?.index(i);
963
+ getGNO2GEDTreeName() {
964
+ const treeName = get(this, "HEAD._TREE.value") || get(this.getGedcom(), "HEAD._TREE.value");
965
+ if (treeName) {
966
+ return treeName;
967
+ }
968
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
969
+ return fileName || "GNO2GED Export";
1264
970
  }
1265
- toValueList() {
1266
- return new List().concat(
1267
- this.value ? { [this.value]: this } : (
1268
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1269
- { ...[this] }
1270
- )
1271
- );
971
+ /**
972
+ * Universal tree ID getter for unknown/unrecognized GEDCOM sources
973
+ * Tries to extract an ID from various common locations
974
+ */
975
+ getUniversalTreeId() {
976
+ const sourceType = this.getSourceType();
977
+ const prefix = sourceType ? sourceType.toLowerCase() : "tree";
978
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
979
+ if (fileName) {
980
+ const idMatch = fileName.match(/_(\d+)/);
981
+ if (idMatch) {
982
+ return `${prefix}_${idMatch[1]}`;
983
+ }
984
+ }
985
+ return `${prefix}_${this._gedcom?.refcount || "unknown"}`;
1272
986
  }
1273
- standardizeObject(tag, options) {
1274
- if (tag === "OBJE" && options?.obje?.standardize && "standardizeMedia" in this) {
1275
- const standardize = this.standardizeMedia;
1276
- return standardize.call(
1277
- this,
1278
- options.obje.namespace,
1279
- options.obje.override,
1280
- this.isAncestry() ? ancestryMediaFileUrl : void 0,
1281
- options.gedcomVersion
1282
- );
987
+ /**
988
+ * Universal tree name getter for unknown/unrecognized GEDCOM sources
989
+ * Tries to extract a name from various common locations
990
+ */
991
+ getUniversalTreeName() {
992
+ const sourceType = this.getSourceType();
993
+ const prefix = sourceType ? `${sourceType}-` : "";
994
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
995
+ if (fileName) {
996
+ const cleanName = fileName.replace(/\.ged$/i, "").replace(/_/g, " ");
997
+ return `${prefix}${cleanName}`;
998
+ }
999
+ const sourName = this.getFromSourceHeads("SOUR.NAME.value") || get(this, "HEAD.SOUR.NAME.value") || get(this.getGedcom(), "HEAD.SOUR.NAME.value");
1000
+ if (sourName) {
1001
+ return `${prefix}${sourName}`;
1002
+ }
1003
+ const sourValue = this.getFromSourceHeads("SOUR.value") || get(this, "HEAD.SOUR.value") || get(this.getGedcom(), "HEAD.SOUR.value");
1004
+ if (sourValue) {
1005
+ return `${prefix}${sourValue}`;
1283
1006
  }
1007
+ return `${prefix}Unknown Tree`;
1284
1008
  }
1285
- toJson(tag, options) {
1286
- const json = this.toObject(tag, options);
1287
- return JSON.stringify(json);
1009
+ getTreeName() {
1010
+ if (this?.isAncestry()) {
1011
+ const name = this.getAncestryTreeName();
1012
+ if (name) return name;
1013
+ }
1014
+ if (this?.isMyHeritage()) {
1015
+ const name = this.getMyHeritageTreeName();
1016
+ if (name) return name;
1017
+ }
1018
+ if (this?.isFamilySearch()) {
1019
+ const name = this.getFamilySearchTreeName();
1020
+ if (name) return name;
1021
+ }
1022
+ if (this?.isGNO2GED()) {
1023
+ const name = this.getGNO2GEDTreeName();
1024
+ if (name) return name;
1025
+ }
1026
+ if (this?.isAhnenblatt()) {
1027
+ const name = this.getAhnenblattTreeName();
1028
+ if (name) return name;
1029
+ }
1030
+ if (this?.isGeni()) {
1031
+ const name = this.getGeniTreeName();
1032
+ if (name) return name;
1033
+ }
1034
+ if (this?.isGenoPro()) {
1035
+ const name = this.getGenoProTreeName();
1036
+ if (name) return name;
1037
+ }
1038
+ return this.getUniversalTreeName();
1288
1039
  }
1289
- toObject(tag, options) {
1290
- this.standardizeObject(tag, options);
1291
- const validKeys = getValidKeys(this);
1292
- let json = {};
1293
- validKeys.forEach((key) => {
1294
- if (options?.persist && (key === "DAY" || key === "MONTH" || key === "YEAR")) {
1295
- return;
1040
+ };
1041
+ var createProxy = (target) => {
1042
+ return new Proxy(target, {
1043
+ get(t, prop, receiver) {
1044
+ if (prop === "unwrapped") {
1045
+ return target;
1296
1046
  }
1297
- if (key === "id" && this.id !== void 0) {
1298
- json.id = this.id;
1299
- } else if (key === "_id" && this._id !== void 0) {
1300
- json.id = this._id;
1301
- } else if (key === "value" && this.value !== void 0) {
1302
- json.value = this.value;
1303
- } else if (key === "_value" && this._value !== void 0) {
1304
- json.value = this._value;
1305
- } else {
1306
- const validKey = key;
1307
- const prop = this.get(validKey);
1308
- if (typeof prop?.toObject === "function") {
1309
- if (prop instanceof _Common) {
1310
- json[validKey] = prop.toObject(validKey, options);
1311
- } else if (prop instanceof List) {
1312
- json = {
1313
- ...json,
1314
- ...prop.toObject(validKey, options)
1315
- };
1316
- }
1047
+ if (prop in t) {
1048
+ return Reflect.get(t, prop, receiver);
1049
+ }
1050
+ if (!isOnlyMainProp(prop)) {
1051
+ const ref = t.ref;
1052
+ if (ref && prop in ref) {
1053
+ return Reflect.get(ref, prop, receiver);
1317
1054
  }
1318
1055
  }
1319
- });
1320
- return json;
1321
- }
1322
- merge(other, override = false, avoidKeys = []) {
1323
- if (!other) {
1324
- return this;
1325
- }
1326
- const validKeys = getValidKeys(other);
1327
- validKeys.forEach((validKey) => {
1328
- if (avoidKeys.includes(validKey)) {
1329
- return;
1330
- }
1331
- const current = this.get(validKey);
1332
- const mergeValue = other.get(validKey);
1333
- if (mergeValue) {
1334
- if (current instanceof _Common || current instanceof List) {
1335
- this.assign(validKey, mergeValue, true);
1336
- } else if (!current || override && validKey !== "id" && validKey !== "_id") {
1337
- this.set(validKey, mergeValue);
1338
- }
1339
- }
1340
- });
1341
- return this;
1342
- }
1343
- clone(newId = false, avoidKeys = []) {
1344
- const ctor = this.constructor;
1345
- const instance = new ctor(
1346
- this._gedcom,
1347
- this._id,
1348
- this._main,
1349
- this._parent
1350
- );
1351
- if (newId && this._id) {
1352
- instance.id = `IFT${this._id.replace(/[^0-9]/g, "")}`;
1353
1056
  }
1354
- const cloned = createProxy(instance);
1355
- cloned.merge(this, true, avoidKeys);
1356
- return cloned;
1057
+ });
1058
+ };
1059
+ var createCommon = (gedcom, id, main, parent) => {
1060
+ return createProxy(
1061
+ new Common(gedcom, id, main, parent)
1062
+ );
1063
+ };
1064
+ var isOnlyMainProp = (key) => {
1065
+ return key === "_gedcom" || key === "_main" || key === "_parent" || key === "_uniqueId" || key === "_type" || key === "_refs" || key === "id" || key === "_id";
1066
+ };
1067
+ var isValidKey = (common, key) => {
1068
+ const prop = get(common, key);
1069
+ 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);
1070
+ };
1071
+ var getValidKeys = (common) => {
1072
+ return Object.keys(common).filter((key) => {
1073
+ return isValidKey(common, key);
1074
+ });
1075
+ };
1076
+ var getValidTag = (tag) => {
1077
+ return tag.replace(/^@@/, "");
1078
+ };
1079
+ var getListTag = (tag) => {
1080
+ return `@@${tag}`;
1081
+ };
1082
+ var isId = (string) => {
1083
+ return ID_REG.test(string);
1084
+ };
1085
+ var idGetter = (id) => {
1086
+ if (id === void 0) {
1087
+ return void 0;
1357
1088
  }
1358
- // fromGedcom<T = typeof this>(value: string) {
1359
- fromGedcom(_value) {
1089
+ let newId = `${id}`;
1090
+ const parts = newId?.match(ID_GETTER_REG)?.groups;
1091
+ if (!parts?.at && !parts?.letter) {
1092
+ newId = `@U${newId}`;
1093
+ } else if (!parts.at) {
1094
+ newId = `@${newId}`;
1095
+ } else if (!parts.letter) {
1096
+ newId = newId.replace(/^@/, "@U");
1360
1097
  }
1361
- toGedcom(tag, level = 0, options) {
1362
- const gedcom = this.toGedcomLines(tag, level, options);
1363
- return gedcom.join("\n");
1098
+ if (!newId.endsWith("@")) {
1099
+ newId = `${newId}@`;
1364
1100
  }
1365
- toGedcomLines(tag, level = 0, options) {
1366
- this.standardizeObject(tag, options);
1367
- const validKeys = getValidKeys(this);
1368
- const gedcom = [];
1369
- const isGedcom7Export = options?.gedcomVersion === "7.0";
1370
- validKeys.forEach((key) => {
1371
- const validKey = key;
1372
- if (isGedcom7Export && validKey === "CONC") {
1373
- return;
1374
- }
1375
- const prop = this.get(validKey);
1376
- if (typeof prop?.toGedcomLines === "function") {
1377
- if (prop instanceof _Common) {
1378
- const value = prop.exportValue();
1379
- gedcom.push(
1380
- `${level} ${validKey}${value ? ` ${value}` : ""}`
1381
- );
1382
- gedcom.push(
1383
- ...prop.toGedcomLines(validKey, level + 1, options)
1384
- );
1385
- } else if (prop instanceof List) {
1386
- gedcom.push(
1387
- ...prop.toGedcomLines(validKey, level, options)
1388
- );
1389
- }
1390
- }
1391
- });
1392
- return gedcom;
1101
+ return newId;
1102
+ };
1103
+
1104
+ // src/classes/list.ts
1105
+ var List = class _List {
1106
+ // length = 0;
1107
+ constructor(items) {
1108
+ this.items = {};
1109
+ this.isListable = true;
1110
+ this.marker = void 0;
1111
+ if (items) {
1112
+ this.concat(items);
1113
+ }
1393
1114
  }
1394
- getHeadRecord() {
1395
- return get(this, "HEAD") || get(this.getGedcom(), "HEAD");
1115
+ get length() {
1116
+ return this.values().length;
1396
1117
  }
1397
- getOriginalHeadRecord() {
1398
- return get(this, ORIG_HEAD_TAG) || get(this.getGedcom(), ORIG_HEAD_TAG) || get(this.getHeadRecord(), ORIG_HEAD_TAG);
1118
+ has(indi) {
1119
+ return !!this.item(
1120
+ typeof indi === "string" ? indi : indi?.id ?? ""
1121
+ );
1399
1122
  }
1400
- getSourceHeads() {
1401
- const heads = [this.getOriginalHeadRecord(), this.getHeadRecord()];
1402
- return heads.filter((head, index) => {
1403
- return Boolean(head && heads.indexOf(head) === index);
1123
+ get(name) {
1124
+ const propList = new _List();
1125
+ this.entries().forEach(([key, item]) => {
1126
+ propList.item(key, item.get(name));
1404
1127
  });
1128
+ return propList;
1405
1129
  }
1406
- getFromSourceHeads(path) {
1407
- for (const head of this.getSourceHeads()) {
1408
- const value = get(head, path);
1409
- if (value !== void 0 && value !== null && value !== "") {
1410
- return value;
1130
+ getIf(name, condition, name2) {
1131
+ const propList = new _List();
1132
+ this.entries().forEach(([key, item]) => {
1133
+ const passedItem = item.getIf(name, condition, name2);
1134
+ if (passedItem) {
1135
+ propList.item(key, passedItem);
1411
1136
  }
1412
- }
1413
- return void 0;
1414
- }
1415
- sourStartsWith(prefix) {
1416
- return this.getSourceHeads().some((head) => {
1417
- const sour = get(head, "SOUR.value");
1418
- return !!sour?.toLowerCase()?.startsWith(prefix);
1419
1137
  });
1138
+ return propList;
1420
1139
  }
1421
- isGenoPro() {
1422
- return this.sourStartsWith("genopro");
1140
+ keys() {
1141
+ return Object.keys(this.items);
1423
1142
  }
1424
- isAhnenblatt() {
1425
- return this.sourStartsWith("ahnenblatt");
1143
+ values() {
1144
+ return Object.values(this.items);
1426
1145
  }
1427
- isGeni() {
1428
- return this.sourStartsWith("geni");
1146
+ entries() {
1147
+ return Object.entries(this.items);
1429
1148
  }
1430
- isAncestry() {
1431
- return this.sourStartsWith("ancestry");
1149
+ setLength(_type) {
1432
1150
  }
1433
- isMyHeritage() {
1434
- return this.sourStartsWith("myheritage");
1151
+ first() {
1152
+ return this.index(0);
1435
1153
  }
1436
- /**
1437
- * Get the source type as a string (for prefixing tree IDs and names)
1438
- * Returns the detected source type or undefined if unknown
1439
- */
1440
- getSourceType() {
1441
- if (this.isAncestry()) return "Ancestry";
1442
- if (this.isMyHeritage()) return "MyHeritage";
1443
- if (this.isFamilySearch()) return "FamilySearch";
1444
- if (this.isGNO2GED()) return "GNO2GED";
1445
- if (this.isGenoPro()) return "GenoPro";
1446
- if (this.isAhnenblatt()) return "Ahnenblatt";
1447
- if (this.isGeni()) return "Geni";
1448
- return void 0;
1154
+ last() {
1155
+ return this.index(this.keys().length - 1);
1449
1156
  }
1450
- isFamilySearch() {
1451
- return this.getSourceHeads().some((head) => {
1452
- const sourName = get(head, "SOUR.NAME.value");
1453
- return sourName === "FamilySearch API";
1454
- });
1157
+ index(index) {
1158
+ const keys = this.keys();
1159
+ const key = keys[index];
1160
+ return key && this.items[key];
1455
1161
  }
1456
- isGNO2GED() {
1457
- return this.getSourceHeads().some((head) => {
1458
- const sour = get(head, "SOUR.value");
1459
- return sour === "GNO2GED";
1460
- });
1162
+ item(name, value) {
1163
+ if (arguments.length > 1) {
1164
+ set(this.items, name, value);
1165
+ this.setLength();
1166
+ }
1167
+ return get(this.items, name);
1461
1168
  }
1462
- getAncestryTreeId() {
1463
- return this.getFromSourceHeads("SOUR._TREE.RIN.value") || (get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value"));
1169
+ removeItem(name) {
1170
+ unset(this.items, name);
1171
+ this.setLength();
1464
1172
  }
1465
- getMyHeritageTreeId() {
1466
- 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"));
1173
+ exclude(excludedList) {
1174
+ excludedList.keys().forEach((itemId) => {
1175
+ delete this.items[itemId];
1176
+ });
1177
+ this.setLength();
1178
+ return this;
1467
1179
  }
1468
- getTreeId() {
1469
- if (this?.isAncestry()) {
1470
- const id = this.getAncestryTreeId();
1471
- if (id !== void 0) return id;
1472
- }
1473
- if (this?.isMyHeritage()) {
1474
- const id = this.getMyHeritageTreeId();
1475
- if (id !== void 0) return id;
1476
- }
1477
- if (this?.isFamilySearch()) {
1478
- const id = this.getFamilySearchTreeId();
1479
- if (id !== void 0) return id;
1480
- }
1481
- if (this?.isGNO2GED()) {
1482
- const id = this.getGNO2GEDTreeId();
1483
- if (id !== void 0) return id;
1484
- }
1485
- if (this?.isAhnenblatt()) {
1486
- const id = this.getAhnenblattTreeId();
1487
- if (id !== void 0) return id;
1180
+ concat(items) {
1181
+ if (Array.isArray(items)) {
1182
+ items.forEach((item) => {
1183
+ this.append(item);
1184
+ });
1185
+ } else {
1186
+ Object.assign(this.items, items ?? {});
1488
1187
  }
1489
- if (this?.isGeni()) {
1490
- const id = this.getGeniTreeId();
1491
- if (id !== void 0) return id;
1492
- }
1493
- if (this?.isGenoPro()) {
1494
- const id = this.getGenoProTreeId();
1495
- if (id !== void 0) return id;
1496
- }
1497
- return this.getUniversalTreeId();
1498
- }
1499
- getAncestryTreeName() {
1500
- return this.getFromSourceHeads("SOUR._TREE.value") || (get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value"));
1188
+ this.setLength();
1189
+ return this;
1501
1190
  }
1502
- getMyHeritageTreeName() {
1503
- const path = "HEAD.FILE.value";
1504
- const treeDetails = get(this, path) || get(this.getGedcom(), path);
1505
- return treeDetails?.match(
1506
- /Exported by MyHeritage.com from (?<tree>.+) in.+$/
1507
- )?.groups?.tree;
1191
+ merge(mergedList) {
1192
+ this.concat(mergedList?.items);
1193
+ return this;
1508
1194
  }
1509
- getFamilySearchTreeId() {
1510
- const rin = this.getFromSourceHeads("SOUR._TREE.RIN.value") || get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value");
1511
- if (rin) {
1512
- return rin;
1513
- }
1514
- return "familysearch";
1195
+ intersection(mergedList) {
1196
+ const inter = intersectionBy(
1197
+ this.values(),
1198
+ mergedList?.values() ?? [],
1199
+ "id"
1200
+ );
1201
+ return new _List(inter);
1515
1202
  }
1516
- getFamilySearchTreeName() {
1517
- const treeName = this.getFromSourceHeads("SOUR._TREE.value") || get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value");
1518
- if (treeName) {
1519
- return treeName;
1520
- }
1521
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1522
- return fileName || "FamilySearch Import";
1203
+ difference(mergedList) {
1204
+ const inter = differenceBy(
1205
+ this.values(),
1206
+ mergedList?.values() ?? [],
1207
+ "id"
1208
+ );
1209
+ return new _List(inter);
1523
1210
  }
1524
- getAhnenblattTreeId() {
1525
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1526
- if (fileName) {
1527
- const idMatch = fileName.match(/_(\d+)/);
1528
- if (idMatch) {
1529
- return idMatch[1];
1211
+ prepend(item) {
1212
+ if (item.id) {
1213
+ let increase = true;
1214
+ if (this.items[item.id]) {
1215
+ delete this.items[item.id];
1216
+ increase = false;
1530
1217
  }
1531
- }
1532
- return void 0;
1533
- }
1534
- getAhnenblattTreeName() {
1535
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1536
- return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
1537
- }
1538
- getGeniTreeId() {
1539
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1540
- if (fileName) {
1541
- const idMatch = fileName.match(/_(\d+)/);
1542
- if (idMatch) {
1543
- return idMatch[1];
1218
+ this.items = Object.assign(
1219
+ {
1220
+ [item.id]: item
1221
+ },
1222
+ this.items
1223
+ );
1224
+ if (increase) {
1225
+ this.setLength("increase");
1544
1226
  }
1545
1227
  }
1546
- return void 0;
1547
- }
1548
- getGeniTreeName() {
1549
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1550
- return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
1228
+ return this;
1551
1229
  }
1552
- getGenoProTreeId() {
1553
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1554
- if (fileName) {
1555
- const idMatch = fileName.match(/_(\d+)/);
1556
- if (idMatch) {
1557
- return idMatch[1];
1230
+ append(item) {
1231
+ if (item.id) {
1232
+ let increase = true;
1233
+ if (this.items[item.id]) {
1234
+ delete this.items[item.id];
1235
+ increase = false;
1236
+ }
1237
+ this.items[item.id] = item;
1238
+ if (increase) {
1239
+ this.setLength("increase");
1558
1240
  }
1559
1241
  }
1560
- return void 0;
1561
- }
1562
- getGenoProTreeName() {
1563
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1564
- return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
1242
+ return this;
1565
1243
  }
1566
- getGNO2GEDTreeId() {
1567
- const rin = get(this, "HEAD._TREE.RIN.value") || get(this.getGedcom(), "HEAD._TREE.RIN.value");
1568
- if (rin) {
1569
- return rin;
1244
+ delete(item) {
1245
+ if (item.id && this.items[item.id]) {
1246
+ delete this.items[item.id];
1247
+ this.setLength("decrease");
1570
1248
  }
1571
- return `gno_${this._gedcom?.refcount || "unknown"}`;
1249
+ return this;
1572
1250
  }
1573
- getGNO2GEDTreeName() {
1574
- const treeName = get(this, "HEAD._TREE.value") || get(this.getGedcom(), "HEAD._TREE.value");
1575
- if (treeName) {
1576
- return treeName;
1577
- }
1578
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1579
- return fileName || "GNO2GED Export";
1251
+ copy(ClassName = _List) {
1252
+ const newList = new ClassName();
1253
+ Object.assign(newList.items, this.items);
1254
+ newList.setLength();
1255
+ return newList;
1580
1256
  }
1581
- /**
1582
- * Universal tree ID getter for unknown/unrecognized GEDCOM sources
1583
- * Tries to extract an ID from various common locations
1584
- */
1585
- getUniversalTreeId() {
1586
- const sourceType = this.getSourceType();
1587
- const prefix = sourceType ? sourceType.toLowerCase() : "tree";
1588
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1589
- if (fileName) {
1590
- const idMatch = fileName.match(/_(\d+)/);
1591
- if (idMatch) {
1592
- return `${prefix}_${idMatch[1]}`;
1593
- }
1594
- }
1595
- return `${prefix}_${this._gedcom?.refcount || "unknown"}`;
1257
+ except(item, ClassName = _List) {
1258
+ return this.copy(ClassName).delete(item);
1596
1259
  }
1597
- /**
1598
- * Universal tree name getter for unknown/unrecognized GEDCOM sources
1599
- * Tries to extract a name from various common locations
1600
- */
1601
- getUniversalTreeName() {
1602
- const sourceType = this.getSourceType();
1603
- const prefix = sourceType ? `${sourceType}-` : "";
1604
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1605
- if (fileName) {
1606
- const cleanName = fileName.replace(/\.ged$/i, "").replace(/_/g, " ");
1607
- return `${prefix}${cleanName}`;
1608
- }
1609
- const sourName = this.getFromSourceHeads("SOUR.NAME.value") || get(this, "HEAD.SOUR.NAME.value") || get(this.getGedcom(), "HEAD.SOUR.NAME.value");
1610
- if (sourName) {
1611
- return `${prefix}${sourName}`;
1612
- }
1613
- const sourValue = this.getFromSourceHeads("SOUR.value") || get(this, "HEAD.SOUR.value") || get(this.getGedcom(), "HEAD.SOUR.value");
1614
- if (sourValue) {
1615
- return `${prefix}${sourValue}`;
1616
- }
1617
- return `${prefix}Unknown Tree`;
1260
+ forEach(iterate) {
1261
+ this.entries().forEach(([key, item], index) => {
1262
+ iterate(item, key, index);
1263
+ });
1618
1264
  }
1619
- getTreeName() {
1620
- if (this?.isAncestry()) {
1621
- const name = this.getAncestryTreeName();
1622
- if (name) return name;
1623
- }
1624
- if (this?.isMyHeritage()) {
1625
- const name = this.getMyHeritageTreeName();
1626
- if (name) return name;
1627
- }
1628
- if (this?.isFamilySearch()) {
1629
- const name = this.getFamilySearchTreeName();
1630
- if (name) return name;
1631
- }
1632
- if (this?.isGNO2GED()) {
1633
- const name = this.getGNO2GEDTreeName();
1634
- if (name) return name;
1635
- }
1636
- if (this?.isAhnenblatt()) {
1637
- const name = this.getAhnenblattTreeName();
1638
- if (name) return name;
1639
- }
1640
- if (this?.isGeni()) {
1641
- const name = this.getGeniTreeName();
1642
- if (name) return name;
1643
- }
1644
- if (this?.isGenoPro()) {
1645
- const name = this.getGenoProTreeName();
1646
- if (name) return name;
1647
- }
1648
- return this.getUniversalTreeName();
1265
+ map(iterate) {
1266
+ return this.entries().map(([key, item], index) => {
1267
+ return iterate(item, key, index);
1268
+ });
1649
1269
  }
1650
- };
1651
- var createProxy = (target) => {
1652
- return new Proxy(target, {
1653
- get(t, prop, receiver) {
1654
- if (prop === "unwrapped") {
1655
- return target;
1270
+ reduce(iterate, initialValue) {
1271
+ return this.entries().reduce((acc, [key, item], index) => {
1272
+ return iterate(acc, item, key, index);
1273
+ }, initialValue);
1274
+ }
1275
+ filter(filters, ClassName = _List) {
1276
+ const newList = new ClassName();
1277
+ const isIterator = typeof filters === "function";
1278
+ this.entries().forEach(([itemId, item], index) => {
1279
+ if (isIterator) {
1280
+ filters(item, itemId, index) && newList.item(itemId, item);
1281
+ return;
1656
1282
  }
1657
- if (prop in t) {
1658
- return Reflect.get(t, prop, receiver);
1283
+ if (!Object.keys(filters).length || Object.entries(filters).every(([key, value]) => {
1284
+ let itemValue;
1285
+ if (key === "id") {
1286
+ itemValue = item.toProp("id");
1287
+ } else {
1288
+ itemValue = item.toProp(key)?.toValue();
1289
+ }
1290
+ if (Array.isArray(value)) {
1291
+ return value.includes(itemValue);
1292
+ }
1293
+ return itemValue === value;
1294
+ })) {
1295
+ newList.item(itemId, item);
1659
1296
  }
1660
- if (!isOnlyMainProp(prop)) {
1661
- const ref = t.ref;
1662
- if (ref && prop in ref) {
1663
- return Reflect.get(ref, prop, receiver);
1297
+ });
1298
+ return newList;
1299
+ }
1300
+ find(filters, _ClassName = _List) {
1301
+ let foundItem;
1302
+ const isIterator = typeof filters === "function";
1303
+ this.entries().find(([itemId, item], index) => {
1304
+ if (isIterator) {
1305
+ if (filters(item, itemId, index)) {
1306
+ foundItem = item;
1307
+ return true;
1664
1308
  }
1309
+ return false;
1665
1310
  }
1311
+ if (!Object.keys(filters).length || Object.entries(filters).every(([key, value]) => {
1312
+ let itemValue;
1313
+ if (key === "id") {
1314
+ itemValue = item.toProp("id");
1315
+ } else {
1316
+ itemValue = item.toProp(key)?.toValue();
1317
+ }
1318
+ if (Array.isArray(value)) {
1319
+ return value.includes(itemValue);
1320
+ }
1321
+ return itemValue === value;
1322
+ })) {
1323
+ foundItem = item;
1324
+ return true;
1325
+ }
1326
+ return false;
1327
+ });
1328
+ return foundItem;
1329
+ }
1330
+ orderBy(orders, ClassName = _List) {
1331
+ const newList = new ClassName();
1332
+ const isIterator = typeof orders === "function";
1333
+ if (!isIterator && (!orders || !Object.keys(orders).length)) {
1334
+ return newList.merge(this);
1666
1335
  }
1667
- });
1668
- };
1669
- var createCommon = (gedcom, id, main, parent) => {
1670
- return createProxy(
1671
- new Common(gedcom, id, main, parent)
1672
- );
1673
- };
1674
- var isOnlyMainProp = (key) => {
1675
- return key === "_gedcom" || key === "_main" || key === "_parent" || key === "_uniqueId" || key === "_type" || key === "_refs" || key === "id" || key === "_id";
1676
- };
1677
- var isValidKey = (common, key) => {
1678
- const prop = get(common, key);
1679
- 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);
1680
- };
1681
- var getValidKeys = (common) => {
1682
- return Object.keys(common).filter((key) => {
1683
- return isValidKey(common, key);
1684
- });
1336
+ const sortedItems = this.entries().toSorted(
1337
+ ([itemAId, itemA], [itemBId, itemB]) => {
1338
+ if (isIterator) {
1339
+ return orders(itemA, itemAId, itemB, itemBId);
1340
+ }
1341
+ const [key, { direction, getter }] = Object.entries(
1342
+ typeof orders === "string" ? { [orders]: { direction: "ASC" } } : orders
1343
+ )[0];
1344
+ const rawA = itemA.get(key);
1345
+ const rawB = itemB.get(key);
1346
+ let valueA = rawA?.toValue();
1347
+ let valueB = rawB?.toValue();
1348
+ if (getter && typeof getter === "function") {
1349
+ valueA = getter(valueA, rawA);
1350
+ valueB = getter(valueB, rawB);
1351
+ }
1352
+ let sortValue2 = 0;
1353
+ if (!valueA && valueA !== 0 && !valueB && valueB !== 0) {
1354
+ sortValue2 = 0;
1355
+ } else if (!valueB && valueB !== 0) {
1356
+ sortValue2 = 1;
1357
+ } else if (!valueA && valueA !== 0) {
1358
+ sortValue2 = -1;
1359
+ } else if (valueA < valueB) {
1360
+ sortValue2 = -1;
1361
+ } else if (valueA > valueB) {
1362
+ sortValue2 = 1;
1363
+ }
1364
+ return sortValue2 * (direction === "DESC" ? -1 : 1);
1365
+ }
1366
+ );
1367
+ sortedItems.forEach(([key, value]) => {
1368
+ newList.item(key, value);
1369
+ });
1370
+ return newList;
1371
+ }
1372
+ groupBy(groups, sort, minOccurance = -1, lessOccuranceLabel = "Appearing less than 5 times", ClassName = _List) {
1373
+ const groupped = {};
1374
+ const isIterator = typeof groups === "function";
1375
+ if (!isIterator && (!groups || !Object.keys(groups).length)) {
1376
+ groupped.Unknown = new ClassName().merge(this);
1377
+ groupped.Unknown.marker = "Unknown";
1378
+ return groupped;
1379
+ }
1380
+ this.forEach((item, itemId) => {
1381
+ const group = [];
1382
+ if (isIterator) {
1383
+ const newGroups = groups(item, itemId);
1384
+ group.push(
1385
+ ...Array.isArray(newGroups) ? newGroups : [newGroups]
1386
+ );
1387
+ } else {
1388
+ const [key, { getter }] = Object.entries(
1389
+ typeof groups === "string" ? { [groups]: {} } : groups
1390
+ )[0];
1391
+ const raw = item.get(key)?.index(0);
1392
+ let value = raw?.toValue();
1393
+ if (getter && typeof getter === "function") {
1394
+ value = getter(value, raw);
1395
+ }
1396
+ if (value) {
1397
+ group.push(value);
1398
+ }
1399
+ }
1400
+ if (!group.length) {
1401
+ group.push("Unknown");
1402
+ }
1403
+ group.forEach((g) => {
1404
+ const newGroup = typeof g === "string" ? { group: g } : g;
1405
+ if (!groupped[newGroup.group]) {
1406
+ groupped[newGroup.group] = new ClassName();
1407
+ groupped[newGroup.group].marker = newGroup.marker ?? newGroup.group;
1408
+ }
1409
+ groupped[newGroup.group]?.append(item);
1410
+ });
1411
+ });
1412
+ if (sort) {
1413
+ return Object.entries(groupped).toSorted(([ak, a], [bk, b]) => {
1414
+ if (typeof sort === "function") {
1415
+ return sort(a, ak, b, bk);
1416
+ }
1417
+ if (ak === "Unknown") {
1418
+ return 1;
1419
+ }
1420
+ if (bk === "Unknown") {
1421
+ return -1;
1422
+ }
1423
+ if (sort === "group") {
1424
+ return ak.localeCompare(bk);
1425
+ }
1426
+ return (b?.length ?? 0) - (a?.length ?? 0);
1427
+ }).reduce((acc, [key, value]) => {
1428
+ if (minOccurance > -1 && (value?.length ?? 0) < minOccurance) {
1429
+ const otherKey = lessOccuranceLabel;
1430
+ acc[otherKey] = acc[otherKey] && value ? acc[otherKey].merge(value) : value;
1431
+ } else {
1432
+ acc[key] = value;
1433
+ }
1434
+ return acc;
1435
+ }, {});
1436
+ }
1437
+ return groupped;
1438
+ }
1439
+ findIndex(item) {
1440
+ if (!item?.id) {
1441
+ return -1;
1442
+ }
1443
+ return this.keys().findIndex((key) => key === item.id);
1444
+ }
1445
+ getItems() {
1446
+ return this.items;
1447
+ }
1448
+ toJson(tag, options) {
1449
+ const json = this.toObject(tag, options);
1450
+ return JSON.stringify(json);
1451
+ }
1452
+ toObject(tag, options) {
1453
+ const json = {};
1454
+ this.entries().forEach(([_, item]) => {
1455
+ const validTag = getValidTag(tag);
1456
+ if (json[validTag]) {
1457
+ if (!Array.isArray(json[validTag])) {
1458
+ json[validTag] = [json[validTag]];
1459
+ }
1460
+ json[validTag].push(
1461
+ item.toObject(validTag, options)
1462
+ );
1463
+ } else {
1464
+ json[validTag] = item.toObject(
1465
+ validTag,
1466
+ options
1467
+ );
1468
+ }
1469
+ });
1470
+ return json;
1471
+ }
1472
+ toGedcom(tag, level = 0, options) {
1473
+ const gedcom = this.toGedcomLines(tag, level, options);
1474
+ return gedcom.join("\n");
1475
+ }
1476
+ toGedcomLines(tag, level = 0, options) {
1477
+ const gedcom = [];
1478
+ this.entries().forEach(([_, item]) => {
1479
+ const validTag = getValidTag(tag);
1480
+ const xref = item.id;
1481
+ const payload = item.exportValue?.();
1482
+ if (xref) {
1483
+ gedcom.push(
1484
+ `${level} ${xref} ${validTag}${payload ? ` ${payload}` : ""}`
1485
+ );
1486
+ } else {
1487
+ gedcom.push(
1488
+ `${level} ${validTag}${payload ? ` ${payload}` : ""}`
1489
+ );
1490
+ }
1491
+ gedcom.push(
1492
+ ...item.toGedcomLines(
1493
+ validTag,
1494
+ level + 1,
1495
+ options
1496
+ )
1497
+ );
1498
+ });
1499
+ return gedcom;
1500
+ }
1501
+ toValue() {
1502
+ const propList = new _List();
1503
+ this.entries().forEach(([key, item]) => {
1504
+ propList.item(key, item?.toValue());
1505
+ });
1506
+ return propList;
1507
+ }
1508
+ // @deprecated use get instead
1509
+ toProp(tag) {
1510
+ return this.get(tag);
1511
+ }
1512
+ toList() {
1513
+ return new _List().concat(this.items);
1514
+ }
1515
+ toValueList() {
1516
+ const newList = new _List();
1517
+ this.values().forEach((value) => {
1518
+ value.value && newList.item(value.value, value);
1519
+ });
1520
+ return newList;
1521
+ }
1685
1522
  };
1686
- var getValidTag = (tag) => {
1687
- return tag.replace(/^@@/, "");
1523
+
1524
+ // src/utils/get-all-prop.ts
1525
+ var getAllProp = (indi, prop) => {
1526
+ return prop && (indi?.get(prop)?.toList().values() ?? []).filter(Boolean) || [];
1688
1527
  };
1689
- var getListTag = (tag) => {
1690
- return `@@${tag}`;
1528
+
1529
+ // src/utils/date-formatter.ts
1530
+ var ACCEPTED_DATE_FORMATS = [
1531
+ "yyyy.MM.dd.",
1532
+ "yyyy-MM-dd",
1533
+ "MM/dd/yyyy"
1534
+ ];
1535
+ var ACCEPTED_DATE_FORMATS_REGEX = new RegExp(
1536
+ `(${ACCEPTED_DATE_FORMATS.map(
1537
+ (acceptedFormat) => acceptedFormat.replace(/[^.\-/]/g, "\\d")
1538
+ ).join("|")})`,
1539
+ "gi"
1540
+ );
1541
+ var firstDate = (date) => {
1542
+ if (!date) return void 0;
1543
+ if (isCommonDate(date)) return date;
1544
+ if (date instanceof List) {
1545
+ return firstDate(
1546
+ date.index(0)
1547
+ );
1548
+ }
1549
+ const node = date;
1550
+ if (typeof node.toValue === "function") {
1551
+ return node;
1552
+ }
1553
+ return void 0;
1691
1554
  };
1692
- var isId = (string) => {
1693
- return ID_REG.test(string);
1555
+ var dateNote = (date, shortNote = true) => {
1556
+ if (date && typeof date.toNote === "function") {
1557
+ return date.toNote(shortNote) ?? "";
1558
+ }
1559
+ return "";
1694
1560
  };
1695
- var idGetter = (id) => {
1696
- if (id === void 0) {
1561
+ var commonDateFormatter = (date, format2 = "yyyy", prefix = "") => {
1562
+ const used = firstDate(date);
1563
+ const formattedDate = used?.toValue(format2);
1564
+ if (!formattedDate) {
1697
1565
  return void 0;
1698
1566
  }
1699
- let newId = `${id}`;
1700
- const parts = newId?.match(ID_GETTER_REG)?.groups;
1701
- if (!parts?.at && !parts?.letter) {
1702
- newId = `@U${newId}`;
1703
- } else if (!parts.at) {
1704
- newId = `@${newId}`;
1705
- } else if (!parts.letter) {
1706
- newId = newId.replace(/^@/, "@U");
1567
+ return `${prefix}${formattedDate}`.trim();
1568
+ };
1569
+ var noteDateFormatter = (date, format2 = "yyyy", prefix = "", shortNote = true, showNote = true) => {
1570
+ const used = firstDate(date);
1571
+ const rawDate = commonDateFormatter(used, format2, "");
1572
+ if (!rawDate) {
1573
+ return void 0;
1707
1574
  }
1708
- if (!newId.endsWith("@")) {
1709
- newId = `${newId}@`;
1575
+ const note = dateNote(used, shortNote);
1576
+ return `${prefix}${note && showNote ? i18n.t(`${note} {{date}}`, { date: rawDate }) : rawDate}`;
1577
+ };
1578
+ var marriageDateFormatter = (fam, showDays = false, showPlaces = false, shortNote = true, showNote = true, showDisplayTextIfNoDate = true, showAllEvents = false, dateFormatPattern) => {
1579
+ const fullDateFormat = i18n.t("dateFormat");
1580
+ const marriageDates = [];
1581
+ const marriagePlaces = [];
1582
+ const marriages = (fam?.toValueList().values() ?? []).flatMap((fam2) => {
1583
+ const family = fam2;
1584
+ const marrEvents = (family?.MARR?.toList().values() ?? []).filter(
1585
+ Boolean
1586
+ );
1587
+ if (marrEvents.length === 0) {
1588
+ const displayText = family?.get("DISPLAYTEXT")?.toValue() ?? "";
1589
+ if (showDisplayTextIfNoDate && displayText) {
1590
+ const displayDate = displayText.match(
1591
+ ACCEPTED_DATE_FORMATS_REGEX
1592
+ )?.[0];
1593
+ if (displayDate) {
1594
+ marriagePlaces.push(displayText.replace(displayDate, ""));
1595
+ const marriageDate = createCommonDate(
1596
+ fam2?.getGedcom(),
1597
+ void 0,
1598
+ family
1599
+ );
1600
+ marriageDate.value = displayDate;
1601
+ marriageDates.push(marriageDate);
1602
+ } else {
1603
+ marriagePlaces.push(displayText);
1604
+ marriageDates.push(void 0);
1605
+ return ["\u221E"];
1606
+ }
1607
+ }
1608
+ return [];
1609
+ }
1610
+ const eventsToProcess = showAllEvents ? marrEvents : marrEvents.slice(0, 1);
1611
+ return eventsToProcess.map((marrEvent) => {
1612
+ const marriageEventDetail = marrEvent;
1613
+ const marriageDate = marriageEventDetail?.DATE;
1614
+ const marriagePlace = showPlaces ? marriageEventDetail?.PLAC?.value : void 0;
1615
+ marriagePlaces.push(marriagePlace);
1616
+ marriageDates.push(marriageDate);
1617
+ const formattedDate = noteDateFormatter(
1618
+ marriageDate,
1619
+ showDays ? fullDateFormat : "yyyy",
1620
+ "\u221E",
1621
+ shortNote,
1622
+ showNote
1623
+ );
1624
+ return formattedDate ? formattedDate : void 0;
1625
+ });
1626
+ });
1627
+ const marriageArray = marriages.length ? marriages.filter(Boolean) : [];
1628
+ const datesArray = marriageArray.filter(Boolean);
1629
+ const placesArray = marriagePlaces.filter(Boolean);
1630
+ const dates = datesArray.join(" ").trim();
1631
+ return {
1632
+ rawArray: marriageDates,
1633
+ inArray: datesArray,
1634
+ inOrder: dates,
1635
+ places: placesArray,
1636
+ marriage: marriageArray,
1637
+ ...showPlaces ? {
1638
+ marriages,
1639
+ marriagePlaces
1640
+ } : {}
1641
+ };
1642
+ };
1643
+ var dateFormatter = (indi, showMarriages = false, showDays = false, showPlaces = false, shortNote = true, showNote = true, isOnStage, showAllEvents = false, dateFormatPattern) => {
1644
+ const fullDateFormat = i18n.t("dateFormat");
1645
+ const birthEvents = getAllProp(indi, "BIRT");
1646
+ const firstBirthValue = birthEvents[0];
1647
+ const deathEvents = getAllProp(indi, "DEAT");
1648
+ const firstDeathValue = deathEvents[0];
1649
+ const birth = commonDateFormatter(
1650
+ firstBirthValue?.DATE,
1651
+ showDays ? fullDateFormat : "yyyy"
1652
+ );
1653
+ const birthPlace = showPlaces ? firstBirthValue?.PLAC?.value : void 0;
1654
+ const death = commonDateFormatter(
1655
+ firstDeathValue?.DATE,
1656
+ showDays ? fullDateFormat : "yyyy"
1657
+ );
1658
+ const deathPlace = showPlaces ? firstDeathValue?.PLAC?.value : void 0;
1659
+ const marriagePlaces = [];
1660
+ const marriages = [];
1661
+ if (showMarriages || isOnStage) {
1662
+ (indi?.get("FAMS")?.toValueList().values() ?? []).forEach((fam) => {
1663
+ const famRef = fam?.ref;
1664
+ const marriageDates = marriageDateFormatter(
1665
+ famRef,
1666
+ showDays,
1667
+ showPlaces,
1668
+ shortNote,
1669
+ showNote,
1670
+ true,
1671
+ showAllEvents);
1672
+ marriages.push(...marriageDates?.marriage ?? []);
1673
+ marriagePlaces.push(...marriageDates?.marriagePlaces ?? []);
1674
+ });
1710
1675
  }
1711
- return newId;
1676
+ const birthStrings = [];
1677
+ const birthPlaces = [];
1678
+ const eventsToProcess = showAllEvents ? birthEvents : birthEvents.slice(0, 1);
1679
+ eventsToProcess.forEach((birthEvent) => {
1680
+ const birthDateNode = firstDate(birthEvent?.DATE);
1681
+ const birthDate = commonDateFormatter(
1682
+ birthDateNode,
1683
+ showDays ? fullDateFormat : "yyyy"
1684
+ );
1685
+ const birthEventNote = dateNote(birthDateNode, shortNote);
1686
+ const birthEventPlace = showPlaces ? birthEvent?.PLAC?.value : void 0;
1687
+ if (birthDate) {
1688
+ birthStrings.push(
1689
+ `*${birthEventNote && showNote ? i18n.t(`${birthEventNote} {{date}}`, {
1690
+ date: birthDate
1691
+ }) : birthDate}`
1692
+ );
1693
+ }
1694
+ birthPlaces.push(birthEventPlace);
1695
+ });
1696
+ const deathStrings = [];
1697
+ const deathPlaces = [];
1698
+ const deathEventsToProcess = showAllEvents ? deathEvents : deathEvents.slice(0, 1);
1699
+ deathEventsToProcess.forEach((deathEvent) => {
1700
+ const deathDateNode = firstDate(deathEvent?.DATE);
1701
+ const deathDate = commonDateFormatter(
1702
+ deathDateNode,
1703
+ showDays ? fullDateFormat : "yyyy"
1704
+ );
1705
+ const deathEventNote = dateNote(deathDateNode, shortNote);
1706
+ const deathEventPlace = showPlaces ? deathEvent?.PLAC?.value : void 0;
1707
+ if (deathDate) {
1708
+ deathStrings.push(
1709
+ `\u2020${deathEventNote && showNote ? i18n.t(`${deathEventNote} {{date}}`, {
1710
+ date: deathDate
1711
+ }) : deathDate}`
1712
+ );
1713
+ }
1714
+ deathPlaces.push(deathEventPlace);
1715
+ });
1716
+ const birthString = birthStrings[0] ?? "";
1717
+ const deathString = deathStrings[0] ?? "";
1718
+ const marriageArray = marriages.length ? marriages.filter(Boolean) : [];
1719
+ const datesArray = !birth && !death ? marriageArray : [...birthStrings, ...marriageArray, ...deathStrings];
1720
+ const placesArray = !birth && !death ? marriagePlaces : [...birthPlaces, ...marriagePlaces, ...deathPlaces];
1721
+ const nonNullDatesArray = datesArray.filter(Boolean);
1722
+ const dates = nonNullDatesArray.join(" ").trim();
1723
+ return {
1724
+ inArray: nonNullDatesArray,
1725
+ inOrder: dates,
1726
+ places: placesArray,
1727
+ birth: birthString,
1728
+ marriage: marriageArray,
1729
+ death: deathString,
1730
+ ...showPlaces ? {
1731
+ birthPlace,
1732
+ deathPlace,
1733
+ ...showMarriages ? { marriages, marriagePlaces } : {}
1734
+ } : {},
1735
+ ...showAllEvents ? {
1736
+ births: birthStrings,
1737
+ birthPlaces,
1738
+ deaths: deathStrings,
1739
+ deathPlaces
1740
+ } : {}
1741
+ };
1712
1742
  };
1713
1743
 
1714
1744
  // src/utils/fact-edit.ts
@@ -8033,6 +8063,8 @@ var formatDateWithComponents = (date, hasDay, hasMonth, hasYear, noteValue, base
8033
8063
  var CommonDate = class extends Common {
8034
8064
  constructor(gedcom, id, main, parent) {
8035
8065
  super(gedcom, id, main, parent);
8066
+ /** One DATE per event — merge must not turn this into a List. */
8067
+ this.isListable = false;
8036
8068
  delete this.id;
8037
8069
  }
8038
8070
  get calendar() {