vladdress
Version:
Lightweight Street Address Parser Written in TypeScript
184 lines (183 loc) • 8.51 kB
JavaScript
;
exports.__esModule = true;
exports.parseAddress = void 0;
var strings_1 = require("./utils/strings");
var country_1 = require("./parsers/country");
var zip_code_1 = require("./parsers/zip-code");
var state_1 = require("./parsers/state");
var line2_1 = require("./parsers/line2");
var array_1 = require("./utils/array");
var city_state_1 = require("./parsers/city-state");
var po_box_1 = require("./parsers/po-box");
var street_address_1 = require("./parsers/street-address");
var no_suffix_1 = require("./parsers/no-suffix");
var parseAddress = function (address, options) {
var _a, _b, _c, _d, _e, _f;
if (!address) {
throw new Error('parseAddress: Argument must be a non-empty string.');
}
// Split the address by given delimiters, remove extraneous ones.
var addressParts = address.split(/,|\t|\n/).map(strings_1.removeRepeatedSpaces).filter(function (s) { return !!s; });
// Check if the last section contains country reference (Just supports US/Canada for now)
var countrySection = (_a = (0, array_1.getLastElement)(addressParts)) === null || _a === void 0 ? void 0 : _a.trim();
// If it does, remove it
// TODO: Add the country code to the return
if ((0, country_1.isValidCountryCode)(countrySection)) {
addressParts = addressParts.slice(0, -1);
}
// Assume the last address section contains state, zip or both
var stateZipString = (_b = (0, array_1.getLastElement)(addressParts)) === null || _b === void 0 ? void 0 : _b.trim();
var zipCode = (0, zip_code_1.parseZipCode)(stateZipString);
var resultZipCode = (zipCode === null || zipCode === void 0 ? void 0 : zipCode.zip5) || (zipCode === null || zipCode === void 0 ? void 0 : zipCode.zipInternational);
var resultZip4;
if ((zipCode === null || zipCode === void 0 ? void 0 : zipCode.zip5) && zipCode.zip4) {
resultZip4 = "".concat(zipCode.zip5, "-").concat(zipCode.zip4);
}
var cityStateString = zipCode === null || zipCode === void 0 ? void 0 : zipCode.trimmedString;
// Parse and remove state
if (cityStateString && cityStateString.length > 0) { // Check if anything is left of last section
addressParts[addressParts.length - 1] = cityStateString;
}
else {
addressParts.splice(-1, 1);
cityStateString = (_c = addressParts[addressParts.length - 1]) === null || _c === void 0 ? void 0 : _c.trim();
}
var stateInfo = (0, state_1.getStateInfo)(cityStateString);
var resultStateAbbreviation = stateInfo.stateAbbreviation;
var resultStateName = stateInfo.stateName;
var cityString = stateInfo.trimmedString;
if (!resultStateAbbreviation || !resultStateName || resultStateAbbreviation.length != 2) {
throw new Error('Can not parse address. State not found.');
}
// Parse and remove city/place name
var placeString;
if (cityString && cityString.length > 0) {
addressParts[addressParts.length - 1] = cityString;
placeString = (0, array_1.getLastElement)(addressParts);
}
else {
addressParts.splice(-1, 1);
placeString = (_d = addressParts[addressParts.length - 1]) === null || _d === void 0 ? void 0 : _d.trim();
}
var placeNameResult = (0, city_state_1.parsePlaceName)(placeString, resultStateAbbreviation);
var resultPlaceName = placeNameResult.placeName;
if (!resultPlaceName) {
throw new Error('No Place Name Specified');
}
placeString = placeNameResult.placeString;
// Parse the street data
var streetString;
if (placeString && placeString.length > 0) {
addressParts[addressParts.length - 1] = placeString;
}
else {
addressParts = addressParts.slice(0, -1);
}
var temporaryLine2;
if (addressParts.length > 2) {
throw new Error('Can not parse address. More than two address lines.');
}
else if (addressParts.length === 2) {
// check if the secondary data is first
var line2Index = addressParts.findIndex(function (part) {
var firstWord = part.substring(0, part.indexOf(' '));
return !!line2_1.usLine2Prefixes[firstWord];
});
var part = addressParts.splice(line2Index, 1)[0];
temporaryLine2 = part === null || part === void 0 ? void 0 : part.trim();
}
if (addressParts.length === 0) {
if (!(options === null || options === void 0 ? void 0 : options.allowPartialAddress)) {
throw new Error('Can not parse address. Invalid street address data. Input string: ' + address);
}
var formattedAddress = makeFormattedAddress(resultStateAbbreviation, resultPlaceName);
return {
formattedAddress: formattedAddress,
id: makeAddressId(formattedAddress),
stateAbbreviation: resultStateAbbreviation,
stateName: resultStateName,
placeName: resultPlaceName,
zipCode: resultZipCode,
zipCodePlusFour: resultZip4
};
}
streetString = (_e = addressParts[0]) === null || _e === void 0 ? void 0 : _e.trim();
if (!temporaryLine2) {
var line2Type = (0, line2_1.validateUsLine2Type)(streetString);
if (line2Type) {
var upperSS = streetString.toUpperCase();
var idx = upperSS.indexOf(line2Type);
temporaryLine2 = streetString === null || streetString === void 0 ? void 0 : streetString.substring(idx);
streetString = (_f = streetString === null || streetString === void 0 ? void 0 : streetString.replace(temporaryLine2, "")) === null || _f === void 0 ? void 0 : _f.trim();
}
}
var resultAddressLine1;
var resultStreetNumber;
var resultStreetName;
var resultStreetDirection;
var resultStreetSuffix;
var resultAddressLine2 = temporaryLine2;
if ((0, po_box_1.matchesPOBox)(streetString)) {
var res = (0, po_box_1.parsePOBox)(streetString);
streetString = res.streetString;
resultAddressLine1 = res.line1;
}
else if ((0, street_address_1.matchesStreetAddress)(streetString)) {
var res = (0, street_address_1.parseStreetAddress)(streetString);
resultAddressLine1 = res.line1;
resultStreetNumber = res.streetNumber;
resultStreetName = res.streetName;
resultStreetDirection = res.streetDirection;
resultStreetSuffix = res.streetSuffix;
streetString = res.streetString;
resultAddressLine2 || (resultAddressLine2 = res.line2);
}
else if ((0, no_suffix_1.matchesNoSuffix)(streetString)) {
var res = (0, no_suffix_1.parseNoSuffix)(streetString);
resultAddressLine1 = res.line1;
resultAddressLine2 = res.line2;
resultStreetName = res.streetName;
resultStreetNumber = res.streetNumber;
streetString = res.streetString;
resultAddressLine2 || (resultAddressLine2 = res.line2);
}
else {
throw new Error('Can not parse address. Invalid street address data. Input string: ' + address);
}
if (!resultAddressLine1) {
throw new Error('Could not generate Address Line 1');
}
var addressString = resultAddressLine1;
if (resultAddressLine2) {
addressString += ', ' + resultAddressLine2;
}
var resultFormattedAddress;
if (addressString && resultPlaceName && resultStateAbbreviation) {
resultFormattedAddress = makeFormattedAddress(resultStateAbbreviation, resultPlaceName, addressString, resultZipCode);
}
else {
throw new Error('Required Address Parts Not Found.');
}
return {
zipCode: resultZipCode,
zipCodePlusFour: resultZip4,
stateAbbreviation: resultStateAbbreviation,
stateName: resultStateName,
placeName: resultPlaceName,
addressLine1: resultAddressLine1,
addressLine2: resultAddressLine2,
streetNumber: resultStreetNumber,
streetSuffix: resultStreetSuffix,
streetDirection: resultStreetDirection,
streetName: resultStreetName,
id: makeAddressId(resultFormattedAddress),
formattedAddress: resultFormattedAddress
};
};
exports.parseAddress = parseAddress;
var makeFormattedAddress = function (stateCode, placeName, line1, zipCode) {
return (line1 ? (line1 + ", ") : '') + placeName + ", " + stateCode + (zipCode ? (" " + zipCode) : '');
};
var makeAddressId = function (formattedAddress) {
return encodeURI(formattedAddress.replace(/[\s#/.,]+/g, '-').toLowerCase());
};