@echecs/pgn
Version:
PGN is a parser that is part of the ECHECS project, designed to interpret the PGN (Portable Game Notation) specification.
94 lines • 3.1 kB
JavaScript
/* eslint-disable sort-keys */
import moo from 'moo';
function pickBy(object, predicate) {
return Object.fromEntries(Object.entries(object).filter(([key, value]) => predicate(value, key)));
}
// eslint-disable-next-line import-x/no-named-as-default-member
const lexer = moo.states({
main: {
__: { lineBreaks: true, match: /\s+/ },
comment_line: { match: /;.*$/, value: (s) => s.slice(1).trim() },
comment_multiline: {
lineBreaks: true,
match: /{[^}]*}/,
value: (s) => s
.slice(1, -1)
.replace(/[\n\t]/g, ' ')
.trim(),
},
escape: /^%.*$/,
// --- TAG ---
lbracket: { match: '[', push: 'tag' },
rbracket: { match: ']', pop: 1 },
// --- RESULT ---
result: ['1-0', '0-1', '1/2-1/2', '*'],
// --- MOVE ---
// https://regex101.com/r/zwTzNe/1
san: {
// @ts-expect-error Mismatching types
match: /(?:[KQBNPR]?[a-h]?[1-8]?x?[a-h][1-8]|O-O-O|O-O)(?:=[NBRQ])?[+#]?/,
value: (s) => {
if (['O-O', 'O-O-O'].includes(s)) {
return { castling: true, long: s === 'O-O-O', piece: 'K', to: s };
}
const extractor = /(?<piece>[KQBNPR])?(?<from>[a-h]|[1-8]|[a-h][1-8])?(?<capture>x)?(?<to>[a-h][1-8])(?<promotion>=[NBRQ])?(?<indication>[+#])?/;
const { groups = {} } = s.match(extractor) || {};
return pickBy({
piece: groups.piece || 'P',
from: groups.from,
capture: Boolean(groups.capture),
to: groups.to,
promotion: groups.promotion?.slice(1),
check: Boolean(groups.indication?.includes('+')),
checkmate: Boolean(groups.indication?.includes('#')),
}, Boolean);
},
},
// @ts-expect-error Mismatching types
number: { match: /\d+[.]*/, value: (s) => Number(s.replace(/[.]/g, '')) },
// --- NAG ---
nag_import: [
'!',
'?',
'!!',
'??',
'!?',
'?!',
'□',
'=',
'∞',
'⩲',
'⩱',
'±',
'∓',
'+ −',
'− +',
'⨀',
'○',
'⟳',
'↑',
'→',
'⯹',
'⇆',
'⨁',
],
nag_export: {
match: /\$25[0-5]|\$2[0-4][0-9]|\$1[0-9][0-9]|\$[1-9][0-9]|\$[0-9]/,
value: (s) => s.slice(1),
},
// --- RAV ---
lparen: '(',
rparen: ')',
},
tag: {
__: { lineBreaks: true, match: /\s+/ },
identifier: /[a-zA-Z0-9_]+/,
rbracket: { match: ']', pop: 1 },
value: {
match: /"[^"]*?"/,
value: (s) => s.slice(1, -1).trim(),
},
},
});
export default lexer;
//# sourceMappingURL=lexer.js.map