Skip to content

Commit 1c4f278

Browse files
committed
fix(geocoding): show street + house number for unnamed addresses
Unnamed address/building features have no OSM name, so the display name fell back to display_name.split(",")[0]. In DE/AT/CH, display_name leads with the bare house number, yielding just "40" for both the place panel title and the directions field. Add a country-aware formatStreetLine() and use it in the name fallback chain (place-lookup) and the autocomplete short label (nominatim provider) so addresses render as "Kinderhauser Straße 40".
1 parent 282bfdd commit 1c4f278

4 files changed

Lines changed: 72 additions & 5 deletions

File tree

integrations/geocoding-nominatim/provider.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { formatAddress } from "@openmapx/integration-geocoding/format-address";
1+
import { formatAddress, formatStreetLine } from "@openmapx/integration-geocoding/format-address";
22
import type { GeocodingProvider as GeocodingProviderImpl } from "@openmapx/integration-geocoding/types";
33
/**
44
* Nominatim geocoding client.
@@ -31,9 +31,16 @@ interface NominatimResult {
3131
lat: string;
3232
lon: string;
3333
display_name: string;
34+
/** Empty for unnamed address/building features; a POI name otherwise. */
35+
name?: string;
3436
class: string;
3537
type: string;
3638
importance: number;
39+
address?: {
40+
road?: string;
41+
house_number?: string;
42+
country_code?: string;
43+
};
3744
}
3845

3946
function mapType(cls: string, type: string): SearchResult["type"] {
@@ -169,7 +176,13 @@ export const nominatimService: GeocodingProviderImpl = {
169176
async autocomplete(query: string, lang?: string): Promise<AutocompleteResult[]> {
170177
const data = await fetchNominatim({ q: query, limit: "6", dedupe: "1" }, lang);
171178
return data.map((r) => {
172-
const short = r.display_name.split(",")[0].trim();
179+
// Unnamed address/building features lead display_name with the bare house
180+
// number in DE/AT/CH, so derive a proper street line ("Kinderhauser
181+
// Straße 40") instead of splitting off "40".
182+
const short =
183+
r.name?.trim() ||
184+
(r.address && formatStreetLine(r.address)) ||
185+
r.display_name.split(",")[0].trim();
173186
return {
174187
id: makeId(r),
175188
label: short,

integrations/geocoding/__tests__/format-address.test.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from "vitest";
2-
import { formatAddress } from "../format-address.js";
2+
import { formatAddress, formatStreetLine } from "../format-address.js";
33

44
// Guards the @fragaria/address-formatter integration (v7): country-aware
55
// templates put the house number before/after the street depending on
@@ -37,3 +37,31 @@ describe("formatAddress", () => {
3737
expect(formatAddress({})).toBe("");
3838
});
3939
});
40+
41+
// Derives the display name for unnamed address/building features. Nominatim's
42+
// display_name leads with the bare house number in DE/AT/CH, so a naive
43+
// first-segment split yields just "40"; formatStreetLine must rebuild the
44+
// country-ordered street line instead.
45+
describe("formatStreetLine", () => {
46+
it("puts the house number after the street for German addresses", () => {
47+
expect(
48+
formatStreetLine({ road: "Kinderhauser Straße", house_number: "40", country_code: "de" }),
49+
).toBe("Kinderhauser Straße 40");
50+
});
51+
52+
it("puts the house number before the street for US addresses", () => {
53+
expect(formatStreetLine({ road: "Market St", house_number: "1", country_code: "us" })).toBe(
54+
"1 Market St",
55+
);
56+
});
57+
58+
it("returns just the street when there is no house number", () => {
59+
expect(formatStreetLine({ road: "Kinderhauser Straße", country_code: "de" })).toBe(
60+
"Kinderhauser Straße",
61+
);
62+
});
63+
64+
it("returns an empty string when there is no street", () => {
65+
expect(formatStreetLine({ house_number: "40", country_code: "de" })).toBe("");
66+
});
67+
});

integrations/geocoding/format-address.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,26 @@ export function formatAddress(
7676
): string {
7777
return runFormatter(components, { appendCountry: options.appendCountry ?? true }).join(", ");
7878
}
79+
80+
/**
81+
* Format just the street line — "Kinderhauser Straße 40" (DE) or
82+
* "40 Main Street" (US). House-number/street order is country-dependent, so we
83+
* reuse the formatter rather than concatenating by hand. Returns "" when there
84+
* is no street to render.
85+
*
86+
* Used to derive a display name for address-type places (buildings, house
87+
* numbers) that have no POI name of their own — without this, Nominatim's
88+
* `display_name` leads with the bare house number in DE/AT/CH ("40, …"), so a
89+
* naive `display_name.split(",")[0]` yields just "40".
90+
*/
91+
export function formatStreetLine(components: AddressComponents): string {
92+
if (!components.road) return "";
93+
return runFormatter(
94+
{
95+
road: components.road,
96+
house_number: components.house_number,
97+
country_code: components.country_code,
98+
},
99+
{ appendCountry: false },
100+
).join(", ");
101+
}

integrations/geocoding/place-lookup.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
parseId,
2020
USER_AGENT,
2121
} from "@openmapx/core";
22-
import { formatAddress } from "./format-address.js";
22+
import { formatAddress, formatStreetLine } from "./format-address.js";
2323
import { resolveOsmLabel } from "./osm-label.js";
2424

2525
function normalizeIdValue(s: string | undefined): string {
@@ -230,7 +230,10 @@ function toPlace(r: NominatimDetailResult, id: string): Place {
230230
}
231231

232232
const address = formatAddress(r.address) || r.display_name;
233-
const name = r.name?.trim() || r.display_name.split(",")[0].trim();
233+
// Address-type places (buildings/house numbers) have no POI name. Derive a
234+
// proper street line ("Kinderhauser Straße 40") instead of falling back to
235+
// display_name's first segment, which is the bare house number in DE/AT/CH.
236+
const name = r.name?.trim() || formatStreetLine(r.address) || r.display_name.split(",")[0].trim();
234237
const city = r.address.city ?? r.address.town ?? r.address.village ?? r.address.county;
235238

236239
return createPlace({

0 commit comments

Comments
 (0)