UNPKG

zcs

Version:

A quick and light esm / node module to look up state city or zips to get either.

640 lines (559 loc) 17.9 kB
Object.defineProperty(exports, "__esModule", { value: true }); const { state_names } = require("./data/states/names.js"); const { state_indexes } = require("./data/states/index.js"); const { state_data } = require("./data/states/data.js"); const { zip_indexes } = require("./data/zips/index.js"); const { zip_data } = require("./data/zips/data.js"); const { zips } = require("./data/zips/zips.js"); const { city_names } = require("./data/cities/names.js"); const { city_indexes } = require("./data/cities/index.js"); const { city_data } = require("./data/cities/data.js"); const { city_population } = require("./data/cities/population.js"); const { roads } = require("./data/utils/roads.js"); //optional street var street_data, street_names, street_index,streets_by_zip; //optional location var mgrs_data, street_mgrs_data, util_mgrs; function validZip(zip) { return zip_indexes[zip] != undefined; } function validState(state) { return state_indexes[state.toUpperCase()] != undefined; } function validCity(city) { return city_indexes[city.toUpperCase()] != undefined; } function getCitiesNameAndPopulationByState(state) { try { state = state.toUpperCase(); var t = state_data[state_names.indexOf(state)]; const keys = Object.keys(t); var tt = []; for (let i = 0; i < keys.length; i++) { const _zips = t[keys[i]]; var zipsn = []; var city = { name: city_names[keys[i]], zip: null, population: 0 } for (let j = 0; j < _zips.length; j++) { if(city_names[zip_data[_zips[j]][1]] === city.name) { if(city.population < city_population[_zips[j]]) { city.population = city_population[_zips[j]]; city.zip = zips[_zips[j]] || city.zip || null; } } else { //console.log(city.name,city_population[_zips[j]],zips[_zips[j]]) } } tt.push(city); } return tt.sort((a,b)=>b.population-a.population); } catch (error) { throw new Error("State or City Not Found"); } } function getCitiesNameByState(state) { try { state = state.toUpperCase(); var t = state_data[state_names.indexOf(state)]; const keys = Object.keys(t); var tt = []; for (let i = 0; i < keys.length; i++) { tt.push(city_names[keys[i]]); } return tt.sort((a, b) => { return (a > b ? 1 : (a === b ? 0 : -1)) }); } catch (error) { throw new Error("State or City Not Found"); } } function getByStateCity(state, city) { try { state = state.toUpperCase(); if (!city) { var t = state_data[state_names.indexOf(state)]; const keys = Object.keys(t); var tt = {}; for (let i = 0; i < keys.length; i++) { const city = city_names[keys[i]]; const _zips = t[keys[i]]; var zipsn = []; for (let j = 0; j < _zips.length; j++) { zipsn.push(zips[_zips[j]]); } tt[city] = zipsn; } return tt; } city = city.toUpperCase(); const _zips = state_data[state_names.indexOf(state)][city_names.indexOf(city)]; var zipsn = []; for (let j = 0; j < _zips.length; j++) { zipsn.push(zips[_zips[j]]); } return zipsn; } catch (error) { throw new Error("State or City Not Found"); } } function getByZip(zip) { try { var t = zip_data[zip_indexes[zip]]; return { state: state_names[t[0]], city: city_names[t[1]], }; } catch (error) { throw new Error("Zip Code Not Found"); } } function getByCityState(city, state) { try { city = city.toUpperCase(); if (!state) { var t = city_data[city_indexes[city]]; var tt = {}; for (let i = 0; i < t.length; i++) { const state = state_names[t[i]]; tt[state] = getByStateCity(state, city); } return tt; } state = state.toUpperCase(); return getByStateCity(state, city); } catch (error) { throw new Error("City or State Not Found"); } } function zipLookAhead(zip, ammount = 10) { return _search(zips, zip, ammount); } function stateLookAhead(state, ammount = 10) { return _search(state_names, state.toUpperCase(), ammount); } function cityLookAhead(city, ammount = 10) { return _search(city_names, city.toUpperCase(), ammount); } function _search(arr, thing, ammount, skip = 0) { var t = []; for (let i = 0; i < arr.length; i++) { if (arr[i].startsWith(thing) && --skip <= 0) { t.push(arr[i]); } if (ammount && t.length >= ammount) { break; } } return t; } // Optional Street Functions /** * Get all street names by zip code * @param {*} zip - zip code * @param {*} opts - skip, limit * @returns */ async function getStreetsbyZip(zip, opts = {}) { var t = streets_by_zip[zip_indexes[zip]]; opts.skip = opts.skip || 0; opts.limit = (opts.limit + opts.skip || 0) || t.length - opts.skip; var tt = []; for(var i = opts.skip; i < opts.limit; i++) { if(tt.indexOf(street_names[t[i]]) !== -1){continue}; tt.push(street_names[t[i]]) } if(opts.skip || (opts.limit < tt.length && opts.limit !== 0)) { return tt.sort((a, b) => { return (a > b ? 1 : (a === b ? 0 : -1))}).splice(opts.skip, opts.limit && opts.limit < tt.length ? opts.limit + opts.skip : tt.length); } else { return tt.sort((a, b) => { return (a > b ? 1 : (a === b ? 0 : -1))}); } } /** * Get all street names by state and city * @param {*} zip - zip code * @param {*} opts - skip, limit * @returns */ async function getStreetsbyStateAndCity(state,city, opts = {}) { var tt = []; var zips = getByStateCity(state,city); opts.skip = opts.skip || 0; opts.limit = opts.limit || 0; for(var i = 0; i < zips.length; i++) { var t = streets_by_zip[zip_indexes[zips[i]]] || []; for(var j = 0; j < t.length; j++) { if(tt.indexOf(street_names[t[j]]) !== -1){continue}; tt.push(street_names[t[j]]) } } return tt.sort((a, b) => { return (a > b ? 1 : (a === b ? 0 : -1)) }).slice(opts.skip, opts.limit && opts.limit < tt.length ? opts.limit + opts.skip : tt.length);; } /** * Get all street numbers by street name and zip code * @param {*} streetName - street name * @param {*} zip - zip code * @param {*} opts - skip, limit * @returns */ async function getStreetNumbersByNameAndZip(streetName,zip, opts = {}) { const streetIndex = street_index[streetName.toUpperCase()]; var zipindex = zip_indexes[zip]; var t = JSON.parse((await street_data.get(streetIndex)).toString()); var numbers = Object.keys(t); opts.skip = opts.skip || 0; opts.limit = (opts.limit + opts.skip || 0) || numbers.length - opts.skip; var n = []; for(var i = 0; i < numbers.length; i++) { if(n.length >= opts.limit) { break; } var zips = t[numbers[i]]; for(var j = 0; j < zips.length; j++) { if(zips[j] === zipindex) { if(opts.skip <= 0) { n.push(numbers[i]) }else { opts.skip--; } break; } } } return n; } /** * Get all street numbers by street name * @param {*} streetName - street name * @param {*} opts - skip, limit * @returns */ async function getStreetNumbersByName(streetName, opts = {}) { const streetIndex = street_index[streetName.toUpperCase()]; var t = JSON.parse((await street_data.get(streetIndex)).toString()); var numbers = Object.keys(t); opts.skip = opts.skip || 0; opts.limit = (opts.limit + opts.skip || 0) || numbers.length - opts.skip; var n = []; for(var i = opts.skip; i < opts.limit; i++) { n.push(numbers[i]); } return n; } /** * Get all zip codes by street name * @param {*} streetName - street name * @returns */ async function getZipsByStreetName(streetName) { const t = JSON.parse( (await street_data.get(street_index[streetName.toUpperCase()])).toString() ); const keys = Object.keys(t); var zipsn = []; for (let i = 0; i < keys.length; i++) { const streetNumbers = t[keys[i]]; for (var j = 0; j < streetNumbers.length; j++) { if ( zipsn.indexOf(zips[streetNumbers[j]]) == -1 && zips[streetNumbers[j]] != undefined ) { zipsn.push(zips[streetNumbers[j]]); } } } return zipsn.sort((a,b)=>a-b); } /** * Look ahead for street names * @param {*} street - street name * @param {*} ammount - ammount of lookaheads */ function streetLookAhead(street, ammount = 10) { return _search(street_names, street.toUpperCase(), ammount); } /** * Look ahead for street numbers * @param {*} number - street number * @param {*} street - street name * @param {*} ammount - ammount of lookaheads * @param {*} opts = state, city, skip, full_number_provided * @returns */ async function streetNumberLookAhead(number, street, ammount = 10, opts = {}) { opts.skip = opts.skip || 0; opts.lookaheads = opts.lookaheads || []; var streets = _search(street_names, street.toUpperCase(), ammount*2, opts.skip ); if(streets.length <= 0) { return opts.lookaheads; } for(var i = 0; i < streets.length; i++) { try { var t = JSON.parse((await street_data.get(street_index[streets[i]])).toString()); var keys = null; if(opts.full_number_provided) { keys = t[`${number}`] ? [`${number}`] : []; } else { keys = _search( Object.keys(t), number); } for(var j = 0; j < keys.length; j++) { var streetNumber = keys[j] var szips = t[keys[j]]; var nstreet = null; for(var k = 0; k < szips.length; k++) { var statecity = getByZip(zips[szips[k]]) if(opts.lookaheads.length >= ammount) { break; } if((!opts.state || opts.state === statecity.state) && (!opts.city || opts.city === statecity.city) && (!opts.full_number_provided || (opts.full_number_provided && Number(streetNumber) === number)) ){ nstreet = { full_address: `${streetNumber} ${streets[i]} ${statecity.city}, ${statecity.state} ${zips[szips[k]]}`, number: streetNumber, street: streets[i], city: statecity.city, state: statecity.state, zip: zips[szips[k]], street_index: street_index[streets[i]] } opts.lookaheads.push(nstreet); } } if(nstreet && opts.lookaheads.length >= ammount) { break; } } } catch (error) { } } opts.skip = opts.skip+(ammount*2); return opts.lookaheads.length >= ammount ? opts.lookaheads.sort((a,b)=>a.street.length-b.street.length) : streetNumberLookAhead(number,street,ammount,opts); } // Optional Street Location Functions /** * Gets the street location in MGRS by number, street, and zip * @param {*} number - Street number * @param {*} street - Street name * @param {*} zip - Zip code * @param {*} searchNearist - (Default True) If the street number is not found, search for the nearest street number * @returns */ async function getLocationByStreet(street, zip, searchNearist = true) { var t; street = street.toUpperCase().split(' '); var number = street.shift(); street = street.join(' '); try { t = (await street_mgrs_data.get(`${street_index[street.toUpperCase()]}:${zip_indexes[zip]}:${number}`)) } catch (error) { var temp = street.split(' '); var rdtype = temp.pop(); if(roads[rdtype].full == rdtype) { rdtype = roads[rdtype].abbr; } else { rdtype = roads[rdtype].full; } street = temp.join(' ') + ` ${rdtype}`; try { t = (await street_mgrs_data.get(`${street_index[street.toUpperCase()]}:${zip_indexes[zip]}:${number}`)) } catch (error) { } } if(!t && searchNearist) { var last_distance = 9999999999; var it = await street_mgrs_data.iterator({ gte: `${street_index[street.toUpperCase()]}:${zip_indexes[zip]}:0`, lte: `${street_index[street.toUpperCase()]}:${zip_indexes[zip]}:9999999999` }) var tmp = null; var last_row = null; while(tmp = await it.next()) { var street_num = Number(tmp[0].toString().split(':').pop()); var distance = Math.abs(street_num - number); if(last_distance < distance) { it.end(); return last_row[1].toString(); } last_row = tmp; last_distance = distance; } } else { return t.toString(); } return null; } /** * Gets the street location in Lat and long by number, street, and zip * @param {*} street - Street * @param {*} zip - Zip code * @returns */ async function getLocationByStreetLL(street, zip) { var loc = await getLocationByStreet(street, zip); if(loc) { loc = util_mgrs.toPoint(loc); loc = { lat: loc[1], long: loc[0] } } return loc; } /** * Gets all streets in the area around in the distance provided * @param {*} mgrs - MGRS location * @param {*} distance - (Default 100m) Distance in meters Allowed (100m, 1km, 10km, 100km) */ async function getStreetsByLocation(mgrs, distance = '100m') { if(!street_index) { throw new Error('Requires zcs-streets module to be loaded'); } mgrs = mgrs.toUpperCase(); var tmgrs = mgrs; if (isNaN(mgrs[1])) { tmgrs = "0" + mgrs; } var block_of_mgrs = []; if(mgrs.length == 15){ tmgrs = mgrs.substring(0, 3) + mgrs.substring(3, 5) + mgrs.substring(5, 6) + mgrs.substring(6, 7) + mgrs.substring(7, 8) + mgrs.substring(10, 11) + mgrs.substring(11, 12) + mgrs.substring(12, 13); } else if(mgrs.length == 13) { tmgrs = mgrs.substring(0, 3) + mgrs.substring(3, 5) + mgrs.substring(5, 6) + mgrs.substring(6, 7) + mgrs.substring(7, 8) + mgrs.substring(9, 10) + mgrs.substring(10, 11) + mgrs.substring(11, 12); } if(distance == '100m') { block_of_mgrs.push(tmgrs); } else if(distance == '1km') { var first_m = tmgrs.substring(0,7) var last_m = tmgrs.substring(8,10) for(var i = 0; i < 10; i++) { for(var j = 0; j < 10; j++) { block_of_mgrs.push(`${first_m}${i}${last_m}${j}`); } } } else if(distance == '10km') { var first_m = tmgrs.substring(0,6) var last_m = tmgrs.substring(8,9) for(var i = 0; i < 100; i++) { for(var j = 0; j < 100; j++) { block_of_mgrs.push(`${first_m}${i}${last_m}${j}`); } } } else if(distance == '100km') { var first_m = tmgrs.substring(0,5) var last_m = tmgrs.substring(8,8) for(var i = 0; i < 1000; i++) { for(var j = 0; j < 1000; j++) { block_of_mgrs.push(`${first_m}${i}${last_m}${j}`); } } } else { throw new Error('Invalid distance'); } var streets = []; for (let i = 0; i < block_of_mgrs.length; i++) { try { var mgrs = block_of_mgrs[i]; var tmp = await mgrs_data.get(mgrs); await __streetsByLocationParse([mgrs,tmp], streets); } catch (error) { //console.log(error) } } return streets; } async function __streetsByLocationParse(tmp, streets) { var mgrs = tmp[0].toString(); var tstreets = tmp[1].toString(); if(!tstreets) { retrun; } tstreets = JSON.parse(tstreets); var street_indexes = Object.keys(tstreets); for(var i = 0; i < street_indexes.length; i++) { var street_numbers = tstreets[street_indexes[i]]; var zip_street = street_indexes[i].split(':'); var street_zip = zips[zip_street[1]]; var street_name = street_names[zip_street[0]]; var street_city_state = {city: 'Unknown', state: 'Unknown'}; try { street_city_state = getByZip(street_zip); } catch (error) {} for(var j = 0; j < street_numbers.length; j++) { var street_loc = mgrs; try { street_loc = (await street_mgrs_data.get(`${street_indexes[i]}:${street_numbers[j]}`)).toString(); } catch (error) { } streets.push({ street:`${street_numbers[j]} ${street_name}`, city: street_city_state.city, state: street_city_state.state, zip: street_zip, location: street_loc }) } } } /** * * @param {*} opts.street.enabled - if true, will enable by street searches * @param {*} opts.street.location - location of the zcs-streets repo * @param {*} opts.geo.enabled - if true, will enable geo searches * @param {*} opts.geo.location - location of the zcs-location repo * @returns */ exports.zcs = (opts) => { const functions = { getByCityState, getByZip, getByStateCity, zipLookAhead, stateLookAhead, cityLookAhead, validZip, validState, validCity, getCitiesNameByState, getCitiesNameAndPopulationByState }; if (opts && opts.street && opts.street.enabled) { var zcs_street = require(opts.street.location).zcs_street(); street_data = zcs_street.street_data; street_names = zcs_street.street_names; street_index = zcs_street.street_index; streets_by_zip = zcs_street.streets_by_zip; functions.getStreetsbyZip = getStreetsbyZip; functions.getStreetsbyStateAndCity = getStreetsbyStateAndCity; functions.getStreetNumbersByName = getStreetNumbersByName; functions.getStreetNumbersByNameAndZip = getStreetNumbersByNameAndZip; functions.getZipsByStreetName = getZipsByStreetName; functions.streetLookAhead = streetLookAhead; functions.streetNumberLookAhead = streetNumberLookAhead; } if (opts && opts.geo && opts.geo.enabled) { var zcs_location = require(opts.geo.location).zcs_location(); street_mgrs_data = zcs_location.street_mgrs_data; mgrs_data = zcs_location.mgrs_data; util_mgrs = zcs_location.mgrs; functions.getLocationByStreet = getLocationByStreet; functions.getLocationByStreetLL = getLocationByStreetLL; functions.getStreetsByLocation = getStreetsByLocation; } return functions; };