Spaces:
Sleeping
Sleeping
File size: 3,502 Bytes
466436b 502af73 466436b 502af73 466436b 502af73 466436b 502af73 466436b 502af73 466436b 502af73 466436b 502af73 466436b 502af73 466436b 502af73 466436b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | /**
* TGN Parser TypeScript Wrapper
*
* Wraps the jison-generated parser with TypeScript types
*
* Based on lotus project architecture:
* - Use jison npm package for grammar compilation at build time
* - Generate parser to .js file in build phase
* - Use synchronous parsing (no async needed)
* - Works in both browser and Node.js environments
*/
/**
* Parsed move action - represents a single player's action in a round
*/
export interface ParsedMoveAction {
type: "move" | "pass" | "resign";
position?: string; // ab0yz coordinate notation
}
/**
* Parsed move round - contains both black and white moves
*/
export interface ParsedMoveRound {
round: number;
action_black: ParsedMoveAction;
action_white?: ParsedMoveAction;
}
/**
* Parsed game result
*/
export interface ParsedGameResult {
Result: string; // "black win" | "white win" | "draw" | "unknown"
Conquer?: {
n: number;
unit: string; // "points" | "stones"
};
}
/**
* Parsed TGN tags (metadata)
*/
export interface ParsedTags {
Event?: string;
Site?: string;
Date?: string;
Round?: string;
Black?: string;
White?: string;
Result?: string;
Board?: number[]; // [x, y, z] or [x, y]
Handicap?: string;
Rules?: string;
TimeControl?: string;
Annotator?: string;
Application?: string;
[key: string]: string | number[] | ParsedGameResult | undefined;
}
/**
* Parser output structure
*/
export interface TGNParseResult {
tags: ParsedTags;
moves: ParsedMoveRound[] | null;
success: boolean;
}
/**
* Parser error with position information
*/
export class TGNParseError extends Error {
constructor(
message: string,
public line?: number,
public column?: number,
public hash?: any
) {
super(message);
this.name = "TGNParseError";
}
}
// Will be set by initialization code or build process
let parserModule: any = null;
/**
* Set the parser module (called by initialization code)
* This allows the pre-built parser to be used
*/
export function setParserModule(module: any): void {
parserModule = module;
}
/**
* Get the parser module
* Throws error if parser not loaded
*/
function getParser() {
if (!parserModule) {
throw new Error(
"TGN parser not loaded. Please ensure the parser has been built.\n" +
"Run: npm run build:parsers"
);
}
return parserModule;
}
/**
* Parse TGN string and return structured data
* Synchronous parsing (no async needed)
*
* @param tgnString - TGN formatted game notation
* @returns Parsed game data with tags and moves
* @throws TGNParseError if parsing fails
*/
export function parseTGN(tgnString: string): TGNParseResult {
const parser = getParser();
if (!parser.parse) {
throw new Error("TGN parser parse method not available");
}
try {
const result = parser.parse(tgnString);
return result as TGNParseResult;
} catch (error: any) {
// Wrap jison errors with our custom error type
throw new TGNParseError(
error.message || "Unknown parse error",
error.hash?.line,
error.hash?.loc?.first_column,
error.hash
);
}
}
/**
* Validate TGN string without fully parsing
* Synchronous validation (no async needed)
*
* @param tgnString - TGN formatted game notation
* @returns Object with valid flag and error message if invalid
*/
export function validateTGN(tgnString: string): { valid: boolean; error?: string } {
try {
parseTGN(tgnString);
return { valid: true };
} catch (error: any) {
return {
valid: false,
error: error.message || "Unknown validation error"
};
}
}
|