Skip to content

Commit 410e683

Browse files
author
Chris Gilardi
committed
Refactored and added model export
1 parent 09d9734 commit 410e683

File tree

5 files changed

+195
-194
lines changed

5 files changed

+195
-194
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vladdress",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"description": "Lightweight Street Address Parser Written in TypeScript",
55
"main": "build/index.js",
66
"scripts": {
@@ -45,4 +45,4 @@
4545
"ts-node": "^9.1.1",
4646
"typescript": "^4.2.4"
4747
}
48-
}
48+
}

src/index.ts

Lines changed: 2 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -1,191 +1,2 @@
1-
import { removeRepeatedSpaces } from './utils/strings';
2-
import { isValidCountryCode } from './parsers/country';
3-
import { parseZipCode } from './parsers/zip-code';
4-
import { getStateInfo } from './parsers/state';
5-
import { usLine2Prefixes, validateUsLine2Type } from './parsers/line2';
6-
import { getLastElement } from './utils/array';
7-
import { parsePlaceName } from './parsers/city-state';
8-
import { matchesPOBox, parsePOBox } from './parsers/po-box';
9-
import { matchesStreetAddress, parseStreetAddress } from './parsers/street-address';
10-
import { matchesNoSuffix, parseNoSuffix } from './parsers/no-suffix';
11-
import { ParsedAddress } from './model/parsed-address';
12-
13-
14-
15-
export const parseAddress = function (address: string): ParsedAddress {
16-
if (!address) {
17-
throw new Error('parseAddress: Argument must be a non-empty string.');
18-
}
19-
20-
// Split the address by given delimiters, remove extraneous ones.
21-
let addressParts = address.split(/,|\t|\n/).map(removeRepeatedSpaces).filter((s) => !!s);
22-
23-
// Check if the last section contains country reference (Just supports US/Canada for now)
24-
const countrySection = getLastElement(addressParts)?.trim();
25-
26-
// If it does, remove it
27-
// TODO: Add the country code to the return
28-
if (isValidCountryCode(countrySection)) {
29-
addressParts = addressParts.slice(0, -1);
30-
}
31-
32-
// Assume the last address section contains state, zip or both
33-
const stateZipString = getLastElement(addressParts)?.trim();
34-
const zipCode = parseZipCode(stateZipString);
35-
const resultZipCode = zipCode?.zip5 || zipCode?.zipInternational;
36-
let resultZip4: string | undefined;
37-
38-
if (zipCode?.zip5 && zipCode.zip4) {
39-
resultZip4 = `${zipCode.zip5}-${zipCode.zip4}`;
40-
}
41-
42-
let cityStateString = zipCode?.trimmedString;
43-
44-
// Parse and remove state
45-
if (cityStateString && cityStateString.length > 0) { // Check if anything is left of last section
46-
addressParts[addressParts.length - 1] = cityStateString;
47-
} else {
48-
addressParts.splice(-1, 1);
49-
cityStateString = addressParts[addressParts.length - 1].trim();
50-
}
51-
52-
const stateInfo = getStateInfo(cityStateString);
53-
const resultStateAbbreviation = stateInfo.stateAbbreviation;
54-
const resultStateName = stateInfo.stateName;
55-
const cityString = stateInfo.trimmedString;
56-
57-
if (!resultStateAbbreviation || !resultStateName || resultStateAbbreviation.length != 2) {
58-
throw new Error('Can not parse address. State not found.');
59-
}
60-
61-
62-
// Parse and remove city/place name
63-
let placeString: string | undefined;
64-
65-
if (cityString && cityString.length > 0) {
66-
addressParts[addressParts.length - 1] = cityString;
67-
placeString = getLastElement(addressParts);
68-
} else {
69-
addressParts.splice(-1, 1);
70-
placeString = addressParts[addressParts.length - 1].trim();
71-
}
72-
73-
const placeNameResult = parsePlaceName(placeString, resultStateAbbreviation);
74-
const resultPlaceName = placeNameResult.placeName;
75-
76-
if (!resultPlaceName) {
77-
throw new Error('No Place Name Specified');
78-
}
79-
80-
placeString = placeNameResult.placeString;
81-
82-
// Parse the street data
83-
let streetString: string | undefined;
84-
85-
if (placeString && placeString.length > 0) {
86-
addressParts[addressParts.length - 1] = placeString;
87-
} else {
88-
addressParts = addressParts.slice(0, -1);
89-
}
90-
91-
let temporaryLine2: string | undefined;
92-
93-
if (addressParts.length > 2) {
94-
throw new Error('Can not parse address. More than two address lines.');
95-
} else if (addressParts.length === 2) {
96-
// check if the secondary data is first
97-
const line2Index = addressParts.findIndex((part) => {
98-
const firstWord = part.substring(0, part.indexOf(' '));
99-
return !!usLine2Prefixes[firstWord];
100-
});
101-
102-
const part = addressParts.splice(line2Index, 1)[0];
103-
104-
temporaryLine2 = part.trim();
105-
}
106-
107-
if (addressParts.length === 0) {
108-
throw new Error('Can not parse address. Invalid street address data. Input string: ' + address);
109-
}
110-
111-
streetString = addressParts[0].trim();
112-
113-
if (!temporaryLine2) {
114-
const line2Type = validateUsLine2Type(streetString);
115-
if (line2Type) {
116-
const upperSS = streetString.toUpperCase();
117-
118-
const idx = upperSS.indexOf(line2Type);
119-
temporaryLine2 = streetString.substring(idx);
120-
streetString = streetString.replace(temporaryLine2, "").trim();
121-
}
122-
}
123-
124-
let resultAddressLine1: string | undefined;
125-
let resultStreetNumber: string | undefined;
126-
let resultStreetName: string | undefined;
127-
let resultStreetDirection: string | undefined;
128-
let resultStreetSuffix: string | undefined;
129-
let resultAddressLine2: string | undefined = temporaryLine2;
130-
131-
if (matchesPOBox(streetString)) {
132-
const res = parsePOBox(streetString);
133-
streetString = res.streetString;
134-
resultAddressLine1 = res.line1;
135-
} else if (matchesStreetAddress(streetString)) {
136-
const res = parseStreetAddress(streetString);
137-
resultAddressLine1 = res.line1;
138-
resultStreetNumber = res.streetNumber;
139-
resultStreetName = res.streetName;
140-
resultStreetDirection = res.streetDirection;
141-
resultStreetSuffix = res.streetSuffix;
142-
streetString = res.streetString;
143-
resultAddressLine2 ||= res.line2;
144-
} else if (matchesNoSuffix(streetString)) {
145-
const res = parseNoSuffix(streetString);
146-
resultAddressLine1 = res.line1;
147-
resultAddressLine2 = res.line2;
148-
resultStreetName = res.streetName;
149-
resultStreetNumber = res.streetNumber;
150-
streetString = res.streetString;
151-
resultAddressLine2 ||= res.line2;
152-
} else {
153-
throw new Error('Can not parse address. Invalid street address data. Input string: ' + address);
154-
}
155-
156-
if (!resultAddressLine1) {
157-
throw new Error('Could not generate Address Line 1');
158-
}
159-
160-
let addressString = resultAddressLine1;
161-
if (resultAddressLine2) {
162-
addressString += ', ' + resultAddressLine2;
163-
}
164-
165-
let resultFormattedAddress: string | undefined;
166-
let resultId: string;
167-
168-
if (addressString && resultPlaceName && resultStateAbbreviation) {
169-
const idString = addressString + ", " + resultPlaceName + ", " + resultStateAbbreviation + (resultZipCode ? (" " + resultZipCode) : '');
170-
resultFormattedAddress = idString;
171-
resultId = encodeURI(idString.replace(/[\s#\/\.\,]+/g, '-').toLowerCase());
172-
} else {
173-
throw new Error('Required Address Parts Not Found.');
174-
}
175-
176-
return {
177-
zipCode: resultZipCode,
178-
zipCodePlusFour: resultZip4,
179-
stateAbbreviation: resultStateAbbreviation,
180-
stateName: resultStateName,
181-
placeName: resultPlaceName,
182-
addressLine1: resultAddressLine1,
183-
addressLine2: resultAddressLine2,
184-
streetNumber: resultStreetNumber,
185-
streetSuffix: resultStreetSuffix,
186-
streetDirection: resultStreetDirection,
187-
streetName: resultStreetName,
188-
id: resultId,
189-
formattedAddress: resultFormattedAddress,
190-
}
191-
};
1+
export * from './parse-address';
2+
export * from './model';

src/model/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './parsed-address';

0 commit comments

Comments
 (0)