https://github.com/echecsjs/san
Parse, resolve, and stringify SAN (Standard Algebraic Notation) chess moves. Strict TypeScript.
https://github.com/echecsjs/san
chess notation parser san typescript
Last synced: about 8 hours ago
JSON representation
Parse, resolve, and stringify SAN (Standard Algebraic Notation) chess moves. Strict TypeScript.
- Host: GitHub
- URL: https://github.com/echecsjs/san
- Owner: echecsjs
- License: mit
- Created: 2026-03-17T21:17:19.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-06-29T14:08:18.000Z (2 days ago)
- Last Synced: 2026-06-29T15:25:28.209Z (2 days ago)
- Topics: chess, notation, parser, san, typescript
- Language: TypeScript
- Homepage: https://github.com/echecsjs/san#readme
- Size: 512 KB
- Stars: 1
- 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/san
[](SPEC.md)
Parse, resolve, and stringify SAN (Standard Algebraic Notation) chess moves.
Strict TypeScript. Implements the notation defined in
[FIDE Laws of Chess, Appendix C](https://handbook.fide.com/chapter/E012023).
## Installation
```bash
npm install @echecs/san
```
## Usage
```typescript
import { parse, resolve, stringify } from '@echecs/san';
// Parse SAN syntax only — returns a SanMove (no position needed)
const sanMove = parse('Nf3');
// Parse and resolve in one call — returns a Move with from/to squares
const move = parse('Nf3', position);
// Resolve a SanMove to a Move (find the from square)
const move = resolve(sanMove, position);
// Convert a Move back to a SAN string
const san = stringify(move, position);
```
## API
### `parse(san: string): SAN`
Parses a SAN string and returns a `SAN` object describing the move's syntax.
Does not require a position. Throws `RangeError` for empty or invalid input.
### `parse(san: string, position: Position): Move`
Parses and resolves a SAN string against a position in one call. Equivalent to
calling `parse` then `resolve`. Throws `RangeError` for empty, invalid, or
illegal input.
### `resolve(move: SAN, position: Position): Move`
Finds the source square for a `SAN` move in the given position. Throws
`RangeError` if no legal move matches or if the move is ambiguous.
### `stringify(move: Move, position: Position): string`
Returns the SAN string for a `Move` in the given position, including
disambiguation, capture marker, check, and checkmate symbols. Throws
`RangeError` if no piece occupies the source square.
## Types
```typescript
interface SAN {
capture: boolean;
castling: boolean;
check: boolean;
checkmate: boolean;
from: Disambiguation | undefined;
long: boolean;
piece: Piece;
promotion: PromotionPiece | undefined;
to: Square | undefined;
}
```
`from` is the disambiguation hint from the SAN string (a file, rank, or full
square), not the origin square. `to` is `undefined` for castling moves.
`Move` and `PromotionPieceType` are re-exported from `@echecs/position`.
`PromotionPiece` is an alias for `PromotionPieceType`.
```typescript
interface Move {
from: Square;
promotion?: PromotionPieceType;
to: Square;
}
```
```typescript
import type { Move, Position, PromotionPieceType, SAN } from '@echecs/san';
```
## Errors
All functions throw `RangeError` for domain violations:
| Situation | Message |
| ------------------------- | ------------------------------ |
| Empty SAN string | `Empty SAN string` |
| Invalid SAN syntax | `Invalid SAN: ""` |
| No legal move found | Describes the move |
| Ambiguous move | Lists the number of candidates |
| No piece on source square | Describes the square |
## License
MIT