mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
fix(search): read hemisphere letters separated from the number (#1340)
Support spaced hemisphere coordinates while rejecting malformed numeric fragments and ambiguous component assignments. Include regression tests and runtime documentation. Contribution by @rudycelekli.
This commit is contained in:
1 parent
5b8e6fbc38
commit
b07352ea6a
4 files changed
+87
-6
No files matched your search
@@ -0,0 +1,3 @@
|
||||
- Read a hemisphere letter that is separated from its number, so a search for
|
||||
`40.7128 N 74.0060 W` flies there instead of falling through to the geocoders
|
||||
(Rudy Celekli, @rudycelekli, #1340).
|
||||
@@ -768,6 +768,12 @@ transports and cancellation through response parsing. Stop and application
|
||||
teardown abort pending connections; reconnect requests a new client secret.
|
||||
Microphone, radio handoff, tool schemas and default model behavior are preserved.
|
||||
|
||||
Coordinate search accepts whitespace-separated decimal degrees with prefix or
|
||||
suffix hemisphere letters, including `40.7128 N 74.0060 W`. Components require
|
||||
an actual separator and an unambiguous hemisphere assignment; malformed numeric
|
||||
fragments and scientific notation fall through to geocoders instead of becoming
|
||||
exact coordinate results.
|
||||
|
||||
Geospatial lookups are composed through `src/search`: forward/reverse geocoding,
|
||||
text/nearby search and routing use configurable providers/endpoints. Annotation,
|
||||
HUD and voice consumers share the configured service. Existing Google/Photon
|
||||
|
||||
@@ -47,15 +47,37 @@ function readComponent(text) {
|
||||
};
|
||||
}
|
||||
|
||||
/** Split on a comma, a semicolon, or whitespace — never on anything else. */
|
||||
/**
|
||||
* Split on a comma, a semicolon, or whitespace — never on anything else.
|
||||
* A hemisphere letter stays with the number it names, so `40.7 N 74.0 W`
|
||||
* is two components. Splitting on the space before that letter used to
|
||||
* leave three pieces and the search declined the coordinate.
|
||||
*/
|
||||
function splitComponents(query) {
|
||||
const text = String(query).trim();
|
||||
if (!text) return null;
|
||||
const parts = /[,;]/.test(text)
|
||||
? text.split(/[,;]/)
|
||||
: text.split(/\s+(?=[+-]?[.\d]|[NSEW]\s*[+-]?[.\d])/i);
|
||||
const trimmed = parts.map((part) => part.trim());
|
||||
return trimmed.length === 2 && trimmed.every(Boolean) ? trimmed : null;
|
||||
if (/[,;]/.test(text)) {
|
||||
const trimmed = text.split(/[,;]/).map((part) => part.trim());
|
||||
return trimmed.length === 2 && trimmed.every(Boolean) ? trimmed : null;
|
||||
}
|
||||
const words = text.split(/\s+/);
|
||||
// Each component has at most a number, a degree sign and one hemisphere.
|
||||
if (words.length > 6) return null;
|
||||
// Keep every character: extracting tokens would turn `1e3` or `1.2.3`
|
||||
// into invented coordinates. A lone letter between numbers can name either
|
||||
// component; require an unambiguous split rather than guessing its owner.
|
||||
let result = null;
|
||||
for (let boundary = words.length - 1; boundary > 0; boundary -= 1) {
|
||||
const parts = [
|
||||
words.slice(0, boundary).join(' '),
|
||||
words.slice(boundary).join(' '),
|
||||
];
|
||||
if (parts.every((part) => readComponent(part))) {
|
||||
if (result) return null;
|
||||
result = parts;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Present a parsed pair the way a coordinate is normally written. */
|
||||
|
||||
@@ -52,6 +52,19 @@ test('hemisphere letters fix the axis, in either order', () => {
|
||||
label: '40.0000° N, 74.0000° W',
|
||||
});
|
||||
assert.deepEqual(parseCoordinateQuery('40° N, 74° W')?.lat, 40);
|
||||
// Written the way a coordinate is usually pasted, with no comma.
|
||||
assert.deepEqual(parseCoordinateQuery('40.7128 N 74.0060 W'), {
|
||||
lat: 40.7128,
|
||||
lon: -74.006,
|
||||
label: '40.7128° N, 74.0060° W',
|
||||
});
|
||||
assert.deepEqual(parseCoordinateQuery('40.7128° N 74.0060° W')?.lon, -74.006);
|
||||
assert.deepEqual(parseCoordinateQuery('N 40.7128 W 74.0060'), {
|
||||
lat: 40.7128,
|
||||
lon: -74.006,
|
||||
label: '40.7128° N, 74.0060° W',
|
||||
});
|
||||
assert.deepEqual(parseCoordinateQuery('74.0060 W 40.7128 N')?.lat, 40.7128);
|
||||
// One letter is enough: it fixes its own axis, the other takes what is left.
|
||||
assert.deepEqual(parseCoordinateQuery('40 N, -74')?.lon, -74);
|
||||
assert.deepEqual(parseCoordinateQuery('-74, 40 N'), {
|
||||
@@ -66,6 +79,21 @@ test('malformed and ambiguous coordinates are refused, never guessed', () => {
|
||||
// The reviewer's case: trailing text must not be discarded.
|
||||
'12junk, 34oops',
|
||||
'12junk,34',
|
||||
'12junk 34',
|
||||
'1e3 5',
|
||||
'1e3',
|
||||
'1E3',
|
||||
'1e-3',
|
||||
'1.2.3',
|
||||
'12-34',
|
||||
'40 NW 74',
|
||||
'40 N 74',
|
||||
'40 W 74',
|
||||
'40 E 74',
|
||||
'°40 74',
|
||||
'40°° 74',
|
||||
'40 74°°',
|
||||
'40 26 46 N 79 58 56 W',
|
||||
'43.1731, -79.0384x',
|
||||
'abc, def',
|
||||
'Paris',
|
||||
@@ -196,3 +224,25 @@ test('malformed or unsupported geo URIs are refused without losing their meaning
|
||||
assert.equal(parseCoordinateQuery(query), null, query);
|
||||
}
|
||||
});
|
||||
|
||||
test('whitespace boundaries preserve degree signs and hemisphere ownership', () => {
|
||||
for (const query of ['40 ° 74', '40° 74', '40 N, 74', 'N 40 74']) {
|
||||
assert.equal(parseCoordinateQuery(query)?.lat, 40, query);
|
||||
assert.equal(parseCoordinateQuery(query)?.lon, 74, query);
|
||||
}
|
||||
for (const query of ['40 ° N 74 ° W', 'N 40 ° W 74 °', '40\tN\n74\tW']) {
|
||||
assert.equal(parseCoordinateQuery(query)?.lat, 40, query);
|
||||
assert.equal(parseCoordinateQuery(query)?.lon, -74, query);
|
||||
}
|
||||
});
|
||||
|
||||
test('a signed plain component leaves a spaced letter with the other component', () => {
|
||||
assert.deepEqual(
|
||||
parseCoordinateQuery('-40 N 74'),
|
||||
parseCoordinateQuery('-40, N 74'),
|
||||
);
|
||||
assert.deepEqual(
|
||||
parseCoordinateQuery('40 N -74'),
|
||||
parseCoordinateQuery('40 N, -74'),
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user