pgn-manager 1.1.0 → 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 +0 -1
- package/dist/index.d.ts +21 -4
- package/dist/index.js +106 -5
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -65,7 +65,6 @@ const headers = manager.headers;
|
|
|
65
65
|
- `getLastMove()`: Get the last move of the game
|
|
66
66
|
- `getMoveFen(moveOrMoveId: Move | number)`: Get FEN position after move
|
|
67
67
|
- `getParentRav(moveOrMoveId: Move | number)`: Get parent variation for move
|
|
68
|
-
- `getChessJSInstance(moveOrMoveId: Move | number)`: Get or create a ChessJS instance for the position after the specified move
|
|
69
68
|
- `getMoveColor(moveOrMoveId: Move | number)`: Gets the color of the player who made the move ("w" for white or "b" for black)
|
|
70
69
|
|
|
71
70
|
## Examples 🎯
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
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 {
|
|
@@ -53,7 +55,7 @@ declare class PGNManager {
|
|
|
53
55
|
* @param moveNumber - The 1-based index of the move
|
|
54
56
|
* @returns The move object at the specified position
|
|
55
57
|
*/
|
|
56
|
-
getMove: (moveNumber: number) => Move;
|
|
58
|
+
getMove: (moveNumber: number) => pgnParser.Move;
|
|
57
59
|
/**
|
|
58
60
|
* Gets the number of a move in the sequence
|
|
59
61
|
* @param move - The move object
|
|
@@ -85,13 +87,13 @@ declare class PGNManager {
|
|
|
85
87
|
* @returns The first move
|
|
86
88
|
* @throws Error if there are no moves in the game
|
|
87
89
|
*/
|
|
88
|
-
getFirstMove: () => Move;
|
|
90
|
+
getFirstMove: () => pgnParser.Move;
|
|
89
91
|
/**
|
|
90
92
|
* Gets the last move in the game
|
|
91
93
|
* @returns The last move
|
|
92
94
|
* @throws Error if there are no moves in the game
|
|
93
95
|
*/
|
|
94
|
-
getLastMove: () =>
|
|
96
|
+
getLastMove: () => pgnParser.Move;
|
|
95
97
|
/**
|
|
96
98
|
* Gets the FEN string for a specific move
|
|
97
99
|
* @param moveOrId - The move object or move number
|
|
@@ -113,5 +115,20 @@ declare class PGNManager {
|
|
|
113
115
|
* @throws Error if the move parameter is invalid
|
|
114
116
|
*/
|
|
115
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;
|
|
116
133
|
}
|
|
117
134
|
export default PGNManager;
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,8 @@ 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 {
|
|
@@ -27,7 +28,7 @@ class PGNManager {
|
|
|
27
28
|
*/
|
|
28
29
|
constructor(pgn) {
|
|
29
30
|
this.rawPGN = pgn;
|
|
30
|
-
this.game =
|
|
31
|
+
this.game = pgnParser.parse(pgn + " *")[0];
|
|
31
32
|
this.sortedMoves = [];
|
|
32
33
|
this.moveParent = new Map();
|
|
33
34
|
this.ravParent = new Map();
|
|
@@ -224,7 +225,7 @@ class PGNManager {
|
|
|
224
225
|
*/
|
|
225
226
|
getMoveFen = (moveOrId) => {
|
|
226
227
|
const move = typeof moveOrId === "number" ? this.getMove(moveOrId) : moveOrId;
|
|
227
|
-
if (!move) {
|
|
228
|
+
if (!move || !this.moveFen.has(move)) {
|
|
228
229
|
throw Error("Invalid 'move' parameter while getting fen");
|
|
229
230
|
}
|
|
230
231
|
let moveFen = this.moveFen.get(move);
|
|
@@ -238,7 +239,7 @@ class PGNManager {
|
|
|
238
239
|
*/
|
|
239
240
|
getParentRav = (moveOrId) => {
|
|
240
241
|
const move = typeof moveOrId === "number" ? this.getMove(moveOrId) : moveOrId;
|
|
241
|
-
if (!move) {
|
|
242
|
+
if (!move || !this.moveParent.has(move)) {
|
|
242
243
|
throw Error("Invalid 'move' parameter while getting parent rav");
|
|
243
244
|
}
|
|
244
245
|
let parentRav = this.moveParent.get(move);
|
|
@@ -252,10 +253,110 @@ class PGNManager {
|
|
|
252
253
|
*/
|
|
253
254
|
getMoveColor = (moveOrId) => {
|
|
254
255
|
const move = typeof moveOrId === "number" ? this.getMove(moveOrId) : moveOrId;
|
|
255
|
-
if (!move) {
|
|
256
|
+
if (!move || !this.moveColor.has(move)) {
|
|
256
257
|
throw Error("Invalid 'move' parameter while getting move color");
|
|
257
258
|
}
|
|
258
259
|
return this.moveColor.get(move);
|
|
259
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
|
+
};
|
|
260
361
|
}
|
|
261
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 .",
|
|
@@ -32,7 +34,11 @@
|
|
|
32
34
|
},
|
|
33
35
|
"devDependencies": {
|
|
34
36
|
"@types/chess.js": "^0.11.2",
|
|
35
|
-
"
|
|
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"
|
|
36
42
|
},
|
|
37
43
|
"files": [
|
|
38
44
|
"dist/index.js",
|