@xwordly/xword-parser
Version:
Fast, type-safe TypeScript library for parsing crossword puzzles (PUZ, iPUZ, JPZ, XD)
423 lines (411 loc) • 12.9 kB
text/typescript
import { P as ParseOptions, a as Puzzle, E as ErrorCode, b as ErrorContext } from './types-BPKJZKk0.cjs';
export { g as Cell, i as Clue, C as ClueNumber, h as Clues, D as Direction, f as Grid, G as GridCoordinate, R as RebusId, c as asClueNumber, d as asGridCoordinate, e as asRebusId } from './types-BPKJZKk0.cjs';
/**
* Parser for ipuz crossword format.
* Based on specification at https://www.puzzazz.com/ipuz
*/
declare enum CellType {
NORMAL = "normal",
BLOCK = "block",
NULL = "null"
}
interface CellStyle {
shapebg?: string;
highlight?: boolean;
named?: boolean;
border?: number;
divided?: string;
label?: string;
mark?: Record<string, unknown>;
imagebg?: string;
color?: string;
colortext?: string;
colorborder?: string;
colorbar?: string;
barred?: string;
dotted?: string;
dashed?: string;
lessthan?: string;
greaterthan?: string;
equal?: string;
handler?: string;
handlerdata?: unknown;
}
interface IpuzCell {
type: CellType;
number?: number | string;
value?: string;
solution?: string;
style?: CellStyle;
continued?: Record<string, unknown>;
directions?: string[];
given?: boolean;
}
interface IpuzClue {
number: number | string;
text: string;
cells?: Array<[number, number]>;
references?: Array<number | string>;
continued?: Record<string, unknown>;
highlight?: boolean;
image?: string;
}
interface IpuzPuzzle {
version: string;
kind: string[];
dimensions: {
width: number;
height: number;
};
puzzle: IpuzCell[][];
title?: string;
author?: string;
copyright?: string;
publisher?: string;
publication?: string;
url?: string;
uniqueId?: string;
intro?: string;
explanation?: string;
annotation?: string;
notes?: string;
difficulty?: string;
origin?: string;
date?: string;
empty?: string;
charset?: string;
clues: Record<string, IpuzClue[]>;
solution?: Array<Array<string | null>>;
zones?: Array<Record<string, unknown>>;
styles?: Record<string, unknown>;
extensions: Record<string, unknown>;
volatile?: Record<string, boolean>;
checksum?: string[];
saved?: Array<Array<string | null>>;
enumeration?: boolean;
enumerations?: string[];
misses?: Record<string, unknown>;
block?: string;
showEnumerations?: boolean;
cluePlacement?: string;
answer?: string;
answers?: string[];
}
/**
* Parse an iPUZ format crossword puzzle.
*
* @param content - The iPUZ data as JSON string or Buffer
* @param options - Optional parsing options
* @param options.maxGridSize - Maximum allowed grid dimensions
* @returns An IpuzPuzzle object containing all puzzle data
* @throws {IpuzParseError} When the content is not valid iPUZ format
* @throws {UnsupportedPuzzleTypeError} When the puzzle is not a crossword
*
* @example
* ```typescript
* import { parseIpuz } from 'xword-parser';
* const ipuzData = '{"version":"http://ipuz.org/v2","kind":["http://ipuz.org/crossword#1"]...}';
* const puzzle = parseIpuz(ipuzData);
* ```
*/
declare function parseIpuz(content: string | Buffer, options?: ParseOptions): IpuzPuzzle;
/**
* Convert an iPUZ puzzle to the unified Puzzle format.
*
* @param puzzle - The IpuzPuzzle object to convert
* @returns A unified Puzzle object
*
* @example
* ```typescript
* import { parseIpuz, convertIpuzToUnified } from 'xword-parser';
* const ipuzPuzzle = parseIpuz(ipuzData);
* const unifiedPuzzle = convertIpuzToUnified(ipuzPuzzle);
* ```
*/
declare function convertIpuzToUnified(puzzle: IpuzPuzzle): Puzzle;
interface XdMetadata {
title?: string;
author?: string;
editor?: string;
copyright?: string;
date?: string;
rebus?: string;
[key: string]: string | undefined;
}
interface XdClue {
number: string;
clue: string;
answer: string;
metadata?: Record<string, string>;
}
interface XdPuzzle {
metadata: XdMetadata;
grid: string[][];
across: XdClue[];
down: XdClue[];
notes?: string;
}
/**
* Parse an XD format crossword puzzle.
*
* @param content - The XD text data as string
* @param options - Optional parsing options
* @param options.maxGridSize - Maximum allowed grid dimensions
* @returns An XdPuzzle object containing all puzzle data
* @throws {XdParseError} When the content is not valid XD format
*
* @example
* ```typescript
* import { parseXd } from 'xword-parser';
* const xdData = 'Title: Example\\nAuthor: John Doe\\n\\n## Grid\\n...';
* const puzzle = parseXd(xdData);
* ```
*/
declare function parseXd(content: string, options?: ParseOptions): XdPuzzle;
/**
* Convert an XD puzzle to the unified Puzzle format.
*
* @param puzzle - The XdPuzzle object to convert
* @returns A unified Puzzle object
*
* @example
* ```typescript
* import { parseXd, convertXdToUnified } from 'xword-parser';
* const xdPuzzle = parseXd(xdData);
* const unifiedPuzzle = convertXdToUnified(xdPuzzle);
* ```
*/
declare function convertXdToUnified(puzzle: XdPuzzle): Puzzle;
/**
* Parser for PUZ crossword format (Across Lite)
* Based on reverse-engineered specification
*/
interface PuzMetadata {
title?: string;
author?: string;
copyright?: string;
notes?: string;
}
interface PuzClue {
number: number;
text: string;
}
interface PuzCell {
solution?: string;
playerState?: string;
isBlack: boolean;
isCircled?: boolean;
hasRebus?: boolean;
rebusKey?: number;
}
interface PuzPuzzle {
width: number;
height: number;
metadata: PuzMetadata;
grid: PuzCell[][];
across: PuzClue[];
down: PuzClue[];
rebusTable?: Map<number, string>;
isScrambled?: boolean;
timer?: {
elapsed: number;
running: boolean;
};
}
/**
* Parse a PUZ format crossword puzzle.
*
* @param data - The PUZ binary data as Buffer, ArrayBuffer, Uint8Array, or string
* @param options - Optional parsing options
* @param options.maxGridSize - Maximum allowed grid dimensions
* @returns A PuzPuzzle object containing all puzzle data
* @throws {PuzParseError} When the content is not valid PUZ format
* @throws {InvalidFileError} When the file is corrupted or has invalid checksums
*
* @example
* ```typescript
* import { parsePuz } from 'xword-parser';
* import { readFileSync } from 'fs';
*
* const puzData = readFileSync('puzzle.puz');
* const puzzle = parsePuz(puzData);
* ```
*/
declare function parsePuz(data: Buffer | ArrayBuffer | Uint8Array | string, options?: ParseOptions): PuzPuzzle;
/**
* Convert a PUZ puzzle to the unified Puzzle format.
*
* @param puzzle - The PuzPuzzle object to convert
* @returns A unified Puzzle object
*
* @example
* ```typescript
* import { parsePuz, convertPuzToUnified } from 'xword-parser';
* const puzPuzzle = parsePuz(puzData);
* const unifiedPuzzle = convertPuzToUnified(puzPuzzle);
* ```
*/
declare function convertPuzToUnified(puzzle: PuzPuzzle): Puzzle;
/**
* Parser for JPZ crossword format (Crossword Compiler)
* JPZ is an XML-based format
*/
interface JpzMetadata {
title?: string;
creator?: string;
copyright?: string;
description?: string;
publisher?: string;
identifier?: string;
}
interface JpzCell {
x: number;
y: number;
solution?: string;
number?: number;
type?: 'block' | 'cell';
isCircled?: boolean;
backgroundColor?: string;
barTop?: boolean;
barBottom?: boolean;
barLeft?: boolean;
barRight?: boolean;
}
interface JpzClue {
number: string | number;
text: string;
format?: string;
}
interface JpzWord {
id: string;
cells: Array<{
x: number;
y: number;
}>;
}
interface JpzPuzzle {
width: number;
height: number;
metadata: JpzMetadata;
grid: JpzCell[][];
across: JpzClue[];
down: JpzClue[];
words?: JpzWord[];
}
/**
* Parse a JPZ format crossword puzzle.
*
* @param content - The JPZ XML data as string
* @param options - Optional parsing options
* @param options.maxGridSize - Maximum allowed grid dimensions
* @returns A JpzPuzzle object containing all puzzle data
* @throws {JpzParseError} When the content is not valid JPZ format
* @throws {UnsupportedPuzzleTypeError} When the puzzle is not a crossword
*
* @example
* ```typescript
* import { parseJpz } from 'xword-parser';
* const jpzData = '<?xml version="1.0"?><crossword-compiler-applet>...';
* const puzzle = parseJpz(jpzData);
* ```
*/
declare function parseJpz(content: string, options?: ParseOptions): JpzPuzzle;
/**
* Convert a JPZ puzzle to the unified Puzzle format.
*
* @param puzzle - The JpzPuzzle object to convert
* @returns A unified Puzzle object
*
* @example
* ```typescript
* import { parseJpz, convertJpzToUnified } from 'xword-parser';
* const jpzPuzzle = parseJpz(jpzData);
* const unifiedPuzzle = convertJpzToUnified(jpzPuzzle);
* ```
*/
declare function convertJpzToUnified(puzzle: JpzPuzzle): Puzzle;
/**
* Custom error classes for xword-parser
*/
/**
* Base error class for all parsing errors
*/
declare class ParseError extends Error {
readonly code: ErrorCode;
readonly context?: ErrorContext;
constructor(message: string, code?: ErrorCode, context?: ErrorContext, cause?: unknown);
/**
* Determines if this error indicates a format mismatch (file is valid but wrong format)
* vs a real parsing error (file is corrupted or has other issues)
*/
isFormatMismatch(): boolean;
}
/**
* Error thrown when the input format cannot be detected
*/
declare class FormatDetectionError extends ParseError {
constructor(message?: string, context?: ErrorContext, cause?: unknown);
}
/**
* Error thrown when a file is corrupted or invalid
*/
declare class InvalidFileError extends ParseError {
constructor(format: string, message: string, context?: ErrorContext, cause?: unknown);
}
/**
* Error thrown when a puzzle type is not supported
*/
declare class UnsupportedPuzzleTypeError extends ParseError {
constructor(puzzleType: string, context?: ErrorContext, cause?: unknown);
}
/**
* Format-specific error classes
*/
declare class IpuzParseError extends ParseError {
constructor(message: string, code?: ErrorCode, context?: ErrorContext, cause?: unknown);
isFormatMismatch(): boolean;
}
declare class PuzParseError extends ParseError {
constructor(message: string, code?: ErrorCode, context?: ErrorContext, cause?: unknown);
isFormatMismatch(): boolean;
}
declare class JpzParseError extends ParseError {
constructor(message: string, code?: ErrorCode, context?: ErrorContext, cause?: unknown);
isFormatMismatch(): boolean;
}
declare class XdParseError extends ParseError {
constructor(message: string, code?: ErrorCode, context?: ErrorContext, cause?: unknown);
isFormatMismatch(): boolean;
}
/**
* Error thrown when binary data cannot be read or parsed correctly.
* This is used by the BinaryReader class for low-level binary parsing errors.
*/
declare class BinaryParseError extends ParseError {
constructor(message: string, context?: ErrorContext);
}
/**
* Parse a crossword puzzle from various formats (iPUZ, PUZ, JPZ, XD).
* Automatically detects the format and returns a unified puzzle structure.
*
* @param data - The puzzle data as string, Buffer, or ArrayBuffer
* @param options - Optional parsing options
* @param options.filename - Filename hint to improve format detection
* @param options.encoding - Character encoding for text formats (default: 'utf-8')
* @param options.maxGridSize - Maximum allowed grid dimensions
* @returns A unified Puzzle object
* @throws {FormatDetectionError} When the format cannot be detected
* @throws {ParseError} When parsing fails for the detected format
*
* @example
* ```typescript
* import { parse } from 'xword-parser';
* import { readFileSync } from 'fs';
*
* const content = readFileSync('puzzle.puz');
* const puzzle = parse(content, { filename: 'puzzle.puz' });
* console.log(puzzle.title, puzzle.grid.width + 'x' + puzzle.grid.height);
* ```
*/
declare function parse(data: string | Buffer | ArrayBuffer, options?: ParseOptions): Puzzle;
export { BinaryParseError, type CellStyle, CellType, ErrorCode, ErrorContext, FormatDetectionError, InvalidFileError, type IpuzCell, type IpuzClue, IpuzParseError, type IpuzPuzzle, type JpzCell, type JpzClue, type JpzMetadata, JpzParseError, type JpzPuzzle, type JpzWord, ParseError, ParseOptions, type PuzCell, type PuzClue, type PuzMetadata, PuzParseError, type PuzPuzzle, Puzzle, UnsupportedPuzzleTypeError, type XdClue, type XdMetadata, XdParseError, type XdPuzzle, convertIpuzToUnified, convertJpzToUnified, convertPuzToUnified, convertXdToUnified, parse, parseIpuz, parseJpz, parsePuz, parseXd };