From bca05438031cd39adde1080a5d1d6a0351dbb5ea Mon Sep 17 00:00:00 2001 From: IliesAllali Date: Fri, 16 Oct 2026 20:20:17 +0200 Subject: [PATCH] Import GEDCOM : lieu lisible, sans colonnes vides ni codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Heredis remplit toutes les colonnes de son format de lieu, même vides, avec le code INSEE (« La Roche-sur-Yon,85191,Vendée,Pays de la Loire,France, »). Le lieu de naissance importé garde les noms seulement, séparés par « , », sans case vide, code INSEE ou postal, ni répétition. Un lieu déjà propre ne change pas. Co-Authored-By: Claude Opus 5.5 --- backend/src/routes/gedcom.ts | 18 +++++++++++++++++- backend/test/gedcom-place.test.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 backend/test/gedcom-place.test.ts diff --git a/backend/src/routes/gedcom.ts b/backend/src/routes/gedcom.ts index 036a92e..7fd8c37 100644 --- a/backend/src/routes/gedcom.ts +++ b/backend/src/routes/gedcom.ts @@ -37,6 +37,22 @@ function clip(value: string | null, max: number): string | null { return trimmed ? trimmed.slice(0, max) : null } +// Lieu d'un GEDCOM : les logiciels remplissent toutes les colonnes de leur format de lieu, même vides, et y +// glissent des codes. Heredis écrit « La Roche-sur-Yon,85191,Vendée,Pays de la Loire,France, » (ville, code +// INSEE, département, région, pays, subdivision). On garde les noms, sans case vide, sans code INSEE ni +// postal, sans répétition : « La Roche-sur-Yon, Vendée, Pays de la Loire, France ». +export function cleanGedcomPlace(value: string | null | undefined): string | null { + if (!value) return null + const parts: string[] = [] + for (const raw of value.split(',')) { + const part = raw.trim() + if (!part || /^(\d{4,5}|2[AB]\d{3})$/i.test(part)) continue + if (parts.length && parts[parts.length - 1].toLowerCase() === part.toLowerCase()) continue + parts.push(part) + } + return parts.length ? parts.join(', ') : null +} + // Export : un champ sur une ligne ne doit jamais en créer une autre (enregistrement injecté) function oneLine(value: string | null | undefined): string { return String(value ?? '').replace(/[\r\n]+/g, ' ') @@ -527,7 +543,7 @@ export const gedcomRoutes: FastifyPluginAsync = async (app) => { const birtNode = findChild(indi, 'BIRT') const birthDateIso = gedcomDateToIso(findChild(birtNode, 'DATE')?.value ?? '') - const birthPlace = clip(findChild(birtNode, 'PLAC')?.value ?? null, 200) + const birthPlace = clip(cleanGedcomPlace(findChild(birtNode, 'PLAC')?.value), 200) const deatNode = findChild(indi, 'DEAT') const deathDateIso = gedcomDateToIso(findChild(deatNode, 'DATE')?.value ?? '') diff --git a/backend/test/gedcom-place.test.ts b/backend/test/gedcom-place.test.ts new file mode 100644 index 0000000..d82b0bc --- /dev/null +++ b/backend/test/gedcom-place.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from 'vitest' + +import { cleanGedcomPlace } from '../src/routes/gedcom' + +describe('lieu importé d’un GEDCOM', () => { + it('Heredis : colonnes vides et code INSEE retirés', () => { + expect(cleanGedcomPlace('La Roche-sur-Yon,85191,Vendée,Pays de la Loire,France,')).toBe('La Roche-sur-Yon, Vendée, Pays de la Loire, France') + expect(cleanGedcomPlace('Ménéac,56129,,,,')).toBe('Ménéac') + expect(cleanGedcomPlace('Ajaccio,2A004,Corse-du-Sud,Corse,France,')).toBe('Ajaccio, Corse-du-Sud, Corse, France') + }) + + it('Gramps, Geneanet : un lieu déjà propre ne change pas', () => { + expect(cleanGedcomPlace('Lille, Nord, Hauts-de-France, France')).toBe('Lille, Nord, Hauts-de-France, France') + expect(cleanGedcomPlace('Paris')).toBe('Paris') + }) + + it('code postal et répétitions écartés', () => { + expect(cleanGedcomPlace('Caen, 14000, Calvados, Calvados, France')).toBe('Caen, Calvados, France') + }) + + it('rien de lisible : pas de lieu', () => { + expect(cleanGedcomPlace(',,,,')).toBeNull() + expect(cleanGedcomPlace('')).toBeNull() + expect(cleanGedcomPlace(undefined)).toBeNull() + }) +})