snailmailaddressparser
Version:
A Javascript library to parse snail mail addresses into components
1,392 lines (1,305 loc) • 34.5 kB
JavaScript
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['simplemailaddressparser'], factory);
} else {
// Browser globals
root.simplemailaddressparser = factory(root.simplemailaddressparser);
}
}(this, function() {
var _, XRegExp, _xregexp, VERSION;
/* Require these as necessary; the may be defined on the global object. */
if (typeof require === 'function') {
_ = require('lodash'); // underscore?
_xregexp = require('xregexp')
XRegExp = _xregexp.XRegExp ? _xregexp.XRegExp : _xregexp;
}
if (_.isFunction(XRegExp.addUnicodePackage)) {
// for XRegExp 2.0
XRegExp.addUnicodePackage();
}
/* ---- Begin AMD content ---- */
VERSION = "0.1.27";
// -- from: lib/Debug.coffee -- \\
/*
#
# Some debugging utilities
#
*/
var inspect, log;
if (typeof module !== 'undefined' && module.exports) {
inspect = function(o, showHidden, depth) {
if (showHidden == null) {
showHidden = false;
}
if (depth == null) {
depth = 2;
}
return require('util').inspect(o, showHidden, depth, true);
};
log = function(string) {
return require('util').debug(string);
};
} else {
inspect = function(o) {
return console.log(o);
};
log = function(o) {
return console.log(o);
};
}
// -- from: lib/iso3166.coffee -- \\
/*
* ISO 3166 country codes
*
* See eg https://github.com/lukes/ISO-3166-Countries-with-Regional-Codes
*/
var ALL_COUNTRY_IDS, COUNTRIES_REX, COUNTRY_NAMES_MAP, iso3166;
iso3166 = [
{
name: "Afghanistan",
aliases: ["AF"]
}, {
name: "Åland Islands",
aliases: ["AX", "Aland Islands"]
}, {
name: "Albania",
aliases: ["AL"]
}, {
name: "Algeria",
aliases: ["DZ"]
}, {
name: "American Samoa",
aliases: ["AS"]
}, {
name: "Andorra",
aliases: ["AD"]
}, {
name: "Angola",
aliases: ["AO"]
}, {
name: "Anguilla",
aliases: ["AI"]
}, {
name: "Antarctica",
aliases: ["AQ"]
}, {
name: "Antigua and Barbuda",
aliases: ["AG"]
}, {
name: "Argentina",
aliases: ["AR"]
}, {
name: "Armenia",
aliases: ["AM"]
}, {
name: "Aruba",
aliases: ["AW"]
}, {
name: "Australia",
aliases: ["AU"]
}, {
name: "Austria",
aliases: ["AT"]
}, {
name: "Azerbaijan",
aliases: ["AZ"]
}, {
name: "Bahamas",
aliases: ["BS"]
}, {
name: "Bahrain",
aliases: ["BH"]
}, {
name: "Bangladesh",
aliases: ["BD"]
}, {
name: "Barbados",
aliases: ["BB"]
}, {
name: "Belarus",
aliases: ["BY"]
}, {
name: "Belgium",
aliases: ["BE"]
}, {
name: "Belize",
aliases: ["BZ"]
}, {
name: "Benin",
aliases: ["BJ"]
}, {
name: "Bermuda",
aliases: ["BM"]
}, {
name: "Bhutan",
aliases: ["BT"]
}, {
name: "Bolivia, Plurinational State of",
aliases: ["BO", "Bolivia"]
}, {
name: "Bonaire, Sint Eustatius and Saba",
aliases: ["BQ"]
}, {
name: "Bosnia and Herzegovina",
aliases: ["BA"]
}, {
name: "Botswana",
aliases: ["BW"]
}, {
name: "Bouvet Island",
aliases: ["BV"]
}, {
name: "Brazil",
aliases: ["BR"]
}, {
name: "British Indian Ocean Territory",
aliases: ["IO"]
}, {
name: "Brunei Darussalam",
aliases: ["BN"]
}, {
name: "Bulgaria",
aliases: ["BG"]
}, {
name: "Burkina Faso",
aliases: ["BF"]
}, {
name: "Burundi",
aliases: ["BI"]
}, {
name: "Cambodia",
aliases: ["KH"]
}, {
name: "Cameroon",
aliases: ["CM"]
}, {
name: "Canada",
aliases: ["CA"]
}, {
name: "Cape Verde",
aliases: ["CV"]
}, {
name: "Cayman Islands",
aliases: ["KY"]
}, {
name: "Central African Republic",
aliases: ["CF"]
}, {
name: "Chad",
aliases: ["TD"]
}, {
name: "Chile",
aliases: ["CL"]
}, {
name: "China",
aliases: ["CN"]
}, {
name: "Christmas Island",
aliases: ["CX"]
}, {
name: "Cocos (Keeling) Islands",
aliases: ["CC"]
}, {
name: "Colombia",
aliases: ["CO"]
}, {
name: "Comoros",
aliases: ["KM"]
}, {
name: "Congo",
aliases: ["CG"]
}, {
name: "Congo, the Democratic Republic of the",
aliases: ["CD"]
}, {
name: "Cook Islands",
aliases: ["CK"]
}, {
name: "Costa Rica",
aliases: ["CR"]
}, {
name: "Côte d'Ivoire",
aliases: ["CI"]
}, {
name: "Croatia",
aliases: ["HR"]
}, {
name: "Cuba",
aliases: ["CU"]
}, {
name: "Curaçao",
aliases: ["CW"]
}, {
name: "Cyprus",
aliases: ["CY"]
}, {
name: "Czech Republic",
aliases: ["CZ"]
}, {
name: "Denmark",
aliases: ["DK"]
}, {
name: "Djibouti",
aliases: ["DJ"]
}, {
name: "Dominica",
aliases: ["DM"]
}, {
name: "Dominican Republic",
aliases: ["DO"]
}, {
name: "Ecuador",
aliases: ["EC"]
}, {
name: "Egypt",
aliases: ["EG"]
}, {
name: "El Salvador",
aliases: ["SV"]
}, {
name: "Equatorial Guinea",
aliases: ["GQ"]
}, {
name: "Eritrea",
aliases: ["ER"]
}, {
name: "Estonia",
aliases: ["EE"]
}, {
name: "Ethiopia",
aliases: ["ET"]
}, {
name: "Falkland Islands (Malvinas)",
aliases: ["FK"]
}, {
name: "Faroe Islands",
aliases: ["FO"]
}, {
name: "Fiji",
aliases: ["FJ"]
}, {
name: "Finland",
aliases: ["FI"]
}, {
name: "France",
aliases: ["FR"]
}, {
name: "French Guiana",
aliases: ["GF"]
}, {
name: "French Polynesia",
aliases: ["PF"]
}, {
name: "French Southern Territories",
aliases: ["TF"]
}, {
name: "Gabon",
aliases: ["GA"]
}, {
name: "Gambia",
aliases: ["GM"]
}, {
name: "Georgia",
aliases: ["GE"]
}, {
name: "Germany",
aliases: ["DE"]
}, {
name: "Ghana",
aliases: ["GH"]
}, {
name: "Gibraltar",
aliases: ["GI"]
}, {
name: "Greece",
aliases: ["GR"]
}, {
name: "Greenland",
aliases: ["GL"]
}, {
name: "Grenada",
aliases: ["GD"]
}, {
name: "Guadeloupe",
aliases: ["GP"]
}, {
name: "Guam",
aliases: ["GU"]
}, {
name: "Guatemala",
aliases: ["GT"]
}, {
name: "Guernsey",
aliases: ["GG"]
}, {
name: "Guinea",
aliases: ["GN"]
}, {
name: "Guinea-Bissau",
aliases: ["GW"]
}, {
name: "Guyana",
aliases: ["GY"]
}, {
name: "Haiti",
aliases: ["HT"]
}, {
name: "Heard Island and McDonald Islands",
aliases: ["HM"]
}, {
name: "Holy See (Vatican City State)",
aliases: ["VA"]
}, {
name: "Honduras",
aliases: ["HN"]
}, {
name: "Hong Kong",
aliases: ["HK"]
}, {
name: "Hungary",
aliases: ["HU"]
}, {
name: "Iceland",
aliases: ["IS"]
}, {
name: "India",
aliases: ["IN"]
}, {
name: "Indonesia",
aliases: ["ID"]
}, {
name: "Iran, Islamic Republic of",
aliases: ["IR"]
}, {
name: "Iraq",
aliases: ["IQ"]
}, {
name: "Ireland",
aliases: ["IE"]
}, {
name: "Isle of Man",
aliases: ["IM"]
}, {
name: "Israel",
aliases: ["IL"]
}, {
name: "Italy",
aliases: ["IT"]
}, {
name: "Jamaica",
aliases: ["JM"]
}, {
name: "Japan",
aliases: ["JP"]
}, {
name: "Jersey",
aliases: ["JE"]
}, {
name: "Jordan",
aliases: ["JO"]
}, {
name: "Kazakhstan",
aliases: ["KZ"]
}, {
name: "Kenya",
aliases: ["KE"]
}, {
name: "Kiribati",
aliases: ["KI"]
}, {
name: "Korea, Democratic People's Republic of",
aliases: ["KP"]
}, {
name: "Korea, Republic of",
aliases: ["KR"]
}, {
name: "Kuwait",
aliases: ["KW"]
}, {
name: "Kyrgyzstan",
aliases: ["KG"]
}, {
name: "Lao People's Democratic Republic",
aliases: ["LA"]
}, {
name: "Latvia",
aliases: ["LV"]
}, {
name: "Lebanon",
aliases: ["LB"]
}, {
name: "Lesotho",
aliases: ["LS"]
}, {
name: "Liberia",
aliases: ["LR"]
}, {
name: "Libya",
aliases: ["LY"]
}, {
name: "Liechtenstein",
aliases: ["LI"]
}, {
name: "Lithuania",
aliases: ["LT"]
}, {
name: "Luxembourg",
aliases: ["LU"]
}, {
name: "Macao",
aliases: ["MO"]
}, {
name: "Macedonia, the former Yugoslav Republic of",
aliases: ["MK"]
}, {
name: "Madagascar",
aliases: ["MG"]
}, {
name: "Malawi",
aliases: ["MW"]
}, {
name: "Malaysia",
aliases: ["MY"]
}, {
name: "Maldives",
aliases: ["MV"]
}, {
name: "Mali",
aliases: ["ML"]
}, {
name: "Malta",
aliases: ["MT"]
}, {
name: "Marshall Islands",
aliases: ["MH"]
}, {
name: "Martinique",
aliases: ["MQ"]
}, {
name: "Mauritania",
aliases: ["MR"]
}, {
name: "Mauritius",
aliases: ["MU"]
}, {
name: "Mayotte",
aliases: ["YT"]
}, {
name: "Mexico",
aliases: ["MX"]
}, {
name: "Micronesia, Federated States of",
aliases: ["FM"]
}, {
name: "Moldova, Republic of",
aliases: ["MD"]
}, {
name: "Monaco",
aliases: ["MC"]
}, {
name: "Mongolia",
aliases: ["MN"]
}, {
name: "Montenegro",
aliases: ["ME"]
}, {
name: "Montserrat",
aliases: ["MS"]
}, {
name: "Morocco",
aliases: ["MA"]
}, {
name: "Mozambique",
aliases: ["MZ"]
}, {
name: "Myanmar",
aliases: ["MM"]
}, {
name: "Namibia",
aliases: ["NA"]
}, {
name: "Nauru",
aliases: ["NR"]
}, {
name: "Nepal",
aliases: ["NP"]
}, {
name: "Netherlands",
aliases: ["NL"]
}, {
name: "New Caledonia",
aliases: ["NC"]
}, {
name: "New Zealand",
aliases: ["NZ"]
}, {
name: "Nicaragua",
aliases: ["NI"]
}, {
name: "Niger",
aliases: ["NE"]
}, {
name: "Nigeria",
aliases: ["NG"]
}, {
name: "Niue",
aliases: ["NU"]
}, {
name: "Norfolk Island",
aliases: ["NF"]
}, {
name: "Northern Mariana Islands",
aliases: ["MP"]
}, {
name: "Norway",
aliases: ["NO"]
}, {
name: "Oman",
aliases: ["OM"]
}, {
name: "Pakistan",
aliases: ["PK"]
}, {
name: "Palau",
aliases: ["PW"]
}, {
name: "Palestinian Territory, Occupied",
aliases: ["PS"]
}, {
name: "Panama",
aliases: ["PA"]
}, {
name: "Papua New Guinea",
aliases: ["PG"]
}, {
name: "Paraguay",
aliases: ["PY"]
}, {
name: "Peru",
aliases: ["PE"]
}, {
name: "Philippines",
aliases: ["PH"]
}, {
name: "Pitcairn",
aliases: ["PN"]
}, {
name: "Poland",
aliases: ["PL"]
}, {
name: "Portugal",
aliases: ["PT"]
}, {
name: "Puerto Rico",
aliases: ["PR"]
}, {
name: "Qatar",
aliases: ["QA"]
}, {
name: "Réunion",
aliases: ["RE"]
}, {
name: "Romania",
aliases: ["RO"]
}, {
name: "Russian Federation",
aliases: ["RU"]
}, {
name: "Rwanda",
aliases: ["RW"]
}, {
name: "Saint Barthélemy",
aliases: ["BL"]
}, {
name: "Saint Helena, Ascension and Tristan da Cunha",
aliases: ["SH"]
}, {
name: "Saint Kitts and Nevis",
aliases: ["KN"]
}, {
name: "Saint Lucia",
aliases: ["LC"]
}, {
name: "Saint Martin (French part)",
aliases: ["MF"]
}, {
name: "Saint Pierre and Miquelon",
aliases: ["PM"]
}, {
name: "Saint Vincent and the Grenadines",
aliases: ["VC"]
}, {
name: "Samoa",
aliases: ["WS"]
}, {
name: "San Marino",
aliases: ["SM"]
}, {
name: "Sao Tome and Principe",
aliases: ["ST"]
}, {
name: "Saudi Arabia",
aliases: ["SA"]
}, {
name: "Senegal",
aliases: ["SN"]
}, {
name: "Serbia",
aliases: ["RS"]
}, {
name: "Seychelles",
aliases: ["SC"]
}, {
name: "Sierra Leone",
aliases: ["SL"]
}, {
name: "Singapore",
aliases: ["SG"]
}, {
name: "Sint Maarten (Dutch part)",
aliases: ["SX"]
}, {
name: "Slovakia",
aliases: ["SK"]
}, {
name: "Slovenia",
aliases: ["SI"]
}, {
name: "Solomon Islands",
aliases: ["SB"]
}, {
name: "Somalia",
aliases: ["SO"]
}, {
name: "South Africa",
aliases: ["ZA"]
}, {
name: "South Georgia and the South Sandwich Islands",
aliases: ["GS"]
}, {
name: "South Sudan",
aliases: ["SS"]
}, {
name: "Spain",
aliases: ["ES"]
}, {
name: "Sri Lanka",
aliases: ["LK"]
}, {
name: "Sudan",
aliases: ["SD"]
}, {
name: "Suriname",
aliases: ["SR"]
}, {
name: "Svalbard and Jan Mayen",
aliases: ["SJ"]
}, {
name: "Swaziland",
aliases: ["SZ"]
}, {
name: "Sweden",
aliases: ["SE"]
}, {
name: "Switzerland",
aliases: ["CH"]
}, {
name: "Syrian Arab Republic",
aliases: ["SY"]
}, {
name: "Taiwan, Province of China",
aliases: ["TW"]
}, {
name: "Tajikistan",
aliases: ["TJ"]
}, {
name: "Tanzania, United Republic of",
aliases: ["TZ"]
}, {
name: "Thailand",
aliases: ["TH"]
}, {
name: "Timor-Leste",
aliases: ["TL"]
}, {
name: "Togo",
aliases: ["TG"]
}, {
name: "Tokelau",
aliases: ["TK"]
}, {
name: "Tonga",
aliases: ["TO"]
}, {
name: "Trinidad and Tobago",
aliases: ["TT"]
}, {
name: "Tunisia",
aliases: ["TN"]
}, {
name: "Turkey",
aliases: ["TR"]
}, {
name: "Turkmenistan",
aliases: ["TM"]
}, {
name: "Turks and Caicos Islands",
aliases: ["TC"]
}, {
name: "Tuvalu",
aliases: ["TV"]
}, {
name: "Uganda",
aliases: ["UG"]
}, {
name: "Ukraine",
aliases: ["UA"]
}, {
name: "United Arab Emirates",
aliases: ["AE"]
}, {
name: "United Kingdom",
aliases: ["GB"]
}, {
name: "United States",
aliases: ["US", "USA", "United States of America"]
}, {
name: "United States Minor Outlying Islands",
aliases: ["UM"]
}, {
name: "Uruguay",
aliases: ["UY"]
}, {
name: "Uzbekistan",
aliases: ["UZ"]
}, {
name: "Vanuatu",
aliases: ["VU"]
}, {
name: "Venezuela, Bolivarian Republic of",
aliases: ["VE"]
}, {
name: "Viet Nam",
aliases: ["VN"]
}, {
name: "Virgin Islands, British",
aliases: ["VG"]
}, {
name: "Virgin Islands, U.S.",
aliases: ["VI"]
}, {
name: "Wallis and Futuna",
aliases: ["WF"]
}, {
name: "Western Sahara",
aliases: ["EH"]
}, {
name: "Yemen",
aliases: ["YE"]
}, {
name: "Zambia",
aliases: ["ZM"]
}, {
name: "Zimbabwe",
aliases: ["ZW"]
}
];
ALL_COUNTRY_IDS = _.flatten(_.map(iso3166, function(c) {
return [c.name, c.aliases];
}));
COUNTRY_NAMES_MAP = {};
_.each(iso3166, function(country) {
var name;
name = country.name.toLowerCase();
COUNTRY_NAMES_MAP[name] = name;
return _.each(country.aliases, function(alias) {
return COUNTRY_NAMES_MAP[alias.toLowerCase()] = name;
});
});
COUNTRIES_REX = XRegExp("(" + (_.keys(iso3166).join("|")) + ")");
// -- from: lib/LineMatcherStrategy.coffee -- \\
var LineMatcherStrategy,
__slice = [].slice;
LineMatcherStrategy = (function() {
function LineMatcherStrategy() {
this._list = [];
}
LineMatcherStrategy.prototype.add = function() {
var line_matcher_list, permutations;
line_matcher_list = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
permutations = [_.toArray(line_matcher_list)];
_.each(line_matcher_list, function(lm, index) {
var perms_wo_lm;
if (!lm.is_optional()) {
return;
}
perms_wo_lm = [];
_.each(permutations, function(perm) {
var matcher_set;
matcher_set = _.clone(perm);
matcher_set.splice(matcher_set.indexOf(lm), 1);
return perms_wo_lm.push(matcher_set);
});
return permutations = permutations.concat(perms_wo_lm);
});
return this._list = this._list.concat(permutations);
};
LineMatcherStrategy.prototype.all = function() {
return this._list;
};
return LineMatcherStrategy;
})();
// -- from: lib/LineMatcher.coffee -- \\
var LineMatcher,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
LineMatcher = (function() {
function LineMatcher(name, expression, options) {
this.name = name;
this.expression = expression;
if (options == null) {
options = {};
}
this.options = _.defaults(options, {
invalid_tests: [],
is_optional: false,
rex_flags: 'xi',
valid_tests: [],
_or: null
});
this.rex = XRegExp("^" + expression + "$", this.options.rex_flags);
}
LineMatcher.prototype.names = function() {
if (this.options._or) {
return "" + this.name + " or " + (this.options._or.names());
} else {
return this.name;
}
};
LineMatcher.prototype.optional = function() {
var copy;
copy = this.clone();
copy.options.is_optional = true;
return copy;
};
LineMatcher.prototype.mandatory = function() {
var copy;
copy = this.clone();
copy.options.is_optional = false;
return copy;
};
LineMatcher.prototype.is_optional = function() {
if (this.options.is_optional) {
return true;
}
if (this.options._or) {
return this.options._or.is_optional();
}
return false;
};
LineMatcher.prototype.clone = function() {
return new LineMatcher(this.name, this.expression, this.options);
};
LineMatcher.prototype.or = function(matcher) {
var lm;
lm = this;
if (_.isObject(this.options._or)) {
if (this.options._or.name === matcher.name) {
return this;
}
this.options._or = this.options._or.or(matcher);
} else {
lm = this.clone();
lm.options._or = matcher;
}
return lm;
};
LineMatcher.prototype.match = function(line, check_or) {
var EXCLUDED, matched_properties, matches, _ref;
if (check_or == null) {
check_or = true;
}
matches = XRegExp.exec(line, this.rex);
if (matches === null) {
if (check_or) {
return ((_ref = this.options._or) != null ? typeof _ref.match === "function" ? _ref.match(line) : void 0 : void 0) || null;
} else {
return check_or;
}
}
EXCLUDED = ['index', 'input'];
matched_properties = {};
_.each(_.keys(matches), function(key) {
if (__indexOf.call(EXCLUDED, key) < 0 && isNaN(key)) {
return matched_properties[key] = matches[key];
}
});
return matched_properties;
};
LineMatcher.prototype.isLineMatcherClass = true;
return LineMatcher;
})();
// -- from: lib/AddressStrategy.coffee -- \\
/*
# This is the base class for all strategies
#
# TODO: get postal verification from the Universal Postal Union
#
# TODO: Address verification with eg Geocoder integration
#
# TODO: Make the Perl gods happy by outputting a big, evil regular expression
#
# TODO: Return an object that has multiple ambiguous addresses (i.e. matches
# multiple destinations)
*/
/*
# AddressStrategy
# ---------------
#
# This class is intended to be subclassed. The `do_parse_address` function
# should take a series of lines and return a simple JSONable object that
# adequately describes the components of the address.
#
# A given `subclass` should, after its definition, call subclass.register()
*/
var AddressStrategy,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
AddressStrategy = (function() {
function AddressStrategy() {}
AddressStrategy._registered_strategies = {};
/*
* Register this subclass as a strategy
* Maps @name to the subclass calling register (@name is the canonical
* iso3166 name)
*/
AddressStrategy.prototype.register = function() {
var name;
name = this.name.toLowerCase();
if (!name) {
throw new Error("Strategies require a `name`");
}
if (__indexOf.call(AddressStrategy._registered_strategies, name) >= 0) {
throw new Error("Strategy " + name + " registered twice");
}
return AddressStrategy._registered_strategies[name] = this;
};
AddressStrategy.all_strategies = function() {
return this._registered_strategies;
};
AddressStrategy.prototype.run_rex_line_strategy = function(matcher_array, addr_lines) {
var result;
result = {};
if (matcher_array.length !== addr_lines.length) {
throw new Error(("Matcher expects " + matcher_array.length + " lines,") + (" but the address has " + addr_lines.length + " lines."));
}
_.each(matcher_array, function(line_strategy, index) {
var matches, overlapping;
matches = line_strategy.match(addr_lines[index]);
if (matches === null) {
throw new Error("Line " + index + " is not a " + (line_strategy.names()));
}
overlapping = _.intersection(result, matches);
if (!_.isEmpty(overlapping)) {
throw new Error("Overlapping elements: " + (inspect(overlapping)));
}
return _.extend(result, matches);
});
return result;
};
AddressStrategy.prototype.run_line_strategies = function(strategies, addr_lines) {
var results,
_this = this;
results = null;
_.any(strategies, function(strat, index) {
var err;
try {
results = _this.run_rex_line_strategy(strat, addr_lines);
} catch (_error) {
err = _error;
return false;
}
return results !== null;
});
return results;
};
AddressStrategy.prototype.debug_line_strategies = function(strategies, addr_lines) {
var addr_str,
_this = this;
addr_str = _.map(addr_lines, function(line, idx) {
return "" + idx + ": " + line;
}).join("\n");
console.log("\n** Debugging:\n" + addr_str);
return _.each(strategies, function(strat, index) {
var err, results;
if (strat.length !== addr_lines.length) {
return;
}
try {
return results = _this.run_rex_line_strategy(strat, addr_lines);
} catch (_error) {
err = _error;
return console.log("Rex failed: " + err);
}
});
};
AddressStrategy.prototype.parse_address = function(lines, address_string, debug) {
var line_strats, results;
if (debug == null) {
debug = false;
}
if (lines.length < 2) {
throw new Error("Addresses must be at least two lines.");
}
line_strats = this.line_strategies() || [];
results = this.run_line_strategies(line_strats, lines) || {};
if (_.isEmpty(results)) {
if (debug) {
this.debug_line_strategies(line_strats, lines);
} else {
throw new Error("This address does not match a known format.");
}
}
return _.defaults(results, this.expected_fields());
};
return AddressStrategy;
})();
AddressStrategy.do_parse_address = function(addr_string, options) {
var country, country_key, last_line, lines, matches, strat, strategies, _i, _len, _ref;
options = _.defaults(options, {
defaultCountry: '',
debug: false
});
strategies = [];
matches = [];
lines = _.filter(_.map(addr_string.split('\n'), function(aline) {
return aline.trim();
}), _.identity);
if (lines.length < 2) {
throw new Error("Addresses must be at least two lines long");
}
last_line = lines[lines.length - 1];
if (_ref = last_line.toLowerCase(), __indexOf.call(_.keys(COUNTRY_NAMES_MAP), _ref) >= 0) {
country = lines.pop().toLowerCase();
} else if (options.defaultCountry) {
country = options.defaultCountry;
}
if (country) {
country_key = COUNTRY_NAMES_MAP[country.toLowerCase()];
if (__indexOf.call(_.keys(AddressStrategy._registered_strategies), country_key) >= 0) {
strategies = [AddressStrategy._registered_strategies[country_key]];
}
}
if (_.isEmpty(strategies)) {
strategies = _.values(AddressStrategy._registered_strategies);
}
for (_i = 0, _len = strategies.length; _i < _len; _i++) {
strat = strategies[_i];
matches.push(strat.parse_address(lines, addr_string, options.debug));
}
return {
matches: _.flatten(matches)
};
};
// -- from: lib/CanadaStrategy.coffee -- \\
/*
# CanadaStrategy
# --------------
# A way to parse Canadian addresses
#
# Reference: 'Addressing Guidelines'
# <http://www.canadapost.ca/tools/pg/manual/PGaddress-e.asp> 2012-11-01
#
*/
var CanadaStrategy, _ref,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
CanadaStrategy = (function(_super) {
var ADDRESSEE, CARE_OF, MORE_ADDR_INFO, MUNICIPALITY, MUNICIPALITY_WITH_POSTAL, PLAIN_STREET, POSTAL, PO_BOX, STREET_UNIT, SUITE, UNIT_STREET, person_rex, provinces_list, street_rex, street_types, unit;
__extends(CanadaStrategy, _super);
function CanadaStrategy() {
_ref = CanadaStrategy.__super__.constructor.apply(this, arguments);
return _ref;
}
CanadaStrategy.prototype.name = 'canada';
provinces_list = ["AB", "Alberta", "BC", "British\\s+Columbia", "Manitoba", "MB", "New Brunswick", "NB", "Newfoundland\\s+and\\s+Labrador", "Newfoundland", "NF", "NL", "Newfoundland\\s+&\\s+Labrador", "Northwest Territories", "NT", "Nova Scotia", "NS", "Nunavut", "NU", "ON", "Ontario", "Prince\\s+Edward\\s+Island", "PE", "PEI", "Quebec", "QC", "Saskatchewan", "SK", "Yukon", "YT"];
street_types = ["Abbey", "ABBEY", "Acres", "ACRES", "Alley", "ALLEY", "Autoroute", "AUT", "Avenue", "AVE", "Avenue", "AV", "Bay", "BAY", "Beach", "BEACH", "Bend", "BEND", "Boulevard", "BLVD", "Boulevard", "BOUL", "building", "By-pass", "BYPASS", "Byway", "BYWAY", "Campus", "CAMPUS", "Cape", "CAPE", "CAR", "Carrefour", "CARREF", "Centre", "CTR", "Centre", "C", "Cercle", "CERCLE", "Chase", "CHASE", "Chemin", "CH", "Circle", "CIR", "Circuit", "CIRCT", "Close", "CLOSE", "Common", "COMMON", "Concession", "CONC", "Corners", "CRNRS", "Cour", "COUR", "Cours", "COURS", "Court", "CRT", "Cove", "COVE", "Crescent", "CRES", "Croissant", "CROIS", "Crossing", "CROSS", "Cul-de-sac", "CDS", "Dale", "DALE", "Dell", "DELL", "Diversion", "DIVERS", "Downs", "DOWNS", "Drive", "DR", "End", "END", "Esplanade", "ESPL", "Estates", "ESTATE", "Expressway", "EXPY", "Extension", "EXTEN", "Farm", "FARM", "Field", "FIELD", "Forest", "FOREST", "Freeway", "FWY", "Front", "FRONT", "Gardens", "GDNS", "Gate", "GATE", "Glade", "GLADE", "Glen", "GLEN", "Green", "GREEN", "Grounds", "GRNDS", "Grove", "GROVE", "Harbour", "HARBR", "Heath", "HEATH", "Heights", "HTS", "Highlands", "HGHLDS", "Highway", "HWY", "Hill", "HILL", "Hollow", "HOLLOW", "Impasse", "IMP", "Inlet", "INLET", "Island", "ISLAND", "Key", "KEY", "Knoll", "KNOLL", "Landing", "LANDNG", "Lane", "LANE", "Limits", "LMTS", "Line", "LINE", "Link", "LINK", "Lookout", "LKOUT", "Loop", "LOOP", "Mall", "MALL", "Manor", "MANOR", "Maze", "MAZE", "Meadow", "MEADOW", "Mews", "MEWS", "Moor", "MOOR", "Mount", "MOUNT", "Mountain", "MTN", "Orchard", "ORCH", "Parade", "PARADE", "Parc", "PARC", "Park", "PK", "Parkway", "PKY", "Passage", "PASS", "Path", "PATH", "Pathway", "PTWAY", "Pines", "PINES", "Place", "PL", "Place", "PLACE", "Plateau", "PLAT", "Plaza", "PLAZA", "Point", "PT", "Pointe", "POINTE", "Port", "PORT", "Private", "PVT", "Promenade", "PROM", "Quai", "QUAI", "Quay", "QUAY", "Ramp", "RAMP", "Rang", "RANG", "Range", "RG", "Ridge", "RIDGE", "Rise", "RISE", "Road", "RD", "Rond-point", "RDPT", "Route", "RTE", "Row", "ROW", "Rue", "RUE", "Ruelle", "RLE", "Run", "RUN", "Sentier", "SENT", "Square", "SQ", "Street", "ST", "Subdivision", "SUBDIV", "Terrace", "TERR", "Terrasse", "TSSE", "Thicket", "THICK", "Towers", "TOWERS", "Townline", "TLINE", "Trail", "TRAIL", "Turnabout", "TRNABT", "Vale", "VALE", "Via", "VIA", "View", "VIEW", "Village", "VILLGE", "Villas", "VILLAS", "Vista", "VISTA", "Voie", "VOIE", "Walk", "WALK", "Way", "WAY", "Wharf", "WHARF", "Wood", "WOOD", "Wynd", "WYND"];
person_rex = "(?: \\p{L} | [\\s\\-\\.])+ ";
ADDRESSEE = new LineMatcher("Addressee", "(?<addressee> " + person_rex + ")", {
valid_tests: {
"Mary Swånson": {
addressee: "Mary Swånson"
}
},
invalid_tests: ["100 Sampsonite Drive"]
});
CARE_OF = new LineMatcher("Care of (c/o)", "(?: c/o | ℅) \\s+ (?<care_of> " + person_rex + ")", {
valid_tests: {
"c/o Sinterklaas": {
care_of: "Sinterklaas"
}
},
invalid_tests: ["no c/o? fine. be that way."]
});
street_rex = "(?<street_number> \\d+) \\s+\n(?<street_name> (?: \\p{L}|[\\.\\s\\-'])+? )";
PLAIN_STREET = new LineMatcher("Plain street", street_rex, {
valid_tests: {
"42 Wallaby Lane": {
street_number: "42",
street_name: "Wallaby Lane"
},
"100 Hûntley Street": {
street_number: "100",
street_name: "Hûntley Street"
}
},
invalid_tests: ["Wallaby 12 Lane", "Suite 100, 42 Wallaby Lane", "42 Wallaby Lane, fl. 2-00"]
});
unit = "(?:\n (?:\n (?: apt\\.? | apartment | unit | suite | floor | fl\\.? | app | bureau )\n \\s* (?: \\s [#] | no\\.? | number \s+ )?\n | [#]\n | no\\.\n )\n \\s*\n [\\d\\w]+\n|\n [\\d\\w]+\n \\s*\n (?: floor | fl\\. )\n)";
UNIT_STREET = new LineMatcher("Unit - Street", "(?<suite> " + unit + "|\\d+) \\s* [\\-,\\s] \\s* " + street_rex, {
valid_tests: {
"Suite 1100a - 42 Wallaby Ave.": {
suite: "Suite 1100a",
street_number: "42",
street_name: "Wallaby Ave."
}
},
invalid_tests: ["100 Wish Line, Unit #212", "Any street with no unit"]
});
STREET_UNIT = new LineMatcher("Street - Unit", "" + street_rex + " \\s* [,\\-]? \\s* (?<suite> " + unit + ")", {
valid_tests: {
"42 Wallaby Ave., Suite 1100A": {
suite: "Suite 1100A",
street_number: "42",
street_name: "Wallaby Ave."
},
"1 Rainy Road #115": {
suite: "#115",
street_number: "1",
street_name: "Rainy Road"
}
},
invalid_tests: ["100 100 100", "Any street without a given unit"]
});
PO_BOX = new LineMatcher("Post Office Box", "(?<po_box>P\\.?\\s* O\\.?\\s* BOX \\s* \\s* \\d+ \\s* ,? \\s*\n(?: (?:stn\\.?|station|rpo\\.?|rr\\.?) \\s* \\w+)? )", {
valid_tests: {
"PO Box 1200": {
po_box: "PO Box 1200"
},
"P.O. Box 1200 stn A": {
po_box: "P.O. Box 1200 stn A"
},
"P.O. Box 39, RR1": {
po_box: "P.O. Box 39, RR1"
}
},
invalid_tests: ["No PO"]
});
MORE_ADDR_INFO = new LineMatcher("Additional Address Anformation", "(?<additional_address_info> .+)", {
valid_tests: {
"Anything": {
additional_address_info: "Anything"
}
},
invalid_tests: [""]
});
SUITE = new LineMatcher("Suite number", "(?<suite> " + unit + ")", {
valid_tests: {
'Suite # 1024': {
suite: 'Suite # 1024'
}
},
invalid_tests: ['10 10']
});
MUNICIPALITY = new LineMatcher("Municipality and Province", "(?<municipality> (?:\\p{L}|[\\-'\\s\\.])+?) \\s* ,? \\s* (?<province> " + (provinces_list.join("|")) + ")", {
valid_tests: {
"Bras-d'Or, NS": {
municipality: "Bras-d'Or",
province: 'NS'
},
"St. Pétersberg, ON": {
municipality: "St. Pétersberg",
province: "ON"
},
"Hudsonville, QC": {
municipality: "Hudsonville",
province: "QC"
}
},
invalid_tests: ["St. Peteresberg, Peterborough, 10005"]
});
POSTAL = new LineMatcher("Postal code", "(?<postal> \s*\\w\\d\\w\\s*\\d\\w\\d)", {
valid_tests: {
"H0H0H0": {
postal: 'H0H0H0'
},
"H0H 0H0": {
postal: 'H0H 0H0'
}
},
invalid_tests: ["HoH 0H0", "HoH 0ü0"]
});
MUNICIPALITY_WITH_POSTAL = new LineMatcher("Municipality, province and postal code", "" + MUNICIPALITY.expression + " (?: \\s* ,? \\s* " + POSTAL.expression + ")?", {
valid_tests: {
"One, QC, M5R 1V2": {
municipality: "One",
province: "QC",
postal: "M5R 1V2"
},
"TreeTree, MB": {
municipality: "TreeTree",
province: "MB",
postal: void 0
}
},
invalid_tests: ["Two, Two, Two"]
});
CanadaStrategy.prototype.expected_fields = function() {
return {
suite: '',
addressee: '',
care_of: '',
street_number: '',
street_name: '',
additional_address_info: '',
po_box: '',
municipality: '',
province: '',
postal: '',
country: 'Canada'
};
};
CanadaStrategy.prototype.line_strategies = function() {
var lms, street;
lms = new LineMatcherStrategy();
street = PLAIN_STREET.or(UNIT_STREET).or(STREET_UNIT).or(PO_BOX).or(SUITE);
lms.add(ADDRESSEE.optional(), CARE_OF.optional(), street.optional(), street, MUNICIPALITY, POSTAL);
lms.add(ADDRESSEE.optional(), CARE_OF.optional(), street.optional(), street, MUNICIPALITY_WITH_POSTAL);
lms.add(ADDRESSEE, MORE_ADDR_INFO.optional(), CARE_OF.optional(), street.optional(), street, MUNICIPALITY, POSTAL);
lms.add(ADDRESSEE, MORE_ADDR_INFO.optional(), CARE_OF.optional(), street.optional(), street, MUNICIPALITY_WITH_POSTAL);
return lms.all();
};
return CanadaStrategy;
})(AddressStrategy);
new CanadaStrategy().register();
// -- from: lib/SnailMailAddressParser.coffee -- \\
var SnailMailAddressParser;
SnailMailAddressParser = (function() {
SnailMailAddressParser.prototype.AddressStrategy = AddressStrategy;
SnailMailAddressParser.prototype.LineMatcher = LineMatcher;
SnailMailAddressParser.prototype.LineMatcherStrategy = LineMatcherStrategy;
SnailMailAddressParser.prototype.Version = VERSION;
function SnailMailAddressParser() {}
SnailMailAddressParser.prototype.parse = function(str, options) {
if (options == null) {
options = {};
}
if (!_.isString(str)) {
throw new Error("Address must be a string, got " + (typeof str) + ".");
}
return AddressStrategy.do_parse_address(str, options);
};
return SnailMailAddressParser;
})();
/* ---- End AMD content ---- */
return new SnailMailAddressParser();
}));