diff --git a/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts b/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts index da3842711b..c3a783cd08 100644 --- a/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +++ b/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts @@ -2,9 +2,9 @@ import { Individual, Organization, } from '@geonetwork-ui/common/domain/model/record' -import { getRoleFromRoleCode } from '../iso19139/codelists/role.mapper' +import { getRoleFromRoleCode } from '../iso19139/utils/role.mapper' import { Thesaurus } from './types' -import { getKeywordTypeFromKeywordTypeCode } from '../iso19139/codelists/keyword.mapper' +import { getKeywordTypeFromKeywordTypeCode } from '../iso19139/utils/keyword.mapper' export type SourceWithUnknownProps = { [key: string]: unknown } diff --git a/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts b/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts index a6941f2e1e..625b857d28 100644 --- a/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +++ b/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts @@ -15,8 +15,8 @@ import { } from './atomic-operations' import { MetadataUrlService } from './metadata-url.service' import { Injectable } from '@angular/core' -import { getStatusFromStatusCode } from '../iso19139/codelists/status.mapper' -import { getUpdateFrequencyFromFrequencyCode } from '../iso19139/codelists/update-frequency.mapper' +import { getStatusFromStatusCode } from '../iso19139/utils/status.mapper' +import { getUpdateFrequencyFromFrequencyCode } from '../iso19139/utils/update-frequency.mapper' import { CatalogRecord, Constraint, diff --git a/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts b/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts index dee1186777..7c6efab2ed 100644 --- a/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +++ b/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts @@ -33,6 +33,7 @@ import { Role, } from '@geonetwork-ui/common/domain/model/record' import { matchMimeType } from '../common/distribution.mapper' +import { fullNameToParts } from '../iso19139/utils/individual-name' export function readKind(rootEl: XmlElement): RecordKind { return pipe( @@ -97,10 +98,7 @@ export function extractIndividual( extractCharacterString(), map((fullName) => { if (!fullName) return [] - const parts = fullName.split(/\s+/) - if (!parts.length) return [fullName, null] - const first = parts.shift() - return [first, parts.join(' ')] + return fullNameToParts(fullName) }) ) const getContact = findNestedElement('cit:contactInfo', 'cit:CI_Contact') diff --git a/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts b/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts index 8bb4afaf12..91c6bf75ad 100644 --- a/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +++ b/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts @@ -48,6 +48,7 @@ import { writeLinkage, } from '../iso19139/write-parts' import { findIdentification } from '../iso19139/read-parts' +import { namePartsToFull } from '../iso19139/utils/individual-name' export function writeUniqueIdentifier( record: CatalogRecord, @@ -241,17 +242,14 @@ export function writeOwnerOrganization( } export function appendResponsibleParty(contact: Individual) { - const name = - contact.lastName && contact.firstName - ? `${contact.firstName} ${contact.lastName}` - : contact.lastName || contact.firstName || null + const fullName = namePartsToFull(contact.firstName, contact.lastName) const createIndividual = pipe( createElement('cit:individual'), createChild('cit:CI_Individual'), - name + fullName ? appendChildren( - pipe(createElement('cit:name'), writeCharacterString(name)) + pipe(createElement('cit:name'), writeCharacterString(fullName)) ) : noop, contact.position diff --git a/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts b/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts index 2bf8c97c83..674feff624 100644 --- a/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +++ b/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts @@ -14,8 +14,8 @@ import { UpdateFrequency, UpdateFrequencyCustom, } from '@geonetwork-ui/common/domain/model/record' -import { getStatusFromStatusCode } from './codelists/status.mapper' -import { getUpdateFrequencyFromFrequencyCode } from './codelists/update-frequency.mapper' +import { getStatusFromStatusCode } from './utils/status.mapper' +import { getUpdateFrequencyFromFrequencyCode } from './utils/update-frequency.mapper' import { findChildElement, findChildrenElement, @@ -37,9 +37,10 @@ import { mapArray, pipe, } from '../function-utils' -import { getRoleFromRoleCode } from './codelists/role.mapper' +import { getRoleFromRoleCode } from './utils/role.mapper' import { matchMimeType, matchProtocol } from '../common/distribution.mapper' -import { getKeywordTypeFromKeywordTypeCode } from './codelists/keyword.mapper' +import { getKeywordTypeFromKeywordTypeCode } from './utils/keyword.mapper' +import { fullNameToParts } from './utils/individual-name' export function extractCharacterString(): ChainableFunction< XmlElement, @@ -143,10 +144,7 @@ export function extractIndividual(): ChainableFunction { extractCharacterString(), map((fullName) => { if (!fullName) return [] - const parts = fullName.split(/\s+/) - if (!parts.length) return [fullName, null] - const first = parts.shift() - return [first, parts.join(' ')] + return fullNameToParts(fullName) }) ) const getOrganization = extractOrganization() diff --git a/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.spec.ts b/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.spec.ts new file mode 100644 index 0000000000..18fd1b68d9 --- /dev/null +++ b/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.spec.ts @@ -0,0 +1,23 @@ +import { fullNameToParts, namePartsToFull } from './individual-name' + +describe('individual name utils', () => { + it('fullNameToParts', () => { + expect(fullNameToParts('John Doe')).toEqual(['John', 'Doe']) + expect(fullNameToParts('John')).toEqual(['John', null]) + expect(fullNameToParts(' John Jim Doe Blah ')).toEqual([ + 'John', + 'Jim Doe Blah', + ]) + }) + it('namePartsToFull', () => { + expect(namePartsToFull('John', 'Doe')).toEqual('John Doe') + expect(namePartsToFull('John', null)).toEqual('John') + expect(namePartsToFull(null, 'Doe')).toEqual('Doe') + expect(namePartsToFull(null, null)).toEqual(null) + expect(namePartsToFull('', ' ')).toEqual(null) + expect(namePartsToFull('John', 'Doe Blah')).toEqual('John Doe Blah') + expect(namePartsToFull(' John Jim ', ' Doe Blah ')).toEqual( + 'John Jim Doe Blah' + ) + }) +}) diff --git a/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.ts b/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.ts new file mode 100644 index 0000000000..ef3ddb7b1a --- /dev/null +++ b/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.ts @@ -0,0 +1,20 @@ +/** + * Parts are [firstName, lastName] + * Second part will be null if no separation could be done + * @param fullName + */ +export function fullNameToParts(fullName: string): [string, string | null] { + const parts = fullName.trim().split(/\s+/) + const first = parts.shift() + return [first, parts.join(' ').trim() || null] +} + +export function namePartsToFull( + firstName: string | null, + lastName: string | null +): string | null { + const first = firstName?.trim() + const last = lastName?.trim() + if (!first && !last) return null + return last && first ? `${first} ${last}` : last || first +} diff --git a/libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.ts b/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.ts similarity index 100% rename from libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.ts rename to libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.ts diff --git a/libs/api/metadata-converter/src/lib/iso19139/codelists/role.mapper.ts b/libs/api/metadata-converter/src/lib/iso19139/utils/role.mapper.ts similarity index 100% rename from libs/api/metadata-converter/src/lib/iso19139/codelists/role.mapper.ts rename to libs/api/metadata-converter/src/lib/iso19139/utils/role.mapper.ts diff --git a/libs/api/metadata-converter/src/lib/iso19139/codelists/status.mapper.ts b/libs/api/metadata-converter/src/lib/iso19139/utils/status.mapper.ts similarity index 100% rename from libs/api/metadata-converter/src/lib/iso19139/codelists/status.mapper.ts rename to libs/api/metadata-converter/src/lib/iso19139/utils/status.mapper.ts diff --git a/libs/api/metadata-converter/src/lib/iso19139/codelists/update-frequency.mapper.ts b/libs/api/metadata-converter/src/lib/iso19139/utils/update-frequency.mapper.ts similarity index 100% rename from libs/api/metadata-converter/src/lib/iso19139/codelists/update-frequency.mapper.ts rename to libs/api/metadata-converter/src/lib/iso19139/utils/update-frequency.mapper.ts diff --git a/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts b/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts index f9f40ba562..21b54ca1c0 100644 --- a/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +++ b/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts @@ -48,6 +48,7 @@ import { } from '../function-utils' import format from 'date-fns/format' import { readKind } from './read-parts' +import { namePartsToFull } from './utils/individual-name' export function writeCharacterString( text: string @@ -235,10 +236,7 @@ export function getISODuration(updateFrequency: UpdateFrequencyCustom): string { } export function appendResponsibleParty(contact: Individual) { - const name = - contact.lastName && contact.firstName - ? `${contact.firstName} ${contact.lastName}` - : contact.lastName || contact.firstName || null + const fullName = namePartsToFull(contact.firstName, contact.lastName) const createAddress = pipe( createElement('gmd:address'), @@ -287,11 +285,11 @@ export function appendResponsibleParty(contact: Individual) { return appendChildren( pipe( createElement('gmd:CI_ResponsibleParty'), - name + fullName ? appendChildren( pipe( createElement('gmd:individualName'), - writeCharacterString(name) + writeCharacterString(fullName) ) ) : noop,