gedcomkit 0.1.4__tar.gz → 0.1.6__tar.gz
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.
- gedcomkit-0.1.6/CHANGELOG.md +175 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/Cargo.lock +1 -1
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/Cargo.toml +1 -1
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/PKG-INFO +1 -1
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/README.md +3 -3
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/bindings/gedcomkit-py/Cargo.lock +2 -2
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/bindings/gedcomkit-py/Cargo.toml +1 -1
- gedcomkit-0.1.6/bindings/gedcomkit-py/gedcomkit.pyi +84 -0
- gedcomkit-0.1.6/bindings/gedcomkit-py/src/lib.rs +521 -0
- gedcomkit-0.1.6/src/build.rs +711 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/src/dates.rs +368 -28
- gedcomkit-0.1.6/src/gedzip.rs +2344 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/src/lib.rs +3 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/tests/requirement_corpus.rs +3 -2
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/tests/version_conversion.rs +3 -2
- gedcomkit-0.1.4/CHANGELOG.md +0 -56
- gedcomkit-0.1.4/bindings/gedcomkit-py/src/lib.rs +0 -234
- gedcomkit-0.1.4/src/gedzip.rs +0 -965
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/LICENSE +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/bindings/gedcomkit-py/LICENSE +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/bindings/gedcomkit-py/README.md +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom-spec/LICENSE +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom-spec/README.md +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom-spec/cardinalities.tsv +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom-spec/enumerations.tsv +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom-spec/enumerationsets.tsv +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom-spec/grammar.abnf +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom-spec/grammar.gedstruct +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom-spec/payloads.tsv +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom-spec/substructures.tsv +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/age-invalid.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/age-valid.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/atsign.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/char_ascii_1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/char_ascii_2.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/char_utf16be-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/char_utf16be-2.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/char_utf16le-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/char_utf16le-2.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/char_utf8-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/char_utf8-2.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/char_utf8-3.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/date-all.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/date-dual-invalid.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/date-dual-valid.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/enum-ext.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/filename-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/lang-all.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/notes-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/obje-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/obsolete-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/pedi-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/rela_1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/sour-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/tiny-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/5/xref-case.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/age-invalid.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/age-valid.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/atsign.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/char_ascii_1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/char_ascii_2.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/char_utf16be-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/char_utf16be-2.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/char_utf16le-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/char_utf16le-2.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/char_utf8-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/char_utf8-2.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/char_utf8-3.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/date-all.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/date-dual-invalid.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/enum-ext.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/filename-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/lang-all.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/notes-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/obje-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/obsolete-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/pedi-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/rela_1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/sour-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/tiny-1.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/7/xref-case.ged +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/LICENSE +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/gedcom7code/UPSTREAM-README.md +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/zip-interop/README.md +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/zip-interop/python-zip64.gdz +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/fixtures/vendored/zip-interop/python-zipfile.gdz +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/pyproject.toml +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/src/convert.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/src/decode.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/src/family.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/src/names.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/src/schema.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/src/synthetic.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/src/tags.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/src/validate.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/src/view.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/tests/endurance.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/tests/external_charset.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/tests/properties.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/tests/spec_conformance.rs +0 -0
- {gedcomkit-0.1.4 → gedcomkit-0.1.6}/tests/vendored_corpus.rs +0 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file. The
|
|
4
|
+
format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
5
|
+
the project uses semantic versioning within the usual pre-1.0 compatibility
|
|
6
|
+
rules.
|
|
7
|
+
|
|
8
|
+
## [0.1.6] - 2026-09-25
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `build`, for a producer writing its own data as GEDCOM rather than
|
|
13
|
+
reading a file. `build::NodeSpec` describes a structure (tag, optional
|
|
14
|
+
identifier and payload, substructures) and `NodeSpec::into_node` checks
|
|
15
|
+
it under `Limits`, refusing with an error what `Node::new` would panic on;
|
|
16
|
+
with the `serde` feature it deserializes, refusing unknown keys.
|
|
17
|
+
`Document::append_records` adds records before the trailer, all or none,
|
|
18
|
+
refusing a repeated identifier or a second header or trailer, and
|
|
19
|
+
`Document::append_structures` adds substructures to any record or the
|
|
20
|
+
header (which 5.5.1 wants a `SUBM` pointer in, and `new_v551` cannot
|
|
21
|
+
supply), leaving every existing line as it was.
|
|
22
|
+
- `Document::wrap_long_lines`, which fits a 5.5.1 document to a line limit
|
|
23
|
+
by splitting payloads across `CONC` lines — at character boundaries, and
|
|
24
|
+
not beside a space where the text allows — and names every structure it
|
|
25
|
+
rewrote. Lines that fit are untouched; a version 7 document is refused.
|
|
26
|
+
- `dates::GedcomDate::to_gedcom_5_5_1`, the reading written in 5.5.1's own
|
|
27
|
+
date grammar (`about 5 January 1882` → `ABT 5 JAN 1882`), or `None` when
|
|
28
|
+
that grammar cannot hold it without loss. A dual year it can spell
|
|
29
|
+
(`1740/41`) is kept; a slashed pair it cannot makes an exact date an `INT`
|
|
30
|
+
date carrying the original as its phrase.
|
|
31
|
+
- Python and JavaScript/WASM bindings: `Gedcom.new_v551` / `newV551`,
|
|
32
|
+
`new_v7` / `newV7`, `append_records` / `appendRecords` (records as plain
|
|
33
|
+
dicts/objects), `append_structures` / `appendStructures`, `wrap_long_lines` / `wrapLongLines`, and
|
|
34
|
+
`parse_date` / `parseDate`, a date reading with its `display` and
|
|
35
|
+
`gedcom551` renderings.
|
|
36
|
+
- Python only: `ArchiveFileWriter`, a GEDZIP writer whose sink is a file,
|
|
37
|
+
with `add_file` streaming an entry from disk without the bytes passing
|
|
38
|
+
through Python — so a multi-gigabyte archive no longer has to fit in
|
|
39
|
+
memory twice. And type stubs (`gedcomkit.pyi`), so the package is typed
|
|
40
|
+
for mypy and pyright.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- The date reader accepts 5.5.1's `B.C.` epoch as well as 7.0's `BCE`.
|
|
45
|
+
- The date reader matched its keywords by ASCII case only, so `après 12
|
|
46
|
+
juillet 1670` and `før 1679` went unread although both words were in its
|
|
47
|
+
tables. Keywords now compare case in every script, and may run straight
|
|
48
|
+
into the date (`abt1810`, `c1700`).
|
|
49
|
+
- `April 9, 1950` read its `9` as September and failed; a month written as a
|
|
50
|
+
word now decides the order. `10 January 1566/67`, a dual year ending a full
|
|
51
|
+
date, now reads as 1566 as the bare `1566/67` already did.
|
|
52
|
+
- More spellings: `vers`, `cir`, `c.`, `around`, `probably`, `omtrent`,
|
|
53
|
+
`cirka` (about); `før` (before); `etter`, `efter` (after); `entre … et …`,
|
|
54
|
+
`mellom … og …` (between); `du … au …`, `fra … til …` (from … to);
|
|
55
|
+
and the months `déc`, `févr`, `janv`, `avr`, `juil`, `desember`.
|
|
56
|
+
|
|
57
|
+
## [0.1.5] - 2026-09-18
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
|
|
61
|
+
- `gedzip::ArchiveWriter`, a streaming GEDZIP writer: entries are added one
|
|
62
|
+
at a time and written straight to a sink, so peak memory is a small
|
|
63
|
+
multiple of the largest single entry plus the growing central directory,
|
|
64
|
+
never the archive's total. Measured, one `add` runs from roughly 2x the
|
|
65
|
+
entry (already-compressed media, stored) to a little over 3.5x (highly
|
|
66
|
+
compressible text, which briefly holds the source, the deflate output and
|
|
67
|
+
the encoder's state together) — never a function of how many entries came
|
|
68
|
+
before. A hash set of every lowercased path added so far is resident for
|
|
69
|
+
the writer's lifetime too, and at the default 100,000-entry limit the
|
|
70
|
+
central directory is bounded but not small.
|
|
71
|
+
It produces Zip64 structures once the entry count, an entry's size or the
|
|
72
|
+
running offset needs them, so it has no archive-size ceiling; the local
|
|
73
|
+
header's Zip64 extra carries both the original and compressed size
|
|
74
|
+
together whenever either overflows, as APPNOTE 4.5.3 requires for readers
|
|
75
|
+
that resolve local headers while streaming. Entry names carry
|
|
76
|
+
general-purpose bit 11 (UTF-8). A write failure to the sink poisons the
|
|
77
|
+
writer, so no entry is ever written next to bytes a failed write left
|
|
78
|
+
truncated, and `finish` flushes the sink before returning it rather than
|
|
79
|
+
leaving the last bytes to a `Drop` that cannot report failure.
|
|
80
|
+
`ArchiveWriter` implements `Debug` — entry count, bytes written, the
|
|
81
|
+
active limits and whether it is poisoned, never the sink or the directory
|
|
82
|
+
buffer's contents.
|
|
83
|
+
- `gedzip::Archive::total_size`, the sum of an opened archive's entries'
|
|
84
|
+
claimed decompressed sizes, read from the central directory alone — so a
|
|
85
|
+
caller can ask what extracting will cost before decompressing anything.
|
|
86
|
+
- Python and JavaScript/WASM bindings for both: `ArchiveWriter` (`new`,
|
|
87
|
+
`add`, `finish`) and `archive_total_size`. Both bindings write to an
|
|
88
|
+
in-memory `Vec<u8>` sink and copy it again when `finish` hands the bytes
|
|
89
|
+
to the host language, so — unlike the Rust API given a real sink such as
|
|
90
|
+
a file — they do not get the streaming memory benefit yet; their
|
|
91
|
+
docstrings say so.
|
|
92
|
+
|
|
93
|
+
### Fixed
|
|
94
|
+
|
|
95
|
+
Both entries below change `gedzip::write_archive`, which has shipped since
|
|
96
|
+
0.1.0. Everything under **Added** is new in this release and never shipped
|
|
97
|
+
broken; these two are what moves under an existing caller.
|
|
98
|
+
|
|
99
|
+
- **`write_archive` now sets general-purpose bit 11 (UTF-8 names)**, so a
|
|
100
|
+
non-ASCII path round-trips as itself instead of being read back as IBM
|
|
101
|
+
code page 437 mush (confirmed against Python 3.12 `zipfile` and Java 17
|
|
102
|
+
`ZipFile`; .NET's `ZipArchive` happened to decode the unflagged form
|
|
103
|
+
correctly, and 7-Zip guesses). Directory entries also now carry the MS-DOS
|
|
104
|
+
directory external attribute (`0x10`) instead of `0`. **This changes the
|
|
105
|
+
bytes `write_archive` emits**: on the same five-entry input, exactly
|
|
106
|
+
eleven bytes differ from 0.1.4 — the flags field on every local and
|
|
107
|
+
central record, and the external-attribute byte on each directory entry.
|
|
108
|
+
Versions, timestamps, CRCs, sizes, offsets and names are unchanged. No
|
|
109
|
+
fixture or test pinned the previous bytes.
|
|
110
|
+
- **`write_archive` now refuses one value earlier**, at the Zip64 sentinel
|
|
111
|
+
rather than past it. It rejected a count or size only once it *exceeded*
|
|
112
|
+
what a plain ZIP field holds, so it accepted a count of exactly 65,535
|
|
113
|
+
entries, or a size, compressed size, directory offset or directory size of
|
|
114
|
+
exactly 4,294,967,295 — but those values *are* the sentinels a reader
|
|
115
|
+
takes as "see the Zip64 record", which `write_archive` never writes. It
|
|
116
|
+
emitted the bare sentinel, and this crate's own `Archive::open` then
|
|
117
|
+
refused the result ("the archive needs a Zip64 directory and has none")
|
|
118
|
+
while Python, Java, 7-Zip and `bsdtar` accepted the broken archive.
|
|
119
|
+
**An input that produced a malformed archive in 0.1.4 is now an error**,
|
|
120
|
+
so a caller writing exactly 65,535 entries sees a refusal where it
|
|
121
|
+
previously saw a file. The design is unchanged — `write_archive` still
|
|
122
|
+
refuses rather than emit Zip64 — only the boundary moved from `>` the
|
|
123
|
+
sentinel to `>=` it, for the entry count and every 32-bit size and offset
|
|
124
|
+
field alike. Confirmed at 65,535 (refused), 65,534 and 4,294,967,294
|
|
125
|
+
(accepted and read back) against this crate's reader, Python 3.12, Java 17
|
|
126
|
+
`ZipFile` and `ZipInputStream`, 7-Zip 26.02, `bsdtar` and .NET's
|
|
127
|
+
`ZipArchive`.
|
|
128
|
+
|
|
129
|
+
## [0.1.4] - 2026-09-16
|
|
130
|
+
|
|
131
|
+
### Changed
|
|
132
|
+
|
|
133
|
+
- Migrated Cargo release publishing to crates.io Trusted Publishing through
|
|
134
|
+
GitLab OIDC, retaining the API token only as a transition fallback.
|
|
135
|
+
|
|
136
|
+
## [0.1.3] - 2026-09-16
|
|
137
|
+
|
|
138
|
+
### Changed
|
|
139
|
+
|
|
140
|
+
- Constrained PyPI Trusted Publishing to the protected `release` environment.
|
|
141
|
+
- Recorded the completed npm OIDC migration and the legacy token removal.
|
|
142
|
+
|
|
143
|
+
## [0.1.2] - 2026-09-16
|
|
144
|
+
|
|
145
|
+
### Changed
|
|
146
|
+
|
|
147
|
+
- Switched npm release publishing to GitLab OIDC Trusted Publishing.
|
|
148
|
+
- Documented the synchronized multi-registry release checklist.
|
|
149
|
+
|
|
150
|
+
## [0.1.1] - 2026-09-16
|
|
151
|
+
|
|
152
|
+
### Changed
|
|
153
|
+
|
|
154
|
+
- Synchronized the Rust core, Python binding, and JavaScript/WASM binding at
|
|
155
|
+
version 0.1.1 for the next registry release.
|
|
156
|
+
- Added protected-tag publishing for Cargo, PyPI, and npm, with clean
|
|
157
|
+
registry-install verification documented for all three packages.
|
|
158
|
+
|
|
159
|
+
## [0.1.0] - 2026-09-08
|
|
160
|
+
|
|
161
|
+
### Added
|
|
162
|
+
|
|
163
|
+
- Archival GEDCOM 5.5 through 7.x parsing, decoding, views, validation, and
|
|
164
|
+
reported version conversion.
|
|
165
|
+
- Bounded GEDZIP reading and writing.
|
|
166
|
+
- Python and JavaScript/WASM bindings over the same Rust core.
|
|
167
|
+
- Byte-exact vendored corpus, conformance, property, interoperability, and
|
|
168
|
+
adversarial test suites.
|
|
169
|
+
|
|
170
|
+
### Security
|
|
171
|
+
|
|
172
|
+
- Refuse traversal, platform-special, duplicate, and central/local-mismatched
|
|
173
|
+
GEDZIP paths before returning entry bytes.
|
|
174
|
+
- Stage and checksum external fixture downloads before making them visible.
|
|
175
|
+
- Reject line injection through programmatically constructed GEDCOM fields.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# was checked on crates.io, npm, and PyPI before the initial release.
|
|
4
4
|
[package]
|
|
5
5
|
name = "gedcomkit"
|
|
6
|
-
version = "0.1.
|
|
6
|
+
version = "0.1.6"
|
|
7
7
|
description = "A byte-preserving GEDCOM document model: decoding, parsing, readings, version conversion, plausibility checks, and the GEDZIP container, for GEDCOM 5.5 through 7.x."
|
|
8
8
|
edition = "2024"
|
|
9
9
|
# The true minimum, not the workspace's toolchain: a parser library is a leaf
|
|
@@ -203,9 +203,9 @@ than dropped.
|
|
|
203
203
|
|
|
204
204
|
## AI disclosure
|
|
205
205
|
|
|
206
|
-
This project was created with the help of AI — specifically
|
|
207
|
-
[
|
|
208
|
-
tests, CI configuration, and documentation, with design decisions and
|
|
206
|
+
This project was created with the help of AI — specifically Anthropic's
|
|
207
|
+
[Claude](https://claude.com/claude-code). That includes the library code,
|
|
208
|
+
bindings, tests, CI configuration, and documentation, with design decisions and
|
|
209
209
|
validation made by a human. See [`AGENTS.md`](AGENTS.md) for the conventions AI
|
|
210
210
|
contributors are expected to follow.
|
|
211
211
|
|
|
@@ -35,7 +35,7 @@ dependencies = [
|
|
|
35
35
|
|
|
36
36
|
[[package]]
|
|
37
37
|
name = "gedcomkit"
|
|
38
|
-
version = "0.1.
|
|
38
|
+
version = "0.1.6"
|
|
39
39
|
dependencies = [
|
|
40
40
|
"flate2",
|
|
41
41
|
"serde",
|
|
@@ -43,7 +43,7 @@ dependencies = [
|
|
|
43
43
|
|
|
44
44
|
[[package]]
|
|
45
45
|
name = "gedcomkit-py"
|
|
46
|
-
version = "0.1.
|
|
46
|
+
version = "0.1.6"
|
|
47
47
|
dependencies = [
|
|
48
48
|
"gedcomkit",
|
|
49
49
|
"pyo3",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# abi3 keeps it to one wheel per platform across Python versions.
|
|
3
3
|
[package]
|
|
4
4
|
name = "gedcomkit-py"
|
|
5
|
-
version = "0.1.
|
|
5
|
+
version = "0.1.6"
|
|
6
6
|
description = "Python bindings for gedcomkit: an archival-grade GEDCOM library — byte-preserving round-trip, encoding detection, GEDCOM 5.5 through 7.x, GEDZIP."
|
|
7
7
|
edition = "2024"
|
|
8
8
|
rust-version = "1.88"
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Type stubs for gedcomkit, an archival-grade GEDCOM library.
|
|
2
|
+
|
|
3
|
+
Views, findings and reports are plain dicts built from the core's JSON
|
|
4
|
+
serialization; their keys are camelCase, as the Rust types name them.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from os import PathLike
|
|
8
|
+
from typing import Any, TypedDict
|
|
9
|
+
|
|
10
|
+
from typing_extensions import NotRequired
|
|
11
|
+
|
|
12
|
+
__version__: str
|
|
13
|
+
|
|
14
|
+
class RecordSpec(TypedDict):
|
|
15
|
+
"""A structure to add: only ``tag`` is required, and any other key is refused."""
|
|
16
|
+
|
|
17
|
+
tag: str
|
|
18
|
+
xref: NotRequired[str | None]
|
|
19
|
+
value: NotRequired[str | None]
|
|
20
|
+
children: NotRequired[list[RecordSpec]]
|
|
21
|
+
|
|
22
|
+
class WrappedLine(TypedDict):
|
|
23
|
+
record: str
|
|
24
|
+
path: list[int]
|
|
25
|
+
tag: str
|
|
26
|
+
|
|
27
|
+
class Gedcom:
|
|
28
|
+
@staticmethod
|
|
29
|
+
def parse(data: bytes) -> Gedcom:
|
|
30
|
+
"""Read a document from a file's bytes; raises ValueError past the bounds."""
|
|
31
|
+
@staticmethod
|
|
32
|
+
def new_v551(source_system: str) -> Gedcom:
|
|
33
|
+
"""An empty GEDCOM 5.5.1 document naming its producing system, declaring UTF-8."""
|
|
34
|
+
@staticmethod
|
|
35
|
+
def new_v7() -> Gedcom:
|
|
36
|
+
"""An empty GEDCOM 7.0 document."""
|
|
37
|
+
@property
|
|
38
|
+
def encoding(self) -> str: ...
|
|
39
|
+
@property
|
|
40
|
+
def version(self) -> str | None: ...
|
|
41
|
+
@property
|
|
42
|
+
def content_records(self) -> int: ...
|
|
43
|
+
def records(self) -> list[dict[str, Any]]: ...
|
|
44
|
+
def record(self, xref: str) -> dict[str, Any]: ...
|
|
45
|
+
def individuals(self) -> list[dict[str, Any]]: ...
|
|
46
|
+
def families(self) -> list[dict[str, Any]]: ...
|
|
47
|
+
def validate(self) -> list[dict[str, Any]]: ...
|
|
48
|
+
def unresolved_pointers(self) -> list[dict[str, Any]]: ...
|
|
49
|
+
def parents_of(self, xref: str) -> list[str]: ...
|
|
50
|
+
def children_of(self, xref: str) -> list[str]: ...
|
|
51
|
+
def partners_of(self, xref: str) -> list[str]: ...
|
|
52
|
+
def append_records(self, records: list[RecordSpec]) -> None:
|
|
53
|
+
"""Add records before the trailer, all or none; raises ValueError."""
|
|
54
|
+
def append_structures(
|
|
55
|
+
self, record: str, path: list[int], structures: list[RecordSpec]
|
|
56
|
+
) -> None:
|
|
57
|
+
"""Add substructures under ``path`` in ``record`` (an xref, or "HEAD")."""
|
|
58
|
+
def wrap_long_lines(self, max_line_bytes: int = 255) -> list[WrappedLine]:
|
|
59
|
+
"""Split lines over the limit across CONC lines and name each one rewritten."""
|
|
60
|
+
def set_logical_value(self, xref: str, path: list[int], value: str) -> None: ...
|
|
61
|
+
def to_text(self) -> str: ...
|
|
62
|
+
def to_bytes(self) -> bytes: ...
|
|
63
|
+
def to_version7(self) -> tuple[Gedcom, list[dict[str, Any]]]: ...
|
|
64
|
+
def to_version551(self) -> tuple[Gedcom, list[dict[str, Any]]]: ...
|
|
65
|
+
def __len__(self) -> int: ...
|
|
66
|
+
|
|
67
|
+
class ArchiveWriter:
|
|
68
|
+
@staticmethod
|
|
69
|
+
def new() -> ArchiveWriter: ...
|
|
70
|
+
def add(self, name: str, data: bytes) -> None: ...
|
|
71
|
+
def finish(self) -> bytes: ...
|
|
72
|
+
|
|
73
|
+
class ArchiveFileWriter:
|
|
74
|
+
"""A GEDZIP archive written straight to a file, one entry at a time."""
|
|
75
|
+
|
|
76
|
+
def __init__(self, path: str | PathLike[str]) -> None: ...
|
|
77
|
+
def add(self, name: str, data: bytes) -> None: ...
|
|
78
|
+
def add_file(self, name: str, source: str | PathLike[str]) -> None: ...
|
|
79
|
+
def finish(self) -> int:
|
|
80
|
+
"""Close the archive and return its size in bytes."""
|
|
81
|
+
|
|
82
|
+
def archive_total_size(data: bytes) -> int: ...
|
|
83
|
+
def parse_date(text: str) -> dict[str, Any]:
|
|
84
|
+
"""A date reading; its ``gedcom551`` key is the 5.5.1 spelling, or None."""
|