import { isRollParserError, roll, type RollParserErrorCode } from 'roll-parser';
const MESSAGES: Partial<Record<RollParserErrorCode, string>> = {
DICE_LIMIT_EXCEEDED: 'That is too many dice.',
DIVISION_BY_ZERO: 'Cannot divide by zero.',
UNEXPECTED_CHARACTER: 'That is not valid dice notation.',
};
try {
roll(userInput);
} catch (error) {
if (isRollParserError(error)) {
reply(MESSAGES[error.code] ?? error.message);
}
}
Programmatic identifier carried by every roll-parser error, grouped by the stage that raises it. The runtime list behind this union is exported as ROLL_PARSER_ERROR_CODES.
Lexer:
UNEXPECTED_CHARACTER,UNEXPECTED_IDENTIFIERParser:
UNEXPECTED_TOKEN,UNEXPECTED_END,EXPECTED_TOKEN,INVALID_KEEP_DROP_TARGET,INVALID_EXPLODE_TARGET,INVALID_REROLL_TARGET,INVALID_SUCCESS_COUNT_TARGET,INVALID_SORT_TARGET,INVALID_CRIT_THRESHOLD_TARGET,INVALID_DIE_BOUND_TARGET,NESTED_VERSUS,INVALID_FUNCTION_ARITY,AMBIGUOUS_DICE_CHAIN,MAX_DEPTH_EXCEEDEDEvaluator:
INVALID_DICE_COUNT,INVALID_DICE_SIDES,DICE_LIMIT_EXCEEDED,DIVISION_BY_ZERO,MODULO_BY_ZERO,UNKNOWN_OPERATOR,UNKNOWN_NODE_TYPE,INVALID_KEEP_DROP_COUNT,EXPLODE_LIMIT_EXCEEDED,REROLL_LIMIT_EXCEEDED,INVALID_THRESHOLD,NESTED_VERSUS,UNKNOWN_FUNCTION,UNDEFINED_VARIABLE,INVALID_VARIABLE_VALUE,NON_FINITE_RESULTRNG:
INCOMPATIBLE_RNG_STATEOptions:
INVALID_EVALUATION_LIMIT— raised before evaluation begins, from the options object rather than from the notation, so it carries no span.Input:
INVALID_NOTATION_TYPE— raised before lexing, whennotationis not a string, so it carries no span either.New codes are only ever introduced in a minor release, never a patch. Treat the union as open when you switch over it: give the switch a
defaultarm rather than relying on exhaustiveness, or a minor upgrade turns a new code into a silent fall-through.