@treeviz/gedcom-parser 2.0.10 → 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.
Files changed (71) hide show
  1. package/README.md +236 -989
  2. package/dist/classes/common.d.ts +10 -5
  3. package/dist/classes/common.d.ts.map +1 -1
  4. package/dist/classes/date.d.ts +2 -0
  5. package/dist/classes/date.d.ts.map +1 -1
  6. package/dist/classes/fam.d.ts +10 -1
  7. package/dist/classes/fam.d.ts.map +1 -1
  8. package/dist/classes/fams.d.ts.map +1 -1
  9. package/dist/classes/gedcom.d.ts +45 -4
  10. package/dist/classes/gedcom.d.ts.map +1 -1
  11. package/dist/classes/index.js +1770 -279
  12. package/dist/classes/indi.d.ts +24 -1
  13. package/dist/classes/indi.d.ts.map +1 -1
  14. package/dist/classes/list.d.ts.map +1 -1
  15. package/dist/classes/note.d.ts.map +1 -1
  16. package/dist/classes/obje.d.ts +2 -1
  17. package/dist/classes/obje.d.ts.map +1 -1
  18. package/dist/cli/index.js +2802 -1296
  19. package/dist/constants/constants.d.ts +7 -0
  20. package/dist/constants/constants.d.ts.map +1 -1
  21. package/dist/constants/index.js +1599 -989
  22. package/dist/factories/index.js +719 -110
  23. package/dist/index.d.ts +12 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +3837 -2028
  26. package/dist/interfaces/common.d.ts +6 -4
  27. package/dist/interfaces/common.d.ts.map +1 -1
  28. package/dist/interfaces/fam.d.ts +10 -1
  29. package/dist/interfaces/fam.d.ts.map +1 -1
  30. package/dist/interfaces/gedcom.d.ts +25 -1
  31. package/dist/interfaces/gedcom.d.ts.map +1 -1
  32. package/dist/interfaces/indi.d.ts +15 -1
  33. package/dist/interfaces/indi.d.ts.map +1 -1
  34. package/dist/kinship-translator/index.js +719 -110
  35. package/dist/structures/gedcom.d.ts +2 -0
  36. package/dist/structures/gedcom.d.ts.map +1 -1
  37. package/dist/types/types.d.ts +32 -4
  38. package/dist/types/types.d.ts.map +1 -1
  39. package/dist/utils/common-creator.d.ts.map +1 -1
  40. package/dist/utils/fact-edit.d.ts +34 -0
  41. package/dist/utils/fact-edit.d.ts.map +1 -0
  42. package/dist/utils/family-edit.d.ts +23 -0
  43. package/dist/utils/family-edit.d.ts.map +1 -0
  44. package/dist/utils/gedcom-trailer.d.ts +6 -0
  45. package/dist/utils/gedcom-trailer.d.ts.map +1 -0
  46. package/dist/utils/gedcom-version.d.ts +6 -0
  47. package/dist/utils/gedcom-version.d.ts.map +1 -0
  48. package/dist/utils/gedcom7-dates.d.ts +20 -0
  49. package/dist/utils/gedcom7-dates.d.ts.map +1 -0
  50. package/dist/utils/gedcom7-enumerations.d.ts +26 -0
  51. package/dist/utils/gedcom7-enumerations.d.ts.map +1 -0
  52. package/dist/utils/gedcom7-metadata.d.ts +19 -0
  53. package/dist/utils/gedcom7-metadata.d.ts.map +1 -0
  54. package/dist/utils/gedcom7-schema.d.ts +27 -0
  55. package/dist/utils/gedcom7-schema.d.ts.map +1 -0
  56. package/dist/utils/gedzip.d.ts +81 -0
  57. package/dist/utils/gedzip.d.ts.map +1 -0
  58. package/dist/utils/index.d.ts +13 -1
  59. package/dist/utils/index.d.ts.map +1 -1
  60. package/dist/utils/index.js +2225 -416
  61. package/dist/utils/local-media.d.ts +30 -0
  62. package/dist/utils/local-media.d.ts.map +1 -0
  63. package/dist/utils/media-utils.d.ts +10 -6
  64. package/dist/utils/media-utils.d.ts.map +1 -1
  65. package/dist/utils/multimedia.d.ts +38 -0
  66. package/dist/utils/multimedia.d.ts.map +1 -0
  67. package/dist/utils/parser.d.ts +3 -0
  68. package/dist/utils/parser.d.ts.map +1 -1
  69. package/dist/utils/uid.d.ts +6 -0
  70. package/dist/utils/uid.d.ts.map +1 -0
  71. 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 - A collection of tools for genealogy data processing and visualization.
