Skip to content

Commit 2992b60

Browse files
author
Lalit Sharma
committed
feat: add functions to parse Google Maps coordinates from JSON and various text formats
1 parent c6452a8 commit 2992b60

1 file changed

Lines changed: 106 additions & 5 deletions

File tree

apps/mobile/src/utils/sharedMapLink.ts

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,22 @@ const GOOGLE_STATICMAP_CENTER_RE = new RegExp(
4949
`center=(${NUMBER_PART})(?:%2c|%2C|,)(${NUMBER_PART})`,
5050
"i",
5151
);
52+
// JSON field patterns from HTML (e.g., "lat":52.28..."lng":-1.53)
53+
const GOOGLE_JSON_LAT_LNG_RE = new RegExp(
54+
`"lat"\\s*:\\s*(${NUMBER_PART})[^]{0,200}?"lng"\\s*:\\s*(${NUMBER_PART})`,
55+
"i",
56+
);
57+
const GOOGLE_JSON_LNG_LAT_RE = new RegExp(
58+
`"lng"\\s*:\\s*(${NUMBER_PART})[^]{0,200}?"lat"\\s*:\\s*(${NUMBER_PART})`,
59+
"i",
60+
);
61+
// Decimal pair pattern - requires 4+ decimals to avoid noise (e.g., 52.2814,-1.5345)
62+
const GOOGLE_DECIMAL_PAIR_RE = /(?<lat>-?\d{1,2}\.\d{4,})\s*,\s*(?<lon>-?\d{1,3}\.\d{4,})/g;
63+
// Center array pattern (e.g., "center":[52.28,-1.53])
64+
const GOOGLE_CENTER_ARRAY_RE = new RegExp(
65+
`"center"\\s*:\\s*\\[\\s*(${NUMBER_PART})\\s*,\\s*(${NUMBER_PART})\\s*\\]`,
66+
"i",
67+
);
5268

5369
type ExpandedShortMapUrlResult = {
5470
expandedUrl: string;
@@ -244,11 +260,91 @@ function parseGoogleStaticMapCenterFromText(input: string): { lat: number; lon:
244260
return sanitizeCoordinates({ lat, lon });
245261
}
246262

263+
function parseGoogleJsonLatLngFromText(input: string): { lat: number; lon: number } | null {
264+
if (!input) return null;
265+
266+
const match = input.match(GOOGLE_JSON_LAT_LNG_RE);
267+
if (!match) return null;
268+
269+
const [, latRaw = "", lngRaw = ""] = match;
270+
const lat = Number(latRaw);
271+
const lon = Number(lngRaw);
272+
if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
273+
if (Math.abs(lat) > 90 || Math.abs(lon) > 180) return null;
274+
// Reject super "round" tiny values that are common noise in arrays
275+
if (Math.abs(lat) <= 2 && Math.abs(lon) <= 2) return null;
276+
277+
return sanitizeCoordinates({ lat, lon });
278+
}
279+
280+
function parseGoogleJsonLngLatFromText(input: string): { lat: number; lon: number } | null {
281+
if (!input) return null;
282+
283+
const match = input.match(GOOGLE_JSON_LNG_LAT_RE);
284+
if (!match) return null;
285+
286+
const [, lngRaw = "", latRaw = ""] = match;
287+
const lat = Number(latRaw);
288+
const lon = Number(lngRaw);
289+
if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
290+
if (Math.abs(lat) > 90 || Math.abs(lon) > 180) return null;
291+
if (Math.abs(lat) <= 2 && Math.abs(lon) <= 2) return null;
292+
293+
return sanitizeCoordinates({ lat, lon });
294+
}
295+
296+
function parseGoogleCenterArrayFromText(input: string): { lat: number; lon: number } | null {
297+
if (!input) return null;
298+
299+
const match = input.match(GOOGLE_CENTER_ARRAY_RE);
300+
if (!match) return null;
301+
302+
const [, latRaw = "", lonRaw = ""] = match;
303+
const lat = Number(latRaw);
304+
const lon = Number(lonRaw);
305+
if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
306+
if (Math.abs(lat) > 90 || Math.abs(lon) > 180) return null;
307+
if (Math.abs(lat) <= 2 && Math.abs(lon) <= 2) return null;
308+
309+
return sanitizeCoordinates({ lat, lon });
310+
}
311+
312+
function parseGoogleDecimalPairFromText(input: string): { lat: number; lon: number } | null {
313+
if (!input) return null;
314+
315+
// Scan for decimal pairs with 4+ decimal places
316+
const regex = new RegExp(GOOGLE_DECIMAL_PAIR_RE);
317+
let match = regex.exec(input);
318+
while (match !== null) {
319+
const groups = match.groups as { lat?: string; lon?: string } | undefined;
320+
if (groups?.lat && groups?.lon) {
321+
const lat = Number(groups.lat);
322+
const lon = Number(groups.lon);
323+
if (
324+
Number.isFinite(lat) &&
325+
Number.isFinite(lon) &&
326+
Math.abs(lat) <= 90 &&
327+
Math.abs(lon) <= 180 &&
328+
!(Math.abs(lat) <= 2 && Math.abs(lon) <= 2)
329+
) {
330+
return sanitizeCoordinates({ lat, lon });
331+
}
332+
}
333+
match = regex.exec(input);
334+
}
335+
336+
return null;
337+
}
338+
247339
function parseGoogleCoordinatesFromText(input: string): { lat: number; lon: number } | null {
248340
return (
249341
parseGooglePreviewCoordinatesFromText(input) ??
250342
parseGoogleStateCoordinatesFromText(input) ??
251-
parseGoogleStaticMapCenterFromText(input)
343+
parseGoogleStaticMapCenterFromText(input) ??
344+
parseGoogleJsonLatLngFromText(input) ??
345+
parseGoogleJsonLngLatFromText(input) ??
346+
parseGoogleCenterArrayFromText(input) ??
347+
parseGoogleDecimalPairFromText(input)
252348
);
253349
}
254350

@@ -385,10 +481,15 @@ async function fetchMapPageText(
385481
timeoutMs,
386482
);
387483
console.info("[share.debug] fetch_simplified_result_length", simpleText?.length ?? 0);
388-
// Check if we still hit consent
389-
const simpleUrl =
390-
typeof simpleResponse.url === "string" ? parseUrl(simpleResponse.url) : null;
391-
if (simpleUrl && !isGoogleConsentHost(simpleUrl.hostname)) {
484+
// Return the simplified HTML even if it still hit consent - let parsing try
485+
if (simpleText) {
486+
const simpleUrl =
487+
typeof simpleResponse.url === "string" ? parseUrl(simpleResponse.url) : null;
488+
if (simpleUrl && !isGoogleConsentHost(simpleUrl.hostname)) {
489+
console.info("[share.debug] fetch_simplified_success_no_consent");
490+
} else {
491+
console.info("[share.debug] fetch_simplified_still_consent_but_returning_html");
492+
}
392493
return simpleText;
393494
}
394495
}

0 commit comments

Comments
 (0)