@treeviz/gedcom-parser 2.0.12 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +236 -989
  2. package/dist/classes/common.d.ts +4 -4
  3. package/dist/classes/common.d.ts.map +1 -1
  4. package/dist/classes/date.d.ts +2 -0
  5. package/dist/classes/date.d.ts.map +1 -1
  6. package/dist/classes/fam.d.ts +2 -1
  7. package/dist/classes/fam.d.ts.map +1 -1
  8. package/dist/classes/fams.d.ts.map +1 -1
  9. package/dist/classes/gedcom.d.ts +39 -2
  10. package/dist/classes/gedcom.d.ts.map +1 -1
  11. package/dist/classes/index.js +1364 -318
  12. package/dist/classes/indi.d.ts +19 -2
  13. package/dist/classes/indi.d.ts.map +1 -1
  14. package/dist/classes/list.d.ts.map +1 -1
  15. package/dist/classes/note.d.ts.map +1 -1
  16. package/dist/classes/obje.d.ts +2 -1
  17. package/dist/classes/obje.d.ts.map +1 -1
  18. package/dist/cli/index.js +1368 -313
  19. package/dist/constants/constants.d.ts.map +1 -1
  20. package/dist/constants/index.js +312 -73
  21. package/dist/factories/index.js +310 -71
  22. package/dist/index.d.ts +10 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +1547 -288
  25. package/dist/interfaces/common.d.ts +6 -4
  26. package/dist/interfaces/common.d.ts.map +1 -1
  27. package/dist/interfaces/fam.d.ts +3 -0
  28. package/dist/interfaces/fam.d.ts.map +1 -1
  29. package/dist/interfaces/gedcom.d.ts +21 -1
  30. package/dist/interfaces/gedcom.d.ts.map +1 -1
  31. package/dist/interfaces/indi.d.ts +11 -1
  32. package/dist/interfaces/indi.d.ts.map +1 -1
  33. package/dist/kinship-translator/index.js +310 -71
  34. package/dist/structures/gedcom.d.ts +1 -0
  35. package/dist/structures/gedcom.d.ts.map +1 -1
  36. package/dist/types/types.d.ts +22 -4
  37. package/dist/types/types.d.ts.map +1 -1
  38. package/dist/utils/common-creator.d.ts.map +1 -1
  39. package/dist/utils/fact-edit.d.ts +12 -0
  40. package/dist/utils/fact-edit.d.ts.map +1 -1
  41. package/dist/utils/family-edit.d.ts +2 -2
  42. package/dist/utils/family-edit.d.ts.map +1 -1
  43. package/dist/utils/gedcom-version.d.ts +6 -0
  44. package/dist/utils/gedcom-version.d.ts.map +1 -0
  45. package/dist/utils/gedcom7-dates.d.ts +20 -0
  46. package/dist/utils/gedcom7-dates.d.ts.map +1 -0
  47. package/dist/utils/gedcom7-enumerations.d.ts +26 -0
  48. package/dist/utils/gedcom7-enumerations.d.ts.map +1 -0
  49. package/dist/utils/gedcom7-metadata.d.ts +19 -0
  50. package/dist/utils/gedcom7-metadata.d.ts.map +1 -0
  51. package/dist/utils/gedcom7-schema.d.ts +27 -0
  52. package/dist/utils/gedcom7-schema.d.ts.map +1 -0
  53. package/dist/utils/gedzip.d.ts +81 -0
  54. package/dist/utils/gedzip.d.ts.map +1 -0
  55. package/dist/utils/index.d.ts +9 -0
  56. package/dist/utils/index.d.ts.map +1 -1
  57. package/dist/utils/index.js +1547 -288
  58. package/dist/utils/local-media.d.ts +30 -0
  59. package/dist/utils/local-media.d.ts.map +1 -0
  60. package/dist/utils/media-utils.d.ts +10 -6
  61. package/dist/utils/media-utils.d.ts.map +1 -1
  62. package/dist/utils/multimedia.d.ts +38 -0
  63. package/dist/utils/multimedia.d.ts.map +1 -0
  64. package/dist/utils/parser.d.ts.map +1 -1
  65. package/dist/utils/uid.d.ts +6 -0
  66. package/dist/utils/uid.d.ts.map +1 -0
  67. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { debounce, set, get, uniqBy, unset, difference, intersectionBy, differenceBy } from 'lodash-es';
2
2
  import { format, isValid, parse } from 'date-fns';
3
+ import JSZip from 'jszip';
3
4
 
4
5
  var __defProp = Object.defineProperty;
