mirror of
https://github.com/IliesAllali/parenthese.git
synced 2026-11-09 23:50:58 +00:00
fix(gedcom) : export en 5.5.1 avec SEX U pour un sexe « autre »
GEDCOM 5.5.1 n'admet que M, F et U ; SEX X n'existe qu'en 7.0, et l'export écrivait X sous un en-tête 5.5.1. Un sexe « autre » s'écrit maintenant U. L'import lit toujours X comme avant. Conséquence connue : à l'aller-retour, « autre » revient comme « non précisé » (5.5.1 n'a pas de valeur pour « autre »). Décision à trancher, voir la description de la PR. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
65a1333d56
commit
6bb0a832d2
3 files changed
+44
-8
No files matched your search
@@ -8,7 +8,7 @@ import { indexGedcomRecords, mediaRefsForPerson, noteText, photoPathForPerson }
|
||||
import type { GedcomRecords } from '../lib/gedcom-photos.js'
|
||||
import type { MembershipRole } from '../types/auth.js'
|
||||
import { nextSiblingOrder } from '../lib/sibling-order.js'
|
||||
import { sexOrNull } from '../lib/person-sex.js'
|
||||
import { sexOrNull, type PersonSex } from '../lib/person-sex.js'
|
||||
|
||||
const treeIdParamSchema = z.object({
|
||||
id: z.string().min(1),
|
||||
@@ -285,6 +285,15 @@ function pairKey(a: string, b: string | null): string {
|
||||
return b ? [a, b].sort().join('|') : `${a}|`
|
||||
}
|
||||
|
||||
// GEDCOM 5.5.1 n'admet que M, F et U (inconnu, autre). « X » n'existe qu'en 7.0 : un sexe « autre » s'écrit U,
|
||||
// et l'import relit X comme avant.
|
||||
export function gedcomSexValue(sex: PersonSex | null): 'M' | 'F' | 'U' | null {
|
||||
if (sex === 'male') return 'M'
|
||||
if (sex === 'female') return 'F'
|
||||
if (sex === 'other') return 'U'
|
||||
return null
|
||||
}
|
||||
|
||||
function sanitizeXref(id: string): string {
|
||||
return id.replace(/[^A-Za-z0-9_]/g, '_')
|
||||
}
|
||||
@@ -456,10 +465,8 @@ export const gedcomRoutes: FastifyPluginAsync = async (app) => {
|
||||
lines.push(`1 NAME ${gedcomNameValue(person.firstName, person.lastName)}`)
|
||||
if (person.nickname) lines.push(`2 NICK ${oneLine(person.nickname)}`)
|
||||
|
||||
const sex = sexOrNull(person.sex)
|
||||
if (sex === 'male') lines.push('1 SEX M')
|
||||
else if (sex === 'female') lines.push('1 SEX F')
|
||||
else if (sex === 'other') lines.push('1 SEX X')
|
||||
const sexValue = gedcomSexValue(sexOrNull(person.sex))
|
||||
if (sexValue) lines.push(`1 SEX ${sexValue}`)
|
||||
|
||||
const personEvents = eventsByPerson.get(person.id) ?? []
|
||||
const birthDetails = personEvents.find((event) => event.type === 'birth')
|
||||
|
||||
@@ -921,7 +921,7 @@ describe('Sexe dans le GEDCOM (issue #114)', () => {
|
||||
await app.close()
|
||||
})
|
||||
|
||||
it('aller-retour : other sort en SEX X, non précisé sans ligne SEX, et tout se relit à l’identique', async () => {
|
||||
it('aller-retour : other sort en SEX U (GEDCOM 5.5.1), non précisé sans ligne SEX, le reste se relit à l’identique', async () => {
|
||||
const app = createApp()
|
||||
await app.ready()
|
||||
const token = (app as any).jwt.sign({ kind: 'tree_access', sub: 'tree:tree-1:visitor', treeId: 'tree-1', role: 'visitor', accessVersion: new Date('2026-02-11T10:00:00.000Z').getTime() })
|
||||
@@ -940,10 +940,12 @@ describe('Sexe dans le GEDCOM (issue #114)', () => {
|
||||
const response = await app.inject({ method: 'GET', url: '/trees/tree-1/export/gedcom', headers: { authorization: `Bearer ${token}` } })
|
||||
expect(response.statusCode).toBe(200)
|
||||
const text = response.body.replace(/\r\n/g, '\n')
|
||||
expect(text).toContain('1 NAME Camille /Martin/\n1 SEX X\n')
|
||||
expect(text).toContain('1 NAME Camille /Martin/\n1 SEX U\n')
|
||||
expect(text).not.toContain('SEX X')
|
||||
expect(text).toMatch(/1 NAME Claude \/Martin\/\n(?!1 SEX)/)
|
||||
|
||||
expect(await importer(app, text)).toEqual({ Jean: 'male', Marie: 'female', Camille: 'other', Claude: null })
|
||||
// SEX U se relit comme non précisé : 5.5.1 n'a pas de valeur pour « autre ». SEX X reste lu à l'import (ligne 915).
|
||||
expect(await importer(app, text)).toEqual({ Jean: 'male', Marie: 'female', Camille: null, Claude: null })
|
||||
await app.close()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { parseSex } from '../src/lib/person-sex'
|
||||
import { gedcomSexValue, parseGedcom } from '../src/routes/gedcom'
|
||||
|
||||
// Export en GEDCOM 5.5.1 : SEX ne vaut que M, F ou U (#118). « X » n'existe qu'en GEDCOM 7.
|
||||
describe('export GEDCOM 5.5.1 : valeur SEX', () => {
|
||||
it('écrit M, F, et U pour un sexe « autre »', () => {
|
||||
expect(gedcomSexValue('male')).toBe('M')
|
||||
expect(gedcomSexValue('female')).toBe('F')
|
||||
expect(gedcomSexValue('other')).toBe('U')
|
||||
})
|
||||
|
||||
it("n'écrit jamais X, et ne déclare rien pour un sexe non précisé", () => {
|
||||
for (const sex of ['male', 'female', 'other', null] as const) {
|
||||
expect(gedcomSexValue(sex)).not.toBe('X')
|
||||
}
|
||||
expect(gedcomSexValue(null)).toBeNull()
|
||||
})
|
||||
|
||||
it('l’import relit toujours SEX X comme « autre », et U comme non précisé', () => {
|
||||
const sexes = parseGedcom(['0 @I1@ INDI', '1 SEX X', '0 @I2@ INDI', '1 SEX U'].join('\n'))
|
||||
.filter((node) => node.tag === 'INDI')
|
||||
.map((indi) => parseSex(indi.children.find((child) => child.tag === 'SEX')?.value ?? null))
|
||||
expect(sexes).toEqual(['other', null])
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user