UNPKG

aamva-parser

Version:

Parse AAMVA PDF417 barcode data from driver's licenses and ID cards

807 lines (773 loc) 24.1 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { EyeColor: () => EyeColor, Gender: () => Gender, GetVersion: () => GetVersion, HairColor: () => HairColor, IsExpired: () => IsExpired, IssuingCountry: () => IssuingCountry, NameSuffix: () => NameSuffix, Parse: () => Parse, Truncation: () => Truncation }); module.exports = __toCommonJS(index_exports); // src/utils/regex.ts var Regex = class { firstMatch(pattern, data) { try { const regex = new RegExp(pattern, "i"); const matches = regex.exec(data); if (!matches || matches.length < 2) { return null; } const matchedGroup = matches[1].trim(); return matchedGroup.length > 0 ? matchedGroup : null; } catch (error) { return null; } } }; // src/mappers/fieldMapping.ts var FieldMapper = class { constructor() { // A list of AAMVA field designator mappings (e.g. "firstName" => "DAC") this._fields = { firstName: "DAC", lastName: "DCS", middleName: "DAD", expirationDate: "DBA", issueDate: "DBD", dateOfBirth: "DBB", gender: "DBC", eyeColor: "DAY", height: "DAU", streetAddress: "DAG", city: "DAI", state: "DAJ", postalCode: "DAK", driversLicenseId: "DAQ", documentId: "DCF", country: "DCG", middleNameTruncation: "DDG", firstNameTruncation: "DDF", lastNameTruncation: "DDE", streetAddressSupplement: "DAH", hairColor: "DAZ", placeOfBirth: "DCI", auditInformation: "DCJ", inventoryControlNumber: "DCK", lastNameAlias: "DBN", firstNameAlias: "DBG", suffixAlias: "DBS", suffix: "DCU", weight: "DAW" }; } // Getter for fields get fields() { return this._fields; } // Setter for fields set fields(newFields) { this._fields = newFields; } /** * Determine the AAMVA field designator for a particular human-readable key. * * @param key - The human-readable key * @returns The AAMVA field designator */ fieldFor(key) { return this.fields[key] || ""; } }; // src/enums/issuingCountry.ts var IssuingCountry = /* @__PURE__ */ ((IssuingCountry2) => { IssuingCountry2["UnitedStates"] = "United States"; IssuingCountry2["Canada"] = "Canada"; IssuingCountry2["Unknown"] = "Unknown"; return IssuingCountry2; })(IssuingCountry || {}); // src/enums/gender.ts var Gender = /* @__PURE__ */ ((Gender2) => { Gender2["Male"] = "Male"; Gender2["Female"] = "Female"; Gender2["Other"] = "Other"; Gender2["Unknown"] = "Unknown"; return Gender2; })(Gender || {}); // src/enums/eyeColor.ts var EyeColor = /* @__PURE__ */ ((EyeColor2) => { EyeColor2["Black"] = "Black"; EyeColor2["Blue"] = "Blue"; EyeColor2["Brown"] = "Brown"; EyeColor2["Gray"] = "Gray"; EyeColor2["Green"] = "Green"; EyeColor2["Hazel"] = "Hazel"; EyeColor2["Maroon"] = "Maroon"; EyeColor2["Pink"] = "Pink"; EyeColor2["Dichromatic"] = "Dichromatic"; EyeColor2["Unknown"] = "Unknown"; return EyeColor2; })(EyeColor || {}); // src/enums/hairColor.ts var HairColor = /* @__PURE__ */ ((HairColor2) => { HairColor2["Bald"] = "Bald"; HairColor2["Black"] = "Black"; HairColor2["Blond"] = "Blond"; HairColor2["Brown"] = "Brown"; HairColor2["Grey"] = "Grey"; HairColor2["Red"] = "Red"; HairColor2["Sandy"] = "Sandy"; HairColor2["White"] = "White"; HairColor2["Unknown"] = "Unknown"; return HairColor2; })(HairColor || {}); // src/enums/truncation.ts var Truncation = /* @__PURE__ */ ((Truncation2) => { Truncation2["Truncated"] = "Truncated"; Truncation2["None"] = "None"; Truncation2["Unknown"] = "Unknown"; return Truncation2; })(Truncation || {}); // src/enums/nameSuffix.ts var NameSuffix = /* @__PURE__ */ ((NameSuffix2) => { NameSuffix2["Junior"] = "Junior"; NameSuffix2["Senior"] = "Senior"; NameSuffix2["First"] = "First"; NameSuffix2["Second"] = "Second"; NameSuffix2["Third"] = "Third"; NameSuffix2["Fourth"] = "Fourth"; NameSuffix2["Fifth"] = "Fifth"; NameSuffix2["Sixth"] = "Sixth"; NameSuffix2["Seventh"] = "Seventh"; NameSuffix2["Eighth"] = "Eighth"; NameSuffix2["Ninth"] = "Ninth"; NameSuffix2["Unknown"] = "Unknown"; return NameSuffix2; })(NameSuffix || {}); // src/mappers/fieldParser.ts var _FieldParser = 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; const month = parseInt(dateString.slice(0, 2), 10); const day = parseInt(dateString.slice(2, 4), 10); const year = parseInt(dateString.slice(4, 8), 10); if (isNaN(month) || isNaN(day) || isNaN(year)) return null; const parsedDate = new Date(year, month - 1, day); return isNaN(parsedDate.getTime()) ? null : parsedDate; } parseFirstName() { return this.parseString("firstName"); } parseLastName() { return this.parseString("lastName"); } parseMiddleName() { return this.parseString("middleName"); } parseExpirationDate() { return this.parseDate("expirationDate"); } parseIsExpired() { const expirationDate = this.parseExpirationDate(); return expirationDate !== null && /* @__PURE__ */ new Date() > expirationDate; } parseIssueDate() { return this.parseDate("issueDate"); } parseDateOfBirth() { return this.parseDate("dateOfBirth"); } parseCountry() { const country = this.parseString("country"); switch (country) { case "USA": return "United States" /* UnitedStates */; case "CAN": return "Canada" /* Canada */; default: return "Unknown" /* Unknown */; } } parseTruncationStatus(field) { const truncation = this.parseString(field); switch (truncation) { case "T": return "Truncated" /* Truncated */; case "N": return "None" /* None */; default: return "Unknown" /* Unknown */; } } parseGender() { const gender = this.parseString("gender"); switch (gender) { case "1": return "Male" /* Male */; case "2": return "Female" /* Female */; default: return "Other" /* Other */; } } parseEyeColor() { const color = this.parseString("eyeColor"); switch (color) { case "BLK": return "Black" /* Black */; case "BLU": return "Blue" /* Blue */; case "BRO": return "Brown" /* Brown */; case "GRY": return "Gray" /* Gray */; case "GRN": return "Green" /* Green */; case "HAZ": return "Hazel" /* Hazel */; case "MAR": return "Maroon" /* Maroon */; case "PNK": return "Pink" /* Pink */; case "DIC": return "Dichromatic" /* Dichromatic */; default: return "Unknown" /* Unknown */; } } parseNameSuffix() { const suffix = this.parseString("suffix"); switch (suffix) { case "JR": return "Junior" /* Junior */; case "SR": return "Senior" /* Senior */; case "1ST": case "I": return "First" /* First */; case "2ND": case "II": return "Second" /* Second */; case "3RD": case "III": return "Third" /* Third */; case "4TH": case "IV": return "Fourth" /* Fourth */; case "5TH": case "V": return "Fifth" /* Fifth */; case "6TH": case "VI": return "Sixth" /* Sixth */; case "7TH": case "VII": return "Seventh" /* Seventh */; case "8TH": case "VIII": return "Eighth" /* Eighth */; case "9TH": case "IX": return "Ninth" /* Ninth */; default: return "Unknown" /* Unknown */; } } parseHairColor() { const color = this.parseString("hairColor"); switch (color) { case "BAL": return "Bald" /* Bald */; case "BLK": return "Black" /* Black */; case "BLN": return "Blond" /* Blond */; case "BRO": return "Brown" /* Brown */; case "GRY": return "Grey" /* Grey */; case "RED": return "Red" /* Red */; case "SDY": return "Sandy" /* Sandy */; case "WHI": return "White" /* White */; default: return "Unknown" /* 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; var FieldParser = _FieldParser; // src/mappers/v1/versionOneFieldMapper.ts var VersionOneFieldMapper = class { constructor() { this.fields = {}; const fieldMapper = new FieldMapper(); this.fields = __spreadValues({}, fieldMapper.fields); this.fields["driversLicenseId"] = "DBJ"; this.fields["lastName"] = "DAB"; this.fields["driverLicenseName"] = "DAA"; } fieldFor(key) { return this.fields[key] || key; } }; // src/mappers/v1/versionOneFieldParser.ts var VersionOneFieldParser = class extends FieldParser { constructor(data) { super(data, new VersionOneFieldMapper()); } parseFirstName() { const firstName = this.parseString("firstName"); return firstName || this.parseDriverLicenseName("firstName"); } parseLastName() { const lastName = this.parseString("lastName"); return lastName || this.parseDriverLicenseName("lastName"); } parseMiddleName() { const middleName = this.parseString("middleName"); return middleName || this.parseDriverLicenseName("middleName"); } parseHeight() { const heightInFeetAndInches = this.parseString("height"); if (!heightInFeetAndInches) return null; const height = this.regex.firstMatch("([0-9]{1})", heightInFeetAndInches); const inches = this.regex.firstMatch("[0-9]{1}([0-9]{2})", heightInFeetAndInches); if (!height || !inches) return null; const calculatedHeight = parseFloat(height) * 12 + parseFloat(inches); if (heightInFeetAndInches.includes("cm")) { return Math.round(calculatedHeight * FieldParser.INCHES_PER_CENTIMETER); } else { return calculatedHeight; } } parseNameSuffix() { let suffix = this.parseString("suffix") || this.parseDriverLicenseName("suffix"); if (!suffix) return "Unknown" /* Unknown */; switch (suffix) { case "JR": return "Junior" /* Junior */; case "SR": return "Senior" /* Senior */; case "1ST": case "I": return "First" /* First */; case "2ND": case "II": return "Second" /* Second */; case "3RD": case "III": return "Third" /* Third */; case "4TH": case "IV": return "Fourth" /* Fourth */; case "5TH": case "V": return "Fifth" /* Fifth */; case "6TH": case "VI": return "Sixth" /* Sixth */; case "7TH": case "VII": return "Seventh" /* Seventh */; case "8TH": case "VIII": return "Eighth" /* Eighth */; case "9TH": case "IX": return "Ninth" /* Ninth */; default: return "Unknown" /* Unknown */; } } parseDriverLicenseName(key) { const driverLicenseName = this.parseString("driverLicenseName"); if (!driverLicenseName) return null; const namePieces = driverLicenseName.split(","); switch (key) { case "lastName": return namePieces[0] || null; case "firstName": return namePieces[1] || null; case "middleName": return namePieces[2] || null; case "suffix": return namePieces[3] || null; default: return null; } } }; // src/mappers/v2/versionTwoFieldMapper.ts var VersionTwoFieldMapper = class { constructor() { this.fields = {}; const fieldMapper = new FieldMapper(); this.fields = __spreadValues({}, fieldMapper.fields); this.fields["firstName"] = "DCT"; } fieldFor(key) { return this.fields[key] || key; } }; // src/mappers/v2/versionTwoFieldParser.ts var VersionTwoFieldParser = class extends FieldParser { constructor(data) { super(data, new VersionTwoFieldMapper()); } }; // src/mappers/v3/versionThreeFieldMapper.ts var VersionThreeFieldMapper = class { constructor() { this.fields = {}; const fieldMapper = new FieldMapper(); this.fields = __spreadValues({}, fieldMapper.fields); this.fields["firstName"] = "DCT"; } fieldFor(key) { return this.fields[key] || key; } }; // src/mappers/v3/versionThreeFieldParser.ts var VersionThreeFieldParser = class extends FieldParser { constructor(data) { super(data, new VersionThreeFieldMapper()); } }; // src/mappers/v4/versionFourFieldMapper.ts var VersionFourFieldMapper = class { constructor() { this.fields = {}; const fieldMapper = new FieldMapper(); this.fields = __spreadValues({}, fieldMapper.fields); } fieldFor(key) { return this.fields[key] || key; } }; // src/mappers/v4/versionFourFieldParser.ts var VersionFourFieldParser = class extends FieldParser { constructor(data) { super(data, new VersionFourFieldMapper()); } }; // src/mappers/v5/versionFiveFieldMapper.ts var VersionFiveFieldMapper = class { constructor() { this.fields = {}; const fieldMapper = new FieldMapper(); this.fields = __spreadValues({}, fieldMapper.fields); } fieldFor(key) { return this.fields[key] || key; } }; // src/mappers/v5/versionFiveFieldParser.ts var VersionFiveFieldParser = class extends FieldParser { constructor(data) { super(data, new VersionFiveFieldMapper()); } }; // src/mappers/v6/versionSixFieldMapper.ts var VersionSixFieldMapper = class { constructor() { this.fields = {}; const fieldMapper = new FieldMapper(); this.fields = __spreadValues({}, fieldMapper.fields); } fieldFor(key) { return this.fields[key] || key; } }; // src/mappers/v6/versionSixFieldParser.ts var VersionSixFieldParser = class extends FieldParser { constructor(data) { super(data, new VersionSixFieldMapper()); } }; // src/mappers/v7/versionSevenFieldMapper.ts var VersionSevenFieldMapper = class { constructor() { this.fields = {}; const fieldMapper = new FieldMapper(); this.fields = __spreadValues({}, fieldMapper.fields); } fieldFor(key) { return this.fields[key] || key; } }; // src/mappers/v7/versionSevenFieldParser.ts var VersionSevenFieldParser = class extends FieldParser { constructor(data) { super(data, new VersionSevenFieldMapper()); } }; // src/mappers/v8/versionEightFieldMapper.ts var VersionEightFieldMapper = class { constructor() { this.fields = {}; const fieldMapper = new FieldMapper(); this.fields = __spreadValues({}, fieldMapper.fields); } fieldFor(key) { return this.fields[key] || key; } }; // src/mappers/v8/versionEightFieldParser.ts var VersionEightFieldParser = class extends FieldParser { constructor(data) { super(data, new VersionEightFieldMapper()); } }; // src/mappers/v9/versionNineFieldMapper.ts var VersionNineFieldMapper = class { constructor() { this.fields = {}; const fieldMapper = new FieldMapper(); this.fields = __spreadValues({}, fieldMapper.fields); } fieldFor(key) { return this.fields[key] || key; } }; // src/mappers/v9/versionNineFieldParser.ts var VersionNineFieldParser = class extends FieldParser { constructor(data) { super(data, new VersionNineFieldMapper()); } }; // src/mappers/v10/versionTenFieldMapper.ts var VersionTenFieldMapper = class { constructor() { this.fields = {}; const fieldMapper = new FieldMapper(); this.fields = __spreadValues({}, fieldMapper.fields); } fieldFor(key) { return this.fields[key] || key; } }; // src/mappers/v10/versionTenFieldParser.ts var VersionTenFieldParser = class extends FieldParser { constructor(data) { super(data, new VersionTenFieldMapper()); } }; // src/models/license.ts var License = class { constructor(data) { this.firstName = null; this.lastName = null; this.middleName = null; this.expirationDate = null; this.issueDate = null; this.dateOfBirth = null; this.gender = "Unknown" /* Unknown */; this.eyeColor = "Unknown" /* Unknown */; this.height = null; this.streetAddress = null; this.city = null; this.state = null; this.postalCode = null; this.driversLicenseId = null; this.documentId = null; this.country = "Unknown" /* Unknown */; this.middleNameTruncation = "None" /* None */; this.firstNameTruncation = "None" /* None */; this.lastNameTruncation = "None" /* None */; this.streetAddressSupplement = null; this.hairColor = "Unknown" /* Unknown */; this.placeOfBirth = null; this.auditInformation = null; this.inventoryControlNumber = null; this.lastNameAlias = null; this.firstNameAlias = null; this.suffixAlias = null; this.suffix = "Unknown" /* Unknown */; this.version = null; this.pdf417 = null; Object.assign(this, data); } isExpired() { return this.expirationDate !== null && /* @__PURE__ */ new Date() > this.expirationDate; } hasBeenIssued() { return this.issueDate !== null && /* @__PURE__ */ new Date() > this.issueDate; } isAcceptable() { return !this.isExpired() && this.hasBeenIssued() && this.expirationDate !== null && this.lastName !== null && this.firstName !== null && this.middleName !== null && this.issueDate !== null && this.dateOfBirth !== null && this.height !== null && this.streetAddress !== null && this.city !== null && this.state !== null && this.postalCode !== null && this.documentId !== null; } }; // src/classes/parser.ts var LicenseParser = class { constructor(data) { this.regex = new Regex(); this.data = this.cleanAndFormatString(data); this.fieldParser = new FieldParser(data); } cleanAndFormatString(data) { data = data.replace(/\u001e/g, "").replace(/\r/g, ""); const lines = data.split("\n"); const cleanedLines = lines.map((line) => line.trim()).filter((line) => line.length > 0); data = cleanedLines.join("\n"); if (!data.startsWith("@")) { data = "@\n" + data; } return data; } parse() { this.fieldParser = this.versionBasedFieldParsing(this.parseVersion()); const licenseData = { firstName: this.fieldParser.parseFirstName(), lastName: this.fieldParser.parseLastName(), middleName: this.fieldParser.parseMiddleName(), expirationDate: this.fieldParser.parseExpirationDate(), issueDate: this.fieldParser.parseIssueDate(), dateOfBirth: this.fieldParser.parseDateOfBirth(), gender: this.fieldParser.parseGender(), eyeColor: this.fieldParser.parseEyeColor(), height: this.fieldParser.parseHeight(), streetAddress: this.fieldParser.parseString("streetAddress"), city: this.fieldParser.parseString("city"), state: this.fieldParser.parseString("state"), postalCode: this.fieldParser.parseString("postalCode"), driversLicenseId: this.fieldParser.parseString("driversLicenseId"), documentId: this.fieldParser.parseString("documentId"), country: this.fieldParser.parseCountry(), middleNameTruncation: this.fieldParser.parseTruncationStatus("middleNameTruncation"), firstNameTruncation: this.fieldParser.parseTruncationStatus("firstNameTruncation"), lastNameTruncation: this.fieldParser.parseTruncationStatus("lastNameTruncation"), streetAddressSupplement: this.fieldParser.parseString("streetAddressSupplement"), hairColor: this.fieldParser.parseHairColor(), placeOfBirth: this.fieldParser.parseString("placeOfBirth"), auditInformation: this.fieldParser.parseString("auditInformation"), inventoryControlNumber: this.fieldParser.parseString("inventoryControlNumber"), lastNameAlias: this.fieldParser.parseString("lastNameAlias"), firstNameAlias: this.fieldParser.parseString("firstNameAlias"), suffixAlias: this.fieldParser.parseString("suffixAlias"), suffix: this.fieldParser.parseNameSuffix(), version: this.parseVersion(), pdf417: this.data, expired: this.fieldParser.parseIsExpired(), weight: this.fieldParser.parseString("weight") }; return new License(licenseData); } parseVersion() { return this.regex.firstMatch("\\d{6}(\\d{2})\\w+", this.data); } versionBasedFieldParsing(version) { const defaultParser = new FieldParser(this.data); if (!version) return defaultParser; switch (version) { case "01": return new VersionOneFieldParser(this.data); case "02": return new VersionTwoFieldParser(this.data); case "03": return new VersionThreeFieldParser(this.data); case "04": return new VersionFourFieldParser(this.data); case "05": return new VersionFiveFieldParser(this.data); case "06": return new VersionSixFieldParser(this.data); case "07": return new VersionSevenFieldParser(this.data); case "08": return new VersionEightFieldParser(this.data); case "09": return new VersionNineFieldParser(this.data); case "10": return new VersionTenFieldParser(this.data); default: return defaultParser; } } isExpired() { const expirationDate = this.fieldParser.parseExpirationDate(); return expirationDate !== null && /* @__PURE__ */ new Date() > expirationDate; } }; // src/index.ts function Parse(barcode) { const parser = new LicenseParser(barcode); return parser.parse(); } function GetVersion(barcode) { const parser = new LicenseParser(barcode); return parser.parseVersion(); } function IsExpired(barcode) { const parser = new LicenseParser(barcode); return parser.isExpired(); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { EyeColor, Gender, GetVersion, HairColor, IsExpired, IssuingCountry, NameSuffix, Parse, Truncation });