@treeviz/gedcom-parser 2.0.10 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +236 -989
- package/dist/classes/common.d.ts +10 -5
- package/dist/classes/common.d.ts.map +1 -1
- package/dist/classes/date.d.ts +2 -0
- package/dist/classes/date.d.ts.map +1 -1
- package/dist/classes/fam.d.ts +10 -1
- package/dist/classes/fam.d.ts.map +1 -1
- package/dist/classes/fams.d.ts.map +1 -1
- package/dist/classes/gedcom.d.ts +45 -4
- package/dist/classes/gedcom.d.ts.map +1 -1
- package/dist/classes/index.js +1770 -279
- package/dist/classes/indi.d.ts +24 -1
- package/dist/classes/indi.d.ts.map +1 -1
- package/dist/classes/list.d.ts.map +1 -1
- package/dist/classes/note.d.ts.map +1 -1
- package/dist/classes/obje.d.ts +2 -1
- package/dist/classes/obje.d.ts.map +1 -1
- package/dist/cli/index.js +2802 -1296
- package/dist/constants/constants.d.ts +7 -0
- package/dist/constants/constants.d.ts.map +1 -1
- package/dist/constants/index.js +1599 -989
- package/dist/factories/index.js +719 -110
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3837 -2028
- package/dist/interfaces/common.d.ts +6 -4
- package/dist/interfaces/common.d.ts.map +1 -1
- package/dist/interfaces/fam.d.ts +10 -1
- package/dist/interfaces/fam.d.ts.map +1 -1
- package/dist/interfaces/gedcom.d.ts +25 -1
- package/dist/interfaces/gedcom.d.ts.map +1 -1
- package/dist/interfaces/indi.d.ts +15 -1
- package/dist/interfaces/indi.d.ts.map +1 -1
- package/dist/kinship-translator/index.js +719 -110
- package/dist/structures/gedcom.d.ts +2 -0
- package/dist/structures/gedcom.d.ts.map +1 -1
- package/dist/types/types.d.ts +32 -4
- package/dist/types/types.d.ts.map +1 -1
- package/dist/utils/common-creator.d.ts.map +1 -1
- package/dist/utils/fact-edit.d.ts +34 -0
- package/dist/utils/fact-edit.d.ts.map +1 -0
- package/dist/utils/family-edit.d.ts +23 -0
- package/dist/utils/family-edit.d.ts.map +1 -0
- package/dist/utils/gedcom-trailer.d.ts +6 -0
- package/dist/utils/gedcom-trailer.d.ts.map +1 -0
- package/dist/utils/gedcom-version.d.ts +6 -0
- package/dist/utils/gedcom-version.d.ts.map +1 -0
- package/dist/utils/gedcom7-dates.d.ts +20 -0
- package/dist/utils/gedcom7-dates.d.ts.map +1 -0
- package/dist/utils/gedcom7-enumerations.d.ts +26 -0
- package/dist/utils/gedcom7-enumerations.d.ts.map +1 -0
- package/dist/utils/gedcom7-metadata.d.ts +19 -0
- package/dist/utils/gedcom7-metadata.d.ts.map +1 -0
- package/dist/utils/gedcom7-schema.d.ts +27 -0
- package/dist/utils/gedcom7-schema.d.ts.map +1 -0
- package/dist/utils/gedzip.d.ts +81 -0
- package/dist/utils/gedzip.d.ts.map +1 -0
- package/dist/utils/index.d.ts +13 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2225 -416
- package/dist/utils/local-media.d.ts +30 -0
- package/dist/utils/local-media.d.ts.map +1 -0
- package/dist/utils/media-utils.d.ts +10 -6
- package/dist/utils/media-utils.d.ts.map +1 -1
- package/dist/utils/multimedia.d.ts +38 -0
- package/dist/utils/multimedia.d.ts.map +1 -0
- package/dist/utils/parser.d.ts +3 -0
- package/dist/utils/parser.d.ts.map +1 -1
- package/dist/utils/uid.d.ts +6 -0
- package/dist/utils/uid.d.ts.map +1 -0
- package/package.json +2 -1
package/dist/classes/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { format, isValid, parse } from 'date-fns';
|
|
2
2
|
import { debounce, set, get, uniqBy, unset, difference, intersectionBy, differenceBy } from 'lodash-es';
|
|
3
|
+
import JSZip from 'jszip';
|
|
3
4
|
|
|
4
5
|
var __defProp = Object.defineProperty;
|
|
5
6
|
var __export = (target, all) => {
|
|
@@ -82,8 +83,28 @@ __export(translators_exports, {
|
|
|
82
83
|
});
|
|
83
84
|
|
|
84
85
|
// src/constants/constants.ts
|
|
86
|
+
var APP_BRANDING = "TreeViz - The Family Tree Visualiser & Editor";
|
|
85
87
|
var ID_REG = /^@[_a-zA-Z0-9]+@/;
|
|
86
88
|
var ID_GETTER_REG = /^(?<at>@)?(?<letter>[A-Z])?/i;
|
|
89
|
+
var ORIG_HEAD_TAG = "_ORIGHEAD";
|
|
90
|
+
|
|
91
|
+
// src/utils/gedcom-trailer.ts
|
|
92
|
+
var TRAILER_LINE = /^0 TRLR\s*$/i;
|
|
93
|
+
var GEDCOM_TRAILER_TAG = "TRLR";
|
|
94
|
+
var isGedcomTrailerTag = (tag) => tag === GEDCOM_TRAILER_TAG;
|
|
95
|
+
var isGedcomTrailerLine = (line) => TRAILER_LINE.test(line);
|
|
96
|
+
var appendGedcomTrailer = (serialized) => {
|
|
97
|
+
const newline = serialized.includes("\r\n") ? "\r\n" : "\n";
|
|
98
|
+
const trimmed = serialized.replace(/(?:\r?\n)+$/, "");
|
|
99
|
+
if (!trimmed) {
|
|
100
|
+
return "0 TRLR";
|
|
101
|
+
}
|
|
102
|
+
const lastLine = trimmed.split(/\r?\n/).at(-1) ?? "";
|
|
103
|
+
if (isGedcomTrailerLine(lastLine)) {
|
|
104
|
+
return trimmed;
|
|
105
|
+
}
|
|
106
|
+
return `${trimmed}${newline}0 TRLR`;
|
|
107
|
+
};
|
|
87
108
|
var List = class _List {
|
|
88
109
|
// length = 0;
|
|
89
110
|
constructor(items) {
|
|
@@ -459,11 +480,17 @@ var List = class _List {
|
|
|
459
480
|
const gedcom = [];
|
|
460
481
|
this.entries().forEach(([_, item]) => {
|
|
461
482
|
const validTag = getValidTag(tag);
|
|
462
|
-
const
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
483
|
+
const xref = item.id;
|
|
484
|
+
const payload = item.exportValue?.();
|
|
485
|
+
if (xref) {
|
|
486
|
+
gedcom.push(
|
|
487
|
+
`${level} ${xref} ${validTag}${payload ? ` ${payload}` : ""}`
|
|
488
|
+
);
|
|
489
|
+
} else {
|
|
490
|
+
gedcom.push(
|
|
491
|
+
`${level} ${validTag}${payload ? ` ${payload}` : ""}`
|
|
492
|
+
);
|
|
493
|
+
}
|
|
467
494
|
gedcom.push(
|
|
468
495
|
...item.toGedcomLines(
|
|
469
496
|
validTag,
|
|
@@ -594,6 +621,9 @@ var Common = class _Common {
|
|
|
594
621
|
delete this._value;
|
|
595
622
|
}
|
|
596
623
|
set(name, value) {
|
|
624
|
+
if (isGedcomTrailerTag(name)) {
|
|
625
|
+
return void 0;
|
|
626
|
+
}
|
|
597
627
|
if (typeof value === "string") {
|
|
598
628
|
const usedValue = createCommon(this._gedcom, void 0, this.main);
|
|
599
629
|
usedValue.value = value;
|
|
@@ -604,6 +634,9 @@ var Common = class _Common {
|
|
|
604
634
|
return get(this, name);
|
|
605
635
|
}
|
|
606
636
|
assign(name, value, unique = false) {
|
|
637
|
+
if (isGedcomTrailerTag(name)) {
|
|
638
|
+
return void 0;
|
|
639
|
+
}
|
|
607
640
|
let curValue = this.get(name);
|
|
608
641
|
if (curValue?.isListable) {
|
|
609
642
|
if (curValue instanceof _Common) {
|
|
@@ -715,12 +748,14 @@ var Common = class _Common {
|
|
|
715
748
|
);
|
|
716
749
|
}
|
|
717
750
|
standardizeObject(tag, options) {
|
|
718
|
-
if (tag === "OBJE" &&
|
|
751
|
+
if (tag === "OBJE" && options?.obje?.standardize && "standardizeMedia" in this) {
|
|
719
752
|
const standardize = this.standardizeMedia;
|
|
720
753
|
return standardize.call(
|
|
721
754
|
this,
|
|
722
755
|
options.obje.namespace,
|
|
723
|
-
options.obje.override
|
|
756
|
+
options.obje.override,
|
|
757
|
+
void 0,
|
|
758
|
+
options.gedcomVersion
|
|
724
759
|
);
|
|
725
760
|
}
|
|
726
761
|
}
|
|
@@ -747,7 +782,7 @@ var Common = class _Common {
|
|
|
747
782
|
if (typeof prop?.toObject === "function") {
|
|
748
783
|
if (prop instanceof _Common) {
|
|
749
784
|
json[validKey] = prop.toObject(validKey, options);
|
|
750
|
-
} else {
|
|
785
|
+
} else if (prop instanceof List) {
|
|
751
786
|
json = {
|
|
752
787
|
...json,
|
|
753
788
|
...prop.toObject(validKey, options)
|
|
@@ -805,8 +840,12 @@ var Common = class _Common {
|
|
|
805
840
|
this.standardizeObject(tag, options);
|
|
806
841
|
const validKeys = getValidKeys(this);
|
|
807
842
|
const gedcom = [];
|
|
843
|
+
const isGedcom7Export = options?.gedcomVersion === "7.0";
|
|
808
844
|
validKeys.forEach((key) => {
|
|
809
845
|
const validKey = key;
|
|
846
|
+
if (isGedcom7Export && validKey === "CONC") {
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
810
849
|
const prop = this.get(validKey);
|
|
811
850
|
if (typeof prop?.toGedcomLines === "function") {
|
|
812
851
|
if (prop instanceof _Common) {
|
|
@@ -817,7 +856,7 @@ var Common = class _Common {
|
|
|
817
856
|
gedcom.push(
|
|
818
857
|
...prop.toGedcomLines(validKey, level + 1, options)
|
|
819
858
|
);
|
|
820
|
-
} else {
|
|
859
|
+
} else if (prop instanceof List) {
|
|
821
860
|
gedcom.push(
|
|
822
861
|
...prop.toGedcomLines(validKey, level, options)
|
|
823
862
|
);
|
|
@@ -826,30 +865,47 @@ var Common = class _Common {
|
|
|
826
865
|
});
|
|
827
866
|
return gedcom;
|
|
828
867
|
}
|
|
868
|
+
getHeadRecord() {
|
|
869
|
+
return get(this, "HEAD") || get(this.getGedcom(), "HEAD");
|
|
870
|
+
}
|
|
871
|
+
getOriginalHeadRecord() {
|
|
872
|
+
return get(this, ORIG_HEAD_TAG) || get(this.getGedcom(), ORIG_HEAD_TAG) || get(this.getHeadRecord(), ORIG_HEAD_TAG);
|
|
873
|
+
}
|
|
874
|
+
getSourceHeads() {
|
|
875
|
+
const heads = [this.getOriginalHeadRecord(), this.getHeadRecord()];
|
|
876
|
+
return heads.filter((head, index) => {
|
|
877
|
+
return Boolean(head && heads.indexOf(head) === index);
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
getFromSourceHeads(path) {
|
|
881
|
+
for (const head of this.getSourceHeads()) {
|
|
882
|
+
const value = get(head, path);
|
|
883
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
884
|
+
return value;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
return void 0;
|
|
888
|
+
}
|
|
889
|
+
sourStartsWith(prefix) {
|
|
890
|
+
return this.getSourceHeads().some((head) => {
|
|
891
|
+
const sour = get(head, "SOUR.value");
|
|
892
|
+
return !!sour?.toLowerCase()?.startsWith(prefix);
|
|
893
|
+
});
|
|
894
|
+
}
|
|
829
895
|
isGenoPro() {
|
|
830
|
-
|
|
831
|
-
const sour = get(head, "SOUR.value");
|
|
832
|
-
return !!sour?.toLowerCase()?.startsWith("genopro");
|
|
896
|
+
return this.sourStartsWith("genopro");
|
|
833
897
|
}
|
|
834
898
|
isAhnenblatt() {
|
|
835
|
-
|
|
836
|
-
const sour = get(head, "SOUR.value");
|
|
837
|
-
return !!sour?.toLowerCase()?.startsWith("ahnenblatt");
|
|
899
|
+
return this.sourStartsWith("ahnenblatt");
|
|
838
900
|
}
|
|
839
901
|
isGeni() {
|
|
840
|
-
|
|
841
|
-
const sour = get(head, "SOUR.value");
|
|
842
|
-
return !!sour?.toLowerCase()?.startsWith("geni");
|
|
902
|
+
return this.sourStartsWith("geni");
|
|
843
903
|
}
|
|
844
904
|
isAncestry() {
|
|
845
|
-
|
|
846
|
-
const sour = get(head, "SOUR.value");
|
|
847
|
-
return !!sour?.toLowerCase()?.startsWith("ancestry");
|
|
905
|
+
return this.sourStartsWith("ancestry");
|
|
848
906
|
}
|
|
849
907
|
isMyHeritage() {
|
|
850
|
-
|
|
851
|
-
const sour = get(head, "SOUR.value");
|
|
852
|
-
return !!sour?.toLowerCase()?.startsWith("myheritage");
|
|
908
|
+
return this.sourStartsWith("myheritage");
|
|
853
909
|
}
|
|
854
910
|
/**
|
|
855
911
|
* Get the source type as a string (for prefixing tree IDs and names)
|
|
@@ -866,22 +922,22 @@ var Common = class _Common {
|
|
|
866
922
|
return void 0;
|
|
867
923
|
}
|
|
868
924
|
isFamilySearch() {
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
925
|
+
return this.getSourceHeads().some((head) => {
|
|
926
|
+
const sourName = get(head, "SOUR.NAME.value");
|
|
927
|
+
return sourName === "FamilySearch API";
|
|
928
|
+
});
|
|
872
929
|
}
|
|
873
930
|
isGNO2GED() {
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
931
|
+
return this.getSourceHeads().some((head) => {
|
|
932
|
+
const sour = get(head, "SOUR.value");
|
|
933
|
+
return sour === "GNO2GED";
|
|
934
|
+
});
|
|
877
935
|
}
|
|
878
936
|
getAncestryTreeId() {
|
|
879
|
-
|
|
880
|
-
return get(this, path) || get(this.getGedcom(), path);
|
|
937
|
+
return this.getFromSourceHeads("SOUR._TREE.RIN.value") || (get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value"));
|
|
881
938
|
}
|
|
882
939
|
getMyHeritageTreeId() {
|
|
883
|
-
|
|
884
|
-
return get(this, path) || get(this.getGedcom(), path);
|
|
940
|
+
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"));
|
|
885
941
|
}
|
|
886
942
|
getTreeId() {
|
|
887
943
|
if (this?.isAncestry()) {
|
|
@@ -915,8 +971,7 @@ var Common = class _Common {
|
|
|
915
971
|
return this.getUniversalTreeId();
|
|
916
972
|
}
|
|
917
973
|
getAncestryTreeName() {
|
|
918
|
-
|
|
919
|
-
return get(this, path) || get(this.getGedcom(), path);
|
|
974
|
+
return this.getFromSourceHeads("SOUR._TREE.value") || (get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value"));
|
|
920
975
|
}
|
|
921
976
|
getMyHeritageTreeName() {
|
|
922
977
|
const path = "HEAD.FILE.value";
|
|
@@ -926,14 +981,14 @@ var Common = class _Common {
|
|
|
926
981
|
)?.groups?.tree;
|
|
927
982
|
}
|
|
928
983
|
getFamilySearchTreeId() {
|
|
929
|
-
const rin = get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value");
|
|
984
|
+
const rin = this.getFromSourceHeads("SOUR._TREE.RIN.value") || get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value");
|
|
930
985
|
if (rin) {
|
|
931
986
|
return rin;
|
|
932
987
|
}
|
|
933
988
|
return "familysearch";
|
|
934
989
|
}
|
|
935
990
|
getFamilySearchTreeName() {
|
|
936
|
-
const treeName = get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value");
|
|
991
|
+
const treeName = this.getFromSourceHeads("SOUR._TREE.value") || get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value");
|
|
937
992
|
if (treeName) {
|
|
938
993
|
return treeName;
|
|
939
994
|
}
|
|
@@ -1025,11 +1080,11 @@ var Common = class _Common {
|
|
|
1025
1080
|
const cleanName = fileName.replace(/\.ged$/i, "").replace(/_/g, " ");
|
|
1026
1081
|
return `${prefix}${cleanName}`;
|
|
1027
1082
|
}
|
|
1028
|
-
const sourName = get(this, "HEAD.SOUR.NAME.value") || get(this.getGedcom(), "HEAD.SOUR.NAME.value");
|
|
1083
|
+
const sourName = this.getFromSourceHeads("SOUR.NAME.value") || get(this, "HEAD.SOUR.NAME.value") || get(this.getGedcom(), "HEAD.SOUR.NAME.value");
|
|
1029
1084
|
if (sourName) {
|
|
1030
1085
|
return `${prefix}${sourName}`;
|
|
1031
1086
|
}
|
|
1032
|
-
const sourValue = get(this, "HEAD.SOUR.value") || get(this.getGedcom(), "HEAD.SOUR.value");
|
|
1087
|
+
const sourValue = this.getFromSourceHeads("SOUR.value") || get(this, "HEAD.SOUR.value") || get(this.getGedcom(), "HEAD.SOUR.value");
|
|
1033
1088
|
if (sourValue) {
|
|
1034
1089
|
return `${prefix}${sourValue}`;
|
|
1035
1090
|
}
|
|
@@ -1095,7 +1150,7 @@ var isOnlyMainProp = (key) => {
|
|
|
1095
1150
|
};
|
|
1096
1151
|
var isValidKey = (common, key) => {
|
|
1097
1152
|
const prop = get(common, key);
|
|
1098
|
-
return key !== "_gedcom" && key !== "_main" && key !== "_parent" && key !== "_uniqueId" && key !== "_refs" && key !== "_type" && (key === "id" || key === "_id" || key === "value" || key === "_value" || prop instanceof Common || prop instanceof List);
|
|
1153
|
+
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);
|
|
1099
1154
|
};
|
|
1100
1155
|
var getValidKeys = (common) => {
|
|
1101
1156
|
return Object.keys(common).filter((key) => {
|
|
@@ -3182,7 +3237,11 @@ var STANDARD_QUALIFIERS = {
|
|
|
3182
3237
|
BEF: "Bef.",
|
|
3183
3238
|
BEFORE: "Bef.",
|
|
3184
3239
|
AFT: "Aft.",
|
|
3185
|
-
AFTER: "Aft."
|
|
3240
|
+
AFTER: "Aft.",
|
|
3241
|
+
CAL: "Abt.",
|
|
3242
|
+
// calculated ≈ about for display
|
|
3243
|
+
EST: "Abt."
|
|
3244
|
+
// estimated ≈ about for display
|
|
3186
3245
|
};
|
|
3187
3246
|
var EXPORT_QUALIFIERS = {
|
|
3188
3247
|
"Abt.": "ABT",
|
|
@@ -3190,6 +3249,11 @@ var EXPORT_QUALIFIERS = {
|
|
|
3190
3249
|
"Aft.": "AFT"
|
|
3191
3250
|
};
|
|
3192
3251
|
var GEDCOM_MONTHS = /\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b/g;
|
|
3252
|
+
var CALENDAR_PREFIX = /^(?<calendar>GREGORIAN|JULIAN|FRENCH_R|HEBREW)\b\s+/i;
|
|
3253
|
+
var isGedcomDateValueForm = (value) => (
|
|
3254
|
+
// Require space/end after the token so display forms like "Abt." are not opaque.
|
|
3255
|
+
/^(FROM|TO|BET|AFT|BEF|ABT|CAL|EST|INT)(\s|$)/i.test(value) || /\bAND\b/i.test(value)
|
|
3256
|
+
);
|
|
3193
3257
|
var NOTE_MARKER = "####";
|
|
3194
3258
|
var formatDateWithComponents = (date, hasDay, hasMonth, hasYear, noteValue, baseFormat = "dd MMM yyyy", locale) => {
|
|
3195
3259
|
const hasNote = baseFormat.includes("NOTE");
|
|
@@ -3214,29 +3278,45 @@ var CommonDate = class extends Common {
|
|
|
3214
3278
|
super(gedcom, id, main, parent);
|
|
3215
3279
|
delete this.id;
|
|
3216
3280
|
}
|
|
3281
|
+
get calendar() {
|
|
3282
|
+
return this._calendar;
|
|
3283
|
+
}
|
|
3217
3284
|
set value(value) {
|
|
3218
3285
|
if (value) {
|
|
3219
|
-
const noteRegExp = /^(?<note>[a-zA-Z]+\.)/;
|
|
3220
|
-
const noteMatch = value.match(noteRegExp)?.groups;
|
|
3221
3286
|
let validValue = value;
|
|
3287
|
+
const calendarMatch = validValue.match(CALENDAR_PREFIX);
|
|
3288
|
+
if (calendarMatch?.groups?.calendar) {
|
|
3289
|
+
this._calendar = calendarMatch.groups.calendar.toUpperCase();
|
|
3290
|
+
validValue = validValue.slice(calendarMatch[0].length);
|
|
3291
|
+
} else {
|
|
3292
|
+
this._calendar = void 0;
|
|
3293
|
+
}
|
|
3294
|
+
const noteRegExp = /^(?<note>[a-zA-Z]+\.)/;
|
|
3295
|
+
const noteMatch = validValue.match(noteRegExp)?.groups;
|
|
3222
3296
|
if (noteMatch?.note) {
|
|
3223
3297
|
this.NOTE = this.NOTE || createCommon(this._gedcom, void 0, this.main);
|
|
3224
3298
|
this.NOTE.value = noteMatch?.note;
|
|
3225
|
-
validValue =
|
|
3299
|
+
validValue = validValue.replace(noteRegExp, "");
|
|
3226
3300
|
} else {
|
|
3227
|
-
const qualifierMatch =
|
|
3228
|
-
/^(?<qualifier>ABT|ABOUT|BEF|BEFORE|AFT|AFTER)\b\s*/i
|
|
3301
|
+
const qualifierMatch = validValue.match(
|
|
3302
|
+
/^(?<qualifier>ABT|ABOUT|BEF|BEFORE|AFT|AFTER|CAL|EST)\b\s*/i
|
|
3229
3303
|
);
|
|
3230
3304
|
const qualifier = qualifierMatch?.groups?.qualifier?.toUpperCase();
|
|
3231
3305
|
const note = qualifier ? STANDARD_QUALIFIERS[qualifier] : void 0;
|
|
3232
3306
|
if (note) {
|
|
3233
3307
|
this.NOTE = this.NOTE || createCommon(this._gedcom, void 0, this.main);
|
|
3234
3308
|
this.NOTE.value = note;
|
|
3235
|
-
validValue =
|
|
3309
|
+
validValue = validValue.slice(qualifierMatch[0].length);
|
|
3236
3310
|
}
|
|
3237
3311
|
}
|
|
3238
3312
|
const acceptedDate = this.isValidDateFormat(validValue);
|
|
3239
|
-
if (
|
|
3313
|
+
if (isGedcomDateValueForm(validValue.trim())) {
|
|
3314
|
+
delete this.DAY;
|
|
3315
|
+
delete this.MONTH;
|
|
3316
|
+
delete this.YEAR;
|
|
3317
|
+
this._date = void 0;
|
|
3318
|
+
this._value = value;
|
|
3319
|
+
} else if (acceptedDate) {
|
|
3240
3320
|
this.DAY = this.DAY || createCommon(this._gedcom, void 0, this.main);
|
|
3241
3321
|
this.DAY.value = format(acceptedDate, "dd");
|
|
3242
3322
|
this.MONTH = this.MONTH || createCommon(this._gedcom, void 0, this.main);
|
|
@@ -3339,6 +3419,15 @@ var CommonDate = class extends Common {
|
|
|
3339
3419
|
);
|
|
3340
3420
|
}
|
|
3341
3421
|
exportValue() {
|
|
3422
|
+
if (typeof this._value === "string") {
|
|
3423
|
+
const withoutCalendar = this._value.replace(CALENDAR_PREFIX, "");
|
|
3424
|
+
if (isGedcomDateValueForm(withoutCalendar.trim())) {
|
|
3425
|
+
return this._value.replace(
|
|
3426
|
+
/^((?:GREGORIAN|JULIAN|FRENCH_R|HEBREW)\s+)?(FROM|TO|BET|AFT|BEF|ABT|CAL|EST|INT)\b/i,
|
|
3427
|
+
(_m, cal, q) => `${cal || ""}${q.toUpperCase()}`
|
|
3428
|
+
);
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3342
3431
|
const formatted = this.toValue("NOTE dd MMM yyyy", null);
|
|
3343
3432
|
if (!formatted) {
|
|
3344
3433
|
return formatted;
|
|
@@ -3346,10 +3435,14 @@ var CommonDate = class extends Common {
|
|
|
3346
3435
|
const note = this.NOTE?.value?.trim();
|
|
3347
3436
|
const qualifier = note ? EXPORT_QUALIFIERS[note] : void 0;
|
|
3348
3437
|
const standardized = qualifier ? formatted.replace(note, qualifier) : formatted;
|
|
3349
|
-
|
|
3438
|
+
const withMonths = standardized.replace(
|
|
3350
3439
|
GEDCOM_MONTHS,
|
|
3351
3440
|
(month) => month.toUpperCase()
|
|
3352
3441
|
);
|
|
3442
|
+
if (this._calendar && this._calendar !== "GREGORIAN") {
|
|
3443
|
+
return `${this._calendar} ${withMonths}`;
|
|
3444
|
+
}
|
|
3445
|
+
return withMonths;
|
|
3353
3446
|
}
|
|
3354
3447
|
toGedcomLines(tag, level = 0, options) {
|
|
3355
3448
|
const internal = new RegExp(
|
|
@@ -3810,6 +3903,268 @@ var cacheDiscoveredPath = (gedcom, path) => {
|
|
|
3810
3903
|
}
|
|
3811
3904
|
};
|
|
3812
3905
|
|
|
3906
|
+
// src/utils/fact-edit.ts
|
|
3907
|
+
var SINGLETON_TAGS = /* @__PURE__ */ new Set(["BIRT", "DEAT", "SSN", "SEX", "DSCR"]);
|
|
3908
|
+
var firstRecord = (node) => {
|
|
3909
|
+
if (!node) {
|
|
3910
|
+
return void 0;
|
|
3911
|
+
}
|
|
3912
|
+
if (node instanceof List) {
|
|
3913
|
+
return node.index(0);
|
|
3914
|
+
}
|
|
3915
|
+
return node.index(0) ?? node;
|
|
3916
|
+
};
|
|
3917
|
+
var setDateOn = (gedcom, owner, parent, date) => {
|
|
3918
|
+
const trimmed = date.trim();
|
|
3919
|
+
if (!trimmed) {
|
|
3920
|
+
return;
|
|
3921
|
+
}
|
|
3922
|
+
let dateNode = parent.get("DATE");
|
|
3923
|
+
if (!dateNode || dateNode instanceof List) {
|
|
3924
|
+
dateNode = createCommonDate(gedcom, void 0, owner, parent);
|
|
3925
|
+
dateNode.type = "DATE";
|
|
3926
|
+
parent.set("DATE", dateNode);
|
|
3927
|
+
}
|
|
3928
|
+
dateNode.value = trimmed;
|
|
3929
|
+
};
|
|
3930
|
+
var fillFact = (gedcom, owner, event, input) => {
|
|
3931
|
+
if (input.value?.trim()) {
|
|
3932
|
+
event.value = input.value.trim();
|
|
3933
|
+
}
|
|
3934
|
+
if (input.type?.trim()) {
|
|
3935
|
+
event.set("TYPE", input.type.trim());
|
|
3936
|
+
}
|
|
3937
|
+
if (input.date) {
|
|
3938
|
+
setDateOn(gedcom, owner, event, input.date);
|
|
3939
|
+
}
|
|
3940
|
+
if (input.place?.trim()) {
|
|
3941
|
+
event.set("PLAC", input.place.trim());
|
|
3942
|
+
}
|
|
3943
|
+
if (input.note?.trim()) {
|
|
3944
|
+
event.set("NOTE", input.note.trim());
|
|
3945
|
+
}
|
|
3946
|
+
};
|
|
3947
|
+
var addIndividualFact = (indi, input) => {
|
|
3948
|
+
const gedcom = indi.getGedcom();
|
|
3949
|
+
if (!gedcom) {
|
|
3950
|
+
return void 0;
|
|
3951
|
+
}
|
|
3952
|
+
const tag = input.tag;
|
|
3953
|
+
let event = SINGLETON_TAGS.has(tag) ? firstRecord(indi.get(tag)) : void 0;
|
|
3954
|
+
if (!event) {
|
|
3955
|
+
event = createCommon(gedcom, void 0, indi);
|
|
3956
|
+
event.type = tag;
|
|
3957
|
+
if (SINGLETON_TAGS.has(tag)) {
|
|
3958
|
+
indi.set(tag, event);
|
|
3959
|
+
} else {
|
|
3960
|
+
indi.assign(tag, event);
|
|
3961
|
+
}
|
|
3962
|
+
}
|
|
3963
|
+
fillFact(gedcom, indi, event, input);
|
|
3964
|
+
return event;
|
|
3965
|
+
};
|
|
3966
|
+
var addFamilyFact = (fam, input) => {
|
|
3967
|
+
const gedcom = fam.getGedcom();
|
|
3968
|
+
if (!gedcom) {
|
|
3969
|
+
return void 0;
|
|
3970
|
+
}
|
|
3971
|
+
const event = createCommon(gedcom, void 0, fam);
|
|
3972
|
+
event.type = input.tag;
|
|
3973
|
+
fam.assign(input.tag, event);
|
|
3974
|
+
fillFact(gedcom, fam, event, input);
|
|
3975
|
+
return event;
|
|
3976
|
+
};
|
|
3977
|
+
var addNonEvent = (owner, input) => {
|
|
3978
|
+
const gedcom = owner.getGedcom();
|
|
3979
|
+
const eventType = input.event?.trim().toUpperCase();
|
|
3980
|
+
if (!gedcom || !eventType) {
|
|
3981
|
+
return void 0;
|
|
3982
|
+
}
|
|
3983
|
+
const no = createCommon(gedcom, void 0, owner);
|
|
3984
|
+
no.type = "NO";
|
|
3985
|
+
no.value = eventType;
|
|
3986
|
+
if (input.date?.trim()) {
|
|
3987
|
+
setDateOn(gedcom, owner, no, input.date);
|
|
3988
|
+
}
|
|
3989
|
+
if (input.note?.trim()) {
|
|
3990
|
+
no.set("NOTE", input.note.trim());
|
|
3991
|
+
}
|
|
3992
|
+
owner.assign("NO", no);
|
|
3993
|
+
return no;
|
|
3994
|
+
};
|
|
3995
|
+
|
|
3996
|
+
// src/utils/family-edit.ts
|
|
3997
|
+
var PEDIGREE_VALUES = [
|
|
3998
|
+
"birth" /* BIRTH */,
|
|
3999
|
+
"adopted" /* ADOPTED */,
|
|
4000
|
+
"foster" /* FOSTER */,
|
|
4001
|
+
"step" /* STEP */,
|
|
4002
|
+
"sealing" /* SEALING */
|
|
4003
|
+
];
|
|
4004
|
+
var toGedcomPedigree = (value) => {
|
|
4005
|
+
const normalized = String(value || "birth" /* BIRTH */).toLowerCase();
|
|
4006
|
+
if (normalized === "biological" /* BIOLOGICAL */ || normalized === "birth" /* BIRTH */) {
|
|
4007
|
+
return "birth" /* BIRTH */;
|
|
4008
|
+
}
|
|
4009
|
+
const match = PEDIGREE_VALUES.find((item) => item === normalized);
|
|
4010
|
+
return match ?? "birth" /* BIRTH */;
|
|
4011
|
+
};
|
|
4012
|
+
var pointerIds = (tag) => {
|
|
4013
|
+
if (!tag) {
|
|
4014
|
+
return [];
|
|
4015
|
+
}
|
|
4016
|
+
if (tag instanceof List) {
|
|
4017
|
+
return tag.values().map((item) => item?.toValue?.()).filter((value2) => !!value2);
|
|
4018
|
+
}
|
|
4019
|
+
const value = tag.toValue?.();
|
|
4020
|
+
return value ? [String(value)] : [];
|
|
4021
|
+
};
|
|
4022
|
+
var firstPointerId = (tag) => pointerIds(tag)[0];
|
|
4023
|
+
var makePointer = (gedcom, parent, value, refType) => {
|
|
4024
|
+
const pointer = createCommon(gedcom, void 0, parent);
|
|
4025
|
+
pointer.value = value;
|
|
4026
|
+
pointer.refType = refType;
|
|
4027
|
+
return pointer;
|
|
4028
|
+
};
|
|
4029
|
+
var nextRecordId = (ids, prefix) => {
|
|
4030
|
+
let max = 0;
|
|
4031
|
+
ids.forEach((id) => {
|
|
4032
|
+
const match = String(id).match(/(\d+)/);
|
|
4033
|
+
const n = match ? Number.parseInt(match[1], 10) : 0;
|
|
4034
|
+
if (n > max) {
|
|
4035
|
+
max = n;
|
|
4036
|
+
}
|
|
4037
|
+
});
|
|
4038
|
+
return `@${prefix}${max + 1}@`;
|
|
4039
|
+
};
|
|
4040
|
+
var familyHasParent = (fam, indiId) => pointerIds(fam.get("HUSB")).includes(indiId) || pointerIds(fam.get("WIFE")).includes(indiId);
|
|
4041
|
+
var familyHasChild = (fam, indiId) => pointerIds(fam.get("CHIL")).includes(indiId);
|
|
4042
|
+
var spouseTagFor = (indi, fam) => {
|
|
4043
|
+
const husbId = firstPointerId(fam.get("HUSB"));
|
|
4044
|
+
const wifeId = firstPointerId(fam.get("WIFE"));
|
|
4045
|
+
if (husbId === indi.id) {
|
|
4046
|
+
return "HUSB";
|
|
4047
|
+
}
|
|
4048
|
+
if (wifeId === indi.id) {
|
|
4049
|
+
return "WIFE";
|
|
4050
|
+
}
|
|
4051
|
+
if (indi.isFemale()) {
|
|
4052
|
+
return wifeId && wifeId !== indi.id ? "HUSB" : "WIFE";
|
|
4053
|
+
}
|
|
4054
|
+
if (indi.isMale()) {
|
|
4055
|
+
return husbId && husbId !== indi.id ? "WIFE" : "HUSB";
|
|
4056
|
+
}
|
|
4057
|
+
return husbId ? "WIFE" : "HUSB";
|
|
4058
|
+
};
|
|
4059
|
+
var canAttachAsSpouse = (fam, indi) => {
|
|
4060
|
+
if (!indi.id) {
|
|
4061
|
+
return false;
|
|
4062
|
+
}
|
|
4063
|
+
if (familyHasParent(fam, indi.id)) {
|
|
4064
|
+
return true;
|
|
4065
|
+
}
|
|
4066
|
+
const tag = spouseTagFor(indi, fam);
|
|
4067
|
+
const occupied = firstPointerId(fam.get(tag));
|
|
4068
|
+
return !occupied || occupied === indi.id;
|
|
4069
|
+
};
|
|
4070
|
+
var pointerByValue = (tag, id) => {
|
|
4071
|
+
if (!tag) {
|
|
4072
|
+
return void 0;
|
|
4073
|
+
}
|
|
4074
|
+
const fromValues = tag.toValueList?.().item(id);
|
|
4075
|
+
if (fromValues) {
|
|
4076
|
+
return fromValues;
|
|
4077
|
+
}
|
|
4078
|
+
return tag.toList()?.values().find((item) => item?.toValue?.() === id);
|
|
4079
|
+
};
|
|
4080
|
+
var setChildPedigree = (fam, child, pedigree, parent) => {
|
|
4081
|
+
if (!fam.id || !child.id) {
|
|
4082
|
+
return;
|
|
4083
|
+
}
|
|
4084
|
+
const pedi = toGedcomPedigree(pedigree);
|
|
4085
|
+
const famc = pointerByValue(child.get("FAMC"), fam.id);
|
|
4086
|
+
if (famc) {
|
|
4087
|
+
famc.set("PEDI", pedi);
|
|
4088
|
+
}
|
|
4089
|
+
const chil = pointerByValue(fam.get("CHIL"), child.id);
|
|
4090
|
+
if (!chil) {
|
|
4091
|
+
return;
|
|
4092
|
+
}
|
|
4093
|
+
const setFather = !parent || parent.isMale() || parent.isUnknownSex();
|
|
4094
|
+
const setMother = !parent || parent.isFemale() || parent.isUnknownSex();
|
|
4095
|
+
if (setFather) {
|
|
4096
|
+
chil.set("_FREL", pedi);
|
|
4097
|
+
}
|
|
4098
|
+
if (setMother) {
|
|
4099
|
+
chil.set("_MREL", pedi);
|
|
4100
|
+
}
|
|
4101
|
+
};
|
|
4102
|
+
var attachSpouseToFamily = (fam, indi) => {
|
|
4103
|
+
const gedcom = fam.getGedcom() ?? indi.getGedcom();
|
|
4104
|
+
if (!indi.id || !fam.id || !gedcom) {
|
|
4105
|
+
return false;
|
|
4106
|
+
}
|
|
4107
|
+
if (!canAttachAsSpouse(fam, indi)) {
|
|
4108
|
+
return false;
|
|
4109
|
+
}
|
|
4110
|
+
const tag = spouseTagFor(indi, fam);
|
|
4111
|
+
if (firstPointerId(fam.get(tag)) !== indi.id) {
|
|
4112
|
+
fam.set(tag, makePointer(gedcom, fam, indi.id, "INDI"));
|
|
4113
|
+
}
|
|
4114
|
+
indi.assign("FAMS", makePointer(gedcom, indi, fam.id, "FAM"), true);
|
|
4115
|
+
return true;
|
|
4116
|
+
};
|
|
4117
|
+
var attachChildToFamily = (fam, child, pedigree, parent) => {
|
|
4118
|
+
const gedcom = fam.getGedcom() ?? child.getGedcom();
|
|
4119
|
+
if (!child.id || !fam.id || !gedcom) {
|
|
4120
|
+
return false;
|
|
4121
|
+
}
|
|
4122
|
+
if (!familyHasChild(fam, child.id)) {
|
|
4123
|
+
fam.assign("CHIL", makePointer(gedcom, fam, child.id, "INDI"), true);
|
|
4124
|
+
}
|
|
4125
|
+
const existingFamc = pointerByValue(child.get("FAMC"), fam.id);
|
|
4126
|
+
if (!existingFamc) {
|
|
4127
|
+
child.assign("FAMC", makePointer(gedcom, child, fam.id, "FAM"), true);
|
|
4128
|
+
}
|
|
4129
|
+
setChildPedigree(fam, child, pedigree, parent);
|
|
4130
|
+
return true;
|
|
4131
|
+
};
|
|
4132
|
+
var findReusableParentChildFamily = (parent, child) => {
|
|
4133
|
+
if (!parent.id || !child.id) {
|
|
4134
|
+
return void 0;
|
|
4135
|
+
}
|
|
4136
|
+
let reusableFamc;
|
|
4137
|
+
let already = false;
|
|
4138
|
+
child.getFamilies("FAMC")?.forEach((fam) => {
|
|
4139
|
+
if (!fam) {
|
|
4140
|
+
return;
|
|
4141
|
+
}
|
|
4142
|
+
if (familyHasParent(fam, parent.id) && familyHasChild(fam, child.id)) {
|
|
4143
|
+
already = true;
|
|
4144
|
+
return;
|
|
4145
|
+
}
|
|
4146
|
+
if (!reusableFamc && canAttachAsSpouse(fam, parent)) {
|
|
4147
|
+
reusableFamc = fam;
|
|
4148
|
+
}
|
|
4149
|
+
});
|
|
4150
|
+
if (already) {
|
|
4151
|
+
return "already";
|
|
4152
|
+
}
|
|
4153
|
+
if (reusableFamc) {
|
|
4154
|
+
return reusableFamc;
|
|
4155
|
+
}
|
|
4156
|
+
const parentFams = [];
|
|
4157
|
+
parent.getFamilies("FAMS")?.forEach((fam) => {
|
|
4158
|
+
if (fam) {
|
|
4159
|
+
parentFams.push(fam);
|
|
4160
|
+
}
|
|
4161
|
+
});
|
|
4162
|
+
if (parentFams.length === 1) {
|
|
4163
|
+
return parentFams[0];
|
|
4164
|
+
}
|
|
4165
|
+
return void 0;
|
|
4166
|
+
};
|
|
4167
|
+
|
|
3813
4168
|
// src/utils/get-places.ts
|
|
3814
4169
|
var getPlaces = (common, type = ["ALL" /* All */], maxLevel = 1, level = 0, mainKey) => {
|
|
3815
4170
|
const types = Array.isArray(type) ? type : [type];
|
|
@@ -3874,16 +4229,58 @@ var getPlaces = (common, type = ["ALL" /* All */], maxLevel = 1, level = 0, main
|
|
|
3874
4229
|
});
|
|
3875
4230
|
return places;
|
|
3876
4231
|
};
|
|
4232
|
+
|
|
4233
|
+
// src/utils/local-media.ts
|
|
4234
|
+
var localMediaResolver;
|
|
4235
|
+
var isRemoteOrEmbeddedMediaUrl = (path) => {
|
|
4236
|
+
if (!path) {
|
|
4237
|
+
return false;
|
|
4238
|
+
}
|
|
4239
|
+
return path.startsWith("data:") || path.startsWith("blob:") || /^https?:\/\//i.test(path);
|
|
4240
|
+
};
|
|
4241
|
+
var resolveLocalMediaUrl = async (path) => {
|
|
4242
|
+
if (!path) {
|
|
4243
|
+
return void 0;
|
|
4244
|
+
}
|
|
4245
|
+
if (isRemoteOrEmbeddedMediaUrl(path)) {
|
|
4246
|
+
return path;
|
|
4247
|
+
}
|
|
4248
|
+
const resolved = await localMediaResolver?.(path);
|
|
4249
|
+
return resolved;
|
|
4250
|
+
};
|
|
3877
4251
|
var implemented = (type, ...args) => {
|
|
3878
4252
|
};
|
|
3879
4253
|
|
|
3880
4254
|
// src/utils/media-utils.ts
|
|
3881
4255
|
var getFileExtension = (filename) => {
|
|
3882
|
-
|
|
3883
|
-
|
|
4256
|
+
if (!filename) {
|
|
4257
|
+
return "";
|
|
4258
|
+
}
|
|
4259
|
+
if (filename.startsWith("data:")) {
|
|
4260
|
+
const mime = filename.slice(5).split(";")[0] || "";
|
|
4261
|
+
const subtype = (mime.split("/")[1] || "").toLowerCase();
|
|
4262
|
+
if (subtype === "jpeg") {
|
|
4263
|
+
return "jpg";
|
|
4264
|
+
}
|
|
4265
|
+
return subtype.split("+")[0] || "";
|
|
4266
|
+
}
|
|
4267
|
+
const withoutQuery = filename.split(/[?#]/)[0] || filename;
|
|
4268
|
+
const match = withoutQuery.match(/\.([^.]+)$/);
|
|
4269
|
+
return match ? match[1].toLowerCase() : "";
|
|
3884
4270
|
};
|
|
3885
4271
|
var isImageFormat = (format2) => {
|
|
3886
|
-
if (!format2)
|
|
4272
|
+
if (!format2) {
|
|
4273
|
+
return false;
|
|
4274
|
+
}
|
|
4275
|
+
let normalized = format2.toLowerCase().trim();
|
|
4276
|
+
if (normalized.startsWith("data:")) {
|
|
4277
|
+
normalized = getFileExtension(normalized);
|
|
4278
|
+
} else if (normalized.includes("/")) {
|
|
4279
|
+
normalized = normalized.split("/")[1]?.split("+")[0] || "";
|
|
4280
|
+
if (normalized === "jpeg") {
|
|
4281
|
+
normalized = "jpg";
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
3887
4284
|
const imageFormats = [
|
|
3888
4285
|
"jpg",
|
|
3889
4286
|
"jpeg",
|
|
@@ -3895,7 +4292,11 @@ var isImageFormat = (format2) => {
|
|
|
3895
4292
|
"tiff",
|
|
3896
4293
|
"tif"
|
|
3897
4294
|
];
|
|
3898
|
-
return imageFormats.includes(
|
|
4295
|
+
return imageFormats.includes(normalized);
|
|
4296
|
+
};
|
|
4297
|
+
var resolveObjeForm = (obje) => {
|
|
4298
|
+
const value = obje?.get?.("FILE.FORM")?.toValue?.() ?? obje?.get?.("FORM")?.toValue?.();
|
|
4299
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
3899
4300
|
};
|
|
3900
4301
|
var uniqueItemsCache = /* @__PURE__ */ new WeakMap();
|
|
3901
4302
|
var setNestedGroup = (obj, key, value, uniqueCounting = true) => {
|
|
@@ -4440,6 +4841,34 @@ var Fam = class extends Common {
|
|
|
4440
4841
|
getParents() {
|
|
4441
4842
|
return this.getHusband().copy().merge(this.getWife());
|
|
4442
4843
|
}
|
|
4844
|
+
hasParent(indi) {
|
|
4845
|
+
const indiId = typeof indi === "string" ? indi : indi?.id;
|
|
4846
|
+
return !!indiId && familyHasParent(this, indiId);
|
|
4847
|
+
}
|
|
4848
|
+
hasChild(indi) {
|
|
4849
|
+
const indiId = typeof indi === "string" ? indi : indi?.id;
|
|
4850
|
+
return !!indiId && familyHasChild(this, indiId);
|
|
4851
|
+
}
|
|
4852
|
+
canAddSpouse(indi) {
|
|
4853
|
+
return canAttachAsSpouse(this, indi);
|
|
4854
|
+
}
|
|
4855
|
+
addSpouse(indi) {
|
|
4856
|
+
return attachSpouseToFamily(this, indi);
|
|
4857
|
+
}
|
|
4858
|
+
addChild(child, pedigree, parent) {
|
|
4859
|
+
return attachChildToFamily(
|
|
4860
|
+
this,
|
|
4861
|
+
child,
|
|
4862
|
+
pedigree,
|
|
4863
|
+
parent
|
|
4864
|
+
);
|
|
4865
|
+
}
|
|
4866
|
+
addFact(input) {
|
|
4867
|
+
return addFamilyFact(this, input);
|
|
4868
|
+
}
|
|
4869
|
+
addNonEvent(input) {
|
|
4870
|
+
return addNonEvent(this, input);
|
|
4871
|
+
}
|
|
4443
4872
|
toList() {
|
|
4444
4873
|
return new Families().concat(
|
|
4445
4874
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -4512,19 +4941,51 @@ var ALLOWED_FACTS = [
|
|
|
4512
4941
|
"OCCU",
|
|
4513
4942
|
"OCCUPATIONS",
|
|
4514
4943
|
"RESI",
|
|
4944
|
+
"BIRT",
|
|
4945
|
+
"DEAT",
|
|
4515
4946
|
"BAPT",
|
|
4947
|
+
"BAPM",
|
|
4516
4948
|
"CHRI",
|
|
4517
4949
|
"CHR",
|
|
4950
|
+
"CHRA",
|
|
4518
4951
|
"BURI",
|
|
4519
|
-
"
|
|
4952
|
+
"CREM",
|
|
4953
|
+
"ADOP",
|
|
4954
|
+
"BARM",
|
|
4955
|
+
"BASM",
|
|
4956
|
+
"BLES",
|
|
4957
|
+
"CONF",
|
|
4958
|
+
"FCOM",
|
|
4959
|
+
"ORDN",
|
|
4960
|
+
"NATU",
|
|
4961
|
+
"EMIG",
|
|
4962
|
+
"IMMI",
|
|
4963
|
+
"CENS",
|
|
4964
|
+
"PROB",
|
|
4965
|
+
"WILL",
|
|
4520
4966
|
"GRAD",
|
|
4967
|
+
"RETI",
|
|
4968
|
+
"EDUC",
|
|
4521
4969
|
"DIV",
|
|
4522
|
-
"IMMI",
|
|
4523
4970
|
"RELI",
|
|
4971
|
+
"CAST",
|
|
4972
|
+
"DSCR",
|
|
4973
|
+
"NATI",
|
|
4974
|
+
"PROP",
|
|
4975
|
+
"SSN",
|
|
4976
|
+
"TITL",
|
|
4977
|
+
"ADDR",
|
|
4978
|
+
"BAPL",
|
|
4979
|
+
"CONL",
|
|
4980
|
+
"ENDL",
|
|
4981
|
+
"SLGC",
|
|
4524
4982
|
"_MILT",
|
|
4525
4983
|
"_MILTID",
|
|
4526
4984
|
"FACT",
|
|
4527
|
-
"_ORIG"
|
|
4985
|
+
"_ORIG",
|
|
4986
|
+
"_WLNK",
|
|
4987
|
+
"WWW",
|
|
4988
|
+
"URL"
|
|
4528
4989
|
];
|
|
4529
4990
|
var DISALLOWED_CUSTOM_FACTS = ["DNA Test", "Newspaper"];
|
|
4530
4991
|
var CustomFactRenderers = {
|
|
@@ -5068,7 +5529,7 @@ var Indi = class extends Common {
|
|
|
5068
5529
|
return result;
|
|
5069
5530
|
}
|
|
5070
5531
|
ancestryLink() {
|
|
5071
|
-
const www = this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
5532
|
+
const www = this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
5072
5533
|
const tree = this.getAncestryTreeId();
|
|
5073
5534
|
if (this.id) {
|
|
5074
5535
|
return `https://${www}/family-tree/person/tree/${tree}/person/${this.id.replace(
|
|
@@ -5080,7 +5541,7 @@ var Indi = class extends Common {
|
|
|
5080
5541
|
async ancestryMedia(namespace) {
|
|
5081
5542
|
const list = {};
|
|
5082
5543
|
const objeList = this.get("OBJE")?.toList().copy();
|
|
5083
|
-
const www = this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
5544
|
+
const www = this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
5084
5545
|
const tree = this.getAncestryTreeId();
|
|
5085
5546
|
if (objeList) {
|
|
5086
5547
|
await Promise.all(
|
|
@@ -5098,10 +5559,14 @@ var Indi = class extends Common {
|
|
|
5098
5559
|
const clone = obje?.get("_CLON._OID")?.toValue();
|
|
5099
5560
|
const mser = obje?.get("_MSER._LKID")?.toValue();
|
|
5100
5561
|
let url = obje?.get("FILE")?.toValue();
|
|
5101
|
-
const title = obje?.get("TITL")?.toValue() ?? "";
|
|
5102
|
-
const type = obje
|
|
5103
|
-
|
|
5104
|
-
|
|
5562
|
+
const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
|
|
5563
|
+
const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
|
|
5564
|
+
let imgId = clone || mser;
|
|
5565
|
+
const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
|
|
5566
|
+
if (!hasEmbeddedOrLocalFile && (!www || !tree || !this.id)) {
|
|
5567
|
+
return;
|
|
5568
|
+
}
|
|
5569
|
+
if (!this.id) {
|
|
5105
5570
|
return;
|
|
5106
5571
|
}
|
|
5107
5572
|
if (!namespace && !url) {
|
|
@@ -5119,13 +5584,16 @@ var Indi = class extends Common {
|
|
|
5119
5584
|
}
|
|
5120
5585
|
url = url || `https://${www}/mediaui-viewer/tree/${tree}/media/${media}`;
|
|
5121
5586
|
}
|
|
5587
|
+
if (!imgId && hasEmbeddedOrLocalFile && url) {
|
|
5588
|
+
imgId = typeof media === "string" && media || `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}`;
|
|
5589
|
+
}
|
|
5122
5590
|
if (url && imgId) {
|
|
5123
|
-
const id = `${tree}-${this.id}-${imgId}`;
|
|
5591
|
+
const id = `${tree || "gedzip"}-${this.id}-${imgId}`;
|
|
5124
5592
|
list[id] = {
|
|
5125
5593
|
key,
|
|
5126
5594
|
isPrimary,
|
|
5127
5595
|
id,
|
|
5128
|
-
tree,
|
|
5596
|
+
tree: tree || "gedzip",
|
|
5129
5597
|
imgId,
|
|
5130
5598
|
person: this.id,
|
|
5131
5599
|
title,
|
|
@@ -5140,7 +5608,7 @@ var Indi = class extends Common {
|
|
|
5140
5608
|
return list;
|
|
5141
5609
|
}
|
|
5142
5610
|
myheritageLink(poolId = 0) {
|
|
5143
|
-
const www = this._gedcom?.HEAD?.SOUR?.CORP?.value?.toLowerCase().replace(/^www\./gi, "");
|
|
5611
|
+
const www = (this.getFromSourceHeads("SOUR.CORP.value") || this._gedcom?.HEAD?.SOUR?.CORP?.value)?.toLowerCase().replace(/^www\./gi, "");
|
|
5144
5612
|
const site = this.getMyHeritageTreeId();
|
|
5145
5613
|
const file = this._gedcom?.HEAD?.get("FILE")?.toValue()?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)?.groups?.site;
|
|
5146
5614
|
const normalizedFile = file?.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
@@ -5171,9 +5639,11 @@ var Indi = class extends Common {
|
|
|
5171
5639
|
obje.standardizeMedia();
|
|
5172
5640
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
5173
5641
|
const url = obje?.get("FILE")?.toValue();
|
|
5174
|
-
const title = obje?.get("NOTE")?.toValue() ?? "";
|
|
5175
|
-
const type = obje
|
|
5176
|
-
const
|
|
5642
|
+
const title = obje?.get("FILE.NOTE")?.toValue() ?? obje?.get("NOTE")?.toValue() ?? "";
|
|
5643
|
+
const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
|
|
5644
|
+
const photoRin = obje?.get("_PHOTO_RIN")?.toValue();
|
|
5645
|
+
const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
|
|
5646
|
+
const imgId = photoRin || (hasEmbeddedOrLocalFile && url ? `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}` : void 0);
|
|
5177
5647
|
if (url && imgId) {
|
|
5178
5648
|
const id = `${tree}-${this.id}-${imgId}`;
|
|
5179
5649
|
list[id] = {
|
|
@@ -5296,10 +5766,10 @@ var Indi = class extends Common {
|
|
|
5296
5766
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
5297
5767
|
const url = obje?.get("FILE")?.toValue();
|
|
5298
5768
|
const title = obje?.get("TITL")?.toValue() ?? "";
|
|
5299
|
-
const type = obje
|
|
5769
|
+
const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
|
|
5300
5770
|
if (url) {
|
|
5301
5771
|
const urlMatch = url.match(/\/([^/]+)\?hash=/);
|
|
5302
|
-
const imgId = urlMatch?.[1] || `img-${index}-${Date.now().toString(36)}
|
|
5772
|
+
const imgId = urlMatch?.[1] || (url.startsWith("data:") ? `data-${index}-${getFileExtension(url) || "bin"}` : `img-${index}-${Date.now().toString(36)}`);
|
|
5303
5773
|
const id = `geni-${geniId}-${imgId}`;
|
|
5304
5774
|
list[id] = {
|
|
5305
5775
|
isPrimary,
|
|
@@ -5336,10 +5806,10 @@ var Indi = class extends Common {
|
|
|
5336
5806
|
obje.standardizeMedia();
|
|
5337
5807
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
5338
5808
|
const url = obje?.get("FILE")?.toValue();
|
|
5339
|
-
const title = obje?.get("TITL")?.toValue() ?? "";
|
|
5340
|
-
const type = obje
|
|
5809
|
+
const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
|
|
5810
|
+
const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
|
|
5341
5811
|
if (url) {
|
|
5342
|
-
const imgId = `media-${index}-${url.split("/").pop()?.split("?")[0]?.substring(0, 20) || Date.now().toString(36)}`;
|
|
5812
|
+
const imgId = `media-${index}-${url.startsWith("data:") ? getFileExtension(url) || "bin" : url.split("/").pop()?.split("?")[0]?.substring(0, 20) || Date.now().toString(36)}`;
|
|
5343
5813
|
const id = `${treeId}-${this.id}-${imgId}`;
|
|
5344
5814
|
list[id] = {
|
|
5345
5815
|
isPrimary,
|
|
@@ -5379,7 +5849,20 @@ var Indi = class extends Common {
|
|
|
5379
5849
|
cacheKey
|
|
5380
5850
|
);
|
|
5381
5851
|
if (cached !== void 0) {
|
|
5382
|
-
|
|
5852
|
+
if (cached?.file && !isRemoteOrEmbeddedMediaUrl(cached.file)) {
|
|
5853
|
+
const resolvedCached = await resolveLocalMediaUrl(cached.file);
|
|
5854
|
+
if (resolvedCached && isRemoteOrEmbeddedMediaUrl(resolvedCached)) {
|
|
5855
|
+
const refreshed = { ...cached, file: resolvedCached };
|
|
5856
|
+
profilePictureCache(
|
|
5857
|
+
this._gedcom,
|
|
5858
|
+
cacheKey,
|
|
5859
|
+
refreshed
|
|
5860
|
+
);
|
|
5861
|
+
return refreshed;
|
|
5862
|
+
}
|
|
5863
|
+
} else {
|
|
5864
|
+
return cached;
|
|
5865
|
+
}
|
|
5383
5866
|
}
|
|
5384
5867
|
const mediaList = await this.multimedia(namespace);
|
|
5385
5868
|
if (!mediaList) {
|
|
@@ -5391,39 +5874,40 @@ var Indi = class extends Common {
|
|
|
5391
5874
|
return void 0;
|
|
5392
5875
|
}
|
|
5393
5876
|
const mediaArray = Object.values(mediaList);
|
|
5394
|
-
const
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5877
|
+
const toDisplayableProfile = async (media, isPrimary) => {
|
|
5878
|
+
const resolvedFile = await resolveLocalMediaUrl(media.url);
|
|
5879
|
+
if (!resolvedFile || !isRemoteOrEmbeddedMediaUrl(resolvedFile)) {
|
|
5880
|
+
return void 0;
|
|
5881
|
+
}
|
|
5882
|
+
return {
|
|
5883
|
+
file: resolvedFile,
|
|
5884
|
+
form: media.contentType,
|
|
5885
|
+
title: media.title,
|
|
5886
|
+
isPrimary
|
|
5403
5887
|
};
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
this._gedcom,
|
|
5410
|
-
cacheKey,
|
|
5411
|
-
void 0
|
|
5412
|
-
);
|
|
5413
|
-
return void 0;
|
|
5414
|
-
}
|
|
5415
|
-
const secondaryMedia = mediaArray.find(
|
|
5416
|
-
(media) => isImageFormat(media.contentType || getFileExtension(media.url))
|
|
5888
|
+
};
|
|
5889
|
+
const candidates = mediaArray.filter(
|
|
5890
|
+
(media) => isImageFormat(
|
|
5891
|
+
media.contentType || media.url || getFileExtension(media.url)
|
|
5892
|
+
)
|
|
5417
5893
|
);
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5894
|
+
const ordered = [
|
|
5895
|
+
...candidates.filter((media) => media.isPrimary),
|
|
5896
|
+
...candidates.filter((media) => !media.isPrimary)
|
|
5897
|
+
];
|
|
5898
|
+
for (const media of ordered) {
|
|
5899
|
+
if (onlyPrimary && !media.isPrimary) {
|
|
5900
|
+
break;
|
|
5901
|
+
}
|
|
5902
|
+
const result = await toDisplayableProfile(media, !!media.isPrimary);
|
|
5903
|
+
if (result) {
|
|
5904
|
+
profilePictureCache(
|
|
5905
|
+
this._gedcom,
|
|
5906
|
+
cacheKey,
|
|
5907
|
+
result
|
|
5908
|
+
);
|
|
5909
|
+
return result;
|
|
5910
|
+
}
|
|
5427
5911
|
}
|
|
5428
5912
|
profilePictureCache(
|
|
5429
5913
|
this._gedcom,
|
|
@@ -5661,6 +6145,156 @@ var Indi = class extends Common {
|
|
|
5661
6145
|
isUnknownSex() {
|
|
5662
6146
|
return !this.isMale() && !this.isFemale();
|
|
5663
6147
|
}
|
|
6148
|
+
addSpouse(other) {
|
|
6149
|
+
if (!this.id || !other?.id || this.id === other.id || !this._gedcom) {
|
|
6150
|
+
return void 0;
|
|
6151
|
+
}
|
|
6152
|
+
const existing = getFamilyWith(this, other.id);
|
|
6153
|
+
if (existing) {
|
|
6154
|
+
return existing;
|
|
6155
|
+
}
|
|
6156
|
+
const fam = this._gedcom.createFamily();
|
|
6157
|
+
if (!fam.addSpouse(this) || !fam.addSpouse(other)) {
|
|
6158
|
+
return void 0;
|
|
6159
|
+
}
|
|
6160
|
+
return fam;
|
|
6161
|
+
}
|
|
6162
|
+
addChild(child, pedigree) {
|
|
6163
|
+
if (!this.id || !child?.id || this.id === child.id || !this._gedcom) {
|
|
6164
|
+
return void 0;
|
|
6165
|
+
}
|
|
6166
|
+
const existing = findReusableParentChildFamily(
|
|
6167
|
+
this,
|
|
6168
|
+
child
|
|
6169
|
+
);
|
|
6170
|
+
if (existing === "already") {
|
|
6171
|
+
const fam2 = child.getFamilies("FAMC")?.find(
|
|
6172
|
+
(item) => !!item && item.hasParent(this.id) && item.hasChild(child.id)
|
|
6173
|
+
);
|
|
6174
|
+
if (fam2) {
|
|
6175
|
+
setChildPedigree(
|
|
6176
|
+
fam2,
|
|
6177
|
+
child,
|
|
6178
|
+
pedigree,
|
|
6179
|
+
this
|
|
6180
|
+
);
|
|
6181
|
+
}
|
|
6182
|
+
return fam2;
|
|
6183
|
+
}
|
|
6184
|
+
const fam = existing ?? this._gedcom.createFamily();
|
|
6185
|
+
if (!fam.addSpouse(this)) {
|
|
6186
|
+
return void 0;
|
|
6187
|
+
}
|
|
6188
|
+
if (!fam.addChild(child, pedigree, this)) {
|
|
6189
|
+
return void 0;
|
|
6190
|
+
}
|
|
6191
|
+
return fam;
|
|
6192
|
+
}
|
|
6193
|
+
addParent(parent, pedigree) {
|
|
6194
|
+
return parent.addChild(this, pedigree);
|
|
6195
|
+
}
|
|
6196
|
+
/**
|
|
6197
|
+
* Link an existing top-level OBJE record to this individual (`1 OBJE @On@`).
|
|
6198
|
+
*/
|
|
6199
|
+
attachMultimedia(objeOrKey, options) {
|
|
6200
|
+
if (!this._gedcom || !this.id) {
|
|
6201
|
+
return void 0;
|
|
6202
|
+
}
|
|
6203
|
+
const obje = typeof objeOrKey === "string" ? this._gedcom.obje(objeOrKey) : objeOrKey;
|
|
6204
|
+
if (!obje?.id) {
|
|
6205
|
+
return void 0;
|
|
6206
|
+
}
|
|
6207
|
+
const already = this.get("OBJE")?.toList()?.values()?.some((item) => item?.toValue?.() === obje.id);
|
|
6208
|
+
if (!already) {
|
|
6209
|
+
const pointer = makePointer(
|
|
6210
|
+
this._gedcom,
|
|
6211
|
+
this,
|
|
6212
|
+
obje.id,
|
|
6213
|
+
"OBJE"
|
|
6214
|
+
);
|
|
6215
|
+
this.assign("OBJE", pointer);
|
|
6216
|
+
}
|
|
6217
|
+
if (options?.primary) {
|
|
6218
|
+
this.get("OBJE")?.toList()?.forEach((item) => {
|
|
6219
|
+
const target = item?.refType === "OBJE" ? this._gedcom?.obje(
|
|
6220
|
+
String(item.toValue())
|
|
6221
|
+
) : item;
|
|
6222
|
+
if (!target) {
|
|
6223
|
+
return;
|
|
6224
|
+
}
|
|
6225
|
+
if (target.id === obje.id) {
|
|
6226
|
+
target.set("_PRIM", "Y");
|
|
6227
|
+
} else if (target.get("_PRIM")?.toValue() === "Y") {
|
|
6228
|
+
target.set("_PRIM", "N");
|
|
6229
|
+
}
|
|
6230
|
+
});
|
|
6231
|
+
obje.set("_PRIM", "Y");
|
|
6232
|
+
}
|
|
6233
|
+
return obje;
|
|
6234
|
+
}
|
|
6235
|
+
detachMultimedia(objeKey) {
|
|
6236
|
+
const list = this.get("OBJE")?.toList();
|
|
6237
|
+
if (!list) {
|
|
6238
|
+
return;
|
|
6239
|
+
}
|
|
6240
|
+
const toRemove = list.values().filter(
|
|
6241
|
+
(item) => item?.toValue?.() === objeKey || item?.id === objeKey
|
|
6242
|
+
);
|
|
6243
|
+
toRemove.forEach((item) => {
|
|
6244
|
+
if (item) {
|
|
6245
|
+
list.delete(item);
|
|
6246
|
+
}
|
|
6247
|
+
});
|
|
6248
|
+
if (list.length === 0) {
|
|
6249
|
+
this.remove("OBJE");
|
|
6250
|
+
}
|
|
6251
|
+
}
|
|
6252
|
+
/**
|
|
6253
|
+
* Create a multimedia record and attach it to this person.
|
|
6254
|
+
*/
|
|
6255
|
+
attachMediaFromUrl(url, options) {
|
|
6256
|
+
if (!this._gedcom || !url) {
|
|
6257
|
+
return void 0;
|
|
6258
|
+
}
|
|
6259
|
+
const obje = this._gedcom.createMultimediaRecord({
|
|
6260
|
+
file: url,
|
|
6261
|
+
form: options?.form,
|
|
6262
|
+
title: options?.title,
|
|
6263
|
+
mediType: options?.mediType,
|
|
6264
|
+
primary: options?.primary,
|
|
6265
|
+
gedcomVersion: options?.gedcomVersion
|
|
6266
|
+
});
|
|
6267
|
+
return this.attachMultimedia(obje, { primary: options?.primary });
|
|
6268
|
+
}
|
|
6269
|
+
/**
|
|
6270
|
+
* Link a shared SNOTE record via `1 NOTE @Nn@` (GEDCOM 7).
|
|
6271
|
+
*/
|
|
6272
|
+
attachSharedNote(noteOrKey) {
|
|
6273
|
+
if (!this._gedcom || !this.id) {
|
|
6274
|
+
return void 0;
|
|
6275
|
+
}
|
|
6276
|
+
const note = typeof noteOrKey === "string" ? this._gedcom.snote(noteOrKey) : noteOrKey;
|
|
6277
|
+
if (!note?.id) {
|
|
6278
|
+
return void 0;
|
|
6279
|
+
}
|
|
6280
|
+
const already = this.get("NOTE")?.toList()?.values()?.some((item) => item?.toValue?.() === note.id);
|
|
6281
|
+
if (!already) {
|
|
6282
|
+
const pointer = makePointer(
|
|
6283
|
+
this._gedcom,
|
|
6284
|
+
this,
|
|
6285
|
+
note.id,
|
|
6286
|
+
"SNOTE"
|
|
6287
|
+
);
|
|
6288
|
+
this.assign("NOTE", pointer);
|
|
6289
|
+
}
|
|
6290
|
+
return note;
|
|
6291
|
+
}
|
|
6292
|
+
addFact(input) {
|
|
6293
|
+
return addIndividualFact(this, input);
|
|
6294
|
+
}
|
|
6295
|
+
addNonEvent(input) {
|
|
6296
|
+
return addNonEvent(this, input);
|
|
6297
|
+
}
|
|
5664
6298
|
getParentType(id) {
|
|
5665
6299
|
let indi;
|
|
5666
6300
|
if (typeof id === "string" || typeof id === "number") {
|
|
@@ -5701,7 +6335,7 @@ var Indi = class extends Common {
|
|
|
5701
6335
|
if (!famChild) {
|
|
5702
6336
|
const childIndi = this._gedcom?.indi(child.id);
|
|
5703
6337
|
const childState = childIndi?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
|
|
5704
|
-
childType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
|
|
6338
|
+
childType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
|
|
5705
6339
|
} else {
|
|
5706
6340
|
childType = famChild.get(usedRel)?.toValue() || "biological" /* BIOLOGICAL */;
|
|
5707
6341
|
}
|
|
@@ -5861,7 +6495,9 @@ var Indi = class extends Common {
|
|
|
5861
6495
|
}
|
|
5862
6496
|
}
|
|
5863
6497
|
if (kinship !== "child" || !breakAfterSpouse) {
|
|
5864
|
-
indi.getBiologicalFathers().copy().merge(indi.getBiologicalMothers()).merge(
|
|
6498
|
+
indi.getBiologicalFathers().copy().merge(indi.getBiologicalMothers()).merge(
|
|
6499
|
+
indi.getFathers().copy().merge(indi.getMothers())
|
|
6500
|
+
).forEach((relative) => {
|
|
5865
6501
|
if (!visited.has(relative)) {
|
|
5866
6502
|
const currentRelation = indi.getParentType(relative);
|
|
5867
6503
|
const isNonBiological = !!currentRelation && currentRelation !== "biological" /* BIOLOGICAL */;
|
|
@@ -6260,7 +6896,7 @@ var Indi = class extends Common {
|
|
|
6260
6896
|
return;
|
|
6261
6897
|
}
|
|
6262
6898
|
const childState = child?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
|
|
6263
|
-
const childType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
|
|
6899
|
+
const childType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
|
|
6264
6900
|
if (childType?.toLowerCase() === filter.PEDI.toLowerCase()) {
|
|
6265
6901
|
children.append(child);
|
|
6266
6902
|
}
|
|
@@ -6368,7 +7004,7 @@ var Indi = class extends Common {
|
|
|
6368
7004
|
const child = this.id && family.CHIL?.toValueList()?.item(this.id);
|
|
6369
7005
|
if (!child) {
|
|
6370
7006
|
const childState = this?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
|
|
6371
|
-
const parentType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
|
|
7007
|
+
const parentType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
|
|
6372
7008
|
if (parentType?.toLowerCase() === filter.PEDI.toLowerCase()) {
|
|
6373
7009
|
parents.merge(family.getParents());
|
|
6374
7010
|
}
|
|
@@ -6760,13 +7396,760 @@ var createIndi = (gedcom, id, main, parent) => {
|
|
|
6760
7396
|
);
|
|
6761
7397
|
};
|
|
6762
7398
|
|
|
7399
|
+
// src/utils/gedcom-version.ts
|
|
7400
|
+
var normalizeGedcomVersion = (value) => {
|
|
7401
|
+
const trimmed = value?.trim() ?? "";
|
|
7402
|
+
if (trimmed.startsWith("7")) {
|
|
7403
|
+
return "7.0";
|
|
7404
|
+
}
|
|
7405
|
+
return "5.5.1";
|
|
7406
|
+
};
|
|
7407
|
+
var GEDZIP_GEDCOM_ENTRY = "gedcom.ged";
|
|
7408
|
+
var sanitizePathSegment = (name) => name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^\.+/, "") || "file";
|
|
7409
|
+
var extensionFor = (contentType) => {
|
|
7410
|
+
const raw = (contentType || "bin").replace(/^\./, "").toLowerCase();
|
|
7411
|
+
if (raw.includes("/")) {
|
|
7412
|
+
return raw.split("/").pop() || "bin";
|
|
7413
|
+
}
|
|
7414
|
+
return raw || "bin";
|
|
7415
|
+
};
|
|
7416
|
+
var rewriteGedcomFilePaths = (gedcomText, urlToPath) => {
|
|
7417
|
+
const entries = urlToPath instanceof Map ? urlToPath : new Map(Object.entries(urlToPath));
|
|
7418
|
+
let text = gedcomText;
|
|
7419
|
+
entries.forEach((path, url) => {
|
|
7420
|
+
const escaped = url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7421
|
+
text = text.replace(
|
|
7422
|
+
new RegExp(`(^|\\r?\\n)(\\d+ FILE )${escaped}`, "g"),
|
|
7423
|
+
`$1$2${path}`
|
|
7424
|
+
);
|
|
7425
|
+
});
|
|
7426
|
+
return text;
|
|
7427
|
+
};
|
|
7428
|
+
var assignMediaPaths = (mediaFiles) => {
|
|
7429
|
+
const urlToPath = /* @__PURE__ */ new Map();
|
|
7430
|
+
const usedPaths = /* @__PURE__ */ new Set([GEDZIP_GEDCOM_ENTRY]);
|
|
7431
|
+
const files = [];
|
|
7432
|
+
for (const file of mediaFiles) {
|
|
7433
|
+
if (!file.content || !file.url) {
|
|
7434
|
+
continue;
|
|
7435
|
+
}
|
|
7436
|
+
const ext = extensionFor(file.contentType);
|
|
7437
|
+
const base = sanitizePathSegment(
|
|
7438
|
+
file.imgId || file.title || file.id || "media"
|
|
7439
|
+
);
|
|
7440
|
+
let path = `media/${base}.${ext}`;
|
|
7441
|
+
let suffix = 1;
|
|
7442
|
+
while (usedPaths.has(path)) {
|
|
7443
|
+
path = `media/${base}-${suffix++}.${ext}`;
|
|
7444
|
+
}
|
|
7445
|
+
usedPaths.add(path);
|
|
7446
|
+
urlToPath.set(file.url, path);
|
|
7447
|
+
const marker = "base64,";
|
|
7448
|
+
const idx = file.content.indexOf(marker);
|
|
7449
|
+
if (idx >= 0) {
|
|
7450
|
+
files.push({
|
|
7451
|
+
path,
|
|
7452
|
+
url: file.url,
|
|
7453
|
+
content: file.content.substring(idx + marker.length),
|
|
7454
|
+
base64: true
|
|
7455
|
+
});
|
|
7456
|
+
} else {
|
|
7457
|
+
files.push({
|
|
7458
|
+
path,
|
|
7459
|
+
url: file.url,
|
|
7460
|
+
content: file.content,
|
|
7461
|
+
base64: false
|
|
7462
|
+
});
|
|
7463
|
+
}
|
|
7464
|
+
}
|
|
7465
|
+
return { urlToPath, files };
|
|
7466
|
+
};
|
|
7467
|
+
var buildGedzip = async (gedcomText, mediaFiles = []) => {
|
|
7468
|
+
const zip = new JSZip();
|
|
7469
|
+
const { urlToPath, files } = assignMediaPaths(mediaFiles);
|
|
7470
|
+
for (const file of files) {
|
|
7471
|
+
zip.file(file.path, file.content, { base64: file.base64 });
|
|
7472
|
+
}
|
|
7473
|
+
zip.file(GEDZIP_GEDCOM_ENTRY, rewriteGedcomFilePaths(gedcomText, urlToPath));
|
|
7474
|
+
return zip.generateAsync({ type: "uint8array" });
|
|
7475
|
+
};
|
|
7476
|
+
|
|
7477
|
+
// src/utils/gedcom7-enumerations.ts
|
|
7478
|
+
var GEDCOM7_SEX_VALUES = ["M", "F", "U", "X", "N"];
|
|
7479
|
+
var GEDCOM7_PEDI_VALUES = [
|
|
7480
|
+
"adopted",
|
|
7481
|
+
"birth",
|
|
7482
|
+
"foster",
|
|
7483
|
+
"sealing"
|
|
7484
|
+
];
|
|
7485
|
+
var GEDCOM7_ROLE_VALUES = [
|
|
7486
|
+
"CHIL",
|
|
7487
|
+
"CLERGY",
|
|
7488
|
+
"FATH",
|
|
7489
|
+
"FRIEND",
|
|
7490
|
+
"GODP",
|
|
7491
|
+
"HUSB",
|
|
7492
|
+
"MOTH",
|
|
7493
|
+
"MULTIPLE",
|
|
7494
|
+
"NGHBR",
|
|
7495
|
+
"OFFICIATOR",
|
|
7496
|
+
"OTHER",
|
|
7497
|
+
"PARENT",
|
|
7498
|
+
"SPOU",
|
|
7499
|
+
"WIFE",
|
|
7500
|
+
"WITN"
|
|
7501
|
+
];
|
|
7502
|
+
var GEDCOM7_RESN_VALUES = [
|
|
7503
|
+
"CONFIDENTIAL",
|
|
7504
|
+
"LOCKED",
|
|
7505
|
+
"PRIVACY"
|
|
7506
|
+
];
|
|
7507
|
+
var isAllowed = (value, allowed) => allowed.includes(value);
|
|
7508
|
+
var moveToPhrase = (node, phrase) => {
|
|
7509
|
+
const previousValue = node.value;
|
|
7510
|
+
const previousPhrase = node.get("PHRASE");
|
|
7511
|
+
const previousPhraseValue = previousPhrase?.toValue();
|
|
7512
|
+
node.removeValue();
|
|
7513
|
+
if (previousPhrase) {
|
|
7514
|
+
previousPhrase.value = phrase;
|
|
7515
|
+
} else {
|
|
7516
|
+
const phraseNode = createCommon(node.getGedcom(), void 0, node.main);
|
|
7517
|
+
phraseNode.value = phrase;
|
|
7518
|
+
node.set("PHRASE", phraseNode);
|
|
7519
|
+
}
|
|
7520
|
+
return () => {
|
|
7521
|
+
if (previousValue === void 0) {
|
|
7522
|
+
node.removeValue();
|
|
7523
|
+
} else {
|
|
7524
|
+
node.value = previousValue;
|
|
7525
|
+
}
|
|
7526
|
+
if (previousPhrase) {
|
|
7527
|
+
previousPhrase.value = previousPhraseValue;
|
|
7528
|
+
} else {
|
|
7529
|
+
node.remove("PHRASE");
|
|
7530
|
+
}
|
|
7531
|
+
};
|
|
7532
|
+
};
|
|
7533
|
+
var normalizeEnum = (node, allowed, mode, restores) => {
|
|
7534
|
+
const value = node?.toValue();
|
|
7535
|
+
if (!node || typeof value !== "string" || !value.trim()) {
|
|
7536
|
+
return;
|
|
7537
|
+
}
|
|
7538
|
+
const normalized = mode === "upper" ? value.trim().toUpperCase() : value.trim().toLowerCase();
|
|
7539
|
+
if (isAllowed(normalized, allowed)) {
|
|
7540
|
+
if (value !== normalized) {
|
|
7541
|
+
const previous = node.value;
|
|
7542
|
+
node.value = normalized;
|
|
7543
|
+
restores.push(() => {
|
|
7544
|
+
node.value = previous;
|
|
7545
|
+
});
|
|
7546
|
+
}
|
|
7547
|
+
return;
|
|
7548
|
+
}
|
|
7549
|
+
restores.push(moveToPhrase(node, value.trim()));
|
|
7550
|
+
};
|
|
7551
|
+
var applyGedcom7Enumerations = (gedcom) => {
|
|
7552
|
+
const restores = [];
|
|
7553
|
+
gedcom.indis()?.forEach((indi) => {
|
|
7554
|
+
if (!indi) return;
|
|
7555
|
+
normalizeEnum(indi.get("SEX"), GEDCOM7_SEX_VALUES, "upper", restores);
|
|
7556
|
+
normalizeEnum(indi.get("RESN"), GEDCOM7_RESN_VALUES, "upper", restores);
|
|
7557
|
+
indi.get("FAMC")?.toList()?.forEach((famc) => {
|
|
7558
|
+
normalizeEnum(
|
|
7559
|
+
famc?.get("PEDI") ?? famc?.get("PEDT"),
|
|
7560
|
+
GEDCOM7_PEDI_VALUES,
|
|
7561
|
+
"lower",
|
|
7562
|
+
restores
|
|
7563
|
+
);
|
|
7564
|
+
});
|
|
7565
|
+
indi.get("ASSO")?.toList()?.forEach((asso) => {
|
|
7566
|
+
normalizeEnum(
|
|
7567
|
+
asso?.get("ROLE"),
|
|
7568
|
+
GEDCOM7_ROLE_VALUES,
|
|
7569
|
+
"upper",
|
|
7570
|
+
restores
|
|
7571
|
+
);
|
|
7572
|
+
});
|
|
7573
|
+
});
|
|
7574
|
+
gedcom.fams()?.forEach((fam) => {
|
|
7575
|
+
if (!fam) return;
|
|
7576
|
+
normalizeEnum(fam.get("RESN"), GEDCOM7_RESN_VALUES, "upper", restores);
|
|
7577
|
+
fam.get("ASSO")?.toList()?.forEach((asso) => {
|
|
7578
|
+
normalizeEnum(
|
|
7579
|
+
asso?.get("ROLE"),
|
|
7580
|
+
GEDCOM7_ROLE_VALUES,
|
|
7581
|
+
"upper",
|
|
7582
|
+
restores
|
|
7583
|
+
);
|
|
7584
|
+
});
|
|
7585
|
+
});
|
|
7586
|
+
return () => {
|
|
7587
|
+
for (let i = restores.length - 1; i >= 0; i -= 1) {
|
|
7588
|
+
restores[i]?.();
|
|
7589
|
+
}
|
|
7590
|
+
};
|
|
7591
|
+
};
|
|
7592
|
+
|
|
7593
|
+
// src/utils/gedcom7-dates.ts
|
|
7594
|
+
var GEDCOM7_CALENDARS = [
|
|
7595
|
+
"GREGORIAN",
|
|
7596
|
+
"JULIAN",
|
|
7597
|
+
"FRENCH_R",
|
|
7598
|
+
"HEBREW"
|
|
7599
|
+
];
|
|
7600
|
+
var CALENDAR_PREFIX2 = /^(?<calendar>GREGORIAN|JULIAN|FRENCH_R|HEBREW)\b\s+/i;
|
|
7601
|
+
var parseGedcom7CalendarPrefix = (value) => {
|
|
7602
|
+
const match = value.match(CALENDAR_PREFIX2);
|
|
7603
|
+
if (!match?.groups?.calendar) {
|
|
7604
|
+
return { calendar: void 0, rest: value };
|
|
7605
|
+
}
|
|
7606
|
+
return {
|
|
7607
|
+
calendar: match.groups.calendar.toUpperCase(),
|
|
7608
|
+
rest: value.slice(match[0].length)
|
|
7609
|
+
};
|
|
7610
|
+
};
|
|
7611
|
+
var withGedcom7Calendar = (value, calendar) => {
|
|
7612
|
+
if (!calendar || calendar.toUpperCase() === "GREGORIAN") {
|
|
7613
|
+
return value;
|
|
7614
|
+
}
|
|
7615
|
+
const upper = calendar.toUpperCase();
|
|
7616
|
+
if (GEDCOM7_CALENDARS.includes(upper)) {
|
|
7617
|
+
const { rest } = parseGedcom7CalendarPrefix(value);
|
|
7618
|
+
return `${upper} ${rest}`.trim();
|
|
7619
|
+
}
|
|
7620
|
+
return value;
|
|
7621
|
+
};
|
|
7622
|
+
var applyGedcom7DatePhrases = (gedcom) => {
|
|
7623
|
+
const restores = [];
|
|
7624
|
+
const visitDate = (dateNode) => {
|
|
7625
|
+
if (!dateNode || typeof dateNode.toValue !== "function") {
|
|
7626
|
+
return;
|
|
7627
|
+
}
|
|
7628
|
+
const asDate = dateNode;
|
|
7629
|
+
const hasComponents = !!(asDate.DAY || asDate.MONTH || asDate.YEAR);
|
|
7630
|
+
const raw = dateNode.exportValue?.() ?? dateNode.toValue();
|
|
7631
|
+
if (typeof raw !== "string" || !raw.trim()) {
|
|
7632
|
+
return;
|
|
7633
|
+
}
|
|
7634
|
+
const { calendar, rest } = parseGedcom7CalendarPrefix(raw.trim());
|
|
7635
|
+
const looksStructured = hasComponents || /^(ABT|CAL|EST|BEF|AFT|FROM|TO|BET|INT)(\s|$)/i.test(rest) || /\bAND\b/i.test(rest) || /^\d{1,2}\s+[A-Z]{3}\s+\d{1,4}/i.test(rest) || /^[A-Z]{3}\s+\d{1,4}/i.test(rest) || /^\d{1,4}$/.test(rest);
|
|
7636
|
+
if (looksStructured) {
|
|
7637
|
+
if (calendar && calendar !== "GREGORIAN") {
|
|
7638
|
+
const previous = dateNode.value;
|
|
7639
|
+
const next = withGedcom7Calendar(rest, calendar);
|
|
7640
|
+
if (previous !== next) {
|
|
7641
|
+
dateNode.value = next;
|
|
7642
|
+
restores.push(() => {
|
|
7643
|
+
dateNode.value = previous;
|
|
7644
|
+
});
|
|
7645
|
+
}
|
|
7646
|
+
}
|
|
7647
|
+
return;
|
|
7648
|
+
}
|
|
7649
|
+
const previousValue = dateNode.value;
|
|
7650
|
+
const previousPhrase = dateNode.get("PHRASE");
|
|
7651
|
+
const previousPhraseValue = previousPhrase?.toValue();
|
|
7652
|
+
dateNode.removeValue();
|
|
7653
|
+
if (previousPhrase) {
|
|
7654
|
+
previousPhrase.value = raw.trim();
|
|
7655
|
+
} else {
|
|
7656
|
+
const phrase = createCommon(
|
|
7657
|
+
dateNode.getGedcom(),
|
|
7658
|
+
void 0,
|
|
7659
|
+
dateNode.main
|
|
7660
|
+
);
|
|
7661
|
+
phrase.value = raw.trim();
|
|
7662
|
+
dateNode.set("PHRASE", phrase);
|
|
7663
|
+
}
|
|
7664
|
+
restores.push(() => {
|
|
7665
|
+
if (previousValue === void 0) {
|
|
7666
|
+
dateNode.removeValue();
|
|
7667
|
+
} else {
|
|
7668
|
+
dateNode.value = previousValue;
|
|
7669
|
+
}
|
|
7670
|
+
if (previousPhrase) {
|
|
7671
|
+
previousPhrase.value = previousPhraseValue;
|
|
7672
|
+
} else {
|
|
7673
|
+
dateNode.remove("PHRASE");
|
|
7674
|
+
}
|
|
7675
|
+
});
|
|
7676
|
+
};
|
|
7677
|
+
const walk = (node) => {
|
|
7678
|
+
if (!node) return;
|
|
7679
|
+
node.get("DATE")?.toList()?.forEach((item) => visitDate(item));
|
|
7680
|
+
node.get("SDATE")?.toList()?.forEach((item) => visitDate(item));
|
|
7681
|
+
};
|
|
7682
|
+
gedcom.indis()?.forEach((indi) => {
|
|
7683
|
+
if (!indi) return;
|
|
7684
|
+
walk(indi);
|
|
7685
|
+
[
|
|
7686
|
+
"BIRT",
|
|
7687
|
+
"DEAT",
|
|
7688
|
+
"CHR",
|
|
7689
|
+
"BAPM",
|
|
7690
|
+
"BURI",
|
|
7691
|
+
"CREM",
|
|
7692
|
+
"ADOP",
|
|
7693
|
+
"EVEN",
|
|
7694
|
+
"RESI",
|
|
7695
|
+
"OCCU",
|
|
7696
|
+
"MARR"
|
|
7697
|
+
].forEach((tag) => {
|
|
7698
|
+
indi.get(tag)?.toList()?.forEach((event) => walk(event));
|
|
7699
|
+
});
|
|
7700
|
+
});
|
|
7701
|
+
gedcom.fams()?.forEach((fam) => {
|
|
7702
|
+
if (!fam) return;
|
|
7703
|
+
["MARR", "DIV", "ENGA", "ANUL", "EVEN"].forEach((tag) => {
|
|
7704
|
+
fam.get(tag)?.toList()?.forEach((event) => walk(event));
|
|
7705
|
+
});
|
|
7706
|
+
});
|
|
7707
|
+
return () => {
|
|
7708
|
+
for (let i = restores.length - 1; i >= 0; i -= 1) {
|
|
7709
|
+
restores[i]?.();
|
|
7710
|
+
}
|
|
7711
|
+
};
|
|
7712
|
+
};
|
|
7713
|
+
|
|
7714
|
+
// src/utils/uid.ts
|
|
7715
|
+
var createGedcomUid = () => {
|
|
7716
|
+
const cryptoObj = typeof globalThis !== "undefined" ? globalThis.crypto : void 0;
|
|
7717
|
+
if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
|
|
7718
|
+
return cryptoObj.randomUUID();
|
|
7719
|
+
}
|
|
7720
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => {
|
|
7721
|
+
const rand = Math.random() * 16 | 0;
|
|
7722
|
+
const value = char === "x" ? rand : rand & 3 | 8;
|
|
7723
|
+
return value.toString(16);
|
|
7724
|
+
});
|
|
7725
|
+
};
|
|
7726
|
+
|
|
7727
|
+
// src/utils/gedcom7-metadata.ts
|
|
7728
|
+
var GEDCOM_MONTHS2 = [
|
|
7729
|
+
"JAN",
|
|
7730
|
+
"FEB",
|
|
7731
|
+
"MAR",
|
|
7732
|
+
"APR",
|
|
7733
|
+
"MAY",
|
|
7734
|
+
"JUN",
|
|
7735
|
+
"JUL",
|
|
7736
|
+
"AUG",
|
|
7737
|
+
"SEP",
|
|
7738
|
+
"OCT",
|
|
7739
|
+
"NOV",
|
|
7740
|
+
"DEC"
|
|
7741
|
+
];
|
|
7742
|
+
var formatGedcom7Timestamp = (date = /* @__PURE__ */ new Date()) => {
|
|
7743
|
+
const day = String(date.getUTCDate());
|
|
7744
|
+
const month = GEDCOM_MONTHS2[date.getUTCMonth()];
|
|
7745
|
+
const year = String(date.getUTCFullYear());
|
|
7746
|
+
const hh = String(date.getUTCHours()).padStart(2, "0");
|
|
7747
|
+
const mm = String(date.getUTCMinutes()).padStart(2, "0");
|
|
7748
|
+
const ss = String(date.getUTCSeconds()).padStart(2, "0");
|
|
7749
|
+
return {
|
|
7750
|
+
date: `${day} ${month} ${year}`,
|
|
7751
|
+
time: `${hh}:${mm}:${ss}Z`
|
|
7752
|
+
};
|
|
7753
|
+
};
|
|
7754
|
+
var ensureMetaDate = (gedcom, record, tag, when, restores) => {
|
|
7755
|
+
if (record.get(tag)) {
|
|
7756
|
+
return;
|
|
7757
|
+
}
|
|
7758
|
+
const { date, time } = formatGedcom7Timestamp(when);
|
|
7759
|
+
const meta = createCommon(gedcom, void 0, record);
|
|
7760
|
+
meta.type = tag;
|
|
7761
|
+
const dateNode = createCommonDate(gedcom, void 0, record, meta);
|
|
7762
|
+
dateNode.type = "DATE";
|
|
7763
|
+
dateNode.value = date;
|
|
7764
|
+
dateNode.set("TIME", time);
|
|
7765
|
+
meta.set("DATE", dateNode);
|
|
7766
|
+
record.set(tag, meta);
|
|
7767
|
+
restores.push(() => {
|
|
7768
|
+
record.remove(tag);
|
|
7769
|
+
});
|
|
7770
|
+
};
|
|
7771
|
+
var ensureUid = (record, restores) => {
|
|
7772
|
+
const existing = record.get("UID")?.toValue();
|
|
7773
|
+
if (typeof existing === "string" && existing.trim()) {
|
|
7774
|
+
return;
|
|
7775
|
+
}
|
|
7776
|
+
const uid = createGedcomUid();
|
|
7777
|
+
record.set("UID", uid);
|
|
7778
|
+
restores.push(() => {
|
|
7779
|
+
record.remove("UID");
|
|
7780
|
+
});
|
|
7781
|
+
};
|
|
7782
|
+
var applyGedcom7RecordMetadata = (gedcom, options) => {
|
|
7783
|
+
const restores = [];
|
|
7784
|
+
const now = /* @__PURE__ */ new Date();
|
|
7785
|
+
const visit = (record) => {
|
|
7786
|
+
if (!record?.id) {
|
|
7787
|
+
return;
|
|
7788
|
+
}
|
|
7789
|
+
ensureUid(record, restores);
|
|
7790
|
+
ensureMetaDate(gedcom, record, "CREA", now, restores);
|
|
7791
|
+
ensureMetaDate(gedcom, record, "CHAN", now, restores);
|
|
7792
|
+
};
|
|
7793
|
+
gedcom.indis()?.forEach((indi) => visit(indi));
|
|
7794
|
+
gedcom.fams()?.forEach((fam) => visit(fam));
|
|
7795
|
+
gedcom.objes()?.forEach((obje) => visit(obje));
|
|
7796
|
+
gedcom.sours()?.forEach((sour) => visit(sour));
|
|
7797
|
+
gedcom.repos()?.forEach((repo) => visit(repo));
|
|
7798
|
+
gedcom.subms()?.forEach((subm) => visit(subm));
|
|
7799
|
+
gedcom.snotes()?.forEach((note) => visit(note));
|
|
7800
|
+
return () => {
|
|
7801
|
+
for (let i = restores.length - 1; i >= 0; i -= 1) {
|
|
7802
|
+
restores[i]?.();
|
|
7803
|
+
}
|
|
7804
|
+
};
|
|
7805
|
+
};
|
|
7806
|
+
|
|
7807
|
+
// src/utils/gedcom7-schema.ts
|
|
7808
|
+
var TREEVIZ_EXTENSION_BASE_URI = "https://treeviz.com/gedcom";
|
|
7809
|
+
var TREEVIZ_EXTENSION_URIS = {
|
|
7810
|
+
_ORIGHEAD: `${TREEVIZ_EXTENSION_BASE_URI}#_ORIGHEAD`,
|
|
7811
|
+
_TREE: `${TREEVIZ_EXTENSION_BASE_URI}#_TREE`,
|
|
7812
|
+
_TID: `${TREEVIZ_EXTENSION_BASE_URI}#_TID`,
|
|
7813
|
+
_PRIM: `${TREEVIZ_EXTENSION_BASE_URI}#_PRIM`,
|
|
7814
|
+
_FREL: `${TREEVIZ_EXTENSION_BASE_URI}#_FREL`,
|
|
7815
|
+
_MREL: `${TREEVIZ_EXTENSION_BASE_URI}#_MREL`,
|
|
7816
|
+
_SREL: `${TREEVIZ_EXTENSION_BASE_URI}#_SREL`,
|
|
7817
|
+
_UID: `${TREEVIZ_EXTENSION_BASE_URI}#_UID`,
|
|
7818
|
+
_WLNK: `${TREEVIZ_EXTENSION_BASE_URI}#_WLNK`,
|
|
7819
|
+
_MTTAG: `${TREEVIZ_EXTENSION_BASE_URI}#_MTTAG`,
|
|
7820
|
+
_MTCAT: `${TREEVIZ_EXTENSION_BASE_URI}#_MTCAT`,
|
|
7821
|
+
_CLON: `${TREEVIZ_EXTENSION_BASE_URI}#_CLON`,
|
|
7822
|
+
_MSER: `${TREEVIZ_EXTENSION_BASE_URI}#_MSER`,
|
|
7823
|
+
_OID: `${TREEVIZ_EXTENSION_BASE_URI}#_OID`,
|
|
7824
|
+
_LKID: `${TREEVIZ_EXTENSION_BASE_URI}#_LKID`,
|
|
7825
|
+
_PHOTO_RIN: `${TREEVIZ_EXTENSION_BASE_URI}#_PHOTO_RIN`,
|
|
7826
|
+
_EXPORTED_FROM_SITE_ID: `${TREEVIZ_EXTENSION_BASE_URI}#_EXPORTED_FROM_SITE_ID`,
|
|
7827
|
+
_FS_ID: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_ID`,
|
|
7828
|
+
_FS_LINK: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_LINK`,
|
|
7829
|
+
_FS_MATCH: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_MATCH`,
|
|
7830
|
+
_FS_SOUR: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_SOUR`,
|
|
7831
|
+
_IS_FS: `${TREEVIZ_EXTENSION_BASE_URI}#_IS_FS`,
|
|
7832
|
+
_LABEL: `${TREEVIZ_EXTENSION_BASE_URI}#_LABEL`,
|
|
7833
|
+
_MILT: `${TREEVIZ_EXTENSION_BASE_URI}#_MILT`,
|
|
7834
|
+
_MILTID: `${TREEVIZ_EXTENSION_BASE_URI}#_MILTID`,
|
|
7835
|
+
_ORIG: `${TREEVIZ_EXTENSION_BASE_URI}#_ORIG`,
|
|
7836
|
+
_ENV: `${TREEVIZ_EXTENSION_BASE_URI}#_ENV`,
|
|
7837
|
+
_TREEVIZ_SETTINGS: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_SETTINGS`,
|
|
7838
|
+
_TREEVIZ_VIEW: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_VIEW`,
|
|
7839
|
+
_TREEVIZ_DETECTIVE: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_DETECTIVE`,
|
|
7840
|
+
_TREEVIZ_DETECTIVE_STATE: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_DETECTIVE_STATE`
|
|
7841
|
+
};
|
|
7842
|
+
var parseTagDefinition = (payload) => {
|
|
7843
|
+
const trimmed = payload.trim();
|
|
7844
|
+
const space = trimmed.indexOf(" ");
|
|
7845
|
+
if (space <= 0) {
|
|
7846
|
+
return void 0;
|
|
7847
|
+
}
|
|
7848
|
+
const tag = trimmed.slice(0, space).trim();
|
|
7849
|
+
const uri = trimmed.slice(space + 1).trim();
|
|
7850
|
+
if (!tag || !uri) {
|
|
7851
|
+
return void 0;
|
|
7852
|
+
}
|
|
7853
|
+
return { tag, uri };
|
|
7854
|
+
};
|
|
7855
|
+
var getExtensionSchema = (gedcom) => {
|
|
7856
|
+
const map = /* @__PURE__ */ new Map();
|
|
7857
|
+
const schma = gedcom.get("HEAD")?.get("SCHMA");
|
|
7858
|
+
if (!schma) {
|
|
7859
|
+
return map;
|
|
7860
|
+
}
|
|
7861
|
+
schma.get("TAG")?.toList()?.forEach((tagNode) => {
|
|
7862
|
+
const payload = tagNode?.toValue();
|
|
7863
|
+
if (typeof payload !== "string") {
|
|
7864
|
+
return;
|
|
7865
|
+
}
|
|
7866
|
+
const parsed = parseTagDefinition(payload);
|
|
7867
|
+
if (parsed) {
|
|
7868
|
+
map.set(parsed.tag.toUpperCase(), parsed.uri);
|
|
7869
|
+
}
|
|
7870
|
+
});
|
|
7871
|
+
return map;
|
|
7872
|
+
};
|
|
7873
|
+
var ensureSchemaNode = (gedcom) => {
|
|
7874
|
+
const head = gedcom.get("HEAD");
|
|
7875
|
+
if (!head) {
|
|
7876
|
+
return void 0;
|
|
7877
|
+
}
|
|
7878
|
+
let schma = head.get("SCHMA");
|
|
7879
|
+
if (!schma) {
|
|
7880
|
+
schma = createCommon(gedcom, void 0, head);
|
|
7881
|
+
head.set("SCHMA", schma);
|
|
7882
|
+
}
|
|
7883
|
+
return schma;
|
|
7884
|
+
};
|
|
7885
|
+
var registerExtensionTag = (gedcom, tag, uri) => {
|
|
7886
|
+
const normalizedTag = tag.trim().toUpperCase();
|
|
7887
|
+
const normalizedUri = uri.trim();
|
|
7888
|
+
if (!normalizedTag.startsWith("_") || !normalizedUri) {
|
|
7889
|
+
return void 0;
|
|
7890
|
+
}
|
|
7891
|
+
const schma = ensureSchemaNode(gedcom);
|
|
7892
|
+
if (!schma) {
|
|
7893
|
+
return void 0;
|
|
7894
|
+
}
|
|
7895
|
+
const payload = `${normalizedTag} ${normalizedUri}`;
|
|
7896
|
+
const existingList = schma.get("TAG")?.toList();
|
|
7897
|
+
const existing = existingList?.values().find((node) => {
|
|
7898
|
+
const value = node?.toValue();
|
|
7899
|
+
return typeof value === "string" && value.trim().toUpperCase().startsWith(`${normalizedTag} `);
|
|
7900
|
+
});
|
|
7901
|
+
if (existing) {
|
|
7902
|
+
existing.value = payload;
|
|
7903
|
+
return existing;
|
|
7904
|
+
}
|
|
7905
|
+
const tagNode = createCommon(gedcom, void 0, schma);
|
|
7906
|
+
tagNode.value = payload;
|
|
7907
|
+
schma.assign("TAG", tagNode);
|
|
7908
|
+
return tagNode;
|
|
7909
|
+
};
|
|
7910
|
+
var ensureExtensionSchema = (gedcom, extraTags) => {
|
|
7911
|
+
const head = gedcom.get("HEAD");
|
|
7912
|
+
const hadSchma = !!head?.get("SCHMA");
|
|
7913
|
+
const previousPayloads = head?.get("SCHMA")?.get("TAG")?.toList()?.values().map((node) => ({
|
|
7914
|
+
node,
|
|
7915
|
+
value: node?.toValue()
|
|
7916
|
+
})) ?? [];
|
|
7917
|
+
const tags = /* @__PURE__ */ new Set([
|
|
7918
|
+
...Object.keys(TREEVIZ_EXTENSION_URIS),
|
|
7919
|
+
...(extraTags ?? []).map((tag) => tag.toUpperCase())
|
|
7920
|
+
]);
|
|
7921
|
+
tags.forEach((tag) => {
|
|
7922
|
+
const uri = TREEVIZ_EXTENSION_URIS[tag] ?? `${TREEVIZ_EXTENSION_BASE_URI}#${tag}`;
|
|
7923
|
+
if (tag.startsWith("_")) {
|
|
7924
|
+
registerExtensionTag(gedcom, tag, uri);
|
|
7925
|
+
}
|
|
7926
|
+
});
|
|
7927
|
+
return () => {
|
|
7928
|
+
if (!head) {
|
|
7929
|
+
return;
|
|
7930
|
+
}
|
|
7931
|
+
if (!hadSchma) {
|
|
7932
|
+
head.remove("SCHMA");
|
|
7933
|
+
return;
|
|
7934
|
+
}
|
|
7935
|
+
const schma = head.get("SCHMA");
|
|
7936
|
+
const list = schma?.get("TAG")?.toList();
|
|
7937
|
+
const keep = new Set(
|
|
7938
|
+
previousPayloads.map(
|
|
7939
|
+
(item) => typeof item.value === "string" ? item.value : void 0
|
|
7940
|
+
).filter((value) => !!value)
|
|
7941
|
+
);
|
|
7942
|
+
list?.values().forEach((node) => {
|
|
7943
|
+
const value = node?.toValue();
|
|
7944
|
+
if (typeof value === "string" && !keep.has(value) && node) {
|
|
7945
|
+
list.delete(node);
|
|
7946
|
+
}
|
|
7947
|
+
});
|
|
7948
|
+
previousPayloads.forEach(({ node, value }) => {
|
|
7949
|
+
if (node && value !== void 0) {
|
|
7950
|
+
node.value = value;
|
|
7951
|
+
}
|
|
7952
|
+
});
|
|
7953
|
+
};
|
|
7954
|
+
};
|
|
7955
|
+
|
|
6763
7956
|
// package.json
|
|
6764
7957
|
var package_default = {
|
|
6765
|
-
version: "2.0
|
|
7958
|
+
version: "2.1.0"};
|
|
6766
7959
|
|
|
6767
7960
|
// src/utils/get-product-details.ts
|
|
6768
7961
|
var getVersion = () => package_default.version;
|
|
6769
7962
|
|
|
7963
|
+
// src/utils/multimedia.ts
|
|
7964
|
+
var inferMediaForm = (file, fallback = "bin") => {
|
|
7965
|
+
const withoutQuery = file.split("?")[0] || file;
|
|
7966
|
+
const ext = getFileExtension(withoutQuery);
|
|
7967
|
+
if (ext) {
|
|
7968
|
+
return ext.toLowerCase() === "jpeg" ? "jpg" : ext.toLowerCase();
|
|
7969
|
+
}
|
|
7970
|
+
return fallback;
|
|
7971
|
+
};
|
|
7972
|
+
var mergeMediaLists = (...lists) => {
|
|
7973
|
+
const merged = {};
|
|
7974
|
+
for (const list of lists) {
|
|
7975
|
+
if (!list) continue;
|
|
7976
|
+
Object.assign(merged, list);
|
|
7977
|
+
}
|
|
7978
|
+
return merged;
|
|
7979
|
+
};
|
|
7980
|
+
|
|
7981
|
+
// src/classes/note.ts
|
|
7982
|
+
var CommonNote = class extends Common {
|
|
7983
|
+
constructor(gedcom, id, main, parent) {
|
|
7984
|
+
super(gedcom, id, main, parent);
|
|
7985
|
+
if (!id) {
|
|
7986
|
+
delete this.id;
|
|
7987
|
+
}
|
|
7988
|
+
}
|
|
7989
|
+
set value(value) {
|
|
7990
|
+
const [note, ...contents] = value?.split(/\r?\n/) ?? [];
|
|
7991
|
+
this._value = note;
|
|
7992
|
+
if (contents.length) {
|
|
7993
|
+
const newContents = new List();
|
|
7994
|
+
contents.forEach((c, i) => {
|
|
7995
|
+
const newContent = createCommon(
|
|
7996
|
+
this._gedcom,
|
|
7997
|
+
void 0,
|
|
7998
|
+
this.main
|
|
7999
|
+
);
|
|
8000
|
+
newContent.id = `@U${i}@`;
|
|
8001
|
+
newContent.value = c;
|
|
8002
|
+
newContents.append(newContent);
|
|
8003
|
+
});
|
|
8004
|
+
const firstItem = newContents.index(0);
|
|
8005
|
+
if (firstItem) {
|
|
8006
|
+
if (newContents.length === 1) {
|
|
8007
|
+
this.set("CONT", firstItem);
|
|
8008
|
+
} else {
|
|
8009
|
+
this.set("CONT", newContents);
|
|
8010
|
+
}
|
|
8011
|
+
}
|
|
8012
|
+
}
|
|
8013
|
+
}
|
|
8014
|
+
get value() {
|
|
8015
|
+
const contents = this.get("CONT")?.toList().map((content) => content.value).join("\n");
|
|
8016
|
+
if (contents) {
|
|
8017
|
+
return `${this._value}
|
|
8018
|
+
${contents}`;
|
|
8019
|
+
}
|
|
8020
|
+
return this._value;
|
|
8021
|
+
}
|
|
8022
|
+
exportValue() {
|
|
8023
|
+
return this._value;
|
|
8024
|
+
}
|
|
8025
|
+
};
|
|
8026
|
+
var createCommonNote = (gedcom, id, main, parent) => {
|
|
8027
|
+
return createProxy(
|
|
8028
|
+
new CommonNote(gedcom, id, main, parent)
|
|
8029
|
+
);
|
|
8030
|
+
};
|
|
8031
|
+
|
|
8032
|
+
// src/classes/obje.ts
|
|
8033
|
+
var Obje = class extends Common {
|
|
8034
|
+
standardizeMedia(namespace, override = true, urlGetter, gedcomVersion) {
|
|
8035
|
+
if (!this._gedcom) {
|
|
8036
|
+
return this;
|
|
8037
|
+
}
|
|
8038
|
+
const rin = this?.get("RIN")?.toValue();
|
|
8039
|
+
const clone = this?.get("_CLON._OID")?.toValue();
|
|
8040
|
+
const mser = this?.get("_MSER._LKID")?.toValue();
|
|
8041
|
+
const title = this?.get("FILE.TITL")?.toValue() ?? this?.get("TITL")?.toValue() ?? "";
|
|
8042
|
+
const note = this?.get("FILE.NOTE")?.toValue() ?? this?.get("NOTE")?.toValue() ?? "";
|
|
8043
|
+
const formRaw = this?.get("FILE.FORM")?.toValue() ?? this?.get("FORM")?.toValue();
|
|
8044
|
+
const mediType = this?.get("FILE.FORM.TYPE")?.toValue() ?? this?.get("FORM.TYPE")?.toValue() ?? this?.get("MEDI")?.toValue();
|
|
8045
|
+
const file = this?.get("FILE")?.toValue();
|
|
8046
|
+
const imgId = rin || clone || mser;
|
|
8047
|
+
const url = file || namespace && urlGetter?.(namespace, imgId);
|
|
8048
|
+
if (!url) {
|
|
8049
|
+
return this;
|
|
8050
|
+
}
|
|
8051
|
+
const version = normalizeGedcomVersion(
|
|
8052
|
+
gedcomVersion ?? this._gedcom.getGedcomVersion?.()
|
|
8053
|
+
);
|
|
8054
|
+
const form = formRaw || inferMediaForm(String(url));
|
|
8055
|
+
const newObject = createObje(this._gedcom, this.id, this.main);
|
|
8056
|
+
if (!override) {
|
|
8057
|
+
Object.assign(newObject, this);
|
|
8058
|
+
}
|
|
8059
|
+
const fileNode = createCommon(this._gedcom, void 0, this.main);
|
|
8060
|
+
fileNode.value = url;
|
|
8061
|
+
if (version === "7.0") {
|
|
8062
|
+
const formNode = createCommon(this._gedcom, void 0, fileNode);
|
|
8063
|
+
formNode.value = form;
|
|
8064
|
+
if (mediType) {
|
|
8065
|
+
formNode.set("TYPE", String(mediType));
|
|
8066
|
+
}
|
|
8067
|
+
fileNode.set("FORM", formNode);
|
|
8068
|
+
if (title) {
|
|
8069
|
+
fileNode.set("TITL", String(title));
|
|
8070
|
+
}
|
|
8071
|
+
if (note) {
|
|
8072
|
+
fileNode.set("NOTE", String(note));
|
|
8073
|
+
}
|
|
8074
|
+
newObject.set("FILE", fileNode);
|
|
8075
|
+
} else {
|
|
8076
|
+
newObject.set("FILE", fileNode);
|
|
8077
|
+
newObject.set("FORM", form);
|
|
8078
|
+
if (mediType) {
|
|
8079
|
+
newObject.set("MEDI", String(mediType));
|
|
8080
|
+
}
|
|
8081
|
+
if (title) {
|
|
8082
|
+
newObject.set("TITL", String(title));
|
|
8083
|
+
if (!note) {
|
|
8084
|
+
newObject.set("NOTE", String(title));
|
|
8085
|
+
}
|
|
8086
|
+
}
|
|
8087
|
+
if (note) {
|
|
8088
|
+
newObject.set("NOTE", String(note));
|
|
8089
|
+
if (!title) {
|
|
8090
|
+
newObject.set("TITL", String(note));
|
|
8091
|
+
}
|
|
8092
|
+
}
|
|
8093
|
+
}
|
|
8094
|
+
const prim = this.get("_PRIM")?.toValue();
|
|
8095
|
+
if (prim === "Y" || prim === "N") {
|
|
8096
|
+
newObject.set("_PRIM", prim);
|
|
8097
|
+
}
|
|
8098
|
+
const photoRin = this.get("_PHOTO_RIN")?.toValue();
|
|
8099
|
+
if (rin) {
|
|
8100
|
+
newObject.set("RIN", String(rin));
|
|
8101
|
+
}
|
|
8102
|
+
if (photoRin) {
|
|
8103
|
+
newObject.set("_PHOTO_RIN", String(photoRin));
|
|
8104
|
+
}
|
|
8105
|
+
const clonNode = this.get("_CLON");
|
|
8106
|
+
if (clonNode) {
|
|
8107
|
+
newObject.set("_CLON", clonNode);
|
|
8108
|
+
}
|
|
8109
|
+
const mserNode = this.get("_MSER");
|
|
8110
|
+
if (mserNode) {
|
|
8111
|
+
newObject.set("_MSER", mserNode);
|
|
8112
|
+
}
|
|
8113
|
+
const oidNode = this.get("_OID");
|
|
8114
|
+
if (oidNode && !newObject.get("_OID")) {
|
|
8115
|
+
newObject.set("_OID", oidNode);
|
|
8116
|
+
}
|
|
8117
|
+
const lkidNode = this.get("_LKID");
|
|
8118
|
+
if (lkidNode && !newObject.get("_LKID")) {
|
|
8119
|
+
newObject.set("_LKID", lkidNode);
|
|
8120
|
+
}
|
|
8121
|
+
if (override) {
|
|
8122
|
+
this.remove("FILE");
|
|
8123
|
+
this.remove("FORM");
|
|
8124
|
+
this.remove("MEDI");
|
|
8125
|
+
this.remove("TITL");
|
|
8126
|
+
this.remove("NOTE");
|
|
8127
|
+
Object.assign(this, newObject);
|
|
8128
|
+
return this;
|
|
8129
|
+
}
|
|
8130
|
+
return newObject;
|
|
8131
|
+
}
|
|
8132
|
+
};
|
|
8133
|
+
var createObje = (gedcom, id, main, parent) => {
|
|
8134
|
+
return createProxy(
|
|
8135
|
+
new Obje(gedcom, id, main, parent)
|
|
8136
|
+
);
|
|
8137
|
+
};
|
|
8138
|
+
|
|
8139
|
+
// src/classes/objes.ts
|
|
8140
|
+
var Objects = class _Objects extends List {
|
|
8141
|
+
copy() {
|
|
8142
|
+
const newList = new _Objects();
|
|
8143
|
+
this.entries().forEach(([key, value]) => {
|
|
8144
|
+
newList.item(key, value);
|
|
8145
|
+
});
|
|
8146
|
+
return newList;
|
|
8147
|
+
}
|
|
8148
|
+
except(item) {
|
|
8149
|
+
return this.copy().delete(item);
|
|
8150
|
+
}
|
|
8151
|
+
};
|
|
8152
|
+
|
|
6770
8153
|
// src/classes/gedcom.ts
|
|
6771
8154
|
var isObjectPatch = (value) => {
|
|
6772
8155
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -6962,6 +8345,189 @@ var GedCom = class extends Common {
|
|
|
6962
8345
|
fams() {
|
|
6963
8346
|
return this.getList("@@FAM");
|
|
6964
8347
|
}
|
|
8348
|
+
nextIndiKey() {
|
|
8349
|
+
const ids = [];
|
|
8350
|
+
this.indis()?.forEach((_indi, id) => {
|
|
8351
|
+
ids.push(String(id));
|
|
8352
|
+
});
|
|
8353
|
+
return nextRecordId(ids, "I");
|
|
8354
|
+
}
|
|
8355
|
+
nextFamKey() {
|
|
8356
|
+
const ids = [];
|
|
8357
|
+
this.fams()?.forEach((_fam, id) => {
|
|
8358
|
+
ids.push(String(id));
|
|
8359
|
+
});
|
|
8360
|
+
return nextRecordId(ids, "F");
|
|
8361
|
+
}
|
|
8362
|
+
createIndividual() {
|
|
8363
|
+
const existing = this.indis();
|
|
8364
|
+
const indis = existing ?? new Individuals();
|
|
8365
|
+
if (!existing) {
|
|
8366
|
+
this.set("@@INDI", indis);
|
|
8367
|
+
}
|
|
8368
|
+
const id = this.nextIndiKey();
|
|
8369
|
+
const indi = createIndi(this, id);
|
|
8370
|
+
indi.type = "INDI";
|
|
8371
|
+
if (this.getGedcomVersion() === "7.0") {
|
|
8372
|
+
indi.set("UID", createGedcomUid());
|
|
8373
|
+
}
|
|
8374
|
+
indis.item(id, indi);
|
|
8375
|
+
return indi;
|
|
8376
|
+
}
|
|
8377
|
+
createFamily() {
|
|
8378
|
+
const existing = this.fams();
|
|
8379
|
+
const fams = existing ?? new Families();
|
|
8380
|
+
if (!existing) {
|
|
8381
|
+
this.set("@@FAM", fams);
|
|
8382
|
+
}
|
|
8383
|
+
const id = this.nextFamKey();
|
|
8384
|
+
const fam = createFam(this, id);
|
|
8385
|
+
fam.type = "FAM";
|
|
8386
|
+
if (this.getGedcomVersion() === "7.0") {
|
|
8387
|
+
fam.set("UID", createGedcomUid());
|
|
8388
|
+
}
|
|
8389
|
+
fams.item(id, fam);
|
|
8390
|
+
return fam;
|
|
8391
|
+
}
|
|
8392
|
+
nextObjeKey() {
|
|
8393
|
+
const ids = [];
|
|
8394
|
+
this.objes()?.forEach((_obje, id) => {
|
|
8395
|
+
ids.push(String(id));
|
|
8396
|
+
});
|
|
8397
|
+
return nextRecordId(ids, "O");
|
|
8398
|
+
}
|
|
8399
|
+
/**
|
|
8400
|
+
* Create a top-level multimedia record (`0 @On@ OBJE`) with FILE/FORM/TITL.
|
|
8401
|
+
* GEDCOM 7 uses nested `FILE → FORM [→ TYPE]`; 5.5.1 uses sibling FORM/TITL.
|
|
8402
|
+
*/
|
|
8403
|
+
createMultimediaRecord(input) {
|
|
8404
|
+
const existing = this.objes();
|
|
8405
|
+
const objes = existing ?? new Objects();
|
|
8406
|
+
if (!existing) {
|
|
8407
|
+
this.set("@@OBJE", objes);
|
|
8408
|
+
}
|
|
8409
|
+
const id = this.nextObjeKey();
|
|
8410
|
+
const obje = createObje(this, id);
|
|
8411
|
+
obje.type = "OBJE";
|
|
8412
|
+
objes.item(id, obje);
|
|
8413
|
+
const version = normalizeGedcomVersion(
|
|
8414
|
+
input.gedcomVersion ?? this.getGedcomVersion()
|
|
8415
|
+
);
|
|
8416
|
+
const form = input.form || inferMediaForm(input.file);
|
|
8417
|
+
const fileNode = createCommon(this, void 0, obje);
|
|
8418
|
+
fileNode.value = input.file;
|
|
8419
|
+
if (version === "7.0") {
|
|
8420
|
+
const formNode = createCommon(
|
|
8421
|
+
this,
|
|
8422
|
+
void 0,
|
|
8423
|
+
fileNode
|
|
8424
|
+
);
|
|
8425
|
+
formNode.value = form;
|
|
8426
|
+
if (input.mediType) {
|
|
8427
|
+
formNode.set("TYPE", input.mediType);
|
|
8428
|
+
}
|
|
8429
|
+
fileNode.set("FORM", formNode);
|
|
8430
|
+
if (input.title) {
|
|
8431
|
+
fileNode.set("TITL", input.title);
|
|
8432
|
+
}
|
|
8433
|
+
obje.set("FILE", fileNode);
|
|
8434
|
+
} else {
|
|
8435
|
+
obje.set("FILE", fileNode);
|
|
8436
|
+
obje.set("FORM", form);
|
|
8437
|
+
if (input.mediType) {
|
|
8438
|
+
obje.set("MEDI", input.mediType);
|
|
8439
|
+
}
|
|
8440
|
+
if (input.title) {
|
|
8441
|
+
obje.set("TITL", input.title);
|
|
8442
|
+
}
|
|
8443
|
+
}
|
|
8444
|
+
if (input.primary) {
|
|
8445
|
+
obje.set("_PRIM", "Y");
|
|
8446
|
+
}
|
|
8447
|
+
if (normalizeGedcomVersion(
|
|
8448
|
+
input.gedcomVersion ?? this.getGedcomVersion()
|
|
8449
|
+
) === "7.0") {
|
|
8450
|
+
obje.set("UID", createGedcomUid());
|
|
8451
|
+
}
|
|
8452
|
+
return obje;
|
|
8453
|
+
}
|
|
8454
|
+
nextSnoteKey() {
|
|
8455
|
+
const ids = [];
|
|
8456
|
+
this.snotes()?.forEach((_note, id) => {
|
|
8457
|
+
ids.push(String(id));
|
|
8458
|
+
});
|
|
8459
|
+
return nextRecordId(ids, "N");
|
|
8460
|
+
}
|
|
8461
|
+
snotes() {
|
|
8462
|
+
return this.getList("@@SNOTE");
|
|
8463
|
+
}
|
|
8464
|
+
snote(index) {
|
|
8465
|
+
return this.getMain(this.snotes(), index);
|
|
8466
|
+
}
|
|
8467
|
+
/**
|
|
8468
|
+
* Create a top-level shared note record (`0 @Nn@ SNOTE` for GEDCOM 7).
|
|
8469
|
+
*/
|
|
8470
|
+
createSharedNote(text) {
|
|
8471
|
+
const existing = this.snotes();
|
|
8472
|
+
const notes = existing ?? new List();
|
|
8473
|
+
if (!existing) {
|
|
8474
|
+
this.set("@@SNOTE", notes);
|
|
8475
|
+
}
|
|
8476
|
+
const id = this.nextSnoteKey();
|
|
8477
|
+
const note = createCommonNote(this, id);
|
|
8478
|
+
note.type = "SNOTE";
|
|
8479
|
+
note.value = text;
|
|
8480
|
+
if (this.getGedcomVersion() === "7.0") {
|
|
8481
|
+
note.set("UID", createGedcomUid());
|
|
8482
|
+
}
|
|
8483
|
+
notes.item(id, note);
|
|
8484
|
+
return note;
|
|
8485
|
+
}
|
|
8486
|
+
registerExtensionTag(tag, uri) {
|
|
8487
|
+
return registerExtensionTag(this, tag, uri);
|
|
8488
|
+
}
|
|
8489
|
+
getExtensionSchema() {
|
|
8490
|
+
return getExtensionSchema(this);
|
|
8491
|
+
}
|
|
8492
|
+
ensureExtensionSchema(extraTags) {
|
|
8493
|
+
ensureExtensionSchema(this, extraTags);
|
|
8494
|
+
return getExtensionSchema(this);
|
|
8495
|
+
}
|
|
8496
|
+
/**
|
|
8497
|
+
* Collect multimedia descriptors via each individual's `multimedia()`.
|
|
8498
|
+
*/
|
|
8499
|
+
async collectMultimedia(options) {
|
|
8500
|
+
const people = [];
|
|
8501
|
+
if (options?.indiIds?.length) {
|
|
8502
|
+
options.indiIds.forEach((id) => {
|
|
8503
|
+
const indi = this.indi(id);
|
|
8504
|
+
if (indi) {
|
|
8505
|
+
people.push(indi);
|
|
8506
|
+
}
|
|
8507
|
+
});
|
|
8508
|
+
} else {
|
|
8509
|
+
this.indis()?.forEach((indi) => {
|
|
8510
|
+
if (indi) {
|
|
8511
|
+
people.push(indi);
|
|
8512
|
+
}
|
|
8513
|
+
});
|
|
8514
|
+
}
|
|
8515
|
+
const lists = await Promise.all(
|
|
8516
|
+
people.map((indi) => indi.multimedia(options?.namespace))
|
|
8517
|
+
);
|
|
8518
|
+
return mergeMediaLists(...lists);
|
|
8519
|
+
}
|
|
8520
|
+
/**
|
|
8521
|
+
* Serialize as GEDCOM 7 and pack a FamilySearch GEDZIP (`.gdz`).
|
|
8522
|
+
* Media bytes must be supplied by the caller (cache/fetch outside the parser).
|
|
8523
|
+
*/
|
|
8524
|
+
async toGedzip(options) {
|
|
8525
|
+
const text = this.toGedcom(void 0, 0, {
|
|
8526
|
+
...options,
|
|
8527
|
+
gedcomVersion: "7.0"
|
|
8528
|
+
});
|
|
8529
|
+
return buildGedzip(text, options?.media ?? []);
|
|
8530
|
+
}
|
|
6965
8531
|
objes() {
|
|
6966
8532
|
return this.getList("@@OBJE");
|
|
6967
8533
|
}
|
|
@@ -7046,18 +8612,70 @@ var GedCom = class extends Common {
|
|
|
7046
8612
|
});
|
|
7047
8613
|
return lists;
|
|
7048
8614
|
}
|
|
7049
|
-
|
|
8615
|
+
getGedcomVersion() {
|
|
8616
|
+
const raw = this.get("HEAD")?.get("GEDC")?.get("VERS")?.toValue();
|
|
8617
|
+
return normalizeGedcomVersion(
|
|
8618
|
+
typeof raw === "string" ? raw : void 0
|
|
8619
|
+
);
|
|
8620
|
+
}
|
|
8621
|
+
/** Rewrite HEAD.GEDC (and CHAR/FORM) for the requested export version. */
|
|
8622
|
+
applyExportVersion(version) {
|
|
8623
|
+
const head = this.get("HEAD");
|
|
8624
|
+
if (!head) {
|
|
8625
|
+
return;
|
|
8626
|
+
}
|
|
8627
|
+
this.applyGedcomSpecToHead(head, normalizeGedcomVersion(version));
|
|
8628
|
+
}
|
|
8629
|
+
applyGedcomSpecToHead(head, version) {
|
|
8630
|
+
const previousGedc = head.get("GEDC");
|
|
8631
|
+
const previousForm = previousGedc?.get("FORM")?.toValue();
|
|
8632
|
+
const previousChar = head.get("CHAR")?.toValue();
|
|
8633
|
+
head.remove("GEDC");
|
|
8634
|
+
const gedc = head.set("GEDC", "");
|
|
8635
|
+
if (!gedc) {
|
|
8636
|
+
return;
|
|
8637
|
+
}
|
|
8638
|
+
gedc.set("VERS", version);
|
|
8639
|
+
if (version === "7.0") {
|
|
8640
|
+
head.remove("CHAR");
|
|
8641
|
+
return;
|
|
8642
|
+
}
|
|
8643
|
+
gedc.set(
|
|
8644
|
+
"FORM",
|
|
8645
|
+
typeof previousForm === "string" && previousForm ? previousForm : "LINEAGE-LINKED"
|
|
8646
|
+
);
|
|
8647
|
+
if (!head.get("CHAR")?.toValue()) {
|
|
8648
|
+
head.set(
|
|
8649
|
+
"CHAR",
|
|
8650
|
+
typeof previousChar === "string" && previousChar ? previousChar : "UTF-8"
|
|
8651
|
+
);
|
|
8652
|
+
}
|
|
8653
|
+
}
|
|
8654
|
+
getDownloadHeader(gedcomVersion) {
|
|
7050
8655
|
const newHead = createCommon();
|
|
7051
8656
|
Object.assign(newHead, this.get("HEAD") ?? {});
|
|
8657
|
+
this.applyGedcomSpecToHead(
|
|
8658
|
+
newHead,
|
|
8659
|
+
gedcomVersion ?? this.getGedcomVersion()
|
|
8660
|
+
);
|
|
8661
|
+
const existingSour = this.get("HEAD")?.get("SOUR");
|
|
8662
|
+
const existingTreeName = existingSour?.get("_TREE")?.toValue();
|
|
8663
|
+
const existingTreeUniqueId = existingSour?.get("_TID")?.toValue();
|
|
7052
8664
|
const newSour = createCommon();
|
|
7053
|
-
newSour.
|
|
7054
|
-
newSour.set("
|
|
7055
|
-
newSour.set("
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
8665
|
+
newSour.value = APP_BRANDING;
|
|
8666
|
+
newSour.set("NAME", APP_BRANDING);
|
|
8667
|
+
newSour.set("VERS", getVersion());
|
|
8668
|
+
if (typeof existingTreeName === "string" && existingTreeName.trim()) {
|
|
8669
|
+
newSour.set("_TREE", existingTreeName.trim());
|
|
8670
|
+
}
|
|
8671
|
+
if (typeof existingTreeUniqueId === "string" && existingTreeUniqueId.trim()) {
|
|
8672
|
+
newSour.set("_TID", existingTreeUniqueId.trim());
|
|
8673
|
+
}
|
|
8674
|
+
const corp = createCommon();
|
|
8675
|
+
corp.value = APP_BRANDING;
|
|
8676
|
+
corp.set("WWW", "treeviz.com");
|
|
8677
|
+
corp.set("EMAIL", "info@treeviz.com");
|
|
8678
|
+
newSour.set("CORP", corp);
|
|
7061
8679
|
newHead.set("SOUR", newSour);
|
|
7062
8680
|
return newHead;
|
|
7063
8681
|
}
|
|
@@ -7086,20 +8704,45 @@ var GedCom = class extends Common {
|
|
|
7086
8704
|
}
|
|
7087
8705
|
toGedcom(tag, level, options) {
|
|
7088
8706
|
if (options?.super) {
|
|
7089
|
-
return super.toGedcom(tag, level, options);
|
|
8707
|
+
return appendGedcomTrailer(super.toGedcom(tag, level, options));
|
|
7090
8708
|
}
|
|
8709
|
+
const requestedVersion = options?.gedcomVersion;
|
|
8710
|
+
const exportVersion = requestedVersion ? normalizeGedcomVersion(requestedVersion) : this.getGedcomVersion();
|
|
8711
|
+
const exportOptions = {
|
|
8712
|
+
...options,
|
|
8713
|
+
obje: {
|
|
8714
|
+
standardize: options?.obje?.standardize ?? (requestedVersion !== void 0 || !options?.original),
|
|
8715
|
+
override: options?.obje?.override,
|
|
8716
|
+
namespace: options?.obje?.namespace
|
|
8717
|
+
}
|
|
8718
|
+
};
|
|
7091
8719
|
const newGedcom = createGedCom();
|
|
7092
|
-
|
|
8720
|
+
Object.assign(newGedcom, this);
|
|
8721
|
+
if (!exportOptions.original) {
|
|
7093
8722
|
Object.assign(newGedcom, {
|
|
7094
|
-
HEAD: this.getDownloadHeader()
|
|
8723
|
+
HEAD: this.getDownloadHeader(exportVersion)
|
|
7095
8724
|
});
|
|
7096
8725
|
}
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
const newContent = this.getIndiRelatedLists(options.indis);
|
|
8726
|
+
if (exportOptions.indis?.length) {
|
|
8727
|
+
const newContent = this.getIndiRelatedLists(exportOptions.indis);
|
|
7100
8728
|
Object.assign(newGedcom, newContent);
|
|
7101
8729
|
}
|
|
7102
|
-
|
|
8730
|
+
const restoreEnums = exportVersion === "7.0" ? applyGedcom7Enumerations(newGedcom) : void 0;
|
|
8731
|
+
const restoreDates = exportVersion === "7.0" ? applyGedcom7DatePhrases(newGedcom) : void 0;
|
|
8732
|
+
const restoreMetadata = exportVersion === "7.0" ? applyGedcom7RecordMetadata(newGedcom) : void 0;
|
|
8733
|
+
const restoreSchema = exportVersion === "7.0" ? ensureExtensionSchema(newGedcom) : void 0;
|
|
8734
|
+
try {
|
|
8735
|
+
return newGedcom.toGedcom(tag, level, {
|
|
8736
|
+
...exportOptions,
|
|
8737
|
+
gedcomVersion: exportVersion,
|
|
8738
|
+
super: true
|
|
8739
|
+
});
|
|
8740
|
+
} finally {
|
|
8741
|
+
restoreSchema?.();
|
|
8742
|
+
restoreMetadata?.();
|
|
8743
|
+
restoreDates?.();
|
|
8744
|
+
restoreEnums?.();
|
|
8745
|
+
}
|
|
7103
8746
|
}
|
|
7104
8747
|
hasTag(tag) {
|
|
7105
8748
|
const tagName = typeof tag === "string" ? tag : tag?.get("NAME")?.toValue();
|
|
@@ -7578,158 +9221,6 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
|
|
|
7578
9221
|
return mergedGedcom;
|
|
7579
9222
|
};
|
|
7580
9223
|
|
|
7581
|
-
// src/classes/note.ts
|
|
7582
|
-
var CommonNote = class extends Common {
|
|
7583
|
-
constructor(gedcom, id, main, parent) {
|
|
7584
|
-
super(gedcom, id, main, parent);
|
|
7585
|
-
delete this.id;
|
|
7586
|
-
}
|
|
7587
|
-
set value(value) {
|
|
7588
|
-
const [note, ...contents] = value?.split(/\r?\n/) ?? [];
|
|
7589
|
-
this._value = note;
|
|
7590
|
-
if (contents.length) {
|
|
7591
|
-
const newContents = new List();
|
|
7592
|
-
contents.forEach((c, i) => {
|
|
7593
|
-
const newContent = createCommon(
|
|
7594
|
-
this._gedcom,
|
|
7595
|
-
void 0,
|
|
7596
|
-
this.main
|
|
7597
|
-
);
|
|
7598
|
-
newContent.id = `@U${i}@`;
|
|
7599
|
-
newContent.value = c;
|
|
7600
|
-
newContents.append(newContent);
|
|
7601
|
-
});
|
|
7602
|
-
const firstItem = newContents.index(0);
|
|
7603
|
-
if (firstItem) {
|
|
7604
|
-
if (newContents.length === 1) {
|
|
7605
|
-
this.set("CONT", firstItem);
|
|
7606
|
-
} else {
|
|
7607
|
-
this.set("CONT", newContents);
|
|
7608
|
-
}
|
|
7609
|
-
}
|
|
7610
|
-
}
|
|
7611
|
-
}
|
|
7612
|
-
get value() {
|
|
7613
|
-
const contents = this.get("CONT")?.toList().map((content) => content.value).join("\n");
|
|
7614
|
-
if (contents) {
|
|
7615
|
-
return `${this._value}
|
|
7616
|
-
${contents}`;
|
|
7617
|
-
}
|
|
7618
|
-
return this._value;
|
|
7619
|
-
}
|
|
7620
|
-
exportValue() {
|
|
7621
|
-
return this._value;
|
|
7622
|
-
}
|
|
7623
|
-
};
|
|
7624
|
-
var createCommonNote = (gedcom, id, main, parent) => {
|
|
7625
|
-
return createProxy(
|
|
7626
|
-
new CommonNote(gedcom, id, main, parent)
|
|
7627
|
-
);
|
|
7628
|
-
};
|
|
7629
|
-
|
|
7630
|
-
// src/classes/obje.ts
|
|
7631
|
-
var Obje = class extends Common {
|
|
7632
|
-
standardizeMedia(namespace, override = true, urlGetter) {
|
|
7633
|
-
if (!this._gedcom) {
|
|
7634
|
-
return this;
|
|
7635
|
-
}
|
|
7636
|
-
const rin = this?.get("RIN")?.toValue();
|
|
7637
|
-
const clone = this?.get("_CLON._OID")?.toValue();
|
|
7638
|
-
const mser = this?.get("_MSER._LKID")?.toValue();
|
|
7639
|
-
const title = this?.get("FILE.TITL")?.toValue() ?? this?.get("TITL")?.toValue() ?? "";
|
|
7640
|
-
const note = this?.get("FILE.NOTE")?.toValue() ?? this?.get("NOTE")?.toValue() ?? "";
|
|
7641
|
-
const form = this?.get("FILE.FORM")?.toValue();
|
|
7642
|
-
const file = this?.get("FILE")?.toValue();
|
|
7643
|
-
const imgId = rin || clone || mser;
|
|
7644
|
-
const url = file || namespace && urlGetter?.(namespace, imgId);
|
|
7645
|
-
if (!url) {
|
|
7646
|
-
return this;
|
|
7647
|
-
}
|
|
7648
|
-
const newObject = createObje(this._gedcom, this.id, this.main);
|
|
7649
|
-
if (!override) {
|
|
7650
|
-
Object.assign(newObject, this);
|
|
7651
|
-
}
|
|
7652
|
-
if (form) {
|
|
7653
|
-
if (typeof form === "string") {
|
|
7654
|
-
const newForm = createCommon(
|
|
7655
|
-
this._gedcom,
|
|
7656
|
-
void 0,
|
|
7657
|
-
this.main
|
|
7658
|
-
);
|
|
7659
|
-
newForm.value = form;
|
|
7660
|
-
newObject.set("FORM", newForm);
|
|
7661
|
-
} else {
|
|
7662
|
-
newObject.set("FORM", form);
|
|
7663
|
-
}
|
|
7664
|
-
}
|
|
7665
|
-
if (title) {
|
|
7666
|
-
if (typeof title === "string") {
|
|
7667
|
-
const newTitle = createCommon(
|
|
7668
|
-
this._gedcom,
|
|
7669
|
-
void 0,
|
|
7670
|
-
this.main
|
|
7671
|
-
);
|
|
7672
|
-
newTitle.value = title;
|
|
7673
|
-
newObject.set("TITL", newTitle);
|
|
7674
|
-
if (!note) {
|
|
7675
|
-
newObject.set("NOTE", newTitle);
|
|
7676
|
-
}
|
|
7677
|
-
} else {
|
|
7678
|
-
newObject.set("TITL", title);
|
|
7679
|
-
if (!note) {
|
|
7680
|
-
newObject.set("NOTE", title);
|
|
7681
|
-
}
|
|
7682
|
-
}
|
|
7683
|
-
}
|
|
7684
|
-
if (note) {
|
|
7685
|
-
if (typeof note === "string") {
|
|
7686
|
-
const newNote = createCommon(
|
|
7687
|
-
this._gedcom,
|
|
7688
|
-
void 0,
|
|
7689
|
-
this.main
|
|
7690
|
-
);
|
|
7691
|
-
newNote.value = note;
|
|
7692
|
-
newObject.set("NOTE", newNote);
|
|
7693
|
-
if (!title) {
|
|
7694
|
-
newObject.set("TITL", newNote);
|
|
7695
|
-
}
|
|
7696
|
-
} else {
|
|
7697
|
-
newObject.set("NOTE", note);
|
|
7698
|
-
if (!title) {
|
|
7699
|
-
newObject.set("TITL", note);
|
|
7700
|
-
}
|
|
7701
|
-
}
|
|
7702
|
-
}
|
|
7703
|
-
const newUrl = createCommon(this._gedcom, void 0, this.main);
|
|
7704
|
-
newUrl.value = url;
|
|
7705
|
-
newObject.set("FILE", newUrl);
|
|
7706
|
-
if (override) {
|
|
7707
|
-
Object.assign(this, newObject);
|
|
7708
|
-
return this;
|
|
7709
|
-
}
|
|
7710
|
-
return newObject;
|
|
7711
|
-
}
|
|
7712
|
-
};
|
|
7713
|
-
var createObje = (gedcom, id, main, parent) => {
|
|
7714
|
-
return createProxy(
|
|
7715
|
-
new Obje(gedcom, id, main, parent)
|
|
7716
|
-
);
|
|
7717
|
-
};
|
|
7718
|
-
|
|
7719
|
-
// src/classes/objes.ts
|
|
7720
|
-
var Objects = class _Objects extends List {
|
|
7721
|
-
copy() {
|
|
7722
|
-
const newList = new _Objects();
|
|
7723
|
-
this.entries().forEach(([key, value]) => {
|
|
7724
|
-
newList.item(key, value);
|
|
7725
|
-
});
|
|
7726
|
-
return newList;
|
|
7727
|
-
}
|
|
7728
|
-
except(item) {
|
|
7729
|
-
return this.copy().delete(item);
|
|
7730
|
-
}
|
|
7731
|
-
};
|
|
7732
|
-
|
|
7733
9224
|
// src/classes/repo.ts
|
|
7734
9225
|
var Repo = class extends Common {
|
|
7735
9226
|
};
|