UNPKG

@randsum/notation

Version:

Dice notation parser and types for the @randsum ecosystem

81 lines (64 loc) 2.87 kB
import type { RerollOptions } from '../types' import { formatComparisonNotation, hasConditions, parseComparisonNotation } from '../comparison' import { formatHumanList } from '../formatHumanList' import { type NotationSchema, defineNotationSchema } from '../schema' const rerollPattern = /[Rr]\{((?:>=|<=|>|<|=)?\d+(?:,(?:>=|<=|>|<|=)?\d+)*)\}(\d+)?/g export const rerollSchema: NotationSchema<RerollOptions> = defineNotationSchema<RerollOptions>({ name: 'reroll', priority: 40, pattern: /[Rr]\{((?:>=|<=|>|<|=)?\d+(?:,(?:>=|<=|>|<|=)?\d+)*)\}(\d+)?/, parse: notation => { const matches = Array.from(notation.matchAll(rerollPattern)) if (matches.length === 0) return {} const reroll: RerollOptions = {} for (const match of matches) { const conditions = match[1] const maxCount = match[2] ? Number(match[2]) : undefined if (maxCount) { reroll.max = maxCount } if (conditions) { const parsed = parseComparisonNotation(conditions) if (parsed.greaterThan !== undefined) reroll.greaterThan = parsed.greaterThan if (parsed.greaterThanOrEqual !== undefined) reroll.greaterThanOrEqual = parsed.greaterThanOrEqual if (parsed.lessThan !== undefined) reroll.lessThan = parsed.lessThan if (parsed.lessThanOrEqual !== undefined) reroll.lessThanOrEqual = parsed.lessThanOrEqual if (parsed.exact) reroll.exact = [...(reroll.exact ?? []), ...parsed.exact] } } return hasConditions(reroll) || reroll.max !== undefined ? { reroll } : {} }, toNotation: options => { const parts = formatComparisonNotation(options) if (!parts.length) return undefined const maxSuffix = options.max ? `${options.max}` : '' return `R{${parts.join(',')}}${maxSuffix}` }, toDescription: options => { const { exact, greaterThan, greaterThanOrEqual, lessThan, lessThanOrEqual, max } = options const rerollList: string[] = [] if (exact) { exact.forEach(roll => rerollList.push(`${roll}`)) } const greaterLessList: string[] = [] if (greaterThanOrEqual !== undefined) { greaterLessList.push(`greater than or equal to ${greaterThanOrEqual}`) } if (greaterThan !== undefined) { greaterLessList.push(`greater than ${greaterThan}`) } if (lessThanOrEqual !== undefined) { greaterLessList.push(`less than or equal to ${lessThanOrEqual}`) } if (lessThan !== undefined) { greaterLessList.push(`less than ${lessThan}`) } const exactList = formatHumanList(rerollList.map(Number)) const greaterLess = greaterLessList.join(' and ') const conditions = [exactList, greaterLess].filter(Boolean).join(', ') if (!conditions) return [] const maxText = max !== undefined ? ` (up to ${max} times)` : '' return [`Reroll ${conditions}${maxText}`] } })