aamva-parser
Version:
Plugin to parse AAMVA Drivers License Data from the PDF417 barcode
194 lines (193 loc) • 6.23 kB
JavaScript
import { Regex } from "../utils/regex";
import { FieldMapper } from "./fieldMapping";
import { IssuingCountry } from "../enums/issuingCountry";
import { Gender } from "../enums/gender";
import { EyeColor } from "../enums/eyeColor";
import { HairColor } from "../enums/hairColor";
import { Truncation } from "../enums/truncation";
import { NameSuffix } from "../enums/nameSuffix";
export class FieldParser {
constructor(data, fieldMapper = new FieldMapper()) {
this.regex = new Regex();
this.data = data;
this.fieldMapper = fieldMapper;
}
parseString(key) {
const identifier = this.fieldMapper.fieldFor(key);
return this.regex.firstMatch(`${identifier}(.+)\\b`, this.data);
}
parseDouble(key) {
const identifier = this.fieldMapper.fieldFor(key);
const result = this.regex.firstMatch(`${identifier}(\\w+)\\b`, this.data);
return result ? parseFloat(result) : null;
}
parseDate(field) {
const dateString = this.parseString(field);
if (!dateString || dateString.length !== 8)
return null; // Ensure the string is 8 characters long
const month = parseInt(dateString.slice(0, 2), 10);
const day = parseInt(dateString.slice(2, 4), 10);
const year = parseInt(dateString.slice(4, 8), 10);
// Validate parsed components
if (isNaN(month) || isNaN(day) || isNaN(year))
return null;
// JavaScript Date constructor: new Date(year, monthIndex, day)
// monthIndex is zero-based, so we subtract 1 from the month
const parsedDate = new Date(year, month - 1, day);
return isNaN(parsedDate.getTime()) ? null : parsedDate;
}
getDateFormat() {
return "MMddyyyy";
}
parseFirstName() {
return this.parseString("firstName");
}
parseLastName() {
return this.parseString("lastName");
}
parseMiddleName() {
return this.parseString("middleName");
}
parseExpirationDate() {
return this.parseDate("expirationDate");
}
parseIsExpired() {
return (this.parseExpirationDate() !== null &&
new Date() > this.parseExpirationDate());
}
parseIssueDate() {
return this.parseDate("issueDate");
}
parseDateOfBirth() {
return this.parseDate("dateOfBirth");
}
parseCountry() {
const country = this.parseString("country");
switch (country) {
case "USA":
return IssuingCountry.UnitedStates;
case "CAN":
return IssuingCountry.Canada;
default:
return IssuingCountry.Unknown;
}
}
parseTruncationStatus(field) {
const truncation = this.parseString(field);
switch (truncation) {
case "T":
return Truncation.Truncated;
case "N":
return Truncation.None;
default:
return Truncation.Unknown;
}
}
parseGender() {
const gender = this.parseString("gender");
switch (gender) {
case "1":
return Gender.Male;
case "2":
return Gender.Female;
default:
return Gender.Other;
}
}
parseEyeColor() {
const color = this.parseString("eyeColor");
switch (color) {
case "BLK":
return EyeColor.Black;
case "BLU":
return EyeColor.Blue;
case "BRO":
return EyeColor.Brown;
case "GRY":
return EyeColor.Gray;
case "GRN":
return EyeColor.Green;
case "HAZ":
return EyeColor.Hazel;
case "MAR":
return EyeColor.Maroon;
case "PNK":
return EyeColor.Pink;
case "DIC":
return EyeColor.Dichromatic;
default:
return EyeColor.Unknown;
}
}
parseNameSuffix() {
const suffix = this.parseString("suffix");
switch (suffix) {
case "JR":
return NameSuffix.Junior;
case "SR":
return NameSuffix.Senior;
case "1ST":
case "I":
return NameSuffix.First;
case "2ND":
case "II":
return NameSuffix.Second;
case "3RD":
case "III":
return NameSuffix.Third;
case "4TH":
case "IV":
return NameSuffix.Fourth;
case "5TH":
case "V":
return NameSuffix.Fifth;
case "6TH":
case "VI":
return NameSuffix.Sixth;
case "7TH":
case "VII":
return NameSuffix.Seventh;
case "8TH":
case "VIII":
return NameSuffix.Eighth;
case "9TH":
case "IX":
return NameSuffix.Ninth;
default:
return NameSuffix.Unknown;
}
}
parseHairColor() {
const color = this.parseString("hairColor");
switch (color) {
case "BAL":
return HairColor.Bald;
case "BLK":
return HairColor.Black;
case "BLN":
return HairColor.Blond;
case "BRO":
return HairColor.Brown;
case "GRY":
return HairColor.Grey;
case "RED":
return HairColor.Red;
case "SDY":
return HairColor.Sandy;
case "WHI":
return HairColor.White;
default:
return HairColor.Unknown;
}
}
parseHeight() {
const heightString = this.parseString("height");
const height = this.parseDouble("height");
if (!heightString || !height)
return null;
return heightString.includes("cm")
? Math.round(height * FieldParser.INCHES_PER_CENTIMETER)
: height;
}
}
FieldParser.INCHES_PER_CENTIMETER = 0.393701;