geonetwork-ui 2.3.0-dev.2c3530dc → 2.3.0-dev.376e0e90

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 (114) hide show
  1. package/esm2022/libs/api/metadata-converter/src/index.mjs +5 -5
  2. package/esm2022/libs/api/metadata-converter/src/lib/base.converter.mjs +14 -0
  3. package/esm2022/libs/api/metadata-converter/src/lib/find-converter.mjs +15 -0
  4. package/esm2022/libs/api/metadata-converter/src/lib/gn4/atomic-operations.mjs +3 -3
  5. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.converter.mjs +52 -0
  6. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +3 -3
  7. package/esm2022/libs/api/metadata-converter/src/lib/gn4/index.mjs +4 -0
  8. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/index.mjs +2 -0
  9. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.mjs +123 -0
  10. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.mjs +116 -0
  11. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.mjs +138 -0
  12. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/index.mjs +2 -0
  13. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.mjs +242 -0
  14. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +58 -62
  15. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.mjs +18 -0
  16. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.mjs +14 -0
  17. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/role.mapper.mjs +48 -0
  18. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/status.mapper.mjs +18 -0
  19. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/update-frequency.mapper.mjs +64 -0
  20. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +75 -58
  21. package/esm2022/libs/api/metadata-converter/src/lib/xml-utils.mjs +76 -14
  22. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +4 -4
  23. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
  24. package/esm2022/libs/feature/editor/src/lib/services/editor.service.mjs +8 -8
  25. package/fesm2022/geonetwork-ui.mjs +822 -245
  26. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  27. package/libs/api/metadata-converter/src/index.d.ts +4 -4
  28. package/libs/api/metadata-converter/src/index.d.ts.map +1 -1
  29. package/libs/api/metadata-converter/src/lib/{metadata-base.mapper.d.ts → base.converter.d.ts} +3 -3
  30. package/libs/api/metadata-converter/src/lib/base.converter.d.ts.map +1 -0
  31. package/libs/api/metadata-converter/src/lib/find-converter.d.ts +3 -0
  32. package/libs/api/metadata-converter/src/lib/find-converter.d.ts.map +1 -0
  33. package/libs/api/metadata-converter/src/lib/gn4/{gn4.metadata.mapper.d.ts → gn4.converter.d.ts} +5 -5
  34. package/libs/api/metadata-converter/src/lib/gn4/gn4.converter.d.ts.map +1 -0
  35. package/libs/api/metadata-converter/src/lib/gn4/index.d.ts +4 -0
  36. package/libs/api/metadata-converter/src/lib/gn4/index.d.ts.map +1 -0
  37. package/libs/api/metadata-converter/src/lib/iso19115-3/index.d.ts +2 -0
  38. package/libs/api/metadata-converter/src/lib/iso19115-3/index.d.ts.map +1 -0
  39. package/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.d.ts +9 -0
  40. package/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.d.ts.map +1 -0
  41. package/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.d.ts +20 -0
  42. package/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.d.ts.map +1 -0
  43. package/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.d.ts +21 -0
  44. package/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.d.ts.map +1 -0
  45. package/libs/api/metadata-converter/src/lib/iso19139/index.d.ts +2 -0
  46. package/libs/api/metadata-converter/src/lib/iso19139/index.d.ts.map +1 -0
  47. package/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.d.ts +11 -0
  48. package/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.d.ts.map +1 -0
  49. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +34 -6
  50. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  51. package/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.d.ts +8 -0
  52. package/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.d.ts.map +1 -0
  53. package/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.d.ts.map +1 -0
  54. package/libs/api/metadata-converter/src/lib/iso19139/utils/role.mapper.d.ts.map +1 -0
  55. package/libs/api/metadata-converter/src/lib/iso19139/utils/status.mapper.d.ts.map +1 -0
  56. package/libs/api/metadata-converter/src/lib/iso19139/utils/update-frequency.mapper.d.ts.map +1 -0
  57. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts +39 -3
  58. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  59. package/libs/api/metadata-converter/src/lib/xml-utils.d.ts +14 -1
  60. package/libs/api/metadata-converter/src/lib/xml-utils.d.ts.map +1 -1
  61. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +2 -2
  62. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  63. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +6 -4
  64. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  65. package/libs/feature/editor/src/lib/services/editor.service.d.ts.map +1 -1
  66. package/package.json +1 -1
  67. package/src/libs/api/metadata-converter/src/index.ts +4 -4
  68. package/src/libs/api/metadata-converter/src/lib/{metadata-base.mapper.ts → base.converter.ts} +2 -2
  69. package/src/libs/api/metadata-converter/src/lib/find-converter.ts +16 -0
  70. package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +32 -5
  71. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +11 -4
  72. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +33 -7
  73. package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +580 -0
  74. package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +2 -2
  75. package/src/libs/api/metadata-converter/src/lib/gn4/{gn4.metadata.mapper.ts → gn4.converter.ts} +2 -2
  76. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +2 -2
  77. package/src/libs/api/metadata-converter/src/lib/gn4/index.ts +3 -0
  78. package/src/libs/api/metadata-converter/src/lib/iso19115-3/index.ts +1 -0
  79. package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +176 -0
  80. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +329 -0
  81. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +513 -0
  82. package/src/libs/api/metadata-converter/src/lib/iso19139/index.ts +1 -0
  83. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +327 -0
  84. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +121 -82
  85. package/src/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.ts +20 -0
  86. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +175 -95
  87. package/src/libs/api/metadata-converter/src/lib/xml-utils.ts +84 -16
  88. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +2 -2
  89. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +9 -4
  90. package/src/libs/feature/editor/src/lib/services/editor.service.ts +27 -16
  91. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.mjs +0 -52
  92. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.mjs +0 -14
  93. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/role.mapper.mjs +0 -48
  94. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/status.mapper.mjs +0 -18
  95. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/update-frequency.mapper.mjs +0 -64
  96. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/converter.mjs +0 -130
  97. package/esm2022/libs/api/metadata-converter/src/lib/metadata-base.mapper.mjs +0 -14
  98. package/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.d.ts.map +0 -1
  99. package/libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.d.ts.map +0 -1
  100. package/libs/api/metadata-converter/src/lib/iso19139/codelists/role.mapper.d.ts.map +0 -1
  101. package/libs/api/metadata-converter/src/lib/iso19139/codelists/status.mapper.d.ts.map +0 -1
  102. package/libs/api/metadata-converter/src/lib/iso19139/codelists/update-frequency.mapper.d.ts.map +0 -1
  103. package/libs/api/metadata-converter/src/lib/iso19139/converter.d.ts +0 -4
  104. package/libs/api/metadata-converter/src/lib/iso19139/converter.d.ts.map +0 -1
  105. package/libs/api/metadata-converter/src/lib/metadata-base.mapper.d.ts.map +0 -1
  106. package/src/libs/api/metadata-converter/src/lib/iso19139/converter.ts +0 -196
  107. /package/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/keyword.mapper.d.ts +0 -0
  108. /package/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/role.mapper.d.ts +0 -0
  109. /package/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/status.mapper.d.ts +0 -0
  110. /package/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/update-frequency.mapper.d.ts +0 -0
  111. /package/src/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/keyword.mapper.ts +0 -0
  112. /package/src/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/role.mapper.ts +0 -0
  113. /package/src/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/status.mapper.ts +0 -0
  114. /package/src/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/update-frequency.mapper.ts +0 -0
