nrb-qr-parser
Version:
Reads QR Code string from Malawi Registration National Bureau Identification document and converts it to a json format
253 lines (252 loc) • 9.16 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseNrbQr = void 0;
const util_1 = require("./util");
var Attribute;
(function (Attribute) {
Attribute["GIVEN_NAME"] = "given_name";
Attribute["FAMILY_NAME"] = "family_name";
Attribute["BIRTHDATE"] = "birthdate";
Attribute["GENDER"] = "gender";
Attribute["NATIONAL_ID"] = "identifier";
Attribute["REGISTRATION_DATE"] = "registration_date";
Attribute["REGISTRATION_TA"] = "registration_ta";
Attribute["REGISTRATION_DISTRICT"] = "registration_district";
Attribute["REGISTRATION_VILLAGE"] = "registration_village";
Attribute["MACHINE_READABLE_ZONE"] = "machine_readable_zone";
})(Attribute || (Attribute = {}));
const SUPPORTED_DOCS = {
'01': {
type: "National registration receipt",
model: [
[
Attribute.REGISTRATION_DISTRICT,
(str) => str,
(str) => (0, util_1.isGeneralString)(str), true
],
[
Attribute.REGISTRATION_DATE,
(str) => (0, util_1.formatDate)(str),
(str) => (0, util_1.isDatePattern)(str), true
],
[
Attribute.REGISTRATION_TA,
(str) => str,
(str) => (0, util_1.isGeneralString)(str), true
],
[
Attribute.REGISTRATION_VILLAGE,
(str) => str,
(str) => (0, util_1.isGeneralString)(str), true
],
[
Attribute.FAMILY_NAME,
(str) => (0, util_1.toSentenceCase)(str),
(str) => (0, util_1.isFullName)(str), true
],
[
Attribute.GIVEN_NAME,
(str) => (0, util_1.toSentenceCase)(str),
(str) => (0, util_1.isFullName)(str), true
],
[
Attribute.NATIONAL_ID,
(str) => str,
(str) => (0, util_1.isValidNationalID)(str)
],
[
Attribute.GENDER,
(str) => (0, util_1.formatGender)(str),
(str) => (0, util_1.isGender)(str)
],
[
Attribute.BIRTHDATE,
(str) => (0, util_1.formatDate)(str),
(str) => (0, util_1.isDatePattern)(str)
]
]
},
'03': {
type: 'Malawi National ID',
model: [
[
Attribute.MACHINE_READABLE_ZONE,
(str) => str,
(str) => (0, util_1.isMachineReadableZone)(str), true
],
[
Attribute.FAMILY_NAME,
(str) => str,
(str) => (0, util_1.isValidNationalIDName)(str), true
],
[
Attribute.NATIONAL_ID,
(str) => str,
(str, dataMap) => {
return (0, util_1.isValidNationalID)(str) &&
// Verify the value is actually a NationalID by checking the machine reable zone..
// These values need to Match!
new RegExp(str).test(dataMap?.[Attribute.MACHINE_READABLE_ZONE]);
}, true
],
[
Attribute.GIVEN_NAME,
(str) => {
// For Given Names which appear as JOHN, NIXON
const fmt1 = `${str}`.match(/(\w*),\s*\w+/i);
if (fmt1 && fmt1.length)
return fmt1[1];
// For GivenNames which appear as NIXONMale or YENSIFEMALE
const fmt2 = `${str}`.match(/([A-Z][a-zA-Z'’-]+)(Male|Female)$/);
if (fmt2 && fmt2.length)
return fmt2[1];
return str;
},
(str) => (0, util_1.isValidNationalIDName)(str)
],
[
Attribute.GENDER,
(str) => (0, util_1.formatGender)(str),
(str) => (0, util_1.isGender)(str), true
],
[
Attribute.BIRTHDATE,
(str) => (0, util_1.formatDate)(str),
(str) => (0, util_1.isDatePattern)(str), true
],
[
Attribute.REGISTRATION_DATE,
(str) => (0, util_1.formatDate)(str),
(str) => (0, util_1.isDatePattern)(str), true
]
]
},
'04': {
type: 'Birth certificate',
model: [
[
Attribute.NATIONAL_ID,
(str) => str,
(str) => (0, util_1.isValidNationalID)(str), true
],
[
Attribute.GIVEN_NAME,
(str) => (0, util_1.toSentenceCase)(str.split(' ')[0]),
(str) => (0, util_1.isFullName)(str)
],
[
Attribute.FAMILY_NAME,
(str) => (0, util_1.toSentenceCase)(str.split(' ').reduce((_, c) => c, '')),
(str) => (0, util_1.isFullName)(str), true
],
[
Attribute.BIRTHDATE,
(str) => (0, util_1.formatDate)(str),
(str) => (0, util_1.isDatePattern)(str), true
],
[
Attribute.GENDER,
(str) => (0, util_1.formatGender)(str),
(str) => (0, util_1.isGender)(str)
]
]
},
'05': {
type: 'Death certificate',
model: [
[
Attribute.NATIONAL_ID,
(str) => str,
(str) => (0, util_1.isValidNationalID)(str), true
],
[
Attribute.GIVEN_NAME,
(str) => (0, util_1.toSentenceCase)(str.split(' ')[0]),
(str) => (0, util_1.isFullName)(str)
],
[
Attribute.FAMILY_NAME,
(str) => (0, util_1.toSentenceCase)(str.split(' ').reduce((_, c) => c, '')),
(str) => (0, util_1.isFullName)(str), true
],
[
Attribute.BIRTHDATE,
(str) => (0, util_1.formatDate)(str),
(str) => (0, util_1.isDatePattern)(str), true
],
[
Attribute.GENDER,
(str) => (0, util_1.formatGender)(str),
(str) => (0, util_1.isGender)(str)
]
]
},
'10': {
type: 'Registration sticker',
model: [
[
Attribute.REGISTRATION_DISTRICT,
(str) => str,
(str) => (0, util_1.isGeneralString)(str), true
],
[
Attribute.REGISTRATION_DATE,
(str) => (0, util_1.formatDate)(str),
(str) => (0, util_1.isDatePattern)(str), true
],
[
Attribute.REGISTRATION_TA,
(str) => str,
(str) => (0, util_1.isGeneralString)(str), true
],
[
Attribute.REGISTRATION_VILLAGE,
(str) => str,
(str) => (0, util_1.isGeneralString)(str), true
],
[
Attribute.NATIONAL_ID,
(str) => str,
(str) => (0, util_1.isValidNationalID)(str), true
],
[
Attribute.FAMILY_NAME,
(str) => (0, util_1.toSentenceCase)(str),
(str) => (0, util_1.isFullName)(str), true
],
[
Attribute.GIVEN_NAME,
(str) => (0, util_1.toSentenceCase)(str),
(str) => (0, util_1.isFullName)(str), true
],
[
Attribute.BIRTHDATE,
(str) => (0, util_1.formatDate)(str),
(str) => (0, util_1.isDatePattern)(str), true
]
]
}
};
function parseNrbQr(code) {
// First character in array index indicate type of identifier that was scanned
const [docType, ...data] = `${code}`.split('~');
// Supported documents are mapped in SUPPORTED_DOCS.
if (!SUPPORTED_DOCS[docType])
return;
return data.reduce((dataMap, codeValue) => {
// Maintain a list of attributes that haven't been mapped yet
const availableAttributes = SUPPORTED_DOCS[docType].model.filter((val) => !Object.keys(dataMap).includes(val[0]));
for (const struct of availableAttributes) {
const [attribute, formatValue, matchToPattern, breaker] = struct;
const value = `${codeValue}`.trim();
if (matchToPattern(value, dataMap)) {
dataMap[attribute] = formatValue(value);
// Do not proceed evaluating other attributes if certainity is explicitly defined
if (breaker)
break;
}
}
return dataMap;
}, { docType: SUPPORTED_DOCS[docType].type });
}
exports.parseNrbQr = parseNrbQr;