5
6
  var __export = (target, all) => {
@@ -9,8 +10,8 @@ var __export = (target, all) => {
9
10
 
10
11
  // src/constants/constants.ts
11
12
  var APP_BRANDING = "TreeViz - The Family Tree Visualiser & Editor";
12
- var REF_LINE_REG = /^0 (?:(@[_a-zA-Z0-9]*@) )?(?<type>_[_A-Z][_a-zA-Z]{2,}|_?[A-Z][a-zA-Z]{2,}) ?(?<value>.*)/gm;
13
- var LINE_REG = /(?<indent>^[0-9]) (?:(@[_a-zA-Z0-9]*@) )?(?<type>_[_A-Z][_a-zA-Z]{2,}|_?[A-Z][a-zA-Z]{2,}) ?(?<value>.*)/;
13
+ var REF_LINE_REG = /^0 (?:(@[_a-zA-Z0-9]*@) )?(?<type>_[_A-Z][_a-zA-Z0-9]{2,}|_?[A-Z][A-Za-z0-9]{2,}) ?(?<value>.*)/gm;
14
+ var LINE_REG = /(?<indent>^[0-9]{1,2}) (?:(@[_a-zA-Z0-9]*@) )?(?<type>_[_A-Z][_a-zA-Z0-9]{2,}|_?[A-Z][A-Za-z0-9]{2,}) ?(?<value>.*)/;
14
15
  var ID_REG = /^@[_a-zA-Z0-9]+@/;
15
16
  var ID_GETTER_REG = /^(?<at>@)?(?<letter>[A-Z])?/i;
16
17
  var ID_SPLIT_REG = /^@[_a-zA-Z0-9]+@:/;
@@ -409,11 +410,17 @@ var List = class _List {
409
410
  const gedcom = [];
410
411
  this.entries().forEach(([_, item]) => {
411
412
  const validTag = getValidTag(tag);
412
- const validKey = item.id;
413
- const validValue = validKey ? validTag : item.exportValue();
414
- gedcom.push(
415
- `${level} ${validKey || validTag}${validValue ? ` ${validValue}` : ""}`
416
- );
413
+ const xref = item.id;
414
+ const payload = item.exportValue?.();
415
+ if (xref) {
416
+ gedcom.push(
417
+ `${level} ${xref} ${validTag}${payload ? ` ${payload}` : ""}`
418
+ );
419
+ } else {
420
+ gedcom.push(
421
+ `${level} ${validTag}${payload ? ` ${payload}` : ""}`
422
+ );
423
+ }
417
424
  gedcom.push(
418
425
  ...item.toGedcomLines(
419
426
  validTag,
@@ -671,12 +678,14 @@ var Common = class _Common {
671
678
  );
672
679
  }
673
680
  standardizeObject(tag, options) {
674
- if (tag === "OBJE" && !options?.original && options?.obje?.standardize && options?.obje?.namespace && "standardizeMedia" in this) {
681
+ if (tag === "OBJE" && options?.obje?.standardize && "standardizeMedia" in this) {
675
682
  const standardize = this.standardizeMedia;
676
683
  return standardize.call(
677
684
  this,
678
685
  options.obje.namespace,
679
- options.obje.override
686
+ options.obje.override,
687
+ void 0,
688
+ options.gedcomVersion
680
689
  );
681
690
  }
682
691
  }
@@ -703,7 +712,7 @@ var Common = class _Common {
703
712
  if (typeof prop?.toObject === "function") {
704
713
  if (prop instanceof _Common) {
705
714
  json[validKey] = prop.toObject(validKey, options);
706
- } else {
715
+ } else if (prop instanceof List) {
707
716
  json = {
708
717
  ...json,
709
718
  ...prop.toObject(validKey, options)
@@ -761,8 +770,12 @@ var Common = class _Common {
761
770
  this.standardizeObject(tag, options);
762
771
  const validKeys = getValidKeys(this);
763
772
  const gedcom = [];
773
+ const isGedcom7Export = options?.gedcomVersion === "7.0";
764
774
  validKeys.forEach((key) => {
765
775
  const validKey = key;
776
+ if (isGedcom7Export && validKey === "CONC") {
777
+ return;
778
+ }
766
779
  const prop = this.get(validKey);
767
780
  if (typeof prop?.toGedcomLines === "function") {
768
781
  if (prop instanceof _Common) {
@@ -773,7 +786,7 @@ var Common = class _Common {
773
786
  gedcom.push(
774
787
  ...prop.toGedcomLines(validKey, level + 1, options)
775
788
  );
776
- } else {
789
+ } else if (prop instanceof List) {
777
790
  gedcom.push(
778
791
  ...prop.toGedcomLines(validKey, level, options)
779
792
  );
@@ -2207,6 +2220,81 @@ var getPlaces = (common, type = ["ALL" /* All */], maxLevel = 1, level = 0, main
2207
2220
  });
2208
2221
  return places;
2209
2222
  };
2223
+
2224
+ // src/utils/local-media.ts
2225
+ var localMediaResolver;
2226
+ var mediaContentResolver;
2227
+ var setLocalMediaResolver = (resolver) => {
2228
+ localMediaResolver = resolver;
2229
+ };
2230
+ var setMediaContentResolver = (resolver) => {
2231
+ mediaContentResolver = resolver;
2232
+ };
2233
+ var isRemoteOrEmbeddedMediaUrl = (path) => {
2234
+ if (!path) {
2235
+ return false;
2236
+ }
2237
+ return path.startsWith("data:") || path.startsWith("blob:") || /^https?:\/\//i.test(path);
2238
+ };
2239
+ var resolveLocalMediaUrl = async (path) => {
2240
+ if (!path) {
2241
+ return void 0;
2242
+ }
2243
+ if (isRemoteOrEmbeddedMediaUrl(path)) {
2244
+ return path;
2245
+ }
2246
+ const resolved = await localMediaResolver?.(path);
2247
+ return resolved;
2248
+ };
2249
+ var blobToDataUrl = async (blob) => {
2250
+ const buffer = await blob.arrayBuffer();
2251
+ const bytes = new Uint8Array(buffer);
2252
+ const mime = blob.type || "application/octet-stream";
2253
+ if (typeof Buffer !== "undefined") {
2254
+ return `data:${mime};base64,${Buffer.from(bytes).toString("base64")}`;
2255
+ }
2256
+ let binary = "";
2257
+ const chunk = 32768;
2258
+ for (let i = 0; i < bytes.length; i += chunk) {
2259
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
2260
+ }
2261
+ return `data:${mime};base64,${btoa(binary)}`;
2262
+ };
2263
+ var resolveMediaContent = async (media) => {
2264
+ const fromHost = await mediaContentResolver?.(media);
2265
+ if (fromHost?.content) {
2266
+ return fromHost;
2267
+ }
2268
+ const url = media.url;
2269
+ if (!url) {
2270
+ return void 0;
2271
+ }
2272
+ if (url.startsWith("data:") || url.startsWith("blob:")) {
2273
+ return { content: url, contentType: media.contentType };
2274
+ }
2275
+ if (!isRemoteOrEmbeddedMediaUrl(url)) {
2276
+ const local = await resolveLocalMediaUrl(url);
2277
+ if (local && isRemoteOrEmbeddedMediaUrl(local)) {
2278
+ return { content: local, contentType: media.contentType };
2279
+ }
2280
+ return void 0;
2281
+ }
2282
+ if (typeof fetch !== "function") {
2283
+ return void 0;
2284
+ }
2285
+ try {
2286
+ const response = await fetch(url);
2287
+ if (!response.ok) {
2288
+ return void 0;
2289
+ }
2290
+ const blob = await response.blob();
2291
+ const content = await blobToDataUrl(blob);
2292
+ const contentType = media.contentType || blob.type.split("/").pop() || "bin";
2293
+ return { content, contentType };
2294
+ } catch {
2295
+ return void 0;
2296
+ }
2297
+ };
2210
2298
  var implemented = (type, ...args) => {
2211
2299
  };
2212
2300
  var notImplemented = (type, ...args) => {
@@ -2215,11 +2303,34 @@ var notImplemented = (type, ...args) => {
2215
2303
 
2216
2304
  // src/utils/media-utils.ts
2217
2305
  var getFileExtension = (filename) => {
2218
- const match = filename.match(/\.([^.]+)$/);
2219
- return match ? match[1] : "";
2306
+ if (!filename) {
2307
+ return "";
2308
+ }
2309
+ if (filename.startsWith("data:")) {
2310
+ const mime = filename.slice(5).split(";")[0] || "";
2311
+ const subtype = (mime.split("/")[1] || "").toLowerCase();
2312
+ if (subtype === "jpeg") {
2313
+ return "jpg";
2314
+ }
2315
+ return subtype.split("+")[0] || "";
2316
+ }
2317
+ const withoutQuery = filename.split(/[?#]/)[0] || filename;
2318
+ const match = withoutQuery.match(/\.([^.]+)$/);
2319
+ return match ? match[1].toLowerCase() : "";
2220
2320
  };
2221
2321
  var isImageFormat = (format2) => {
2222
- if (!format2) return false;
2322
+ if (!format2) {
2323
+ return false;
2324
+ }
2325
+ let normalized = format2.toLowerCase().trim();
2326
+ if (normalized.startsWith("data:")) {
2327
+ normalized = getFileExtension(normalized);
2328
+ } else if (normalized.includes("/")) {
2329
+ normalized = normalized.split("/")[1]?.split("+")[0] || "";
2330
+ if (normalized === "jpeg") {
2331
+ normalized = "jpg";
2332
+ }
2333
+ }
2223
2334
  const imageFormats = [
2224
2335
  "jpg",
2225
2336
  "jpeg",
@@ -2231,7 +2342,11 @@ var isImageFormat = (format2) => {
2231
2342
  "tiff",
2232
2343
  "tif"
2233
2344
  ];
2234
- return imageFormats.includes(format2.toLowerCase());
2345
+ return imageFormats.includes(normalized);
2346
+ };
2347
+ var resolveObjeForm = (obje) => {
2348
+ const value = obje?.get?.("FILE.FORM")?.toValue?.() ?? obje?.get?.("FORM")?.toValue?.();
2349
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2235
2350
  };
2236
2351
 
2237
2352
  // src/factories/place-parser-provider.ts
@@ -3462,10 +3577,14 @@ var Indi = class extends Common {
3462
3577
  const clone = obje?.get("_CLON._OID")?.toValue();
3463
3578
  const mser = obje?.get("_MSER._LKID")?.toValue();
3464
3579
  let url = obje?.get("FILE")?.toValue();
3465
- const title = obje?.get("TITL")?.toValue() ?? "";
3466
- const type = obje?.get("FORM")?.toValue() ?? "raw";
3467
- const imgId = clone || mser;
3468
- if (!www || !tree || !this.id) {
3580
+ const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
3581
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
3582
+ let imgId = clone || mser;
3583
+ const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
3584
+ if (!hasEmbeddedOrLocalFile && (!www || !tree || !this.id)) {
3585
+ return;
3586
+ }
3587
+ if (!this.id) {
3469
3588
  return;
3470
3589
  }
3471
3590
  if (!namespace && !url) {
@@ -3483,13 +3602,16 @@ var Indi = class extends Common {
3483
3602
  }
3484
3603
  url = url || `https://${www}/mediaui-viewer/tree/${tree}/media/${media}`;
3485
3604
  }
3605
+ if (!imgId && hasEmbeddedOrLocalFile && url) {
3606
+ imgId = typeof media === "string" && media || `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}`;
3607
+ }
3486
3608
  if (url && imgId) {
3487
- const id = `${tree}-${this.id}-${imgId}`;
3609
+ const id = `${tree || "gedzip"}-${this.id}-${imgId}`;
3488
3610
  list[id] = {
3489
3611
  key,
3490
3612
  isPrimary,
3491
3613
  id,
3492
- tree,
3614
+ tree: tree || "gedzip",
3493
3615
  imgId,
3494
3616
  person: this.id,
3495
3617
  title,
@@ -3535,9 +3657,11 @@ var Indi = class extends Common {
3535
3657
  obje.standardizeMedia();
3536
3658
  const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
3537
3659
  const url = obje?.get("FILE")?.toValue();
3538
- const title = obje?.get("NOTE")?.toValue() ?? "";
3539
- const type = obje?.get("FORM")?.toValue() ?? "raw";
3540
- const imgId = obje?.get("_PHOTO_RIN")?.toValue();
3660
+ const title = obje?.get("FILE.NOTE")?.toValue() ?? obje?.get("NOTE")?.toValue() ?? "";
3661
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
3662
+ const photoRin = obje?.get("_PHOTO_RIN")?.toValue();
3663
+ const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
3664
+ const imgId = photoRin || (hasEmbeddedOrLocalFile && url ? `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}` : void 0);
3541
3665
  if (url && imgId) {
3542
3666
  const id = `${tree}-${this.id}-${imgId}`;
3543
3667
  list[id] = {
@@ -3660,10 +3784,10 @@ var Indi = class extends Common {
3660
3784
  const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
3661
3785
  const url = obje?.get("FILE")?.toValue();
3662
3786
  const title = obje?.get("TITL")?.toValue() ?? "";
3663
- const type = obje?.get("FORM")?.toValue() ?? "raw";
3787
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
3664
3788
  if (url) {
3665
3789
  const urlMatch = url.match(/\/([^/]+)\?hash=/);
3666
- const imgId = urlMatch?.[1] || `img-${index}-${Date.now().toString(36)}`;
3790
+ const imgId = urlMatch?.[1] || (url.startsWith("data:") ? `data-${index}-${getFileExtension(url) || "bin"}` : `img-${index}-${Date.now().toString(36)}`);
3667
3791
  const id = `geni-${geniId}-${imgId}`;
3668
3792
  list[id] = {
3669
3793
  isPrimary,
@@ -3700,10 +3824,10 @@ var Indi = class extends Common {
3700
3824
  obje.standardizeMedia();
3701
3825
  const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
3702
3826
  const url = obje?.get("FILE")?.toValue();
3703
- const title = obje?.get("TITL")?.toValue() ?? "";
3704
- const type = obje?.get("FORM")?.toValue() ?? "raw";
3827
+ const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
3828
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
3705
3829
  if (url) {
3706
- const imgId = `media-${index}-${url.split("/").pop()?.split("?")[0]?.substring(0, 20) || Date.now().toString(36)}`;
3830
+ const imgId = `media-${index}-${url.startsWith("data:") ? getFileExtension(url) || "bin" : url.split("/").pop()?.split("?")[0]?.substring(0, 20) || Date.now().toString(36)}`;
3707
3831
  const id = `${treeId}-${this.id}-${imgId}`;
3708
3832
  list[id] = {
3709
3833
  isPrimary,
@@ -3743,7 +3867,20 @@ var Indi = class extends Common {
3743
3867
  cacheKey
3744
3868
  );
3745
3869
  if (cached !== void 0) {
3746
- return cached;
3870
+ if (cached?.file && !isRemoteOrEmbeddedMediaUrl(cached.file)) {
3871
+ const resolvedCached = await resolveLocalMediaUrl(cached.file);
3872
+ if (resolvedCached && isRemoteOrEmbeddedMediaUrl(resolvedCached)) {
3873
+ const refreshed = { ...cached, file: resolvedCached };
3874
+ profilePictureCache(
3875
+ this._gedcom,
3876
+ cacheKey,
3877
+ refreshed
3878
+ );
3879
+ return refreshed;
3880
+ }
3881
+ } else {
3882
+ return cached;
3883
+ }
3747
3884
  }
3748
3885
  const mediaList = await this.multimedia(namespace);
3749
3886
  if (!mediaList) {
@@ -3755,39 +3892,40 @@ var Indi = class extends Common {
3755
3892
  return void 0;
3756
3893
  }
3757
3894
  const mediaArray = Object.values(mediaList);
3758
- const primaryMedia = mediaArray.find(
3759
- (media) => media.isPrimary && isImageFormat(media.contentType || getFileExtension(media.url))
3760
- );
3761
- if (primaryMedia) {
3762
- const result = {
3763
- file: primaryMedia.url,
3764
- form: primaryMedia.contentType,
3765
- title: primaryMedia.title,
3766
- isPrimary: true
3895
+ const toDisplayableProfile = async (media, isPrimary) => {
3896
+ const resolvedFile = await resolveLocalMediaUrl(media.url);
3897
+ if (!resolvedFile || !isRemoteOrEmbeddedMediaUrl(resolvedFile)) {
3898
+ return void 0;
3899
+ }
3900
+ return {
3901
+ file: resolvedFile,
3902
+ form: media.contentType,
3903
+ title: media.title,
3904
+ isPrimary
3767
3905
  };
3768
- profilePictureCache(this._gedcom, cacheKey, result);
3769
- return result;
3770
- }
3771
- if (onlyPrimary) {
3772
- profilePictureCache(
3773
- this._gedcom,
3774
- cacheKey,
3775
- void 0
3776
- );
3777
- return void 0;
3778
- }
3779
- const secondaryMedia = mediaArray.find(
3780
- (media) => isImageFormat(media.contentType || getFileExtension(media.url))
3906
+ };
3907
+ const candidates = mediaArray.filter(
3908
+ (media) => isImageFormat(
3909
+ media.contentType || media.url || getFileExtension(media.url)
3910
+ )
3781
3911
  );
3782
- if (secondaryMedia) {
3783
- const result = {
3784
- file: secondaryMedia.url,
3785
- form: secondaryMedia.contentType,
3786
- title: secondaryMedia.title,
3787
- isPrimary: false
3788
- };
3789
- profilePictureCache(this._gedcom, cacheKey, result);
3790
- return result;
3912
+ const ordered = [
3913
+ ...candidates.filter((media) => media.isPrimary),
3914
+ ...candidates.filter((media) => !media.isPrimary)
3915
+ ];
3916
+ for (const media of ordered) {
3917
+ if (onlyPrimary && !media.isPrimary) {
3918
+ break;
3919
+ }
3920
+ const result = await toDisplayableProfile(media, !!media.isPrimary);
3921
+ if (result) {
3922
+ profilePictureCache(
3923
+ this._gedcom,
3924
+ cacheKey,
3925
+ result
3926
+ );
3927
+ return result;
3928
+ }
3791
3929
  }
3792
3930
  profilePictureCache(
3793
3931
  this._gedcom,
@@ -4073,9 +4211,108 @@ var Indi = class extends Common {
4073
4211
  addParent(parent, pedigree) {
4074
4212
  return parent.addChild(this, pedigree);
4075
4213
  }
4214
+ /**
4215
+ * Link an existing top-level OBJE record to this individual (`1 OBJE @On@`).
4216
+ */
4217
+ attachMultimedia(objeOrKey, options) {
4218
+ if (!this._gedcom || !this.id) {
4219
+ return void 0;
4220
+ }
4221
+ const obje = typeof objeOrKey === "string" ? this._gedcom.obje(objeOrKey) : objeOrKey;
4222
+ if (!obje?.id) {
4223
+ return void 0;
4224
+ }
4225
+ const already = this.get("OBJE")?.toList()?.values()?.some((item) => item?.toValue?.() === obje.id);
4226
+ if (!already) {
4227
+ const pointer = makePointer(
4228
+ this._gedcom,
4229
+ this,
4230
+ obje.id,
4231
+ "OBJE"
4232
+ );
4233
+ this.assign("OBJE", pointer);
4234
+ }
4235
+ if (options?.primary) {
4236
+ this.get("OBJE")?.toList()?.forEach((item) => {
4237
+ const target = item?.refType === "OBJE" ? this._gedcom?.obje(
4238
+ String(item.toValue())
4239
+ ) : item;
4240
+ if (!target) {
4241
+ return;
4242
+ }
4243
+ if (target.id === obje.id) {
4244
+ target.set("_PRIM", "Y");
4245
+ } else if (target.get("_PRIM")?.toValue() === "Y") {
4246
+ target.set("_PRIM", "N");
4247
+ }
4248
+ });
4249
+ obje.set("_PRIM", "Y");
4250
+ }
4251
+ return obje;
4252
+ }
4253
+ detachMultimedia(objeKey) {
4254
+ const list = this.get("OBJE")?.toList();
4255
+ if (!list) {
4256
+ return;
4257
+ }
4258
+ const toRemove = list.values().filter(
4259
+ (item) => item?.toValue?.() === objeKey || item?.id === objeKey
4260
+ );
4261
+ toRemove.forEach((item) => {
4262
+ if (item) {
4263
+ list.delete(item);
4264
+ }
4265
+ });
4266
+ if (list.length === 0) {
4267
+ this.remove("OBJE");
4268
+ }
4269
+ }
4270
+ /**
4271
+ * Create a multimedia record and attach it to this person.
4272
+ */
4273
+ attachMediaFromUrl(url, options) {
4274
+ if (!this._gedcom || !url) {
4275
+ return void 0;
4276
+ }
4277
+ const obje = this._gedcom.createMultimediaRecord({
4278
+ file: url,
4279
+ form: options?.form,
4280
+ title: options?.title,
4281
+ mediType: options?.mediType,
4282
+ primary: options?.primary,
4283
+ gedcomVersion: options?.gedcomVersion
4284
+ });
4285
+ return this.attachMultimedia(obje, { primary: options?.primary });
4286
+ }
4287
+ /**
4288
+ * Link a shared SNOTE record via `1 NOTE @Nn@` (GEDCOM 7).
4289
+ */
4290
+ attachSharedNote(noteOrKey) {
4291
+ if (!this._gedcom || !this.id) {
4292
+ return void 0;
4293
+ }
4294
+ const note = typeof noteOrKey === "string" ? this._gedcom.snote(noteOrKey) : noteOrKey;
4295
+ if (!note?.id) {
4296
+ return void 0;
4297
+ }
4298
+ const already = this.get("NOTE")?.toList()?.values()?.some((item) => item?.toValue?.() === note.id);
4299
+ if (!already) {
4300
+ const pointer = makePointer(
4301
+ this._gedcom,
4302
+ this,
4303
+ note.id,
4304
+ "SNOTE"
4305
+ );
4306
+ this.assign("NOTE", pointer);
4307
+ }
4308
+ return note;
4309
+ }
4076
4310
  addFact(input) {
4077
4311
  return addIndividualFact(this, input);
4078
4312
  }
4313
+ addNonEvent(input) {
4314
+ return addNonEvent(this, input);
4315
+ }
4079
4316
  getParentType(id) {
4080
4317
  let indi;
4081
4318
  if (typeof id === "string" || typeof id === "number") {
@@ -4116,7 +4353,7 @@ var Indi = class extends Common {
4116
4353
  if (!famChild) {
4117
4354
  const childIndi = this._gedcom?.indi(child.id);
4118
4355
  const childState = childIndi?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
4119
- childType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
4356
+ childType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
4120
4357
  } else {
4121
4358
  childType = famChild.get(usedRel)?.toValue() || "biological" /* BIOLOGICAL */;
4122
4359
  }
@@ -4677,7 +4914,7 @@ var Indi = class extends Common {
4677
4914
  return;
4678
4915
  }
4679
4916
  const childState = child?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
4680
- const childType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
4917
+ const childType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
4681
4918
  if (childType?.toLowerCase() === filter.PEDI.toLowerCase()) {
4682
4919
  children.append(child);
4683
4920
  }
@@ -4785,7 +5022,7 @@ var Indi = class extends Common {
4785
5022
  const child = this.id && family.CHIL?.toValueList()?.item(this.id);
4786
5023
  if (!child) {
4787
5024
  const childState = this?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
4788
- const parentType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
5025
+ const parentType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
4789
5026
  if (parentType?.toLowerCase() === filter.PEDI.toLowerCase()) {
4790
5027
  parents.merge(family.getParents());
4791
5028
  }
@@ -7192,7 +7429,11 @@ var STANDARD_QUALIFIERS = {
7192
7429
  BEF: "Bef.",
7193
7430
  BEFORE: "Bef.",
7194
7431
  AFT: "Aft.",
7195
- AFTER: "Aft."
7432
+ AFTER: "Aft.",
7433
+ CAL: "Abt.",
7434
+ // calculated ≈ about for display
7435
+ EST: "Abt."
7436
+ // estimated ≈ about for display
7196
7437
  };
7197
7438
  var EXPORT_QUALIFIERS = {
7198
7439
  "Abt.": "ABT",
@@ -7200,6 +7441,11 @@ var EXPORT_QUALIFIERS = {
7200
7441
  "Aft.": "AFT"
7201
7442
  };
7202
7443
  var GEDCOM_MONTHS = /\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b/g;
7444
+ var CALENDAR_PREFIX = /^(?<calendar>GREGORIAN|JULIAN|FRENCH_R|HEBREW)\b\s+/i;
7445
+ var isGedcomDateValueForm = (value) => (
7446
+ // Require space/end after the token so display forms like "Abt." are not opaque.
7447
+ /^(FROM|TO|BET|AFT|BEF|ABT|CAL|EST|INT)(\s|$)/i.test(value) || /\bAND\b/i.test(value)
7448
+ );
7203
7449
  var NOTE_MARKER = "####";
7204
7450
  var formatDateWithComponents = (date, hasDay, hasMonth, hasYear, noteValue, baseFormat = "dd MMM yyyy", locale) => {
7205
7451
  const hasNote = baseFormat.includes("NOTE");
@@ -7224,29 +7470,45 @@ var CommonDate = class extends Common {
7224
7470
  super(gedcom, id, main, parent);
7225
7471
  delete this.id;
7226
7472
  }
7473
+ get calendar() {
7474
+ return this._calendar;
7475
+ }
7227
7476
  set value(value) {
7228
7477
  if (value) {
7229
- const noteRegExp = /^(?<note>[a-zA-Z]+\.)/;
7230
- const noteMatch = value.match(noteRegExp)?.groups;
7231
7478
  let validValue = value;
7479
+ const calendarMatch = validValue.match(CALENDAR_PREFIX);
7480
+ if (calendarMatch?.groups?.calendar) {
7481
+ this._calendar = calendarMatch.groups.calendar.toUpperCase();
7482
+ validValue = validValue.slice(calendarMatch[0].length);
7483
+ } else {
7484
+ this._calendar = void 0;
7485
+ }
7486
+ const noteRegExp = /^(?<note>[a-zA-Z]+\.)/;
7487
+ const noteMatch = validValue.match(noteRegExp)?.groups;
7232
7488
  if (noteMatch?.note) {
7233
7489
  this.NOTE = this.NOTE || createCommon(this._gedcom, void 0, this.main);
7234
7490
  this.NOTE.value = noteMatch?.note;
7235
- validValue = value.replace(noteRegExp, "");
7491
+ validValue = validValue.replace(noteRegExp, "");
7236
7492
  } else {
7237
- const qualifierMatch = value.match(
7238
- /^(?<qualifier>ABT|ABOUT|BEF|BEFORE|AFT|AFTER)\b\s*/i
7493
+ const qualifierMatch = validValue.match(
7494
+ /^(?<qualifier>ABT|ABOUT|BEF|BEFORE|AFT|AFTER|CAL|EST)\b\s*/i
7239
7495
  );
7240
7496
  const qualifier = qualifierMatch?.groups?.qualifier?.toUpperCase();
7241
7497
  const note = qualifier ? STANDARD_QUALIFIERS[qualifier] : void 0;
7242
7498
  if (note) {
7243
7499
  this.NOTE = this.NOTE || createCommon(this._gedcom, void 0, this.main);
7244
7500
  this.NOTE.value = note;
7245
- validValue = value.slice(qualifierMatch[0].length);
7501
+ validValue = validValue.slice(qualifierMatch[0].length);
7246
7502
  }
7247
7503
  }
7248
7504
  const acceptedDate = this.isValidDateFormat(validValue);
7249
- if (acceptedDate) {
7505
+ if (isGedcomDateValueForm(validValue.trim())) {
7506
+ delete this.DAY;
7507
+ delete this.MONTH;
7508
+ delete this.YEAR;
7509
+ this._date = void 0;
7510
+ this._value = value;
7511
+ } else if (acceptedDate) {
7250
7512
  this.DAY = this.DAY || createCommon(this._gedcom, void 0, this.main);
7251
7513
  this.DAY.value = format(acceptedDate, "dd");
7252
7514
  this.MONTH = this.MONTH || createCommon(this._gedcom, void 0, this.main);
@@ -7349,6 +7611,15 @@ var CommonDate = class extends Common {
7349
7611
  );
7350
7612
  }
7351
7613
  exportValue() {
7614
+ if (typeof this._value === "string") {
7615
+ const withoutCalendar = this._value.replace(CALENDAR_PREFIX, "");
7616
+ if (isGedcomDateValueForm(withoutCalendar.trim())) {
7617
+ return this._value.replace(
7618
+ /^((?:GREGORIAN|JULIAN|FRENCH_R|HEBREW)\s+)?(FROM|TO|BET|AFT|BEF|ABT|CAL|EST|INT)\b/i,
7619
+ (_m, cal, q) => `${cal || ""}${q.toUpperCase()}`
7620
+ );
7621
+ }
7622
+ }
7352
7623
  const formatted = this.toValue("NOTE dd MMM yyyy", null);
7353
7624
  if (!formatted) {
7354
7625
  return formatted;
@@ -7356,10 +7627,14 @@ var CommonDate = class extends Common {
7356
7627
  const note = this.NOTE?.value?.trim();
7357
7628
  const qualifier = note ? EXPORT_QUALIFIERS[note] : void 0;
7358
7629
  const standardized = qualifier ? formatted.replace(note, qualifier) : formatted;
7359
- return standardized.replace(
7630
+ const withMonths = standardized.replace(
7360
7631
  GEDCOM_MONTHS,
7361
7632
  (month) => month.toUpperCase()
7362
7633
  );
7634
+ if (this._calendar && this._calendar !== "GREGORIAN") {
7635
+ return `${this._calendar} ${withMonths}`;
7636
+ }
7637
+ return withMonths;
7363
7638
  }
7364
7639
  toGedcomLines(tag, level = 0, options) {
7365
7640
  const internal = new RegExp(
@@ -7535,6 +7810,24 @@ var setDeceased = (indi, deceased) => {
7535
7810
  }
7536
7811
  addIndividualFact(indi, { tag: "DEAT", value: "Y" });
7537
7812
  };
7813
+ var addNonEvent = (owner, input) => {
7814
+ const gedcom = owner.getGedcom();
7815
+ const eventType = input.event?.trim().toUpperCase();
7816
+ if (!gedcom || !eventType) {
7817
+ return void 0;
7818
+ }
7819
+ const no = createCommon(gedcom, void 0, owner);
7820
+ no.type = "NO";
7821
+ no.value = eventType;
7822
+ if (input.date?.trim()) {
7823
+ setDateOn(gedcom, owner, no, input.date);
7824
+ }
7825
+ if (input.note?.trim()) {
7826
+ no.set("NOTE", input.note.trim());
7827
+ }
7828
+ owner.assign("NO", no);
7829
+ return no;
7830
+ };
7538
7831
 
7539
7832
  // src/classes/fam.ts
7540
7833
  var Fam = class extends Common {
@@ -7586,6 +7879,9 @@ var Fam = class extends Common {
7586
7879
  addFact(input) {
7587
7880
  return addFamilyFact(this, input);
7588
7881
  }
7882
+ addNonEvent(input) {
7883
+ return addNonEvent(this, input);
7884
+ }
7589
7885
  toList() {
7590
7886
  return new Families().concat(
7591
7887
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -7639,70 +7935,965 @@ var Families = class _Families extends List {
7639
7935
  }
7640
7936
  };
7641
7937
 
7642
- // package.json
7643
- var package_default = {
7644
- name: "@treeviz/gedcom-parser",
7645
- version: "2.0.12"};
7646
-
7647
- // src/utils/get-product-details.ts
7648
- var isDevelopment = () => {
7649
- return !process.env.NODE_ENV || process.env.NODE_ENV === "development";
7938
+ // src/utils/gedcom-version.ts
7939
+ var GEDCOM_EXPORT_VERSIONS = ["5.5.1", "7.0"];
7940
+ var DEFAULT_GEDCOM_EXPORT_VERSION = "5.5.1";
7941
+ var normalizeGedcomVersion = (value) => {
7942
+ const trimmed = value?.trim() ?? "";
7943
+ if (trimmed.startsWith("7")) {
7944
+ return "7.0";
7945
+ }
7946
+ return "5.5.1";
7947
+ };
7948
+ var isGedcom7 = (value) => normalizeGedcomVersion(value) === "7.0";
7949
+ var GEDZIP_MIME = "application/vnd.familysearch.gedcom+zip";
7950
+ var GEDZIP_EXTENSION = "gdz";
7951
+ var GEDZIP_GEDCOM_ENTRY = "gedcom.ged";
7952
+ var sanitizePathSegment = (name) => name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^\.+/, "") || "file";
7953
+ var extensionFor = (contentType) => {
7954
+ const raw = (contentType || "bin").replace(/^\./, "").toLowerCase();
7955
+ if (raw.includes("/")) {
7956
+ return raw.split("/").pop() || "bin";
7957
+ }
7958
+ return raw || "bin";
7959
+ };
7960
+ var rewriteGedcomFilePaths = (gedcomText, urlToPath) => {
7961
+ const entries = urlToPath instanceof Map ? urlToPath : new Map(Object.entries(urlToPath));
7962
+ let text = gedcomText;
7963
+ entries.forEach((path, url) => {
7964
+ const escaped = url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7965
+ text = text.replace(
7966
+ new RegExp(`(^|\\r?\\n)(\\d+ FILE )${escaped}`, "g"),
7967
+ `$1$2${path}`
7968
+ );
7969
+ });
7970
+ return text;
7971
+ };
7972
+ var assignMediaPaths = (mediaFiles) => {
7973
+ const urlToPath = /* @__PURE__ */ new Map();
7974
+ const usedPaths = /* @__PURE__ */ new Set([GEDZIP_GEDCOM_ENTRY]);
7975
+ const files = [];
7976
+ for (const file of mediaFiles) {
7977
+ if (!file.content || !file.url) {
7978
+ continue;
7979
+ }
7980
+ const ext = extensionFor(file.contentType);
7981
+ const base = sanitizePathSegment(
7982
+ file.imgId || file.title || file.id || "media"
7983
+ );
7984
+ let path = `media/${base}.${ext}`;
7985
+ let suffix = 1;
7986
+ while (usedPaths.has(path)) {
7987
+ path = `media/${base}-${suffix++}.${ext}`;
7988
+ }
7989
+ usedPaths.add(path);
7990
+ urlToPath.set(file.url, path);
7991
+ const marker = "base64,";
7992
+ const idx = file.content.indexOf(marker);
7993
+ if (idx >= 0) {
7994
+ files.push({
7995
+ path,
7996
+ url: file.url,
7997
+ content: file.content.substring(idx + marker.length),
7998
+ base64: true
7999
+ });
8000
+ } else {
8001
+ files.push({
8002
+ path,
8003
+ url: file.url,
8004
+ content: file.content,
8005
+ base64: false
8006
+ });
8007
+ }
8008
+ }
8009
+ return { urlToPath, files };
8010
+ };
8011
+ var buildGedzip = async (gedcomText, mediaFiles = []) => {
8012
+ const zip = new JSZip();
8013
+ const { urlToPath, files } = assignMediaPaths(mediaFiles);
8014
+ for (const file of files) {
8015
+ zip.file(file.path, file.content, { base64: file.base64 });
8016
+ }
8017
+ zip.file(GEDZIP_GEDCOM_ENTRY, rewriteGedcomFilePaths(gedcomText, urlToPath));
8018
+ return zip.generateAsync({ type: "uint8array" });
8019
+ };
8020
+ var normalizeZipPath = (name) => name.replace(/\\/g, "/").replace(/^\.\//, "");
8021
+ var MIME_BY_EXT = {
8022
+ jpg: "image/jpeg",
8023
+ jpeg: "image/jpeg",
8024
+ png: "image/png",
8025
+ gif: "image/gif",
8026
+ webp: "image/webp",
8027
+ bmp: "image/bmp",
8028
+ tif: "image/tiff",
8029
+ tiff: "image/tiff",
8030
+ svg: "image/svg+xml",
8031
+ pdf: "application/pdf"
8032
+ };
8033
+ var mimeForPath = (path) => {
8034
+ const ext = (path.split(".").pop() || "").toLowerCase();
8035
+ return MIME_BY_EXT[ext] || "application/octet-stream";
8036
+ };
8037
+ var bytesToBase64 = (bytes) => {
8038
+ if (typeof Buffer !== "undefined") {
8039
+ return Buffer.from(bytes).toString("base64");
8040
+ }
8041
+ let binary = "";
8042
+ const chunk = 32768;
8043
+ for (let i = 0; i < bytes.length; i += chunk) {
8044
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
8045
+ }
8046
+ return btoa(binary);
8047
+ };
8048
+ var bytesToDataUrl = (bytes, mime) => `data:${mime};base64,${bytesToBase64(bytes)}`;
8049
+ var remountGedzipMediaAsDataUrls = (extracted) => {
8050
+ if (!extracted.mediaEntries.length) {
8051
+ return extracted.gedcomText;
8052
+ }
8053
+ const pathToDataUrl = /* @__PURE__ */ new Map();
8054
+ for (const media of extracted.mediaEntries) {
8055
+ const path = normalizeZipPath(media.path);
8056
+ const dataUrl = bytesToDataUrl(media.content, mimeForPath(path));
8057
+ pathToDataUrl.set(path, dataUrl);
8058
+ pathToDataUrl.set(`./${path}`, dataUrl);
8059
+ const base = path.split("/").pop();
8060
+ if (base) {
8061
+ pathToDataUrl.set(base, dataUrl);
8062
+ pathToDataUrl.set(`media/${base}`, dataUrl);
8063
+ }
8064
+ }
8065
+ return rewriteGedcomFilePaths(extracted.gedcomText, pathToDataUrl);
8066
+ };
8067
+ var extractGedzip = async (data) => {
8068
+ const zip = await JSZip.loadAsync(data);
8069
+ const entries = Object.values(zip.files).filter((entry) => !entry.dir);
8070
+ const preferred = entries.find(
8071
+ (entry) => normalizeZipPath(entry.name).toLowerCase() === GEDZIP_GEDCOM_ENTRY
8072
+ ) ?? entries.find(
8073
+ (entry) => normalizeZipPath(entry.name).toLowerCase().endsWith(".ged")
8074
+ );
8075
+ if (!preferred) {
8076
+ throw new Error("No .ged file found in the archive.");
8077
+ }
8078
+ const gedcomText = await preferred.async("string");
8079
+ const mediaEntries = [];
8080
+ for (const entry of entries) {
8081
+ const path = normalizeZipPath(entry.name);
8082
+ if (path === normalizeZipPath(preferred.name)) {
8083
+ continue;
8084
+ }
8085
+ if (path.toLowerCase().endsWith(".ged")) {
8086
+ continue;
8087
+ }
8088
+ mediaEntries.push({
8089
+ path,
8090
+ content: await entry.async("uint8array")
8091
+ });
8092
+ }
8093
+ return {
8094
+ gedcomText,
8095
+ entryName: normalizeZipPath(preferred.name),
8096
+ mediaEntries
8097
+ };
8098
+ };
8099
+ var extractGedzipGedcom = async (data, options) => {
8100
+ const extracted = await extractGedzip(data);
8101
+ if (options?.embedMediaAsDataUrls === false) {
8102
+ return extracted.gedcomText;
8103
+ }
8104
+ return remountGedzipMediaAsDataUrls(extracted);
8105
+ };
8106
+ var isGedzipContainer = (file) => {
8107
+ const name = (file.name || "").toLowerCase();
8108
+ const type = (file.type || "").toLowerCase();
8109
+ return name.endsWith(`.${GEDZIP_EXTENSION}`) || name.endsWith(".zip") || type === GEDZIP_MIME || type === "application/zip" || type === "application/x-zip-compressed";
8110
+ };
8111
+ var downloadGedzipMedia = async (media, onProgress) => {
8112
+ const entries = Object.values(media).filter((item) => !!item.url);
8113
+ const total = entries.length;
8114
+ let done = 0;
8115
+ const downloaded = [];
8116
+ await Promise.all(
8117
+ entries.map(async (item) => {
8118
+ try {
8119
+ const resolved = await resolveMediaContent({
8120
+ url: item.url,
8121
+ id: item.id,
8122
+ imgId: item.imgId,
8123
+ key: "key" in item ? item.key : void 0,
8124
+ contentType: item.contentType
8125
+ });
8126
+ if (!resolved?.content) {
8127
+ return;
8128
+ }
8129
+ downloaded.push({
8130
+ ...item,
8131
+ content: resolved.content,
8132
+ contentType: resolved.contentType || item.contentType
8133
+ });
8134
+ } catch {
8135
+ } finally {
8136
+ done += 1;
8137
+ onProgress?.(done, total);
8138
+ }
8139
+ })
8140
+ );
8141
+ return downloaded;
8142
+ };
8143
+ var buildGedzipBlob = async (gedcomText, mediaFiles = []) => {
8144
+ const bytes = await buildGedzip(gedcomText, mediaFiles);
8145
+ return new Blob([bytes], { type: GEDZIP_MIME });
7650
8146
  };
7651
- var getVersion = () => package_default.version;
7652
- var getName = () => package_default.name;
7653
8147
 
7654
- // src/classes/gedcom.ts
7655
- var isObjectPatch = (value) => {
7656
- return !!value && typeof value === "object" && !Array.isArray(value);
8148
+ // src/utils/gedcom7-enumerations.ts
8149
+ var GEDCOM7_SEX_VALUES = ["M", "F", "U", "X", "N"];
8150
+ var GEDCOM7_PEDI_VALUES = [
8151
+ "adopted",
8152
+ "birth",
8153
+ "foster",
8154
+ "sealing"
8155
+ ];
8156
+ var GEDCOM7_ROLE_VALUES = [
8157
+ "CHIL",
8158
+ "CLERGY",
8159
+ "FATH",
8160
+ "FRIEND",
8161
+ "GODP",
8162
+ "HUSB",
8163
+ "MOTH",
8164
+ "MULTIPLE",
8165
+ "NGHBR",
8166
+ "OFFICIATOR",
8167
+ "OTHER",
8168
+ "PARENT",
8169
+ "SPOU",
8170
+ "WIFE",
8171
+ "WITN"
8172
+ ];
8173
+ var GEDCOM7_RESN_VALUES = [
8174
+ "CONFIDENTIAL",
8175
+ "LOCKED",
8176
+ "PRIVACY"
8177
+ ];
8178
+ var isAllowed = (value, allowed) => allowed.includes(value);
8179
+ var moveToPhrase = (node, phrase) => {
8180
+ const previousValue = node.value;
8181
+ const previousPhrase = node.get("PHRASE");
8182
+ const previousPhraseValue = previousPhrase?.toValue();
8183
+ node.removeValue();
8184
+ if (previousPhrase) {
8185
+ previousPhrase.value = phrase;
8186
+ } else {
8187
+ const phraseNode = createCommon(node.getGedcom(), void 0, node.main);
8188
+ phraseNode.value = phrase;
8189
+ node.set("PHRASE", phraseNode);
8190
+ }
8191
+ return () => {
8192
+ if (previousValue === void 0) {
8193
+ node.removeValue();
8194
+ } else {
8195
+ node.value = previousValue;
8196
+ }
8197
+ if (previousPhrase) {
8198
+ previousPhrase.value = previousPhraseValue;
8199
+ } else {
8200
+ node.remove("PHRASE");
8201
+ }
8202
+ };
7657
8203
  };
7658
- var GedCom = class extends Common {
7659
- constructor() {
7660
- super();
7661
- this.tagMembers = {};
7662
- this.reflist = {};
7663
- this.refcount = 0;
7664
- delete this._gedcom;
7665
- delete this.id;
7666
- this.removeValue();
8204
+ var normalizeEnum = (node, allowed, mode, restores) => {
8205
+ const value = node?.toValue();
8206
+ if (!node || typeof value !== "string" || !value.trim()) {
8207
+ return;
7667
8208
  }
7668
- getMain(type, index) {
7669
- const list = !type || type instanceof List ? type : this.getList(type);
7670
- if (!list) {
7671
- return void 0;
8209
+ const normalized = mode === "upper" ? value.trim().toUpperCase() : value.trim().toLowerCase();
8210
+ if (isAllowed(normalized, allowed)) {
8211
+ if (value !== normalized) {
8212
+ const previous = node.value;
8213
+ node.value = normalized;
8214
+ restores.push(() => {
8215
+ node.value = previous;
8216
+ });
7672
8217
  }
7673
- if (typeof index === "string") {
7674
- return list.item(index);
8218
+ return;
8219
+ }
8220
+ restores.push(moveToPhrase(node, value.trim()));
8221
+ };
8222
+ var applyGedcom7Enumerations = (gedcom) => {
8223
+ const restores = [];
8224
+ gedcom.indis()?.forEach((indi) => {
8225
+ if (!indi) return;
8226
+ normalizeEnum(indi.get("SEX"), GEDCOM7_SEX_VALUES, "upper", restores);
8227
+ normalizeEnum(indi.get("RESN"), GEDCOM7_RESN_VALUES, "upper", restores);
8228
+ indi.get("FAMC")?.toList()?.forEach((famc) => {
8229
+ normalizeEnum(
8230
+ famc?.get("PEDI") ?? famc?.get("PEDT"),
8231
+ GEDCOM7_PEDI_VALUES,
8232
+ "lower",
8233
+ restores
8234
+ );
8235
+ });
8236
+ indi.get("ASSO")?.toList()?.forEach((asso) => {
8237
+ normalizeEnum(
8238
+ asso?.get("ROLE"),
8239
+ GEDCOM7_ROLE_VALUES,
8240
+ "upper",
8241
+ restores
8242
+ );
8243
+ });
8244
+ });
8245
+ gedcom.fams()?.forEach((fam) => {
8246
+ if (!fam) return;
8247
+ normalizeEnum(fam.get("RESN"), GEDCOM7_RESN_VALUES, "upper", restores);
8248
+ fam.get("ASSO")?.toList()?.forEach((asso) => {
8249
+ normalizeEnum(
8250
+ asso?.get("ROLE"),
8251
+ GEDCOM7_ROLE_VALUES,
8252
+ "upper",
8253
+ restores
8254
+ );
8255
+ });
8256
+ });
8257
+ return () => {
8258
+ for (let i = restores.length - 1; i >= 0; i -= 1) {
8259
+ restores[i]?.();
7675
8260
  }
7676
- const keys = list.keys();
7677
- return list.item(keys[index]);
8261
+ };
8262
+ };
8263
+
8264
+ // src/utils/gedcom7-dates.ts
8265
+ var GEDCOM7_CALENDARS = [
8266
+ "GREGORIAN",
8267
+ "JULIAN",
8268
+ "FRENCH_R",
8269
+ "HEBREW"
8270
+ ];
8271
+ var CALENDAR_PREFIX2 = /^(?<calendar>GREGORIAN|JULIAN|FRENCH_R|HEBREW)\b\s+/i;
8272
+ var parseGedcom7CalendarPrefix = (value) => {
8273
+ const match = value.match(CALENDAR_PREFIX2);
8274
+ if (!match?.groups?.calendar) {
8275
+ return { calendar: void 0, rest: value };
7678
8276
  }
7679
- getList(type) {
7680
- return this.get(type);
8277
+ return {
8278
+ calendar: match.groups.calendar.toUpperCase(),
8279
+ rest: value.slice(match[0].length)
8280
+ };
8281
+ };
8282
+ var withGedcom7Calendar = (value, calendar) => {
8283
+ if (!calendar || calendar.toUpperCase() === "GREGORIAN") {
8284
+ return value;
7681
8285
  }
7682
- createNodeFromPatchValue(value, main) {
7683
- if (value === void 0 || value === null) {
7684
- return void 0;
8286
+ const upper = calendar.toUpperCase();
8287
+ if (GEDCOM7_CALENDARS.includes(upper)) {
8288
+ const { rest } = parseGedcom7CalendarPrefix(value);
8289
+ return `${upper} ${rest}`.trim();
8290
+ }
8291
+ return value;
8292
+ };
8293
+ var applyGedcom7DatePhrases = (gedcom) => {
8294
+ const restores = [];
8295
+ const visitDate = (dateNode) => {
8296
+ if (!dateNode || typeof dateNode.toValue !== "function") {
8297
+ return;
7685
8298
  }
7686
- const node = createCommon(this, void 0, main);
7687
- if (Array.isArray(value)) {
7688
- value.forEach((item) => {
7689
- const childNode = this.createNodeFromPatchValue(item, node);
7690
- if (childNode) {
7691
- node.assign("DATA", childNode);
8299
+ const asDate = dateNode;
8300
+ const hasComponents = !!(asDate.DAY || asDate.MONTH || asDate.YEAR);
8301
+ const raw = dateNode.exportValue?.() ?? dateNode.toValue();
8302
+ if (typeof raw !== "string" || !raw.trim()) {
8303
+ return;
8304
+ }
8305
+ const { calendar, rest } = parseGedcom7CalendarPrefix(raw.trim());
8306
+ 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);
8307
+ if (looksStructured) {
8308
+ if (calendar && calendar !== "GREGORIAN") {
8309
+ const previous = dateNode.value;
8310
+ const next = withGedcom7Calendar(rest, calendar);
8311
+ if (previous !== next) {
8312
+ dateNode.value = next;
8313
+ restores.push(() => {
8314
+ dateNode.value = previous;
8315
+ });
7692
8316
  }
7693
- });
7694
- return node;
8317
+ }
8318
+ return;
7695
8319
  }
7696
- if (isObjectPatch(value)) {
7697
- this.applyObjectToCommon(node, value);
7698
- return node;
8320
+ const previousValue = dateNode.value;
8321
+ const previousPhrase = dateNode.get("PHRASE");
8322
+ const previousPhraseValue = previousPhrase?.toValue();
8323
+ dateNode.removeValue();
8324
+ if (previousPhrase) {
8325
+ previousPhrase.value = raw.trim();
8326
+ } else {
8327
+ const phrase = createCommon(
8328
+ dateNode.getGedcom(),
8329
+ void 0,
8330
+ dateNode.main
8331
+ );
8332
+ phrase.value = raw.trim();
8333
+ dateNode.set("PHRASE", phrase);
7699
8334
  }
7700
- node.value = String(value);
7701
- return node;
7702
- }
7703
- applyObjectToCommon(target, patch) {
7704
- Object.entries(patch).forEach(([rawTag, value]) => {
7705
- if (rawTag === "value") {
8335
+ restores.push(() => {
8336
+ if (previousValue === void 0) {
8337
+ dateNode.removeValue();
8338
+ } else {
8339
+ dateNode.value = previousValue;
8340
+ }
8341
+ if (previousPhrase) {
8342
+ previousPhrase.value = previousPhraseValue;
8343
+ } else {
8344
+ dateNode.remove("PHRASE");
8345
+ }
8346
+ });
8347
+ };
8348
+ const walk = (node) => {
8349
+ if (!node) return;
8350
+ node.get("DATE")?.toList()?.forEach((item) => visitDate(item));
8351
+ node.get("SDATE")?.toList()?.forEach((item) => visitDate(item));
8352
+ };
8353
+ gedcom.indis()?.forEach((indi) => {
8354
+ if (!indi) return;
8355
+ walk(indi);
8356
+ [
8357
+ "BIRT",
8358
+ "DEAT",
8359
+ "CHR",
8360
+ "BAPM",
8361
+ "BURI",
8362
+ "CREM",
8363
+ "ADOP",
8364
+ "EVEN",
8365
+ "RESI",
8366
+ "OCCU",
8367
+ "MARR"
8368
+ ].forEach((tag) => {
8369
+ indi.get(tag)?.toList()?.forEach((event) => walk(event));
8370
+ });
8371
+ });
8372
+ gedcom.fams()?.forEach((fam) => {
8373
+ if (!fam) return;
8374
+ ["MARR", "DIV", "ENGA", "ANUL", "EVEN"].forEach((tag) => {
8375
+ fam.get(tag)?.toList()?.forEach((event) => walk(event));
8376
+ });
8377
+ });
8378
+ return () => {
8379
+ for (let i = restores.length - 1; i >= 0; i -= 1) {
8380
+ restores[i]?.();
8381
+ }
8382
+ };
8383
+ };
8384
+
8385
+ // src/utils/uid.ts
8386
+ var createGedcomUid = () => {
8387
+ const cryptoObj = typeof globalThis !== "undefined" ? globalThis.crypto : void 0;
8388
+ if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
8389
+ return cryptoObj.randomUUID();
8390
+ }
8391
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => {
8392
+ const rand = Math.random() * 16 | 0;
8393
+ const value = char === "x" ? rand : rand & 3 | 8;
8394
+ return value.toString(16);
8395
+ });
8396
+ };
8397
+
8398
+ // src/utils/gedcom7-metadata.ts
8399
+ var GEDCOM_MONTHS2 = [
8400
+ "JAN",
8401
+ "FEB",
8402
+ "MAR",
8403
+ "APR",
8404
+ "MAY",
8405
+ "JUN",
8406
+ "JUL",
8407
+ "AUG",
8408
+ "SEP",
8409
+ "OCT",
8410
+ "NOV",
8411
+ "DEC"
8412
+ ];
8413
+ var formatGedcom7Timestamp = (date = /* @__PURE__ */ new Date()) => {
8414
+ const day = String(date.getUTCDate());
8415
+ const month = GEDCOM_MONTHS2[date.getUTCMonth()];
8416
+ const year = String(date.getUTCFullYear());
8417
+ const hh = String(date.getUTCHours()).padStart(2, "0");
8418
+ const mm = String(date.getUTCMinutes()).padStart(2, "0");
8419
+ const ss = String(date.getUTCSeconds()).padStart(2, "0");
8420
+ return {
8421
+ date: `${day} ${month} ${year}`,
8422
+ time: `${hh}:${mm}:${ss}Z`
8423
+ };
8424
+ };
8425
+ var ensureMetaDate = (gedcom, record, tag, when, restores) => {
8426
+ if (record.get(tag)) {
8427
+ return;
8428
+ }
8429
+ const { date, time } = formatGedcom7Timestamp(when);
8430
+ const meta = createCommon(gedcom, void 0, record);
8431
+ meta.type = tag;
8432
+ const dateNode = createCommonDate(gedcom, void 0, record, meta);
8433
+ dateNode.type = "DATE";
8434
+ dateNode.value = date;
8435
+ dateNode.set("TIME", time);
8436
+ meta.set("DATE", dateNode);
8437
+ record.set(tag, meta);
8438
+ restores.push(() => {
8439
+ record.remove(tag);
8440
+ });
8441
+ };
8442
+ var ensureUid = (record, restores) => {
8443
+ const existing = record.get("UID")?.toValue();
8444
+ if (typeof existing === "string" && existing.trim()) {
8445
+ return;
8446
+ }
8447
+ const uid = createGedcomUid();
8448
+ record.set("UID", uid);
8449
+ restores.push(() => {
8450
+ record.remove("UID");
8451
+ });
8452
+ };
8453
+ var applyGedcom7RecordMetadata = (gedcom, options) => {
8454
+ const restores = [];
8455
+ const now = options?.now ?? /* @__PURE__ */ new Date();
8456
+ const visit = (record) => {
8457
+ if (!record?.id) {
8458
+ return;
8459
+ }
8460
+ ensureUid(record, restores);
8461
+ ensureMetaDate(gedcom, record, "CREA", now, restores);
8462
+ ensureMetaDate(gedcom, record, "CHAN", now, restores);
8463
+ };
8464
+ gedcom.indis()?.forEach((indi) => visit(indi));
8465
+ gedcom.fams()?.forEach((fam) => visit(fam));
8466
+ gedcom.objes()?.forEach((obje) => visit(obje));
8467
+ gedcom.sours()?.forEach((sour) => visit(sour));
8468
+ gedcom.repos()?.forEach((repo) => visit(repo));
8469
+ gedcom.subms()?.forEach((subm) => visit(subm));
8470
+ gedcom.snotes()?.forEach((note) => visit(note));
8471
+ return () => {
8472
+ for (let i = restores.length - 1; i >= 0; i -= 1) {
8473
+ restores[i]?.();
8474
+ }
8475
+ };
8476
+ };
8477
+
8478
+ // src/utils/gedcom7-schema.ts
8479
+ var TREEVIZ_EXTENSION_BASE_URI = "https://treeviz.com/gedcom";
8480
+ var TREEVIZ_EXTENSION_URIS = {
8481
+ _ORIGHEAD: `${TREEVIZ_EXTENSION_BASE_URI}#_ORIGHEAD`,
8482
+ _TREE: `${TREEVIZ_EXTENSION_BASE_URI}#_TREE`,
8483
+ _TID: `${TREEVIZ_EXTENSION_BASE_URI}#_TID`,
8484
+ _PRIM: `${TREEVIZ_EXTENSION_BASE_URI}#_PRIM`,
8485
+ _FREL: `${TREEVIZ_EXTENSION_BASE_URI}#_FREL`,
8486
+ _MREL: `${TREEVIZ_EXTENSION_BASE_URI}#_MREL`,
8487
+ _SREL: `${TREEVIZ_EXTENSION_BASE_URI}#_SREL`,
8488
+ _UID: `${TREEVIZ_EXTENSION_BASE_URI}#_UID`,
8489
+ _WLNK: `${TREEVIZ_EXTENSION_BASE_URI}#_WLNK`,
8490
+ _MTTAG: `${TREEVIZ_EXTENSION_BASE_URI}#_MTTAG`,
8491
+ _MTCAT: `${TREEVIZ_EXTENSION_BASE_URI}#_MTCAT`,
8492
+ _CLON: `${TREEVIZ_EXTENSION_BASE_URI}#_CLON`,
8493
+ _MSER: `${TREEVIZ_EXTENSION_BASE_URI}#_MSER`,
8494
+ _OID: `${TREEVIZ_EXTENSION_BASE_URI}#_OID`,
8495
+ _LKID: `${TREEVIZ_EXTENSION_BASE_URI}#_LKID`,
8496
+ _PHOTO_RIN: `${TREEVIZ_EXTENSION_BASE_URI}#_PHOTO_RIN`,
8497
+ _EXPORTED_FROM_SITE_ID: `${TREEVIZ_EXTENSION_BASE_URI}#_EXPORTED_FROM_SITE_ID`,
8498
+ _FS_ID: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_ID`,
8499
+ _FS_LINK: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_LINK`,
8500
+ _FS_MATCH: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_MATCH`,
8501
+ _FS_SOUR: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_SOUR`,
8502
+ _IS_FS: `${TREEVIZ_EXTENSION_BASE_URI}#_IS_FS`,
8503
+ _LABEL: `${TREEVIZ_EXTENSION_BASE_URI}#_LABEL`,
8504
+ _MILT: `${TREEVIZ_EXTENSION_BASE_URI}#_MILT`,
8505
+ _MILTID: `${TREEVIZ_EXTENSION_BASE_URI}#_MILTID`,
8506
+ _ORIG: `${TREEVIZ_EXTENSION_BASE_URI}#_ORIG`,
8507
+ _ENV: `${TREEVIZ_EXTENSION_BASE_URI}#_ENV`,
8508
+ _TREEVIZ_SETTINGS: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_SETTINGS`,
8509
+ _TREEVIZ_VIEW: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_VIEW`,
8510
+ _TREEVIZ_DETECTIVE: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_DETECTIVE`,
8511
+ _TREEVIZ_DETECTIVE_STATE: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_DETECTIVE_STATE`
8512
+ };
8513
+ var parseTagDefinition = (payload) => {
8514
+ const trimmed = payload.trim();
8515
+ const space = trimmed.indexOf(" ");
8516
+ if (space <= 0) {
8517
+ return void 0;
8518
+ }
8519
+ const tag = trimmed.slice(0, space).trim();
8520
+ const uri = trimmed.slice(space + 1).trim();
8521
+ if (!tag || !uri) {
8522
+ return void 0;
8523
+ }
8524
+ return { tag, uri };
8525
+ };
8526
+ var getExtensionSchema = (gedcom) => {
8527
+ const map = /* @__PURE__ */ new Map();
8528
+ const schma = gedcom.get("HEAD")?.get("SCHMA");
8529
+ if (!schma) {
8530
+ return map;
8531
+ }
8532
+ schma.get("TAG")?.toList()?.forEach((tagNode) => {
8533
+ const payload = tagNode?.toValue();
8534
+ if (typeof payload !== "string") {
8535
+ return;
8536
+ }
8537
+ const parsed = parseTagDefinition(payload);
8538
+ if (parsed) {
8539
+ map.set(parsed.tag.toUpperCase(), parsed.uri);
8540
+ }
8541
+ });
8542
+ return map;
8543
+ };
8544
+ var ensureSchemaNode = (gedcom) => {
8545
+ const head = gedcom.get("HEAD");
8546
+ if (!head) {
8547
+ return void 0;
8548
+ }
8549
+ let schma = head.get("SCHMA");
8550
+ if (!schma) {
8551
+ schma = createCommon(gedcom, void 0, head);
8552
+ head.set("SCHMA", schma);
8553
+ }
8554
+ return schma;
8555
+ };
8556
+ var registerExtensionTag = (gedcom, tag, uri) => {
8557
+ const normalizedTag = tag.trim().toUpperCase();
8558
+ const normalizedUri = uri.trim();
8559
+ if (!normalizedTag.startsWith("_") || !normalizedUri) {
8560
+ return void 0;
8561
+ }
8562
+ const schma = ensureSchemaNode(gedcom);
8563
+ if (!schma) {
8564
+ return void 0;
8565
+ }
8566
+ const payload = `${normalizedTag} ${normalizedUri}`;
8567
+ const existingList = schma.get("TAG")?.toList();
8568
+ const existing = existingList?.values().find((node) => {
8569
+ const value = node?.toValue();
8570
+ return typeof value === "string" && value.trim().toUpperCase().startsWith(`${normalizedTag} `);
8571
+ });
8572
+ if (existing) {
8573
+ existing.value = payload;
8574
+ return existing;
8575
+ }
8576
+ const tagNode = createCommon(gedcom, void 0, schma);
8577
+ tagNode.value = payload;
8578
+ schma.assign("TAG", tagNode);
8579
+ return tagNode;
8580
+ };
8581
+ var ensureExtensionSchema = (gedcom, extraTags) => {
8582
+ const head = gedcom.get("HEAD");
8583
+ const hadSchma = !!head?.get("SCHMA");
8584
+ const previousPayloads = head?.get("SCHMA")?.get("TAG")?.toList()?.values().map((node) => ({
8585
+ node,
8586
+ value: node?.toValue()
8587
+ })) ?? [];
8588
+ const tags = /* @__PURE__ */ new Set([
8589
+ ...Object.keys(TREEVIZ_EXTENSION_URIS),
8590
+ ...(extraTags ?? []).map((tag) => tag.toUpperCase())
8591
+ ]);
8592
+ tags.forEach((tag) => {
8593
+ const uri = TREEVIZ_EXTENSION_URIS[tag] ?? `${TREEVIZ_EXTENSION_BASE_URI}#${tag}`;
8594
+ if (tag.startsWith("_")) {
8595
+ registerExtensionTag(gedcom, tag, uri);
8596
+ }
8597
+ });
8598
+ return () => {
8599
+ if (!head) {
8600
+ return;
8601
+ }
8602
+ if (!hadSchma) {
8603
+ head.remove("SCHMA");
8604
+ return;
8605
+ }
8606
+ const schma = head.get("SCHMA");
8607
+ const list = schma?.get("TAG")?.toList();
8608
+ const keep = new Set(
8609
+ previousPayloads.map(
8610
+ (item) => typeof item.value === "string" ? item.value : void 0
8611
+ ).filter((value) => !!value)
8612
+ );
8613
+ list?.values().forEach((node) => {
8614
+ const value = node?.toValue();
8615
+ if (typeof value === "string" && !keep.has(value) && node) {
8616
+ list.delete(node);
8617
+ }
8618
+ });
8619
+ previousPayloads.forEach(({ node, value }) => {
8620
+ if (node && value !== void 0) {
8621
+ node.value = value;
8622
+ }
8623
+ });
8624
+ };
8625
+ };
8626
+ var collectExtensionTagsFrom = (node, into = /* @__PURE__ */ new Set()) => {
8627
+ if (!node) {
8628
+ return into;
8629
+ }
8630
+ const keys = Object.keys(node).filter(
8631
+ (key) => key.startsWith("_") && !key.startsWith("_gedcom") && !key.startsWith("_value") && !key.startsWith("_id") && !key.startsWith("_main") && !key.startsWith("_parent") && !key.startsWith("_unique") && !key.startsWith("_type") && !key.startsWith("_refs") && !key.startsWith("_date")
8632
+ );
8633
+ keys.forEach((key) => {
8634
+ const tag = key.toUpperCase();
8635
+ if (/^_[A-Z0-9_]+$/.test(tag)) {
8636
+ into.add(tag);
8637
+ }
8638
+ });
8639
+ return into;
8640
+ };
8641
+
8642
+ // package.json
8643
+ var package_default = {
8644
+ name: "@treeviz/gedcom-parser",
8645
+ version: "2.1.1"};
8646
+
8647
+ // src/utils/get-product-details.ts
8648
+ var isDevelopment = () => {
8649
+ return !process.env.NODE_ENV || process.env.NODE_ENV === "development";
8650
+ };
8651
+ var getVersion = () => package_default.version;
8652
+ var getName = () => package_default.name;
8653
+
8654
+ // src/utils/multimedia.ts
8655
+ var inferMediaForm = (file, fallback = "bin") => {
8656
+ const withoutQuery = file.split("?")[0] || file;
8657
+ const ext = getFileExtension(withoutQuery);
8658
+ if (ext) {
8659
+ return ext.toLowerCase() === "jpeg" ? "jpg" : ext.toLowerCase();
8660
+ }
8661
+ return fallback;
8662
+ };
8663
+ var mergeMediaLists = (...lists) => {
8664
+ const merged = {};
8665
+ for (const list of lists) {
8666
+ if (!list) continue;
8667
+ Object.assign(merged, list);
8668
+ }
8669
+ return merged;
8670
+ };
8671
+ var isObjePointer = (value) => typeof value === "string" && /^@O\d+@$/.test(value);
8672
+
8673
+ // src/classes/note.ts
8674
+ var CommonNote = class extends Common {
8675
+ constructor(gedcom, id, main, parent) {
8676
+ super(gedcom, id, main, parent);
8677
+ if (!id) {
8678
+ delete this.id;
8679
+ }
8680
+ }
8681
+ set value(value) {
8682
+ const [note, ...contents] = value?.split(/\r?\n/) ?? [];
8683
+ this._value = note;
8684
+ if (contents.length) {
8685
+ const newContents = new List();
8686
+ contents.forEach((c, i) => {
8687
+ const newContent = createCommon(
8688
+ this._gedcom,
8689
+ void 0,
8690
+ this.main
8691
+ );
8692
+ newContent.id = `@U${i}@`;
8693
+ newContent.value = c;
8694
+ newContents.append(newContent);
8695
+ });
8696
+ const firstItem = newContents.index(0);
8697
+ if (firstItem) {
8698
+ if (newContents.length === 1) {
8699
+ this.set("CONT", firstItem);
8700
+ } else {
8701
+ this.set("CONT", newContents);
8702
+ }
8703
+ }
8704
+ }
8705
+ }
8706
+ get value() {
8707
+ const contents = this.get("CONT")?.toList().map((content) => content.value).join("\n");
8708
+ if (contents) {
8709
+ return `${this._value}
8710
+ ${contents}`;
8711
+ }
8712
+ return this._value;
8713
+ }
8714
+ exportValue() {
8715
+ return this._value;
8716
+ }
8717
+ };
8718
+ var createCommonNote = (gedcom, id, main, parent) => {
8719
+ return createProxy(
8720
+ new CommonNote(gedcom, id, main, parent)
8721
+ );
8722
+ };
8723
+
8724
+ // src/classes/obje.ts
8725
+ var Obje = class extends Common {
8726
+ standardizeMedia(namespace, override = true, urlGetter, gedcomVersion) {
8727
+ if (!this._gedcom) {
8728
+ return this;
8729
+ }
8730
+ const rin = this?.get("RIN")?.toValue();
8731
+ const clone = this?.get("_CLON._OID")?.toValue();
8732
+ const mser = this?.get("_MSER._LKID")?.toValue();
8733
+ const title = this?.get("FILE.TITL")?.toValue() ?? this?.get("TITL")?.toValue() ?? "";
8734
+ const note = this?.get("FILE.NOTE")?.toValue() ?? this?.get("NOTE")?.toValue() ?? "";
8735
+ const formRaw = this?.get("FILE.FORM")?.toValue() ?? this?.get("FORM")?.toValue();
8736
+ const mediType = this?.get("FILE.FORM.TYPE")?.toValue() ?? this?.get("FORM.TYPE")?.toValue() ?? this?.get("MEDI")?.toValue();
8737
+ const file = this?.get("FILE")?.toValue();
8738
+ const imgId = rin || clone || mser;
8739
+ const url = file || namespace && urlGetter?.(namespace, imgId);
8740
+ if (!url) {
8741
+ return this;
8742
+ }
8743
+ const version = normalizeGedcomVersion(
8744
+ gedcomVersion ?? this._gedcom.getGedcomVersion?.()
8745
+ );
8746
+ const form = formRaw || inferMediaForm(String(url));
8747
+ const newObject = createObje(this._gedcom, this.id, this.main);
8748
+ if (!override) {
8749
+ Object.assign(newObject, this);
8750
+ }
8751
+ const fileNode = createCommon(this._gedcom, void 0, this.main);
8752
+ fileNode.value = url;
8753
+ if (version === "7.0") {
8754
+ const formNode = createCommon(this._gedcom, void 0, fileNode);
8755
+ formNode.value = form;
8756
+ if (mediType) {
8757
+ formNode.set("TYPE", String(mediType));
8758
+ }
8759
+ fileNode.set("FORM", formNode);
8760
+ if (title) {
8761
+ fileNode.set("TITL", String(title));
8762
+ }
8763
+ if (note) {
8764
+ fileNode.set("NOTE", String(note));
8765
+ }
8766
+ newObject.set("FILE", fileNode);
8767
+ } else {
8768
+ newObject.set("FILE", fileNode);
8769
+ newObject.set("FORM", form);
8770
+ if (mediType) {
8771
+ newObject.set("MEDI", String(mediType));
8772
+ }
8773
+ if (title) {
8774
+ newObject.set("TITL", String(title));
8775
+ if (!note) {
8776
+ newObject.set("NOTE", String(title));
8777
+ }
8778
+ }
8779
+ if (note) {
8780
+ newObject.set("NOTE", String(note));
8781
+ if (!title) {
8782
+ newObject.set("TITL", String(note));
8783
+ }
8784
+ }
8785
+ }
8786
+ const prim = this.get("_PRIM")?.toValue();
8787
+ if (prim === "Y" || prim === "N") {
8788
+ newObject.set("_PRIM", prim);
8789
+ }
8790
+ const photoRin = this.get("_PHOTO_RIN")?.toValue();
8791
+ if (rin) {
8792
+ newObject.set("RIN", String(rin));
8793
+ }
8794
+ if (photoRin) {
8795
+ newObject.set("_PHOTO_RIN", String(photoRin));
8796
+ }
8797
+ const clonNode = this.get("_CLON");
8798
+ if (clonNode) {
8799
+ newObject.set("_CLON", clonNode);
8800
+ }
8801
+ const mserNode = this.get("_MSER");
8802
+ if (mserNode) {
8803
+ newObject.set("_MSER", mserNode);
8804
+ }
8805
+ const oidNode = this.get("_OID");
8806
+ if (oidNode && !newObject.get("_OID")) {
8807
+ newObject.set("_OID", oidNode);
8808
+ }
8809
+ const lkidNode = this.get("_LKID");
8810
+ if (lkidNode && !newObject.get("_LKID")) {
8811
+ newObject.set("_LKID", lkidNode);
8812
+ }
8813
+ if (override) {
8814
+ this.remove("FILE");
8815
+ this.remove("FORM");
8816
+ this.remove("MEDI");
8817
+ this.remove("TITL");
8818
+ this.remove("NOTE");
8819
+ Object.assign(this, newObject);
8820
+ return this;
8821
+ }
8822
+ return newObject;
8823
+ }
8824
+ };
8825
+ var createObje = (gedcom, id, main, parent) => {
8826
+ return createProxy(
8827
+ new Obje(gedcom, id, main, parent)
8828
+ );
8829
+ };
8830
+
8831
+ // src/classes/objes.ts
8832
+ var Objects = class _Objects extends List {
8833
+ copy() {
8834
+ const newList = new _Objects();
8835
+ this.entries().forEach(([key, value]) => {
8836
+ newList.item(key, value);
8837
+ });
8838
+ return newList;
8839
+ }
8840
+ except(item) {
8841
+ return this.copy().delete(item);
8842
+ }
8843
+ };
8844
+
8845
+ // src/classes/gedcom.ts
8846
+ var isObjectPatch = (value) => {
8847
+ return !!value && typeof value === "object" && !Array.isArray(value);
8848
+ };
8849
+ var GedCom = class extends Common {
8850
+ constructor() {
8851
+ super();
8852
+ this.tagMembers = {};
8853
+ this.reflist = {};
8854
+ this.refcount = 0;
8855
+ delete this._gedcom;
8856
+ delete this.id;
8857
+ this.removeValue();
8858
+ }
8859
+ getMain(type, index) {
8860
+ const list = !type || type instanceof List ? type : this.getList(type);
8861
+ if (!list) {
8862
+ return void 0;
8863
+ }
8864
+ if (typeof index === "string") {
8865
+ return list.item(index);
8866
+ }
8867
+ const keys = list.keys();
8868
+ return list.item(keys[index]);
8869
+ }
8870
+ getList(type) {
8871
+ return this.get(type);
8872
+ }
8873
+ createNodeFromPatchValue(value, main) {
8874
+ if (value === void 0 || value === null) {
8875
+ return void 0;
8876
+ }
8877
+ const node = createCommon(this, void 0, main);
8878
+ if (Array.isArray(value)) {
8879
+ value.forEach((item) => {
8880
+ const childNode = this.createNodeFromPatchValue(item, node);
8881
+ if (childNode) {
8882
+ node.assign("DATA", childNode);
8883
+ }
8884
+ });
8885
+ return node;
8886
+ }
8887
+ if (isObjectPatch(value)) {
8888
+ this.applyObjectToCommon(node, value);
8889
+ return node;
8890
+ }
8891
+ node.value = String(value);
8892
+ return node;
8893
+ }
8894
+ applyObjectToCommon(target, patch) {
8895
+ Object.entries(patch).forEach(([rawTag, value]) => {
8896
+ if (rawTag === "value") {
7706
8897
  if (value === null || value === void 0 || Array.isArray(value) || isObjectPatch(value)) {
7707
8898
  return;
7708
8899
  }
@@ -7869,6 +9060,9 @@ var GedCom = class extends Common {
7869
9060
  const id = this.nextIndiKey();
7870
9061
  const indi = createIndi(this, id);
7871
9062
  indi.type = "INDI";
9063
+ if (this.getGedcomVersion() === "7.0") {
9064
+ indi.set("UID", createGedcomUid());
9065
+ }
7872
9066
  indis.item(id, indi);
7873
9067
  return indi;
7874
9068
  }
@@ -7881,9 +9075,151 @@ var GedCom = class extends Common {
7881
9075
  const id = this.nextFamKey();
7882
9076
  const fam = createFam(this, id);
7883
9077
  fam.type = "FAM";
9078
+ if (this.getGedcomVersion() === "7.0") {
9079
+ fam.set("UID", createGedcomUid());
9080
+ }
7884
9081
  fams.item(id, fam);
7885
9082
  return fam;
7886
9083
  }
9084
+ nextObjeKey() {
9085
+ const ids = [];
9086
+ this.objes()?.forEach((_obje, id) => {
9087
+ ids.push(String(id));
9088
+ });
9089
+ return nextRecordId(ids, "O");
9090
+ }
9091
+ /**
9092
+ * Create a top-level multimedia record (`0 @On@ OBJE`) with FILE/FORM/TITL.
9093
+ * GEDCOM 7 uses nested `FILE → FORM [→ TYPE]`; 5.5.1 uses sibling FORM/TITL.
9094
+ */
9095
+ createMultimediaRecord(input) {
9096
+ const existing = this.objes();
9097
+ const objes = existing ?? new Objects();
9098
+ if (!existing) {
9099
+ this.set("@@OBJE", objes);
9100
+ }
9101
+ const id = this.nextObjeKey();
9102
+ const obje = createObje(this, id);
9103
+ obje.type = "OBJE";
9104
+ objes.item(id, obje);
9105
+ const version = normalizeGedcomVersion(
9106
+ input.gedcomVersion ?? this.getGedcomVersion()
9107
+ );
9108
+ const form = input.form || inferMediaForm(input.file);
9109
+ const fileNode = createCommon(this, void 0, obje);
9110
+ fileNode.value = input.file;
9111
+ if (version === "7.0") {
9112
+ const formNode = createCommon(
9113
+ this,
9114
+ void 0,
9115
+ fileNode
9116
+ );
9117
+ formNode.value = form;
9118
+ if (input.mediType) {
9119
+ formNode.set("TYPE", input.mediType);
9120
+ }
9121
+ fileNode.set("FORM", formNode);
9122
+ if (input.title) {
9123
+ fileNode.set("TITL", input.title);
9124
+ }
9125
+ obje.set("FILE", fileNode);
9126
+ } else {
9127
+ obje.set("FILE", fileNode);
9128
+ obje.set("FORM", form);
9129
+ if (input.mediType) {
9130
+ obje.set("MEDI", input.mediType);
9131
+ }
9132
+ if (input.title) {
9133
+ obje.set("TITL", input.title);
9134
+ }
9135
+ }
9136
+ if (input.primary) {
9137
+ obje.set("_PRIM", "Y");
9138
+ }
9139
+ if (normalizeGedcomVersion(
9140
+ input.gedcomVersion ?? this.getGedcomVersion()
9141
+ ) === "7.0") {
9142
+ obje.set("UID", createGedcomUid());
9143
+ }
9144
+ return obje;
9145
+ }
9146
+ nextSnoteKey() {
9147
+ const ids = [];
9148
+ this.snotes()?.forEach((_note, id) => {
9149
+ ids.push(String(id));
9150
+ });
9151
+ return nextRecordId(ids, "N");
9152
+ }
9153
+ snotes() {
9154
+ return this.getList("@@SNOTE");
9155
+ }
9156
+ snote(index) {
9157
+ return this.getMain(this.snotes(), index);
9158
+ }
9159
+ /**
9160
+ * Create a top-level shared note record (`0 @Nn@ SNOTE` for GEDCOM 7).
9161
+ */
9162
+ createSharedNote(text) {
9163
+ const existing = this.snotes();
9164
+ const notes = existing ?? new List();
9165
+ if (!existing) {
9166
+ this.set("@@SNOTE", notes);
9167
+ }
9168
+ const id = this.nextSnoteKey();
9169
+ const note = createCommonNote(this, id);
9170
+ note.type = "SNOTE";
9171
+ note.value = text;
9172
+ if (this.getGedcomVersion() === "7.0") {
9173
+ note.set("UID", createGedcomUid());
9174
+ }
9175
+ notes.item(id, note);
9176
+ return note;
9177
+ }
9178
+ registerExtensionTag(tag, uri) {
9179
+ return registerExtensionTag(this, tag, uri);
9180
+ }
9181
+ getExtensionSchema() {
9182
+ return getExtensionSchema(this);
9183
+ }
9184
+ ensureExtensionSchema(extraTags) {
9185
+ ensureExtensionSchema(this, extraTags);
9186
+ return getExtensionSchema(this);
9187
+ }
9188
+ /**
9189
+ * Collect multimedia descriptors via each individual's `multimedia()`.
9190
+ */
9191
+ async collectMultimedia(options) {
9192
+ const people = [];
9193
+ if (options?.indiIds?.length) {
9194
+ options.indiIds.forEach((id) => {
9195
+ const indi = this.indi(id);
9196
+ if (indi) {
9197
+ people.push(indi);
9198
+ }
9199
+ });
9200
+ } else {
9201
+ this.indis()?.forEach((indi) => {
9202
+ if (indi) {
9203
+ people.push(indi);
9204
+ }
9205
+ });
9206
+ }
9207
+ const lists = await Promise.all(
9208
+ people.map((indi) => indi.multimedia(options?.namespace))
9209
+ );
9210
+ return mergeMediaLists(...lists);
9211
+ }
9212
+ /**
9213
+ * Serialize as GEDCOM 7 and pack a FamilySearch GEDZIP (`.gdz`).
9214
+ * Media bytes must be supplied by the caller (cache/fetch outside the parser).
9215
+ */
9216
+ async toGedzip(options) {
9217
+ const text = this.toGedcom(void 0, 0, {
9218
+ ...options,
9219
+ gedcomVersion: "7.0"
9220
+ });
9221
+ return buildGedzip(text, options?.media ?? []);
9222
+ }
7887
9223
  objes() {
7888
9224
  return this.getList("@@OBJE");
7889
9225
  }
@@ -7968,9 +9304,52 @@ var GedCom = class extends Common {
7968
9304
  });
7969
9305
  return lists;
7970
9306
  }
7971
- getDownloadHeader() {
9307
+ getGedcomVersion() {
9308
+ const raw = this.get("HEAD")?.get("GEDC")?.get("VERS")?.toValue();
9309
+ return normalizeGedcomVersion(
9310
+ typeof raw === "string" ? raw : void 0
9311
+ );
9312
+ }
9313
+ /** Rewrite HEAD.GEDC (and CHAR/FORM) for the requested export version. */
9314
+ applyExportVersion(version) {
9315
+ const head = this.get("HEAD");
9316
+ if (!head) {
9317
+ return;
9318
+ }
9319
+ this.applyGedcomSpecToHead(head, normalizeGedcomVersion(version));
9320
+ }
9321
+ applyGedcomSpecToHead(head, version) {
9322
+ const previousGedc = head.get("GEDC");
9323
+ const previousForm = previousGedc?.get("FORM")?.toValue();
9324
+ const previousChar = head.get("CHAR")?.toValue();
9325
+ head.remove("GEDC");
9326
+ const gedc = head.set("GEDC", "");
9327
+ if (!gedc) {
9328
+ return;
9329
+ }
9330
+ gedc.set("VERS", version);
9331
+ if (version === "7.0") {
9332
+ head.remove("CHAR");
9333
+ return;
9334
+ }
9335
+ gedc.set(
9336
+ "FORM",
9337
+ typeof previousForm === "string" && previousForm ? previousForm : "LINEAGE-LINKED"
9338
+ );
9339
+ if (!head.get("CHAR")?.toValue()) {
9340
+ head.set(
9341
+ "CHAR",
9342
+ typeof previousChar === "string" && previousChar ? previousChar : "UTF-8"
9343
+ );
9344
+ }
9345
+ }
9346
+ getDownloadHeader(gedcomVersion) {
7972
9347
  const newHead = createCommon();
7973
9348
  Object.assign(newHead, this.get("HEAD") ?? {});
9349
+ this.applyGedcomSpecToHead(
9350
+ newHead,
9351
+ gedcomVersion ?? this.getGedcomVersion()
9352
+ );
7974
9353
  const existingSour = this.get("HEAD")?.get("SOUR");
7975
9354
  const existingTreeName = existingSour?.get("_TREE")?.toValue();
7976
9355
  const existingTreeUniqueId = existingSour?.get("_TID")?.toValue();
@@ -8017,22 +9396,45 @@ var GedCom = class extends Common {
8017
9396
  }
8018
9397
  toGedcom(tag, level, options) {
8019
9398
  if (options?.super) {
8020
- return appendGedcomTrailer(
8021
- super.toGedcom(tag, level, options)
8022
- );
9399
+ return appendGedcomTrailer(super.toGedcom(tag, level, options));
8023
9400
  }
9401
+ const requestedVersion = options?.gedcomVersion;
9402
+ const exportVersion = requestedVersion ? normalizeGedcomVersion(requestedVersion) : this.getGedcomVersion();
9403
+ const exportOptions = {
9404
+ ...options,
9405
+ obje: {
9406
+ standardize: options?.obje?.standardize ?? (requestedVersion !== void 0 || !options?.original),
9407
+ override: options?.obje?.override,
9408
+ namespace: options?.obje?.namespace
9409
+ }
9410
+ };
8024
9411
  const newGedcom = createGedCom();
8025
9412
  Object.assign(newGedcom, this);
8026
- if (!options?.original) {
9413
+ if (!exportOptions.original) {
8027
9414
  Object.assign(newGedcom, {
8028
- HEAD: this.getDownloadHeader()
9415
+ HEAD: this.getDownloadHeader(exportVersion)
8029
9416
  });
8030
9417
  }
8031
- if (options?.indis?.length) {
8032
- const newContent = this.getIndiRelatedLists(options.indis);
9418
+ if (exportOptions.indis?.length) {
9419
+ const newContent = this.getIndiRelatedLists(exportOptions.indis);
8033
9420
  Object.assign(newGedcom, newContent);
8034
9421
  }
8035
- return newGedcom.toGedcom(tag, level, { ...options, super: true });
9422
+ const restoreEnums = exportVersion === "7.0" ? applyGedcom7Enumerations(newGedcom) : void 0;
9423
+ const restoreDates = exportVersion === "7.0" ? applyGedcom7DatePhrases(newGedcom) : void 0;
9424
+ const restoreMetadata = exportVersion === "7.0" ? applyGedcom7RecordMetadata(newGedcom) : void 0;
9425
+ const restoreSchema = exportVersion === "7.0" ? ensureExtensionSchema(newGedcom) : void 0;
9426
+ try {
9427
+ return newGedcom.toGedcom(tag, level, {
9428
+ ...exportOptions,
9429
+ gedcomVersion: exportVersion,
9430
+ super: true
9431
+ });
9432
+ } finally {
9433
+ restoreSchema?.();
9434
+ restoreMetadata?.();
9435
+ restoreDates?.();
9436
+ restoreEnums?.();
9437
+ }
8036
9438
  }
8037
9439
  hasTag(tag) {
8038
9440
  const tagName = typeof tag === "string" ? tag : tag?.get("NAME")?.toValue();
@@ -8511,20 +9913,6 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
8511
9913
  return mergedGedcom;
8512
9914
  };
8513
9915
 
8514
- // src/classes/objes.ts
8515
- var Objects = class _Objects extends List {
8516
- copy() {
8517
- const newList = new _Objects();
8518
- this.entries().forEach(([key, value]) => {
8519
- newList.item(key, value);
8520
- });
8521
- return newList;
8522
- }
8523
- except(item) {
8524
- return this.copy().delete(item);
8525
- }
8526
- };
8527
-
8528
9916
  // src/classes/repos.ts
8529
9917
  var Repositories = class _Repositories extends List {
8530
9918
  copy() {
@@ -8567,144 +9955,6 @@ var Submitters = class _Submitters extends List {
8567
9955
  }
8568
9956
  };
8569
9957
 
8570
- // src/classes/note.ts
8571
- var CommonNote = class extends Common {
8572
- constructor(gedcom, id, main, parent) {
8573
- super(gedcom, id, main, parent);
8574
- delete this.id;
8575
- }
8576
- set value(value) {
8577
- const [note, ...contents] = value?.split(/\r?\n/) ?? [];
8578
- this._value = note;
8579
- if (contents.length) {
8580
- const newContents = new List();
8581
- contents.forEach((c, i) => {
8582
- const newContent = createCommon(
8583
- this._gedcom,
8584
- void 0,
8585
- this.main
8586
- );
8587
- newContent.id = `@U${i}@`;
8588
- newContent.value = c;
8589
- newContents.append(newContent);
8590
- });
8591
- const firstItem = newContents.index(0);
8592
- if (firstItem) {
8593
- if (newContents.length === 1) {
8594
- this.set("CONT", firstItem);
8595
- } else {
8596
- this.set("CONT", newContents);
8597
- }
8598
- }
8599
- }
8600
- }
8601
- get value() {
8602
- const contents = this.get("CONT")?.toList().map((content) => content.value).join("\n");
8603
- if (contents) {
8604
- return `${this._value}
8605
- ${contents}`;
8606
- }
8607
- return this._value;
8608
- }
8609
- exportValue() {
8610
- return this._value;
8611
- }
8612
- };
8613
- var createCommonNote = (gedcom, id, main, parent) => {
8614
- return createProxy(
8615
- new CommonNote(gedcom, id, main, parent)
8616
- );
8617
- };
8618
-
8619
- // src/classes/obje.ts
8620
- var Obje = class extends Common {
8621
- standardizeMedia(namespace, override = true, urlGetter) {
8622
- if (!this._gedcom) {
8623
- return this;
8624
- }
8625
- const rin = this?.get("RIN")?.toValue();
8626
- const clone = this?.get("_CLON._OID")?.toValue();
8627
- const mser = this?.get("_MSER._LKID")?.toValue();
8628
- const title = this?.get("FILE.TITL")?.toValue() ?? this?.get("TITL")?.toValue() ?? "";
8629
- const note = this?.get("FILE.NOTE")?.toValue() ?? this?.get("NOTE")?.toValue() ?? "";
8630
- const form = this?.get("FILE.FORM")?.toValue();
8631
- const file = this?.get("FILE")?.toValue();
8632
- const imgId = rin || clone || mser;
8633
- const url = file || namespace && urlGetter?.(namespace, imgId);
8634
- if (!url) {
8635
- return this;
8636
- }
8637
- const newObject = createObje(this._gedcom, this.id, this.main);
8638
- if (!override) {
8639
- Object.assign(newObject, this);
8640
- }
8641
- if (form) {
8642
- if (typeof form === "string") {
8643
- const newForm = createCommon(
8644
- this._gedcom,
8645
- void 0,
8646
- this.main
8647
- );
8648
- newForm.value = form;
8649
- newObject.set("FORM", newForm);
8650
- } else {
8651
- newObject.set("FORM", form);
8652
- }
8653
- }
8654
- if (title) {
8655
- if (typeof title === "string") {
8656
- const newTitle = createCommon(
8657
- this._gedcom,
8658
- void 0,
8659
- this.main
8660
- );
8661
- newTitle.value = title;
8662
- newObject.set("TITL", newTitle);
8663
- if (!note) {
8664
- newObject.set("NOTE", newTitle);
8665
- }
8666
- } else {
8667
- newObject.set("TITL", title);
8668
- if (!note) {
8669
- newObject.set("NOTE", title);
8670
- }
8671
- }
8672
- }
8673
- if (note) {
8674
- if (typeof note === "string") {
8675
- const newNote = createCommon(
8676
- this._gedcom,
8677
- void 0,
8678
- this.main
8679
- );
8680
- newNote.value = note;
8681
- newObject.set("NOTE", newNote);
8682
- if (!title) {
8683
- newObject.set("TITL", newNote);
8684
- }
8685
- } else {
8686
- newObject.set("NOTE", note);
8687
- if (!title) {
8688
- newObject.set("TITL", note);
8689
- }
8690
- }
8691
- }
8692
- const newUrl = createCommon(this._gedcom, void 0, this.main);
8693
- newUrl.value = url;
8694
- newObject.set("FILE", newUrl);
8695
- if (override) {
8696
- Object.assign(this, newObject);
8697
- return this;
8698
- }
8699
- return newObject;
8700
- }
8701
- };
8702
- var createObje = (gedcom, id, main, parent) => {
8703
- return createProxy(
8704
- new Obje(gedcom, id, main, parent)
8705
- );
8706
- };
8707
-
8708
9958
  // src/classes/repo.ts
8709
9959
  var Repo = class extends Common {
8710
9960
  };
@@ -8753,6 +10003,8 @@ var create = (gedcom, type, id, nodes) => {
8753
10003
  prevNode = createIndi(gedcom, id);
8754
10004
  } else if (convertType === "FAM") {
8755
10005
  prevNode = createFam(gedcom, id);
10006
+ } else if (convertType === "SNOTE" || convertType === "NOTE") {
10007
+ prevNode = createCommonNote(gedcom, id);
8756
10008
  } else {
8757
10009
  prevNode = createCommon(gedcom, id);
8758
10010
  }
@@ -8768,7 +10020,7 @@ var create = (gedcom, type, id, nodes) => {
8768
10020
  prevNode = createObje(gedcom, void 0, mainNode, curNode);
8769
10021
  } else if (type === "DATE") {
8770
10022
  prevNode = createCommonDate(gedcom, void 0, mainNode, curNode);
8771
- } else if (type === "NOTE") {
10023
+ } else if (type === "NOTE" || type === "SNOTE") {
8772
10024
  prevNode = createCommonNote(gedcom, void 0, mainNode, curNode);
8773
10025
  } else if (type === "NAME" && mainNode instanceof Indi) {
8774
10026
  prevNode = createCommonName(gedcom, void 0, mainNode, curNode);
@@ -8851,6 +10103,13 @@ var GedcomTree = {
8851
10103
  if (linesAcc._inHead && lineIndent === 1 && lineType === "FILE") {
8852
10104
  linesAcc._hasFile = true;
8853
10105
  }
10106
+ if (lineType.toUpperCase() === "CONC") {
10107
+ const last = acc[acc.length - 1];
10108
+ if (last !== void 0) {
10109
+ acc[acc.length - 1] = `${last}${lineValue}`;
10110
+ return acc;
10111
+ }
10112
+ }
8854
10113
  if (lineIndent > 0 && lineIndent > prevLineIndent && lineValue && isId(lineValue)) {
8855
10114
  const refLines = lineValue.split(/,\s*/).map((id) => line.replace(lineValue, id));
8856
10115
  if (refLines.length > 1) {
@@ -9049,4 +10308,4 @@ var createEmptyGedcom = (options) => {
9049
10308
  return gedcom;
9050
10309
  };
9051
10310
 
9052
- export { ACCEPTED_DATE_FORMATS, ACCEPTED_DATE_FORMATS_REGEX, ADOPTED, APP_BRANDING, BIOLOGICAL, BIRTH, BIRTH_ASC, BIRTH_DESC, Common, CommonDate, CommonName, CommonNote, CustomTags, DATE_ASC, DATE_DESC, DEATH_ASC, DEATH_DESC, DEFAULT, EVERY, Existed, FEMALE, FOSTER, FRIEND, Fam, Families, GedCom, parser_default as GedcomTree, ID_GETTER_REG, ID_REG, ID_SPLIT_REG, Indi, Individuals, KinshipTranslator, KinshipTranslatorBasic, KinshipTranslatorDe as KinshipTranslatorDE, KinshipTranslatorEn as KinshipTranslatorEN, KinshipTranslatorEs as KinshipTranslatorES, KinshipTranslatorFr as KinshipTranslatorFR, KinshipTranslatorHU, KinshipTranslatorRu as KinshipTranslatorRU, LINE_REG, List, MALE, MAX_FILE_SIZE_TO_SYNC, ORIG_HEAD_TAG, OTHER, Obje, Objects, PARTNER, PEDIGREE_VALUES, PartnerType, PlaceType, REF_LINE_REG, Range, RelationType, Repo, Repositories, SEALING, SINGLE, SPOUSE, STEP, Sour, Sources, Subm, Submitters, UNKOWN, addFamilyFact, addIndividualFact, attachChildToFamily, attachSpouseToFamily, cacheDiscoveredPath, canAttachAsSpouse, commonDateFormatter, create, createCommon, createCommonDate, createCommonName, createCommonNote, createEmptyGedcom, createFam, createGedCom, createIndi, createObje, createProxy, createRepo, createSour, createSubm, dateFormatter, parser_default as default, extractSeparationYears, extractSplitPoints, familyHasChild, familyHasParent, findMatchingRangeForSplitRange, findReusableParentChildFamily, firstPointerId, fromTuple, generateSplitRanges, getAllProp, getBirthAsc, getCacheManagerFactory, getDateLocale, getFamilyWith, getI18n, getKinshipTranslatorClass, getListTag, getMarriageAsc, getMarriageAscAndBirth, getMarriageAscAndChildBirth, getName, getNameAsc, getNameAscAndBirth, getNameDesc, getPlaceParserProvider, getPlaceParts, getPlaceTranslatorProvider, getPlaces, getRawSize, getValidKey, getValidKeys, getValidTag, getVersion, hungarianOrdinalize, i18n, idGetter, implemented, inRange, initializeCache, isCommonDate, isDevelopment, isGedcomString, isId, isIntersectedRange, isOnlyMainProp, isRangeContained, isValidKey, makePointer, marriageDateFormatter, mergeGedcoms, nameFormatter, nextRecordId, notImplemented, noteDateFormatter, ordinalize, parseRangeBounds, pathCache, placeTranslator, pointerIds, profilePictureCache, relativesCache, resetCacheManagerFactory, resetDateLocaleProvider, resetI18nProvider, resetKinshipTranslatorClass, resetPlaceParserProvider, resetPlaceTranslatorProvider, resetRelativesCache, setCacheManagerFactory, setCauseOfDeath, setChildPedigree, setDateLocaleProvider, setDeceased, setFamilyMarriage, setI18nProvider, setKinshipTranslatorClass, setNestedGroup, setPlaceParserProvider, setPlaceTranslatorProvider, splitOverlappingRanges, splitRange, spouseTagFor, toGedcomPedigree, translators_exports as translators, updateFactRecord, validateGedcomContent };
10311
+ export { ACCEPTED_DATE_FORMATS, ACCEPTED_DATE_FORMATS_REGEX, ADOPTED, APP_BRANDING, BIOLOGICAL, BIRTH, BIRTH_ASC, BIRTH_DESC, Common, CommonDate, CommonName, CommonNote, CustomTags, DATE_ASC, DATE_DESC, DEATH_ASC, DEATH_DESC, DEFAULT, DEFAULT_GEDCOM_EXPORT_VERSION, EVERY, Existed, FEMALE, FOSTER, FRIEND, Fam, Families, GEDCOM7_CALENDARS, GEDCOM7_PEDI_VALUES, GEDCOM7_RESN_VALUES, GEDCOM7_ROLE_VALUES, GEDCOM7_SEX_VALUES, GEDCOM_EXPORT_VERSIONS, GEDZIP_EXTENSION, GEDZIP_GEDCOM_ENTRY, GEDZIP_MIME, GedCom, parser_default as GedcomTree, ID_GETTER_REG, ID_REG, ID_SPLIT_REG, Indi, Individuals, KinshipTranslator, KinshipTranslatorBasic, KinshipTranslatorDe as KinshipTranslatorDE, KinshipTranslatorEn as KinshipTranslatorEN, KinshipTranslatorEs as KinshipTranslatorES, KinshipTranslatorFr as KinshipTranslatorFR, KinshipTranslatorHU, KinshipTranslatorRu as KinshipTranslatorRU, LINE_REG, List, MALE, MAX_FILE_SIZE_TO_SYNC, ORIG_HEAD_TAG, OTHER, Obje, Objects, PARTNER, PEDIGREE_VALUES, PartnerType, PlaceType, REF_LINE_REG, Range, RelationType, Repo, Repositories, SEALING, SINGLE, SPOUSE, STEP, Sour, Sources, Subm, Submitters, TREEVIZ_EXTENSION_BASE_URI, TREEVIZ_EXTENSION_URIS, UNKOWN, addFamilyFact, addIndividualFact, addNonEvent, applyGedcom7DatePhrases, applyGedcom7Enumerations, applyGedcom7RecordMetadata, attachChildToFamily, attachSpouseToFamily, buildGedzip, buildGedzipBlob, bytesToDataUrl, cacheDiscoveredPath, canAttachAsSpouse, collectExtensionTagsFrom, commonDateFormatter, create, createCommon, createCommonDate, createCommonName, createCommonNote, createEmptyGedcom, createFam, createGedCom, createGedcomUid, createIndi, createObje, createProxy, createRepo, createSour, createSubm, dateFormatter, parser_default as default, downloadGedzipMedia, ensureExtensionSchema, extractGedzip, extractGedzipGedcom, extractSeparationYears, extractSplitPoints, familyHasChild, familyHasParent, findMatchingRangeForSplitRange, findReusableParentChildFamily, firstPointerId, formatGedcom7Timestamp, fromTuple, generateSplitRanges, getAllProp, getBirthAsc, getCacheManagerFactory, getDateLocale, getExtensionSchema, getFamilyWith, getFileExtension, getI18n, getKinshipTranslatorClass, getListTag, getMarriageAsc, getMarriageAscAndBirth, getMarriageAscAndChildBirth, getName, getNameAsc, getNameAscAndBirth, getNameDesc, getPlaceParserProvider, getPlaceParts, getPlaceTranslatorProvider, getPlaces, getRawSize, getValidKey, getValidKeys, getValidTag, getVersion, hungarianOrdinalize, i18n, idGetter, implemented, inRange, inferMediaForm, initializeCache, isCommonDate, isDevelopment, isGedcom7, isGedcomString, isGedzipContainer, isId, isImageFormat, isIntersectedRange, isObjePointer, isOnlyMainProp, isRangeContained, isRemoteOrEmbeddedMediaUrl, isValidKey, makePointer, marriageDateFormatter, mergeGedcoms, mergeMediaLists, nameFormatter, nextRecordId, normalizeGedcomVersion, notImplemented, noteDateFormatter, ordinalize, parseGedcom7CalendarPrefix, parseRangeBounds, pathCache, placeTranslator, pointerIds, profilePictureCache, registerExtensionTag, relativesCache, remountGedzipMediaAsDataUrls, resetCacheManagerFactory, resetDateLocaleProvider, resetI18nProvider, resetKinshipTranslatorClass, resetPlaceParserProvider, resetPlaceTranslatorProvider, resetRelativesCache, resolveLocalMediaUrl, resolveMediaContent, resolveObjeForm, rewriteGedcomFilePaths, setCacheManagerFactory, setCauseOfDeath, setChildPedigree, setDateLocaleProvider, setDeceased, setFamilyMarriage, setI18nProvider, setKinshipTranslatorClass, setLocalMediaResolver, setMediaContentResolver, setNestedGroup, setPlaceParserProvider, setPlaceTranslatorProvider, splitOverlappingRanges, splitRange, spouseTagFor, toGedcomPedigree, translators_exports as translators, updateFactRecord, validateGedcomContent, withGedcom7Calendar };