@@ -162,6 +162,8 @@ function createDocument(rootEl) {
162
162
  const namespace = extractNamespace(name);
163
163
  if (namespace === 'xmlns' || namespace === null)
164
164
  return;
165
+ if (rootEl.attributes[`xmlns:${namespace}`])
166
+ return;
165
167
  if (!NAMESPACES[namespace]) {
166
168
  throw new Error(`No known URI for namespace ${namespace}`);
167
169
  }
@@ -185,6 +187,10 @@ function stripNamespace(name) {
185
187
  const colon = name.indexOf(':');
186
188
  return colon > -1 ? name.substring(colon + 1) : name;
187
189
  }
190
+ function getNamespace(name) {
191
+ const colon = name.indexOf(':');
192
+ return colon > -1 ? name.substring(0, colon) : '';
193
+ }
188
194
  function getElementName(element) {
189
195
  return element.name || '';
190
196
  }
@@ -336,6 +342,29 @@ const NAMESPACES = {
336
342
  gsr: 'http://www.isotc211.org/2005/gsr',
337
343
  gmi: 'http://www.isotc211.org/2005/gmi',
338
344
  xlink: 'http://www.w3.org/1999/xlink',
345
+ mdb: 'http://standards.iso.org/iso/19115/-3/mdb/2.0',
346
+ mdq: 'http://standards.iso.org/iso/19157/-2/mdq/1.0',
347
+ msr: 'http://standards.iso.org/iso/19115/-3/msr/2.0',
348
+ mrs: 'http://standards.iso.org/iso/19115/-3/mrs/1.0',
349
+ mmi: 'http://standards.iso.org/iso/19115/-3/mmi/1.0',
350
+ mrl: 'http://standards.iso.org/iso/19115/-3/mrl/2.0',
351
+ mdt: 'http://standards.iso.org/iso/19115/-3/mdt/2.0',
352
+ mrd: 'http://standards.iso.org/iso/19115/-3/mrd/1.0',
353
+ mds: 'http://standards.iso.org/iso/19115/-3/mds/2.0',
354
+ mpc: 'http://standards.iso.org/iso/19115/-3/mpc/1.0',
355
+ mcc: 'http://standards.iso.org/iso/19115/-3/mcc/1.0',
356
+ mac: 'http://standards.iso.org/iso/19115/-3/mac/2.0',
357
+ mco: 'http://standards.iso.org/iso/19115/-3/mco/1.0',
358
+ mda: 'http://standards.iso.org/iso/19115/-3/mda/1.0',
359
+ mex: 'http://standards.iso.org/iso/19115/-3/mex/1.0',
360
+ gex: 'http://standards.iso.org/iso/19115/-3/gex/1.0',
361
+ gcx: 'http://standards.iso.org/iso/19115/-3/gcx/1.0',
362
+ mas: 'http://standards.iso.org/iso/19115/-3/mas/1.0',
363
+ mri: 'http://standards.iso.org/iso/19115/-3/mri/1.0',
364
+ cit: 'http://standards.iso.org/iso/19115/-3/cit/2.0',
365
+ cat: 'http://standards.iso.org/iso/19115/-3/cat/1.0',
366
+ lan: 'http://standards.iso.org/iso/19115/-3/lan/1.0',
367
+ mrc: 'http://standards.iso.org/iso/19115/-3/mrc/2.0',
339
368
  };
340
369
  /**
341
370
  * @param name Full name with namespace, e.g.: gmd:MD_Metadata
@@ -349,25 +378,36 @@ function addAttribute(name, value) {
349
378
  return element;
350
379
  };
351
380
  }
381
+ function getTreeRoot(element) {
382
+ let root = element;
383
+ while (root.parent instanceof XmlElement) {
384
+ root = root.parent;
385
+ }
386
+ return root;
387
+ }
352
388
  // stays on the parent element
353
389
  // if the given elements are part of a subtree, will add the root of subtree
354
390
  function appendChildren(...childrenFns) {
355
391
  return (element) => {
356
392
  if (!element)
357
393
  return null;
358
- element.children.push(...childrenFns
359
- .map((fn) => fn())
360
- .map((el) => {
361
- let root = el;
362
- while (root.parent instanceof XmlElement) {
363
- root = root.parent;
364
- }
365
- return root;
366
- }));
394
+ element.children.push(...childrenFns.map((fn) => fn()).map(getTreeRoot));
367
395
  element.children.forEach((el) => (el.parent = element));
368
396
  return element;
369
397
  };
370
398
  }
399
+ // switch to the tip of the subtree
400
+ function appendChildTree(childrenFn) {
401
+ return (element) => {
402
+ if (!element)
403
+ return null;
404
+ const treeTip = childrenFn();
405
+ const treeRoot = getTreeRoot(treeTip);
406
+ element.children.push(treeRoot);
407
+ treeRoot.parent = element;
408
+ return treeTip;
409
+ };
410
+ }
371
411
  // switches to the child element
372
412
  function createChild(childName) {
373
413
  return (element) => {
@@ -414,6 +454,7 @@ function removeAllChildren() {
414
454
  return element;
415
455
  };
416
456
  }
457
+ // stays on the same element
417
458
  function removeChildrenByName(name) {
418
459
  return (element) => {
419
460
  if (!element)
@@ -428,12 +469,33 @@ function removeChildrenByName(name) {
428
469
  }
429
470
  function removeChildren(childrenFn) {
430
471
  return (element) => {
431
- const children = childrenFn(element);
432
- children.forEach((child) => (child.parent = null));
433
- element.children = element.children.filter((child) => child instanceof XmlElement && children.indexOf(child) === -1);
472
+ const childrenToRemove = childrenFn(element);
473
+ childrenToRemove.forEach((child) => (child.parent = null));
474
+ element.children = element.children.filter((child) => child instanceof XmlElement && childrenToRemove.indexOf(child) === -1);
434
475
  return element;
435
476
  };
436
477
  }
478
+ /**
479
+ * Renames elements in the XML tree according to the map
480
+ * Either specify a full element name like 'gmd:MD_Metadata' or simply a namespace like 'gmd'
481
+ * @param rootElement
482
+ * @param replaceMap
483
+ */
484
+ function renameElements(rootElement, replaceMap) {
485
+ function doReplace(element) {
486
+ if (element.name in replaceMap) {
487
+ element.name = replaceMap[element.name];
488
+ }
489
+ else if (element.name && getNamespace(element.name) in replaceMap) {
490
+ element.name = `${replaceMap[getNamespace(element.name)]}:${stripNamespace(element.name)}`;
491
+ }
492
+ if (element.children) {
493
+ element.children.forEach(doReplace);
494
+ }
495
+ }
496
+ doReplace(rootElement);
497
+ return rootElement;
498
+ }
437
499
 
438
500
  function getStatusFromStatusCode(statusCode) {
439
501
  switch (statusCode) {
@@ -601,6 +663,24 @@ function getKeywordTypeFromKeywordTypeCode(typeCode) {
601
663
  }
602
664
  }
603
665
 
666
+ /**
667
+ * Parts are [firstName, lastName]
668
+ * Second part will be null if no separation could be done
669
+ * @param fullName
670
+ */
671
+ function fullNameToParts(fullName) {
672
+ const parts = fullName.trim().split(/\s+/);
673
+ const first = parts.shift();
674
+ return [first, parts.join(' ').trim() || null];
675
+ }
676
+ function namePartsToFull(firstName, lastName) {
677
+ const first = firstName?.trim();
678
+ const last = lastName?.trim();
679
+ if (!first && !last)
680
+ return null;
681
+ return last && first ? `${first} ${last}` : last || first;
682
+ }
683
+
604
684
  function extractCharacterString() {
605
685
  return pipe(fallback(findChildElement('gco:CharacterString', false), findChildElement('gmx:Anchor', false)), readText());
606
686
  }
@@ -628,7 +708,7 @@ function extractRole() {
628
708
  return pipe(findChildElement('gmd:CI_RoleCode'), readAttribute('codeListValue'), map(getRoleFromRoleCode));
629
709
  }
630
710
  // from gmd:CI_ResponsibleParty
631
- function extractOrganization() {
711
+ function extractOrganization$1() {
632
712
  const getUrl = pipe(findNestedElements('gmd:contactInfo', 'gmd:CI_Contact', 'gmd:onlineResource', 'gmd:CI_OnlineResource', 'gmd:linkage'), getAtIndex(0), extractUrl());
633
713
  return pipe(combine(pipe(findChildElement('gmd:organisationName', false), extractCharacterString()), getUrl), map(([name, website]) => ({
634
714
  name,
@@ -636,28 +716,29 @@ function extractOrganization() {
636
716
  })));
637
717
  }
638
718
  // from gmd:CI_ResponsibleParty
639
- function extractIndividuals() {
719
+ function extractIndividual$1() {
640
720
  const getRole = pipe(findChildElement('gmd:role'), extractRole());
641
721
  const getPosition = pipe(findChildElement('gmd:positionName'), extractCharacterString());
642
722
  const getNameParts = pipe(findChildElement('gmd:individualName'), extractCharacterString(), map((fullName) => {
643
723
  if (!fullName)
644
724
  return [];
645
- const parts = fullName.split(/\s+/);
646
- if (!parts.length)
647
- return [fullName, null];
648
- const first = parts.shift();
649
- return [first, parts.join(' ')];
725
+ return fullNameToParts(fullName);
650
726
  }));
651
- const getOrganization = extractOrganization();
652
- const getEmail = pipe(findChildElement('gmd:electronicMailAddress'), extractCharacterString(), map((email) => (email === null ? 'missing@missing.com' : email)));
653
- return pipe(combine(getRole, getPosition, getNameParts, getOrganization, pipe(findChildrenElement('gmd:contactInfo'), mapArray(getEmail))), map(([role, position, [firstName, lastName], organization, emails]) => emails.map((email) => ({
727
+ const getOrganization = extractOrganization$1();
728
+ const getContactRoot = findNestedElement('gmd:contactInfo', 'gmd:CI_Contact');
729
+ const getEmail = pipe(getContactRoot, findChildElement('gmd:electronicMailAddress'), extractCharacterString(), map((email) => (email === null ? 'missing@missing.com' : email)));
730
+ const getAddress = pipe(getContactRoot, findNestedElement('gmd:address', 'gmd:CI_Address'), combine(pipe(findChildElement('gmd:deliveryPoint', false), extractCharacterString()), pipe(findChildElement('gmd:city', false), extractCharacterString()), pipe(findChildElement('gmd:postalCode', false), extractCharacterString()), pipe(findChildElement('gmd:country', false), extractCharacterString())), map((parts) => parts.filter((p) => !!p).join(', ')));
731
+ const getPhone = pipe(getContactRoot, findNestedElement('gmd:phone', 'gmd:CI_Telephone', 'gmd:voice'), extractCharacterString());
732
+ return pipe(combine(getRole, getPosition, getNameParts, getOrganization, getEmail, getAddress, getPhone), map(([role, position, [firstName, lastName], organization, email, address, phone,]) => ({
654
733
  email,
655
734
  role,
656
735
  organization,
657
736
  ...(position && { position }),
658
737
  ...(firstName && { firstName }),
659
738
  ...(lastName && { lastName }),
660
- }))));
739
+ ...(address && { address }),
740
+ ...(phone && { phone }),
741
+ })));
661
742
  }
662
743
  function extractStatus() {
663
744
  return pipe(findChildElement('gmd:MD_ProgressCode'), readAttribute('codeListValue'), map(getStatusFromStatusCode));
@@ -690,9 +771,12 @@ function extractLicenses() {
690
771
  text,
691
772
  })));
692
773
  }
693
- // from gmd:MD_Distribution
694
- function extractDatasetDistributions() {
695
- const getFormat = pipe(findParent('gmd:MD_Distribution'), findNestedElement('gmd:distributionFormat', 'gmd:MD_Format', 'gmd:name'), extractCharacterString(), map(matchMimeType));
774
+ const getMimeType$1 = pipe(findParent('gmd:MD_Distribution'), findNestedElement('gmd:distributionFormat', 'gmd:MD_Format', 'gmd:name'), extractCharacterString(), map(matchMimeType));
775
+ /**
776
+ * Extract distributions from a MD_Distribution element
777
+ * @param getMimeTypeFn This function starts from a gmd:transferOptions element
778
+ */
779
+ function extractDatasetDistributions(getMimeTypeFn) {
696
780
  const getUrl = pipe(findChildElement('gmd:linkage'), extractMandatoryUrl());
697
781
  const getProtocolStr = pipe(findChildElement('gmd:protocol'), extractCharacterString());
698
782
  const getProtocol = pipe(getProtocolStr, map(matchProtocol));
@@ -702,7 +786,7 @@ function extractDatasetDistributions() {
702
786
  /download/i.test(protocolStr)));
703
787
  const getName = pipe(findChildElement('gmd:name'), extractCharacterString());
704
788
  const getDescription = pipe(findChildElement('gmd:description'), extractCharacterString());
705
- return pipe(findNestedElements('gmd:transferOptions', 'gmd:MD_DigitalTransferOptions', 'gmd:onLine', 'gmd:CI_OnlineResource'), mapArray(combine(getIsService, getIsDownload, getProtocol, getUrl, getName, getDescription, getFormat)), mapArray(([isService, isDownload, protocol, url, name, description, format]) => {
789
+ return pipe(findNestedElements('gmd:transferOptions', 'gmd:MD_DigitalTransferOptions', 'gmd:onLine', 'gmd:CI_OnlineResource'), mapArray(combine(getIsService, getIsDownload, getProtocol, getUrl, getName, getDescription, getMimeTypeFn)), mapArray(([isService, isDownload, protocol, url, name, description, mimeType]) => {
706
790
  if (isService) {
707
791
  const hasIdentifier = protocol === 'wms' || protocol === 'wfs';
708
792
  return {
@@ -715,7 +799,6 @@ function extractDatasetDistributions() {
715
799
  };
716
800
  }
717
801
  else if (isDownload) {
718
- const mimeType = format;
719
802
  return {
720
803
  type: 'download',
721
804
  url: url,
@@ -794,18 +877,13 @@ function extractUpdateFrequency() {
794
877
  }
795
878
  /**
796
879
  * Looks for srv:SV_ServiceIdentification or gmd:MD_DataIdentification element
797
- * depending on record type
880
+ * Will find the first one that exists, not reading the type of the record
881
+ * (this allows using this function in other similar schemas)
798
882
  */
799
883
  function findIdentification() {
800
- return (rootEl) => {
801
- const kind = readKind(rootEl);
802
- let eltName = 'gmd:MD_DataIdentification';
803
- if (kind === 'service')
804
- eltName = 'srv:SV_ServiceIdentification';
805
- return findNestedElement('gmd:identificationInfo', eltName)(rootEl);
806
- };
884
+ return pipe(findChildElement('gmd:identificationInfo', false), combine(findChildElement('gmd:MD_DataIdentification', false), findChildElement('srv:SV_ServiceIdentification', false)), filterArray((el) => el !== null), getAtIndex(0));
807
885
  }
808
- function extractCitationDate(type) {
886
+ function extractIdentificationDate(type) {
809
887
  return pipe(findIdentification(), findNestedElements('gmd:citation', 'gmd:CI_Citation', 'gmd:date'), filterArray(pipe(findNestedElements('gmd:CI_Date', 'gmd:dateType', 'gmd:CI_DateTypeCode'), getAtIndex(0), readAttribute('codeListValue'), map((value) => value === type))), getAtIndex(0), findNestedElements('gmd:CI_Date', 'gmd:date'), getAtIndex(0), extractDateTime());
810
888
  }
811
889
  function getSpatialRepresentationFromCode(spatialRepresentationCode) {
@@ -820,19 +898,25 @@ function getSpatialRepresentationFromCode(spatialRepresentationCode) {
820
898
  return null;
821
899
  }
822
900
  }
823
- function readUniqueIdentifier(rootEl) {
901
+ function readUniqueIdentifier$1(rootEl) {
824
902
  return pipe(findChildElement('gmd:fileIdentifier', false), extractCharacterString())(rootEl);
825
903
  }
826
- function readKind(rootEl) {
904
+ function readKind$1(rootEl) {
827
905
  return pipe(findNestedElement('gmd:hierarchyLevel', 'gmd:MD_ScopeCode'), readAttribute('codeListValue'), map((scopeCode) => scopeCode === 'service' ? 'service' : 'dataset'))(rootEl);
828
906
  }
829
- function readOwnerOrganization(rootEl) {
830
- return pipe(findNestedElement('gmd:contact', 'gmd:CI_ResponsibleParty'), extractOrganization())(rootEl);
907
+ function readOwnerOrganization$1(rootEl) {
908
+ return pipe(findNestedElement('gmd:contact', 'gmd:CI_ResponsibleParty'), extractOrganization$1())(rootEl);
831
909
  }
832
- function readRecordUpdated(rootEl) {
833
- return pipe(findChildElement('gmd:dateStamp'), extractDateTime())(rootEl);
910
+ function readResourceUpdated(rootEl) {
911
+ return extractIdentificationDate('revision')(rootEl);
834
912
  }
835
- function readRecordPublished(rootEl) {
913
+ function readResourceCreated(rootEl) {
914
+ return extractIdentificationDate('creation')(rootEl);
915
+ }
916
+ function readResourcePublished(rootEl) {
917
+ return extractIdentificationDate('publication')(rootEl);
918
+ }
919
+ function readRecordUpdated$1(rootEl) {
836
920
  return pipe(findChildElement('gmd:dateStamp'), extractDateTime())(rootEl);
837
921
  }
838
922
  function readTitle(rootEl) {
@@ -841,14 +925,11 @@ function readTitle(rootEl) {
841
925
  function readAbstract(rootEl) {
842
926
  return pipe(findIdentification(), findChildElement('gmd:abstract', false), extractCharacterString())(rootEl);
843
927
  }
844
- function readDatasetCreated(rootEl) {
845
- return extractCitationDate('creation')(rootEl);
928
+ function readContacts$1(rootEl) {
929
+ return pipe(findChildrenElement('gmd:contact', false), mapArray(findChildElement('gmd:CI_ResponsibleParty', false)), mapArray(extractIndividual$1()))(rootEl);
846
930
  }
847
- function readDatasetUpdated(rootEl) {
848
- return extractCitationDate('revision')(rootEl);
849
- }
850
- function readContacts(rootEl) {
851
- return pipe(findIdentification(), combine(findChildrenElement('gmd:contact'), findChildrenElement('gmd:pointOfContact')), flattenArray(), mapArray(findChildElement('gmd:CI_ResponsibleParty', false)), mapArray(extractIndividuals()), flattenArray())(rootEl);
931
+ function readContactsForResource(rootEl) {
932
+ return pipe(findIdentification(), combine(findChildrenElement('gmd:contact', false), findChildrenElement('gmd:pointOfContact', false)), flattenArray(), mapArray(findChildElement('gmd:CI_ResponsibleParty', false)), mapArray(extractIndividual$1()))(rootEl);
852
933
  }
853
934
  // from gmd:thesaurusName
854
935
  function readThesaurus(rootEl) {
@@ -909,17 +990,11 @@ function readOverviews(rootEl) {
909
990
  ...(description && { description }),
910
991
  })))(rootEl);
911
992
  }
912
- function readSpatialExtents(rootEl) {
913
- return []; // TODO
914
- }
915
- function readTemporalExtents(rootEl) {
916
- return []; // TODO
917
- }
918
- function readLineage(rootEl) {
993
+ function readLineage$1(rootEl) {
919
994
  return pipe(findNestedElement('gmd:dataQualityInfo', 'gmd:DQ_DataQuality', 'gmd:lineage', 'gmd:LI_Lineage', 'gmd:statement'), extractCharacterString())(rootEl);
920
995
  }
921
- function readDistributions(rootEl) {
922
- return pipe(findNestedElements('gmd:distributionInfo', 'gmd:MD_Distribution'), mapArray(extractDatasetDistributions()), flattenArray())(rootEl);
996
+ function readDistributions$1(rootEl) {
997
+ return pipe(findNestedElements('gmd:distributionInfo', 'gmd:MD_Distribution'), mapArray(extractDatasetDistributions(getMimeType$1)), flattenArray())(rootEl);
923
998
  }
924
999
  function readUpdateFrequency(rootEl) {
925
1000
  return pipe(findIdentification(), findNestedElement('gmd:resourceMaintenance', 'gmd:MD_MaintenanceInformation'), extractUpdateFrequency(), map((updateFrequency) => updateFrequency || 'unknown'))(rootEl);
@@ -1096,17 +1171,21 @@ function getISODuration(updateFrequency) {
1096
1171
  const hours = duration.hours > 0 ? `T${duration.hours}H` : '';
1097
1172
  return `P${duration.years}Y${duration.months}M${duration.days}D${hours}`;
1098
1173
  }
1099
- function appendResponsibleParty(contact) {
1100
- const name = contact.lastName && contact.firstName
1101
- ? `${contact.firstName} ${contact.lastName}`
1102
- : contact.lastName || contact.firstName || null;
1103
- return appendChildren(pipe(createElement('gmd:CI_ResponsibleParty'), name
1104
- ? appendChildren(pipe(createElement('gmd:individualName'), writeCharacterString(name)))
1174
+ function appendResponsibleParty$1(contact) {
1175
+ const fullName = namePartsToFull(contact.firstName, contact.lastName);
1176
+ const createAddress = pipe(createElement('gmd:address'), createChild('gmd:CI_Address'), appendChildren(pipe(createElement('gmd:electronicMailAddress'), writeCharacterString(contact.email))), contact.address
1177
+ ? appendChildren(pipe(createElement('gmd:deliveryPoint'), writeCharacterString(contact.address)))
1178
+ : noop);
1179
+ const createContact = pipe(createElement('gmd:contactInfo'), createChild('gmd:CI_Contact'), contact.phone
1180
+ ? appendChildren(pipe(createElement('gmd:phone'), createChild('gmd:CI_Telephone'), createChild('gmd:voice'), writeCharacterString(contact.phone)))
1181
+ : noop, appendChildren(createAddress), 'website' in contact.organization
1182
+ ? appendChildren(pipe(createElement('gmd:onlineResource'), createChild('gmd:CI_OnlineResource'), writeLinkage(contact.organization.website)))
1183
+ : noop);
1184
+ return appendChildren(pipe(createElement('gmd:CI_ResponsibleParty'), fullName
1185
+ ? appendChildren(pipe(createElement('gmd:individualName'), writeCharacterString(fullName)))
1105
1186
  : noop, contact.position
1106
1187
  ? appendChildren(pipe(createElement('gmd:positionName'), writeCharacterString(contact.position)))
1107
- : noop, appendChildren(pipe(createElement('gmd:organisationName'), writeCharacterString(contact.organization.name)), pipe(createElement('gmd:contactInfo'), createChild('gmd:CI_Contact'), appendChildren(pipe(createElement('gmd:address'), createChild('gmd:CI_Address'), createChild('gmd:electronicMailAddress'), writeCharacterString(contact.email))), 'website' in contact.organization
1108
- ? appendChildren(pipe(createElement('gmd:onlineResource'), createChild('gmd:CI_OnlineResource'), writeLinkage(contact.organization.website)))
1109
- : noop), pipe(createElement('gmd:role'), createChild('gmd:CI_RoleCode'), addAttribute('codeList', 'http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#CI_RoleCode'), addAttribute('codeListValue', getRoleCode(contact.role))))));
1188
+ : noop, appendChildren(pipe(createElement('gmd:organisationName'), writeCharacterString(contact.organization.name)), createContact, pipe(createElement('gmd:role'), createChild('gmd:CI_RoleCode'), addAttribute('codeList', 'http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#CI_RoleCode'), addAttribute('codeListValue', getRoleCode(contact.role))))));
1110
1189
  }
1111
1190
  function updateCitationDate(date, type) {
1112
1191
  return pipe(findNestedElements('gmd:date', 'gmd:CI_Date'), filterArray(pipe(findChildElement('gmd:CI_DateTypeCode'), readAttribute('codeListValue'), map((value) => value === type))), getAtIndex(0), findChildElement('gmd:date'), removeAllChildren(), writeDateTime(date));
@@ -1124,12 +1203,13 @@ function createThesaurus(thesaurus) {
1124
1203
  : writeCharacterString(thesaurus.id))))));
1125
1204
  }
1126
1205
  function appendKeywords(keywords) {
1206
+ // keywords are grouped by thesaurus if they have one, otherwise by type
1127
1207
  const keywordsByThesaurus = keywords.reduce((acc, keyword) => {
1128
1208
  const thesaurusId = keyword.thesaurus?.id;
1129
1209
  const type = keyword.type;
1130
- let existingGroup = acc.find((group) => group[0].thesaurus
1131
- ? group[0].thesaurus.id === thesaurusId
1132
- : group[0].type === type);
1210
+ let existingGroup = acc.find((group) => thesaurusId
1211
+ ? group[0].thesaurus?.id === thesaurusId
1212
+ : group[0].type === type && !group[0].thesaurus);
1133
1213
  if (!existingGroup) {
1134
1214
  existingGroup = [];
1135
1215
  acc.push(existingGroup);
@@ -1170,36 +1250,39 @@ function createLicense(license) {
1170
1250
  function removeDistributions() {
1171
1251
  return pipe(removeChildrenByName('gmd:distributionInfo'));
1172
1252
  }
1173
- function createDistribution(distribution) {
1174
- const appendDistributionFormat = 'mimeType' in distribution
1175
- ? appendChildren(pipe(createElement('gmd:distributionFormat'), createChild('gmd:MD_Format'), appendChildren(pipe(createElement('gmd:name'), writeCharacterString(distribution.mimeType)), pipe(createElement('gmd:version'), writeCharacterString('1.0') // hardcoding this as it most likely won't be used but is mandatory
1176
- ))))
1177
- : noop;
1178
- let linkageUrl, name, functionCode, protocol;
1253
+ function appendDistributionFormat$1(mimeType) {
1254
+ return appendChildren(pipe(createElement('gmd:distributionFormat'), createChild('gmd:MD_Format'), appendChildren(pipe(createElement('gmd:name'), writeCharacterString(mimeType)), pipe(createElement('gmd:version'), writeCharacterString('1.0') // hardcoding this as it most likely won't be used but is mandatory
1255
+ ))));
1256
+ }
1257
+ function createDistributionInfo() {
1258
+ return pipe(createElement('gmd:distributionInfo'), createChild('gmd:MD_Distribution'));
1259
+ }
1260
+ // apply to MD_Distribution
1261
+ function appendDistribution(distribution, appendFormatFn) {
1262
+ let name;
1263
+ let functionCode;
1264
+ let protocol;
1179
1265
  if (distribution.type === 'service') {
1180
- linkageUrl = distribution.url.toString();
1181
1266
  name = distribution.identifierInService; // this is for GeoNetwork to know the layer name
1182
1267
  functionCode = 'download';
1183
1268
  protocol = getDistributionProtocol(distribution);
1184
1269
  }
1185
1270
  else if (distribution.type === 'download') {
1186
- linkageUrl = distribution.url.toString();
1187
1271
  name = distribution.name;
1188
1272
  functionCode = 'download';
1189
1273
  protocol = 'WWW:DOWNLOAD';
1190
1274
  }
1191
1275
  else {
1192
- linkageUrl = distribution.url.toString();
1193
1276
  name = distribution.name;
1194
1277
  functionCode = 'information';
1195
1278
  protocol = 'WWW:LINK';
1196
1279
  }
1197
- const appendTransferOptions = appendChildren(pipe(createElement('gmd:transferOptions'), createChild('gmd:MD_DigitalTransferOptions'), createChild('gmd:onLine'), createChild('gmd:CI_OnlineResource'), writeLinkage(linkageUrl), 'description' in distribution
1280
+ const appendTransferOptions = appendChildren(pipe(createElement('gmd:transferOptions'), createChild('gmd:MD_DigitalTransferOptions'), createChild('gmd:onLine'), createChild('gmd:CI_OnlineResource'), writeLinkage(distribution.url), 'description' in distribution
1198
1281
  ? appendChildren(pipe(createElement('gmd:description'), writeCharacterString(distribution.description)))
1199
1282
  : noop, name !== undefined
1200
1283
  ? appendChildren(pipe(createElement('gmd:name'), writeCharacterString(name)))
1201
1284
  : noop, appendChildren(pipe(createElement('gmd:protocol'), writeCharacterString(protocol)), pipe(createElement('gmd:function'), createChild('gmd:CI_OnLineFunctionCode'), addAttribute('codeList', 'http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#CI_OnLineFunctionCode'), addAttribute('codeListValue', functionCode)))));
1202
- return pipe(createElement('gmd:distributionInfo'), createChild('gmd:MD_Distribution'), appendDistributionFormat, appendTransferOptions);
1285
+ return pipe('mimeType' in distribution ? appendFormatFn(distribution.mimeType) : noop, appendTransferOptions);
1203
1286
  }
1204
1287
  /**
1205
1288
  * Looks for srv:SV_ServiceIdentification or gmd:MD_DataIdentification element
@@ -1207,7 +1290,7 @@ function createDistribution(distribution) {
1207
1290
  */
1208
1291
  function findOrCreateIdentification() {
1209
1292
  return (rootEl) => {
1210
- const kind = readKind(rootEl);
1293
+ const kind = readKind$1(rootEl);
1211
1294
  let eltName = 'gmd:MD_DataIdentification';
1212
1295
  if (kind === 'service')
1213
1296
  eltName = 'srv:SV_ServiceIdentification';
@@ -1219,16 +1302,16 @@ function findOrCreateDistribution() {
1219
1302
  return findNestedChildOrCreate('gmd:distributionInfo', 'gmd:MD_Distribution')(rootEl);
1220
1303
  };
1221
1304
  }
1222
- function writeUniqueIdentifier(record, rootEl) {
1305
+ function writeUniqueIdentifier$1(record, rootEl) {
1223
1306
  pipe(findChildOrCreate('gmd:fileIdentifier'), writeCharacterString(record.uniqueIdentifier))(rootEl);
1224
1307
  }
1225
- function writeKind(record, rootEl) {
1308
+ function writeKind$1(record, rootEl) {
1226
1309
  pipe(findNestedChildOrCreate('gmd:hierarchyLevel', 'gmd:MD_ScopeCode'), addAttribute('codeList', 'http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_ScopeCode'), addAttribute('codeListValue', record.kind))(rootEl);
1227
1310
  }
1228
- function writeOwnerOrganization(record, rootEl) {
1311
+ function writeOwnerOrganization$1(record, rootEl) {
1229
1312
  // if no contact matches the owner org, create an empty one
1230
1313
  const ownerContact = record.contacts.find((contact) => contact.organization.name === record.ownerOrganization.name);
1231
- pipe(findChildOrCreate('gmd:contact'), removeAllChildren(), appendResponsibleParty(ownerContact
1314
+ pipe(findChildOrCreate('gmd:contact'), removeAllChildren(), appendResponsibleParty$1(ownerContact
1232
1315
  ? {
1233
1316
  ...ownerContact,
1234
1317
  // owner responsible party is always point of contact
@@ -1240,7 +1323,7 @@ function writeOwnerOrganization(record, rootEl) {
1240
1323
  role: 'point_of_contact',
1241
1324
  }))(rootEl);
1242
1325
  }
1243
- function writeRecordUpdated(record, rootEl) {
1326
+ function writeRecordUpdated$1(record, rootEl) {
1244
1327
  pipe(findChildOrCreate('gmd:dateStamp'), removeAllChildren(), writeDateTime(record.recordUpdated))(rootEl);
1245
1328
  }
1246
1329
  function writeTitle(record, rootEl) {
@@ -1249,13 +1332,16 @@ function writeTitle(record, rootEl) {
1249
1332
  function writeAbstract(record, rootEl) {
1250
1333
  pipe(findOrCreateIdentification(), findChildOrCreate('gmd:abstract'), writeCharacterString(record.abstract))(rootEl);
1251
1334
  }
1252
- function writeStatus(record, rootEl) {
1335
+ function writeStatus$1(record, rootEl) {
1253
1336
  pipe(findOrCreateIdentification(), findNestedChildOrCreate('gmd:status', 'gmd:MD_ProgressCode'), addAttribute('codeList', 'http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_ProgressCode'), addAttribute('codeListValue', getProgressCode(record.status)))(rootEl);
1254
1337
  }
1255
- function writeContacts(record, rootEl) {
1256
- pipe(findOrCreateIdentification(), removeChildrenByName('gmd:pointOfContact'), appendChildren(...record.contacts.map((contact) => pipe(createElement('gmd:pointOfContact'), appendResponsibleParty(contact)))))(rootEl);
1338
+ function writeContacts$1(record, rootEl) {
1339
+ pipe(removeChildrenByName('gmd:contact'), appendChildren(...record.contacts.map((contact) => pipe(createElement('gmd:contact'), appendResponsibleParty$1(contact)))))(rootEl);
1257
1340
  }
1258
- function writeKeywords(record, rootEl) {
1341
+ function writeContactsForResource$1(record, rootEl) {
1342
+ pipe(findOrCreateIdentification(), removeChildrenByName('gmd:pointOfContact'), removeChildrenByName('gmd:contact'), appendChildren(...record.contactsForResource.map((contact) => pipe(createElement('gmd:pointOfContact'), appendResponsibleParty$1(contact)))))(rootEl);
1343
+ }
1344
+ function writeKeywords$1(record, rootEl) {
1259
1345
  pipe(findOrCreateIdentification(), removeKeywords(), appendKeywords(record.keywords))(rootEl);
1260
1346
  }
1261
1347
  function writeTopics(record, rootEl) {
@@ -1278,17 +1364,22 @@ function writeUpdateFrequency(record, rootEl) {
1278
1364
  ? pipe(createChild('gmd:userDefinedMaintenanceFrequency'), createChild('gts:TM_PeriodDuration'), setTextContent(getISODuration(record.updateFrequency)))
1279
1365
  : pipe(createChild('gmd:maintenanceAndUpdateFrequency'), createChild('gmd:MD_MaintenanceFrequencyCode'), addAttribute('codeList', 'http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_MaintenanceFrequencyCode'), addAttribute('codeListValue', getMaintenanceFrequencyCode(record.updateFrequency))))(rootEl);
1280
1366
  }
1281
- function writeDatasetCreated(record, rootEl) {
1282
- if (!('datasetCreated' in record))
1367
+ function writeResourceCreated$1(record, rootEl) {
1368
+ if (!('resourceCreated' in record))
1283
1369
  return;
1284
- pipe(findOrCreateIdentification(), findNestedChildOrCreate('gmd:citation', 'gmd:CI_Citation'), fallback(updateCitationDate(record.datasetCreated, 'creation'), appendCitationDate(record.datasetCreated, 'creation')))(rootEl);
1370
+ pipe(findOrCreateIdentification(), findNestedChildOrCreate('gmd:citation', 'gmd:CI_Citation'), fallback(updateCitationDate(record.resourceCreated, 'creation'), appendCitationDate(record.resourceCreated, 'creation')))(rootEl);
1285
1371
  }
1286
- function writeDatasetUpdated(record, rootEl) {
1287
- if (!('datasetUpdated' in record))
1372
+ function writeResourceUpdated$1(record, rootEl) {
1373
+ if (!('resourceUpdated' in record))
1288
1374
  return;
1289
- pipe(findOrCreateIdentification(), findNestedChildOrCreate('gmd:citation', 'gmd:CI_Citation'), fallback(updateCitationDate(record.datasetUpdated, 'revision'), appendCitationDate(record.datasetUpdated, 'revision')))(rootEl);
1375
+ pipe(findOrCreateIdentification(), findNestedChildOrCreate('gmd:citation', 'gmd:CI_Citation'), fallback(updateCitationDate(record.resourceUpdated, 'revision'), appendCitationDate(record.resourceUpdated, 'revision')))(rootEl);
1290
1376
  }
1291
- function writeSpatialRepresentation(record, rootEl) {
1377
+ function writeResourcePublished$1(record, rootEl) {
1378
+ if (!('resourcePublished' in record))
1379
+ return;
1380
+ pipe(findOrCreateIdentification(), findNestedChildOrCreate('gmd:citation', 'gmd:CI_Citation'), fallback(updateCitationDate(record.resourcePublished, 'publication'), appendCitationDate(record.resourcePublished, 'publication')))(rootEl);
1381
+ }
1382
+ function writeSpatialRepresentation$1(record, rootEl) {
1292
1383
  pipe(findOrCreateIdentification(), findNestedChildOrCreate('gmd:spatialRepresentationType', 'gmd:MD_SpatialRepresentationTypeCode'), addAttribute('codeList', 'http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_SpatialRepresentationTypeCode'), addAttribute('codeListValue', record.spatialRepresentation))(rootEl);
1293
1384
  }
1294
1385
  function writeGraphicOverviews(record, rootEl) {
@@ -1296,10 +1387,10 @@ function writeGraphicOverviews(record, rootEl) {
1296
1387
  ? appendChildren(pipe(createElement('gmd:fileDescription'), writeCharacterString(overview.description)))
1297
1388
  : noop))))(rootEl);
1298
1389
  }
1299
- function writeDistributions(record, rootEl) {
1300
- pipe(removeDistributions(), appendChildren(...record.distributions.map(createDistribution)))(rootEl);
1390
+ function writeDistributions$1(record, rootEl) {
1391
+ pipe(removeDistributions(), appendChildren(...record.distributions.map((d) => pipe(createDistributionInfo(), appendDistribution(d, appendDistributionFormat$1)))))(rootEl);
1301
1392
  }
1302
- function writeLineage(record, rootEl) {
1393
+ function writeLineage$1(record, rootEl) {
1303
1394
  pipe(findNestedChildOrCreate('gmd:dataQualityInfo', 'gmd:DQ_DataQuality', 'gmd:lineage', 'gmd:LI_Lineage', 'gmd:statement'), writeCharacterString(record.lineage))(rootEl);
1304
1395
  }
1305
1396
  function getServiceEndpointProtocol(endpoint) {
@@ -1356,130 +1447,631 @@ function isEqual(a, b) {
1356
1447
  return a === b;
1357
1448
  }
1358
1449
 
1359
- function toModel(xml) {
1360
- const doc = parseXmlString(xml);
1361
- const rootEl = getRootElement(doc);
1362
- const uniqueIdentifier = readUniqueIdentifier(rootEl);
1363
- const kind = readKind(rootEl);
1364
- const ownerOrganization = readOwnerOrganization(rootEl);
1365
- const title = readTitle(rootEl);
1366
- const abstract = readAbstract(rootEl);
1367
- const contacts = readContacts(rootEl);
1368
- const recordUpdated = readRecordUpdated(rootEl);
1369
- const recordCreated = recordUpdated;
1370
- const recordPublished = readRecordPublished(rootEl);
1371
- const keywords = readKeywords(rootEl);
1372
- const topics = readIsoTopics(rootEl);
1373
- const legalConstraints = readLegalConstraints(rootEl);
1374
- const otherConstraints = readOtherConstraints(rootEl);
1375
- const securityConstraints = readSecurityConstraints(rootEl);
1376
- const licenses = readLicenses(rootEl);
1377
- const overviews = readOverviews(rootEl);
1378
- if (kind === 'dataset') {
1379
- const status = readStatus(rootEl);
1380
- const datasetCreated = readDatasetCreated(rootEl);
1381
- const datasetUpdated = readDatasetUpdated(rootEl);
1382
- const spatialRepresentation = readSpatialRepresentation(rootEl);
1383
- const spatialExtents = readSpatialExtents(rootEl);
1384
- const temporalExtents = readTemporalExtents(rootEl);
1385
- const lineage = readLineage(rootEl);
1386
- const distributions = readDistributions(rootEl);
1387
- const updateFrequency = readUpdateFrequency(rootEl);
1388
- return {
1389
- uniqueIdentifier,
1390
- kind,
1391
- languages: [],
1392
- recordCreated,
1393
- recordUpdated,
1394
- recordPublished,
1395
- status,
1396
- title,
1397
- abstract,
1398
- ownerOrganization,
1399
- contacts,
1400
- contactsForResource: [],
1401
- keywords,
1402
- topics,
1403
- licenses,
1404
- legalConstraints,
1405
- securityConstraints,
1406
- otherConstraints,
1407
- ...(datasetCreated && { datasetCreated }),
1408
- ...(datasetUpdated && { datasetUpdated }),
1409
- lineage,
1410
- ...(spatialRepresentation && { spatialRepresentation }),
1411
- overviews,
1412
- spatialExtents,
1413
- temporalExtents,
1414
- distributions,
1415
- updateFrequency,
1450
+ class MetadataMapperContext {
1451
+ }
1452
+ class BaseConverter {
1453
+ constructor(ctx = new MetadataMapperContext()) {
1454
+ this.ctx = ctx;
1455
+ }
1456
+ readRecords(documents) {
1457
+ return Promise.all(documents.map((doc) => this.readRecord(doc)));
1458
+ }
1459
+ writeRecords(records) {
1460
+ return Promise.all(records.map((doc) => this.writeRecord(doc)));
1461
+ }
1462
+ }
1463
+
1464
+ class Iso19139Converter extends BaseConverter {
1465
+ constructor() {
1466
+ super(...arguments);
1467
+ this.readers = {
1468
+ uniqueIdentifier: readUniqueIdentifier$1,
1469
+ kind: readKind$1,
1470
+ ownerOrganization: readOwnerOrganization$1,
1471
+ recordUpdated: readRecordUpdated$1,
1472
+ recordCreated: () => undefined,
1473
+ recordPublished: () => undefined,
1474
+ resourceUpdated: readResourceUpdated,
1475
+ resourceCreated: readResourceCreated,
1476
+ resourcePublished: readResourcePublished,
1477
+ title: readTitle,
1478
+ abstract: readAbstract,
1479
+ contacts: readContacts$1,
1480
+ contactsForResource: readContactsForResource,
1481
+ keywords: readKeywords,
1482
+ topics: readIsoTopics,
1483
+ licenses: readLicenses,
1484
+ legalConstraints: readLegalConstraints,
1485
+ securityConstraints: readSecurityConstraints,
1486
+ otherConstraints: readOtherConstraints,
1487
+ status: readStatus,
1488
+ updateFrequency: readUpdateFrequency,
1489
+ spatialRepresentation: readSpatialRepresentation,
1490
+ overviews: readOverviews,
1491
+ lineage: readLineage$1,
1492
+ distributions: readDistributions$1,
1493
+ onlineResources: readOnlineResources,
1494
+ // TODO
1495
+ spatialExtents: () => [],
1496
+ temporalExtents: () => [],
1497
+ extras: () => undefined,
1498
+ landingPage: () => undefined,
1499
+ languages: () => [],
1500
+ };
1501
+ this.writers = {
1502
+ uniqueIdentifier: writeUniqueIdentifier$1,
1503
+ kind: writeKind$1,
1504
+ ownerOrganization: writeOwnerOrganization$1,
1505
+ recordUpdated: writeRecordUpdated$1,
1506
+ recordCreated: () => undefined,
1507
+ recordPublished: () => undefined,
1508
+ resourceUpdated: writeResourceUpdated$1,
1509
+ resourceCreated: writeResourceCreated$1,
1510
+ resourcePublished: writeResourcePublished$1,
1511
+ title: writeTitle,
1512
+ abstract: writeAbstract,
1513
+ contacts: writeContacts$1,
1514
+ contactsForResource: writeContactsForResource$1,
1515
+ keywords: writeKeywords$1,
1516
+ topics: writeTopics,
1517
+ licenses: writeLicenses,
1518
+ legalConstraints: writeLegalConstraints,
1519
+ securityConstraints: writeSecurityConstraints,
1520
+ otherConstraints: writeOtherConstraints,
1521
+ status: writeStatus$1,
1522
+ updateFrequency: writeUpdateFrequency,
1523
+ spatialRepresentation: writeSpatialRepresentation$1,
1524
+ overviews: writeGraphicOverviews,
1525
+ lineage: writeLineage$1,
1526
+ distributions: writeDistributions$1,
1527
+ onlineResources: writeOnlineResources,
1528
+ // TODO
1529
+ spatialExtents: () => undefined,
1530
+ temporalExtents: () => undefined,
1531
+ extras: () => undefined,
1532
+ landingPage: () => undefined,
1533
+ languages: () => undefined,
1416
1534
  };
1417
1535
  }
1418
- else {
1419
- const onlineResources = readOnlineResources(rootEl);
1420
- return {
1421
- uniqueIdentifier,
1422
- kind,
1423
- languages: [],
1424
- recordCreated,
1425
- recordUpdated,
1426
- recordPublished,
1427
- title,
1428
- abstract,
1429
- ownerOrganization,
1430
- contacts,
1431
- keywords,
1432
- topics,
1433
- licenses,
1434
- legalConstraints,
1435
- securityConstraints,
1436
- otherConstraints,
1437
- overviews,
1438
- onlineResources,
1536
+ beforeDocumentCreation(rootElement) {
1537
+ // to override
1538
+ }
1539
+ async readRecord(document) {
1540
+ const doc = parseXmlString(document);
1541
+ const rootEl = getRootElement(doc);
1542
+ const uniqueIdentifier = this.readers['uniqueIdentifier'](rootEl);
1543
+ const kind = this.readers['kind'](rootEl);
1544
+ const ownerOrganization = this.readers['ownerOrganization'](rootEl);
1545
+ const title = this.readers['title'](rootEl);
1546
+ const abstract = this.readers['abstract'](rootEl);
1547
+ const contacts = this.readers['contacts'](rootEl);
1548
+ const contactsForResource = this.readers['contactsForResource'](rootEl);
1549
+ const recordUpdated = this.readers['recordUpdated'](rootEl);
1550
+ const recordCreated = this.readers['recordCreated'](rootEl);
1551
+ const recordPublished = this.readers['recordPublished'](rootEl);
1552
+ const resourceCreated = this.readers['resourceCreated'](rootEl);
1553
+ const resourceUpdated = this.readers['resourceUpdated'](rootEl);
1554
+ const resourcePublished = this.readers['resourcePublished'](rootEl);
1555
+ const keywords = this.readers['keywords'](rootEl);
1556
+ const topics = this.readers['topics'](rootEl);
1557
+ const legalConstraints = this.readers['legalConstraints'](rootEl);
1558
+ const otherConstraints = this.readers['otherConstraints'](rootEl);
1559
+ const securityConstraints = this.readers['securityConstraints'](rootEl);
1560
+ const licenses = this.readers['licenses'](rootEl);
1561
+ const overviews = this.readers['overviews'](rootEl);
1562
+ const landingPage = this.readers['landingPage'](rootEl);
1563
+ if (kind === 'dataset') {
1564
+ const status = this.readers['status'](rootEl);
1565
+ const spatialRepresentation = this.readers['spatialRepresentation'](rootEl);
1566
+ const spatialExtents = this.readers['spatialExtents'](rootEl);
1567
+ const temporalExtents = this.readers['temporalExtents'](rootEl);
1568
+ const lineage = this.readers['lineage'](rootEl);
1569
+ const distributions = this.readers['distributions'](rootEl);
1570
+ const updateFrequency = this.readers['updateFrequency'](rootEl);
1571
+ return {
1572
+ uniqueIdentifier,
1573
+ kind,
1574
+ languages: [],
1575
+ ...(recordCreated && { recordCreated }),
1576
+ ...(recordPublished && { recordPublished }),
1577
+ recordUpdated,
1578
+ ...(resourceCreated && { resourceCreated }),
1579
+ ...(resourceUpdated && { resourceUpdated }),
1580
+ ...(resourcePublished && { resourcePublished }),
1581
+ status,
1582
+ title,
1583
+ abstract,
1584
+ ownerOrganization,
1585
+ contacts,
1586
+ contactsForResource,
1587
+ keywords,
1588
+ topics,
1589
+ licenses,
1590
+ legalConstraints,
1591
+ securityConstraints,
1592
+ otherConstraints,
1593
+ lineage,
1594
+ ...(spatialRepresentation && { spatialRepresentation }),
1595
+ overviews,
1596
+ spatialExtents,
1597
+ temporalExtents,
1598
+ distributions,
1599
+ updateFrequency,
1600
+ ...(landingPage && { landingPage }),
1601
+ };
1602
+ }
1603
+ else {
1604
+ const onlineResources = this.readers['onlineResources'](rootEl);
1605
+ return {
1606
+ uniqueIdentifier,
1607
+ kind,
1608
+ languages: [],
1609
+ ...(recordCreated && { recordCreated }),
1610
+ ...(recordPublished && { recordPublished }),
1611
+ recordUpdated,
1612
+ ...(resourceCreated && { resourceCreated }),
1613
+ ...(resourceUpdated && { resourceUpdated }),
1614
+ ...(resourcePublished && { resourcePublished }),
1615
+ title,
1616
+ abstract,
1617
+ ownerOrganization,
1618
+ contacts,
1619
+ contactsForResource,
1620
+ keywords,
1621
+ topics,
1622
+ licenses,
1623
+ legalConstraints,
1624
+ securityConstraints,
1625
+ otherConstraints,
1626
+ overviews,
1627
+ onlineResources,
1628
+ ...(landingPage && { landingPage }),
1629
+ };
1630
+ }
1631
+ }
1632
+ async writeRecord(record, reference) {
1633
+ let rootEl;
1634
+ let fieldChanged;
1635
+ if (reference) {
1636
+ const originalDoc = parseXmlString(reference);
1637
+ const originalRecord = await this.readRecord(reference);
1638
+ rootEl = getRootElement(originalDoc);
1639
+ fieldChanged = (name) => {
1640
+ return originalRecord !== null
1641
+ ? !isEqual(record[name], originalRecord[name])
1642
+ : true;
1643
+ };
1644
+ }
1645
+ else {
1646
+ rootEl = createElement('gmd:MD_Metadata')();
1647
+ fieldChanged = () => true;
1648
+ }
1649
+ fieldChanged('uniqueIdentifier') &&
1650
+ this.writers['uniqueIdentifier'](record, rootEl);
1651
+ fieldChanged('kind') && this.writers['kind'](record, rootEl);
1652
+ fieldChanged('contacts') && this.writers['contacts'](record, rootEl);
1653
+ fieldChanged('ownerOrganization') &&
1654
+ this.writers['ownerOrganization'](record, rootEl);
1655
+ fieldChanged('recordUpdated') &&
1656
+ this.writers['recordUpdated'](record, rootEl);
1657
+ fieldChanged('recordCreated') &&
1658
+ this.writers['recordCreated'](record, rootEl);
1659
+ fieldChanged('recordPublished') &&
1660
+ this.writers['recordPublished'](record, rootEl);
1661
+ fieldChanged('title') && this.writers['title'](record, rootEl);
1662
+ fieldChanged('abstract') && this.writers['abstract'](record, rootEl);
1663
+ fieldChanged('resourceCreated') &&
1664
+ this.writers['resourceCreated'](record, rootEl);
1665
+ fieldChanged('resourcePublished') &&
1666
+ this.writers['resourcePublished'](record, rootEl);
1667
+ fieldChanged('resourceUpdated') &&
1668
+ this.writers['resourceUpdated'](record, rootEl);
1669
+ fieldChanged('contactsForResource') &&
1670
+ this.writers['contactsForResource'](record, rootEl);
1671
+ fieldChanged('keywords') && this.writers['keywords'](record, rootEl);
1672
+ fieldChanged('topics') && this.writers['topics'](record, rootEl);
1673
+ fieldChanged('legalConstraints') &&
1674
+ this.writers['legalConstraints'](record, rootEl);
1675
+ fieldChanged('securityConstraints') &&
1676
+ this.writers['securityConstraints'](record, rootEl);
1677
+ fieldChanged('licenses') && this.writers['licenses'](record, rootEl);
1678
+ fieldChanged('otherConstraints') &&
1679
+ this.writers['otherConstraints'](record, rootEl);
1680
+ if (record.kind === 'dataset') {
1681
+ fieldChanged('status') && this.writers['status'](record, rootEl);
1682
+ fieldChanged('updateFrequency') &&
1683
+ this.writers['updateFrequency'](record, rootEl);
1684
+ fieldChanged('spatialRepresentation') &&
1685
+ this.writers['spatialRepresentation'](record, rootEl);
1686
+ fieldChanged('overviews') && this.writers['overviews'](record, rootEl);
1687
+ fieldChanged('distributions') &&
1688
+ this.writers['distributions'](record, rootEl);
1689
+ fieldChanged('lineage') && this.writers['lineage'](record, rootEl);
1690
+ }
1691
+ else {
1692
+ fieldChanged('onlineResources') &&
1693
+ this.writers['onlineResources'](record, rootEl);
1694
+ }
1695
+ this.beforeDocumentCreation(rootEl);
1696
+ const newDocument = createDocument(rootEl);
1697
+ return xmlToString(newDocument);
1698
+ }
1699
+ }
1700
+
1701
+ function readKind(rootEl) {
1702
+ return pipe(findNestedElement('mdb:metadataScope', 'mdb:MD_MetadataScope', 'mdb:resourceScope', 'mcc:MD_ScopeCode'), readAttribute('codeListValue'), map((scopeCode) => scopeCode === 'service' ? 'service' : 'dataset'))(rootEl);
1703
+ }
1704
+ function findDistribution() {
1705
+ return findNestedElement('mdb:distributionInfo', 'mrd:MD_Distribution');
1706
+ }
1707
+ // from cit:CI_Organisation
1708
+ function extractOrganization() {
1709
+ const getUrl = pipe(findNestedElements('cit:contactInfo', 'cit:CI_Contact', 'cit:onlineResource', 'cit:CI_OnlineResource', 'cit:linkage'), getAtIndex(0), extractUrl());
1710
+ return pipe(combine(pipe(findChildElement('cit:name', false), extractCharacterString()), getUrl), map(([name, website]) => ({
1711
+ name,
1712
+ ...(website && { website }),
1713
+ })));
1714
+ }
1715
+ // from cit:CI_Individual or cit:CI_Organisation
1716
+ function extractIndividual(role, organization, orgContact) {
1717
+ const getPosition = pipe(findChildElement('cit:positionName'), extractCharacterString());
1718
+ const getNameParts = pipe(findChildElement('cit:name'), extractCharacterString(), map((fullName) => {
1719
+ if (!fullName)
1720
+ return [];
1721
+ return fullNameToParts(fullName);
1722
+ }));
1723
+ const getContact = findNestedElement('cit:contactInfo', 'cit:CI_Contact');
1724
+ const getAddressRoot = pipe(getContact, findNestedElement('cit:address', 'cit:CI_Address'));
1725
+ const getAddress = pipe(getAddressRoot, combine(pipe(findChildElement('cit:deliveryPoint', false), extractCharacterString()), pipe(findChildElement('cit:city', false), extractCharacterString()), pipe(findChildElement('cit:postalCode', false), extractCharacterString()), pipe(findChildElement('cit:country', false), extractCharacterString())), map((parts) => parts.filter((p) => !!p).join(', ')));
1726
+ const getPhone = pipe(getContact, findNestedElement('cit:phone', 'cit:CI_Telephone', 'cit:number'), extractCharacterString());
1727
+ const getEmail = pipe(getAddressRoot, findChildElement('cit:electronicMailAddress', false), extractCharacterString());
1728
+ const defaultOrg = {
1729
+ name: 'Missing Organization',
1730
+ };
1731
+ let defaultIndividual = {};
1732
+ if (orgContact) {
1733
+ defaultIndividual = {
1734
+ email: orgContact.email,
1735
+ ...(orgContact.address && { address: orgContact.address }),
1736
+ ...(orgContact.phone && { phone: orgContact.phone }),
1737
+ ...(orgContact.position && { position: orgContact.position }),
1738
+ organization,
1439
1739
  };
1440
1740
  }
1741
+ return pipe(combine(getPosition, getNameParts, getEmail, getAddress, getPhone), map(([position, [firstName, lastName], email, address, phone]) => ({
1742
+ ...defaultIndividual,
1743
+ email: email || defaultIndividual.email || 'missing@missing.com',
1744
+ role,
1745
+ organization: organization || defaultOrg,
1746
+ ...(position && { position }),
1747
+ ...(firstName && { firstName }),
1748
+ ...(lastName && { lastName }),
1749
+ ...(address && { address }),
1750
+ ...(phone && { phone }),
1751
+ })));
1752
+ }
1753
+ // from cit:CI_Organisation
1754
+ function extractOrganizationIndividuals(role) {
1755
+ return pipe(combine(extractOrganization(), extractIndividual(role), findNestedElements('cit:individual', 'cit:CI_Individual')), map(([org, orgContact, els]) => els.length
1756
+ ? els.map((el) => extractIndividual(role, org, orgContact)(el))
1757
+ : [
1758
+ {
1759
+ email: orgContact.email,
1760
+ ...(orgContact.address && { address: orgContact.address }),
1761
+ ...(orgContact.phone && { phone: orgContact.phone }),
1762
+ ...(orgContact.position && { position: orgContact.position }),
1763
+ organization: org,
1764
+ role,
1765
+ },
1766
+ ]));
1767
+ }
1768
+ // from cit:CI_Responsibility
1769
+ function extractIndividuals() {
1770
+ const getRole = pipe(findChildElement('cit:role'), extractRole());
1771
+ const getIndividuals = pipe(combine(getRole, findNestedElements('cit:party', 'cit:CI_Individual')), ([role, els]) => els.map((el) => extractIndividual(role)(el)));
1772
+ const getOrgIndividuals = pipe(combine(getRole, findNestedElements('cit:party', 'cit:CI_Organisation')), map(([role, els]) => els.map((el) => extractOrganizationIndividuals(role)(el))), flattenArray());
1773
+ return pipe(combine(getIndividuals, getOrgIndividuals), flattenArray());
1774
+ }
1775
+ function readUniqueIdentifier(rootEl) {
1776
+ return pipe(findNestedElement('mdb:metadataIdentifier', 'mcc:MD_Identifier', 'mcc:code'), extractCharacterString())(rootEl);
1777
+ }
1778
+ function readOwnerOrganization(rootEl) {
1779
+ const contacts = readContacts(rootEl);
1780
+ const pointOfContact = contacts.filter((c) => c.role === 'point_of_contact')[0];
1781
+ return (pointOfContact || contacts[0]).organization;
1782
+ }
1783
+ function readContacts(rootEl) {
1784
+ return pipe(findNestedElements('mdb:contact', 'cit:CI_Responsibility'), mapArray(extractIndividuals()), flattenArray())(rootEl);
1785
+ }
1786
+ function readResourceContacts(rootEl) {
1787
+ return pipe(combine(pipe(findIdentification(), findNestedElements('mri:citation', 'cit:CI_Citation', 'cit:citedResponsibleParty')), pipe(findIdentification(), findChildrenElement('mri:pointOfContact', false)), pipe(findDistribution(), findChildrenElement('mrd:distributorContact'))), flattenArray(), mapArray(findChildElement('cit:CI_Responsibility', false)), mapArray(extractIndividuals()), flattenArray())(rootEl);
1788
+ }
1789
+ function readLandingPage(rootEl) {
1790
+ return pipe(findNestedElement('mdb:metadataLinkage', 'cit:CI_OnlineResource', 'cit:linkage'), extractUrl())(rootEl);
1791
+ }
1792
+ function readLineage(rootEl) {
1793
+ return pipe(findNestedElement('mdb:resourceLineage', 'mrl:LI_Lineage', 'mrl:statement'), extractCharacterString())(rootEl);
1794
+ }
1795
+ function extractDateInfo(type) {
1796
+ return pipe(findChildrenElement('mdb:dateInfo', false), filterArray((el) => pipe(findChildElement('cit:CI_DateTypeCode'), readAttribute('codeListValue'))(el) === type), getAtIndex(0), findChildElement('cit:date'), extractDateTime());
1441
1797
  }
1442
- function toXml(record, originalXml) {
1443
- const originalDoc = originalXml ? parseXmlString(originalXml) : null;
1444
- const originalRecord = originalXml ? toModel(originalXml) : null;
1445
- const rootEl = originalDoc
1446
- ? getRootElement(originalDoc)
1447
- : createElement('gmd:MD_Metadata')();
1448
- function fieldChanged(name) {
1449
- return originalRecord !== null
1450
- ? !isEqual(record[name], originalRecord[name])
1451
- : true;
1452
- }
1453
- writeUniqueIdentifier(record, rootEl);
1454
- writeKind(record, rootEl);
1455
- fieldChanged('ownerOrganization') && writeOwnerOrganization(record, rootEl);
1456
- fieldChanged('recordUpdated') && writeRecordUpdated(record, rootEl);
1457
- writeTitle(record, rootEl);
1458
- writeAbstract(record, rootEl);
1459
- fieldChanged('contacts') && writeContacts(record, rootEl);
1460
- fieldChanged('keywords') && writeKeywords(record, rootEl);
1461
- fieldChanged('topics') && writeTopics(record, rootEl);
1462
- fieldChanged('legalConstraints') && writeLegalConstraints(record, rootEl);
1463
- fieldChanged('securityConstraints') &&
1464
- writeSecurityConstraints(record, rootEl);
1465
- fieldChanged('licenses') && writeLicenses(record, rootEl);
1466
- fieldChanged('otherConstraints') && writeOtherConstraints(record, rootEl);
1467
- if (record.kind === 'dataset') {
1468
- writeStatus(record, rootEl);
1469
- fieldChanged('updateFrequency') && writeUpdateFrequency(record, rootEl);
1470
- fieldChanged('datasetCreated') && writeDatasetCreated(record, rootEl);
1471
- fieldChanged('datasetUpdated') && writeDatasetUpdated(record, rootEl);
1472
- fieldChanged('spatialRepresentation') &&
1473
- writeSpatialRepresentation(record, rootEl);
1474
- fieldChanged('overviews') && writeGraphicOverviews(record, rootEl);
1475
- fieldChanged('distributions') && writeDistributions(record, rootEl);
1476
- writeLineage(record, rootEl);
1798
+ function readRecordUpdated(rootEl) {
1799
+ return extractDateInfo('revision')(rootEl);
1800
+ }
1801
+ function readRecordCreated(rootEl) {
1802
+ return extractDateInfo('creation')(rootEl);
1803
+ }
1804
+ function readRecordPublished(rootEl) {
1805
+ return extractDateInfo('publication')(rootEl);
1806
+ }
1807
+ const getMimeType = pipe(findParent('mrd:MD_Distribution'), findNestedElement('mrd:distributionFormat', 'mrd:MD_Format', 'mrd:formatSpecificationCitation', 'cit:CI_Citation', 'cit:title'), extractCharacterString(), map(matchMimeType));
1808
+ function readDistributions(rootEl) {
1809
+ return pipe(findNestedElements('mrd:distributionInfo', 'mrd:MD_Distribution'), mapArray(extractDatasetDistributions(getMimeType)), flattenArray())(rootEl);
1810
+ }
1811
+
1812
+ function writeUniqueIdentifier(record, rootEl) {
1813
+ pipe(findChildOrCreate('mdb:metadataIdentifier'), findChildOrCreate('mcc:MD_Identifier'), findChildOrCreate('mcc:code'), writeCharacterString(record.uniqueIdentifier))(rootEl);
1814
+ }
1815
+ function writeKind(record, rootEl) {
1816
+ pipe(findNestedChildOrCreate('mdb:metadataScope', 'mdb:MD_MetadataScope', 'mdb:resourceScope', 'mcc:MD_ScopeCode'), addAttribute('codeList', 'https://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#MD_ScopeCode'), addAttribute('codeListValue', record.kind), setTextContent(record.kind))(rootEl);
1817
+ }
1818
+ function removeRecordDate(type) {
1819
+ return removeChildren(pipe(findChildrenElement('mdb:dateInfo', false), filterArray(pipe(findChildElement('cit:CI_DateTypeCode'), readAttribute('codeListValue'), map((value) => value === type)))));
1820
+ }
1821
+ function appendRecordDate(date, type) {
1822
+ return appendChildren(pipe(createElement('mdb:dateInfo'), createChild('cit:CI_Date'), appendChildren(pipe(createElement('cit:date'), writeDateTime(date)), pipe(createElement('cit:dateType'), createChild('cit:CI_DateTypeCode'), addAttribute('codeList', 'https://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#CI_DateTypeCode'), addAttribute('codeListValue', type), setTextContent(type)))));
1823
+ }
1824
+ function writeRecordUpdated(record, rootEl) {
1825
+ removeRecordDate('revision')(rootEl);
1826
+ appendRecordDate(record.recordUpdated, 'revision')(rootEl);
1827
+ }
1828
+ function writeRecordCreated(record, rootEl) {
1829
+ removeRecordDate('creation')(rootEl);
1830
+ if (!('recordCreated' in record))
1831
+ return;
1832
+ appendRecordDate(record.recordCreated, 'creation')(rootEl);
1833
+ }
1834
+ function writeRecordPublished(record, rootEl) {
1835
+ removeRecordDate('publication')(rootEl);
1836
+ if (!('recordPublished' in record))
1837
+ return;
1838
+ appendRecordDate(record.recordPublished, 'publication')(rootEl);
1839
+ }
1840
+ function removeResourceDate(type) {
1841
+ return pipe(findIdentification(), findNestedElement('mri:citation', 'cit:CI_Citation'), removeChildren(pipe(findChildrenElement('cit:date', false), filterArray(pipe(findChildElement('cit:CI_DateTypeCode'), readAttribute('codeListValue'), map((value) => value === type))))));
1842
+ }
1843
+ function appendResourceDate(date, type) {
1844
+ return pipe(findIdentification(), findNestedElement('mri:citation', 'cit:CI_Citation'), appendChildren(pipe(createElement('cit:date'), createChild('cit:CI_Date'), appendChildren(pipe(createElement('cit:date'), writeDateTime(date)), pipe(createElement('cit:dateType'), createChild('cit:CI_DateTypeCode'), addAttribute('codeList', 'https://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#CI_DateTypeCode'), addAttribute('codeListValue', type), setTextContent(type))))));
1845
+ }
1846
+ function writeResourceUpdated(record, rootEl) {
1847
+ removeResourceDate('revision')(rootEl);
1848
+ if (!('resourceUpdated' in record))
1849
+ return;
1850
+ appendResourceDate(record.resourceUpdated, 'revision')(rootEl);
1851
+ }
1852
+ function writeResourceCreated(record, rootEl) {
1853
+ removeResourceDate('creation')(rootEl);
1854
+ if (!('resourceCreated' in record))
1855
+ return;
1856
+ appendResourceDate(record.resourceCreated, 'creation')(rootEl);
1857
+ }
1858
+ function writeResourcePublished(record, rootEl) {
1859
+ removeResourceDate('publication')(rootEl);
1860
+ if (!('resourcePublished' in record))
1861
+ return;
1862
+ appendResourceDate(record.resourcePublished, 'publication')(rootEl);
1863
+ }
1864
+ function writeOwnerOrganization(record, rootEl) {
1865
+ // if no contact matches the owner org, create an empty one
1866
+ const ownerContact = record.contacts.find((contact) => contact.organization.name === record.ownerOrganization.name);
1867
+ pipe(findChildOrCreate('mdb:contact'), removeAllChildren(), appendResponsibleParty(ownerContact
1868
+ ? {
1869
+ ...ownerContact,
1870
+ // owner responsible party is always point of contact
1871
+ role: 'point_of_contact',
1872
+ }
1873
+ : {
1874
+ organization: record.ownerOrganization,
1875
+ email: 'missing@missing.com',
1876
+ role: 'point_of_contact',
1877
+ }))(rootEl);
1878
+ }
1879
+ function appendResponsibleParty(contact) {
1880
+ const fullName = namePartsToFull(contact.firstName, contact.lastName);
1881
+ const createIndividual = pipe(createElement('cit:individual'), createChild('cit:CI_Individual'), fullName
1882
+ ? appendChildren(pipe(createElement('cit:name'), writeCharacterString(fullName)))
1883
+ : noop, contact.position
1884
+ ? appendChildren(pipe(createElement('cit:positionName'), writeCharacterString(contact.position)))
1885
+ : noop);
1886
+ const createContactInfo = pipe(createElement('cit:contactInfo'), createChild('cit:CI_Contact'), appendChildren(pipe(createElement('cit:address'), createChild('cit:CI_Address'), appendChildren(pipe(createElement('cit:electronicMailAddress'), writeCharacterString(contact.email))), contact.address
1887
+ ? appendChildren(pipe(createElement('cit:deliveryPoint'), writeCharacterString(contact.address)))
1888
+ : noop)), contact.organization?.website
1889
+ ? appendChildren(pipe(createElement('cit:onlineResource'), createChild('cit:CI_OnlineResource'), createChild('cit:linkage'), writeCharacterString(contact.organization.website.toString())))
1890
+ : noop, contact.phone
1891
+ ? appendChildren(pipe(createElement('cit:phone'), createChild('cit:CI_Telephone'), createChild('cit:number'), writeCharacterString(contact.phone)))
1892
+ : noop);
1893
+ const createRole = pipe(createElement('cit:role'), createChild('cit:CI_RoleCode'), addAttribute('codeList', 'https://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#CI_RoleCode'), addAttribute('codeListValue', getRoleCode(contact.role)), setTextContent(getRoleCode(contact.role)));
1894
+ const createParty = pipe(createElement('cit:party'), createChild('cit:CI_Organisation'), contact.organization?.name
1895
+ ? appendChildren(pipe(createElement('cit:name'), writeCharacterString(contact.organization?.name)))
1896
+ : noop, appendChildren(createContactInfo, createIndividual));
1897
+ return appendChildren(pipe(createElement('cit:CI_Responsibility'), appendChildren(createRole, createParty)));
1898
+ }
1899
+ function writeContacts(record, rootEl) {
1900
+ pipe(removeChildrenByName('mdb:contact'), appendChildren(...record.contacts.map((contact) => pipe(createElement('gmd:contact'), appendResponsibleParty(contact)))))(rootEl);
1901
+ }
1902
+ function writeContactsForResource(record, rootEl) {
1903
+ const withoutDistributors = record.contactsForResource.filter((c) => c.role !== 'distributor');
1904
+ const distributors = record.contactsForResource.filter((c) => c.role === 'distributor');
1905
+ pipe(findOrCreateIdentification(), removeChildrenByName('mri:pointOfContact'), appendChildren(...withoutDistributors.map((contact) => pipe(createElement('mri:pointOfContact'), appendResponsibleParty(contact)))))(rootEl);
1906
+ if (!distributors.length)
1907
+ return;
1908
+ pipe(findOrCreateDistribution(), removeChildrenByName('mrd:distributor'), createChild('mrd:distributor'), createChild('mrd:MD_Distributor'), appendChildren(...distributors.map((contact) => pipe(createElement('mrd:distributorContact'), appendResponsibleParty(contact)))))(rootEl);
1909
+ }
1910
+ function writeKeywords(record, rootEl) {
1911
+ pipe(findOrCreateIdentification(), removeKeywords(), appendKeywords(record.keywords))(rootEl);
1912
+ }
1913
+ function writeLandingPage(record, rootEl) {
1914
+ pipe(findNestedChildOrCreate('mdb:metadataLinkage', 'cit:CI_OnlineResource', 'cit:linkage'), writeLinkage(record.landingPage))(rootEl);
1915
+ }
1916
+ function writeLineage(record, rootEl) {
1917
+ pipe(findNestedChildOrCreate('mdb:resourceLineage', 'mrl:LI_Lineage', 'mrl:statement'), writeCharacterString(record.lineage))(rootEl);
1918
+ }
1919
+ function writeStatus(record, rootEl) {
1920
+ const progressCode = getProgressCode(record.status);
1921
+ pipe(findOrCreateIdentification(), findNestedChildOrCreate('mri:status', 'mcc:MD_ProgressCode'), addAttribute('codeList', 'https://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#MD_ProgressCode'), addAttribute('codeListValue', progressCode), setTextContent(progressCode))(rootEl);
1922
+ }
1923
+ function writeSpatialRepresentation(record, rootEl) {
1924
+ pipe(findOrCreateIdentification(), findNestedChildOrCreate('mri:spatialRepresentationType', 'mcc:MD_SpatialRepresentationTypeCode'), addAttribute('codeList', 'https://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#MD_SpatialRepresentationTypeCode'), addAttribute('codeListValue', record.spatialRepresentation), setTextContent(record.spatialRepresentation))(rootEl);
1925
+ }
1926
+ // this will remove all transfer options and formats from distribution info
1927
+ // and remove empty distribution info
1928
+ function removeTransferOptions(rootEl) {
1929
+ // remove transfer options & formats
1930
+ pipe(findNestedElements('mdb:distributionInfo', 'mrd:MD_Distribution'), mapArray(pipe(removeChildren(findChildrenElement('mrd:distributionFormat', false)), removeChildren(findChildrenElement('mrd:transferOptions', false)))))(rootEl);
1931
+ // remove empty distributions
1932
+ removeChildren(pipe(findChildrenElement('mdb:distributionInfo', false), filterArray(pipe(findChildElement('mrd:MD_Distribution'), allChildrenElement, map((children) => children.length === 0)))))(rootEl);
1933
+ }
1934
+ function appendDistributionFormat(mimeType) {
1935
+ return appendChildren(pipe(createElement('mrd:distributionFormat'), createChild('mrd:MD_Format'), createChild('mrd:formatSpecificationCitation'), createChild('cit:CI_Citation'), createChild('cit:title'), writeCharacterString(mimeType)));
1936
+ }
1937
+ function writeDistributions(record, rootEl) {
1938
+ removeTransferOptions(rootEl);
1939
+ // for each distribution, either find an existing distribution info or create a new one
1940
+ record.distributions.forEach((distribution, index) => {
1941
+ pipe(fallback(pipe(findNestedElements('gmd:distributionInfo', 'gmd:MD_Distribution'), getAtIndex(index)), appendChildTree(createDistributionInfo())), appendDistribution(distribution, appendDistributionFormat))(rootEl);
1942
+ });
1943
+ }
1944
+
1945
+ class Iso191153Converter extends Iso19139Converter {
1946
+ constructor() {
1947
+ super();
1948
+ this.readers['uniqueIdentifier'] = readUniqueIdentifier;
1949
+ this.readers['kind'] = readKind;
1950
+ this.readers['recordUpdated'] = readRecordUpdated;
1951
+ this.readers['recordCreated'] = readRecordCreated;
1952
+ this.readers['recordPublished'] = readRecordPublished;
1953
+ this.readers['contacts'] = readContacts;
1954
+ this.readers['contactsForResource'] = readResourceContacts;
1955
+ this.readers['ownerOrganization'] = readOwnerOrganization;
1956
+ this.readers['landingPage'] = readLandingPage;
1957
+ this.readers['lineage'] = readLineage;
1958
+ this.readers['distributions'] = readDistributions;
1959
+ this.writers['uniqueIdentifier'] = writeUniqueIdentifier;
1960
+ this.writers['kind'] = writeKind;
1961
+ this.writers['recordUpdated'] = writeRecordUpdated;
1962
+ this.writers['recordCreated'] = writeRecordCreated;
1963
+ this.writers['recordPublished'] = writeRecordPublished;
1964
+ this.writers['resourceUpdated'] = writeResourceUpdated;
1965
+ this.writers['resourceCreated'] = writeResourceCreated;
1966
+ this.writers['resourcePublished'] = writeResourcePublished;
1967
+ this.writers['contacts'] = writeContacts;
1968
+ this.writers['contactsForResource'] = writeContactsForResource;
1969
+ this.writers['ownerOrganization'] = writeOwnerOrganization;
1970
+ this.writers['landingPage'] = writeLandingPage;
1971
+ this.writers['lineage'] = writeLineage;
1972
+ this.writers['distributions'] = writeDistributions;
1973
+ this.writers['status'] = writeStatus;
1974
+ this.writers['spatialRepresentation'] = writeSpatialRepresentation;
1975
+ }
1976
+ beforeDocumentCreation(rootEl) {
1977
+ renameElements(rootEl, {
1978
+ gmd: 'mdb',
1979
+ 'gmd:characterEncoding': 'lan:characterEncoding',
1980
+ 'gmd:MD_CharacterSetCode': 'lan:MD_CharacterSetCode',
1981
+ 'gmd:MD_DataIdentification': 'mri:MD_DataIdentification',
1982
+ 'gmd:citation': 'mri:citation',
1983
+ 'gmd:abstract': 'mri:abstract',
1984
+ 'gmd:title': 'cit:title',
1985
+ 'gmd:CI_Citation': 'cit:CI_Citation',
1986
+ 'gmx:Anchor': 'gcx:Anchor',
1987
+ // languages
1988
+ 'gmd:PT_Locale': 'lan:PT_Locale',
1989
+ 'gmd:languageCode': 'lan:languageCode',
1990
+ 'gmd:LanguageCode': 'lan:LanguageCode',
1991
+ // status
1992
+ 'gmd:status': 'mri:status',
1993
+ 'gmd:MD_ProgressCode': 'mri:MD_ProgressCode',
1994
+ // dates
1995
+ 'gmd:date': 'cit:date',
1996
+ 'gmd:CI_Date': 'cit:CI_Date',
1997
+ 'gmd:dateType': 'cit:dateType',
1998
+ 'gmd:CI_DateTypeCode': 'cit:CI_DateTypeCode',
1999
+ // contacts
2000
+ 'gmd:CI_Responsibility': 'cit:CI_Responsibility',
2001
+ 'gmd:role': 'cit:role',
2002
+ 'gmd:CI_RoleCode': 'cit:CI_RoleCode',
2003
+ // keywords
2004
+ 'gmd:descriptiveKeywords': 'mri:descriptiveKeywords',
2005
+ 'gmd:MD_Keywords': 'mri:MD_Keywords',
2006
+ 'gmd:type': 'mri:type',
2007
+ 'gmd:MD_KeywordTypeCode': 'mri:MD_KeywordTypeCode',
2008
+ 'gmd:thesaurusName': 'mri:thesaurusName',
2009
+ 'gmd:keyword': 'mri:keyword',
2010
+ 'gmd:identifier': 'cit:identifier',
2011
+ 'gmd:MD_Identifier': 'mcc:MD_Identifier',
2012
+ 'gmd:code': 'mcc:code',
2013
+ // distributions
2014
+ 'gmd:MD_Distribution': 'mrd:MD_Distribution',
2015
+ 'gmd:transferOptions': 'mrd:transferOptions',
2016
+ 'gmd:MD_DigitalTransferOptions': 'mrd:MD_DigitalTransferOptions',
2017
+ 'gmd:onLine': 'mrd:onLine',
2018
+ 'gmd:distributionFormat': 'mrd:distributionFormat',
2019
+ 'gmd:MD_Format': 'mrd:MD_Format',
2020
+ 'gmd:CI_OnlineResource': 'cit:CI_OnlineResource',
2021
+ 'gmd:linkage': 'cit:linkage',
2022
+ 'gmd:name': 'cit:name',
2023
+ 'gmd:description': 'cit:description',
2024
+ 'gmd:CI_OnLineFunctionCode': 'cit:CI_OnLineFunctionCode',
2025
+ 'gmd:function': 'cit:function',
2026
+ 'gmd:protocol': 'cit:protocol',
2027
+ // topic
2028
+ 'gmd:topicCategory': 'mri:topicCategory',
2029
+ 'gmd:MD_TopicCategoryCode': 'mri:MD_TopicCategoryCode',
2030
+ // update frequency
2031
+ 'gmd:resourceMaintenance': 'mri:resourceMaintenance',
2032
+ 'gmd:MD_MaintenanceInformation': 'mmi:MD_MaintenanceInformation',
2033
+ 'gmd:userDefinedMaintenanceFrequency': 'mmi:userDefinedMaintenanceFrequency',
2034
+ 'gts:TM_PeriodDuration': 'gco:TM_PeriodDuration',
2035
+ // constraints
2036
+ 'gmd:resourceConstraints': 'mri:resourceConstraints',
2037
+ 'gmd:MD_Constraints': 'mco:MD_Constraints',
2038
+ 'gmd:MD_LegalConstraints': 'mco:MD_LegalConstraints',
2039
+ 'gmd:MD_SecurityConstraints': 'mco:MD_SecurityConstraints',
2040
+ 'gmd:useLimitation': 'mco:useLimitation',
2041
+ 'gmd:useConstraints': 'mco:useConstraints',
2042
+ 'gmd:accessConstraints': 'mco:accessConstraints',
2043
+ 'gmd:otherConstraints': 'mco:otherConstraints',
2044
+ 'gmd:MD_RestrictionCode': 'mco:MD_RestrictionCode',
2045
+ 'gmd:classification': 'mco:classification',
2046
+ 'gmd:MD_ClassificationCode': 'mco:MD_ClassificationCode',
2047
+ // overviews
2048
+ 'gmd:graphicOverview': 'mri:graphicOverview',
2049
+ 'gmd:MD_BrowseGraphic': 'mcc:MD_BrowseGraphic',
2050
+ 'gmd:fileName': 'mcc:fileName',
2051
+ 'gmd:fileDescription': 'mcc:fileDescription',
2052
+ // no more URL elements
2053
+ 'gmd:URL': 'gco:CharacterString',
2054
+ });
2055
+ }
2056
+ async writeRecord(record, reference) {
2057
+ let result = await super.writeRecord(record, reference);
2058
+ // fix gco namespace definition (changes between iso19139 and iso19115-3
2059
+ result = result.replace('"http://www.isotc211.org/2005/gco"', '"http://standards.iso.org/iso/19115/-3/gco/1.0"');
2060
+ return result;
2061
+ }
2062
+ }
2063
+
2064
+ function findConverterForDocument(document) {
2065
+ if (document.indexOf('mdb:MD_Metadata') > 0) {
2066
+ return new Iso191153Converter();
2067
+ }
2068
+ else if (document.indexOf('gmd:MD_Metadata') > 0) {
2069
+ return new Iso19139Converter();
1477
2070
  }
1478
2071
  else {
1479
- fieldChanged('onlineResources') && writeOnlineResources(record, rootEl);
2072
+ throw new Error(`No suitable converter found for the following document:
2073
+ ${document.substring(0, 400)}...`);
1480
2074
  }
1481
- const newDocument = createDocument(rootEl);
1482
- return xmlToString(newDocument);
1483
2075
  }
1484
2076
 
1485
2077
  const selectField = (source, fieldName) => source !== null && fieldName in source ? source[fieldName] : null;
@@ -19434,21 +20026,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImpor
19434
20026
  class OrganizationsServiceInterface {
19435
20027
  }
19436
20028
 
19437
- class MetadataMapperContext {
19438
- }
19439
- class MetadataBaseMapper {
19440
- constructor(ctx = new MetadataMapperContext()) {
19441
- this.ctx = ctx;
19442
- }
19443
- readRecords(documents) {
19444
- return Promise.all(documents.map((doc) => this.readRecord(doc)));
19445
- }
19446
- writeRecords(records) {
19447
- return Promise.all(records.map((doc) => this.writeRecord(doc)));
19448
- }
19449
- }
19450
-
19451
- class Gn4MetadataMapper extends MetadataBaseMapper {
20029
+ class Gn4Converter extends BaseConverter {
19452
20030
  constructor(fieldMapper, orgsService) {
19453
20031
  super();
19454
20032
  this.fieldMapper = fieldMapper;
@@ -19482,10 +20060,10 @@ class Gn4MetadataMapper extends MetadataBaseMapper {
19482
20060
  writeRecord(record) {
19483
20061
  throw new Error('not implemented');
19484
20062
  }
19485
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: Gn4MetadataMapper, deps: [{ token: Gn4FieldMapper }, { token: OrganizationsServiceInterface }], target: i0.ɵɵFactoryTarget.Injectable }); }
19486
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: Gn4MetadataMapper, providedIn: 'root' }); }
20063
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: Gn4Converter, deps: [{ token: Gn4FieldMapper }, { token: OrganizationsServiceInterface }], target: i0.ɵɵFactoryTarget.Injectable }); }
20064
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: Gn4Converter, providedIn: 'root' }); }
19487
20065
  }
19488
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: Gn4MetadataMapper, decorators: [{
20066
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: Gn4Converter, decorators: [{
19489
20067
  type: Injectable,
19490
20068
  args: [{
19491
20069
  providedIn: 'root',
@@ -20075,12 +20653,12 @@ class Gn4Repository {
20075
20653
  records,
20076
20654
  }))));
20077
20655
  }
20078
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: Gn4Repository, deps: [{ token: SearchApiService }, { token: ElasticsearchService }, { token: Gn4MetadataMapper }], target: i0.ɵɵFactoryTarget.Injectable }); }
20656
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: Gn4Repository, deps: [{ token: SearchApiService }, { token: ElasticsearchService }, { token: Gn4Converter }], target: i0.ɵɵFactoryTarget.Injectable }); }
20079
20657
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: Gn4Repository }); }
20080
20658
  }
20081
20659
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: Gn4Repository, decorators: [{
20082
20660
  type: Injectable
20083
- }], ctorParameters: function () { return [{ type: SearchApiService }, { type: ElasticsearchService }, { type: Gn4MetadataMapper }]; } });
20661
+ }], ctorParameters: function () { return [{ type: SearchApiService }, { type: ElasticsearchService }, { type: Gn4Converter }]; } });
20084
20662
 
20085
20663
  class PlatformServiceInterface {
20086
20664
  }
@@ -32156,7 +32734,7 @@ class EditorService {
32156
32734
  Accept: 'application/xml',
32157
32735
  },
32158
32736
  })
32159
- .pipe(map$1((response) => toModel(response.toString())));
32737
+ .pipe(switchMap$1((response) => findConverterForDocument(response).readRecord(response.toString())));
32160
32738
  }
32161
32739
  // returns the record as it was when saved
32162
32740
  saveRecord(record, fieldsConfig) {
@@ -32172,14 +32750,13 @@ class EditorService {
32172
32750
  }
32173
32751
  }
32174
32752
  // TODO: use the catalog repository instead
32175
- return this.http
32176
- .put(`${this.apiUrl}/records?metadataType=METADATA&uuidProcessing=OVERWRITE&transformWith=_none_&publishToAll=on`, toXml(savedRecord), {
32753
+ // TODO: use converter based on the format of the record before change
32754
+ return from(new Iso19139Converter().writeRecord(savedRecord)).pipe(switchMap$1((recordXml) => this.http.put(`${this.apiUrl}/records?metadataType=METADATA&uuidProcessing=OVERWRITE&transformWith=_none_&publishToAll=on`, recordXml, {
32177
32755
  headers: {
32178
32756
  'Content-Type': 'application/xml',
32179
32757
  },
32180
32758
  withCredentials: true,
32181
- })
32182
- .pipe(map$1(() => savedRecord));
32759
+ })), map$1(() => savedRecord));
32183
32760
  }
32184
32761
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: EditorService, deps: [{ token: i1.HttpClient }, { token: Configuration, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
32185
32762
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: EditorService, providedIn: 'root' }); }
@@ -32649,5 +33226,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImpor
32649
33226
  * Generated bundle index. Do not edit.
32650
33227
  */
32651
33228
 
32652
- export { ADD_RESULTS, ADD_SEARCH, AbstractAction, AddLayerFromCatalogComponent, AddLayerRecordPreviewComponent, AddResults, AddSearch, AnchorLinkDirective, ApiCardComponent, AuthService, AutocompleteComponent, AvatarComponent, AvatarServiceInterface, BLOCK_MODEL_FIXTURE, BadgeComponent, BaseReader, ButtonComponent, CLEAR_ERROR, CLEAR_RESULTS, CONFIG_MALFORMED, CONFIG_MINIMAL, CONFIG_MISSING_MANDATORY, CONFIG_OK, CONFIG_UNRECOGNIZED_KEYS, CONFIG_WITH_TRANSLATIONS, CONFIG_WRONG_LANGUAGE_CODE, CarouselComponent, CatalogTitleComponent, ChartComponent, ChartViewComponent, CheckToggleComponent, CheckboxComponent, ChipsInputComponent, ClearError, ClearResults, ColorScaleComponent, ContentGhostComponent, CopyTextButtonComponent, DEFAULT_BASELAYER_CONTEXT, DEFAULT_GN4_LOGIN_URL, DEFAULT_LANG, DEFAULT_PAGE_SIZE, DEFAULT_RESULTS_LAYOUT_CONFIG, DEFAULT_SEARCH_KEY, DEFAULT_STYLE_FIXTURE, DEFAULT_STYLE_HL_FIXTURE, DEFAULT_VIEW, DataService, DataViewComponent, DataViewPermalinkComponent, DataViewShareComponent, DataViewWebComponentComponent, DateRangePickerComponent, DefaultRouterModule, DownloadItemComponent, DownloadsListComponent, DragAndDropFileInputComponent, DropdownMultiselectComponent, DropdownSelectorComponent, EDITOR_FEATURE_KEY, EMPTY_BLOCK_MODEL_FIXTURE, ES_QUERY_FIELDS_PRIORITY, ES_RESOURCES_VALUES, ES_SOURCE_SUMMARY, EditableLabelDirective, EditorFacade, EditorService, ElasticsearchService, EmbeddedTranslateLoader, ErrorType, ExpandablePanelButtonComponent, ExpandablePanelComponent, ExternalViewerButtonComponent, FACET_ITEM_FIXTURE, FEATURE_MAP_OPTIONS, FIELDS_BRIEF, FIELDS_SUMMARY, FILTER_GEOMETRY, FORMATS, FacetBlockComponent, FacetBlockStubComponent, FacetItemComponent, FacetItemStubComponent, FacetListComponent, FacetsContainerComponent, FacetsModule, FavoriteStarComponent, FavoritesService, FeatureAuthModule, FeatureCatalogModule, FeatureDatavizModule, FeatureDetailComponent, FeatureEditorModule, FeatureInfoService, FeatureMapModule, FeatureRecordModule, FeatureSearchModule, FetchError, FieldsService, FigureComponent, FigureContainerComponent, FileTranslateLoader, FilterDropdownComponent, FormFieldArrayComponent, FormFieldComponent, FormFieldFileComponent, FormFieldObjectComponent, FormFieldRichComponent, FormFieldSimpleComponent, FormFieldSpatialExtentComponent, FormFieldTemporalExtentComponent, FuzzySearchComponent, GN_UI_VERSION, GeoTableViewComponent, GeocodingComponent, Gn4MetadataMapper, Gn4PlatformMapper, Gn4PlatformService, Gn4Repository, Gn4SettingsService, GravatarService, HttpLoaderFactory, I18nInterceptor, ImageFallbackDirective, ImageOverlayPreviewComponent, InteractiveTableColumnComponent, InteractiveTableComponent, LANGUAGES_LIST, LANGUAGE_NAMES, LANGUAGE_STORAGE_KEY, LANG_2_TO_3_MAPPER, LANG_3_TO_2_MAPPER, LOGIN_URL, LONLAT_CRS_CODES, LangService, LanguageSwitcherComponent, LayersPanelComponent, LinkCardComponent, LinkClassifierService, LinkUsage, LoadingMaskComponent, LogService, MAP_CONFIG_FIXTURE, MAP_FEATURE_KEY, METADATA_LANGUAGE, MY_FORMATS, MapComponent, MapContainerComponent, MapContextComponent, MapContextLayerTypeEnum, MapContextService, MapFacade, MapInstanceDirective, MapManagerService, MapStyleService, MapUtilsService, MapViewComponent, MarkdownParserComponent, MaxLinesComponent, mdview_actions as MdViewActions, MdViewFacade, MetadataCatalogComponent, MetadataContactComponent, MetadataInfoComponent, MetadataLinkType, MetadataQualityComponent, MetadataQualityItemComponent, MyOrgService, NavigationButtonComponent, ORGANIZATIONS_STRATEGY, ORGANIZATION_URL_TOKEN, OrganisationPreviewComponent, OrganisationsComponent, OrganisationsFilterComponent, OrganisationsResultComponent, OrganizationsFromGroupsService, OrganizationsFromMetadataService, PAGINATE, PARSE_DELIMITER, PATCH_RESULTS_AGGREGATIONS, PROXY_PATH, Paginate, PaginationButtonsComponent, PaginationComponent, PatchResultsAggregations, PopupAlertComponent, ProgressBarComponent, ProxyService, QUERY_FIELDS, RECORD_URL_TOKEN, REQUEST_MORE_ON_AGGREGATION, REQUEST_MORE_RESULTS, REQUEST_NEW_RESULTS, RESULTS_LAYOUT_CONFIG, ROUTER_CONFIG, ROUTER_ROUTE_DATASET, ROUTER_ROUTE_SEARCH, ROUTER_STATE_KEY, ROUTE_PARAMS, RecordApiFormComponent, RecordFormComponent, RecordMetricComponent, RecordPreviewCardComponent, RecordPreviewComponent, RecordPreviewFeedComponent, RecordPreviewListComponent, RecordPreviewRowComponent, RecordPreviewTextComponent, RecordPreviewTitleComponent, RecordsMetricsComponent, RecordsService, RelatedRecordCardComponent, RequestMoreOnAggregation, RequestMoreResults, RequestNewResults, ResultsHitsContainerComponent, ResultsHitsNumberComponent, ResultsLayoutComponent, ResultsLayoutConfigItem, ResultsListComponent, ResultsListContainerComponent, ResultsListItemComponent, ResultsTableComponent, RouterEffects, RouterFacade, RouterService, SEARCH_FEATURE_KEY, SET_CONFIG_AGGREGATIONS, SET_CONFIG_FILTERS, SET_CONFIG_REQUEST_FIELDS, SET_ERROR, SET_FAVORITES_ONLY, SET_FILTERS, SET_INCLUDE_ON_AGGREGATION, SET_PAGE_SIZE, SET_RESULTS_AGGREGATIONS, SET_RESULTS_HITS, SET_RESULTS_LAYOUT, SET_SEARCH, SET_SORT_BY, SET_SPATIAL_FILTER_ENABLED, SearchEffects, SearchFacade, SearchInputComponent, SearchResultsErrorComponent, SearchRouterContainerDirective, SearchService, SearchStateContainerDirective, SelectionService, SetConfigAggregations, SetConfigFilters, SetConfigRequestFields, SetError, SetFavoritesOnly, SetFilters, SetIncludeOnAggregation, SetPageSize, SetResultsAggregations, SetResultsHits, SetResultsLayout, SetSearch, SetSortBy, SetSpatialFilterEnabled, SiteTitleComponent, SortByComponent, SourceLabelComponent, SourcesService, SpinningLoaderComponent, StarToggleComponent, StepBarComponent, StickyHeaderComponent, SupportedTypes, TABLE_ITEM_FIXTURE, TABLE_ITEM_FIXTURE_HAB, THUMBNAIL_PLACEHOLDER, TRANSLATE_DEFAULT_CONFIG, TRANSLATE_WITH_OVERRIDES_CONFIG, TableComponent, TableViewComponent, TextAreaComponent, TextInputComponent, ThemeService, ThumbnailComponent, UPDATE_CONFIG_AGGREGATIONS, UPDATE_FILTERS, UPDATE_REQUEST_AGGREGATION_TERM, UiCatalogModule, UiDatavizModule, UiElementsModule, FacetsModule$1 as UiFacetsModule, UiInputsModule, UiLayoutModule, UiMapModule, UiSearchModule, UiWidgetsModule, UpdateConfigAggregations, UpdateFilters, UserPreviewComponent, UtilI18nModule, UtilSharedModule, ViewportIntersectorComponent, WEB_COMPONENT_EMBEDDER_URL, WFS_MAX_FEATURES, WizardComponent, WizardFieldComponent, WizardFieldType, WizardService, WizardSummarizeComponent, _reset, addLayer, changeLayerOrder, checkFileFormat, clearLayerError, createFuzzyFilter, currentPage, defaultMapOptions, dragPanCondition, dropEmptyTranslations, editorReducer, getArrayItem, getAsArray, getAsUrl, getBadgeColor, getCustomTranslations, getError, getFavoritesOnly, getFileFormat, getFileFormatFromServiceOutput, getFirstValue, getFormatPriority, getGeometryFromGeoJSON, getGlobalConfig, getJsonDataItemsProxy, getLangFromBrowser, getLinkLabel, getLinkPriority, getMapLayers, getMapState, getMetadataQualityConfig, getMimeTypeForFormat, getOptionalMapConfig, getOptionalSearchConfig, getPageSize, getSearchConfigAggregations, getSearchFilters, getSearchResults, getSearchResultsAggregations, getSearchResultsHits, getSearchResultsLayout, getSearchResultsLoading, getSearchSortBy, getSearchState, getSearchStateSearch, getSpatialFilterEnabled, getTemporalRangeUnion, getThemeConfig, initSearch, initialEditorState, initialMapState, initialState, isConfigLoaded, isEndOfResults, isFormatInQueryParam, loadAppConfig, mapContact, mapKeywords, mapLogo, mapOrganization, mapReducer, markRecordAsChanged, mimeTypeToFormat, mouseWheelZoomCondition, openDataset, openRecord, parse, placeholder, propagateToDocumentOnly, provideGn4, provideRepositoryUrl, readDataset, readDatasetHeaders, reducer$2 as reducer, reducerSearch, removeLayer, removeSearchParams, removeWhitespace, saveRecord, saveRecordFailure, saveRecordSuccess, selectEditorState, selectFallback, selectFallbackFields, selectField, selectRecord, selectRecordChangedSinceSave, selectRecordFields, selectRecordFieldsConfig, selectRecordSaveError, selectRecordSaving, selectTranslatedField, selectTranslatedValue, setLayerError, sortByFromString, sortByToString, sortByToStrings, stripHtml, toDate, toModel, toXml, totalPages, updateLayer, updateRecordField };
33229
+ export { ADD_RESULTS, ADD_SEARCH, AbstractAction, AddLayerFromCatalogComponent, AddLayerRecordPreviewComponent, AddResults, AddSearch, AnchorLinkDirective, ApiCardComponent, AuthService, AutocompleteComponent, AvatarComponent, AvatarServiceInterface, BLOCK_MODEL_FIXTURE, BadgeComponent, BaseReader, ButtonComponent, CLEAR_ERROR, CLEAR_RESULTS, CONFIG_MALFORMED, CONFIG_MINIMAL, CONFIG_MISSING_MANDATORY, CONFIG_OK, CONFIG_UNRECOGNIZED_KEYS, CONFIG_WITH_TRANSLATIONS, CONFIG_WRONG_LANGUAGE_CODE, CarouselComponent, CatalogTitleComponent, ChartComponent, ChartViewComponent, CheckToggleComponent, CheckboxComponent, ChipsInputComponent, ClearError, ClearResults, ColorScaleComponent, ContentGhostComponent, CopyTextButtonComponent, DEFAULT_BASELAYER_CONTEXT, DEFAULT_GN4_LOGIN_URL, DEFAULT_LANG, DEFAULT_PAGE_SIZE, DEFAULT_RESULTS_LAYOUT_CONFIG, DEFAULT_SEARCH_KEY, DEFAULT_STYLE_FIXTURE, DEFAULT_STYLE_HL_FIXTURE, DEFAULT_VIEW, DataService, DataViewComponent, DataViewPermalinkComponent, DataViewShareComponent, DataViewWebComponentComponent, DateRangePickerComponent, DefaultRouterModule, DownloadItemComponent, DownloadsListComponent, DragAndDropFileInputComponent, DropdownMultiselectComponent, DropdownSelectorComponent, EDITOR_FEATURE_KEY, EMPTY_BLOCK_MODEL_FIXTURE, ES_QUERY_FIELDS_PRIORITY, ES_RESOURCES_VALUES, ES_SOURCE_SUMMARY, EditableLabelDirective, EditorFacade, EditorService, ElasticsearchService, EmbeddedTranslateLoader, ErrorType, ExpandablePanelButtonComponent, ExpandablePanelComponent, ExternalViewerButtonComponent, FACET_ITEM_FIXTURE, FEATURE_MAP_OPTIONS, FIELDS_BRIEF, FIELDS_SUMMARY, FILTER_GEOMETRY, FORMATS, FacetBlockComponent, FacetBlockStubComponent, FacetItemComponent, FacetItemStubComponent, FacetListComponent, FacetsContainerComponent, FacetsModule, FavoriteStarComponent, FavoritesService, FeatureAuthModule, FeatureCatalogModule, FeatureDatavizModule, FeatureDetailComponent, FeatureEditorModule, FeatureInfoService, FeatureMapModule, FeatureRecordModule, FeatureSearchModule, FetchError, FieldsService, FigureComponent, FigureContainerComponent, FileTranslateLoader, FilterDropdownComponent, FormFieldArrayComponent, FormFieldComponent, FormFieldFileComponent, FormFieldObjectComponent, FormFieldRichComponent, FormFieldSimpleComponent, FormFieldSpatialExtentComponent, FormFieldTemporalExtentComponent, FuzzySearchComponent, GN_UI_VERSION, GeoTableViewComponent, GeocodingComponent, Gn4Converter, Gn4PlatformMapper, Gn4PlatformService, Gn4Repository, Gn4SettingsService, GravatarService, HttpLoaderFactory, I18nInterceptor, ImageFallbackDirective, ImageOverlayPreviewComponent, InteractiveTableColumnComponent, InteractiveTableComponent, Iso191153Converter, Iso19139Converter, LANGUAGES_LIST, LANGUAGE_NAMES, LANGUAGE_STORAGE_KEY, LANG_2_TO_3_MAPPER, LANG_3_TO_2_MAPPER, LOGIN_URL, LONLAT_CRS_CODES, LangService, LanguageSwitcherComponent, LayersPanelComponent, LinkCardComponent, LinkClassifierService, LinkUsage, LoadingMaskComponent, LogService, MAP_CONFIG_FIXTURE, MAP_FEATURE_KEY, METADATA_LANGUAGE, MY_FORMATS, MapComponent, MapContainerComponent, MapContextComponent, MapContextLayerTypeEnum, MapContextService, MapFacade, MapInstanceDirective, MapManagerService, MapStyleService, MapUtilsService, MapViewComponent, MarkdownParserComponent, MaxLinesComponent, mdview_actions as MdViewActions, MdViewFacade, MetadataCatalogComponent, MetadataContactComponent, MetadataInfoComponent, MetadataLinkType, MetadataQualityComponent, MetadataQualityItemComponent, MyOrgService, NavigationButtonComponent, ORGANIZATIONS_STRATEGY, ORGANIZATION_URL_TOKEN, OrganisationPreviewComponent, OrganisationsComponent, OrganisationsFilterComponent, OrganisationsResultComponent, OrganizationsFromGroupsService, OrganizationsFromMetadataService, PAGINATE, PARSE_DELIMITER, PATCH_RESULTS_AGGREGATIONS, PROXY_PATH, Paginate, PaginationButtonsComponent, PaginationComponent, PatchResultsAggregations, PopupAlertComponent, ProgressBarComponent, ProxyService, QUERY_FIELDS, RECORD_URL_TOKEN, REQUEST_MORE_ON_AGGREGATION, REQUEST_MORE_RESULTS, REQUEST_NEW_RESULTS, RESULTS_LAYOUT_CONFIG, ROUTER_CONFIG, ROUTER_ROUTE_DATASET, ROUTER_ROUTE_SEARCH, ROUTER_STATE_KEY, ROUTE_PARAMS, RecordApiFormComponent, RecordFormComponent, RecordMetricComponent, RecordPreviewCardComponent, RecordPreviewComponent, RecordPreviewFeedComponent, RecordPreviewListComponent, RecordPreviewRowComponent, RecordPreviewTextComponent, RecordPreviewTitleComponent, RecordsMetricsComponent, RecordsService, RelatedRecordCardComponent, RequestMoreOnAggregation, RequestMoreResults, RequestNewResults, ResultsHitsContainerComponent, ResultsHitsNumberComponent, ResultsLayoutComponent, ResultsLayoutConfigItem, ResultsListComponent, ResultsListContainerComponent, ResultsListItemComponent, ResultsTableComponent, RouterEffects, RouterFacade, RouterService, SEARCH_FEATURE_KEY, SET_CONFIG_AGGREGATIONS, SET_CONFIG_FILTERS, SET_CONFIG_REQUEST_FIELDS, SET_ERROR, SET_FAVORITES_ONLY, SET_FILTERS, SET_INCLUDE_ON_AGGREGATION, SET_PAGE_SIZE, SET_RESULTS_AGGREGATIONS, SET_RESULTS_HITS, SET_RESULTS_LAYOUT, SET_SEARCH, SET_SORT_BY, SET_SPATIAL_FILTER_ENABLED, SearchEffects, SearchFacade, SearchInputComponent, SearchResultsErrorComponent, SearchRouterContainerDirective, SearchService, SearchStateContainerDirective, SelectionService, SetConfigAggregations, SetConfigFilters, SetConfigRequestFields, SetError, SetFavoritesOnly, SetFilters, SetIncludeOnAggregation, SetPageSize, SetResultsAggregations, SetResultsHits, SetResultsLayout, SetSearch, SetSortBy, SetSpatialFilterEnabled, SiteTitleComponent, SortByComponent, SourceLabelComponent, SourcesService, SpinningLoaderComponent, StarToggleComponent, StepBarComponent, StickyHeaderComponent, SupportedTypes, TABLE_ITEM_FIXTURE, TABLE_ITEM_FIXTURE_HAB, THUMBNAIL_PLACEHOLDER, TRANSLATE_DEFAULT_CONFIG, TRANSLATE_WITH_OVERRIDES_CONFIG, TableComponent, TableViewComponent, TextAreaComponent, TextInputComponent, ThemeService, ThumbnailComponent, UPDATE_CONFIG_AGGREGATIONS, UPDATE_FILTERS, UPDATE_REQUEST_AGGREGATION_TERM, UiCatalogModule, UiDatavizModule, UiElementsModule, FacetsModule$1 as UiFacetsModule, UiInputsModule, UiLayoutModule, UiMapModule, UiSearchModule, UiWidgetsModule, UpdateConfigAggregations, UpdateFilters, UserPreviewComponent, UtilI18nModule, UtilSharedModule, ViewportIntersectorComponent, WEB_COMPONENT_EMBEDDER_URL, WFS_MAX_FEATURES, WizardComponent, WizardFieldComponent, WizardFieldType, WizardService, WizardSummarizeComponent, _reset, addLayer, changeLayerOrder, checkFileFormat, clearLayerError, createFuzzyFilter, currentPage, defaultMapOptions, dragPanCondition, dropEmptyTranslations, editorReducer, findConverterForDocument, getArrayItem, getAsArray, getAsUrl, getBadgeColor, getCustomTranslations, getError, getFavoritesOnly, getFileFormat, getFileFormatFromServiceOutput, getFirstValue, getFormatPriority, getGeometryFromGeoJSON, getGlobalConfig, getJsonDataItemsProxy, getLangFromBrowser, getLinkLabel, getLinkPriority, getMapLayers, getMapState, getMetadataQualityConfig, getMimeTypeForFormat, getOptionalMapConfig, getOptionalSearchConfig, getPageSize, getSearchConfigAggregations, getSearchFilters, getSearchResults, getSearchResultsAggregations, getSearchResultsHits, getSearchResultsLayout, getSearchResultsLoading, getSearchSortBy, getSearchState, getSearchStateSearch, getSpatialFilterEnabled, getTemporalRangeUnion, getThemeConfig, initSearch, initialEditorState, initialMapState, initialState, isConfigLoaded, isEndOfResults, isFormatInQueryParam, loadAppConfig, mapContact, mapKeywords, mapLogo, mapOrganization, mapReducer, markRecordAsChanged, mimeTypeToFormat, mouseWheelZoomCondition, openDataset, openRecord, parse, placeholder, propagateToDocumentOnly, provideGn4, provideRepositoryUrl, readDataset, readDatasetHeaders, reducer$2 as reducer, reducerSearch, removeLayer, removeSearchParams, removeWhitespace, saveRecord, saveRecordFailure, saveRecordSuccess, selectEditorState, selectFallback, selectFallbackFields, selectField, selectRecord, selectRecordChangedSinceSave, selectRecordFields, selectRecordFieldsConfig, selectRecordSaveError, selectRecordSaving, selectTranslatedField, selectTranslatedValue, setLayerError, sortByFromString, sortByToString, sortByToStrings, stripHtml, toDate, totalPages, updateLayer, updateRecordField };
32653
33230
  //# sourceMappingURL=geonetwork-ui.mjs.map