@echecs/pgn 3.4.0 → 3.5.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/CHANGELOG.md CHANGED
@@ -7,3 +7,131 @@ and this project adheres to
7
7
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
9
  ## [Unreleased]
10
+
11
+ ## [3.5.1] - 2026-03-14
12
+
13
+ ### Changed
14
+
15
+ - README: document `stream()` API with signature and Node.js usage example
16
+ - README: update type names (`Moves` → `MoveList`) and clarify `Move.from`
17
+ disambiguation and move tuple slot semantics
18
+ - Updated benchmark results for v3.5.0 SAN rule restructure
19
+
20
+ ## [3.5.0] - 2026-03-14
21
+
22
+ ### Added
23
+
24
+ - `stream(input: AsyncIterable<string>): AsyncGenerator<PGN>` — new named export
25
+ for incremental, memory-efficient parsing of large PGN databases
26
+
27
+ ### Changed
28
+
29
+ - `Move.from` widened from `File | Rank` to `Disambiguation`
30
+ (`Square | File | Rank`) to correctly type fully-disambiguated moves (e.g.
31
+ `Qd1xe4` → `from: "d1"`)
32
+ - `type Moves` renamed to `MoveList`; new
33
+ `MovePair = [number, Move | undefined, Move?]` tuple
34
+ - `type Variation` simplified to `MoveList[]`
35
+
36
+ ### Performance
37
+
38
+ - Restructured `SAN` grammar rule to eliminate post-match regex on every move;
39
+ closes remaining ~1.1–1.2x gap vs `pgn-parser` on move-heavy fixtures
40
+
41
+ ## [3.4.0] - 2026-02-21
42
+
43
+ ### Changed
44
+
45
+ - Rewrote README following `@echecs/elo` library style with badges, Why, Quick
46
+ Start, Usage, and Contributing sections
47
+ - Updated AGENTS.md to reflect Peggy migration and remove stale nearley/moo
48
+ references
49
+
50
+ ### Added
51
+
52
+ - Features section in README highlighting RAV and NAG support with a parser
53
+ comparison table
54
+ - Performance section in README with benchmark results table
55
+ - Codecov badge to README
56
+
57
+ ### Removed
58
+
59
+ - `docs.yml` workflow (no hosted docs in this project)
60
+
61
+ ## [3.3.0] - 2026-02-21
62
+
63
+ ### Added
64
+
65
+ - Peggy PEG parser replacing nearley/moo for O(n) linear-time parsing —
66
+ delivering up to 10× throughput improvement on large PGN files
67
+ - Comparative benchmark (`comparison.bench.ts`) measuring `@echecs/pgn` against
68
+ `@mliebelt/pgn-parser` and `chess.js`
69
+
70
+ ### Performance
71
+
72
+ - Replaced `pickBy` with direct property assignment in SAN action block,
73
+ reducing allocations per move
74
+ - Added length-check guards before NAG and comment processing in MOVE action,
75
+ skipping unnecessary work for moves without annotations
76
+ - Removed `delete` mutations and reduced allocations in `pairMoves`, avoiding V8
77
+ hidden-class transitions
78
+
79
+ ### Removed
80
+
81
+ - Stale `tokenizer.ts` debug script
82
+
83
+ ## [3.2.1] - 2026-02-20
84
+
85
+ ### Fixed
86
+
87
+ - Sort `multiGameFixtures` keys in comparison benchmark to satisfy the
88
+ `sort-keys` lint rule
89
+
90
+ ## [3.2.0] - 2026-02-20
91
+
92
+ ### Added
93
+
94
+ - Comparative PGN parser benchmark (`comparison.bench.ts`) for cross-library
95
+ performance tracking
96
+
97
+ ### Performance
98
+
99
+ - Reduced Earley parser overhead via grammar and caching optimizations
100
+
101
+ ## [3.1.3] - 2025-03-27
102
+
103
+ ### Fixed
104
+
105
+ - Removed accidental production dependency introduced in 3.1.2
106
+
107
+ ## [3.1.2] - 2025-03-01
108
+
109
+ ### Fixed
110
+
111
+ - Increased per-test timeout to accommodate `long.pgn` (~3 500 games) on slow CI
112
+ runners
113
+
114
+ ## [3.1.1] - 2025-03-01
115
+
116
+ ### Fixed
117
+
118
+ - Corrected `.js` extension on relative imports in test files (NodeNext
119
+ resolution)
120
+
121
+ ## [3.1.0] - 2025-03-01
122
+
123
+ ### Added
124
+
125
+ - moo tokenizer for faster lexing
126
+ - New grammar supporting the full PGN specification including RAV (recursive
127
+ annotated variations) and NAG (numeric annotation glyphs)
128
+
129
+ [unreleased]: https://github.com/mormubis/pgn/compare/v3.4.0...HEAD
130
+ [3.4.0]: https://github.com/mormubis/pgn/compare/v3.3.0...v3.4.0
131
+ [3.3.0]: https://github.com/mormubis/pgn/compare/v3.2.1...v3.3.0
132
+ [3.2.1]: https://github.com/mormubis/pgn/compare/v3.2.0...v3.2.1
133
+ [3.2.0]: https://github.com/mormubis/pgn/compare/v3.1.3...v3.2.0
134
+ [3.1.3]: https://github.com/mormubis/pgn/compare/v3.1.2...v3.1.3
135
+ [3.1.2]: https://github.com/mormubis/pgn/compare/v3.1.1...v3.1.2
136
+ [3.1.1]: https://github.com/mormubis/pgn/compare/v3.1.0...v3.1.1
137
+ [3.1.0]: https://github.com/mormubis/pgn/releases/tag/v3.1.0
package/README.md CHANGED
@@ -31,8 +31,9 @@ opening book, or game viewer, you need more:
31
31
  - **NAG support** — symbolic (`!`, `?`, `!!`, `??`, `!?`, `?!`) and numeric
