https://github.com/echecsjs/fen
Parse and stringify FEN (Forsyth–Edwards Notation) chess positions. Strict TypeScript, no-throw API.
https://github.com/echecsjs/fen
chess fen parser typescript
Last synced: about 7 hours ago
JSON representation
Parse and stringify FEN (Forsyth–Edwards Notation) chess positions. Strict TypeScript, no-throw API.
- Host: GitHub
- URL: https://github.com/echecsjs/fen
- Owner: echecsjs
- License: mit
- Created: 2026-03-17T21:17:17.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-06-29T14:11:32.000Z (2 days ago)
- Last Synced: 2026-06-29T15:26:11.711Z (2 days ago)
- Topics: chess, fen, parser, typescript
- Language: TypeScript
- Homepage: https://github.com/echecsjs/fen#readme
- Size: 571 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# @echecs/fen
[](SPEC.md)
Parse and stringify
[FEN](https://www.chessprogramming.org/Forsyth-Edwards_Notation)
(Forsyth-Edwards Notation) chess positions. Strict TypeScript, no-throw API.
## Install
```bash
npm install @echecs/fen
```
## Usage
### Parsing
```typescript
import { parse } from '@echecs/fen';
const position = parse(
'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
);
// => { board, turn, castlingRights, enPassantSquare, halfmoveClock, fullmoveNumber }
parse('invalid');
// => null
```
`parse` never throws. It returns `null` when the input is not a valid FEN
string. The result can be passed directly to the `Position` constructor from
`@echecs/position`:
```typescript
import { Position } from '@echecs/position';
const position = new Position(parse(fen));
```
#### Error and warning callbacks
Errors indicate invalid FEN syntax — the string cannot be parsed. Warnings
indicate a successfully parsed position that is suspicious (e.g. missing king).
```typescript
const position = parse(fen, {
onError(error) {
// FEN is malformed — parse returns null.
console.error(`[${error.offset}] ${error.message}`);
},
onWarning(warning) {
// FEN is valid but the position is suspicious.
console.warn(warning.message);
},
});
```
Errors are reported for:
- Wrong number of fields
- Invalid piece placement (bad piece type, wrong rank length)
- Invalid active color
- Invalid castling availability
- Invalid en passant target square
- Invalid halfmove clock (non-numeric or negative)
- Invalid fullmove number (non-numeric or less than 1)
Warnings are reported for:
- Missing king for either side
- Pawn on rank 1 or 8
- More than 8 pawns per side
- More than 16 pieces per side
### Stringifying
```typescript
import { stringify } from '@echecs/fen';
stringify(position);
// => 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
```
`stringify` always succeeds.
### Constants
```typescript
import { STARTING_FEN } from '@echecs/fen';
STARTING_FEN;
// => 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
```
## API
### `parse(input: string, options?: ParseOptions): PositionData | null`
Parses a FEN string into a `PositionData` object. Returns `null` if the input is
not a valid FEN string.
### `stringify(position: PositionData): string`
Serializes a `PositionData` object into a FEN string. Omitted fields use
defaults (empty board, white to move, all castling rights, no en passant,
halfmove clock 0, fullmove number 1).
### `STARTING_FEN`
The FEN string for the standard starting position.
### Types
Chess types (`Color`, `Square`, `Piece`, `CastlingRights`, `PositionData`, etc.)
are re-exported from `@echecs/position`. Parse/stringify types are defined
locally:
```typescript
import type {
CastlingRights,
Color,
EnPassantSquare,
File,
ParseError,
ParseOptions,
ParseWarning,
Piece,
PieceType,
PositionData,
Rank,
SideCastlingRights,
Square,
} from '@echecs/fen';
```
```typescript
interface ParseOptions {
onError?: (error: ParseError) => void;
onWarning?: (warning: ParseWarning) => void;
}
interface ParseError {
column: number; // 1-indexed column in the FEN string
line: number; // Always 1 (FEN is single-line)
message: string;
offset: number; // 0-indexed offset into the FEN string
}
interface ParseWarning {
column: number;
line: number;
message: string;
offset: number;
}
```
See `@echecs/position` for the full type definitions of `PositionData`, `Color`,
`Square`, `Piece`, and other chess types.
## License
MIT