gedcom-ts 2.0.2 → 2.1.0
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 +92 -0
- package/README.md +370 -89
- package/dist/commons/Act.d.ts +38 -6
- package/dist/commons/DateAct.d.ts +40 -2
- package/dist/commons/Identifier.enum.d.ts +3 -0
- package/dist/commons/IndiAttribute.d.ts +11 -0
- package/dist/commons/IndiGedcomSubLine.d.ts +6 -0
- package/dist/commons/MultimediaFile.d.ts +13 -2
- package/dist/commons/Person.d.ts +21 -3
- package/dist/commons/PersonNameVariant.d.ts +21 -0
- package/dist/commons/Place.d.ts +19 -0
- package/dist/commons/gedcomEventTags.d.ts +10 -0
- package/dist/edit/ActEdit.d.ts +29 -0
- package/dist/edit/ActsEdit.d.ts +17 -0
- package/dist/edit/DateActEdit.d.ts +37 -0
- package/dist/edit/NotesEdit.d.ts +14 -0
- package/dist/edit/PersonEdit.d.ts +27 -0
- package/dist/edit/PlaceEdit.d.ts +23 -0
- package/dist/edit/index.d.ts +19 -0
- package/dist/export/GEDCOM.d.ts +33 -4
- package/dist/import/LoadFile.d.ts +14 -0
- package/dist/import/ReadGed.d.ts +43 -0
- package/dist/import/SplitedInformations.d.ts +29 -3
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +17 -4
- package/dist/index.mjs +1 -1
- package/dist/utils/gedcom/actExtraction.d.ts +3 -1
- package/dist/utils/gedcom/datasetVersion.d.ts +7 -0
- package/dist/utils/gedcom/extractIndiNamesAndAttributes.d.ts +4 -0
- package/dist/utils/gedcom/labelKeyedRecords.d.ts +13 -0
- package/dist/utils/gedcom/mediaFormFromUri.d.ts +2 -0
- package/dist/utils/gedcom/parseStandaloneObje.d.ts +9 -0
- package/dist/utils/gedcom/personName.d.ts +7 -0
- package/dist/utils/gedcom/pointers.d.ts +16 -0
- package/dist/version.d.ts +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,13 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
`gedcom-ts` is a browser-oriented TypeScript library to:
|
|
4
4
|
|
|
5
|
-
- import genealogy data from GEDCOM (`.ged`) or ZIP (`.zip`)
|
|
6
|
-
- work with a typed JSON model (persons, acts, notes, media,
|
|
7
|
-
-
|
|
5
|
+
- import genealogy data from GEDCOM (`.ged`) or ZIP (`.zip` / `.gdz`)
|
|
6
|
+
- work with a typed JSON model (persons, acts, dates, places, notes, media, name variants, attributes)
|
|
7
|
+
- edit the model in-place through a fluent, chainable API (`editPerson`, `editAct`, …)
|
|
8
|
+
- export data back to GEDCOM (`.ged`) or GEDZIP (`.zip`)
|
|
9
|
+
|
|
10
|
+
## Live demo
|
|
11
|
+
|
|
12
|
+
A graphical demo showcasing the public API (import a `.ged` / `.zip`, browse the typed model, export back) is available at **[https://gedcomts.jaunet.me](https://gedcomts.jaunet.me)**
|
|
8
13
|
|
|
9
14
|
## Project
|
|
10
15
|
|
|
11
16
|
- NPM package: [gedcom-ts](https://www.npmjs.com/package/gedcom-ts)
|
|
17
|
+
- **GEDCOM 7 roadmap** (spec gedcom.io, coverage matrix, prioritized gaps): [docs/GEDCOM7-roadmap.md](docs/GEDCOM7-roadmap.md)
|
|
12
18
|
|
|
13
19
|
## Installation
|
|
14
20
|
|
|
@@ -19,58 +25,143 @@ npm install gedcom-ts
|
|
|
19
25
|
## Runtime Requirements
|
|
20
26
|
|
|
21
27
|
- modern browser runtime (`File`, `Blob`, `XMLHttpRequest`, `URL.createObjectURL`)
|
|
22
|
-
- for pure Node.js usage, DOM polyfills are required
|
|
28
|
+
- for pure Node.js usage, DOM polyfills are required (the library targets browsers)
|
|
23
29
|
|
|
24
|
-
##
|
|
30
|
+
## Quick start
|
|
25
31
|
|
|
26
32
|
```ts
|
|
27
|
-
import { importGedFile } from "gedcom-ts";
|
|
33
|
+
import { importGedFile, ExportGedzipFile } from "gedcom-ts";
|
|
28
34
|
|
|
29
|
-
async function
|
|
35
|
+
async function roundTrip(file: File) {
|
|
30
36
|
const readGed = await importGedFile(file);
|
|
31
|
-
|
|
37
|
+
const persons = readGed.persons;
|
|
38
|
+
|
|
39
|
+
if (persons.length > 0) {
|
|
40
|
+
persons[0].lastname = persons[0].lastname.toUpperCase();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await new ExportGedzipFile("updated-tree", persons).download();
|
|
32
44
|
}
|
|
33
45
|
```
|
|
34
46
|
|
|
35
|
-
|
|
47
|
+
Typical workflow:
|
|
48
|
+
|
|
49
|
+
1. import a file with `importGedFile` (or start from `createEmptyReadGed()`)
|
|
50
|
+
2. read / mutate the typed `Person`, `Act`, `Place`, `Note`, `MultimediaFile` objects (directly or through `editPerson` / `editAct` / `editPlace` / …)
|
|
51
|
+
3. export as `.ged` (`ExportGedcomFile`) or `.zip` (`ExportGedzipFile`)
|
|
52
|
+
|
|
53
|
+
## Public API reference
|
|
54
|
+
|
|
55
|
+
Everything exported from `gedcom-ts` is documented below with a short description and a minimal usage snippet. The full list mirrors the public exports of `src/index.ts`.
|
|
36
56
|
|
|
37
|
-
|
|
38
|
-
- a ZIP containing one GED file + optional media files
|
|
57
|
+
### Importing a file
|
|
39
58
|
|
|
40
|
-
|
|
59
|
+
#### `importGedFile(file: File): Promise<ReadGed>`
|
|
41
60
|
|
|
42
|
-
|
|
61
|
+
Detects the format from the file MIME / extension and dispatches to the right reader.
|
|
62
|
+
|
|
63
|
+
- accepts a single `.ged` file
|
|
64
|
+
- accepts a `.zip` / `.gdz` archive containing one `.ged` + optional media files
|
|
65
|
+
- throws `Error(IMPORT_ERR_ZIP_GED_UNREADABLE)` when the embedded `.ged` cannot be decoded (typical cause: password-protected ZIP)
|
|
43
66
|
|
|
44
67
|
```ts
|
|
45
|
-
import {
|
|
68
|
+
import { importGedFile } from "gedcom-ts";
|
|
46
69
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
70
|
+
const readGed = await importGedFile(fileInput.files![0]);
|
|
71
|
+
console.log(readGed.persons.length, readGed.datasetVersion);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### `createEmptyReadGed(options?): ReadGed`
|
|
75
|
+
|
|
76
|
+
Creates an empty graph with the same runtime shape as a successful import (empty `persons`, initialized `mapPersons` / `partnersMap` / `childsMap` / `placesMap` / `mapFiles`). Use it to start a brand-new tree without parsing a file. `datasetVersion` is set to `"7.0"`.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { createEmptyReadGed } from "gedcom-ts";
|
|
80
|
+
|
|
81
|
+
const readGed = createEmptyReadGed();
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### `IMPORT_ERR_ZIP_GED_UNREADABLE: string`
|
|
85
|
+
|
|
86
|
+
Sentinel error message thrown by `importGedFile` when a `.ged` inside a ZIP cannot be decoded (typically because the ZIP is password-protected). Compare with `error.message === IMPORT_ERR_ZIP_GED_UNREADABLE` to display a tailored message.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { importGedFile, IMPORT_ERR_ZIP_GED_UNREADABLE } from "gedcom-ts";
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
await importGedFile(file);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
if (error instanceof Error && error.message === IMPORT_ERR_ZIP_GED_UNREADABLE) {
|
|
95
|
+
alert("Please unzip the archive manually and import the .ged file.");
|
|
96
|
+
}
|
|
52
97
|
}
|
|
53
98
|
```
|
|
54
99
|
|
|
55
|
-
|
|
100
|
+
#### `ReadGed`
|
|
101
|
+
|
|
102
|
+
Result of an import. Top-level GEDCOM records not modeled into the typed graph (`OBJE`, `REPO`, `SOUR`, `SUBM`, …) are kept in order on `readGed.preservedTopLevelRecords` for round-trip export.
|
|
103
|
+
|
|
104
|
+
Notable members:
|
|
105
|
+
|
|
106
|
+
| Member | Description |
|
|
107
|
+
| --- | --- |
|
|
108
|
+
| `persons: Person[]` | Imported individuals. |
|
|
109
|
+
| `mapPersons: Map<number, Person>` | `INDI` (integer) → `Person`. |
|
|
110
|
+
| `partnersMap: Map<number, Person[]>` | Family id → spouses. |
|
|
111
|
+
| `childsMap: Map<number, Person[]>` | Family id → children. |
|
|
112
|
+
| `placesMap: Map<string, Place>` | City name → `Place` (first occurrence wins). |
|
|
113
|
+
| `mapFiles: Map<string, File>` | Relative path → media `File` (for ZIP imports). |
|
|
114
|
+
| `datasetVersion: GedcomDatasetVersion` | `"7.0"`, `"5.5"` or `"unknown"`. |
|
|
115
|
+
| `preservedTopLevelRecords: string[]` | Raw blocks for partial round-trip. |
|
|
116
|
+
| `resolveIndividualPointer(raw)` | Resolves `@I12@`, `I12`, `@Homer_Simpson@`, `Homer_Simpson` to a `Person`. |
|
|
117
|
+
| `getChildrenForParent(parent)` | All children attached to a parent (via `FAMS`). |
|
|
118
|
+
| `getChildrenOfFamily(familyId)` | Children of a single family. |
|
|
119
|
+
| `groupPartners()` | Rebuilds `partnersMap` / `childsMap` after editing links. |
|
|
120
|
+
| `generateUniqueIndi()` | Next free `INDI` number for new persons. |
|
|
56
121
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
122
|
+
```ts
|
|
123
|
+
import { ReadGed } from "gedcom-ts";
|
|
124
|
+
|
|
125
|
+
function describe(readGed: ReadGed) {
|
|
126
|
+
return {
|
|
127
|
+
version: readGed.datasetVersion,
|
|
128
|
+
persons: readGed.persons.length,
|
|
129
|
+
places: readGed.placesMap.size,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Exporting
|
|
60
135
|
|
|
61
|
-
|
|
136
|
+
#### `ExportGedcomFile`
|
|
62
137
|
|
|
63
|
-
|
|
138
|
+
Writes a GEDCOM 7 (`.ged`) file. Three call signatures are supported:
|
|
64
139
|
|
|
65
140
|
```ts
|
|
66
|
-
|
|
141
|
+
new ExportGedcomFile(persons);
|
|
142
|
+
new ExportGedcomFile(title, persons);
|
|
143
|
+
new ExportGedcomFile(title, persons, options);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`.download()` triggers a browser download. `.toString()` returns the GEDCOM text.
|
|
67
147
|
|
|
68
|
-
|
|
69
|
-
|
|
148
|
+
```ts
|
|
149
|
+
import { ExportGedcomFile, type ReadGed } from "gedcom-ts";
|
|
150
|
+
|
|
151
|
+
function exportGed(readGed: ReadGed) {
|
|
152
|
+
new ExportGedcomFile("my-tree", readGed.persons, {
|
|
153
|
+
extraTopLevelRecords: readGed.preservedTopLevelRecords,
|
|
154
|
+
headLanguageTag: "fr-FR",
|
|
155
|
+
headCopyright: "© 2026 Family Archive",
|
|
156
|
+
headDestination: "https://gedcom.io/",
|
|
157
|
+
headSchemaTagDefs: [{ tag: "_FOO", uri: "https://example.com/foo" }],
|
|
158
|
+
}).download();
|
|
70
159
|
}
|
|
71
160
|
```
|
|
72
161
|
|
|
73
|
-
|
|
162
|
+
#### `ExportGedzipFile`
|
|
163
|
+
|
|
164
|
+
Writes a `.zip` (GEDZIP) bundling the GEDCOM and all attached `MultimediaFile` payloads.
|
|
74
165
|
|
|
75
166
|
```ts
|
|
76
167
|
import { ExportGedzipFile, Person } from "gedcom-ts";
|
|
@@ -80,37 +171,132 @@ async function exportZip(persons: Person[]) {
|
|
|
80
171
|
}
|
|
81
172
|
```
|
|
82
173
|
|
|
83
|
-
|
|
174
|
+
#### `GedcomExportOptions`
|
|
175
|
+
|
|
176
|
+
Options shared by both exporters:
|
|
84
177
|
|
|
85
|
-
|
|
178
|
+
| Option | Effect |
|
|
179
|
+
| --- | --- |
|
|
180
|
+
| `extraTopLevelRecords` | Raw `0 …` blocks re-emitted before `SUBM` / `TRLR` (round-trip with `readGed.preservedTopLevelRecords`). |
|
|
181
|
+
| `headLanguageTag` | BCP 47 tag for `HEAD`.`LANG` (defaults to `en-US`). |
|
|
182
|
+
| `headCopyright` | One-line `1 COPR` notice. |
|
|
183
|
+
| `headDestination` | Value of `HEAD`.`DEST` (target app / URI). |
|
|
184
|
+
| `headSchemaTagDefs` | Extension tag definitions emitted as `HEAD`.`SCHMA` / `2 TAG …`. |
|
|
86
185
|
|
|
87
|
-
###
|
|
186
|
+
### Domain model
|
|
187
|
+
|
|
188
|
+
#### `Person`, `Sex`
|
|
88
189
|
|
|
89
190
|
```ts
|
|
90
191
|
import { Person, Sex } from "gedcom-ts";
|
|
91
192
|
|
|
92
193
|
const person = new Person();
|
|
93
194
|
person.INDI = 1;
|
|
94
|
-
person.SEX = Sex.M;
|
|
195
|
+
person.SEX = Sex.M; // M | F | U | X
|
|
95
196
|
person.firstnames = ["Jean"];
|
|
96
197
|
person.lastname = "DUPONT";
|
|
198
|
+
|
|
199
|
+
person.addMultimedia(/* MultimediaFile */);
|
|
200
|
+
person.deleteMultimedia("1/photo.jpg");
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Key fields: `INDI`, `sosa`, `SEX`, `firstnames`, `lastname`, `FAMC`, `FAMS`, `acts`, `notes`, `multimediaFiles`, `nameVariants`, `attributes`.
|
|
204
|
+
|
|
205
|
+
#### `PersonGedcomImportOptions` (type)
|
|
206
|
+
|
|
207
|
+
Optional hints consumed by `Person.createPersonJson` when re-parsing a single individual block (label-keyed pointers for `FAMS` / `FAMC` / `NOTE`, and standalone `OBJE` payloads). Useful when assembling a graph manually outside `ReadGed`.
|
|
208
|
+
|
|
209
|
+
#### `PersonNameVariant`, `PersonNameTranslation`
|
|
210
|
+
|
|
211
|
+
Lossless representation of every `1 NAME` block of an individual (type, `NPFX`/`GIVN`/`SURN`/… parts, `TRAN` translations). `Person.nameVariants` keeps them in order so alias / translation data survive an import → export round-trip.
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import { PersonNameVariant, PersonNameTranslation } from "gedcom-ts";
|
|
215
|
+
|
|
216
|
+
const variant = new PersonNameVariant("Jean /Dupont/", "BIRTH");
|
|
217
|
+
variant.parts.push({ level: "2", tag: "GIVN", value: "Jean" });
|
|
218
|
+
variant.translations.push(new PersonNameTranslation("ジャン /デュポン/", "jp"));
|
|
97
219
|
```
|
|
98
220
|
|
|
99
|
-
|
|
221
|
+
#### `IndiAttribute`, `IndiGedcomSubLine`
|
|
222
|
+
|
|
223
|
+
Generic level-1 individual attributes (`FACT`, `DSCR`, `CAST`, `EDUC`, `OCCU`, `RELI`, `TITL`, `RESN`, …) with their sub-lines preserved (`IndiGedcomSubLine = { level; tag; value }`).
|
|
100
224
|
|
|
101
225
|
```ts
|
|
102
|
-
import {
|
|
226
|
+
import { IndiAttribute } from "gedcom-ts";
|
|
227
|
+
|
|
228
|
+
const occ = new IndiAttribute("OCCU", "Blacksmith", [
|
|
229
|
+
{ level: "2", tag: "DATE", value: "1820" },
|
|
230
|
+
]);
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### `Act`, `Acts`, `TypeAct`, `ActConstructionOptions`
|
|
234
|
+
|
|
235
|
+
`Act` models an individual or family event (BIRT, MARR, etc.). `Acts` is the ordered collection on a `Person`. `TypeAct` is the union of every supported GEDCOM 7 event tag (= `Gedcom7EventTag`).
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
import { Act, Acts, Identifier, type TypeAct } from "gedcom-ts";
|
|
103
239
|
|
|
104
|
-
const actType: TypeAct = Identifier.BIRT;
|
|
105
|
-
const act = new Act(actType);
|
|
106
240
|
const acts = new Acts();
|
|
107
|
-
|
|
241
|
+
const type: TypeAct = Identifier.BIRT;
|
|
242
|
+
acts.add(new Act(type));
|
|
243
|
+
acts.sortByDate();
|
|
108
244
|
```
|
|
109
245
|
|
|
110
|
-
|
|
246
|
+
`ActConstructionOptions` controls the extras when building an `Act` manually:
|
|
111
247
|
|
|
112
248
|
```ts
|
|
113
|
-
import {
|
|
249
|
+
import { Act, DateAct, Identifier } from "gedcom-ts";
|
|
250
|
+
|
|
251
|
+
const act = new Act(
|
|
252
|
+
Identifier.EVEN,
|
|
253
|
+
new DateAct("12 JAN 1901"),
|
|
254
|
+
null,
|
|
255
|
+
null,
|
|
256
|
+
null,
|
|
257
|
+
undefined,
|
|
258
|
+
undefined,
|
|
259
|
+
{
|
|
260
|
+
evenDescription: "Won a medal",
|
|
261
|
+
evenTypeLabel: "Award",
|
|
262
|
+
sdateAct: new DateAct("13 JAN 1901"),
|
|
263
|
+
eventPhrases: ["family gathering"],
|
|
264
|
+
preservedSubrecordPrefix: [],
|
|
265
|
+
preservedSubrecordSuffix: [],
|
|
266
|
+
},
|
|
267
|
+
);
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### `GEDCOM_7_ALL_EVENT_TAGS`, `GEDCOM_7_EVENT_SORT_ORDER`, `GEDCOM_7_EVENT_TAG_SET`, `Gedcom7EventTag`
|
|
271
|
+
|
|
272
|
+
Canonical lists of GEDCOM 7 event tags (`INDIVIDUAL_EVENT_STRUCTURE` ∪ `FAMILY_EVENT_STRUCTURE`, LDS ordinances excluded). Use them to build UI selects or guard custom logic.
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
import {
|
|
276
|
+
GEDCOM_7_ALL_EVENT_TAGS,
|
|
277
|
+
GEDCOM_7_EVENT_SORT_ORDER,
|
|
278
|
+
GEDCOM_7_EVENT_TAG_SET,
|
|
279
|
+
type Gedcom7EventTag,
|
|
280
|
+
} from "gedcom-ts";
|
|
281
|
+
|
|
282
|
+
const options: Gedcom7EventTag[] = [...GEDCOM_7_ALL_EVENT_TAGS];
|
|
283
|
+
const isEvent = GEDCOM_7_EVENT_TAG_SET.has("MARR");
|
|
284
|
+
const sorted = [...GEDCOM_7_EVENT_SORT_ORDER];
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
#### `DateAct`, `Day`, `Month`, `dateToDateLine`, `days`, `months`, `TypeDateActSimpleQualifier`
|
|
288
|
+
|
|
289
|
+
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.
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
import {
|
|
293
|
+
DateAct,
|
|
294
|
+
Day,
|
|
295
|
+
Month,
|
|
296
|
+
dateToDateLine,
|
|
297
|
+
days,
|
|
298
|
+
months,
|
|
299
|
+
} from "gedcom-ts";
|
|
114
300
|
|
|
115
301
|
const day: Day = 12;
|
|
116
302
|
const month: Month = months[0]; // JAN
|
|
@@ -120,38 +306,53 @@ const formattedDate = dateAct.date;
|
|
|
120
306
|
const knownDaysCount = days.length;
|
|
121
307
|
```
|
|
122
308
|
|
|
123
|
-
|
|
309
|
+
`TypeDateActSimpleQualifier` is the union of single-anchor qualifiers (`BEF | ABT | AFT | INT | EST | CAL`) accepted by `DateAct.updateQualifiedDate` and by `DateActEdit.setQualified`.
|
|
310
|
+
|
|
311
|
+
#### `Place`, `CoordinateGPS`
|
|
124
312
|
|
|
125
313
|
```ts
|
|
126
|
-
import {
|
|
314
|
+
import { Place, CoordinateGPS } from "gedcom-ts";
|
|
127
315
|
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
316
|
+
const place = new Place("Paris, FR", new CoordinateGPS(48.8566, 2.3522));
|
|
317
|
+
place.setFromGedcom7PlacPayload("Paris, Île-de-France, France");
|
|
318
|
+
const payload = place.toGedcom7PlacPayload(); // "Paris, , Île-de-France, France"
|
|
131
319
|
```
|
|
132
320
|
|
|
133
|
-
|
|
321
|
+
`Place` understands the `City, County, State, Country` GEDCOM 7 list (1 to 4+ segments) and exposes `placPhrase` for `3 PHRASE` under `PLAC` (import + export).
|
|
322
|
+
|
|
323
|
+
#### `MultimediaFile`, `MultimediaFiles`
|
|
324
|
+
|
|
325
|
+
Wraps either a local `File`, an external URI (`sourceUri`) or an OBJE pointer (`objeXrefId`) so the same model can survive a GED / ZIP round-trip.
|
|
134
326
|
|
|
135
327
|
```ts
|
|
136
|
-
import {
|
|
328
|
+
import { MultimediaFile, MultimediaFiles } from "gedcom-ts";
|
|
137
329
|
|
|
138
|
-
const
|
|
330
|
+
const bucket = new MultimediaFiles();
|
|
331
|
+
bucket.relativePath = "1/BIRT";
|
|
332
|
+
bucket.add(new MultimediaFile(new File(["img"], "birth.jpg")));
|
|
333
|
+
|
|
334
|
+
const remote = new MultimediaFile(undefined, "https://example.com/p.jpg");
|
|
335
|
+
const isExportable = remote.hasExportablePayload();
|
|
139
336
|
```
|
|
140
337
|
|
|
141
|
-
|
|
338
|
+
#### `Note`, `Notes`, `TypeNote`
|
|
142
339
|
|
|
143
340
|
```ts
|
|
144
|
-
import { Notes, Note,
|
|
341
|
+
import { Notes, Note, Identifier, type TypeNote } from "gedcom-ts";
|
|
145
342
|
|
|
146
343
|
const typeNote: TypeNote = Identifier.CONT;
|
|
147
344
|
const note = new Note();
|
|
148
345
|
note.updateType(typeNote);
|
|
149
346
|
note.updateLines(["first line", "second line"]);
|
|
347
|
+
|
|
150
348
|
const notes = new Notes();
|
|
151
349
|
notes.addNote(note);
|
|
350
|
+
notes.removeFromIndex(0);
|
|
152
351
|
```
|
|
153
352
|
|
|
154
|
-
|
|
353
|
+
#### `Identifier` (and deprecated `Identificator`)
|
|
354
|
+
|
|
355
|
+
Enum of every GEDCOM tag the library refers to (`INDI`, `BIRT`, `MARR`, `DATE`, `PLAC`, …). Prefer `Identifier`; `Identificator` is kept as a deprecated alias.
|
|
155
356
|
|
|
156
357
|
```ts
|
|
157
358
|
import { Identifier } from "gedcom-ts";
|
|
@@ -159,93 +360,173 @@ import { Identifier } from "gedcom-ts";
|
|
|
159
360
|
const birthTag = Identifier.BIRT;
|
|
160
361
|
```
|
|
161
362
|
|
|
162
|
-
|
|
363
|
+
#### `EventsByYears`, `ActsByYear`
|
|
364
|
+
|
|
365
|
+
Group acts by year, deduplicating per individual. Handy to build chronological timelines.
|
|
163
366
|
|
|
164
367
|
```ts
|
|
165
|
-
import {
|
|
368
|
+
import { EventsByYears, ActsByYear } from "gedcom-ts";
|
|
369
|
+
|
|
370
|
+
const grouped = new EventsByYears(person.acts.list);
|
|
371
|
+
for (const bucket of grouped.events) {
|
|
372
|
+
console.log(bucket.year, bucket.list.length);
|
|
373
|
+
}
|
|
166
374
|
|
|
167
|
-
const
|
|
168
|
-
new ExportGedcomFile("tree", persons).download();
|
|
169
|
-
await new ExportGedzipFile("tree", persons).download();
|
|
375
|
+
const yearBucket = new ActsByYear(1901);
|
|
170
376
|
```
|
|
171
377
|
|
|
172
|
-
###
|
|
378
|
+
### Edit layer (in-place, chainable)
|
|
379
|
+
|
|
380
|
+
Wrap an existing model object to mutate it with a fluent API. Every method returns `this`, so you can chain. `.value` exposes the underlying target.
|
|
173
381
|
|
|
174
382
|
```ts
|
|
175
|
-
import {
|
|
383
|
+
import { editPerson, editDateAct, DateAct } from "gedcom-ts";
|
|
176
384
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
385
|
+
editPerson(person)
|
|
386
|
+
.setLastname("Dupont")
|
|
387
|
+
.setFirstnames(["Jean", "Marie"])
|
|
388
|
+
.acts()
|
|
389
|
+
.at(0)
|
|
390
|
+
.setDateAct(new DateAct("1 JAN 1900"));
|
|
391
|
+
|
|
392
|
+
editDateAct(person.acts.list[0].dateAct!).setExactDate(1900, "JAN", 1);
|
|
183
393
|
```
|
|
184
394
|
|
|
185
|
-
|
|
395
|
+
| Helper / class | Purpose |
|
|
396
|
+
| --- | --- |
|
|
397
|
+
| `editPerson(person)` / `PersonEdit` | identity (`setLastname`, `setFirstnames`, `setSex`, `setSosa`), links (`setFamc`, `setFams`, `clearFams`, `appendFams`), name variants (`setNameVariants`), attributes (`setAttributes`), entry points to `acts()` and `notes()`. |
|
|
398
|
+
| `editActs(acts)` / `ActsEdit` | `add`, `replaceAt`, `removeAt`, `clear`, `sortByDate`, `at(index)`. |
|
|
399
|
+
| `editAct(act)` / `ActEdit` | `setType`, `setIndis`, `setDateAct`, `setSdateAct`, `setPlace`, `setEvenDescription`, `setEvenTypeLabel`, `setEventPhrases` / `appendEventPhrase` / `clearEventPhrases`, plus `setPreservedPrefix` / `Suffix` helpers. |
|
|
400
|
+
| `editDateAct(dateAct)` / `DateActEdit` | `clear`, `applyGedcomPayload`, `setExactDate`, `setQualified`, `setBetween`, `setFromTo`, `setTime`, `setDatePhrase` / `appendDatePhrase`, `setVerbatimPayload`. |
|
|
401
|
+
| `editPlace(place)` / `PlaceEdit` | `setFromGedcom7Payload`, `setCity`, `setCounty`, `setState`, `setCountry`, `setPlacPhrase` / `appendPlacPhrase` / `clearPlacPhrase`, `setCoordinates` / `clearCoordinates` / `replaceCoordinateModel`, `clearStructured`. |
|
|
402
|
+
| `editNotes(notes)` / `NotesEdit` | `add`, `replaceAt`, `removeAt`, `clear`. |
|
|
186
403
|
|
|
187
|
-
|
|
188
|
-
import { importGedFile } from "gedcom-ts";
|
|
404
|
+
### Utilities
|
|
189
405
|
|
|
190
|
-
|
|
191
|
-
```
|
|
406
|
+
#### `createSosaMap(root, partnersMap)`
|
|
192
407
|
|
|
193
|
-
|
|
408
|
+
Computes a Sosa numbering (Ahnentafel) starting at `root` (Sosa 1) and recursively walking ancestors via `partnersMap`.
|
|
194
409
|
|
|
195
410
|
```ts
|
|
196
411
|
import { createSosaMap, Person } from "gedcom-ts";
|
|
197
412
|
|
|
198
|
-
const
|
|
199
|
-
root.INDI
|
|
200
|
-
const sosaMap = createSosaMap(root, new Map());
|
|
413
|
+
const sosaMap = createSosaMap(root, readGed.partnersMap);
|
|
414
|
+
// e.g. sosaMap.get(root.INDI) === 1
|
|
201
415
|
```
|
|
202
416
|
|
|
203
|
-
|
|
417
|
+
#### `remainingTypesAct(acts, actToUpdate?)`
|
|
418
|
+
|
|
419
|
+
Returns the list of event types still allowed for a person’s `Acts`, enforcing the “unique per individual” rule for `BIRT` / `DEAT` / `BURI` / `CHR` while keeping every other tag selectable. Pass the currently edited act as `actToUpdate` so its own type stays in the list when re-opening a form.
|
|
204
420
|
|
|
205
421
|
```ts
|
|
206
422
|
import { remainingTypesAct, Acts } from "gedcom-ts";
|
|
207
423
|
|
|
208
|
-
const
|
|
424
|
+
const available = remainingTypesAct(new Acts());
|
|
209
425
|
```
|
|
210
426
|
|
|
211
|
-
|
|
427
|
+
#### `getCityCoordinates(cityName, callback)`
|
|
428
|
+
|
|
429
|
+
Queries OpenStreetMap’s Nominatim API and returns a list of candidate `Place` objects with coordinates. Browser-only (uses `XMLHttpRequest`).
|
|
212
430
|
|
|
213
431
|
```ts
|
|
214
|
-
import {
|
|
432
|
+
import { getCityCoordinates } from "gedcom-ts";
|
|
215
433
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const selectedYear = yearBucket.year;
|
|
434
|
+
getCityCoordinates("Paris", (places) => {
|
|
435
|
+
console.log(places[0]?.coordinate.latitude, places[0]?.coordinate.longitude);
|
|
436
|
+
});
|
|
220
437
|
```
|
|
221
438
|
|
|
222
|
-
|
|
439
|
+
#### `resolveDatasetVersion(headerLines)` / `GedcomDatasetVersion`
|
|
440
|
+
|
|
441
|
+
Inspects the lines of a `0 HEAD` block and returns `"7.0"`, `"5.5"` or `"unknown"`. Useful to branch UI behaviour for legacy datasets.
|
|
223
442
|
|
|
224
443
|
```ts
|
|
225
|
-
import {
|
|
444
|
+
import { resolveDatasetVersion } from "gedcom-ts";
|
|
445
|
+
|
|
446
|
+
const version = resolveDatasetVersion(headLines); // "7.0" | "5.5" | "unknown"
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
#### `guessMediaFormFromUri(uri)`
|
|
450
|
+
|
|
451
|
+
Best-effort media type detection from a path/URI (jpg, png, gif, webp, mp3, mp4, pdf, …). Used internally to fill `OBJE`.`FILE`.`FORM`.
|
|
452
|
+
|
|
453
|
+
```ts
|
|
454
|
+
import { guessMediaFormFromUri } from "gedcom-ts";
|
|
455
|
+
|
|
456
|
+
guessMediaFormFromUri("https://example.com/photo.jpg"); // "image/jpeg"
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
#### `extractPersonNameVariants(personLines)` / `extractIndiAttributes(personLines)`
|
|
460
|
+
|
|
461
|
+
Low-level parsers used by `Person.createPersonJson`. They turn the raw GEDCOM lines of a single `INDI` record into structured `PersonNameVariant[]` / `IndiAttribute[]`. Reuse them when parsing custom GEDCOM fragments outside `ReadGed`.
|
|
462
|
+
|
|
463
|
+
```ts
|
|
464
|
+
import { extractPersonNameVariants, extractIndiAttributes } from "gedcom-ts";
|
|
465
|
+
|
|
466
|
+
const variants = extractPersonNameVariants(rawIndiLines);
|
|
467
|
+
const attributes = extractIndiAttributes(rawIndiLines);
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
#### `selectPrimaryNameVariant(variants)`
|
|
471
|
+
|
|
472
|
+
Picks the most relevant `1 NAME` block: priority to `2 TYPE BIRTH`, then to a name with a `/surname/` payload, otherwise the first variant.
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
import { selectPrimaryNameVariant } from "gedcom-ts";
|
|
476
|
+
|
|
477
|
+
const primary = selectPrimaryNameVariant(person.nameVariants);
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
#### `GEDCOM_LIBRARY_VERSION`
|
|
481
|
+
|
|
482
|
+
The library version embedded in the exported `HEAD`.`SOUR`.`VERS`. Kept aligned with the `version` field of `package.json` (a test enforces it).
|
|
483
|
+
|
|
484
|
+
```ts
|
|
485
|
+
import { GEDCOM_LIBRARY_VERSION } from "gedcom-ts";
|
|
486
|
+
|
|
487
|
+
console.log(`gedcom-ts ${GEDCOM_LIBRARY_VERSION}`);
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## End-to-end example
|
|
491
|
+
|
|
492
|
+
```ts
|
|
493
|
+
import {
|
|
494
|
+
importGedFile,
|
|
495
|
+
ExportGedzipFile,
|
|
496
|
+
editPerson,
|
|
497
|
+
DateAct,
|
|
498
|
+
Identifier,
|
|
499
|
+
} from "gedcom-ts";
|
|
226
500
|
|
|
227
501
|
async function importModifyExport(file: File) {
|
|
228
502
|
const readGed = await importGedFile(file);
|
|
229
503
|
const persons = readGed.persons;
|
|
230
504
|
|
|
231
505
|
if (persons.length > 0) {
|
|
232
|
-
persons[0]
|
|
506
|
+
editPerson(persons[0])
|
|
507
|
+
.setLastname(persons[0].lastname.toUpperCase())
|
|
508
|
+
.acts()
|
|
509
|
+
.at(0)
|
|
510
|
+
.setDateAct(new DateAct("1 JAN 1900"));
|
|
233
511
|
}
|
|
234
512
|
|
|
235
513
|
await new ExportGedzipFile("updated-tree", persons).download();
|
|
236
514
|
}
|
|
237
515
|
```
|
|
238
516
|
|
|
239
|
-
## Error
|
|
517
|
+
## Error handling
|
|
240
518
|
|
|
241
519
|
```ts
|
|
242
|
-
import { importGedFile } from "gedcom-ts";
|
|
520
|
+
import { importGedFile, IMPORT_ERR_ZIP_GED_UNREADABLE } from "gedcom-ts";
|
|
243
521
|
|
|
244
522
|
try {
|
|
245
523
|
const readGed = await importGedFile(file);
|
|
246
|
-
|
|
524
|
+
console.log(readGed.persons.length);
|
|
247
525
|
} catch (error) {
|
|
248
|
-
|
|
526
|
+
if (error instanceof Error && error.message === IMPORT_ERR_ZIP_GED_UNREADABLE) {
|
|
527
|
+
console.error("Encrypted ZIP: please extract the .ged manually.");
|
|
528
|
+
} else {
|
|
529
|
+
console.error("GED import failed:", error);
|
|
530
|
+
}
|
|
249
531
|
}
|
|
250
532
|
```
|
|
251
|
-
|