@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
@@ -723,11 +723,17 @@ var List = class _List {
723
723
  const gedcom = [];
724
724
  this.entries().forEach(([_, item]) => {
725
725
  const validTag = getValidTag(tag);
726
- const validKey = item.id;
727
- const validValue = validKey ? validTag : item.exportValue();
728
- gedcom.push(
729
- `${level} ${validKey || validTag}${validValue ? ` ${validValue}` : ""}`
730
- );
726
+ const xref = item.id;
727
+ const payload = item.exportValue?.();
728
+ if (xref) {
729
+ gedcom.push(
730
+ `${level} ${xref} ${validTag}${payload ? ` ${payload}` : ""}`
731
+ );
732
+ } else {
733
+ gedcom.push(
734
+ `${level} ${validTag}${payload ? ` ${payload}` : ""}`
735
+ );
736
+ }
731
737
  gedcom.push(
732
738
  ...item.toGedcomLines(
733
739
  validTag,
@@ -985,12 +991,14 @@ var Common = class _Common {
985
991
  );
986
992
  }
987
993
  standardizeObject(tag, options) {
988
- if (tag === "OBJE" && !options?.original && options?.obje?.standardize && options?.obje?.namespace && "standardizeMedia" in this) {
994
+ if (tag === "OBJE" && options?.obje?.standardize && "standardizeMedia" in this) {
989
995
  const standardize = this.standardizeMedia;
990
996
  return standardize.call(
991
997
  this,
992
998
  options.obje.namespace,
993
- options.obje.override
999
+ options.obje.override,
1000
+ void 0,
1001
+ options.gedcomVersion
994
1002
  );
995
1003
  }
996
1004
  }
@@ -1017,7 +1025,7 @@ var Common = class _Common {
1017
1025
  if (typeof prop?.toObject === "function") {
1018
1026
  if (prop instanceof _Common) {
1019
1027
  json[validKey] = prop.toObject(validKey, options);
1020
- } else {
1028
+ } else if (prop instanceof List) {
1021
1029
  json = {
1022
1030
  ...json,
1023
1031
  ...prop.toObject(validKey, options)
@@ -1075,8 +1083,12 @@ var Common = class _Common {
1075
1083
  this.standardizeObject(tag, options);
1076
1084
  const validKeys = getValidKeys(this);
1077
1085
  const gedcom = [];
1086
+ const isGedcom7Export = options?.gedcomVersion === "7.0";
1078
1087
  validKeys.forEach((key) => {
1079
1088
  const validKey = key;
1089
+ if (isGedcom7Export && validKey === "CONC") {
1090
+ return;
1091
+ }
1080
1092
  const prop = this.get(validKey);
1081
1093
  if (typeof prop?.toGedcomLines === "function") {
1082
1094
  if (prop instanceof _Common) {
@@ -1087,7 +1099,7 @@ var Common = class _Common {
1087
1099
  gedcom.push(
1088
1100
  ...prop.toGedcomLines(validKey, level + 1, options)
1089
1101
  );
1090
- } else {
1102
+ } else if (prop instanceof List) {
1091
1103
  gedcom.push(
1092
1104
  ...prop.toGedcomLines(validKey, level, options)
1093
1105
  );
@@ -1428,7 +1440,11 @@ var STANDARD_QUALIFIERS = {
1428
1440
  BEF: "Bef.",
1429
1441
  BEFORE: "Bef.",
1430
1442
  AFT: "Aft.",
1431
- AFTER: "Aft."
1443
+ AFTER: "Aft.",
1444
+ CAL: "Abt.",
1445
+ // calculated ≈ about for display
1446
+ EST: "Abt."
1447
+ // estimated ≈ about for display
1432
1448
  };
1433
1449
  var EXPORT_QUALIFIERS = {
1434
1450
  "Abt.": "ABT",
@@ -1436,6 +1452,11 @@ var EXPORT_QUALIFIERS = {
1436
1452
  "Aft.": "AFT"
1437
1453
  };
1438
1454
  var GEDCOM_MONTHS = /\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b/g;
1455
+ var CALENDAR_PREFIX = /^(?<calendar>GREGORIAN|JULIAN|FRENCH_R|HEBREW)\b\s+/i;
1456
+ var isGedcomDateValueForm = (value) => (
1457
+ // Require space/end after the token so display forms like "Abt." are not opaque.
1458
+ /^(FROM|TO|BET|AFT|BEF|ABT|CAL|EST|INT)(\s|$)/i.test(value) || /\bAND\b/i.test(value)
1459
+ );
1439
1460
  var NOTE_MARKER = "####";
1440
1461
  var formatDateWithComponents = (date, hasDay, hasMonth, hasYear, noteValue, baseFormat = "dd MMM yyyy", locale) => {
1441
1462
  const hasNote = baseFormat.includes("NOTE");
@@ -1460,29 +1481,45 @@ var CommonDate = class extends Common {
1460
1481
  super(gedcom, id, main, parent);
1461
1482
  delete this.id;
1462
1483
  }
1484
+ get calendar() {
1485
+ return this._calendar;
1486
+ }
1463
1487
  set value(value) {
1464
1488
  if (value) {
1465
- const noteRegExp = /^(?<note>[a-zA-Z]+\.)/;
1466
- const noteMatch = value.match(noteRegExp)?.groups;
1467
1489
  let validValue = value;
1490
+ const calendarMatch = validValue.match(CALENDAR_PREFIX);
1491
+ if (calendarMatch?.groups?.calendar) {
1492
+ this._calendar = calendarMatch.groups.calendar.toUpperCase();
1493
+ validValue = validValue.slice(calendarMatch[0].length);
1494
+ } else {
1495
+ this._calendar = void 0;
1496
+ }
1497
+ const noteRegExp = /^(?<note>[a-zA-Z]+\.)/;
1498
+ const noteMatch = validValue.match(noteRegExp)?.groups;
1468
1499
  if (noteMatch?.note) {
1469
1500
  this.NOTE = this.NOTE || createCommon(this._gedcom, void 0, this.main);
1470
1501
  this.NOTE.value = noteMatch?.note;
1471
- validValue = value.replace(noteRegExp, "");
1502
+ validValue = validValue.replace(noteRegExp, "");
1472
1503
  } else {
1473
- const qualifierMatch = value.match(
1474
- /^(?<qualifier>ABT|ABOUT|BEF|BEFORE|AFT|AFTER)\b\s*/i
1504
+ const qualifierMatch = validValue.match(
1505
+ /^(?<qualifier>ABT|ABOUT|BEF|BEFORE|AFT|AFTER|CAL|EST)\b\s*/i
1475
1506
  );
1476
1507
  const qualifier = qualifierMatch?.groups?.qualifier?.toUpperCase();
1477
1508
  const note = qualifier ? STANDARD_QUALIFIERS[qualifier] : void 0;
1478
1509
  if (note) {
1479
1510
  this.NOTE = this.NOTE || createCommon(this._gedcom, void 0, this.main);
1480
1511
  this.NOTE.value = note;
1481
- validValue = value.slice(qualifierMatch[0].length);
1512
+ validValue = validValue.slice(qualifierMatch[0].length);
1482
1513
  }
1483
1514
  }
1484
1515
  const acceptedDate = this.isValidDateFormat(validValue);
1485
- if (acceptedDate) {
1516
+ if (isGedcomDateValueForm(validValue.trim())) {
1517
+ delete this.DAY;
1518
+ delete this.MONTH;
1519
+ delete this.YEAR;
1520
+ this._date = void 0;
1521
+ this._value = value;
1522
+ } else if (acceptedDate) {
1486
1523
  this.DAY = this.DAY || createCommon(this._gedcom, void 0, this.main);
1487
1524
  this.DAY.value = format(acceptedDate, "dd");
1488
1525
  this.MONTH = this.MONTH || createCommon(this._gedcom, void 0, this.main);
@@ -1585,6 +1622,15 @@ var CommonDate = class extends Common {
1585
1622
  );
1586
1623
  }
1587
1624
  exportValue() {
1625
+ if (typeof this._value === "string") {
1626
+ const withoutCalendar = this._value.replace(CALENDAR_PREFIX, "");
1627
+ if (isGedcomDateValueForm(withoutCalendar.trim())) {
1628
+ return this._value.replace(
1629
+ /^((?:GREGORIAN|JULIAN|FRENCH_R|HEBREW)\s+)?(FROM|TO|BET|AFT|BEF|ABT|CAL|EST|INT)\b/i,
1630
+ (_m, cal, q) => `${cal || ""}${q.toUpperCase()}`
1631
+ );
1632
+ }
1633
+ }
1588
1634
  const formatted = this.toValue("NOTE dd MMM yyyy", null);
1589
1635
  if (!formatted) {
1590
1636
  return formatted;
@@ -1592,10 +1638,14 @@ var CommonDate = class extends Common {
1592
1638
  const note = this.NOTE?.value?.trim();
1593
1639
  const qualifier = note ? EXPORT_QUALIFIERS[note] : void 0;
1594
1640
  const standardized = qualifier ? formatted.replace(note, qualifier) : formatted;
1595
- return standardized.replace(
1641
+ const withMonths = standardized.replace(
1596
1642
  GEDCOM_MONTHS,
1597
1643
  (month) => month.toUpperCase()
1598
1644
  );
1645
+ if (this._calendar && this._calendar !== "GREGORIAN") {
1646
+ return `${this._calendar} ${withMonths}`;
1647
+ }
1648
+ return withMonths;
1599
1649
  }
1600
1650
  toGedcomLines(tag, level = 0, options) {
1601
1651
  const internal = new RegExp(
@@ -2127,6 +2177,24 @@ var addFamilyFact = (fam, input) => {
2127
2177
  fillFact(gedcom, fam, event, input);
2128
2178
  return event;
2129
2179
  };
2180
+ var addNonEvent = (owner, input) => {
2181
+ const gedcom = owner.getGedcom();
2182
+ const eventType = input.event?.trim().toUpperCase();
2183
+ if (!gedcom || !eventType) {
2184
+ return void 0;
2185
+ }
2186
+ const no = createCommon(gedcom, void 0, owner);
2187
+ no.type = "NO";
2188
+ no.value = eventType;
2189
+ if (input.date?.trim()) {
2190
+ setDateOn(gedcom, owner, no, input.date);
2191
+ }
2192
+ if (input.note?.trim()) {
2193
+ no.set("NOTE", input.note.trim());
2194
+ }
2195
+ owner.assign("NO", no);
2196
+ return no;
2197
+ };
2130
2198
 
2131
2199
  // src/utils/family-edit.ts
2132
2200
  var PEDIGREE_VALUES = [
@@ -2353,16 +2421,58 @@ var getPlaces = (common, type = ["ALL" /* All */], maxLevel = 1, level = 0, main
2353
2421
  });
2354
2422
  return places;
2355
2423
  };
2424
+
2425
+ // src/utils/local-media.ts
2426
+ var localMediaResolver;
2427
+ var isRemoteOrEmbeddedMediaUrl = (path) => {
2428
+ if (!path) {
2429
+ return false;
2430
+ }
2431
+ return path.startsWith("data:") || path.startsWith("blob:") || /^https?:\/\//i.test(path);
2432
+ };
2433
+ var resolveLocalMediaUrl = async (path) => {
2434
+ if (!path) {
2435
+ return void 0;
2436
+ }
2437
+ if (isRemoteOrEmbeddedMediaUrl(path)) {
2438
+ return path;
2439
+ }
2440
+ const resolved = await localMediaResolver?.(path);
2441
+ return resolved;
2442
+ };
2356
2443
  var implemented = (type, ...args) => {
2357
2444
  };
2358
2445
 
2359
2446
  // src/utils/media-utils.ts
2360
2447
  var getFileExtension = (filename) => {
2361
- const match = filename.match(/\.([^.]+)$/);
2362
- return match ? match[1] : "";
2448
+ if (!filename) {
2449
+ return "";
2450
+ }
2451
+ if (filename.startsWith("data:")) {
2452
+ const mime = filename.slice(5).split(";")[0] || "";
2453
+ const subtype = (mime.split("/")[1] || "").toLowerCase();
2454
+ if (subtype === "jpeg") {
2455
+ return "jpg";
2456
+ }
2457
+ return subtype.split("+")[0] || "";
2458
+ }
2459
+ const withoutQuery = filename.split(/[?#]/)[0] || filename;
2460
+ const match = withoutQuery.match(/\.([^.]+)$/);
2461
+ return match ? match[1].toLowerCase() : "";
2363
2462
  };
2364
2463
  var isImageFormat = (format2) => {
2365
- if (!format2) return false;
2464
+ if (!format2) {
2465
+ return false;
2466
+ }
2467
+ let normalized = format2.toLowerCase().trim();
2468
+ if (normalized.startsWith("data:")) {
2469
+ normalized = getFileExtension(normalized);
2470
+ } else if (normalized.includes("/")) {
2471
+ normalized = normalized.split("/")[1]?.split("+")[0] || "";
2472
+ if (normalized === "jpeg") {
2473
+ normalized = "jpg";
2474
+ }
2475
+ }
2366
2476
  const imageFormats = [
2367
2477
  "jpg",
2368
2478
  "jpeg",
@@ -2374,7 +2484,11 @@ var isImageFormat = (format2) => {
2374
2484
  "tiff",
2375
2485
  "tif"
2376
2486
  ];
2377
- return imageFormats.includes(format2.toLowerCase());
2487
+ return imageFormats.includes(normalized);
2488
+ };
2489
+ var resolveObjeForm = (obje) => {
2490
+ const value = obje?.get?.("FILE.FORM")?.toValue?.() ?? obje?.get?.("FORM")?.toValue?.();
2491
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2378
2492
  };
2379
2493
 
2380
2494
  // src/factories/place-parser-provider.ts
@@ -2972,6 +3086,9 @@ var Fam = class extends Common {
2972
3086
  addFact(input) {
2973
3087
  return addFamilyFact(this, input);
2974
3088
  }
3089
+ addNonEvent(input) {
3090
+ return addNonEvent(this, input);
3091
+ }
2975
3092
  toList() {
2976
3093
  return new Families().concat(
2977
3094
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -3690,10 +3807,14 @@ var Indi = class extends Common {
3690
3807
  const clone = obje?.get("_CLON._OID")?.toValue();
3691
3808
  const mser = obje?.get("_MSER._LKID")?.toValue();
3692
3809
  let url = obje?.get("FILE")?.toValue();
3693
- const title = obje?.get("TITL")?.toValue() ?? "";
3694
- const type = obje?.get("FORM")?.toValue() ?? "raw";
3695
- const imgId = clone || mser;
3696
- if (!www || !tree || !this.id) {
3810
+ const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
3811
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
3812
+ let imgId = clone || mser;
3813
+ const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
3814
+ if (!hasEmbeddedOrLocalFile && (!www || !tree || !this.id)) {
3815
+ return;
3816
+ }
3817
+ if (!this.id) {
3697
3818
  return;
3698
3819
  }
3699
3820
  if (!namespace && !url) {
@@ -3711,13 +3832,16 @@ var Indi = class extends Common {
3711
3832
  }
3712
3833
  url = url || `https://${www}/mediaui-viewer/tree/${tree}/media/${media}`;
3713
3834
  }
3835
+ if (!imgId && hasEmbeddedOrLocalFile && url) {
3836
+ imgId = typeof media === "string" && media || `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}`;
3837
+ }
3714
3838
  if (url && imgId) {
3715
- const id = `${tree}-${this.id}-${imgId}`;
3839
+ const id = `${tree || "gedzip"}-${this.id}-${imgId}`;
3716
3840
  list[id] = {
3717
3841
  key,
3718
3842
  isPrimary,
3719
3843
  id,
3720
- tree,
3844
+ tree: tree || "gedzip",
3721
3845
  imgId,
3722
3846
  person: this.id,
3723
3847
  title,
@@ -3763,9 +3887,11 @@ var Indi = class extends Common {
3763
3887
  obje.standardizeMedia();
3764
3888
  const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
3765
3889
  const url = obje?.get("FILE")?.toValue();
3766
- const title = obje?.get("NOTE")?.toValue() ?? "";
3767
- const type = obje?.get("FORM")?.toValue() ?? "raw";
3768
- const imgId = obje?.get("_PHOTO_RIN")?.toValue();
3890
+ const title = obje?.get("FILE.NOTE")?.toValue() ?? obje?.get("NOTE")?.toValue() ?? "";
3891
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
3892
+ const photoRin = obje?.get("_PHOTO_RIN")?.toValue();
3893
+ const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
3894
+ const imgId = photoRin || (hasEmbeddedOrLocalFile && url ? `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}` : void 0);
3769
3895
  if (url && imgId) {
3770
3896
  const id = `${tree}-${this.id}-${imgId}`;
3771
3897
  list[id] = {
@@ -3888,10 +4014,10 @@ var Indi = class extends Common {
3888
4014
  const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
3889
4015
  const url = obje?.get("FILE")?.toValue();
3890
4016
  const title = obje?.get("TITL")?.toValue() ?? "";
3891
- const type = obje?.get("FORM")?.toValue() ?? "raw";
4017
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
3892
4018
  if (url) {
3893
4019
  const urlMatch = url.match(/\/([^/]+)\?hash=/);
3894
- const imgId = urlMatch?.[1] || `img-${index}-${Date.now().toString(36)}`;
4020
+ const imgId = urlMatch?.[1] || (url.startsWith("data:") ? `data-${index}-${getFileExtension(url) || "bin"}` : `img-${index}-${Date.now().toString(36)}`);
3895
4021
  const id = `geni-${geniId}-${imgId}`;
3896
4022
  list[id] = {
3897
4023
  isPrimary,
@@ -3928,10 +4054,10 @@ var Indi = class extends Common {
3928
4054
  obje.standardizeMedia();
3929
4055
  const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
3930
4056
  const url = obje?.get("FILE")?.toValue();
3931
- const title = obje?.get("TITL")?.toValue() ?? "";
3932
- const type = obje?.get("FORM")?.toValue() ?? "raw";
4057
+ const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
4058
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
3933
4059
  if (url) {
3934
- const imgId = `media-${index}-${url.split("/").pop()?.split("?")[0]?.substring(0, 20) || Date.now().toString(36)}`;
4060
+ const imgId = `media-${index}-${url.startsWith("data:") ? getFileExtension(url) || "bin" : url.split("/").pop()?.split("?")[0]?.substring(0, 20) || Date.now().toString(36)}`;
3935
4061
  const id = `${treeId}-${this.id}-${imgId}`;
3936
4062
  list[id] = {
3937
4063
  isPrimary,
@@ -3971,7 +4097,20 @@ var Indi = class extends Common {
3971
4097
  cacheKey
3972
4098
  );
3973
4099
  if (cached !== void 0) {
3974
- return cached;
4100
+ if (cached?.file && !isRemoteOrEmbeddedMediaUrl(cached.file)) {
4101
+ const resolvedCached = await resolveLocalMediaUrl(cached.file);
4102
+ if (resolvedCached && isRemoteOrEmbeddedMediaUrl(resolvedCached)) {
4103
+ const refreshed = { ...cached, file: resolvedCached };
4104
+ profilePictureCache(
4105
+ this._gedcom,
4106
+ cacheKey,
4107
+ refreshed
4108
+ );
4109
+ return refreshed;
4110
+ }
4111
+ } else {
4112
+ return cached;
4113
+ }
3975
4114
  }
3976
4115
  const mediaList = await this.multimedia(namespace);
3977
4116
  if (!mediaList) {
@@ -3983,39 +4122,40 @@ var Indi = class extends Common {
3983
4122
  return void 0;
3984
4123
  }
3985
4124
  const mediaArray = Object.values(mediaList);
3986
- const primaryMedia = mediaArray.find(
3987
- (media) => media.isPrimary && isImageFormat(media.contentType || getFileExtension(media.url))
3988
- );
3989
- if (primaryMedia) {
3990
- const result = {
3991
- file: primaryMedia.url,
3992
- form: primaryMedia.contentType,
3993
- title: primaryMedia.title,
3994
- isPrimary: true
4125
+ const toDisplayableProfile = async (media, isPrimary) => {
4126
+ const resolvedFile = await resolveLocalMediaUrl(media.url);
4127
+ if (!resolvedFile || !isRemoteOrEmbeddedMediaUrl(resolvedFile)) {
4128
+ return void 0;
4129
+ }
4130
+ return {
4131
+ file: resolvedFile,
4132
+ form: media.contentType,
4133
+ title: media.title,
4134
+ isPrimary
3995
4135
  };
3996
- profilePictureCache(this._gedcom, cacheKey, result);
3997
- return result;
3998
- }
3999
- if (onlyPrimary) {
4000
- profilePictureCache(
4001
- this._gedcom,
4002
- cacheKey,
4003
- void 0
4004
- );
4005
- return void 0;
4006
- }
4007
- const secondaryMedia = mediaArray.find(
4008
- (media) => isImageFormat(media.contentType || getFileExtension(media.url))
4136
+ };
4137
+ const candidates = mediaArray.filter(
4138
+ (media) => isImageFormat(
4139
+ media.contentType || media.url || getFileExtension(media.url)
4140
+ )
4009
4141
  );
4010
- if (secondaryMedia) {
4011
- const result = {
4012
- file: secondaryMedia.url,
4013
- form: secondaryMedia.contentType,
4014
- title: secondaryMedia.title,
4015
- isPrimary: false
4016
- };
4017
- profilePictureCache(this._gedcom, cacheKey, result);
4018
- return result;
4142
+ const ordered = [
4143
+ ...candidates.filter((media) => media.isPrimary),
4144
+ ...candidates.filter((media) => !media.isPrimary)
4145
+ ];
4146
+ for (const media of ordered) {
4147
+ if (onlyPrimary && !media.isPrimary) {
4148
+ break;
4149
+ }
4150
+ const result = await toDisplayableProfile(media, !!media.isPrimary);
4151
+ if (result) {
4152
+ profilePictureCache(
4153
+ this._gedcom,
4154
+ cacheKey,
4155
+ result
4156
+ );
4157
+ return result;
4158
+ }
4019
4159
  }
4020
4160
  profilePictureCache(
4021
4161
  this._gedcom,
@@ -4301,9 +4441,108 @@ var Indi = class extends Common {
4301
4441
  addParent(parent, pedigree) {
4302
4442
  return parent.addChild(this, pedigree);
4303
4443
  }
4444
+ /**
4445
+ * Link an existing top-level OBJE record to this individual (`1 OBJE @On@`).
4446
+ */
4447
+ attachMultimedia(objeOrKey, options) {
4448
+ if (!this._gedcom || !this.id) {
4449
+ return void 0;
4450
+ }
4451
+ const obje = typeof objeOrKey === "string" ? this._gedcom.obje(objeOrKey) : objeOrKey;
4452
+ if (!obje?.id) {
4453
+ return void 0;
4454
+ }
4455
+ const already = this.get("OBJE")?.toList()?.values()?.some((item) => item?.toValue?.() === obje.id);
4456
+ if (!already) {
4457
+ const pointer = makePointer(
4458
+ this._gedcom,
4459
+ this,
4460
+ obje.id,
4461
+ "OBJE"
4462
+ );
4463
+ this.assign("OBJE", pointer);
4464
+ }
4465
+ if (options?.primary) {
4466
+ this.get("OBJE")?.toList()?.forEach((item) => {
4467
+ const target = item?.refType === "OBJE" ? this._gedcom?.obje(
4468
+ String(item.toValue())
4469
+ ) : item;
4470
+ if (!target) {
4471
+ return;
4472
+ }
4473
+ if (target.id === obje.id) {
4474
+ target.set("_PRIM", "Y");
4475
+ } else if (target.get("_PRIM")?.toValue() === "Y") {
4476
+ target.set("_PRIM", "N");
4477
+ }
4478
+ });
4479
+ obje.set("_PRIM", "Y");
4480
+ }
4481
+ return obje;
4482
+ }
4483
+ detachMultimedia(objeKey) {
4484
+ const list = this.get("OBJE")?.toList();
4485
+ if (!list) {
4486
+ return;
4487
+ }
4488
+ const toRemove = list.values().filter(
4489
+ (item) => item?.toValue?.() === objeKey || item?.id === objeKey
4490
+ );
4491
+ toRemove.forEach((item) => {
4492
+ if (item) {
4493
+ list.delete(item);
4494
+ }
4495
+ });
4496
+ if (list.length === 0) {
4497
+ this.remove("OBJE");
4498
+ }
4499
+ }
4500
+ /**
4501
+ * Create a multimedia record and attach it to this person.
4502
+ */
4503
+ attachMediaFromUrl(url, options) {
4504
+ if (!this._gedcom || !url) {
4505
+ return void 0;
4506
+ }
4507
+ const obje = this._gedcom.createMultimediaRecord({
4508
+ file: url,
4509
+ form: options?.form,
4510
+ title: options?.title,
4511
+ mediType: options?.mediType,
4512
+ primary: options?.primary,
4513
+ gedcomVersion: options?.gedcomVersion
4514
+ });
4515
+ return this.attachMultimedia(obje, { primary: options?.primary });
4516
+ }
4517
+ /**
4518
+ * Link a shared SNOTE record via `1 NOTE @Nn@` (GEDCOM 7).
4519
+ */
4520
+ attachSharedNote(noteOrKey) {
4521
+ if (!this._gedcom || !this.id) {
4522
+ return void 0;
4523
+ }
4524
+ const note = typeof noteOrKey === "string" ? this._gedcom.snote(noteOrKey) : noteOrKey;
4525
+ if (!note?.id) {
4526
+ return void 0;
4527
+ }
4528
+ const already = this.get("NOTE")?.toList()?.values()?.some((item) => item?.toValue?.() === note.id);
4529
+ if (!already) {
4530
+ const pointer = makePointer(
4531
+ this._gedcom,
4532
+ this,
4533
+ note.id,
4534
+ "SNOTE"
4535
+ );
4536
+ this.assign("NOTE", pointer);
4537
+ }
4538
+ return note;
4539
+ }
4304
4540
  addFact(input) {
4305
4541
  return addIndividualFact(this, input);
4306
4542
  }
4543
+ addNonEvent(input) {
4544
+ return addNonEvent(this, input);
4545
+ }
4307
4546
  getParentType(id) {
4308
4547
  let indi;
4309
4548
  if (typeof id === "string" || typeof id === "number") {
@@ -4344,7 +4583,7 @@ var Indi = class extends Common {
4344
4583
  if (!famChild) {
4345
4584
  const childIndi = this._gedcom?.indi(child.id);
4346
4585
  const childState = childIndi?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
4347
- childType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
4586
+ childType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
4348
4587
  } else {
4349
4588
  childType = famChild.get(usedRel)?.toValue() || "biological" /* BIOLOGICAL */;
4350
4589
  }
@@ -4905,7 +5144,7 @@ var Indi = class extends Common {
4905
5144
  return;
4906
5145
  }
4907
5146
  const childState = child?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
4908
- const childType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
5147
+ const childType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
4909
5148
  if (childType?.toLowerCase() === filter.PEDI.toLowerCase()) {
4910
5149
  children.append(child);
4911
5150
  }
@@ -5013,7 +5252,7 @@ var Indi = class extends Common {
5013
5252
  const child = this.id && family.CHIL?.toValueList()?.item(this.id);
5014
5253
  if (!child) {
5015
5254
  const childState = this?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
5016
- const parentType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
5255
+ const parentType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
5017
5256
  if (parentType?.toLowerCase() === filter.PEDI.toLowerCase()) {
5018
5257
  parents.merge(family.getParents());
5019
5258
  }
package/dist/index.d.ts CHANGED
@@ -15,7 +15,17 @@ export * from "./utils/cache";
15
15
  export * from "./utils/common-creator";
16
16
  export * from "./utils/date-formatter";
17
17
  export * from "./utils/family-edit";
18
+ export * from "./utils/gedcom-version";
19
+ export * from "./utils/gedcom7-dates";
20
+ export * from "./utils/gedcom7-enumerations";
21
+ export * from "./utils/gedcom7-metadata";
22
+ export * from "./utils/gedcom7-schema";
23
+ export * from "./utils/gedzip";
18
24
  export * from "./utils/fact-edit";
25
+ export * from "./utils/local-media";
26
+ export * from "./utils/media-utils";
27
+ export * from "./utils/multimedia";
28
+ export * from "./utils/uid";
19
29
  export * from "./utils/get-all-prop";
20
30
  export * from "./utils/get-family-with";
21
31
  export * from "./utils/get-places";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGvD,cAAc,aAAa,CAAC;AAG5B,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,cAAc,sBAAsB,CAAC;AAGrC,cAAc,SAAS,CAAC;AAGxB,cAAc,aAAa,CAAC;AAG5B,cAAc,WAAW,CAAC;AAG1B,cAAc,cAAc,CAAC;AAG7B,cAAc,cAAc,CAAC;AAI7B,YAAY,EACX,cAAc,EACd,KAAK,IAAI,SAAS,EAClB,WAAW,GACX,MAAM,eAAe,CAAC;AAGvB,OAAO,EACN,SAAS,EACT,OAAO,EACP,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,8BAA8B,EAC9B,sBAAsB,GACtB,MAAM,eAAe,CAAC;AAGvB,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGvD,cAAc,aAAa,CAAC;AAG5B,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,cAAc,sBAAsB,CAAC;AAGrC,cAAc,SAAS,CAAC;AAGxB,cAAc,aAAa,CAAC;AAG5B,cAAc,WAAW,CAAC;AAG1B,cAAc,cAAc,CAAC;AAG7B,cAAc,cAAc,CAAC;AAI7B,YAAY,EACX,cAAc,EACd,KAAK,IAAI,SAAS,EAClB,WAAW,GACX,MAAM,eAAe,CAAC;AAGvB,OAAO,EACN,SAAS,EACT,OAAO,EACP,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,8BAA8B,EAC9B,sBAAsB,GACtB,MAAM,eAAe,CAAC;AAGvB,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC"}