@treeviz/gedcom-parser 2.0.12 â 2.1.1
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/README.md +236 -989
- package/dist/classes/common.d.ts +4 -4
- package/dist/classes/common.d.ts.map +1 -1
- package/dist/classes/date.d.ts +2 -0
- package/dist/classes/date.d.ts.map +1 -1
- package/dist/classes/fam.d.ts +2 -1
- package/dist/classes/fam.d.ts.map +1 -1
- package/dist/classes/fams.d.ts.map +1 -1
- package/dist/classes/gedcom.d.ts +39 -2
- package/dist/classes/gedcom.d.ts.map +1 -1
- package/dist/classes/index.js +1364 -318
- package/dist/classes/indi.d.ts +19 -2
- package/dist/classes/indi.d.ts.map +1 -1
- package/dist/classes/list.d.ts.map +1 -1
- package/dist/classes/note.d.ts.map +1 -1
- package/dist/classes/obje.d.ts +2 -1
- package/dist/classes/obje.d.ts.map +1 -1
- package/dist/cli/index.js +1368 -313
- package/dist/constants/constants.d.ts.map +1 -1
- package/dist/constants/index.js +312 -73
- package/dist/factories/index.js +310 -71
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1547 -288
- package/dist/interfaces/common.d.ts +6 -4
- package/dist/interfaces/common.d.ts.map +1 -1
- package/dist/interfaces/fam.d.ts +3 -0
- package/dist/interfaces/fam.d.ts.map +1 -1
- package/dist/interfaces/gedcom.d.ts +21 -1
- package/dist/interfaces/gedcom.d.ts.map +1 -1
- package/dist/interfaces/indi.d.ts +11 -1
- package/dist/interfaces/indi.d.ts.map +1 -1
- package/dist/kinship-translator/index.js +310 -71
- package/dist/structures/gedcom.d.ts +1 -0
- package/dist/structures/gedcom.d.ts.map +1 -1
- package/dist/types/types.d.ts +22 -4
- package/dist/types/types.d.ts.map +1 -1
- package/dist/utils/common-creator.d.ts.map +1 -1
- package/dist/utils/fact-edit.d.ts +12 -0
- package/dist/utils/fact-edit.d.ts.map +1 -1
- package/dist/utils/family-edit.d.ts +2 -2
- package/dist/utils/family-edit.d.ts.map +1 -1
- package/dist/utils/gedcom-version.d.ts +6 -0
- package/dist/utils/gedcom-version.d.ts.map +1 -0
- package/dist/utils/gedcom7-dates.d.ts +20 -0
- package/dist/utils/gedcom7-dates.d.ts.map +1 -0
- package/dist/utils/gedcom7-enumerations.d.ts +26 -0
- package/dist/utils/gedcom7-enumerations.d.ts.map +1 -0
- package/dist/utils/gedcom7-metadata.d.ts +19 -0
- package/dist/utils/gedcom7-metadata.d.ts.map +1 -0
- package/dist/utils/gedcom7-schema.d.ts +27 -0
- package/dist/utils/gedcom7-schema.d.ts.map +1 -0
- package/dist/utils/gedzip.d.ts +81 -0
- package/dist/utils/gedzip.d.ts.map +1 -0
- package/dist/utils/index.d.ts +9 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1547 -288
- package/dist/utils/local-media.d.ts +30 -0
- package/dist/utils/local-media.d.ts.map +1 -0
- package/dist/utils/media-utils.d.ts +10 -6
- package/dist/utils/media-utils.d.ts.map +1 -1
- package/dist/utils/multimedia.d.ts +38 -0
- package/dist/utils/multimedia.d.ts.map +1 -0
- package/dist/utils/parser.d.ts.map +1 -1
- package/dist/utils/uid.d.ts +6 -0
- package/dist/utils/uid.d.ts.map +1 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
# @treeviz/gedcom-parser
|
|
2
2
|
|
|
3
|
-
> Part of the [@treeviz](https://www.npmjs.com/org/treeviz) organization
|
|
3
|
+
> Part of the [@treeviz](https://www.npmjs.com/org/treeviz) organization â tools for genealogy data processing and visualization.
|
|
4
4
|
|
|
5
|
-
A
|
|
5
|
+
A pluggable GEDCOM parser for JavaScript/TypeScript. Originally part of [TreeViz](https://treeviz.com), published as a standalone package.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
9
|
+
- **Parse** GEDCOM 5.5 / 5.5.1 and GEDCOM 7 (legacy `CONC` is folded on import)
|
|
10
|
+
- **Export** as GEDCOM **5.5.1** or **7.0**
|
|
11
|
+
- **GEDZIP** â build / extract FamilySearch `.gdz` (`toGedzip`, `extractGedzip`, `buildGedzip`, `buildGedzipBlob`, `downloadGedzipMedia`)
|
|
12
|
+
- **Multimedia** â create / attach OBJE; G7 uses nested `FILE â FORM [â TYPE]`
|
|
13
|
+
- **GEDCOM 7 extras** â `SNOTE`, `NO` (non-event), `SCHMA`, `UID` / `CREA` / `CHAN`, `PHRASE` for non-enum values, calendars / date periods
|
|
14
|
+
- **Original source head** â `_ORIGHEAD` preserved for vendor detection (`getOriginalHeadRecord`, `getSourceHeads`)
|
|
15
|
+
- **Local media hooks** â inject IndexedDB / host storage for `media/...` paths without coupling the parser to the browser
|
|
16
|
+
- **CLI** â `info`, `find`, `show`, `get`, `open`, `validate`, `relatives`, `extract`, `stats`, `merge`, `convert`
|
|
17
|
+
- **Pluggable** â i18n, date locale, places, cache, kinship (no hard dependency on IndexedDB)
|
|
18
|
+
- **TypeScript** â full type definitions
|
|
19
|
+
- **SSR-safe** defaults when factories are unset
|
|
20
|
+
|
|
21
|
+
> **Export version priority:** `toGedcom(..., { gedcomVersion })` â else source `HEAD.GEDC.VERS` â else **5.5.1**.
|
|
22
|
+
> GEDCOM 7 transforms (PHRASE, SCHMA, UID/CREA/CHAN backfill, CONC omission, âĶ) run **only** when the resolved export version is `7.0`.
|
|
23
|
+
>
|
|
24
|
+
> Extension tags in `HEAD.SCHMA` are documented at [treeviz.com/gedcom](https://treeviz.com/gedcom) (e.g. `#_ORIGHEAD`).
|
|
25
|
+
|
|
26
|
+
**Dependencies:** `lodash-es`, `date-fns`, `jszip` (GEDZIP), plus CLI-only `commander` / `chalk`. Core parsing does not require a browser.
|
|
17
27
|
|
|
18
28
|
## Installation
|
|
19
29
|
|
|
@@ -21,400 +31,239 @@ A lightweight, pluggable GEDCOM parser library for JavaScript/TypeScript applica
|
|
|
21
31
|
npm install @treeviz/gedcom-parser
|
|
22
32
|
```
|
|
23
33
|
|
|
24
|
-
|
|
34
|
+
Requires **Node.js 20+** (see `engines` in `package.json`).
|
|
25
35
|
|
|
26
|
-
|
|
36
|
+
## Quick Start
|
|
27
37
|
|
|
28
38
|
```typescript
|
|
29
39
|
import GedcomTree from '@treeviz/gedcom-parser';
|
|
30
40
|
|
|
31
|
-
const
|
|
41
|
+
const { gedcom } = GedcomTree.parse(`0 HEAD
|
|
32
42
|
1 SOUR MyApp
|
|
43
|
+
1 GEDC
|
|
44
|
+
2 VERS 5.5.1
|
|
33
45
|
0 @I1@ INDI
|
|
34
46
|
1 NAME John /Doe/
|
|
35
|
-
0 TRLR
|
|
36
|
-
|
|
37
|
-
const { gedcom } = GedcomTree.parse(gedcomContent);
|
|
38
|
-
const individuals = gedcom.indis();
|
|
47
|
+
0 TRLR`);
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
console.log(indi
|
|
42
|
-
console.log(indi
|
|
43
|
-
console.log(indi
|
|
44
|
-
console.log(indi.getBirthPlace()); // "New York, USA"
|
|
49
|
+
gedcom.indis()?.forEach((indi) => {
|
|
50
|
+
console.log(indi?.toName());
|
|
51
|
+
console.log(indi?.getBirthDate?.());
|
|
52
|
+
console.log(indi?.getBirthPlace?.());
|
|
45
53
|
});
|
|
46
54
|
```
|
|
47
55
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
The package includes a powerful CLI for working with GEDCOM files directly from the terminal.
|
|
51
|
-
|
|
52
|
-
### Installation
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
# Install globally
|
|
56
|
-
npm install -g @treeviz/gedcom-parser
|
|
57
|
-
|
|
58
|
-
# Or use npx
|
|
59
|
-
npx @treeviz/gedcom-parser --help
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Available Commands
|
|
63
|
-
|
|
64
|
-
#### `info` - Display file information
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
gedcom-parser info <file> [options]
|
|
68
|
-
|
|
69
|
-
# Show basic statistics
|
|
70
|
-
gedcom-parser info family.ged
|
|
71
|
-
|
|
72
|
-
# Show detailed information
|
|
73
|
-
gedcom-parser info family.ged --verbose
|
|
74
|
-
|
|
75
|
-
# Output as JSON
|
|
76
|
-
gedcom-parser info family.ged --json
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
#### `find` - Search for individuals
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
gedcom-parser find <file> [query] [options]
|
|
83
|
-
|
|
84
|
-
# Find by name
|
|
85
|
-
gedcom-parser find family.ged "John Smith"
|
|
86
|
-
|
|
87
|
-
# Find by ID
|
|
88
|
-
gedcom-parser find family.ged --id @I123@
|
|
89
|
-
|
|
90
|
-
# Find with filters
|
|
91
|
-
gedcom-parser find family.ged --birth-year 1850 --death-year 1920
|
|
92
|
-
|
|
93
|
-
# Output as JSON
|
|
94
|
-
gedcom-parser find family.ged "Smith" --json
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
#### `show` - Display individual details
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
gedcom-parser show <file> <id> [options]
|
|
101
|
-
|
|
102
|
-
# Show individual details
|
|
103
|
-
gedcom-parser show family.ged @I123@
|
|
104
|
-
|
|
105
|
-
# Output as JSON
|
|
106
|
-
gedcom-parser show family.ged @I123@ --json
|
|
107
|
-
|
|
108
|
-
# Output as Markdown
|
|
109
|
-
gedcom-parser show family.ged @I123@ --format markdown
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
#### `get` - Get a value from a GEDCOM record
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
gedcom-parser get <file> <id> [options]
|
|
116
|
-
|
|
117
|
-
# Get a specific value by path
|
|
118
|
-
gedcom-parser get family.ged @I123@ --path "BIRT.DATE"
|
|
119
|
-
|
|
120
|
-
# Get birth place
|
|
121
|
-
gedcom-parser get family.ged @I123@ --path "BIRT.PLAC"
|
|
122
|
-
|
|
123
|
-
# Get full record as JSON
|
|
124
|
-
gedcom-parser get family.ged @I123@ --json
|
|
125
|
-
|
|
126
|
-
# Get raw value only
|
|
127
|
-
gedcom-parser get family.ged @I123@ --path "NAME" --raw
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
#### `open` - Interactive REPL mode
|
|
131
|
-
|
|
132
|
-
```bash
|
|
133
|
-
gedcom-parser open <file>
|
|
134
|
-
|
|
135
|
-
# Open a GEDCOM file in interactive mode
|
|
136
|
-
gedcom-parser open family.ged
|
|
137
|
-
|
|
138
|
-
# Once in REPL, you can use commands like:
|
|
139
|
-
# - stats : Show statistics
|
|
140
|
-
# - find <query> : Search for individuals
|
|
141
|
-
# - select <n> : Select an individual from search results
|
|
142
|
-
# - show : Show details of selected individual
|
|
143
|
-
# - get --path <p> : Get a value from selected individual
|
|
144
|
-
# - relatives [opts] : Get ancestors/descendants of selected individual
|
|
145
|
-
# - validate [opts] : Validate the GEDCOM file
|
|
146
|
-
# - clear : Clear screen
|
|
147
|
-
# - help : Show available commands
|
|
148
|
-
# - exit : Exit REPL
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
#### `validate` - Validate GEDCOM file
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
gedcom-parser validate <file> [options]
|
|
155
|
-
|
|
156
|
-
# Validate file
|
|
157
|
-
gedcom-parser validate family.ged
|
|
158
|
-
|
|
159
|
-
# Strict validation
|
|
160
|
-
gedcom-parser validate family.ged --strict
|
|
161
|
-
|
|
162
|
-
# Output as JSON
|
|
163
|
-
gedcom-parser validate family.ged --json
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
#### `relatives` - Extract family tree
|
|
167
|
-
|
|
168
|
-
```bash
|
|
169
|
-
gedcom-parser relatives <file> <id> [options]
|
|
170
|
-
|
|
171
|
-
# Get ancestors
|
|
172
|
-
gedcom-parser relatives family.ged @I123@ --ancestors
|
|
56
|
+
### Export 5.5.1 vs 7.0
|
|
173
57
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
# Get full tree (ancestors and descendants)
|
|
178
|
-
gedcom-parser relatives family.ged @I123@ --tree
|
|
58
|
+
```typescript
|
|
59
|
+
// Explicit GEDCOM 7
|
|
60
|
+
const ged7 = gedcom.toGedcom(undefined, 0, { gedcomVersion: '7.0' });
|
|
179
61
|
|
|
180
|
-
|
|
181
|
-
|
|
62
|
+
// Explicit 5.5.1 (no G7 transforms)
|
|
63
|
+
const ged551 = gedcom.toGedcom(undefined, 0, { gedcomVersion: '5.5.1' });
|
|
182
64
|
|
|
183
|
-
|
|
184
|
-
|
|
65
|
+
// Omit gedcomVersion â use HEAD.GEDC.VERS, else 5.5.1
|
|
66
|
+
const auto = gedcom.toGedcom();
|
|
185
67
|
```
|
|
186
68
|
|
|
187
|
-
|
|
69
|
+
### GEDZIP (`.gdz`)
|
|
188
70
|
|
|
189
|
-
```
|
|
190
|
-
|
|
71
|
+
```typescript
|
|
72
|
+
import {
|
|
73
|
+
extractGedzip,
|
|
74
|
+
buildGedzipBlob,
|
|
75
|
+
downloadGedzipMedia,
|
|
76
|
+
setMediaContentResolver,
|
|
77
|
+
} from '@treeviz/gedcom-parser';
|
|
191
78
|
|
|
192
|
-
|
|
193
|
-
|
|
79
|
+
// Import archive â GEDCOM text + media bytes
|
|
80
|
+
const { gedcomText, mediaEntries } = await extractGedzip(file);
|
|
194
81
|
|
|
195
|
-
|
|
196
|
-
|
|
82
|
+
// Export: collect descriptors, resolve bytes (host cache / fetch), pack Blob
|
|
83
|
+
setMediaContentResolver(async (media) => {
|
|
84
|
+
// e.g. look up IndexedDB by media.url / media.imgId
|
|
85
|
+
return undefined; // fall through to fetch for http(s)
|
|
86
|
+
});
|
|
197
87
|
|
|
198
|
-
|
|
199
|
-
|
|
88
|
+
const media = await gedcom.collectMultimedia({ namespace: spaceId });
|
|
89
|
+
const downloaded = await downloadGedzipMedia(media);
|
|
90
|
+
const blob = await buildGedzipBlob(
|
|
91
|
+
gedcom.toGedcom(undefined, 0, { gedcomVersion: '7.0' }) || '',
|
|
92
|
+
downloaded
|
|
93
|
+
);
|
|
200
94
|
```
|
|
201
95
|
|
|
202
|
-
|
|
96
|
+
Or use `gedcom.toGedzip({ media: downloaded })` when you already have byte payloads.
|
|
203
97
|
|
|
204
|
-
|
|
205
|
-
gedcom-parser stats <file> [options]
|
|
98
|
+
### Local / cached media paths
|
|
206
99
|
|
|
207
|
-
|
|
208
|
-
gedcom-parser stats family.ged
|
|
100
|
+
After GEDZIP import, `FILE` payloads often look like `media/uuid.jpg`. Inject resolvers so profile pictures and export can turn those into data URLs:
|
|
209
101
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
```bash
|
|
217
|
-
gedcom-parser merge <files...> --output <output> [options]
|
|
102
|
+
```typescript
|
|
103
|
+
import {
|
|
104
|
+
setLocalMediaResolver,
|
|
105
|
+
setMediaContentResolver,
|
|
106
|
+
} from '@treeviz/gedcom-parser';
|
|
218
107
|
|
|
219
|
-
|
|
220
|
-
|
|
108
|
+
setLocalMediaResolver(async (path) => {
|
|
109
|
+
// Return a data:/blob:/https: URL for display
|
|
110
|
+
return await myImageStore.get(path);
|
|
111
|
+
});
|
|
221
112
|
|
|
222
|
-
|
|
223
|
-
|
|
113
|
+
setMediaContentResolver(async (media) => {
|
|
114
|
+
// Return { content, contentType? } for GEDZIP export
|
|
115
|
+
const hit = await myImageStore.get(media.url || media.imgId);
|
|
116
|
+
return hit ? { content: hit } : undefined;
|
|
117
|
+
});
|
|
224
118
|
```
|
|
225
119
|
|
|
226
|
-
|
|
120
|
+
## Command-Line Interface
|
|
227
121
|
|
|
228
122
|
```bash
|
|
229
|
-
gedcom-parser
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
gedcom-parser convert family.ged --format json --output data.json
|
|
233
|
-
|
|
234
|
-
# Convert to CSV
|
|
235
|
-
gedcom-parser convert family.ged --format csv --output individuals.csv
|
|
236
|
-
|
|
237
|
-
# Convert to Markdown
|
|
238
|
-
gedcom-parser convert family.ged --format markdown --output tree.md
|
|
123
|
+
npm install -g @treeviz/gedcom-parser
|
|
124
|
+
# or
|
|
125
|
+
npx @treeviz/gedcom-parser --help
|
|
239
126
|
```
|
|
240
127
|
|
|
241
|
-
|
|
128
|
+
| Command | Purpose |
|
|
129
|
+
| --- | --- |
|
|
130
|
+
| `info <file>` | File statistics (`--verbose`, `--json`) |
|
|
131
|
+
| `find <file> [query]` | Search individuals |
|
|
132
|
+
| `show <file> <id>` | Individual details |
|
|
133
|
+
| `get <file> <id>` | Value by path (`--path BIRT.DATE`) |
|
|
134
|
+
| `select <file> <id>` | Select record helpers |
|
|
135
|
+
| `open <file>` | Interactive REPL |
|
|
136
|
+
| `validate <file>` | Validation |
|
|
137
|
+
| `relatives <file> <id>` | Ancestors / descendants / subtree |
|
|
138
|
+
| `extract <file>` | Filtered subset GEDCOM |
|
|
139
|
+
| `stats <file>` | Statistics |
|
|
140
|
+
| `merge <files...>` | Merge GEDCOMs |
|
|
141
|
+
| `convert <file>` | JSON / CSV / Markdown |
|
|
242
142
|
|
|
243
143
|
```bash
|
|
244
|
-
|
|
245
|
-
gedcom-parser find family.ged
|
|
246
|
-
|
|
247
|
-
# Show detailed information about an individual
|
|
144
|
+
gedcom-parser info family.ged --verbose
|
|
145
|
+
gedcom-parser find family.ged "John Smith"
|
|
248
146
|
gedcom-parser show family.ged @I123@
|
|
249
|
-
|
|
250
|
-
# Get specific value from a record
|
|
251
|
-
gedcom-parser get family.ged @I123@ --path "BIRT.DATE"
|
|
252
|
-
|
|
253
|
-
# Extract all descendants of an individual
|
|
254
|
-
gedcom-parser relatives family.ged @I123@ --descendants --output descendants.ged
|
|
255
|
-
|
|
256
|
-
# Generate statistics in JSON format
|
|
257
|
-
gedcom-parser stats family.ged --json > stats.json
|
|
258
|
-
|
|
259
|
-
# Validate and check for errors
|
|
260
|
-
gedcom-parser validate family.ged
|
|
261
|
-
|
|
262
|
-
# Open interactive REPL mode
|
|
147
|
+
gedcom-parser relatives family.ged @I123@ --tree --output subset.ged
|
|
263
148
|
gedcom-parser open family.ged
|
|
264
149
|
```
|
|
265
150
|
|
|
266
151
|
## Factory Providers
|
|
267
152
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
### Available Factory Providers
|
|
271
|
-
|
|
272
|
-
#### 1. **i18n Provider** (Translation)
|
|
153
|
+
All factories are **optional**. Set them **before** parsing if you need localization, places, or durable cache.
|
|
273
154
|
|
|
274
|
-
|
|
155
|
+
### 1. i18n
|
|
275
156
|
|
|
276
157
|
```typescript
|
|
277
158
|
import { setI18nProvider } from '@treeviz/gedcom-parser';
|
|
278
|
-
import i18n from './my-i18n-setup';
|
|
279
159
|
|
|
280
|
-
|
|
281
|
-
setI18nProvider((key: string, options?: Record<string, unknown>) =>
|
|
282
|
-
i18n.t(key, options)
|
|
283
|
-
);
|
|
160
|
+
setI18nProvider((key, options) => i18n.t(key, options));
|
|
284
161
|
```
|
|
285
162
|
|
|
286
|
-
**Default:**
|
|
163
|
+
**Default:** returns the key unchanged.
|
|
287
164
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
#### 2. **Date Locale Provider**
|
|
291
|
-
|
|
292
|
-
Provide date-fns locale for date formatting.
|
|
165
|
+
### 2. Date locale (`date-fns`)
|
|
293
166
|
|
|
294
167
|
```typescript
|
|
295
168
|
import { setDateLocaleProvider } from '@treeviz/gedcom-parser';
|
|
296
|
-
import {
|
|
297
|
-
|
|
298
|
-
// Set up date locale provider
|
|
299
|
-
setDateLocaleProvider((lang: string) => {
|
|
300
|
-
switch (lang) {
|
|
301
|
-
case 'hu': return hu;
|
|
302
|
-
case 'de': return de;
|
|
303
|
-
default: return enUS;
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
```
|
|
169
|
+
import { hu } from 'date-fns/locale';
|
|
307
170
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
171
|
+
// No language argument â return the locale for the *current* app language
|
|
172
|
+
setDateLocaleProvider(() => hu);
|
|
173
|
+
```
|
|
311
174
|
|
|
312
|
-
|
|
175
|
+
**Default:** `undefined` (date-fns default behavior).
|
|
313
176
|
|
|
314
|
-
|
|
177
|
+
### 3. Place parser
|
|
315
178
|
|
|
316
179
|
```typescript
|
|
317
180
|
import { setPlaceParserProvider } from '@treeviz/gedcom-parser';
|
|
318
181
|
import type { PlaceParts } from '@treeviz/gedcom-parser';
|
|
319
182
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
// e.g., recognize counties, historical boundaries, etc.
|
|
324
|
-
return [{
|
|
325
|
-
leftParts: ['District'],
|
|
326
|
-
town: 'Budapest',
|
|
327
|
-
county: 'Pest',
|
|
328
|
-
country: 'Hungary'
|
|
329
|
-
}] as PlaceParts[];
|
|
183
|
+
setPlaceParserProvider((place) => {
|
|
184
|
+
// Return PlaceParts[]
|
|
185
|
+
return [{ leftParts: [], town: 'Budapest', county: 'Pest', country: 'Hungary' }];
|
|
330
186
|
});
|
|
331
187
|
```
|
|
332
188
|
|
|
333
|
-
**Default:**
|
|
334
|
-
|
|
335
|
-
---
|
|
189
|
+
**Default:** simple comma-split heuristic.
|
|
336
190
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
Provide custom place name translation and normalization.
|
|
191
|
+
### 4. Place translator
|
|
340
192
|
|
|
341
193
|
```typescript
|
|
342
194
|
import { setPlaceTranslatorProvider } from '@treeviz/gedcom-parser';
|
|
343
195
|
|
|
344
|
-
|
|
345
|
-
setPlaceTranslatorProvider((
|
|
346
|
-
place?: string | string[],
|
|
347
|
-
level?: number,
|
|
348
|
-
toReversed?: boolean
|
|
349
|
-
) => {
|
|
350
|
-
// Your translation logic
|
|
351
|
-
// e.g., "MagyarorszÃĄg" â "Hungary", "RomÃĄnia" â "Romania"
|
|
196
|
+
setPlaceTranslatorProvider((place, level, toReversed) => {
|
|
352
197
|
return translatedPlace;
|
|
353
198
|
});
|
|
354
199
|
```
|
|
355
200
|
|
|
356
|
-
**Default:**
|
|
357
|
-
|
|
358
|
-
---
|
|
201
|
+
**Default:** identity.
|
|
359
202
|
|
|
360
|
-
|
|
203
|
+
### 5. Cache manager
|
|
361
204
|
|
|
362
|
-
|
|
205
|
+
Caches **whole objects** (not key/value maps). The host chooses the storage key inside the factory.
|
|
363
206
|
|
|
364
207
|
```typescript
|
|
365
|
-
import {
|
|
366
|
-
|
|
208
|
+
import {
|
|
209
|
+
setCacheManagerFactory,
|
|
210
|
+
type CacheManagerFactory,
|
|
211
|
+
type ICacheManager,
|
|
212
|
+
} from '@treeviz/gedcom-parser';
|
|
367
213
|
|
|
368
|
-
const
|
|
214
|
+
const factory: CacheManagerFactory = <T>(
|
|
369
215
|
name: string,
|
|
370
216
|
store: string,
|
|
371
217
|
type: string,
|
|
372
218
|
encrypted: boolean
|
|
373
|
-
) => {
|
|
374
|
-
|
|
219
|
+
): ICacheManager<T> => {
|
|
220
|
+
const key = `gedcom_${name}_${store}_${type}`;
|
|
375
221
|
return {
|
|
376
|
-
async getItem()
|
|
377
|
-
|
|
222
|
+
async getItem() {
|
|
223
|
+
return (await myDb.get(key)) as T | null;
|
|
378
224
|
},
|
|
379
|
-
async setItem(value: T)
|
|
380
|
-
|
|
225
|
+
async setItem(value: T) {
|
|
226
|
+
await myDb.set(key, value);
|
|
381
227
|
},
|
|
382
|
-
async removeItem(): Promise<void> {
|
|
383
|
-
// Your cache remove logic
|
|
384
|
-
}
|
|
385
228
|
};
|
|
386
229
|
};
|
|
387
230
|
|
|
388
|
-
setCacheManagerFactory(
|
|
231
|
+
setCacheManagerFactory(factory);
|
|
389
232
|
```
|
|
390
233
|
|
|
391
|
-
**Default:**
|
|
392
|
-
|
|
393
|
-
---
|
|
234
|
+
**Default:** in-memory single-slot cache.
|
|
394
235
|
|
|
395
|
-
|
|
236
|
+
**Cached today:** path calculations, relatives queries, profile-picture cache (when used).
|
|
396
237
|
|
|
397
|
-
|
|
238
|
+
### 6. Kinship translator class
|
|
398
239
|
|
|
399
240
|
```typescript
|
|
400
241
|
import { setKinshipTranslatorClass, KinshipTranslator } from '@treeviz/gedcom-parser';
|
|
401
242
|
|
|
402
|
-
|
|
403
|
-
class MyCustomTranslator extends KinshipTranslator {
|
|
243
|
+
class MyTranslator extends KinshipTranslator {
|
|
404
244
|
translate(showMainPerson: boolean) {
|
|
405
245
|
const result = super.translate(showMainPerson);
|
|
406
246
|
return result ? `Custom: ${result}` : result;
|
|
407
247
|
}
|
|
408
248
|
}
|
|
409
249
|
|
|
410
|
-
setKinshipTranslatorClass(
|
|
250
|
+
setKinshipTranslatorClass(MyTranslator);
|
|
411
251
|
```
|
|
412
252
|
|
|
413
|
-
|
|
253
|
+
### Reset helpers
|
|
414
254
|
|
|
415
|
-
|
|
255
|
+
```typescript
|
|
256
|
+
import {
|
|
257
|
+
resetI18nProvider,
|
|
258
|
+
resetDateLocaleProvider,
|
|
259
|
+
resetPlaceParserProvider,
|
|
260
|
+
resetPlaceTranslatorProvider,
|
|
261
|
+
resetCacheManagerFactory,
|
|
262
|
+
resetKinshipTranslatorClass,
|
|
263
|
+
} from '@treeviz/gedcom-parser';
|
|
264
|
+
```
|
|
416
265
|
|
|
417
|
-
###
|
|
266
|
+
### Minimal host setup (browser app)
|
|
418
267
|
|
|
419
268
|
```typescript
|
|
420
269
|
import {
|
|
@@ -423,737 +272,148 @@ import {
|
|
|
423
272
|
setPlaceParserProvider,
|
|
424
273
|
setPlaceTranslatorProvider,
|
|
425
274
|
setCacheManagerFactory,
|
|
426
|
-
|
|
275
|
+
setLocalMediaResolver,
|
|
276
|
+
setMediaContentResolver,
|
|
277
|
+
initializeCache,
|
|
278
|
+
GedcomTree,
|
|
427
279
|
} from '@treeviz/gedcom-parser';
|
|
428
280
|
|
|
429
|
-
// 1. Set up all factories BEFORE parsing
|
|
430
281
|
setI18nProvider((key, options) => i18n.t(key, options));
|
|
431
282
|
setDateLocaleProvider(getDateFnsLocale);
|
|
432
283
|
setPlaceParserProvider(getPlaceParts);
|
|
433
284
|
setPlaceTranslatorProvider(placeTranslator);
|
|
434
|
-
setCacheManagerFactory(
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
285
|
+
setCacheManagerFactory(bridgeToIndexedDb);
|
|
286
|
+
setLocalMediaResolver(resolveFromImageStore);
|
|
287
|
+
setMediaContentResolver(resolveContentFromImageStore);
|
|
288
|
+
await initializeCache();
|
|
438
289
|
|
|
439
|
-
|
|
440
|
-
const individuals = gedcom.indis();
|
|
290
|
+
const { gedcom } = GedcomTree.parse(content);
|
|
441
291
|
```
|
|
442
292
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
## Advanced Examples
|
|
293
|
+
## API Overview
|
|
446
294
|
|
|
447
|
-
###
|
|
448
|
-
|
|
449
|
-
```typescript
|
|
450
|
-
import { setCacheFactory, type ICacheManager } from '@treeviz/gedcom-parser';
|
|
451
|
-
import localforage from 'localforage';
|
|
452
|
-
|
|
453
|
-
// Create your cache implementation
|
|
454
|
-
class IndexedDbCache<T> implements ICacheManager<T> {
|
|
455
|
-
private store: LocalForage;
|
|
456
|
-
|
|
457
|
-
constructor(name: string, storeName: string, enc?: boolean) {
|
|
458
|
-
this.store = localforage.createInstance({ name, storeName });
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
async getItem(key: string): Promise<T | null> {
|
|
462
|
-
return this.store.getItem<T>(key);
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
async setItem(key: string, value: T): Promise<void> {
|
|
466
|
-
await this.store.setItem(key, value);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
clear(): void {
|
|
470
|
-
this.store.clear();
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
async clearBy(comparer: (key: string) => boolean): Promise<void> {
|
|
474
|
-
await this.store.iterate((value, key) => {
|
|
475
|
-
if (comparer(key)) {
|
|
476
|
-
this.store.removeItem(key);
|
|
477
|
-
}
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
async clearCache(): Promise<void> {
|
|
482
|
-
// Clear in-memory cache if applicable
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
async getAllItems(): Promise<Record<string, () => Promise<T>>> {
|
|
486
|
-
const items: Record<string, () => Promise<T>> = {};
|
|
487
|
-
await this.store.iterate((value, key) => {
|
|
488
|
-
items[key] = async () => value as T;
|
|
489
|
-
});
|
|
490
|
-
return items;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// Initialize the factory BEFORE using the parser
|
|
495
|
-
setCacheFactory((name, storeName, dataType, enc) =>
|
|
496
|
-
new IndexedDbCache(name, `${storeName}-${dataType}`, enc)
|
|
497
|
-
);
|
|
498
|
-
|
|
499
|
-
// Now caching is enabled for path calculations and relatives
|
|
500
|
-
const { gedcom } = GedcomTree.parse(gedcomContent);
|
|
501
|
-
```
|
|
502
|
-
|
|
503
|
-
---
|
|
504
|
-
|
|
505
|
-
## API Reference
|
|
506
|
-
|
|
507
|
-
### Parser
|
|
508
|
-
|
|
509
|
-
#### `GedcomTree`
|
|
510
|
-
|
|
511
|
-
Main parser object for GEDCOM content.
|
|
295
|
+
### `GedcomTree`
|
|
512
296
|
|
|
513
297
|
```typescript
|
|
514
298
|
import GedcomTree from '@treeviz/gedcom-parser';
|
|
515
299
|
|
|
516
|
-
const { gedcom, settings } = GedcomTree.parse(
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
**Methods:**
|
|
520
|
-
- `parse(content, options?)` - Parse GEDCOM string, returns `{ gedcom, settings }`
|
|
521
|
-
- `parseHierarchy(content, options?)` - Same as `parse()`
|
|
522
|
-
|
|
523
|
-
**Parsed GEDCOM Object Methods:**
|
|
524
|
-
- `gedcom.indis()` - Get all individuals (Individuals collection)
|
|
525
|
-
- `gedcom.fams()` - Get all families (Families collection)
|
|
526
|
-
- `gedcom.sours()` - Get all sources
|
|
527
|
-
- `gedcom.repos()` - Get all repositories
|
|
528
|
-
- `gedcom.objes()` - Get all media objects
|
|
529
|
-
- `gedcom.subms()` - Get all submitters
|
|
530
|
-
- `gedcom.indi(id)` - Get individual by ID
|
|
531
|
-
- `gedcom.fam(id)` - Get family by ID
|
|
532
|
-
|
|
533
|
-
**Individual Methods (on each `indi`):**
|
|
534
|
-
- `toName()` - Get formatted name (e.g., "John Doe")
|
|
535
|
-
- `toNaturalName()` - Get natural order name
|
|
536
|
-
- `getBirthDate(showDays?, shortNote?, showNote?)` - Get formatted birth date (e.g., "*1850" or "*ca. 1850")
|
|
537
|
-
- `getDeathDate(showDays?, shortNote?, showNote?)` - Get formatted death date (e.g., "â 1920" or "â after 1920")
|
|
538
|
-
- `getBirthPlace()` - Get birth place as string
|
|
539
|
-
- `getDeathPlace()` - Get death place as string
|
|
540
|
-
- `BIRT` - Birth event property (access with `.BIRT.DATE`, `.BIRT.PLAC`)
|
|
541
|
-
- `DEAT` - Death event property (access with `.DEAT.DATE`, `.DEAT.PLAC`)
|
|
542
|
-
- `getParents()` - Get parent individuals
|
|
543
|
-
- `getChildren()` - Get all children
|
|
544
|
-
- `getSpouses()` - Get spouses
|
|
545
|
-
- `getSiblings()` - Get siblings
|
|
546
|
-
- `getBrothers()`, `getSisters()` - Get siblings by gender
|
|
547
|
-
- `getFathers()`, `getMothers()` - Get parents by gender
|
|
548
|
-
- `getSons()`, `getDaughters()` - Get children by gender
|
|
549
|
-
- `getGrandParents()`, `getGrandChildren()` - Get grandparents/grandchildren
|
|
550
|
-
- `getAuncles()`, `getUncles()`, `getAunts()` - Get aunts and uncles
|
|
551
|
-
- `getNiblings()`, `getNieces()`, `getNephews()` - Get nieces and nephews
|
|
552
|
-
- `getCousins()` - Get cousins
|
|
553
|
-
- `getParentsInLaw()`, `getChildrenInLaw()`, `getSiblingsInLaw()` - Get in-laws
|
|
554
|
-
- And many more relationship methods...
|
|
555
|
-
|
|
556
|
-
### Cache Manager
|
|
557
|
-
|
|
558
|
-
#### `setCacheManagerFactory(factory)`
|
|
559
|
-
|
|
560
|
-
Set up caching for performance optimization.
|
|
561
|
-
|
|
562
|
-
```typescript
|
|
563
|
-
import { setCacheManagerFactory, type CacheManagerFactory } from '@treeviz/gedcom-parser';
|
|
564
|
-
|
|
565
|
-
const factory: CacheManagerFactory = <T>(name: string, store: string, type: string, encrypted: boolean) => {
|
|
566
|
-
// Return your cache manager implementation
|
|
567
|
-
return {
|
|
568
|
-
async getItem(): Promise<T | null> { /* ... */ },
|
|
569
|
-
async setItem(value: T): Promise<void> { /* ... */ },
|
|
570
|
-
async removeItem(): Promise<void> { /* ... */ }
|
|
571
|
-
};
|
|
572
|
-
};
|
|
573
|
-
|
|
574
|
-
setCacheManagerFactory(factory);
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
**Cache Manager Interface:**
|
|
578
|
-
|
|
579
|
-
```typescript
|
|
580
|
-
interface ICacheManager<T> {
|
|
581
|
-
/** Get an item from cache */
|
|
582
|
-
getItem(): Promise<T | null>;
|
|
583
|
-
|
|
584
|
-
/** Set an item in cache */
|
|
585
|
-
setItem(value: T): Promise<void>;
|
|
586
|
-
|
|
587
|
-
/** Remove item from cache */
|
|
588
|
-
removeItem(): Promise<void>;
|
|
589
|
-
}
|
|
590
|
-
```
|
|
591
|
-
|
|
592
|
-
**What gets cached:**
|
|
593
|
-
- Path calculations between individuals (family tree traversal)
|
|
594
|
-
- Relatives queries (all relatives at N degrees)
|
|
595
|
-
- Kinship translations
|
|
596
|
-
|
|
597
|
-
**When to use caching:**
|
|
598
|
-
- â
Large GEDCOM files (>10MB or >5000 individuals)
|
|
599
|
-
- â
Repeated path calculations
|
|
600
|
-
- â
Multiple relatives queries
|
|
601
|
-
- â
Interactive family tree applications
|
|
602
|
-
|
|
603
|
-
**When NOT to use caching:**
|
|
604
|
-
- â Server-side rendering (use no-op default)
|
|
605
|
-
- â Simple/small GEDCOM files
|
|
606
|
-
- â Memory-constrained environments
|
|
607
|
-
- â One-time parsing tasks
|
|
608
|
-
|
|
609
|
-
---
|
|
610
|
-
|
|
611
|
-
### Factory Providers API Reference
|
|
612
|
-
|
|
613
|
-
#### `setI18nProvider(provider)`
|
|
614
|
-
|
|
615
|
-
Provide translation function for localized content.
|
|
616
|
-
|
|
617
|
-
```typescript
|
|
618
|
-
import { setI18nProvider, type I18nProvider } from '@treeviz/gedcom-parser';
|
|
619
|
-
|
|
620
|
-
const provider: I18nProvider = (key: string, options?: Record<string, unknown>) => {
|
|
621
|
-
// Return translated string
|
|
622
|
-
return myI18n.t(key, options);
|
|
623
|
-
};
|
|
624
|
-
|
|
625
|
-
setI18nProvider(provider);
|
|
626
|
-
```
|
|
627
|
-
|
|
628
|
-
---
|
|
629
|
-
|
|
630
|
-
#### `setDateLocaleProvider(provider)`
|
|
631
|
-
|
|
632
|
-
Provide date-fns locale for date formatting.
|
|
633
|
-
|
|
634
|
-
```typescript
|
|
635
|
-
import { setDateLocaleProvider, type DateLocaleProvider } from '@treeviz/gedcom-parser';
|
|
636
|
-
import { enUS, hu } from 'date-fns/locale';
|
|
637
|
-
|
|
638
|
-
const provider: DateLocaleProvider = (lang: string) => {
|
|
639
|
-
return lang === 'hu' ? hu : enUS;
|
|
640
|
-
};
|
|
641
|
-
|
|
642
|
-
setDateLocaleProvider(provider);
|
|
643
|
-
```
|
|
644
|
-
|
|
645
|
-
---
|
|
646
|
-
|
|
647
|
-
#### `setPlaceParserProvider(provider)`
|
|
648
|
-
|
|
649
|
-
Provide custom place parsing logic.
|
|
650
|
-
|
|
651
|
-
```typescript
|
|
652
|
-
import { setPlaceParserProvider, type PlaceParserFunction } from '@treeviz/gedcom-parser';
|
|
653
|
-
|
|
654
|
-
const provider: PlaceParserFunction = (place: string | (string | undefined)[]) => {
|
|
655
|
-
// Return parsed place parts
|
|
656
|
-
return [{
|
|
657
|
-
leftParts: [],
|
|
658
|
-
town: 'Budapest',
|
|
659
|
-
county: 'Pest',
|
|
660
|
-
country: 'Hungary'
|
|
661
|
-
}];
|
|
662
|
-
};
|
|
663
|
-
|
|
664
|
-
setPlaceParserProvider(provider);
|
|
300
|
+
const { gedcom, settings } = GedcomTree.parse(content, options?);
|
|
665
301
|
```
|
|
666
302
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
#### `setPlaceTranslatorProvider(provider)`
|
|
670
|
-
|
|
671
|
-
Provide custom place name translation.
|
|
672
|
-
|
|
673
|
-
```typescript
|
|
674
|
-
import { setPlaceTranslatorProvider, type PlaceTranslatorFunction } from '@treeviz/gedcom-parser';
|
|
675
|
-
|
|
676
|
-
const provider: PlaceTranslatorFunction = (
|
|
677
|
-
place?: string | string[],
|
|
678
|
-
level?: number,
|
|
679
|
-
toReversed?: boolean
|
|
680
|
-
) => {
|
|
681
|
-
// Return translated place name
|
|
682
|
-
return translatedPlace;
|
|
683
|
-
};
|
|
303
|
+
**On `gedcom`:**
|
|
684
304
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
const result = super.translate(showMainPerson);
|
|
700
|
-
return result ? `Custom: ${result}` : result;
|
|
701
|
-
}
|
|
702
|
-
}
|
|
305
|
+
| Method | Notes |
|
|
306
|
+
| --- | --- |
|
|
307
|
+
| `indis()` / `indi(id)` | Individuals |
|
|
308
|
+
| `fams()` / `fam(id)` | Families |
|
|
309
|
+
| `objes()` / `sours()` / `repos()` / `subms()` / `snotes()` | Other top-level records |
|
|
310
|
+
| `toGedcom(tag?, level?, options?)` | Serialize; `options.gedcomVersion`, `options.original`, media standardize |
|
|
311
|
+
| `toGedzip(options?)` | GEDCOM 7 text + media â `.gdz` bytes |
|
|
312
|
+
| `createMultimediaRecord(input)` | New OBJE |
|
|
313
|
+
| `collectMultimedia(options?)` | Merge `Indi.multimedia()` |
|
|
314
|
+
| `stats()` | Aggregate statistics |
|
|
315
|
+
| `getGedcomVersion()` | Normalized `5.5.1` \| `7.0` |
|
|
316
|
+
| `getOriginalHeadRecord()` | `_ORIGHEAD` if present |
|
|
317
|
+
| `getSourceHeads()` | Original head first, then live `HEAD` |
|
|
318
|
+
| `isAncestry()` / `isMyHeritage()` / âĶ | Vendor detection (uses source heads) |
|
|
703
319
|
|
|
704
|
-
|
|
705
|
-
```
|
|
320
|
+
**On each individual (`indi`):**
|
|
706
321
|
|
|
707
|
-
|
|
322
|
+
- Names / dates / places: `toName()`, `getBirthDate()`, `getDeathDate()`, `getBirthPlace()`, âĶ
|
|
323
|
+
- Relationships: parents, children, spouses, siblings, grandparents, cousins, in-laws, âĶ
|
|
324
|
+
- Media: `multimedia(namespace?)`, `getProfilePicture(namespace?)`, `attachMultimedia()`, `attachMediaFromUrl()`
|
|
325
|
+
- Editing helpers: facts / non-events (`NO`), shared notes, FamilySearch markers, âĶ
|
|
708
326
|
|
|
709
|
-
|
|
327
|
+
See TypeScript definitions under `classes/` and `interfaces/` for the full surface.
|
|
710
328
|
|
|
711
|
-
|
|
329
|
+
### GEDZIP utilities
|
|
712
330
|
|
|
713
331
|
```typescript
|
|
714
332
|
import {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
333
|
+
GEDZIP_MIME,
|
|
334
|
+
GEDZIP_EXTENSION,
|
|
335
|
+
extractGedzip,
|
|
336
|
+
extractGedzipGedcom,
|
|
337
|
+
buildGedzip,
|
|
338
|
+
buildGedzipBlob,
|
|
339
|
+
downloadGedzipMedia,
|
|
340
|
+
remountGedzipMediaAsDataUrls,
|
|
341
|
+
isGedzipContainer,
|
|
342
|
+
rewriteGedcomFilePaths,
|
|
721
343
|
} from '@treeviz/gedcom-parser';
|
|
722
|
-
|
|
723
|
-
// Reset individual providers
|
|
724
|
-
resetI18nProvider();
|
|
725
|
-
resetDateLocaleProvider();
|
|
726
|
-
resetPlaceParserProvider();
|
|
727
|
-
resetPlaceTranslatorProvider();
|
|
728
|
-
resetCacheManagerFactory();
|
|
729
|
-
resetKinshipTranslatorClass();
|
|
344
|
+
// or: '@treeviz/gedcom-parser/utils/gedzip'
|
|
730
345
|
```
|
|
731
346
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
### Country Data Provider (Deprecated)
|
|
735
|
-
|
|
736
|
-
#### `setCountryDataProvider(provider)`
|
|
737
|
-
|
|
738
|
-
â ïļ **Deprecated:** Use `setPlaceParserProvider` and `setPlaceTranslatorProvider` instead for better flexibility.
|
|
739
|
-
|
|
740
|
-
```typescript
|
|
741
|
-
import {
|
|
742
|
-
clearBy(comparer: (key: string) => boolean): Promise<void>;
|
|
743
|
-
|
|
744
|
-
/** Clear in-memory cache */
|
|
745
|
-
clearCache(): Promise<void>;
|
|
746
|
-
|
|
747
|
-
/** Get an item from cache */
|
|
748
|
-
getItem(key: string): Promise<T | null>;
|
|
749
|
-
|
|
750
|
-
/** Get all items as lazy-loaded promises */
|
|
751
|
-
getAllItems(): Promise<Record<string, () => Promise<T>>>;
|
|
752
|
-
|
|
753
|
-
/** Set an item in cache */
|
|
754
|
-
setItem(key: string, value: T): Promise<void>;
|
|
755
|
-
}
|
|
756
|
-
```
|
|
757
|
-
|
|
758
|
-
**What gets cached:**
|
|
759
|
-
- Path calculations between individuals (family tree traversal)
|
|
760
|
-
- Relatives queries (all relatives at N degrees)
|
|
761
|
-
|
|
762
|
-
**When to use caching:**
|
|
763
|
-
- â
Large GEDCOM files (>10MB or >5000 individuals)
|
|
764
|
-
- â
Repeated path calculations
|
|
765
|
-
- â
Multiple relatives queries
|
|
766
|
-
- â
Interactive family tree applications
|
|
767
|
-
|
|
768
|
-
**When NOT to use caching:**
|
|
769
|
-
- â Server-side rendering (use no-op default)
|
|
770
|
-
- â Simple/small GEDCOM files
|
|
771
|
-
- â Memory-constrained environments
|
|
772
|
-
- â One-time parsing tasks
|
|
773
|
-
|
|
774
|
-
### Country Data Provider
|
|
775
|
-
|
|
776
|
-
#### `setCountryDataProvider(provider)`
|
|
777
|
-
|
|
778
|
-
Set up place matching and country/town data.
|
|
347
|
+
### Order / filter / group
|
|
779
348
|
|
|
780
349
|
```typescript
|
|
781
|
-
import {
|
|
782
|
-
setCountryDataProvider,
|
|
783
|
-
type ICountryDataProvider
|
|
784
|
-
} from '@treeviz/gedcom-parser';
|
|
785
|
-
|
|
786
|
-
const provider: ICountryDataProvider = {
|
|
787
|
-
translations: {
|
|
788
|
-
[languageCode]: { countryName: translation }
|
|
789
|
-
},
|
|
790
|
-
countries: {
|
|
791
|
-
[countryCode]: {
|
|
792
|
-
counties: { countyId: countyName },
|
|
793
|
-
towns: {
|
|
794
|
-
[year]: {
|
|
795
|
-
_source: { en: 'Source Name', hu: 'ForrÃĄs NÃĐv' },
|
|
796
|
-
_year: 1913,
|
|
797
|
-
data: { /* town data */ }
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
};
|
|
803
|
-
|
|
804
|
-
setCountryDataProvider(provider);
|
|
805
|
-
```
|
|
806
|
-
|
|
807
|
-
**Helper Functions:**
|
|
808
|
-
```typescript
|
|
809
|
-
// Get country translations for a specific language
|
|
810
|
-
getCountryTranslations(languageCode: string): CountryTranslations;
|
|
811
|
-
|
|
812
|
-
// Get country data by country code
|
|
813
|
-
getCountryData(countryCode: string): CountryData | undefined;
|
|
814
|
-
|
|
815
|
-
// List all supported countries
|
|
816
|
-
getAvailableCountries(): string[];
|
|
817
|
-
|
|
818
|
-
// List all available translations
|
|
819
|
-
getAvailableLanguages(): string[];
|
|
820
|
-
```
|
|
821
|
-
|
|
822
|
-
### Settings & Types
|
|
823
|
-
|
|
824
|
-
#### `Settings`
|
|
825
|
-
|
|
826
|
-
Configuration for parser behavior.
|
|
827
|
-
|
|
828
|
-
```typescript
|
|
829
|
-
import { type Settings } from '@treeviz/gedcom-parser';
|
|
830
|
-
|
|
831
|
-
interface Settings {
|
|
832
|
-
nameOrder?: NameOrder; // 'FIRST_LAST' | 'LAST_FIRST'
|
|
833
|
-
placeOrder?: PlaceOrder; // 'HIERARCHICAL' | 'REVERSE'
|
|
834
|
-
dateFormatPattern?: string; // Date format pattern
|
|
835
|
-
linkedPersons?: LinkedPersons; // How to link related personsname
|
|
836
|
-
// ... other settings
|
|
837
|
-
}
|
|
838
|
-
```
|
|
839
|
-
|
|
840
|
-
#### `Order`, `Filter`, `Group`
|
|
841
|
-
|
|
842
|
-
Utilities for sorting, filtering, and grouping individuals.
|
|
843
|
-
|
|
844
|
-
```typescript
|
|
845
|
-
import { type Order, type Filter, type Group } from '@treeviz/gedcom-parser';
|
|
350
|
+
import GedcomTree, { type Order, type Filter, type Group } from '@treeviz/gedcom-parser';
|
|
846
351
|
|
|
847
|
-
|
|
848
|
-
const byBirthDate: Order = {
|
|
849
|
-
'BIRT.DATE': {
|
|
850
|
-
direction: 'ASC',
|
|
851
|
-
getter: (value, raw) => value
|
|
852
|
-
}
|
|
853
|
-
};
|
|
352
|
+
const individuals = GedcomTree.parse(content).gedcom.indis();
|
|
854
353
|
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
'BIRT.DATE': {
|
|
858
|
-
comparer: (value) => {
|
|
859
|
-
const year = new Date(value).getFullYear();
|
|
860
|
-
return year > 1900;
|
|
861
|
-
}
|
|
862
|
-
}
|
|
354
|
+
const byBirth: Order = {
|
|
355
|
+
'BIRT.DATE': { direction: 'ASC', getter: (value) => value },
|
|
863
356
|
};
|
|
864
357
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
}
|
|
358
|
+
const after1900: Filter = {
|
|
359
|
+
'BIRT.DATE': {
|
|
360
|
+
comparer: (value) => Number(String(value).match(/\d{4}/)?.[0]) > 1900,
|
|
361
|
+
},
|
|
870
362
|
};
|
|
871
363
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
const ordered = individuals.order(byBirthDate);
|
|
875
|
-
const filtered = individuals.filter(bornAfter1900);
|
|
876
|
-
const grouped = individuals.group(byBirthPlace);
|
|
364
|
+
individuals?.order(byBirth);
|
|
365
|
+
individuals?.filter(after1900);
|
|
877
366
|
```
|
|
878
367
|
|
|
879
368
|
## Architecture
|
|
880
369
|
|
|
881
|
-
### Pluggable Design Philosophy
|
|
882
|
-
|
|
883
|
-
The package uses a **pluggable architecture** to avoid browser-specific dependencies:
|
|
884
|
-
|
|
885
370
|
```
|
|
886
|
-
|
|
887
|
-
â
|
|
888
|
-
â
|
|
889
|
-
â
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
â Consumer Application â
|
|
897
|
-
â - Provides ICacheManager â
|
|
898
|
-
â - Provides ICountryDataProvider â
|
|
899
|
-
â - Controls implementation â
|
|
900
|
-
âââââââââââââââââââââââââââââââââââââââ
|
|
371
|
+
ââââââââââââââââââââââââââââââââââââââââ
|
|
372
|
+
â @treeviz/gedcom-parser â
|
|
373
|
+
â parse / export / GEDZIP / kinship â
|
|
374
|
+
â optional factories + media hooks â
|
|
375
|
+
ââââââââââââââââââââŽââââââââââââââââââââ
|
|
376
|
+
â inject
|
|
377
|
+
ââââââââââââââââââââīââââââââââââââââââââ
|
|
378
|
+
â Host app (e.g. TreeViz) â
|
|
379
|
+
â IndexedDB, i18n, place DB, fetch â
|
|
380
|
+
ââââââââââââââââââââââââââââââââââââââââ
|
|
901
381
|
```
|
|
902
382
|
|
|
903
|
-
|
|
904
|
-
-
|
|
905
|
-
-
|
|
906
|
-
- â
Consumer controls all implementation details
|
|
907
|
-
- â
Lightweight package size
|
|
908
|
-
- â
Easy to test (mock implementations)
|
|
909
|
-
- â
Flexible backend choices
|
|
910
|
-
|
|
911
|
-
### Performance Optimization
|
|
912
|
-
|
|
913
|
-
**Without caching:**
|
|
914
|
-
- Path between distant relatives: ~500-1000ms
|
|
915
|
-
- All relatives at 5 degrees: ~2-5 seconds
|
|
916
|
-
- Repeated queries: Same time every time
|
|
917
|
-
|
|
918
|
-
**With caching:**
|
|
919
|
-
- Path between distant relatives: ~10-50ms (10-20x faster)
|
|
920
|
-
- All relatives at 5 degrees: ~100-500ms (10-20x faster)
|
|
921
|
-
- Repeated queries: Near instant (cache hit)
|
|
922
|
-
|
|
923
|
-
**Memory usage:**
|
|
924
|
-
- Core parser: ~5-10MB for typical GEDCOM
|
|
925
|
-
- With cache: +10-50MB depending on cache size
|
|
926
|
-
- Without cache: No additional memory
|
|
927
|
-
|
|
928
|
-
## Complete Examples
|
|
383
|
+
- Works in browser and Node (avoid browser-only factories on the server).
|
|
384
|
+
- Media storage stays in the host; the parser only calls injected resolvers.
|
|
385
|
+
- `_ORIGHEAD` keeps the pre-TreeViz `HEAD` so Ancestry / MyHeritage / FamilySearch detection still works after re-export.
|
|
929
386
|
|
|
930
|
-
|
|
387
|
+
## TypeScript
|
|
931
388
|
|
|
932
389
|
```typescript
|
|
933
|
-
// src/utils/gedcom-init.ts
|
|
934
|
-
import {
|
|
935
|
-
setCacheFactory,
|
|
936
|
-
setCountryDataProvider,
|
|
937
|
-
type ICacheManager
|
|
938
|
-
} from '@treeviz/gedcom-parser';
|
|
939
|
-
import localforage from 'localforage';
|
|
940
|
-
|
|
941
|
-
// Import your data files
|
|
942
|
-
import huCountries from '../data/hu-countries.json';
|
|
943
|
-
import enCountries from '../data/en-countries.json';
|
|
944
|
-
import huCounties from '../data/hungary/counties.json';
|
|
945
|
-
import huTowns2020 from '../data/hungary/towns-2020.json';
|
|
946
|
-
|
|
947
|
-
// Cache implementation
|
|
948
|
-
class IndexedDbCache<T> implements ICacheManager<T> {
|
|
949
|
-
private store: LocalForage;
|
|
950
|
-
|
|
951
|
-
constructor(name: string, storeName: string, enc?: boolean) {
|
|
952
|
-
this.store = localforage.createInstance({
|
|
953
|
-
name,
|
|
954
|
-
storeName,
|
|
955
|
-
driver: localforage.INDEXEDDB
|
|
956
|
-
});
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
clear(): void {
|
|
960
|
-
this.store.clear();
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
async clearBy(comparer: (key: string) => boolean): Promise<void> {
|
|
964
|
-
await this.store.iterate((value, key) => {
|
|
965
|
-
if (comparer(key)) {
|
|
966
|
-
this.store.removeItem(key);
|
|
967
|
-
}
|
|
968
|
-
});
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
async clearCache(): Promise<void> {
|
|
972
|
-
// Optional: clear in-memory cache
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
async getItem(key: string): Promise<T | null> {
|
|
976
|
-
return this.store.getItem<T>(key);
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
async getAllItems(): Promise<Record<string, () => Promise<T>>> {
|
|
980
|
-
const items: Record<string, () => Promise<T>> = {};
|
|
981
|
-
await this.store.iterate((value, key) => {
|
|
982
|
-
items[key] = async () => value as T;
|
|
983
|
-
});
|
|
984
|
-
return items;
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
async setItem(key: string, value: T): Promise<void> {
|
|
988
|
-
await this.store.setItem(key, value);
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
// Initialize gedcom-parser
|
|
993
|
-
export function initGedcomParser() {
|
|
994
|
-
// Set up caching
|
|
995
|
-
setCacheFactory((name, storeName, dataType, enc) =>
|
|
996
|
-
new IndexedDbCache(name, `${storeName}-${dataType}`, enc)
|
|
997
|
-
);
|
|
998
|
-
|
|
999
|
-
// Set up country data
|
|
1000
|
-
setCountryDataProvider({
|
|
1001
|
-
translations: {
|
|
1002
|
-
hu: huCountries,
|
|
1003
|
-
en: enCountries,
|
|
1004
|
-
},
|
|
1005
|
-
countries: {
|
|
1006
|
-
HU: {
|
|
1007
|
-
counties: huCounties,
|
|
1008
|
-
towns: {
|
|
1009
|
-
'2020': {
|
|
1010
|
-
_source: { en: 'Hungary 2020', hu: 'MagyarorszÃĄg 2020' },
|
|
1011
|
-
_year: 2020,
|
|
1012
|
-
data: huTowns2020,
|
|
1013
|
-
},
|
|
1014
|
-
},
|
|
1015
|
-
},
|
|
1016
|
-
},
|
|
1017
|
-
});
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
// Call this in your app initialization
|
|
1021
|
-
// src/index.tsx
|
|
1022
|
-
import { initGedcomParser } from './utils/gedcom-init';
|
|
1023
|
-
import GedcomTree from '@treeviz/gedcom-parser';
|
|
1024
|
-
|
|
1025
|
-
initGedcomParser();
|
|
1026
|
-
|
|
1027
|
-
// Now you can use the parser anywhere
|
|
1028
|
-
function parseGedcom(content: string) {
|
|
1029
|
-
const { gedcom } = GedcomTree.parse(content);
|
|
1030
|
-
return gedcom.indis();
|
|
1031
|
-
}
|
|
1032
|
-
```
|
|
1033
|
-
|
|
1034
|
-
### Order, Filter, Group Example
|
|
1035
|
-
|
|
1036
|
-
```typescript
|
|
1037
|
-
import GedcomTree, { type Order, type Filter, type Group } from '@treeviz/gedcom-parser';
|
|
1038
|
-
|
|
1039
|
-
const { gedcom } = GedcomTree.parse(gedcomContent);
|
|
1040
|
-
const individuals = gedcom.indis();
|
|
1041
|
-
|
|
1042
|
-
// 1. Order by birth date (oldest first)
|
|
1043
|
-
const byBirthDateAsc: Order = {
|
|
1044
|
-
'BIRT.DATE': {
|
|
1045
|
-
direction: 'ASC',
|
|
1046
|
-
getter: (value) => new Date(value).getTime()
|
|
1047
|
-
}
|
|
1048
|
-
};
|
|
1049
|
-
|
|
1050
|
-
const orderedByBirth = individuals.order(byBirthDateAsc);
|
|
1051
|
-
|
|
1052
|
-
// 2. Filter born in 20th century
|
|
1053
|
-
const born20thCentury: Filter = {
|
|
1054
|
-
'BIRT.DATE': {
|
|
1055
|
-
comparer: (date) => {
|
|
1056
|
-
const year = new Date(date).getFullYear();
|
|
1057
|
-
return year >= 1900 && year < 2000;
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
};
|
|
1061
|
-
|
|
1062
|
-
const filtered20thCentury = individuals.filter(born20thCentury);
|
|
1063
|
-
|
|
1064
|
-
// 3. Group by birth place
|
|
1065
|
-
const byBirthPlace: Group = {
|
|
1066
|
-
'BIRT.PLAC': {
|
|
1067
|
-
getter: (place) => place || 'Unknown'
|
|
1068
|
-
}
|
|
1069
|
-
};
|
|
1070
|
-
|
|
1071
|
-
const groupedByPlace = individuals.group(byBirthPlace);
|
|
1072
|
-
|
|
1073
|
-
// Print results
|
|
1074
|
-
groupedByPlace.forEach((group, place) => {
|
|
1075
|
-
console.log(`Born in ${place}:`);
|
|
1076
|
-
group.forEach(indi => {
|
|
1077
|
-
console.log(` - ${indi.toName()}`);
|
|
1078
|
-
});
|
|
1079
|
-
});
|
|
1080
|
-
|
|
1081
|
-
// 4. Combine: Filter + Order + Group
|
|
1082
|
-
const males born20thInBudapest = individuals
|
|
1083
|
-
.filter(born20thCentury)
|
|
1084
|
-
.filter({ 'BIRT.PLAC': { comparer: (place) => place?.includes('Budapest') } })
|
|
1085
|
-
.filter({ 'SEX': { comparer: (sex) => sex === 'M' } })
|
|
1086
|
-
.order(byBirthDateAsc);
|
|
1087
|
-
```
|
|
1088
|
-
|
|
1089
|
-
## TypeScript Support
|
|
1090
|
-
|
|
1091
|
-
Full TypeScript support with complete type definitions:
|
|
1092
|
-
|
|
1093
|
-
```typescript
|
|
1094
|
-
// Import types
|
|
1095
390
|
import type {
|
|
1096
|
-
// Core
|
|
1097
391
|
Settings,
|
|
1098
392
|
Order,
|
|
1099
|
-
OrderDefinition,
|
|
1100
393
|
Filter,
|
|
1101
394
|
Group,
|
|
1102
|
-
|
|
1103
|
-
// Pluggable interfaces
|
|
1104
395
|
ICacheManager,
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
IEventDetailStructure,
|
|
1114
|
-
|
|
1115
|
-
// Class interfaces
|
|
1116
|
-
GedComInterface,
|
|
1117
|
-
IndiInterface,
|
|
1118
|
-
FamInterface,
|
|
1119
|
-
|
|
1120
|
-
// And many more...
|
|
1121
|
-
} from '@treeviz/gedcom-parser';
|
|
1122
|
-
```
|
|
1123
|
-
|
|
1124
|
-
## Legacy Compatibility
|
|
1125
|
-
|
|
1126
|
-
For backward compatibility, the package exports legacy names:
|
|
1127
|
-
|
|
1128
|
-
```typescript
|
|
1129
|
-
// Old names (still work)
|
|
1130
|
-
import {
|
|
1131
|
-
setIndexedDbFactory, // â Same as setCacheFactory
|
|
1132
|
-
type IIndexedDbManager, // â Same as ICacheManager
|
|
1133
|
-
type IndexedDbFactory // â Same as CacheFactory
|
|
396
|
+
CacheManagerFactory,
|
|
397
|
+
I18nProvider,
|
|
398
|
+
DateLocaleProvider,
|
|
399
|
+
PlaceParserFunction,
|
|
400
|
+
PlaceTranslatorFunction,
|
|
401
|
+
LocalMediaResolver,
|
|
402
|
+
MediaContentResolver,
|
|
403
|
+
GedzipMediaInput,
|
|
1134
404
|
} from '@treeviz/gedcom-parser';
|
|
1135
405
|
|
|
1136
|
-
|
|
1137
|
-
import {
|
|
1138
|
-
setCacheFactory,
|
|
1139
|
-
type ICacheManager,
|
|
1140
|
-
type CacheFactory
|
|
1141
|
-
} from '@treeviz/gedcom-parser';
|
|
406
|
+
import type { GedComType } from '@treeviz/gedcom-parser/classes';
|
|
407
|
+
import type { IndiType } from '@treeviz/gedcom-parser/classes';
|
|
1142
408
|
```
|
|
1143
409
|
|
|
1144
|
-
##
|
|
1145
|
-
|
|
1146
|
-
- Chrome/Edge: â
Full support
|
|
1147
|
-
- Firefox: â
Full support
|
|
1148
|
-
- Safari: â
Full support
|
|
1149
|
-
- IE11: â Not supported (use transpilation)
|
|
1150
|
-
|
|
1151
|
-
## Node.js Compatibility
|
|
410
|
+
## Compatibility
|
|
1152
411
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
412
|
+
| Environment | Support |
|
|
413
|
+
| --- | --- |
|
|
414
|
+
| Modern Chromium / Firefox / Safari | â
|
|
|
415
|
+
| Node.js 20+ | â
|
|
|
416
|
+
| IE11 | â |
|
|
1157
417
|
|
|
1158
418
|
## License
|
|
1159
419
|
|
|
@@ -1161,33 +421,20 @@ MIT
|
|
|
1161
421
|
|
|
1162
422
|
## Contributing
|
|
1163
423
|
|
|
1164
|
-
Contributions welcome! Please open an issue or PR on GitHub.
|
|
1165
|
-
|
|
1166
|
-
### Development Setup
|
|
1167
|
-
|
|
1168
424
|
```bash
|
|
1169
|
-
# Clone repository
|
|
1170
425
|
git clone https://github.com/idavidka/gedcom-parser.git
|
|
1171
426
|
cd gedcom-parser
|
|
1172
|
-
|
|
1173
|
-
# Install dependencies
|
|
1174
427
|
npm install
|
|
1175
|
-
|
|
1176
|
-
# Build
|
|
1177
428
|
npm run build
|
|
1178
|
-
|
|
1179
|
-
# Run tests (if available)
|
|
1180
429
|
npm test
|
|
1181
430
|
```
|
|
1182
431
|
|
|
1183
432
|
## Support
|
|
1184
433
|
|
|
1185
|
-
-
|
|
1186
|
-
-
|
|
1187
|
-
-
|
|
434
|
+
- Issues: [GitHub Issues](https://github.com/idavidka/gedcom-parser/issues)
|
|
435
|
+
- Discussions: [GitHub Discussions](https://github.com/idavidka/gedcom-parser/discussions)
|
|
436
|
+
- App: [TreeViz](https://treeviz.com)
|
|
1188
437
|
|
|
1189
438
|
## Credits
|
|
1190
439
|
|
|
1191
440
|
Originally developed as part of **TreeViz** by [@idavidka](https://github.com/idavidka).
|
|
1192
|
-
|
|
1193
|
-
Special thanks to all contributors and the genealogy community.
|