pgn-manager 1.0.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/dist/index.d.ts +116 -9
- package/dist/index.js +219 -9
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -6,7 +6,6 @@ A powerful TypeScript/JavaScript library for managing chess PGN (Portable Game N
|
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](https://www.typescriptlang.org/)
|
|
8
8
|
[](https://www.npmjs.com/package/pgn-manager)
|
|
9
|
-
[](https://coveralls.io/github/username/pgn-manager?branch=main)
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
## Features ✨
|
|
@@ -58,14 +57,15 @@ const headers = manager.headers;
|
|
|
58
57
|
|
|
59
58
|
### Methods
|
|
60
59
|
- `getMove(moveNumber: number)`: Get move by number
|
|
61
|
-
- `getMoveNumber(
|
|
62
|
-
- `nextMove(
|
|
63
|
-
- `previousMove(
|
|
64
|
-
- `hasNextMove(
|
|
60
|
+
- `getMoveNumber(moveOrMoveId: Move | number)`: Get number for a move
|
|
61
|
+
- `nextMove(moveOrMoveId: Move | number)`: Get next move in the sequence
|
|
62
|
+
- `previousMove(moveOrMoveId: Move | number)`: Get previous move
|
|
63
|
+
- `hasNextMove(moveOrMoveId: Move | number)`: Check if move has a next move
|
|
65
64
|
- `getFirstMove()`: Get the first move of the game
|
|
66
65
|
- `getLastMove()`: Get the last move of the game
|
|
67
|
-
- `getMoveFen(
|
|
68
|
-
- `getParentRav(
|
|
66
|
+
- `getMoveFen(moveOrMoveId: Move | number)`: Get FEN position after move
|
|
67
|
+
- `getParentRav(moveOrMoveId: Move | number)`: Get parent variation for move
|
|
68
|
+
- `getMoveColor(moveOrMoveId: Move | number)`: Gets the color of the player who made the move ("w" for white or "b" for black)
|
|
69
69
|
|
|
70
70
|
## Examples 🎯
|
|
71
71
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,27 +1,134 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ShortMove } from "chess.js";
|
|
2
|
+
import * as pgnParser from "pgn-parser";
|
|
3
|
+
import type { ParsedPGN, Move, Rav, Header, Result } from "pgn-parser";
|
|
2
4
|
export declare const FEN_START_POSITION = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
3
5
|
export declare const FEN_EMPTY_POSITION = "8/8/8/8/8/8/8/8";
|
|
4
6
|
declare class PGNManager {
|
|
7
|
+
/** The raw PGN string input */
|
|
5
8
|
private rawPGN;
|
|
9
|
+
/** The parsed PGN game object */
|
|
6
10
|
private game;
|
|
11
|
+
/** Array of moves in traversal order */
|
|
7
12
|
private sortedMoves;
|
|
13
|
+
/** Map of moves to their FEN position strings */
|
|
8
14
|
private moveFen;
|
|
15
|
+
/** Map of moves to their parent variations (or null for mainline) */
|
|
9
16
|
private moveParent;
|
|
17
|
+
/** Map of variations to their parent moves */
|
|
10
18
|
private ravParent;
|
|
19
|
+
/** Map of moves to the color of the player who made the move */
|
|
20
|
+
private moveColor;
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new PGNManager instance
|
|
23
|
+
* @param pgn - The PGN string to parse and manage
|
|
24
|
+
*/
|
|
11
25
|
constructor(pgn: string);
|
|
26
|
+
/**
|
|
27
|
+
* Initializes the game traversal starting from the initial position
|
|
28
|
+
* @param game - The parsed PGN game object
|
|
29
|
+
*/
|
|
12
30
|
private dfOnGame;
|
|
31
|
+
/**
|
|
32
|
+
* Performs depth-first traversal of the game moves and variations
|
|
33
|
+
* @param move - The current move being processed
|
|
34
|
+
* @param parent - The parent RAV (variation) containing the move
|
|
35
|
+
* @param chessGame - The chess instance for the current position
|
|
36
|
+
*/
|
|
13
37
|
private dfsOnGame;
|
|
38
|
+
/**
|
|
39
|
+
* Gets the raw PGN string
|
|
40
|
+
* @returns The original PGN string
|
|
41
|
+
*/
|
|
14
42
|
get pgn(): string;
|
|
43
|
+
/**
|
|
44
|
+
* Gets the parsed PGN object
|
|
45
|
+
* @returns The parsed PGN game object
|
|
46
|
+
*/
|
|
15
47
|
get parsedPGN(): ParsedPGN;
|
|
48
|
+
/**
|
|
49
|
+
* Gets the game headers
|
|
50
|
+
* @returns Array of game headers
|
|
51
|
+
*/
|
|
16
52
|
get headers(): Array<Header>;
|
|
17
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Gets a move by its number in the sequence
|
|
55
|
+
* @param moveNumber - The 1-based index of the move
|
|
56
|
+
* @returns The move object at the specified position
|
|
57
|
+
*/
|
|
58
|
+
getMove: (moveNumber: number) => pgnParser.Move;
|
|
59
|
+
/**
|
|
60
|
+
* Gets the number of a move in the sequence
|
|
61
|
+
* @param move - The move object
|
|
62
|
+
* @returns The 1-based index of the move
|
|
63
|
+
*/
|
|
18
64
|
getMoveNumber: (move: Move) => number;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Gets the next move in the sequence
|
|
67
|
+
* @param moveOrId - The current move object or move number
|
|
68
|
+
* @returns The next move in the sequence
|
|
69
|
+
* @throws Error if there are no moves in the game
|
|
70
|
+
*/
|
|
71
|
+
nextMove: (moveOrId: Move | number | undefined) => Move;
|
|
72
|
+
/**
|
|
73
|
+
* Checks if there is a next move available
|
|
74
|
+
* @param moveOrId - The current move object or move number
|
|
75
|
+
* @returns True if there is a next move, false otherwise
|
|
76
|
+
*/
|
|
77
|
+
hasNextMove: (moveOrId: Move | number) => boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Gets the previous move in the sequence
|
|
80
|
+
* @param moveOrId - The current move object or move number
|
|
81
|
+
* @returns The previous move or undefined if at the start
|
|
82
|
+
* @throws Error if there are no moves or if the move parameter is invalid
|
|
83
|
+
*/
|
|
84
|
+
previousMove: (moveOrId: Move | number) => Move | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Gets the first move in the game
|
|
87
|
+
* @returns The first move
|
|
88
|
+
* @throws Error if there are no moves in the game
|
|
89
|
+
*/
|
|
90
|
+
getFirstMove: () => pgnParser.Move;
|
|
91
|
+
/**
|
|
92
|
+
* Gets the last move in the game
|
|
93
|
+
* @returns The last move
|
|
94
|
+
* @throws Error if there are no moves in the game
|
|
95
|
+
*/
|
|
96
|
+
getLastMove: () => pgnParser.Move;
|
|
97
|
+
/**
|
|
98
|
+
* Gets the FEN string for a specific move
|
|
99
|
+
* @param moveOrId - The move object or move number
|
|
100
|
+
* @returns The FEN string representing the position after the move
|
|
101
|
+
* @throws Error if the move parameter is invalid
|
|
102
|
+
*/
|
|
103
|
+
getMoveFen: (moveOrId: Move | number) => string;
|
|
104
|
+
/**
|
|
105
|
+
* Gets the parent RAV (variation) for a move
|
|
106
|
+
* @param moveOrId - The move object or move number
|
|
107
|
+
* @returns The parent RAV or null if the move is in the main line
|
|
108
|
+
* @throws Error if the move parameter is invalid
|
|
109
|
+
*/
|
|
110
|
+
getParentRav: (moveOrId: Move | number) => Rav | null;
|
|
111
|
+
/**
|
|
112
|
+
* Gets the color of the player who made the move
|
|
113
|
+
* @param moveOrId - The move object or move ID number
|
|
114
|
+
* @returns "w" for white or "b" for black
|
|
115
|
+
* @throws Error if the move parameter is invalid
|
|
116
|
+
*/
|
|
117
|
+
getMoveColor: (moveOrId: Move | number) => "w" | "b";
|
|
118
|
+
/***
|
|
119
|
+
* Pushes a new move into the game
|
|
120
|
+
* @param moveId - The ID of the move to push
|
|
121
|
+
* @param newMove - The move object to add
|
|
122
|
+
* @param result - The result of the game after this move (default is "*")
|
|
123
|
+
* @returns The newly created move object
|
|
124
|
+
* @throws Error if the move parameter is invalid
|
|
125
|
+
*/
|
|
126
|
+
pushMove: (moveId: number, newMove: ShortMove, result?: Result) => Move;
|
|
127
|
+
/**
|
|
128
|
+
* Delete a move and all subsequent moves in its variation from the game
|
|
129
|
+
* @param moveId - The ID of the move to delete from
|
|
130
|
+
* @throws Error if the move parameter is invalid
|
|
131
|
+
*/
|
|
132
|
+
deleteMove: (moveId: number) => void;
|
|
26
133
|
}
|
|
27
134
|
export default PGNManager;
|
package/dist/index.js
CHANGED
|
@@ -3,25 +3,43 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.FEN_EMPTY_POSITION = exports.FEN_START_POSITION = void 0;
|
|
4
4
|
const ChessJS = require("chess.js");
|
|
5
5
|
const Chess = typeof ChessJS === "function" ? ChessJS : ChessJS.Chess;
|
|
6
|
-
const
|
|
6
|
+
const pgnParser = require("pgn-parser");
|
|
7
|
+
const utils_1 = require("./utils");
|
|
7
8
|
exports.FEN_START_POSITION = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
|
8
9
|
exports.FEN_EMPTY_POSITION = "8/8/8/8/8/8/8/8";
|
|
9
10
|
class PGNManager {
|
|
11
|
+
/** The raw PGN string input */
|
|
10
12
|
rawPGN;
|
|
13
|
+
/** The parsed PGN game object */
|
|
11
14
|
game;
|
|
15
|
+
/** Array of moves in traversal order */
|
|
12
16
|
sortedMoves;
|
|
17
|
+
/** Map of moves to their FEN position strings */
|
|
13
18
|
moveFen;
|
|
19
|
+
/** Map of moves to their parent variations (or null for mainline) */
|
|
14
20
|
moveParent;
|
|
21
|
+
/** Map of variations to their parent moves */
|
|
15
22
|
ravParent;
|
|
23
|
+
/** Map of moves to the color of the player who made the move */
|
|
24
|
+
moveColor;
|
|
25
|
+
/**
|
|
26
|
+
* Creates a new PGNManager instance
|
|
27
|
+
* @param pgn - The PGN string to parse and manage
|
|
28
|
+
*/
|
|
16
29
|
constructor(pgn) {
|
|
17
30
|
this.rawPGN = pgn;
|
|
18
|
-
this.game =
|
|
31
|
+
this.game = pgnParser.parse(pgn + " *")[0];
|
|
19
32
|
this.sortedMoves = [];
|
|
20
33
|
this.moveParent = new Map();
|
|
21
34
|
this.ravParent = new Map();
|
|
22
35
|
this.moveFen = new Map();
|
|
36
|
+
this.moveColor = new Map();
|
|
23
37
|
this.dfOnGame(this.game);
|
|
24
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Initializes the game traversal starting from the initial position
|
|
41
|
+
* @param game - The parsed PGN game object
|
|
42
|
+
*/
|
|
25
43
|
dfOnGame = (game) => {
|
|
26
44
|
this.sortedMoves = [];
|
|
27
45
|
var chessGame = new Chess(exports.FEN_START_POSITION);
|
|
@@ -29,6 +47,12 @@ class PGNManager {
|
|
|
29
47
|
this.dfsOnGame(move, game, chessGame);
|
|
30
48
|
}
|
|
31
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* Performs depth-first traversal of the game moves and variations
|
|
52
|
+
* @param move - The current move being processed
|
|
53
|
+
* @param parent - The parent RAV (variation) containing the move
|
|
54
|
+
* @param chessGame - The chess instance for the current position
|
|
55
|
+
*/
|
|
32
56
|
dfsOnGame = (move, parent, chessGame) => {
|
|
33
57
|
this.sortedMoves.push(move);
|
|
34
58
|
this.moveParent.set(move, parent);
|
|
@@ -46,26 +70,62 @@ class PGNManager {
|
|
|
46
70
|
!chessGame.move(move.move, { sloppy: true }))
|
|
47
71
|
console.log("Invalid move: " + move.move);
|
|
48
72
|
this.moveFen.set(move, chessGame.fen());
|
|
73
|
+
this.moveColor.set(move, chessGame.turn() === "w" ? "b" : "w");
|
|
49
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* Gets the raw PGN string
|
|
77
|
+
* @returns The original PGN string
|
|
78
|
+
*/
|
|
50
79
|
get pgn() {
|
|
51
80
|
return this.rawPGN;
|
|
52
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Gets the parsed PGN object
|
|
84
|
+
* @returns The parsed PGN game object
|
|
85
|
+
*/
|
|
53
86
|
get parsedPGN() {
|
|
54
87
|
return this.game;
|
|
55
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Gets the game headers
|
|
91
|
+
* @returns Array of game headers
|
|
92
|
+
*/
|
|
56
93
|
get headers() {
|
|
57
94
|
if (!this.game || !this.game.headers)
|
|
58
95
|
return [];
|
|
59
96
|
return this.game.headers;
|
|
60
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Gets a move by its number in the sequence
|
|
100
|
+
* @param moveNumber - The 1-based index of the move
|
|
101
|
+
* @returns The move object at the specified position
|
|
102
|
+
*/
|
|
61
103
|
getMove = (moveNumber) => {
|
|
62
104
|
let move = this.sortedMoves[moveNumber - 1];
|
|
63
105
|
return move;
|
|
64
106
|
};
|
|
107
|
+
/**
|
|
108
|
+
* Gets the number of a move in the sequence
|
|
109
|
+
* @param move - The move object
|
|
110
|
+
* @returns The 1-based index of the move
|
|
111
|
+
*/
|
|
65
112
|
getMoveNumber = (move) => {
|
|
66
113
|
return this.sortedMoves.indexOf(move) + 1;
|
|
67
114
|
};
|
|
68
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Gets the next move in the sequence
|
|
117
|
+
* @param moveOrId - The current move object or move number
|
|
118
|
+
* @returns The next move in the sequence
|
|
119
|
+
* @throws Error if there are no moves in the game
|
|
120
|
+
*/
|
|
121
|
+
nextMove = (moveOrId) => {
|
|
122
|
+
let move;
|
|
123
|
+
if (typeof moveOrId === "number") {
|
|
124
|
+
move = this.getMove(moveOrId);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
move = moveOrId;
|
|
128
|
+
}
|
|
69
129
|
if (!move) {
|
|
70
130
|
if (this.sortedMoves.length == 0) {
|
|
71
131
|
throw Error("No moves in game");
|
|
@@ -92,10 +152,23 @@ class PGNManager {
|
|
|
92
152
|
}
|
|
93
153
|
return tempNextMove;
|
|
94
154
|
};
|
|
95
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Checks if there is a next move available
|
|
157
|
+
* @param moveOrId - The current move object or move number
|
|
158
|
+
* @returns True if there is a next move, false otherwise
|
|
159
|
+
*/
|
|
160
|
+
hasNextMove = (moveOrId) => {
|
|
161
|
+
const move = typeof moveOrId === "number" ? this.getMove(moveOrId) : moveOrId;
|
|
96
162
|
return !move || this.nextMove(move) !== move;
|
|
97
163
|
};
|
|
98
|
-
|
|
164
|
+
/**
|
|
165
|
+
* Gets the previous move in the sequence
|
|
166
|
+
* @param moveOrId - The current move object or move number
|
|
167
|
+
* @returns The previous move or undefined if at the start
|
|
168
|
+
* @throws Error if there are no moves or if the move parameter is invalid
|
|
169
|
+
*/
|
|
170
|
+
previousMove = (moveOrId) => {
|
|
171
|
+
const move = typeof moveOrId === "number" ? this.getMove(moveOrId) : moveOrId;
|
|
99
172
|
if (!move) {
|
|
100
173
|
if (this.sortedMoves.length == 0) {
|
|
101
174
|
throw Error("No moves in game");
|
|
@@ -122,31 +195,168 @@ class PGNManager {
|
|
|
122
195
|
}
|
|
123
196
|
return tempPrevMove;
|
|
124
197
|
};
|
|
198
|
+
/**
|
|
199
|
+
* Gets the first move in the game
|
|
200
|
+
* @returns The first move
|
|
201
|
+
* @throws Error if there are no moves in the game
|
|
202
|
+
*/
|
|
125
203
|
getFirstMove = () => {
|
|
126
204
|
if (this.sortedMoves.length == 0) {
|
|
127
205
|
throw Error("No moves in game");
|
|
128
206
|
}
|
|
129
207
|
return this.sortedMoves[0];
|
|
130
208
|
};
|
|
209
|
+
/**
|
|
210
|
+
* Gets the last move in the game
|
|
211
|
+
* @returns The last move
|
|
212
|
+
* @throws Error if there are no moves in the game
|
|
213
|
+
*/
|
|
131
214
|
getLastMove = () => {
|
|
132
215
|
if (this.sortedMoves.length == 0) {
|
|
133
216
|
throw Error("No moves in game");
|
|
134
217
|
}
|
|
135
218
|
return this.game.moves[this.game.moves.length - 1];
|
|
136
219
|
};
|
|
137
|
-
|
|
138
|
-
|
|
220
|
+
/**
|
|
221
|
+
* Gets the FEN string for a specific move
|
|
222
|
+
* @param moveOrId - The move object or move number
|
|
223
|
+
* @returns The FEN string representing the position after the move
|
|
224
|
+
* @throws Error if the move parameter is invalid
|
|
225
|
+
*/
|
|
226
|
+
getMoveFen = (moveOrId) => {
|
|
227
|
+
const move = typeof moveOrId === "number" ? this.getMove(moveOrId) : moveOrId;
|
|
228
|
+
if (!move || !this.moveFen.has(move)) {
|
|
139
229
|
throw Error("Invalid 'move' parameter while getting fen");
|
|
140
230
|
}
|
|
141
231
|
let moveFen = this.moveFen.get(move);
|
|
142
232
|
return moveFen ? moveFen : exports.FEN_EMPTY_POSITION;
|
|
143
233
|
};
|
|
144
|
-
|
|
145
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Gets the parent RAV (variation) for a move
|
|
236
|
+
* @param moveOrId - The move object or move number
|
|
237
|
+
* @returns The parent RAV or null if the move is in the main line
|
|
238
|
+
* @throws Error if the move parameter is invalid
|
|
239
|
+
*/
|
|
240
|
+
getParentRav = (moveOrId) => {
|
|
241
|
+
const move = typeof moveOrId === "number" ? this.getMove(moveOrId) : moveOrId;
|
|
242
|
+
if (!move || !this.moveParent.has(move)) {
|
|
146
243
|
throw Error("Invalid 'move' parameter while getting parent rav");
|
|
147
244
|
}
|
|
148
245
|
let parentRav = this.moveParent.get(move);
|
|
149
246
|
return parentRav ? parentRav : null;
|
|
150
247
|
};
|
|
248
|
+
/**
|
|
249
|
+
* Gets the color of the player who made the move
|
|
250
|
+
* @param moveOrId - The move object or move ID number
|
|
251
|
+
* @returns "w" for white or "b" for black
|
|
252
|
+
* @throws Error if the move parameter is invalid
|
|
253
|
+
*/
|
|
254
|
+
getMoveColor = (moveOrId) => {
|
|
255
|
+
const move = typeof moveOrId === "number" ? this.getMove(moveOrId) : moveOrId;
|
|
256
|
+
if (!move || !this.moveColor.has(move)) {
|
|
257
|
+
throw Error("Invalid 'move' parameter while getting move color");
|
|
258
|
+
}
|
|
259
|
+
return this.moveColor.get(move);
|
|
260
|
+
};
|
|
261
|
+
/***
|
|
262
|
+
* Pushes a new move into the game
|
|
263
|
+
* @param moveId - The ID of the move to push
|
|
264
|
+
* @param newMove - The move object to add
|
|
265
|
+
* @param result - The result of the game after this move (default is "*")
|
|
266
|
+
* @returns The newly created move object
|
|
267
|
+
* @throws Error if the move parameter is invalid
|
|
268
|
+
*/
|
|
269
|
+
pushMove = (moveId, newMove, result = "*") => {
|
|
270
|
+
const currentMove = this.getMove(moveId);
|
|
271
|
+
// check if it's a valid move
|
|
272
|
+
const chess = new Chess(this.getMoveFen(currentMove));
|
|
273
|
+
if (!chess.move(newMove)) {
|
|
274
|
+
throw Error("Invalid move");
|
|
275
|
+
}
|
|
276
|
+
// check if this is a new variation
|
|
277
|
+
let isNewVariation = false;
|
|
278
|
+
const parentRav = this.getParentRav(currentMove);
|
|
279
|
+
if (parentRav.moves[parentRav.moves.length - 1] != currentMove) {
|
|
280
|
+
isNewVariation = true;
|
|
281
|
+
}
|
|
282
|
+
// add the move to the game
|
|
283
|
+
let move = undefined;
|
|
284
|
+
if (isNewVariation) {
|
|
285
|
+
move = {
|
|
286
|
+
move: chess.history().slice(-1)[0],
|
|
287
|
+
ravs: undefined,
|
|
288
|
+
move_number: currentMove.move_number,
|
|
289
|
+
comments: [],
|
|
290
|
+
};
|
|
291
|
+
const newVar = {
|
|
292
|
+
moves: [move],
|
|
293
|
+
result,
|
|
294
|
+
};
|
|
295
|
+
currentMove.ravs.push(newVar);
|
|
296
|
+
// update class variables
|
|
297
|
+
this.moveParent.set(move, newVar);
|
|
298
|
+
this.ravParent.set(newVar, currentMove);
|
|
299
|
+
this.moveFen.set(move, chess.fen());
|
|
300
|
+
this.moveColor.set(move, this.getMoveColor(currentMove));
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
move = {
|
|
304
|
+
move: chess.history().slice(-1)[0],
|
|
305
|
+
ravs: undefined,
|
|
306
|
+
move_number: this.getMoveColor(currentMove) === "w"
|
|
307
|
+
? undefined
|
|
308
|
+
: currentMove.move_number + 1,
|
|
309
|
+
comments: [],
|
|
310
|
+
};
|
|
311
|
+
parentRav.moves.push(move);
|
|
312
|
+
// update class variables
|
|
313
|
+
this.moveParent.set(move, parentRav);
|
|
314
|
+
this.moveFen.set(move, chess.fen());
|
|
315
|
+
this.moveColor.set(move, this.getMoveColor(currentMove) === "w" ? "b" : "w");
|
|
316
|
+
}
|
|
317
|
+
this.rawPGN = (0, utils_1.regeneratePGN)(this.game, this.moveColor);
|
|
318
|
+
this.dfOnGame(this.game);
|
|
319
|
+
return move;
|
|
320
|
+
};
|
|
321
|
+
/**
|
|
322
|
+
* Delete a move and all subsequent moves in its variation from the game
|
|
323
|
+
* @param moveId - The ID of the move to delete from
|
|
324
|
+
* @throws Error if the move parameter is invalid
|
|
325
|
+
*/
|
|
326
|
+
deleteMove = (moveId) => {
|
|
327
|
+
const move = this.getMove(moveId);
|
|
328
|
+
if (!move) {
|
|
329
|
+
throw Error("Invalid move");
|
|
330
|
+
}
|
|
331
|
+
// delete the move and subsequent moves from the game
|
|
332
|
+
const parentRav = this.getParentRav(move);
|
|
333
|
+
const index = parentRav.moves.indexOf(move);
|
|
334
|
+
const deletedMoves = parentRav.moves.splice(index);
|
|
335
|
+
// collect all moves and variations that need cleanup
|
|
336
|
+
const movsToClean = [];
|
|
337
|
+
const ravsToClean = [];
|
|
338
|
+
for (const deletedMove of deletedMoves) {
|
|
339
|
+
movsToClean.push(deletedMove);
|
|
340
|
+
if (deletedMove.ravs) {
|
|
341
|
+
for (const rav of deletedMove.ravs) {
|
|
342
|
+
ravsToClean.push(rav);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
// Sort moves by their moveId in decreasing order
|
|
347
|
+
movsToClean.sort((a, b) => this.getMoveNumber(b) - this.getMoveNumber(a));
|
|
348
|
+
// clean up all maps at once
|
|
349
|
+
movsToClean.forEach((move) => {
|
|
350
|
+
this.moveParent.delete(move);
|
|
351
|
+
this.moveFen.delete(move);
|
|
352
|
+
this.moveColor.delete(move);
|
|
353
|
+
});
|
|
354
|
+
ravsToClean.forEach((rav) => {
|
|
355
|
+
this.ravParent.delete(rav);
|
|
356
|
+
});
|
|
357
|
+
// update the PGN and rebuild internal state
|
|
358
|
+
this.rawPGN = (0, utils_1.regeneratePGN)(this.game, this.moveColor);
|
|
359
|
+
this.dfOnGame(this.game);
|
|
360
|
+
};
|
|
151
361
|
}
|
|
152
362
|
exports.default = PGNManager;
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pgn-manager",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Libraray built on top of chess.js and pgn-parser to load and process PGN files in typescript.",
|
|
5
5
|
"main": "dist/index",
|
|
6
6
|
"typings": "dist/index",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"test": "
|
|
8
|
+
"test": "jest",
|
|
9
|
+
"test:watch": "jest --watch",
|
|
10
|
+
"test:coverage": "jest --coverage",
|
|
9
11
|
"prepublishOnly": "npm run compile",
|
|
10
12
|
"compile": "npm run clean && tsc -p .",
|
|
11
13
|
"watch": "tsc -w -p .",
|
|
@@ -31,7 +33,12 @@
|
|
|
31
33
|
"pgn-parser": "2.1.0"
|
|
32
34
|
},
|
|
33
35
|
"devDependencies": {
|
|
34
|
-
"
|
|
36
|
+
"@types/chess.js": "^0.11.2",
|
|
37
|
+
"@types/jest": "^30.0.0",
|
|
38
|
+
"@types/pgn-parser": "^2.1.0",
|
|
39
|
+
"jest": "^30.0.4",
|
|
40
|
+
"ts-jest": "^29.4.0",
|
|
41
|
+
"typescript": "^5.8.3"
|
|
35
42
|
},
|
|
36
43
|
"files": [
|
|
37
44
|
"dist/index.js",
|