aamva-parser
Version:
Parse AAMVA PDF417 barcode data from driver's licenses and ID cards
807 lines (773 loc) • 24.1 kB
JavaScript
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
});