32
32
  (`$1`–`$255`) annotations are surfaced as an `annotations` array. Essential
33
33
  for Lichess and ChessBase exports.
34
- - **Multi-game files** — parse entire PGN databases in one call. Tested on files
35
- with 3 500+ games.
34
+ - **Multi-game files** — parse entire PGN databases in one call, or stream them
35
+ game-by-game with `stream()` for memory-efficient processing of large files.
36
+ Tested on files with 3 500+ games.
36
37
  - **Fast** — built on a [Peggy](https://peggyjs.org/) PEG parser. Throughput is
37
38
  within 1.1–1.2x of the fastest parsers on npm, which do far less work per move
38
39
  (see [BENCHMARK_RESULTS.md](./BENCHMARK_RESULTS.md)).
@@ -67,19 +68,41 @@ console.log(games[0].moves[0]);
67
68
 
68
69
  ## Usage
69
70
 
70
- `parse()` takes a PGN string and returns an array of game objects — one per game
71
- in the file.
71
+ ### `parse()`
72
+
73
+ Takes a PGN string and returns an array of game objects — one per game in the
74
+ file.
72
75
 
73
76
  ```typescript
74
77
  parse(input: string): PGN[]
75
78
  ```
76
79
 
80
+ ### `stream()`
81
+
82
+ Takes any `AsyncIterable<string>` and yields one `PGN` object per game. Memory
83
+ usage stays proportional to one game at a time, making it suitable for large
84
+ databases read from disk or a network stream.
85
+
86
+ ```typescript
87
+ stream(input: AsyncIterable<string>): AsyncGenerator<PGN>
88
+ ```
89
+
90
+ ```typescript
91
+ import { createReadStream } from 'node:fs';
92
+ import { stream } from '@echecs/pgn';
93
+
94
+ const chunks = createReadStream('database.pgn', { encoding: 'utf8' });
95
+ for await (const game of stream(chunks)) {
96
+ console.log(game.meta.White, 'vs', game.meta.Black);
97
+ }
98
+ ```
99
+
77
100
  ### PGN object
78
101
 
79
102
  ```typescript
80
103
  {
81
- meta: Meta, // tag pairs (Event, Site, Date, White, Black, …)
82
- moves: Moves, // paired move list
104
+ meta: Meta, // tag pairs (Event, Site, Date, White, Black, …)
105
+ moves: MoveList, // paired move list
83
106
  result: 1 | 0 | 0.5 | '?'
84
107
  }
85
108
  ```
@@ -90,7 +113,7 @@ parse(input: string): PGN[]
90
113
  {
91
114
  piece: 'P' | 'R' | 'N' | 'B' | 'Q' | 'K', // always present
92
115
  to: string, // destination square, e.g. "e4"
93
- from?: string, // disambiguation, e.g. "e" or "e2"
116
+ from?: string, // disambiguation: file "e", rank "2", or square "e2"
94
117
  capture?: true,
95
118
  castling?: true,
96
119
  check?: true,
@@ -98,12 +121,13 @@ parse(input: string): PGN[]
98
121
  promotion?: 'R' | 'N' | 'B' | 'Q',
99
122
  annotations?: string[], // e.g. ["!", "$14"]
100
123
  comment?: string,
101
- variants?: Moves[], // recursive annotation variations
124
+ variants?: MoveList[], // recursive annotation variations
102
125
  }
103
126
  ```
104
127
 
105
- Moves are grouped into tuples: `[moveNumber, whiteMove, blackMove]`. If the last
106
- move of a game or variation was made by white, `blackMove` is `undefined`.
128
+ Moves are grouped into tuples: `[moveNumber, whiteMove, blackMove]`. Both move
129
+ slots can be `undefined` `whiteMove` when a variation begins on black's turn,
130
+ `blackMove` when the game or variation ends on white's move.
107
131
 
108
132
  ### Annotations and comments
109
133