diff --git a/Readme.md b/Readme.md index 6a24f44..582f0bd 100644 --- a/Readme.md +++ b/Readme.md @@ -61,6 +61,7 @@ If successful, geocoding service will return object with field `places` - an arr - `place` - place name (may be absent if address doesn't correspond to a named place) - `type` - place type - `address` - formated address +- `normal` - normalized address: `house street,town,province,country_code` - `house` - building number - `street` - street name - `community` - neighborhood or village diff --git a/lib/service/index.js b/lib/service/index.js index f60ccad..05e49e3 100644 --- a/lib/service/index.js +++ b/lib/service/index.js @@ -137,6 +137,7 @@ function init(options) { switch (options.status(err, response)) { case status.success: const res = options.processResponse(response, query, {}); + res.places?.forEach(p => p.normal = util.stringify(p) || ''); resolve(res); break; case status.failure: diff --git a/lib/service/opencage/index.js b/lib/service/opencage/index.js index f18f3df..c0b4121 100644 --- a/lib/service/opencage/index.js +++ b/lib/service/opencage/index.js @@ -108,7 +108,7 @@ function init(options) { res.county = components.county; } if (components.state_code) { - res.province = components.state_code; + res.province = normalize.state(components.state) || components.state_code; } if (components.country) { res.country = normalize.country(components.country); diff --git a/lib/service/positionstack/index.js b/lib/service/positionstack/index.js index 3f98c67..8abf3a6 100644 --- a/lib/service/positionstack/index.js +++ b/lib/service/positionstack/index.js @@ -66,7 +66,7 @@ function map(f) { house: f.number, street: f.street, town: guessCity(f), - province: f.region_code, + province: normalize.state(f.region) || f.region_code, country: normalize.country(f.country) }; if (f.type === 'address') { diff --git a/lib/service/util.js b/lib/service/util.js index 763144a..a5bcdf9 100644 --- a/lib/service/util.js +++ b/lib/service/util.js @@ -1,6 +1,9 @@ +const { stringify } = require('@furkot/address'); + module.exports = { address, defaults, + stringify, removeEmpties, toObject, withTimeout diff --git a/test/replay/api.opencagedata.com-443/address b/test/replay/api.opencagedata.com-443/address new file mode 100644 index 0000000..3bbb385 --- /dev/null +++ b/test/replay/api.opencagedata.com-443/address @@ -0,0 +1,19 @@ +GET /geocode/v1/json?q=2200+S.+Jason+St%2C+Denver%2C+CO+80223&no_annotations=1&key=furkot +accept: application/json +accept-encoding: gzip,deflate + +HTTP/1.1 200 OK +date: Sun, 11 Feb 2024 21:21:23 GMT +server: Apache +access-control-allow-origin: * +x-ratelimit-limit: 2500 +x-ratelimit-remaining: 2365 +x-ratelimit-reset: 1707696000 +vary: Accept-Encoding +x-frame-options: DENY +x-xss-protection: 1; mode=block +content-type: application/json; charset=utf-8 +strict-transport-security: max-age=31536000; includeSubDomains; preload +connection: close + +{"documentation":"https://opencagedata.com/api","licenses":[{"name":"see attribution guide","url":"https://opencagedata.com/credits"}],"rate":{"limit":2500,"remaining":2365,"reset":1707696000},"results":[{"bounds":{"northeast":{"lat":39.676586,"lng":-104.999304},"southwest":{"lat":39.676486,"lng":-104.999404}},"components":{"ISO_3166-1_alpha-2":"US","ISO_3166-1_alpha-3":"USA","ISO_3166-2":["US-CO"],"_category":"building","_normalized_city":"Denver","_type":"building","city":"Denver","continent":"North America","country":"United States","country_code":"us","house_number":"2200","postcode":"80223","road":"South Jason Street","state":"Colorado","state_code":"CO"},"confidence":10,"formatted":"2200 South Jason Street, Denver, CO 80223, United States of America","geometry":{"lat":39.676536,"lng":-104.999354}},{"components":{"ISO_3166-1_alpha-2":"US","ISO_3166-1_alpha-3":"USA","ISO_3166-2":["US-CO"],"_category":"building","_normalized_city":"Denver","_type":"building","continent":"North America","country":"United States of America","country_code":"us","house_number":"2200","road":"S Jason St","state":"Colorado","state_code":"CO","town":"Denver"},"confidence":10,"formatted":"2200 S Jason St, Denver, CO, United States of America","geometry":{"lat":39.676659,"lng":-104.999461}},{"bounds":{"northeast":{"lat":39.725665,"lng":-104.98745},"southwest":{"lat":39.660455,"lng":-105.018673}},"components":{"ISO_3166-1_alpha-2":"US","ISO_3166-1_alpha-3":"USA","ISO_3166-2":["US-CO"],"_category":"postcode","_type":"postcode","continent":"North America","country":"United States of America","country_code":"us","county":"Denver County","postcode":"80223","state":"Colorado","state_code":"CO"},"confidence":7,"formatted":"Denver County, CO 80223, United States of America","geometry":{"lat":39.7002,"lng":-105.0028}}],"status":{"code":200,"message":"OK"},"stay_informed":{"blog":"https://blog.opencagedata.com","mastodon":"https://en.osm.town/@opencage"},"thanks":"For using an OpenCage API","timestamp":{"created_http":"Sun, 11 Feb 2024 21:21:23 GMT","created_unix":1707686483},"total_results":3} diff --git a/test/service/geocodio/index.js b/test/service/geocodio/index.js index dd4cb7d..b745839 100644 --- a/test/service/geocodio/index.js +++ b/test/service/geocodio/index.js @@ -18,6 +18,7 @@ describe('geocodio geocoding', function () { result.places[0].should.deepEqual({ ll: [-87.12502, 39.52365], address: 'Brazil, IN 47834', + normal: 'Brazil,IN,US', town: 'Brazil', county: 'Clay County', province: 'IN', @@ -45,6 +46,7 @@ describe('geocodio geocoding', function () { result.places[0].should.deepEqual({ ll: [-111.400596, 45.284265], address: '50 Big Sky Resort Rd, Big Sky, MT 59716', + normal: '50 Big Sky Resort,Big Sky,MT,US', house: '50', street: 'Big Sky Resort', county: 'Madison County', diff --git a/test/service/graphhopper/index.js b/test/service/graphhopper/index.js index ffa698b..0ebcc1c 100644 --- a/test/service/graphhopper/index.js +++ b/test/service/graphhopper/index.js @@ -21,10 +21,11 @@ describe('graphhopper geocoding', function () { ll: [-46.8359735, -23.5370962], type: 'residential', street: 'Rua Cafelândia', - address: 'Rua Cafelândia, Carapicuíba, São Paulo, Brasil', + address: 'Rua Cafelândia, Carapicuíba, São Paulo, Brazil', + normal: 'Rua Cafelândia,Carapicuíba,São Paulo,BR', town: 'Carapicuíba', province: 'São Paulo', - country: 'Brasil' + country: 'Brazil' }); }); @@ -42,6 +43,7 @@ describe('graphhopper geocoding', function () { place: 'SS Sołdek', type: 'museum', address: 'Długie Pobrzeże, Gdansk, Pomeranian Voivodeship, Poland', + normal: 'Długie Pobrzeże,Gdansk,Pomeranian Voivodeship,PL', street: 'Długie Pobrzeże', province: 'Pomeranian Voivodeship', town: 'Gdansk', @@ -64,14 +66,16 @@ describe('graphhopper geocoding', function () { type: 'peak', country: 'USA', place: 'Main Street Cemetery', - address: 'USA' + address: 'USA', + normal: 'US' }); result.places[1].should.deepEqual({ ll: [-69.2728254, 44.8350646], type: 'dam', country: 'USA', place: 'Main Street Dam', - address: 'USA' + address: 'USA', + normal: 'US' }); result.places[2].should.deepEqual({ ll: [-71.086670478147, 42.36274665], @@ -82,14 +86,16 @@ describe('graphhopper geocoding', function () { province: 'MA', country: 'USA', place: '325 Main Street', - address: '325 Main Street, Cambridge, MA, USA' + address: '325 Main Street, Cambridge, MA, USA', + normal: '325 Main Street,Cambridge,MA,US' }); result.places[3].should.deepEqual({ ll: [-71.6192199, 42.5524712], type: 'dam', country: 'USA', place: 'West Main Street Dam', - address: 'USA' + address: 'USA', + normal: 'US' }); result.places[4].should.deepEqual({ ll: [-10.6756677, 6.5080848], @@ -97,7 +103,8 @@ describe('graphhopper geocoding', function () { province: 'Montserrado County', country: 'Liberia', place: 'Main Street', - address: 'Montserrado County, Liberia' + address: 'Montserrado County, Liberia', + normal: 'Montserrado County,LR' }); }); @@ -114,6 +121,7 @@ describe('graphhopper geocoding', function () { place: 'Beryl\'s Restaurant', type: 'restaurant', address: 'Woermann St, Swakopmund, Erongo Region, Namibia', + normal: 'Woermann St,Swakopmund,Erongo Region,NA', street: 'Woermann St', province: 'Erongo Region', town: "Swakopmund", @@ -136,7 +144,8 @@ describe('graphhopper geocoding', function () { province: 'MT', country: 'USA', place: 'Mountain Mall', - address: 'Black Eagle, MT, USA' + address: 'Black Eagle, MT, USA', + normal: 'Black Eagle,,MT,US' }); result.places[1].should.deepEqual({ ll: [-111.4011158, 45.2839783], @@ -147,7 +156,8 @@ describe('graphhopper geocoding', function () { province: 'MT', country: 'USA', place: 'Big Sky Resort', - address: '50 Big Sky Resort Road, Big Sky, MT, USA' + address: '50 Big Sky Resort Road, Big Sky, MT, USA', + normal: '50 Big Sky Resort Road,Big Sky,MT,US' }); result.places[2].should.deepEqual({ ll: [-111.40110501870444, 45.284622], @@ -156,7 +166,8 @@ describe('graphhopper geocoding', function () { province: 'MT', country: 'USA', place: 'Basecamp', - address: 'Black Eagle, MT, USA' + address: 'Black Eagle, MT, USA', + normal: 'Black Eagle,,MT,US' }); result.places[3].should.deepEqual({ ll: [-111.4015212, 45.2842756], @@ -166,7 +177,8 @@ describe('graphhopper geocoding', function () { province: 'MT', country: 'USA', place: 'Different Spokes', - address: 'Mountain to Meadow, Big Sky, MT, USA' + address: 'Mountain to Meadow, Big Sky, MT, USA', + normal: 'Mountain to Meadow,Big Sky,MT,US' }); result.places[4].should.deepEqual({ ll: [-111.40158763890292, 45.284196300000005], @@ -176,7 +188,8 @@ describe('graphhopper geocoding', function () { province: 'MT', country: 'USA', place: 'Snowcrest Lodge', - address: 'Mountain to Meadow, Big Sky, MT, USA' + address: 'Mountain to Meadow, Big Sky, MT, USA', + normal: 'Mountain to Meadow,Big Sky,MT,US' }); }); }); diff --git a/test/service/hogfish/index.js b/test/service/hogfish/index.js index f21f1d4..719b73d 100644 --- a/test/service/hogfish/index.js +++ b/test/service/hogfish/index.js @@ -47,7 +47,8 @@ describe('hogfish geocoding', function () { }, osm: { id: '0000000041fc198163200000' } }, - address: '11005 E Briarwood Ave, Centennial, CO' + address: '11005 E Briarwood Ave, Centennial, CO', + normal: '11005 E Briarwood Ave,Centennial,CO,US' }); }); @@ -86,7 +87,8 @@ describe('hogfish geocoding', function () { url: 'https://www.booking.com/hotel/us/hyatt-house-denver-tech-center.html' } }, - address: '9280 E Costilla Ave, Englewood, CO, United States' + address: '9280 E Costilla Ave, Englewood, CO, United States', + normal: '9280 E Costilla Ave,Englewood,CO,US' }); }); }); diff --git a/test/service/locationiq/index.js b/test/service/locationiq/index.js index f91968e..a5b7bc8 100644 --- a/test/service/locationiq/index.js +++ b/test/service/locationiq/index.js @@ -21,6 +21,7 @@ describe('locationiq geocoding', function () { ll: [-46.8359735, -23.5370962], type: 'road', address: 'Rua Cafelândia, Carapicuíba, São Paulo, Brazil', + normal: 'Rua Cafelândia,Carapicuíba,São Paulo,BR', street: 'Rua Cafelândia', town: 'Carapicuíba', province: 'São Paulo', @@ -41,11 +42,12 @@ describe('locationiq geocoding', function () { ll: [18.658631239705393, 54.35145095], place: 'SS Sołdek', type: 'museum', - address: 'Długie Pobrzeże, Gdańsk, województwo pomorskie, Polska', + address: 'Długie Pobrzeże, Gdańsk, województwo pomorskie, Poland', + normal: 'Długie Pobrzeże,Gdańsk,województwo pomorskie,PL', street: 'Długie Pobrzeże', province: 'województwo pomorskie', town: 'Gdańsk', - country: 'Polska' + country: 'Poland' }); }); @@ -67,6 +69,7 @@ describe('locationiq geocoding', function () { type: 'restaurant', ll: [-73.9904326, 40.7442736], address: '30 West 26th Street, New York, NY, USA', + normal: '30 West 26th Street,New York,NY,US', house: '30', street: 'West 26th Street', town: 'New York', @@ -78,6 +81,7 @@ describe('locationiq geocoding', function () { type: 'disused', ll: [-73.9903515, 40.7442363], address: '30 West 26th Street, New York, NY, USA', + normal: '30 West 26th Street,New York,NY,US', house: '30', street: 'West 26th Street', town: 'New York', @@ -89,6 +93,7 @@ describe('locationiq geocoding', function () { type: 'company', ll: [-73.9903727, 40.7442104], address: '30 West 26th Street, New York, NY, USA', + normal: '30 West 26th Street,New York,NY,US', house: '30', street: 'West 26th Street', town: 'New York', @@ -110,6 +115,7 @@ describe('locationiq geocoding', function () { place: 'Beryl\'s Restaurant', type: 'restaurant', address: 'Woermann St, Swakopmund, Erongo Region, Namibia', + normal: 'Woermann St,Swakopmund,Erongo Region,NA', street: 'Woermann St', province: 'Erongo Region', town: "Swakopmund", @@ -134,6 +140,7 @@ describe('locationiq geocoding', function () { type: 'house_number', ll: [-104.999354, 39.676536], address: '2200 South Jason Street, Denver, CO, USA', + normal: '2200 South Jason Street,Denver,CO,US', house: '2200', street: 'South Jason Street', town: 'Denver', diff --git a/test/service/opencage/index.js b/test/service/opencage/index.js index 924da55..8e514f1 100644 --- a/test/service/opencage/index.js +++ b/test/service/opencage/index.js @@ -22,19 +22,21 @@ describe('opencage geocoding', function () { type: 'road', place: 'Rua Cafelândia', address: 'Rua Cafelândia, Parque José Alexandre, Carapicuíba - SP, 06321-665, Brazil', + normal: 'Rua Cafelândia,Carapicuíba,São Paulo,BR', street: 'Rua Cafelândia', town: 'Carapicuíba', county: 'Região Metropolitana de São Paulo', - province: 'SP', + province: 'São Paulo', country: 'Brazil' }); result.places[1].should.deepEqual({ ll: [-46.835, -23.52272], type: 'city', address: 'Carapicuíba, Brazil', + normal: 'Carapicuíba,São Paulo,BR', town: 'Carapicuíba', county: 'Carapicuíba', - province: 'SP', + province: 'São Paulo', country: 'Brazil' }); }); @@ -53,11 +55,12 @@ describe('opencage geocoding', function () { place: 'SS Sołdek', type: 'museum', address: 'Długie Pobrzeże, 80-838 Gdańsk, Polska', + normal: 'Długie Pobrzeże,Gdańsk,województwo pomorskie,PL', street: 'Długie Pobrzeże', community: 'Wyspa Spichrzów', town: 'Gdańsk', - province: '22', - country: 'Polska' + province: 'województwo pomorskie', + country: 'Poland' }); }); @@ -74,9 +77,32 @@ describe('opencage geocoding', function () { place: 'Beryl\'s Restaurant', type: 'restaurant', address: 'Woermann St, Swakopmund 22001, Namibia', + normal: 'Woermann St,Swakopmund,,NA', street: 'Woermann St', town: 'Swakopmund', country: 'Namibia' }); }); + + it('address', async function () { + + const query = { + address: '2200 S. Jason St, Denver, CO 80223', + partial: true + }; + const result = await geocode('forward', 10, query); + should.exist(result); + result.should.have.property('places').with.length(3); + result.places[0].should.deepEqual({ + type: 'building', + ll: [-104.999354, 39.676536], + address: '2200 South Jason Street, Denver, CO 80223, USA', + normal: '2200 South Jason Street,Denver,CO,US', + house: '2200', + street: 'South Jason Street', + town: 'Denver', + province: 'CO', + country: 'USA' + }); + }); }); diff --git a/test/service/pelias/index.js b/test/service/pelias/index.js index 2a672f6..c7df264 100644 --- a/test/service/pelias/index.js +++ b/test/service/pelias/index.js @@ -24,6 +24,7 @@ describe('pelias geocoding', function () { ll: [-46.836557, -23.5372], type: 'street', address: 'Rua Cafelândia, Carapicuíba, Sao Paulo, Brazil', + normal: 'Rua Cafelândia,Carapicuíba,Sao Paulo,BR', street: 'Rua Cafelândia', town: 'Carapicuíba', county: 'Carapicuiba', @@ -46,11 +47,12 @@ describe('pelias geocoding', function () { place: 'SS Sołdek', url: 'https://www.openstreetmap.org/way/125199669', type: 'venue', - address: 'Gdańsk, pomorskie, Polska', + address: 'Gdańsk, pomorskie, Poland', + normal: 'Gdańsk,pomorskie,PL', county: 'Gdańsk', province: 'pomorskie', town: 'Gdańsk', - country: 'Polska' + country: 'Poland' }); }); @@ -71,7 +73,8 @@ describe('pelias geocoding', function () { county: 'Grand County', province: 'UT', country: 'USA', - address: 'Grand County, UT, USA' + address: 'Grand County, UT, USA', + normal: 'UT,US' }); result.places[1].should.deepEqual({ ll: [-109.61995, 38.616497], @@ -81,7 +84,8 @@ describe('pelias geocoding', function () { county: 'Grand County', province: 'UT', country: 'USA', - address: 'Grand County, UT, USA' + address: 'Grand County, UT, USA', + normal: 'UT,US' }); result.places[2].should.deepEqual({ ll: [125.23645, 6.815029], @@ -91,7 +95,8 @@ describe('pelias geocoding', function () { county: 'Bansalan', province: 'Davao del Sur', country: 'Philippines', - address: 'Bansalan, Davao del Sur, Philippines' + address: 'Bansalan, Davao del Sur, Philippines', + normal: 'Davao del Sur,PH' }); result.places[3].should.deepEqual({ ll: [-109.548641, 38.561166], @@ -104,7 +109,8 @@ describe('pelias geocoding', function () { county: 'Grand County', province: 'UT', country: 'USA', - address: '800 South Main Street, Moab, UT, USA' + address: '800 South Main Street, Moab, UT, USA', + normal: '800 South Main Street,Moab,UT,US' }); }); @@ -122,6 +128,7 @@ describe('pelias geocoding', function () { url: 'https://www.openstreetmap.org/node/4488973891', type: 'venue', address: 'Swakopmund, Erongo, Namibia', + normal: 'Erongo,NA', county: 'Swakopmund', province: 'Erongo', country: 'Namibia' @@ -143,6 +150,7 @@ describe('pelias geocoding', function () { url: 'https://www.openstreetmap.org/node/10238187804', type: 'restaurant', address: '7221 West Ray Road, Chandler, AZ, USA', + normal: '7221 West Ray Road,Chandler,AZ,US', house: '7221', street: 'West Ray Road', town: 'Chandler', @@ -164,6 +172,7 @@ describe('pelias geocoding', function () { ll: [-111.967228, 33.31982], type: 'street', address: 'West Ray Road, Chandler, AZ, USA', + normal: 'West Ray Road,Chandler,AZ,US', street: 'West Ray Road', town: 'Chandler', county: 'Maricopa County', @@ -184,7 +193,8 @@ describe('pelias geocoding', function () { ll: [-40.308722, 23.992882], place: 'North Pacific Ocean', url: 'https://spelunker.whosonfirst.org/id/404528711/', - type: 'venue' + type: 'venue', + normal: '' }); }); @@ -200,6 +210,7 @@ describe('pelias geocoding', function () { ll: [-118.983976, 37.63619], type: 'venue', address: '3253 Meridian, Mammoth Lakes, CA, USA', + normal: '3253 Meridian,Mammoth Lakes,CA,US', place: 'The Summit', url: 'https://www.openstreetmap.org/way/42188373', house: '3253', @@ -213,6 +224,7 @@ describe('pelias geocoding', function () { ll: [-118.983976, 37.63619], type: 'address', address: '3253 Meridian, Mammoth Lakes, CA, USA', + normal: '3253 Meridian,Mammoth Lakes,CA,US', house: '3253', street: 'Meridian', town: 'Mammoth Lakes', diff --git a/test/service/positionstack/index.js b/test/service/positionstack/index.js index 2e405e2..aeee903 100644 --- a/test/service/positionstack/index.js +++ b/test/service/positionstack/index.js @@ -21,10 +21,11 @@ describe('positionstack geocoding', function () { ll: [-46.830942, -23.532918], type: 'locality', town: 'Carapicuíba', - province: 'SP', + province: 'Sao Paulo', country: 'Brazil', place: 'Carapicuíba', - address: 'Carapicuíba, SP, Brazil' + address: 'Carapicuíba, Sao Paulo, Brazil', + normal: 'Carapicuíba,Sao Paulo,BR' }); }); @@ -43,7 +44,8 @@ describe('positionstack geocoding', function () { province: 'CA', country: 'USA', place: 'Golden Gate Bridge', - address: 'San Francisco, CA, USA' + address: 'San Francisco, CA, USA', + normal: 'San Francisco,CA,US' }); }); @@ -60,7 +62,8 @@ describe('positionstack geocoding', function () { type: 'country', country: 'Brazil', place: 'Brazil', - address: 'Brazil' + address: 'Brazil', + normal: 'BR' }); }); @@ -75,10 +78,11 @@ describe('positionstack geocoding', function () { result.places[0].should.deepEqual({ ll: [14.526802, -22.679183], type: 'venue', - province: 'ER', + province: 'Erongo', country: 'Namibia', place: 'Beryl\'s Restaurant', - address: 'ER, Namibia' + address: 'Erongo, Namibia', + normal: 'Erongo,NA' }); }); }); diff --git a/test/service/synchronous/index.js b/test/service/synchronous/index.js index 9d89f94..763d503 100644 --- a/test/service/synchronous/index.js +++ b/test/service/synchronous/index.js @@ -27,7 +27,8 @@ describe('synchronous geocoding', function () { result.should.have.property('places').with.length(1); result.places[0].should.deepEqual({ ll: [18.658663, 54.351444], - place: 'SS Sołdek' + place: 'SS Sołdek', + normal: '' }); }); diff --git a/test/service/tilehosting/index.js b/test/service/tilehosting/index.js index 6636b7c..80e5407 100644 --- a/test/service/tilehosting/index.js +++ b/test/service/tilehosting/index.js @@ -21,13 +21,15 @@ describe('tilehosting geocoding', function () { ll: [-46.8365592, -23.5372062], type: 'street', place: 'Rua Cafelândia', - address: 'Carapicuíba, Região Metropolitana de São Paulo, São Paulo' + address: 'Carapicuíba, Região Metropolitana de São Paulo, São Paulo', + normal: '' }); result.places[1].should.deepEqual({ ll: [-46.8900124, -23.4851747], type: 'street', place: 'Rua Cafelândia', - address: 'Barueri, Região Metropolitana de São Paulo, São Paulo' + address: 'Barueri, Região Metropolitana de São Paulo, São Paulo', + normal: '' }); }); @@ -43,7 +45,8 @@ describe('tilehosting geocoding', function () { ll: [-122.4773342, 37.8096796], type: 'street', place: 'Golden Gate Bridge', - address: 'San Francisco, San Francisco City and County, California' + address: 'San Francisco, San Francisco City and County, California', + normal: '' }); }); @@ -59,7 +62,8 @@ describe('tilehosting geocoding', function () { ll: [14.526695, -22.6793015], type: 'street', place: 'Woermann St', - address: 'Erongo Region' + address: 'Erongo Region', + normal: '' }); }); });