3
+ > Part of the [@treeviz](https://www.npmjs.com/org/treeviz) organization — tools for genealogy data processing and visualization.
4
4
 
5
- A lightweight, pluggable GEDCOM parser library for JavaScript/TypeScript applications. Originally part of [TreeViz](https://treeviz.com), extracted as a standalone package for reusability.
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
- - 🚀 **Parse GEDCOM files** - Full GEDCOM 5.5.1 support
10
- - ðŸ–Ĩïļ **Command-Line Interface** - CLI tools for common GEDCOM operations
11
- - 🔌 **Pluggable Architecture** - Zero dependencies on browser-specific APIs
12
- - ðŸ’ū **Optional Caching** - Provide your own cache implementation (IndexedDB, localStorage, Redis, etc.)
13
- - 🌍 **Optional Place Matching** - Provide your own country/place data
14
- - 🏗ïļ **TypeScript** - Full type definitions included
15
- - ðŸŠķ **Lightweight** - Core package has minimal dependencies
16
- - 🔒 **SSR-Safe** - No-op defaults for server-side rendering
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
- ## Quick Start
34
+ Requires **Node.js 20+** (see `engines` in `package.json`).
25
35
 
26
- ### Basic Usage (No Plugins)
36
+ ## Quick Start
27
37
 
28
38
  ```typescript
29
39
  import GedcomTree from '@treeviz/gedcom-parser';
30
40
 
31
- const gedcomContent = `0 HEAD
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
- individuals.forEach(indi => {
41
- console.log(indi.toName()); // "John Doe"
42
- console.log(indi.getBirthDate()); // "*1850" (year only)
43
- console.log(indi.getBirthDate(true)); // "*1850.05.15." (full date)
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
- ## Command-Line Interface (CLI)
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
- # Get descendants
175
- gedcom-parser relatives family.ged @I123@ --descendants
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
- # Limit depth
181
- gedcom-parser relatives family.ged @I123@ --ancestors --depth 3
62
+ // Explicit 5.5.1 (no G7 transforms)
63
+ const ged551 = gedcom.toGedcom(undefined, 0, { gedcomVersion: '5.5.1' });
182
64
 
183
- # Save to file
184
- gedcom-parser relatives family.ged @I123@ --tree --output subset.ged
65
+ // Omit gedcomVersion → use HEAD.GEDC.VERS, else 5.5.1
66
+ const auto = gedcom.toGedcom();
185
67
  ```
186
68
 
187
- #### `extract` - Create filtered subset
69
+ ### GEDZIP (`.gdz`)
188
70
 
189
- ```bash
190
- gedcom-parser extract <file> --output <output> [options]
71
+ ```typescript
72
+ import {
73
+ extractGedzip,
74
+ buildGedzipBlob,
75
+ downloadGedzipMedia,
76
+ setMediaContentResolver,
77
+ } from '@treeviz/gedcom-parser';
191
78
 
192
- # Extract by surname
193
- gedcom-parser extract family.ged --surname Smith --output smiths.ged
79
+ // Import archive → GEDCOM text + media bytes
80
+ const { gedcomText, mediaEntries } = await extractGedzip(file);
194
81
 
195
- # Extract by birth year range
196
- gedcom-parser extract family.ged --birth-after 1900 --birth-before 2000 --output 20th-century.ged
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
- # Combine filters
199
- gedcom-parser extract family.ged --surname "Johnson" --birth-after 1850 --output johnsons.ged
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
- #### `stats` - Generate statistics
96
+ Or use `gedcom.toGedzip({ media: downloaded })` when you already have byte payloads.
203
97
 
204
- ```bash
205
- gedcom-parser stats <file> [options]
98
+ ### Local / cached media paths
206
99
 
207
- # Show statistics
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
- # Output as JSON
211
- gedcom-parser stats family.ged --json
212
- ```
213
-
214
- #### `merge` - Combine GEDCOM files
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
- # Merge multiple files
220
- gedcom-parser merge file1.ged file2.ged file3.ged --output merged.ged
108
+ setLocalMediaResolver(async (path) => {
109
+ // Return a data:/blob:/https: URL for display
110
+ return await myImageStore.get(path);
111
+ });
221
112
 
222
- # Merge with deduplication
223
- gedcom-parser merge file1.ged file2.ged --output merged.ged --dedupe
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
- #### `convert` - Convert to other formats
120
+ ## Command-Line Interface
227
121
 
228
122
  ```bash
229
- gedcom-parser convert <file> --format <format> [options]
230
-
231
- # Convert to JSON
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
- ### CLI Examples
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
- # Find all individuals with surname "Smith" born after 1900
245
- gedcom-parser find family.ged --surname Smith --birth-after 1900
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
- The package uses factory patterns to allow customization of core functionality. All factories are **optional** - the package provides sensible defaults.
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
- Provide your translation function for date formatting and other localized content.
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
- // Set up translation provider
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:** Returns the key as-is (no translation)
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 { enUS, hu, de } from 'date-fns/locale';
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
- **Default:** English (en-US) locale
309
-
310
- ---
171
+ // No language argument — return the locale for the *current* app language
172
+ setDateLocaleProvider(() => hu);
173
+ ```
311
174
 
312
- #### 3. **Place Parser Provider**
175
+ **Default:** `undefined` (date-fns default behavior).
313
176
 
314
- Provide custom place parsing logic for sophisticated place name recognition.
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
- // Custom place parser with historical place recognition
321
- setPlaceParserProvider((place: string | (string | undefined)[]) => {
322
- // Your sophisticated place parsing logic
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:** Simple comma-split parser (last part = country, second-to-last = county, rest = town)
334
-
335
- ---
189
+ **Default:** simple comma-split heuristic.
336
190
 
337
- #### 4. **Place Translator Provider**
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
- // Custom place translator with country name translation
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:** Returns place name as-is (no translation)
357
-
358
- ---
201
+ **Default:** identity.
359
202
 
360
- #### 5. **Cache Manager Factory**
203
+ ### 5. Cache manager
361
204
 
362
- Provide your own caching implementation (IndexedDB, localStorage, Redis, etc.).
205
+ Caches **whole objects** (not key/value maps). The host chooses the storage key inside the factory.
363
206
 
364
207
  ```typescript
365
- import { setCacheManagerFactory } from '@treeviz/gedcom-parser';
366
- import type { CacheManagerFactory } from '@treeviz/gedcom-parser';
208
+ import {
209
+ setCacheManagerFactory,
210
+ type CacheManagerFactory,
211
+ type ICacheManager,
212
+ } from '@treeviz/gedcom-parser';
367
213
 
368
- const cacheFactory: CacheManagerFactory = <T>(
214
+ const factory: CacheManagerFactory = <T>(
369
215
  name: string,
370
216
  store: string,
371
217
  type: string,
372
218
  encrypted: boolean
373
- ) => {
374
- // Return cache manager instance
219
+ ): ICacheManager<T> => {
220
+ const key = `gedcom_${name}_${store}_${type}`;
375
221
  return {
376
- async getItem(): Promise<T | null> {
377
- // Your cache get logic
222
+ async getItem() {
223
+ return (await myDb.get(key)) as T | null;
378
224
  },
379
- async setItem(value: T): Promise<void> {
380
- // Your cache set logic
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(cacheFactory);
231
+ setCacheManagerFactory(factory);
389
232
  ```
390
233
 
391
- **Default:** In-memory cache (suitable for Node.js, testing, or small trees)
392
-
393
- ---
234
+ **Default:** in-memory single-slot cache.
394
235
 
395
- #### 6. **Kinship Translator Class**
236
+ **Cached today:** path calculations, relatives queries, profile-picture cache (when used).
396
237
 
397
- Override the kinship relationship translator.
238
+ ### 6. Kinship translator class
398
239
 
399
240
  ```typescript
400
241
  import { setKinshipTranslatorClass, KinshipTranslator } from '@treeviz/gedcom-parser';
401
242
 
402
- // Extend built-in translator
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(MyCustomTranslator);
250
+ setKinshipTranslatorClass(MyTranslator);
411
251
  ```
412
252
 
413
- **Default:** Built-in multi-language translator (EN, HU, DE, ES, FR)
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
- ### Complete Setup Example
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
- GedcomTree
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(cacheFactory);
435
-
436
- // Now parse GEDCOM
437
- const { gedcom } = GedcomTree.parse(gedcomContent);
285
+ setCacheManagerFactory(bridgeToIndexedDb);
286
+ setLocalMediaResolver(resolveFromImageStore);
287
+ setMediaContentResolver(resolveContentFromImageStore);
288
+ await initializeCache();
438
289
 
439
- // All functionality now uses your custom implementations
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
- ### With Caching (IndexedDB Example)
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(gedcomContent, options?);
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
- setPlaceTranslatorProvider(provider);
686
- ```
687
-
688
- ---
689
-
690
- #### `setKinshipTranslatorClass(translatorClass)`
691
-
692
- Override the kinship relationship translator.
693
-
694
- ```typescript
695
- import { setKinshipTranslatorClass, KinshipTranslator } from '@treeviz/gedcom-parser';
696
-
697
- class MyTranslator extends KinshipTranslator {
698
- translate(showMainPerson: boolean): string | undefined {
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
- setKinshipTranslatorClass(MyTranslator);
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
- #### Reset Functions
327
+ See TypeScript definitions under `classes/` and `interfaces/` for the full surface.
710
328
 
711
- All providers have corresponding reset functions to restore defaults:
329
+ ### GEDZIP utilities
712
330
 
713
331
  ```typescript
714
332
  import {
715
- resetI18nProvider,
716
- resetDateLocaleProvider,
717
- resetPlaceParserProvider,
718
- resetPlaceTranslatorProvider,
719
- resetCacheManagerFactory,
720
- resetKinshipTranslatorClass
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
- // Order individuals by birth date
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
- // Filter individuals born after 1900
856
- const bornAfter1900: Filter = {
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
- // Group individuals by birth place
866
- const byBirthPlace: Group = {
867
- 'BIRT.PLAC': {
868
- getter: (value) => value || 'Unknown'
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
- // Use them
873
- const individuals = tree.indis();
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
- │ @treeviz/gedcom-parser (Core) │
888
- │ - Pure parsing logic │
889
- │ - Type definitions │
890
- │ - No browser dependencies │
891
- └──────────────┮──────────────────────┘
892
- │
893
- │ Interfaces
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
- **Benefits:**
904
- - ✅ Works in any environment (browser, Node.js, React Native, Electron, etc.)
905
- - ✅ No bundling of unused code (tree-shakeable)
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
- ### Full React Application Setup
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
- CacheFactory,
1106
- ICountryDataProvider,
1107
- CountryTranslations,
1108
- CountryData,
1109
-
1110
- // Date & Event structures
1111
- CommonDate,
1112
- IDateStructure,
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
- // New names (recommended)
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
- ## Browser Compatibility
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
- - Node.js 14+: ✅ Full support
1154
- - Recommended: Node.js 18+ (LTS)
1155
-
1156
- **Note:** When using in Node.js, don't set up browser-specific plugins (IndexedDB). The package works fine with no-op defaults.
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
- - **Issues**: [GitHub Issues](https://github.com/idavidka/gedcom-parser/issues)
1186
- - **Discussions**: [GitHub Discussions](https://github.com/idavidka/gedcom-parser/discussions)
1187
- - **Main App**: [TreeViz](https://treeviz.com)
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.