A validação ficou muito boa.
Um detalhe que percebi, é que na função toValue não precisa fazer o teste pra retornar parseInt se for número. Pode sempre fazer a conta do c.charCodeAt(0) - 48, pois os números ficarão com o valor correto. Do ponto de vista performance não sei se influencia em algo.
E vale lembrar que as letras precisam estar em maiúscula, pois o ASCII das minúsculas dariam conta errada. Mas aí, se a pessoa tentou validar com minúscula, tem que dar erro mesmo.