chess-moments 1.4.7 → 1.5.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.
@@ -1,7 +1,7 @@
1
1
  const prettify = require('./prettify');
2
2
  const shape = require('./shape');
3
3
 
4
- module.exports = ({ depth, move, fen, comment, suffix, from, to }) => {
4
+ module.exports = ({ depth, move, fen, comment, suffix, from, to, headers }) => {
5
5
  const moment = { depth, fen };
6
6
  if (move) {
7
7
  moment.move = move;
@@ -23,6 +23,9 @@ module.exports = ({ depth, move, fen, comment, suffix, from, to }) => {
23
23
  if (suffix) {
24
24
  moment.suffix = suffix;
25
25
  }
26
+ if (headers) {
27
+ moment.headers = headers;
28
+ }
26
29
 
27
30
  return moment;
28
31
  };
@@ -1,3 +1,4 @@
1
+ const { isEmpty } = require('lodash');
1
2
  const fen = require('../fen');
2
3
  const { getBrushCode } = require('../helpers');
3
4
 
@@ -10,7 +11,7 @@ const momentsToPgn = (moments) => {
10
11
  let pgn = '';
11
12
 
12
13
  // Return empty PGN if no moments are provided
13
- if (!Array.isArray(moments) || moments.length === 0) {
14
+ if (isEmpty(moments)) {
14
15
  pgn += `[SetUp "1"]\n`;
15
16
  pgn += `[FEN "${fen.initial}"]\n\n`;
16
17
  pgn += '*';
@@ -20,13 +21,47 @@ const momentsToPgn = (moments) => {
20
21
  let currentDepth = 1;
21
22
  let variationStack = [];
22
23
 
23
- // Check if we need to add FEN headers for non-standard starting position
24
- const initialMoment = moments[0];
25
- if (initialMoment && initialMoment.fen && initialMoment.fen !== fen.initial) {
26
- pgn += `[SetUp "1"]\n`;
27
- pgn += `[FEN "${initialMoment.fen}"]\n\n`;
24
+ const headers = moments[0].headers;
25
+ const standardHeaders = [
26
+ 'Event',
27
+ 'Site',
28
+ 'Date',
29
+ 'Round',
30
+ 'White',
31
+ 'Black',
32
+ 'Result',
33
+ ];
34
+
35
+ if (headers) {
36
+ // Add standard headers (excluding placeholder values)
37
+ for (const key of standardHeaders) {
38
+ if (
39
+ headers[key] &&
40
+ headers[key] !== '?' &&
41
+ headers[key] !== '????.??.??'
42
+ ) {
43
+ pgn += `[${key} "${headers[key]}"]\n`;
44
+ }
45
+ }
46
+
47
+ // Add custom headers
48
+ for (const key in headers) {
49
+ if (!standardHeaders.includes(key) && key !== 'FEN' && key !== 'SetUp') {
50
+ pgn += `[${key} "${headers[key]}"]\n`;
51
+ }
52
+ }
28
53
  }
29
54
 
55
+ const fenString = headers?.FEN || moments[0].fen;
56
+
57
+ if (fenString !== fen.initial) {
58
+ const setUp = headers?.SetUp || '1';
59
+ pgn += `[SetUp "${setUp}"]\n`;
60
+ pgn += `[FEN "${fenString}"]\n`;
61
+ }
62
+
63
+ pgn += '\n';
64
+
30
65
  for (let i = 0; i < moments.length; i++) {
31
66
  const moment = moments[i];
32
67
  const depth = moment.depth || 1;
@@ -166,8 +201,8 @@ const momentsToPgn = (moments) => {
166
201
  pgn += ')';
167
202
  }
168
203
 
169
- // Add default result
170
- pgn += ' *';
204
+ // Add result from headers if available, otherwise default to *
205
+ pgn += ` ${headers?.Result || '*'}`;
171
206
 
172
207
  return pgn.trim();
173
208
  };
@@ -5,7 +5,11 @@ const pgn = require('./pgn');
5
5
  const split = require('./split');
6
6
 
7
7
  const make = (sloppyPgn) => {
8
- const normalizedPgn = pgn.normalize(sloppyPgn);
8
+ let normalizedPgn = pgn.normalize(sloppyPgn);
9
+ // when PGN is empty, create a default one with initial FEN
10
+ if (!normalizedPgn) {
11
+ normalizedPgn = pgn.build([], fen.initial);
12
+ }
9
13
 
10
14
  // load PGN and check headers for existing FEN
11
15
  const chess = new Chess(); // can throw if PGN is invalid
@@ -18,7 +22,7 @@ const make = (sloppyPgn) => {
18
22
  };
19
23
 
20
24
  const history = new Map();
21
- const variations = split(normalizedPgn).map(({ moves, depth }) => {
25
+ const variations = split(normalizedPgn).map(({ moves, depth }, index) => {
22
26
  // find previous FEN
23
27
  if (history.get(store.depth)) {
24
28
  store.fen = fen.previous(history, moves, depth, store.depth);
@@ -26,7 +30,13 @@ const make = (sloppyPgn) => {
26
30
  store.depth = depth;
27
31
 
28
32
  // parse current moves with the computed FEN
29
- const moments = parser(moves, store.fen, depth);
33
+ // only pass headers to the first move
34
+ const moments = parser(
35
+ moves,
36
+ store.fen,
37
+ depth,
38
+ index === 0 ? headers : null
39
+ );
30
40
 
31
41
  // set history for the current depth
32
42
  history.set(depth, fen.history(moments, history, depth));
@@ -3,7 +3,7 @@ const { initial } = require('./fen');
3
3
  const pgn = require('./pgn');
4
4
  const moment = require('./moment');
5
5
 
6
- module.exports = (moves, fen = initial, depth = 1) => {
6
+ module.exports = (moves, fen = initial, depth = 1, headers = null) => {
7
7
  const chess = new Chess();
8
8
  chess.loadPgn(pgn.build(moves, fen)); // can throw if PGN is invalid
9
9
 
@@ -17,6 +17,7 @@ module.exports = (moves, fen = initial, depth = 1) => {
17
17
  depth,
18
18
  comment: chess.getComment(),
19
19
  fen: chess.fen(),
20
+ headers,
20
21
  });
21
22
 
22
23
  const moments = history.map((item) => {
@@ -34,8 +35,8 @@ module.exports = (moves, fen = initial, depth = 1) => {
34
35
  });
35
36
 
36
37
  // finally, add the first chess "moment" when needed
37
- const headers = chess.getHeaders();
38
- if (headers.FEN || fen === initial || first.comment || first.shapes) {
38
+ const pgnHeaders = chess.getHeaders();
39
+ if (pgnHeaders.FEN || fen === initial || first.comment || first.shapes) {
39
40
  moments.unshift(first);
40
41
  }
41
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chess-moments",
3
- "version": "1.4.7",
3
+ "version": "1.5.0",
4
4
  "description": "PGN parser that transforms PGN files into chess \"moments\"",
5
5
  "main": "index.js",
6
6
  "files": [