gedcom-ts 2026.6.1 → 2026.6.2
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.
- package/CHANGELOG.md +85 -72
- package/README.md +121 -117
- package/dist/booklet.cjs +1 -1
- package/dist/booklet.mjs +1 -1
- package/dist/commons/DateAct.d.ts +1 -0
- package/dist/export/GEDCOM.d.ts +9 -4
- package/dist/export/buildGedzipBlob.d.ts +10 -0
- package/dist/export/familyUnionExport.d.ts +10 -0
- package/dist/import/LoadFile.d.ts +5 -1
- package/dist/import/ReadGed.d.ts +7 -1
- package/dist/import/SplitedInformations.d.ts +2 -1
- package/dist/import/enrichMarriageActsFromUnions.d.ts +6 -0
- package/dist/import/extractZipContent.d.ts +6 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.mjs +1 -1
- package/dist/utils/gedcom/spouseAssoRoles.d.ts +2 -0
- package/dist/utils/gedcom/transferProgress.d.ts +12 -0
- package/dist/version.d.ts +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ A graphical demo showcasing the public API (import a `.ged` / `.zip`, browse the
|
|
|
28
28
|
## Package
|
|
29
29
|
|
|
30
30
|
- NPM: [gedcom-ts](https://www.npmjs.com/package/gedcom-ts)
|
|
31
|
-
- Current release **`2026.6.
|
|
31
|
+
- Current release **`2026.6.2`** — parsing de dates GEDCOM (mois en minuscules). Version format **CalVer** `AAAA.M.micro` (e.g. `2026.6.2` = June 2026, micro release). See [CHANGELOG.md](CHANGELOG.md).
|
|
32
32
|
- Entry points:
|
|
33
33
|
- **`gedcom-ts`** — import, model, edit layer, export, geocoding
|
|
34
34
|
- **`gedcom-ts/booklet`** — PDF livret (`pdf-lib` en peerDependency, chargé depuis `node_modules`)
|
|
@@ -85,13 +85,11 @@ You work with a `ReadGed` (after import) and a flat `Act[]` built from every per
|
|
|
85
85
|
|
|
86
86
|
The library groups variants of the same place with **`citiesAreSimilar`**, not exact string equality.
|
|
87
87
|
|
|
88
|
-
|
|
89
88
|
| Label A | Label B | Same place? |
|
|
90
89
|
| ----------- | ------------------------------------ | --------------------------- |
|
|
91
90
|
| `Pleurtuit` | `Pleurtuit, Ille-et-Vilaine, France` | Yes |
|
|
92
91
|
| `Paris` | `Paris, TX, USA` | Depends on similarity rules |
|
|
93
92
|
|
|
94
|
-
|
|
95
93
|
Use the functions in the tables below for grouping, geocoding, and maps. Do **not** compare raw strings yourself, and do **not** use `normalizeCityKey` for grouping (spelling normalization only).
|
|
96
94
|
|
|
97
95
|
### Prepare act list
|
|
@@ -112,7 +110,6 @@ function collectAllActs(ged: ReadGed): Act[] {
|
|
|
112
110
|
|
|
113
111
|
When the user picks a city and a Nominatim result, update **every similar act that still has no GPS** — not only acts with the exact same label.
|
|
114
112
|
|
|
115
|
-
|
|
116
113
|
| Step | Function |
|
|
117
114
|
| ---------------------------------------------- | ----------------------------------------------------------- |
|
|
118
115
|
| 1. Context from the tree (countries, centroid) | `inferGeocodeContext(ged)` |
|
|
@@ -120,7 +117,6 @@ When the user picks a city and a Nominatim result, update **every similar act th
|
|
|
120
117
|
| 3. Acts to update | `actsNeedingGeocodeForCity(allActs, cityName)` |
|
|
121
118
|
| 4. Write coordinates | `applyGeocodeCandidateToActs(targets, candidate, cityName)` |
|
|
122
119
|
|
|
123
|
-
|
|
124
120
|
```ts
|
|
125
121
|
import {
|
|
126
122
|
inferGeocodeContext,
|
|
@@ -150,7 +146,9 @@ One row per city; `withoutCoordCount` is how many acts still need GPS.
|
|
|
150
146
|
```ts
|
|
151
147
|
import { groupActsBySimilarCity } from "gedcom-ts";
|
|
152
148
|
|
|
153
|
-
const groups = groupActsBySimilarCity(allActs, {
|
|
149
|
+
const groups = groupActsBySimilarCity(allActs, {
|
|
150
|
+
onlyWithoutCoordinates: true,
|
|
151
|
+
});
|
|
154
152
|
|
|
155
153
|
for (const group of groups) {
|
|
156
154
|
console.log(group.cityLabel, group.withoutCoordCount);
|
|
@@ -185,7 +183,6 @@ After a full geocode via `actsNeedingGeocodeForCity`, you should not get a clust
|
|
|
185
183
|
|
|
186
184
|
### Geocoding API cheat sheet
|
|
187
185
|
|
|
188
|
-
|
|
189
186
|
| Goal | Call |
|
|
190
187
|
| ------------------------- | ---------------------------------------------------------------- |
|
|
191
188
|
| Search | `searchPlacesWithContext(city, inferGeocodeContext(ged))` |
|
|
@@ -195,7 +192,6 @@ After a full geocode via `actsNeedingGeocodeForCity`, you should not get a clust
|
|
|
195
192
|
| Map marker id | `clusterKeyForCity(city)` |
|
|
196
193
|
| Inconsistencies | `findHarmonizationClusters(ged)` |
|
|
197
194
|
|
|
198
|
-
|
|
199
195
|
Network: `GET https://nominatim.openstreetmap.org/search?q=…&format=jsonv2` with a `User-Agent` (`gedcom-ts/<version> (genealogy library)`). For offline or mocked search, pass `fetchFn` in `searchPlaces` / `searchPlacesWithContext` options.
|
|
200
196
|
|
|
201
197
|
The legacy callback `getCityCoordinates` is deprecated — use the flow above.
|
|
@@ -208,18 +204,18 @@ The **`gedcom-ts/booklet`** subpath builds a printable family booklet: cover pag
|
|
|
208
204
|
|
|
209
205
|
Code is split so the host app only downloads what it uses. Approximate sizes after minify (obfuscation adds ~25–30 KiB on `gedcom-ts/booklet`).
|
|
210
206
|
|
|
211
|
-
| Artifact
|
|
212
|
-
|
|
|
213
|
-
| `gedcom-ts` (`dist/index.mjs`)
|
|
214
|
-
| `gedcom-ts/booklet` (`dist/booklet.mjs`)
|
|
215
|
-
| `locale-chunks/booklet-locale-*`
|
|
216
|
-
| `feature-chunks/booklet-logo-draw`
|
|
217
|
-
| `feature-chunks/booklet-timeline-raster`
|
|
218
|
-
| `font-chunks/booklet-pdf-font-bytes-ar`
|
|
219
|
-
| `font-chunks/booklet-pdf-font-bytes-he`
|
|
220
|
-
| `font-chunks/booklet-pdf-font-bytes-zh`
|
|
221
|
-
| `font-chunks/booklet-pdf-font-bytes-zh-ext` |
|
|
222
|
-
| `pdf-lib` (peer, not in gedcom-ts)
|
|
207
|
+
| Artifact | Size (typ.) | When loaded |
|
|
208
|
+
| ------------------------------------------- | ----------: | -------------------------------------------- |
|
|
209
|
+
| `gedcom-ts` (`dist/index.mjs`) | ~180 KiB | GEDCOM import / edit / export |
|
|
210
|
+
| `gedcom-ts/booklet` (`dist/booklet.mjs`) | ~100 KiB | livret (collect, estimate, PDF) |
|
|
211
|
+
| `locale-chunks/booklet-locale-*` | 14–26 KiB | one UI language |
|
|
212
|
+
| `feature-chunks/booklet-logo-draw` | ~11 KiB | cover logo (`coverLogo !== false`) |
|
|
213
|
+
| `feature-chunks/booklet-timeline-raster` | ~3 KiB | `timelineStyle: "canvas"` |
|
|
214
|
+
| `font-chunks/booklet-pdf-font-bytes-ar` | ~43 KiB | Arabic PDF |
|
|
215
|
+
| `font-chunks/booklet-pdf-font-bytes-he` | ~13 KiB | Hebrew PDF |
|
|
216
|
+
| `font-chunks/booklet-pdf-font-bytes-zh` | ~190 KiB | Chinese PDF (base subset) |
|
|
217
|
+
| `font-chunks/booklet-pdf-font-bytes-zh-ext` | ~1.4 MiB | Chinese PDF when GEDCOM names need extra Han |
|
|
218
|
+
| `pdf-lib` (peer, not in gedcom-ts) | ~500 KiB+ | any PDF generation |
|
|
223
219
|
|
|
224
220
|
**Not bundled in gedcom-ts:** `fflate` (main entry, external), `pdf-lib` (booklet peer). **`bidi-js`** and **`naqqash`** (Arabic shaping / RTL reordering) ship inside `gedcom-ts/booklet` today.
|
|
225
221
|
|
|
@@ -227,12 +223,12 @@ Call **`await ensureBookletLocale(locale)`** before sync APIs. `generateGenealog
|
|
|
227
223
|
|
|
228
224
|
**Lazy chunk subpaths** (for bundler preload or explicit `import()` — normal apps should use `ensureBookletLocale()` instead):
|
|
229
225
|
|
|
230
|
-
| Subpath
|
|
231
|
-
|
|
|
226
|
+
| Subpath | Role |
|
|
227
|
+
| ----------------------------------------------------------------------------------- | --------------------------------------------------- |
|
|
232
228
|
| `gedcom-ts/booklet/locale-chunks/booklet-locale-{en,fr,de,nl,es,zh,it,pt,pl,ar,he}` | Messages, narratives, date/place helpers per locale |
|
|
233
|
-
| `gedcom-ts/booklet/font-chunks/booklet-pdf-font-bytes-{ar,he,zh,zh-ext}`
|
|
234
|
-
| `gedcom-ts/booklet/feature-chunks/booklet-logo-draw`
|
|
235
|
-
| `gedcom-ts/booklet/feature-chunks/booklet-timeline-raster`
|
|
229
|
+
| `gedcom-ts/booklet/font-chunks/booklet-pdf-font-bytes-{ar,he,zh,zh-ext}` | Subset Noto font bytes |
|
|
230
|
+
| `gedcom-ts/booklet/feature-chunks/booklet-logo-draw` | Cover logo SVG paths |
|
|
231
|
+
| `gedcom-ts/booklet/feature-chunks/booklet-timeline-raster` | Canvas timeline PNG rasterizer |
|
|
236
232
|
|
|
237
233
|
Each subpath is listed in `package.json` **`exports`** with matching **`types`** (`.d.ts` under `dist/booklet/…`) and runtime (`.mjs` / `.cjs` under `dist/…`). TypeScript resolves them via `exports.types` (`moduleResolution: bundler` / `node16`). Adding a locale updates `scripts/booklet-chunk-manifest.mjs`; `npm run build:js` regenerates chunk files and syncs `exports`.
|
|
238
234
|
|
|
@@ -289,7 +285,14 @@ async function exportBooklet(file: File) {
|
|
|
289
285
|
|
|
290
286
|
const chapters = groupBookletIntoChapters(entries, locale);
|
|
291
287
|
const families = chapters.reduce((n, ch) => n + ch.families.length, 0);
|
|
292
|
-
const size = estimateBookletSize(
|
|
288
|
+
const size = estimateBookletSize(
|
|
289
|
+
chapters,
|
|
290
|
+
entries.length,
|
|
291
|
+
families,
|
|
292
|
+
"summary",
|
|
293
|
+
"canvas",
|
|
294
|
+
locale,
|
|
295
|
+
);
|
|
293
296
|
console.log(size.label);
|
|
294
297
|
|
|
295
298
|
const pdf = await generateGenealogyBookletPdf(
|
|
@@ -316,25 +319,25 @@ Use `scope: "all"` and `referencePerson: null` to include every individual in th
|
|
|
316
319
|
|
|
317
320
|
### `collectBookletPersons` options
|
|
318
321
|
|
|
319
|
-
| Option
|
|
320
|
-
|
|
|
321
|
-
| `ged`
|
|
322
|
-
| `scope`
|
|
323
|
-
| `referencePerson` | Root person for `"from-reference"`; `null` if scope is `"all"`
|
|
324
|
-
| `maxGeneration`
|
|
325
|
-
| `locale`
|
|
322
|
+
| Option | Role |
|
|
323
|
+
| ----------------- | --------------------------------------------------------------------------------------------------- |
|
|
324
|
+
| `ged` | `ReadGed` after import |
|
|
325
|
+
| `scope` | `"all"` or `"from-reference"` (Sosa from `referencePerson`) |
|
|
326
|
+
| `referencePerson` | Root person for `"from-reference"`; `null` if scope is `"all"` |
|
|
327
|
+
| `maxGeneration` | Max Sosa generation (e.g. `6`); ignored when `scope === "all"` |
|
|
328
|
+
| `locale` | `BookletLocale` (default `"en"`) — `en`, `fr`, `de`, `nl`, `es`, `zh`, `it`, `pt`, `pl`, `ar`, `he` |
|
|
326
329
|
|
|
327
330
|
Helpers: `personDisplayName`, `buildBookletPersonEntry`, `sortBookletEntries`, `bookletSexFromPerson`, `DEFAULT_BOOKLET_LOCALE`, `BOOKLET_LOCALES`, `isBookletLocaleRtl`.
|
|
328
331
|
|
|
329
332
|
### `generateGenealogyBookletPdf` options
|
|
330
333
|
|
|
331
|
-
| Option
|
|
332
|
-
|
|
|
333
|
-
| `detailLevel`
|
|
334
|
-
| `timelineStyle` | `"off"` \| `"canvas"`
|
|
335
|
-
| `coverLogo`
|
|
336
|
-
| `locale`
|
|
337
|
-
| `unicodeFont`
|
|
334
|
+
| Option | Values | Effect |
|
|
335
|
+
| --------------- | ------------------------------------------------------- | ------------------------------------------------------ |
|
|
336
|
+
| `detailLevel` | `"summary"` \| `"detailed"` | Short prose per person vs longer biographies |
|
|
337
|
+
| `timelineStyle` | `"off"` \| `"canvas"` | Generation timeline pages per chapter |
|
|
338
|
+
| `coverLogo` | `true` (default), `false`, or `DrawGedcomTsLogoOptions` | gedcom-ts vector logo on the cover |
|
|
339
|
+
| `locale` | `BookletLocale` (default `"en"`) | Narrative, chapter titles, PDF chrome, timeline legend |
|
|
340
|
+
| `unicodeFont` | `Uint8Array` (optional) | Replace bundled Noto font for `zh` / `ar` / `he` |
|
|
338
341
|
|
|
339
342
|
`BookletPdfMeta`: `title`, `scopeLabel`, `personCount`, optional `referenceName` (usually translated in the host app).
|
|
340
343
|
|
|
@@ -358,17 +361,17 @@ await drawGedcomTsLogoOnPage(page, defaultCoverLogoOptions());
|
|
|
358
361
|
|
|
359
362
|
### Booklet API cheat sheet
|
|
360
363
|
|
|
361
|
-
| Goal
|
|
362
|
-
|
|
|
363
|
-
| Persons for the booklet
|
|
364
|
-
| Chapters / families
|
|
364
|
+
| Goal | Export |
|
|
365
|
+
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
366
|
+
| Persons for the booklet | `collectBookletPersons` |
|
|
367
|
+
| Chapters / families | `groupBookletIntoChapters`, `partnerNamesLabel` |
|
|
365
368
|
| Localized narratives (custom UI) | `buildPersonSummaryNarrative`, `buildPersonDetailedNarratives`, `buildFamilyNarrative`, `buildChapterIntroNarrative` |
|
|
366
|
-
| Page estimate
|
|
367
|
-
| Timeline data / PNG
|
|
368
|
-
| PDF output
|
|
369
|
-
| Locale helpers
|
|
370
|
-
| Font preload (host)
|
|
371
|
-
| Logo
|
|
369
|
+
| Page estimate | `estimateBookletSize`, `bookletSizeAdvice` |
|
|
370
|
+
| Timeline data / PNG | `buildGenerationTimeline`, `rasterizeGenerationTimelinePng` |
|
|
371
|
+
| PDF output | `generateGenealogyBookletPdf`, `downloadBookletPdf`, `toPdfText`, `preparePdfText` |
|
|
372
|
+
| Locale helpers | `resolveBookletLocale`, `bookletLocaleToBcp47`, `bookletTextDirection`, `BOOKLET_RTL_LOCALES`, `ensureBookletLocale` |
|
|
373
|
+
| Font preload (host) | `registerBookletPdfFontBytes`, `registerPdfFontkit`, `localeNeedsUnicodePdfFont` |
|
|
374
|
+
| Logo | `ensureBookletLogo`, `drawGedcomTsLogoOnPage`, `getGedcomTsLogoPaths`, `defaultCoverLogoOptions` |
|
|
372
375
|
|
|
373
376
|
## Audio and oral history (GEDCOM 7)
|
|
374
377
|
|
|
@@ -416,18 +419,21 @@ async function addInterview(readGed: ReadGed, person: Person, mp3: File) {
|
|
|
416
419
|
editAct(act)
|
|
417
420
|
.asAudioInterview(readGed.persons, objeMap)
|
|
418
421
|
.setTranscription("Suite de l'entretien…")
|
|
419
|
-
.attachAudio({
|
|
422
|
+
.attachAudio({
|
|
423
|
+
audioUri: "https://example.org/rec.mp3",
|
|
424
|
+
ownerIndi: person.INDI,
|
|
425
|
+
});
|
|
420
426
|
```
|
|
421
427
|
|
|
422
|
-
| Goal
|
|
423
|
-
|
|
|
424
|
-
| Create interview act
|
|
425
|
-
| Attach audio to act
|
|
426
|
-
| Detect imported interviews | `isAudioInterviewAct`, `isAudioInterviewEvenType`
|
|
427
|
-
| Read transcription / media | `getAudioInterviewTranscription`, `primaryAudioInterviewUri`
|
|
428
|
-
| OBJE round-trip
|
|
429
|
-
| Low-level OBJE parse/emit
|
|
430
|
-
| EVEN type constants
|
|
428
|
+
| Goal | API |
|
|
429
|
+
| -------------------------- | ------------------------------------------------------------------------ |
|
|
430
|
+
| Create interview act | `createAudioInterviewAct` |
|
|
431
|
+
| Attach audio to act | `attachAudioInterviewToAct`, `editAct(act).asAudioInterview()` |
|
|
432
|
+
| Detect imported interviews | `isAudioInterviewAct`, `isAudioInterviewEvenType` |
|
|
433
|
+
| Read transcription / media | `getAudioInterviewTranscription`, `primaryAudioInterviewUri` |
|
|
434
|
+
| OBJE round-trip | `readGed.objeRecordsById` → `objeRecordsById` in export options |
|
|
435
|
+
| Low-level OBJE parse/emit | `parseStandaloneObjeBlock`, `formatObjeRecordBlock`, `guessMediFromForm` |
|
|
436
|
+
| EVEN type constants | `GEDCOM_7_EVEN_TYPE_AUDIO_INTERVIEW`, `GEDCOM_7_EVEN_TYPE_ORAL_HISTORY` |
|
|
431
437
|
|
|
432
438
|
## API reference
|
|
433
439
|
|
|
@@ -470,7 +476,10 @@ import { importGedFile, IMPORT_ERR_ZIP_GED_UNREADABLE } from "gedcom-ts";
|
|
|
470
476
|
try {
|
|
471
477
|
await importGedFile(file);
|
|
472
478
|
} catch (error) {
|
|
473
|
-
if (
|
|
479
|
+
if (
|
|
480
|
+
error instanceof Error &&
|
|
481
|
+
error.message === IMPORT_ERR_ZIP_GED_UNREADABLE
|
|
482
|
+
) {
|
|
474
483
|
alert("Please unzip the archive manually and import the .ged file.");
|
|
475
484
|
}
|
|
476
485
|
}
|
|
@@ -482,25 +491,23 @@ Result of an import. Standalone `0 @O…@ OBJE` blocks with at least one `FILE`
|
|
|
482
491
|
|
|
483
492
|
Notable members:
|
|
484
493
|
|
|
485
|
-
|
|
486
|
-
|
|
|
487
|
-
|
|
|
488
|
-
| `
|
|
489
|
-
| `
|
|
490
|
-
| `
|
|
491
|
-
| `
|
|
492
|
-
| `
|
|
493
|
-
| `
|
|
494
|
-
| `
|
|
495
|
-
| `
|
|
496
|
-
| `
|
|
497
|
-
| `
|
|
498
|
-
| `
|
|
499
|
-
| `
|
|
500
|
-
| `
|
|
501
|
-
| `
|
|
502
|
-
| `rehydratePlacesFromActs()` | Rebuilds `placesMap` from act places (e.g. after manual graph edits). Use `editReadGed(readGed).addPerson(...)` to register persons so maps stay coherent. |
|
|
503
|
-
|
|
494
|
+
| Member | Description |
|
|
495
|
+
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
496
|
+
| `persons: Person[]` | Imported individuals. |
|
|
497
|
+
| `mapPersons: Map<number, Person>` | `INDI` (integer) → `Person`. |
|
|
498
|
+
| `partnersMap: Map<number, Person[]>` | Family id → spouses. |
|
|
499
|
+
| `childsMap: Map<number, Person[]>` | Family id → children. |
|
|
500
|
+
| `placesMap: Map<string, Place>` | City name → `Place` (first occurrence wins). |
|
|
501
|
+
| `mapFiles: Map<string, File>` | Relative path → media `File` (for ZIP imports). |
|
|
502
|
+
| `datasetVersion: GedcomDatasetVersion` | `"7.0"`, `"5.5"` or `"unknown"`. |
|
|
503
|
+
| `objeRecordsById: Map<number, ObjeRecord>` | Parsed `OBJE` records (audio, images, …) keyed by `@O{n}@`. |
|
|
504
|
+
| `preservedTopLevelRecords: string[]` | Raw blocks for partial round-trip. |
|
|
505
|
+
| `resolveIndividualPointer(raw)` | Resolves `@I12@`, `I12`, `@Homer_Simpson@`, `Homer_Simpson` to a `Person`. |
|
|
506
|
+
| `getChildrenForParent(parent)` | All children attached to a parent (via `FAMS`). |
|
|
507
|
+
| `getChildrenOfFamily(familyId)` | Children of a single family. |
|
|
508
|
+
| `groupPartners()` | Rebuilds `partnersMap` / `childsMap` after editing links. |
|
|
509
|
+
| `generateUniqueIndi()` | Next free `INDI` number for new persons. |
|
|
510
|
+
| `rehydratePlacesFromActs()` | Rebuilds `placesMap` from act places (e.g. after manual graph edits). Use `editReadGed(readGed).addPerson(...)` to register persons so maps stay coherent. |
|
|
504
511
|
|
|
505
512
|
```ts
|
|
506
513
|
import { ReadGed } from "gedcom-ts";
|
|
@@ -545,7 +552,7 @@ function exportGed(readGed: ReadGed) {
|
|
|
545
552
|
|
|
546
553
|
#### `ExportGedzipFile`
|
|
547
554
|
|
|
548
|
-
Writes a `.zip` (GEDZIP) bundling the GEDCOM and all attached `MultimediaFile` payloads.
|
|
555
|
+
Writes a `.zip` (GEDZIP) bundling the GEDCOM and all attached `MultimediaFile` payloads. Compression is streamed per entry (`ZipWriter` + `BlobReader`) so large archives are not built entirely in memory.
|
|
549
556
|
|
|
550
557
|
```ts
|
|
551
558
|
import { ExportGedzipFile, Person } from "gedcom-ts";
|
|
@@ -553,13 +560,16 @@ import { ExportGedzipFile, Person } from "gedcom-ts";
|
|
|
553
560
|
async function exportZip(persons: Person[]) {
|
|
554
561
|
await new ExportGedzipFile("my-tree", persons).download();
|
|
555
562
|
}
|
|
563
|
+
|
|
564
|
+
async function exportZipBlob(persons: Person[]) {
|
|
565
|
+
return new ExportGedzipFile("my-tree", persons).gedzipBlob();
|
|
566
|
+
}
|
|
556
567
|
```
|
|
557
568
|
|
|
558
569
|
#### `GedcomExportOptions`
|
|
559
570
|
|
|
560
571
|
Options shared by both exporters:
|
|
561
572
|
|
|
562
|
-
|
|
563
573
|
| Option | Effect |
|
|
564
574
|
| ---------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
565
575
|
| `extraTopLevelRecords` | Raw `0 …` blocks re-emitted before `SUBM` / `TRLR` (round-trip with `readGed.preservedTopLevelRecords`). |
|
|
@@ -569,7 +579,6 @@ Options shared by both exporters:
|
|
|
569
579
|
| `headDestination` | Value of `HEAD`.`DEST` (target app / URI). |
|
|
570
580
|
| `headSchemaTagDefs` | Extension tag definitions emitted as `HEAD`.`SCHMA` / `2 TAG …`. |
|
|
571
581
|
|
|
572
|
-
|
|
573
582
|
### Domain model
|
|
574
583
|
|
|
575
584
|
#### `Person`, `Sex`
|
|
@@ -673,17 +682,10 @@ const sorted = [...GEDCOM_7_EVENT_SORT_ORDER];
|
|
|
673
682
|
|
|
674
683
|
#### `DateAct`, `Day`, `Month`, `dateToDateLine`, `days`, `months`, `TypeDateActSimpleQualifier`
|
|
675
684
|
|
|
676
|
-
GEDCOM dates with full GEDCOM 7 / 5.5 support, including `INT`, `EST`, `CAL`, `BET … AND …`, `FROM … TO …`, ISO `YYYY-MM-DD`, `3 PHRASE` under `DATE`, `3 TIME`, and a verbatim fallback for unparseable payloads.
|
|
685
|
+
GEDCOM dates with full GEDCOM 7 / 5.5 support, including `INT`, `EST`, `CAL`, `BET … AND …`, `FROM … TO …`, ISO `YYYY-MM-DD`, `3 PHRASE` under `DATE`, `3 TIME`, and a verbatim fallback for unparseable payloads. Month tokens (`JAN`, `may`, …) and simple qualifiers are matched **case-insensitively** (since **2026.6.2**).
|
|
677
686
|
|
|
678
687
|
```ts
|
|
679
|
-
import {
|
|
680
|
-
DateAct,
|
|
681
|
-
Day,
|
|
682
|
-
Month,
|
|
683
|
-
dateToDateLine,
|
|
684
|
-
days,
|
|
685
|
-
months,
|
|
686
|
-
} from "gedcom-ts";
|
|
688
|
+
import { DateAct, Day, Month, dateToDateLine, days, months } from "gedcom-ts";
|
|
687
689
|
|
|
688
690
|
const day: Day = 12;
|
|
689
691
|
const month: Month = months[0]; // JAN
|
|
@@ -779,17 +781,15 @@ editPerson(person)
|
|
|
779
781
|
editDateAct(person.acts.list[0].dateAct!).setExactDate(1900, "JAN", 1);
|
|
780
782
|
```
|
|
781
783
|
|
|
782
|
-
|
|
783
|
-
|
|
|
784
|
-
|
|
|
785
|
-
| `
|
|
786
|
-
| `
|
|
787
|
-
| `
|
|
788
|
-
| `
|
|
789
|
-
| `
|
|
790
|
-
| `
|
|
791
|
-
| `editNotes(notes)` / `NotesEdit` | `add`, `addNew`, `insertAt`, `insertNewAt`, `replaceAt`, `removeAt`, `removeNote`, `removeLast`, `clear`, `at`, `indexOfNote`. |
|
|
792
|
-
|
|
784
|
+
| Helper / class | Purpose |
|
|
785
|
+
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
786
|
+
| `editPerson(person)` / `PersonEdit` | Identity, `FAMS` / `FAMC` / `removeFams*`, `nameVariants()` / `attributes()` / `multimedia()`, bulk `clear*`, entry points to `acts()` and `notes()`. |
|
|
787
|
+
| `editActs(acts)` / `ActsEdit` | `add`, `addNew`, `insertAt`, `insertNewAt`, `replaceAt`, `removeAt`, `removeAct`, `removeLast`, `clear`, `sortByDate`, `at`, `indexOfAct`. |
|
|
788
|
+
| `editAct(act)` / `ActEdit` | `setType`, `setIndis`, dates, place, EVEN fields, preserved lines, `notes()`, `multimedia()`, `asAudioInterview()`, `clearNotes`, `clearMultimedia`. |
|
|
789
|
+
| `editAudioInterviewAct(act)` / `AudioInterviewActEdit` | Oral-history facade: `attachAudio`, `setTranscription`, `setDescription`, `registerPendingObje`, `isAudioInterview`, … |
|
|
790
|
+
| `editDateAct(dateAct)` / `DateActEdit` | `clear`, `applyGedcomPayload`, `setExactDate`, `setQualified`, `setBetween`, `setFromTo`, `setTime`, `setDatePhrase` / `appendDatePhrase`, `setVerbatimPayload`. |
|
|
791
|
+
| `editPlace(place)` / `PlaceEdit` | `setFromGedcom7Payload`, `setCity`, `setCounty`, `setState`, `setCountry`, `setPlacPhrase` / `appendPlacPhrase` / `clearPlacPhrase`, `setCoordinates` / `clearCoordinates` / `replaceCoordinateModel`, `clearStructured`. |
|
|
792
|
+
| `editNotes(notes)` / `NotesEdit` | `add`, `addNew`, `insertAt`, `insertNewAt`, `replaceAt`, `removeAt`, `removeNote`, `removeLast`, `clear`, `at`, `indexOfNote`. |
|
|
793
793
|
|
|
794
794
|
### Dataset editing: `ReadGed`, graph, clone, export options, validation
|
|
795
795
|
|
|
@@ -816,7 +816,11 @@ import {
|
|
|
816
816
|
} from "gedcom-ts";
|
|
817
817
|
|
|
818
818
|
const readGed = createEmptyReadGed();
|
|
819
|
-
const p = createPersonStub(readGed.generateUniqueIndi(), {
|
|
819
|
+
const p = createPersonStub(readGed.generateUniqueIndi(), {
|
|
820
|
+
sex: Sex.M,
|
|
821
|
+
firstnames: ["Jean"],
|
|
822
|
+
lastname: "Dupont",
|
|
823
|
+
});
|
|
820
824
|
editReadGed(readGed).addPerson(p);
|
|
821
825
|
p.acts.add(new Act(Identifier.BIRT, new DateAct("1900")));
|
|
822
826
|
|
|
@@ -847,17 +851,15 @@ validateReadGed(readGed, {
|
|
|
847
851
|
|
|
848
852
|
`tryAddPersonToReadGed`, `tryRemovePersonFromReadGedByIndi`, `tryLinkChildToFamily`, `tryUnlinkChildFromFamily`, and `tryCreateMarriageFamily` return a `CommandResult` (`ok` + `issues` or `value` + optional `warnings`). `editReadGed(...).addPerson` uses these checks internally (throws on blocking errors). For UI or transactional flows, prefer the `try*` APIs and inspect `commandBlockingIssues`.
|
|
849
853
|
|
|
850
|
-
|
|
851
|
-
|
|
|
852
|
-
|
|
|
853
|
-
| `
|
|
854
|
-
| `
|
|
855
|
-
| `
|
|
856
|
-
| `
|
|
857
|
-
| `createMarriageFamily`, `linkChildToFamily`, `unlinkChildFromFamily`, `removeFamilyReferencesFromDataset` | Create family `F` and spouse acts; optional `{ eventTag }` (default `MARR`, also `ENGA`, banns, contract, `EVEN` + `CreateActInit`, …). See `GEDCOM_7_PAIR_UNION_EVENT_TAGS`. |
|
|
854
|
+
| Export | Role |
|
|
855
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
856
|
+
| `editReadGed(readGed)` / `ReadGedEdit` | `addPerson`, `removePersonByIndi`, `preserved()` → `PreservedTopLevelEdit` (`append`, `insertAt`, `replaceAt`, `removeAt`, `clear`) on `preservedTopLevelRecords`. Low-level helpers: `addPersonToReadGed`, `removePersonFromReadGedByIndi`. |
|
|
857
|
+
| `editGedcomExportOptions(opts)` / `GedcomExportOptionsEdit` | Fluent setters for `extraTopLevelRecords`, `objeRecordsById`, `headLanguageTag`, `headCopyright`, `headDestination`, `headSchemaTagDefs`. |
|
|
858
|
+
| `clonePerson(person, newIndi)` / `cloneAct(act)` / `person.clone` / `act.clone` | Deep copies for templates or undo stacks. |
|
|
859
|
+
| `nextFamilyId(persons)` | Next internal family id `F`. |
|
|
860
|
+
| `createMarriageFamily`, `linkChildToFamily`, `unlinkChildFromFamily`, `removeFamilyReferencesFromDataset` | Create family `F` and spouse acts; optional `{ eventTag }` (default `MARR`, also `ENGA`, banns, contract, `EVEN` + `CreateActInit`, …). See `GEDCOM_7_PAIR_UNION_EVENT_TAGS`. |
|
|
858
861
|
| `validateReadGed`, `assertReadGedConsistent`, `validatePerson`, `assertPersonConsistent` | Typed `code` / `severity` (`error` \| `warn`). Options: `checkMarrParticipants`, `checkDuplicateIndis`, `checkFamcWithoutSpouses`, `checkFamsWithoutSpouses`, `checkDuplicateFamsEntries`, `checkAncestorCycles`. Assertions: `failOn` (default: `error`). |
|
|
859
|
-
| `tryAddPersonToReadGed`, `tryRemovePersonFromReadGedByIndi`, `tryLinkChildToFamily`, `tryUnlinkChildFromFamily`, `tryCreateMarriageFamily`, `commandBlockingIssues` | Command layer with `CommandResult` / `validate*Command` prechecks.
|
|
860
|
-
|
|
862
|
+
| `tryAddPersonToReadGed`, `tryRemovePersonFromReadGedByIndi`, `tryLinkChildToFamily`, `tryUnlinkChildFromFamily`, `tryCreateMarriageFamily`, `commandBlockingIssues` | Command layer with `CommandResult` / `validate*Command` prechecks. |
|
|
861
863
|
|
|
862
864
|
### Utilities
|
|
863
865
|
|
|
@@ -930,7 +932,7 @@ const primary = selectPrimaryNameVariant(person.nameVariants);
|
|
|
930
932
|
|
|
931
933
|
#### `GEDCOM_LIBRARY_VERSION`
|
|
932
934
|
|
|
933
|
-
CalVer string written in exported `HEAD`.`SOUR`.`VERS` (same value as the npm package version, e.g. `2026.6.
|
|
935
|
+
CalVer string written in exported `HEAD`.`SOUR`.`VERS` (same value as the npm package version, e.g. `2026.6.2`).
|
|
934
936
|
|
|
935
937
|
```ts
|
|
936
938
|
import { GEDCOM_LIBRARY_VERSION } from "gedcom-ts";
|
|
@@ -947,11 +949,13 @@ try {
|
|
|
947
949
|
const readGed = await importGedFile(file);
|
|
948
950
|
console.log(readGed.persons.length);
|
|
949
951
|
} catch (error) {
|
|
950
|
-
if (
|
|
952
|
+
if (
|
|
953
|
+
error instanceof Error &&
|
|
954
|
+
error.message === IMPORT_ERR_ZIP_GED_UNREADABLE
|
|
955
|
+
) {
|
|
951
956
|
console.error("Encrypted ZIP: please extract the .ged manually.");
|
|
952
957
|
} else {
|
|
953
958
|
console.error("GED import failed:", error);
|
|
954
959
|
}
|
|
955
960
|
}
|
|
956
961
|
```
|
|
957
|
-
|