@echecs/fen 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/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.0] - 2026-04-09
4
+
5
+ ### Changed
6
+
7
+ - `Color` type from `'w' | 'b'` to `'white' | 'black'`.
8
+ - `PieceType` type from single-char (`'p'`, `'n'`, `'b'`, `'r'`, `'q'`, `'k'`)
9
+ to full names (`'pawn'`, `'knight'`, `'bishop'`, `'rook'`, `'queen'`,
10
+ `'king'`).
11
+ - `CastlingRights` from flat `{ wK, wQ, bK, bQ }` to nested
12
+ `{ white: { king, queen }, black: { king, queen } }`.
13
+ - `Position.board` from `Map` to `ReadonlyMap`.
14
+ - En passant square type narrowed from `Square` to `` `${File}${'3' | '6'}` ``.
15
+
16
+ ### Added
17
+
18
+ - `EnPassantSquare` and `SideCastlingRights` type exports.
19
+
20
+ ### Fixed
21
+
22
+ - ESLint config ordering (`eslint-config-prettier` moved to end of array).
23
+
3
24
  ## [1.0.1] - 2026-03-19
4
25
 
5
26
  ### Fixed
package/README.md CHANGED
@@ -103,9 +103,9 @@ The FEN string for the standard starting position.
103
103
 
104
104
  ```typescript
105
105
  interface Position {
106
- board: Map<Square, Piece>;
106
+ board: ReadonlyMap<Square, Piece>;
107
107
  castlingRights: CastlingRights;
108
- enPassantSquare: Square | undefined;
108
+ enPassantSquare: EnPassantSquare | undefined;
109
109
  fullmoveNumber: number;
110
110
  halfmoveClock: number;
111
111
  turn: Color;
@@ -125,22 +125,26 @@ interface ParseWarning {
125
125
  offset: number;
126
126
  }
127
127
 
128
- type Color = 'w' | 'b';
128
+ type Color = 'black' | 'white';
129
129
  type Square = `${File}${Rank}`;
130
+ type EnPassantSquare = `${File}${'3' | '6'}`;
130
131
  type File = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h';
131
132
  type Rank = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8';
132
- type PieceType = 'p' | 'n' | 'b' | 'r' | 'q' | 'k';
133
+ type PieceType = 'bishop' | 'king' | 'knight' | 'pawn' | 'queen' | 'rook';
133
134
 
134
135
  interface Piece {
135
136
  color: Color;
136
137
  type: PieceType;
137
138
  }
138
139
 
140
+ interface SideCastlingRights {
141
+ king: boolean;
142
+ queen: boolean;
143
+ }
144
+
139
145
  interface CastlingRights {
140
- wK: boolean;
141
- wQ: boolean;
142
- bK: boolean;
143
- bQ: boolean;
146
+ black: SideCastlingRights;
147
+ white: SideCastlingRights;
144
148
  }
145
149
  ```
146
150
 
package/dist/index.d.ts CHANGED
@@ -1,23 +1,26 @@
1
1
  //#region src/types.d.ts
2
- type Color = 'b' | 'w';
2
+ type Color = 'black' | 'white';
3
3
  type File = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h';
4
- type PieceType = 'b' | 'k' | 'n' | 'p' | 'q' | 'r';
4
+ type PieceType = 'bishop' | 'king' | 'knight' | 'pawn' | 'queen' | 'rook';
5
5
  type Rank = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8';
6
6
  type Square = `${File}${Rank}`;
7
+ type EnPassantSquare = `${File}${'3' | '6'}`;
8
+ interface SideCastlingRights {
9
+ king: boolean;
10
+ queen: boolean;
11
+ }
7
12
  interface CastlingRights {
8
- bK: boolean;
9
- bQ: boolean;
10
- wK: boolean;
11
- wQ: boolean;
13
+ black: SideCastlingRights;
14
+ white: SideCastlingRights;
12
15
  }
13
16
  interface Piece {
14
17
  color: Color;
15
18
  type: PieceType;
16
19
  }
