@randyd45/curp-validation
Version:
a simple package for curp validation
125 lines (111 loc) • 5.35 kB
JavaScript
import {CURPValueError, ExceptionCodes} from "./exceptions.js";
import {CURPChars} from "./enums.js";
import {altisonantes} from "./altisonantes.js";
const VOCALS = 'AEIOU'.split('');
const CONSONANTS = 'BCDFGHJKLMNÑPQRSTVWXYZ'.split('');
const CHARSET = 'AEIOUBCDFGHJKLMNPQRSTVWXYZ'.split('')
const IGNORED_NAMES = ['MARIA', 'MA', 'MA.', 'JOSE', 'J', 'J.'];
const IGNORED_WORDS = ['DA', 'DAS', 'DE', 'DEL', 'DER', 'DI', 'DIE', 'DD', 'EL', 'LA', 'LOS', 'LAS', 'LE', 'LES', 'MAC', 'MC', 'VAN', 'VON', 'Y'];
const IGNORED_COMBINED = [...IGNORED_NAMES, ...IGNORED_WORDS]
const accentMap = {
'Á': 'A', 'À': 'A', 'Ä': 'A', 'Â': 'A', 'Ā': 'A', 'Ă': 'A', 'Ą': 'A',
'É': 'E', 'È': 'E', 'Ë': 'E', 'Ê': 'E', 'Ē': 'E', 'Ĕ': 'E', 'Ę': 'E',
'Í': 'I', 'Ì': 'I', 'Ï': 'I', 'Î': 'I', 'Ī': 'I', 'Ĭ': 'I', 'Į': 'I',
'Ó': 'O', 'Ò': 'O', 'Ö': 'O', 'Ô': 'O', 'Ō': 'O', 'Ŏ': 'O', 'Ő': 'O',
'Ú': 'U', 'Ù': 'U', 'Ü': 'U', 'Û': 'U', 'Ū': 'U', 'Ŭ': 'U', 'Ů': 'U', 'Ű': 'U', 'Ų': 'U',
'Ý': 'Y', 'Ỳ': 'Y', 'Ÿ': 'Y', 'Ŷ': 'Y'
};
export class CURP {
constructor(curp) {
this.curp = curp.toUpperCase();
}
isFormatValid() {
if (this.curp.length !== 18)
return false;
let re = /^([A-Z][AEIOUX][A-Z]{2}\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])[HM](?:AS|B[CS]|C[CLMSH]|D[FG]|G[TR]|HG|JC|M[CNS]|N[ETL]|OC|PL|Q[TR]|S[PLR]|T[CSL]|VZ|YN|ZS)[B-DF-HJ-NP-TV-Z]{3}[A-Z\d])(\d)$/;
return re.test(this.curp);
}
isNameValid(name) {
let pieces = name.toUpperCase().split(" ");
if (pieces.length > 1 && IGNORED_NAMES.includes(pieces[0]))
delete pieces[0];
let name_features = this.preProcessWord(name, IGNORED_COMBINED);
return this.curp[CURPChars.NAME_CHAR] === name_features.letter
&& this.curp[CURPChars.NAME_CONSONANT] === name_features.consonant;
}
isFirstLastnameValid(lastname) {
let curp_start = this.curp.toUpperCase().substring(0, 4);
let lastname_features = this.preProcessWord(lastname, IGNORED_WORDS);
let valid = this.curp[CURPChars.SURNAME_A_CHAR] === lastname_features.letter
&& this.curp[CURPChars.SURNAME_A_CONSONANT] === lastname_features.consonant;
if (valid) {
valid = this.curp[CURPChars.SURNAME_A_VOWEL] === lastname_features.vocal;
if (altisonantes[curp_start]) {
for (let i = 0; i < altisonantes[curp_start].length; i++) {
valid = valid || altisonantes[curp_start][i] === lastname_features.vocal;
}
}
}
return valid;
}
isSecondLastnameValid(lastname) {
let lastname_features = this.preProcessWord(lastname, IGNORED_WORDS);
return this.curp[CURPChars.SURNAME_B_CHAR] === lastname_features.letter
&& this.curp[CURPChars.SURNAME_B_CONSONANT] === lastname_features.consonant;
}
preProcessWord(word, ignored_words) {
let new_word = word.toUpperCase().split('');
for (let i = 0; i < new_word.length; i++) {
if (accentMap[new_word[i]]) {
new_word[i] = accentMap[new_word[i]];
}
else if (new_word[i] === 'Ñ') {
new_word[i] = 'X';
}
else if (!CHARSET.find(item => item === new_word[i])) {
new_word[i] = ' ';
}
}
let pieces = new_word.join('').split(" ");
new_word = pieces.filter(item => !ignored_words.find(iw => iw === item));
new_word.push(pieces[pieces.length - 1]);
new_word = new_word[0];
let features = {
letter: new_word[0],
vocal: undefined,
consonant: undefined,
};
for (let i = 1; i < new_word.length; i++) {
if (!features.vocal && VOCALS.find(item => item === new_word[i])) {
features.vocal = new_word[i];
} else if (!features.consonant && CONSONANTS.find(item => item === new_word[i])) {
features.consonant = new_word[i];
}
if (features.vocal && features.consonant)
return features
}
return new_word;
}
isBirthdayValid(year, month, day) {
if (!(year === parseInt(this.curp[CURPChars.YEAR_0]+ "" + this.curp[CURPChars.YEAR_1])))
return false;
if (!(month === parseInt(this.curp[CURPChars.MONTH_0] + "" + this.curp[CURPChars.MONTH_1])))
return false;
return day === parseInt(this.curp[CURPChars.DAY_0] + "" + this.curp[CURPChars.DAY_1]);
}
extractBirthday(){
let homonym = this.curp[CURPChars.HOMONYMY];
let before_2k = homonym >= '0' && homonym <= '9';
let day = parseInt(this.curp[CURPChars.DAY_0] + this.curp[CURPChars.DAY_1]);
let month = parseInt(this.curp[CURPChars.MONTH_0] + this.curp[CURPChars.MONTH_1]);
let year = parseInt(this.curp[CURPChars.YEAR_0] + this.curp[CURPChars.YEAR_1]);
let century = before_2k ? 19 : 20;
year += century * 100;
year = year > new Date().getFullYear() ? year - 100 : year;
return {
year: String(year).padStart(2, '0'),
month: String(month).padStart(2, '0'),
day: String(day).padStart(2, '0'),
}
}
}