17
20
  interface Position {
18
- board: Map<Square, Piece>;
21
+ board: ReadonlyMap<Square, Piece>;
19
22
  castlingRights: CastlingRights;
20
- enPassantSquare: Square | undefined;
23
+ enPassantSquare: EnPassantSquare | undefined;
21
24
  fullmoveNumber: number;
22
25
  halfmoveClock: number;
23
26
  turn: Color;
@@ -44,4 +47,4 @@ declare const STARTING_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq
44
47
  declare function parse(input: string, options?: ParseOptions): Position | null;
45
48
  declare function stringify(position: Position): string;
46
49
  //#endregion
47
- export { type CastlingRights, type Color, type File, type ParseError, type ParseOptions, type ParseWarning, type Piece, type PieceType, type Position, type Rank, STARTING_FEN, type Square, parse as default, stringify };
50
+ export { type CastlingRights, type Color, type EnPassantSquare, type File, type ParseError, type ParseOptions, type ParseWarning, type Piece, type PieceType, type Position, type Rank, STARTING_FEN, type SideCastlingRights, type Square, parse as default, stringify };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- const e=`rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1`,t=[`a`,`b`,`c`,`d`,`e`,`f`,`g`,`h`],n=new Set([`p`,`n`,`b`,`r`,`q`,`k`]),r=[`8`,`7`,`6`,`5`,`4`,`3`,`2`,`1`];function i(e,t=0){return{column:t+1,line:1,message:e,offset:t}}function a(e,t=0){return{column:t+1,line:1,message:e,offset:t}}function o(e,a){let o=new Map,s=e.split(`/`);if(s.length!==8)return null;for(let[e,c]of s.entries()){let s=r[e];if(s===void 0||c===void 0)return null;let l=0;for(let e of c){let r=Number.parseInt(e,10);if(Number.isNaN(r)){let r=e.toLowerCase();if(!n.has(r))return a?.(i(`Invalid piece type: "${e}"`)),null;let c=e===e.toUpperCase()?`w`:`b`,u=r,d=t[l];if(d===void 0)return null;o.set(`${d}${s}`,{color:c,type:u}),l+=1}else l+=r}if(l!==8)return a?.(i(`Invalid FEN rank "${c}": expected 8 files, got ${l}`)),null}return o}const s=/^(?:-|K?Q?k?q?)$/,c=/^[a-h][36]$/;function l(e){return!s.test(e)||e.length===0?null:{bK:e.includes(`k`),bQ:e.includes(`q`),wK:e.includes(`K`),wQ:e.includes(`Q`)}}function u(e){let n=[];for(let i of r){let r=``,a=0;for(let n of t){let t=e.get(`${n}${i}`);t===void 0?a+=1:(a>0&&(r+=String(a),a=0),r+=t.color===`w`?t.type.toUpperCase():t.type)}a>0&&(r+=String(a)),n.push(r)}return n.join(`/`)}function d(e){let t=``;return e.wK&&(t+=`K`),e.wQ&&(t+=`Q`),e.bK&&(t+=`k`),e.bQ&&(t+=`q`),t.length>0?t:`-`}function f(e,t){let n=e.replace(/^\uFEFF/,``).trim();if(n.length===0)return t?.onError?.(i(`Input is empty`)),null;let r=n.split(` `);if(r.length!==6)return t?.onError?.(i(`Expected 6 FEN fields, got ${r.length}`)),null;let[s,u,d,f,p,m]=r,h=[0];for(let e=0;e<r.length-1;e++){let t=h[e]??0,n=r[e]??``;h.push(t+n.length+1)}let g=o(s,t?.onError);if(g===null)return null;if(u!==`w`&&u!==`b`)return t?.onError?.(i(`Invalid active color: "${u}"`,h[1])),null;let _=l(d);if(_===null)return t?.onError?.(i(`Invalid castling availability: "${d}"`,h[2])),null;if(f!==`-`&&!c.test(f))return t?.onError?.(i(`Invalid en passant square: "${f}"`,h[3])),null;let v=f===`-`?void 0:f,y=Number.parseInt(p,10);if(Number.isNaN(y)||y<0)return t?.onError?.(i(`Invalid halfmove clock: "${p}"`,h[4])),null;let b=Number.parseInt(m,10);if(Number.isNaN(b)||b<1)return t?.onError?.(i(`Invalid fullmove number: "${m}"`,h[5])),null;if(t?.onWarning){let e=0,n=0,r=0,i=0,o=0,s=0,c=!1;for(let[t,a]of g)a.color===`w`?(o+=1,a.type===`k`&&(e+=1),a.type===`p`&&(r+=1,(t.endsWith(`1`)||t.endsWith(`8`))&&(c=!0))):(s+=1,a.type===`k`&&(n+=1),a.type===`p`&&(i+=1,(t.endsWith(`1`)||t.endsWith(`8`))&&(c=!0)));e===0&&t.onWarning(a(`White king is missing`)),n===0&&t.onWarning(a(`Black king is missing`)),c&&t.onWarning(a(`Pawn on rank 1 or 8`)),r>8&&t.onWarning(a(`White has ${r} pawns (maximum is 8)`)),i>8&&t.onWarning(a(`Black has ${i} pawns (maximum is 8)`)),o>16&&t.onWarning(a(`White has ${o} pieces (maximum is 16)`)),s>16&&t.onWarning(a(`Black has ${s} pieces (maximum is 16)`))}return{board:g,castlingRights:_,enPassantSquare:v,fullmoveNumber:b,halfmoveClock:y,turn:u}}function p(e){let t=u(e.board),n=d(e.castlingRights),r=e.enPassantSquare??`-`;return[t,e.turn,n,r,String(e.halfmoveClock),String(e.fullmoveNumber)].join(` `)}export{e as STARTING_FEN,f as default,p as stringify};
1
+ const e=`rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1`,t=[`a`,`b`,`c`,`d`,`e`,`f`,`g`,`h`],n=[`8`,`7`,`6`,`5`,`4`,`3`,`2`,`1`],r={b:`bishop`,k:`king`,n:`knight`,p:`pawn`,q:`queen`,r:`rook`},i={bishop:`b`,king:`k`,knight:`n`,pawn:`p`,queen:`q`,rook:`r`};function a(e,t=0){return{column:t+1,line:1,message:e,offset:t}}function o(e,t=0){return{column:t+1,line:1,message:e,offset:t}}function s(e,i){let o=new Map,s=e.split(`/`);if(s.length!==8)return null;for(let[e,c]of s.entries()){let s=n[e];if(s===void 0||c===void 0)return null;let l=0;for(let e of c){let n=Number.parseInt(e,10);if(Number.isNaN(n)){let n=r[e.toLowerCase()];if(n===void 0)return i?.(a(`Invalid piece type: "${e}"`)),null;let c=e===e.toUpperCase()?`white`:`black`,u=t[l];if(u===void 0)return null;o.set(`${u}${s}`,{color:c,type:n}),l+=1}else l+=n}if(l!==8)return i?.(a(`Invalid FEN rank "${c}": expected 8 files, got ${l}`)),null}return o}const c=/^(?:-|K?Q?k?q?)$/,l=/^[a-h][36]$/;function u(e){return!c.test(e)||e.length===0?null:{black:{king:e.includes(`k`),queen:e.includes(`q`)},white:{king:e.includes(`K`),queen:e.includes(`Q`)}}}function d(e){let r=[];for(let a of n){let n=``,o=0;for(let r of t){let t=e.get(`${r}${a}`);if(t===void 0)o+=1;else{o>0&&(n+=String(o),o=0);let e=i[t.type];n+=t.color===`white`?e.toUpperCase():e}}o>0&&(n+=String(o)),r.push(n)}return r.join(`/`)}function f(e){let t=``;return e.white.king&&(t+=`K`),e.white.queen&&(t+=`Q`),e.black.king&&(t+=`k`),e.black.queen&&(t+=`q`),t.length>0?t:`-`}function p(e,t){let n=e.replace(/^\uFEFF/,``).trim();if(n.length===0)return t?.onError?.(a(`Input is empty`)),null;let r=n.split(` `);if(r.length!==6)return t?.onError?.(a(`Expected 6 FEN fields, got ${r.length}`)),null;let[i,c,d,f,p,m]=r,h=[0];for(let e=0;e<r.length-1;e++){let t=h[e]??0,n=r[e]??``;h.push(t+n.length+1)}let g=s(i,t?.onError);if(g===null)return null;if(c!==`w`&&c!==`b`)return t?.onError?.(a(`Invalid active color: "${c}"`,h[1])),null;let _=c===`w`?`white`:`black`,v=u(d);if(v===null)return t?.onError?.(a(`Invalid castling availability: "${d}"`,h[2])),null;if(f!==`-`&&!l.test(f))return t?.onError?.(a(`Invalid en passant square: "${f}"`,h[3])),null;let y=f===`-`?void 0:f,b=Number.parseInt(p,10);if(Number.isNaN(b)||b<0)return t?.onError?.(a(`Invalid halfmove clock: "${p}"`,h[4])),null;let x=Number.parseInt(m,10);if(Number.isNaN(x)||x<1)return t?.onError?.(a(`Invalid fullmove number: "${m}"`,h[5])),null;if(t?.onWarning){let e=0,n=0,r=0,i=0,a=0,s=0,c=!1;for(let[t,o]of g)o.color===`white`?(a+=1,o.type===`king`&&(e+=1),o.type===`pawn`&&(r+=1,(t.endsWith(`1`)||t.endsWith(`8`))&&(c=!0))):(s+=1,o.type===`king`&&(n+=1),o.type===`pawn`&&(i+=1,(t.endsWith(`1`)||t.endsWith(`8`))&&(c=!0)));e===0&&t.onWarning(o(`White king is missing`)),n===0&&t.onWarning(o(`Black king is missing`)),c&&t.onWarning(o(`Pawn on rank 1 or 8`)),r>8&&t.onWarning(o(`White has ${r} pawns (maximum is 8)`)),i>8&&t.onWarning(o(`Black has ${i} pawns (maximum is 8)`)),a>16&&t.onWarning(o(`White has ${a} pieces (maximum is 16)`)),s>16&&t.onWarning(o(`Black has ${s} pieces (maximum is 16)`))}return{board:g,castlingRights:v,enPassantSquare:y,fullmoveNumber:x,halfmoveClock:b,turn:_}}function m(e){return[d(e.board),e.turn===`white`?`w`:`b`,f(e.castlingRights),e.enPassantSquare??`-`,String(e.halfmoveClock),String(e.fullmoveNumber)].join(` `)}export{e as STARTING_FEN,p as default,m as stringify};
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type {\n CastlingRights,\n Color,\n File,\n Piece,\n PieceType,\n Position,\n Rank,\n Square,\n} from './types.js';\n\ninterface ParseError {\n column: number;\n line: number;\n message: string;\n offset: number;\n}\n\ninterface ParseWarning {\n column: number;\n line: number;\n message: string;\n offset: number;\n}\n\ninterface ParseOptions {\n onError?: (error: ParseError) => void;\n onWarning?: (warning: ParseWarning) => void;\n}\n\nconst STARTING_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';\n\nconst FILES: File[] = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];\nconst PIECE_TYPES = new Set<string>(['p', 'n', 'b', 'r', 'q', 'k']);\nconst RANKS: Rank[] = ['8', '7', '6', '5', '4', '3', '2', '1'];\n\nfunction makeError(message: string, offset = 0): ParseError {\n return { column: offset + 1, line: 1, message, offset };\n}\n\nfunction makeWarning(message: string, offset = 0): ParseWarning {\n return { column: offset + 1, line: 1, message, offset };\n}\n\nfunction parsePlacement(\n placement: string,\n onError?: (error: ParseError) => void,\n): Map<Square, Piece> | null {\n const board = new Map<Square, Piece>();\n const ranks = placement.split('/');\n\n if (ranks.length !== 8) {\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n for (const [rankIndex, rankString] of ranks.entries()) {\n const rank = RANKS[rankIndex];\n if (rank === undefined || rankString === undefined) {\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n let fileIndex = 0;\n for (const char of rankString) {\n const emptyCount = Number.parseInt(char, 10);\n if (Number.isNaN(emptyCount)) {\n const lower = char.toLowerCase();\n if (!PIECE_TYPES.has(lower)) {\n onError?.(makeError(`Invalid piece type: \"${char}\"`));\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n const color: Color = char === char.toUpperCase() ? 'w' : 'b';\n const type = lower as PieceType;\n const file = FILES[fileIndex];\n if (file === undefined) {\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n board.set(`${file}${rank}` as Square, { color, type });\n fileIndex += 1;\n } else {\n fileIndex += emptyCount;\n }\n }\n\n if (fileIndex !== 8) {\n onError?.(\n makeError(\n `Invalid FEN rank \"${rankString}\": expected 8 files, got ${fileIndex}`,\n ),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n }\n\n return board;\n}\n\nconst CASTLING_PATTERN = /^(?:-|K?Q?k?q?)$/;\nconst EN_PASSANT_PATTERN = /^[a-h][36]$/;\n\nfunction parseCastling(castling: string): CastlingRights | null {\n if (!CASTLING_PATTERN.test(castling) || castling.length === 0) {\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n return {\n bK: castling.includes('k'),\n bQ: castling.includes('q'),\n wK: castling.includes('K'),\n wQ: castling.includes('Q'),\n };\n}\n\nfunction stringifyPlacement(board: Map<Square, Piece>): string {\n const rankStrings: string[] = [];\n\n for (const rank of RANKS) {\n let rankString = '';\n let emptyCount = 0;\n\n for (const file of FILES) {\n const p = board.get(`${file}${rank}` as Square);\n if (p === undefined) {\n emptyCount += 1;\n } else {\n if (emptyCount > 0) {\n rankString += String(emptyCount);\n emptyCount = 0;\n }\n rankString += p.color === 'w' ? p.type.toUpperCase() : p.type;\n }\n }\n\n if (emptyCount > 0) {\n rankString += String(emptyCount);\n }\n rankStrings.push(rankString);\n }\n\n return rankStrings.join('/');\n}\n\nfunction stringifyCastling(rights: CastlingRights): string {\n let result = '';\n if (rights.wK) {\n result += 'K';\n }\n if (rights.wQ) {\n result += 'Q';\n }\n if (rights.bK) {\n result += 'k';\n }\n if (rights.bQ) {\n result += 'q';\n }\n return result.length > 0 ? result : '-';\n}\n\nfunction parse(input: string, options?: ParseOptions): Position | null {\n const content = input.replace(/^\\uFEFF/, '').trim();\n\n if (content.length === 0) {\n options?.onError?.(makeError('Input is empty'));\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n const parts = content.split(' ');\n if (parts.length !== 6) {\n options?.onError?.(makeError(`Expected 6 FEN fields, got ${parts.length}`));\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n const [\n placement,\n turnString,\n castlingString,\n epString,\n halfString,\n fullString,\n ] = parts as [string, string, string, string, string, string];\n\n // Compute the start offset of each field within the content string.\n // Fields are separated by single spaces.\n const fieldOffsets: number[] = [0];\n for (let index = 0; index < parts.length - 1; index++) {\n const previous = fieldOffsets[index] ?? 0;\n const field = parts[index] ?? '';\n fieldOffsets.push(previous + field.length + 1);\n }\n\n const board = parsePlacement(placement, options?.onError);\n if (board === null) {\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n if (turnString !== 'w' && turnString !== 'b') {\n options?.onError?.(\n makeError(`Invalid active color: \"${turnString}\"`, fieldOffsets[1]),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n const castlingRights = parseCastling(castlingString);\n if (castlingRights === null) {\n options?.onError?.(\n makeError(\n `Invalid castling availability: \"${castlingString}\"`,\n fieldOffsets[2],\n ),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n if (epString !== '-' && !EN_PASSANT_PATTERN.test(epString)) {\n options?.onError?.(\n makeError(`Invalid en passant square: \"${epString}\"`, fieldOffsets[3]),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n const enPassantSquare: Square | undefined =\n epString === '-' ? undefined : (epString as Square);\n\n const halfmoveClock = Number.parseInt(halfString, 10);\n if (Number.isNaN(halfmoveClock) || halfmoveClock < 0) {\n options?.onError?.(\n makeError(`Invalid halfmove clock: \"${halfString}\"`, fieldOffsets[4]),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n const fullmoveNumber = Number.parseInt(fullString, 10);\n if (Number.isNaN(fullmoveNumber) || fullmoveNumber < 1) {\n options?.onError?.(\n makeError(`Invalid fullmove number: \"${fullString}\"`, fieldOffsets[5]),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n // Position warnings — syntactically valid FEN but suspicious position.\n if (options?.onWarning) {\n let whiteKings = 0;\n let blackKings = 0;\n let whitePawns = 0;\n let blackPawns = 0;\n let whitePieces = 0;\n let blackPieces = 0;\n let pawnOnBackRank = false;\n\n for (const [square, piece] of board) {\n if (piece.color === 'w') {\n whitePieces += 1;\n if (piece.type === 'k') {\n whiteKings += 1;\n }\n if (piece.type === 'p') {\n whitePawns += 1;\n if (square.endsWith('1') || square.endsWith('8')) {\n pawnOnBackRank = true;\n }\n }\n } else {\n blackPieces += 1;\n if (piece.type === 'k') {\n blackKings += 1;\n }\n if (piece.type === 'p') {\n blackPawns += 1;\n if (square.endsWith('1') || square.endsWith('8')) {\n pawnOnBackRank = true;\n }\n }\n }\n }\n\n if (whiteKings === 0) {\n options.onWarning(makeWarning('White king is missing'));\n }\n if (blackKings === 0) {\n options.onWarning(makeWarning('Black king is missing'));\n }\n if (pawnOnBackRank) {\n options.onWarning(makeWarning('Pawn on rank 1 or 8'));\n }\n if (whitePawns > 8) {\n options.onWarning(\n makeWarning(`White has ${whitePawns} pawns (maximum is 8)`),\n );\n }\n if (blackPawns > 8) {\n options.onWarning(\n makeWarning(`Black has ${blackPawns} pawns (maximum is 8)`),\n );\n }\n if (whitePieces > 16) {\n options.onWarning(\n makeWarning(`White has ${whitePieces} pieces (maximum is 16)`),\n );\n }\n if (blackPieces > 16) {\n options.onWarning(\n makeWarning(`Black has ${blackPieces} pieces (maximum is 16)`),\n );\n }\n }\n\n return {\n board,\n castlingRights,\n enPassantSquare,\n fullmoveNumber,\n halfmoveClock,\n turn: turnString,\n };\n}\n\nfunction stringify(position: Position): string {\n const placement = stringifyPlacement(position.board);\n const castling = stringifyCastling(position.castlingRights);\n const enPassant = position.enPassantSquare ?? '-';\n\n return [\n placement,\n position.turn,\n castling,\n enPassant,\n String(position.halfmoveClock),\n String(position.fullmoveNumber),\n ].join(' ');\n}\n\nexport type { ParseError, ParseOptions, ParseWarning };\nexport type {\n CastlingRights,\n Color,\n File,\n Piece,\n PieceType,\n Position,\n Rank,\n Square,\n} from './types.js';\nexport { STARTING_FEN, stringify };\nexport default parse;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type {\n CastlingRights,\n Color,\n EnPassantSquare,\n File,\n Piece,\n PieceType,\n Position,\n Rank,\n Square,\n} from './types.js';\n\ninterface ParseError {\n column: number;\n line: number;\n message: string;\n offset: number;\n}\n\ninterface ParseWarning {\n column: number;\n line: number;\n message: string;\n offset: number;\n}\n\ninterface ParseOptions {\n onError?: (error: ParseError) => void;\n onWarning?: (warning: ParseWarning) => void;\n}\n\nconst STARTING_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';\n\nconst FILES: File[] = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];\nconst RANKS: Rank[] = ['8', '7', '6', '5', '4', '3', '2', '1'];\n\nconst CHAR_TO_PIECE_TYPE: Record<string, PieceType> = {\n b: 'bishop',\n k: 'king',\n n: 'knight',\n p: 'pawn',\n q: 'queen',\n r: 'rook',\n};\n\nconst PIECE_TYPE_TO_CHAR: Record<PieceType, string> = {\n bishop: 'b',\n king: 'k',\n knight: 'n',\n pawn: 'p',\n queen: 'q',\n rook: 'r',\n};\n\nfunction makeError(message: string, offset = 0): ParseError {\n return { column: offset + 1, line: 1, message, offset };\n}\n\nfunction makeWarning(message: string, offset = 0): ParseWarning {\n return { column: offset + 1, line: 1, message, offset };\n}\n\nfunction parsePlacement(\n placement: string,\n onError?: (error: ParseError) => void,\n): Map<Square, Piece> | null {\n const board = new Map<Square, Piece>();\n const ranks = placement.split('/');\n\n if (ranks.length !== 8) {\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n for (const [rankIndex, rankString] of ranks.entries()) {\n const rank = RANKS[rankIndex];\n if (rank === undefined || rankString === undefined) {\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n let fileIndex = 0;\n for (const char of rankString) {\n const emptyCount = Number.parseInt(char, 10);\n if (Number.isNaN(emptyCount)) {\n const lower = char.toLowerCase();\n const type = CHAR_TO_PIECE_TYPE[lower];\n if (type === undefined) {\n onError?.(makeError(`Invalid piece type: \"${char}\"`));\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n const color: Color = char === char.toUpperCase() ? 'white' : 'black';\n const file = FILES[fileIndex];\n if (file === undefined) {\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n board.set(`${file}${rank}` as Square, { color, type });\n fileIndex += 1;\n } else {\n fileIndex += emptyCount;\n }\n }\n\n if (fileIndex !== 8) {\n onError?.(\n makeError(\n `Invalid FEN rank \"${rankString}\": expected 8 files, got ${fileIndex}`,\n ),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n }\n\n return board;\n}\n\nconst CASTLING_PATTERN = /^(?:-|K?Q?k?q?)$/;\nconst EN_PASSANT_PATTERN = /^[a-h][36]$/;\n\nfunction parseCastling(castling: string): CastlingRights | null {\n if (!CASTLING_PATTERN.test(castling) || castling.length === 0) {\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n return {\n black: {\n king: castling.includes('k'),\n queen: castling.includes('q'),\n },\n white: {\n king: castling.includes('K'),\n queen: castling.includes('Q'),\n },\n };\n}\n\nfunction stringifyPlacement(board: ReadonlyMap<Square, Piece>): string {\n const rankStrings: string[] = [];\n\n for (const rank of RANKS) {\n let rankString = '';\n let emptyCount = 0;\n\n for (const file of FILES) {\n const p = board.get(`${file}${rank}` as Square);\n if (p === undefined) {\n emptyCount += 1;\n } else {\n if (emptyCount > 0) {\n rankString += String(emptyCount);\n emptyCount = 0;\n }\n const char = PIECE_TYPE_TO_CHAR[p.type];\n rankString += p.color === 'white' ? char.toUpperCase() : char;\n }\n }\n\n if (emptyCount > 0) {\n rankString += String(emptyCount);\n }\n rankStrings.push(rankString);\n }\n\n return rankStrings.join('/');\n}\n\nfunction stringifyCastling(rights: CastlingRights): string {\n let result = '';\n if (rights.white.king) {\n result += 'K';\n }\n if (rights.white.queen) {\n result += 'Q';\n }\n if (rights.black.king) {\n result += 'k';\n }\n if (rights.black.queen) {\n result += 'q';\n }\n return result.length > 0 ? result : '-';\n}\n\nfunction parse(input: string, options?: ParseOptions): Position | null {\n const content = input.replace(/^\\uFEFF/, '').trim();\n\n if (content.length === 0) {\n options?.onError?.(makeError('Input is empty'));\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n const parts = content.split(' ');\n if (parts.length !== 6) {\n options?.onError?.(makeError(`Expected 6 FEN fields, got ${parts.length}`));\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n const [\n placement,\n turnString,\n castlingString,\n epString,\n halfString,\n fullString,\n ] = parts as [string, string, string, string, string, string];\n\n // Compute the start offset of each field within the content string.\n // Fields are separated by single spaces.\n const fieldOffsets: number[] = [0];\n for (let index = 0; index < parts.length - 1; index++) {\n const previous = fieldOffsets[index] ?? 0;\n const field = parts[index] ?? '';\n fieldOffsets.push(previous + field.length + 1);\n }\n\n const board = parsePlacement(placement, options?.onError);\n if (board === null) {\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n if (turnString !== 'w' && turnString !== 'b') {\n options?.onError?.(\n makeError(`Invalid active color: \"${turnString}\"`, fieldOffsets[1]),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n const turn: Color = turnString === 'w' ? 'white' : 'black';\n\n const castlingRights = parseCastling(castlingString);\n if (castlingRights === null) {\n options?.onError?.(\n makeError(\n `Invalid castling availability: \"${castlingString}\"`,\n fieldOffsets[2],\n ),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n if (epString !== '-' && !EN_PASSANT_PATTERN.test(epString)) {\n options?.onError?.(\n makeError(`Invalid en passant square: \"${epString}\"`, fieldOffsets[3]),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n const enPassantSquare: EnPassantSquare | undefined =\n epString === '-' ? undefined : (epString as EnPassantSquare);\n\n const halfmoveClock = Number.parseInt(halfString, 10);\n if (Number.isNaN(halfmoveClock) || halfmoveClock < 0) {\n options?.onError?.(\n makeError(`Invalid halfmove clock: \"${halfString}\"`, fieldOffsets[4]),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n const fullmoveNumber = Number.parseInt(fullString, 10);\n if (Number.isNaN(fullmoveNumber) || fullmoveNumber < 1) {\n options?.onError?.(\n makeError(`Invalid fullmove number: \"${fullString}\"`, fieldOffsets[5]),\n );\n // eslint-disable-next-line unicorn/no-null\n return null;\n }\n\n // Position warnings — syntactically valid FEN but suspicious position.\n if (options?.onWarning) {\n let whiteKings = 0;\n let blackKings = 0;\n let whitePawns = 0;\n let blackPawns = 0;\n let whitePieces = 0;\n let blackPieces = 0;\n let pawnOnBackRank = false;\n\n for (const [square, piece] of board) {\n if (piece.color === 'white') {\n whitePieces += 1;\n if (piece.type === 'king') {\n whiteKings += 1;\n }\n if (piece.type === 'pawn') {\n whitePawns += 1;\n if (square.endsWith('1') || square.endsWith('8')) {\n pawnOnBackRank = true;\n }\n }\n } else {\n blackPieces += 1;\n if (piece.type === 'king') {\n blackKings += 1;\n }\n if (piece.type === 'pawn') {\n blackPawns += 1;\n if (square.endsWith('1') || square.endsWith('8')) {\n pawnOnBackRank = true;\n }\n }\n }\n }\n\n if (whiteKings === 0) {\n options.onWarning(makeWarning('White king is missing'));\n }\n if (blackKings === 0) {\n options.onWarning(makeWarning('Black king is missing'));\n }\n if (pawnOnBackRank) {\n options.onWarning(makeWarning('Pawn on rank 1 or 8'));\n }\n if (whitePawns > 8) {\n options.onWarning(\n makeWarning(`White has ${whitePawns} pawns (maximum is 8)`),\n );\n }\n if (blackPawns > 8) {\n options.onWarning(\n makeWarning(`Black has ${blackPawns} pawns (maximum is 8)`),\n );\n }\n if (whitePieces > 16) {\n options.onWarning(\n makeWarning(`White has ${whitePieces} pieces (maximum is 16)`),\n );\n }\n if (blackPieces > 16) {\n options.onWarning(\n makeWarning(`Black has ${blackPieces} pieces (maximum is 16)`),\n );\n }\n }\n\n return {\n board,\n castlingRights,\n enPassantSquare,\n fullmoveNumber,\n halfmoveClock,\n turn,\n };\n}\n\nfunction stringify(position: Position): string {\n const placement = stringifyPlacement(position.board);\n const turn = position.turn === 'white' ? 'w' : 'b';\n const castling = stringifyCastling(position.castlingRights);\n const enPassant = position.enPassantSquare ?? '-';\n\n return [\n placement,\n turn,\n castling,\n enPassant,\n String(position.halfmoveClock),\n String(position.fullmoveNumber),\n ].join(' ');\n}\n\nexport type { ParseError, ParseOptions, ParseWarning };\nexport type {\n CastlingRights,\n Color,\n EnPassantSquare,\n File,\n Piece,\n PieceType,\n Position,\n Rank,\n SideCastlingRights,\n Square,\n} from './types.js';\nexport { STARTING_FEN, stringify };\nexport default parse;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -13,13 +13,13 @@
13
13
  "eslint-config-prettier": "^10.1.8",
14
14
  "eslint-import-resolver-typescript": "^4.4.4",
15
15
  "eslint-plugin-import-x": "^4.16.2",
16
- "eslint-plugin-unicorn": "^63.0.0",
16
+ "eslint-plugin-unicorn": "^64.0.0",
17
17
  "husky": "^9.1.7",
18
18
  "lint-staged": "^16.4.0",
19
19
  "prettier": "^3.8.1",
20
20
  "tsdown": "^0.21.4",
21
21
  "typedoc": "^0.28.17",
22
- "typescript": "^5.9.3",
22
+ "typescript": "^6.0.2",
23
23
  "typescript-eslint": "^8.57.0",
24
24
  "vitest": "^4.1.0"
25
25
  },
@@ -55,7 +55,7 @@
55
55
  },
56
56
  "sideEffects": false,
57
57
  "type": "module",
58
- "version": "1.0.1",
58
+ "version": "2.0.0",
59
59
  "scripts": {
60
60
  "build": "tsdown",
61
61
  "docs": "typedoc",