diff --git a/src/index.html b/src/index.html
index 641c08a..614727e 100644
--- a/src/index.html
+++ b/src/index.html
@@ -136,14 +136,14 @@
Test
diff --git a/src/index.test.ts b/src/index.test.ts
index ebfd892..babc316 100644
--- a/src/index.test.ts
+++ b/src/index.test.ts
@@ -1,5 +1,5 @@
-import { ACCUWEATHER_STRUCT, FORECA_STRUCT, SIMPLE_STRUCT } from './structs.ts'
import { QueryParams } from './types.ts'
+import { STRUCTS } from './structs.ts'
import main from './index.ts'
type OptionalParams = Partial>
@@ -17,7 +17,7 @@ Deno.test('Provider: Accuweather', async function () {
lat: LAT,
lon: LON,
}),
- FORECA_STRUCT,
+ STRUCTS.FORECA.WEATHER,
)
})
@@ -28,7 +28,7 @@ Deno.test('Provider: Foreca', async function () {
lat: LAT,
lon: LON,
}),
- FORECA_STRUCT,
+ STRUCTS.FORECA.WEATHER,
)
})
@@ -39,7 +39,7 @@ Deno.test('Provider: Auto', async function () {
lat: LAT,
lon: LON,
}),
- SIMPLE_STRUCT,
+ STRUCTS.SIMPLE.WEATHER,
)
})
@@ -50,7 +50,7 @@ Deno.test.ignore('Provider: Wunderground', async function () {
lat: LAT,
lon: LON,
}),
- ACCUWEATHER_STRUCT,
+ STRUCTS.ACCUWEATHER.WEATHER,
)
})
@@ -64,7 +64,7 @@ Deno.test('Simple data: Accuweather', async function () {
lat: LAT,
lon: LON,
}),
- SIMPLE_STRUCT,
+ STRUCTS.SIMPLE.WEATHER,
)
})
@@ -76,7 +76,7 @@ Deno.test('Simple data: Foreca', async function () {
lat: LAT,
lon: LON,
}),
- SIMPLE_STRUCT,
+ STRUCTS.SIMPLE.WEATHER,
)
})
@@ -88,7 +88,43 @@ Deno.test('Simple data: Auto overrides "all" data', async function () {
lat: LAT,
lon: LON,
}),
- SIMPLE_STRUCT,
+ STRUCTS.SIMPLE.WEATHER,
+ )
+})
+
+Deno.test.ignore('Geo: Accuweather', async function () {
+ compareTypes(
+ await getJson({
+ provider: 'accuweather',
+ geo: 'true',
+ lat: LAT,
+ lon: LON,
+ }),
+ STRUCTS.ACCUWEATHER.GEO,
+ )
+})
+
+Deno.test.ignore('Geo: Foreca', async function () {
+ compareTypes(
+ await getJson({
+ provider: 'accuweather',
+ geo: 'true',
+ lat: LAT,
+ lon: LON,
+ }),
+ STRUCTS.ACCUWEATHER.GEO,
+ )
+})
+
+Deno.test.ignore('Geo: Simple', async function () {
+ compareTypes(
+ await getJson({
+ provider: 'accuweather',
+ geo: 'true',
+ lat: LAT,
+ lon: LON,
+ }),
+ STRUCTS.ACCUWEATHER.GEO,
)
})
@@ -129,8 +165,8 @@ Deno.test('Params: Wrong unit falls back to C', async function () {
Deno.test('Params: Has provider & no query/coords', async function () {
const req = new Request(`https://example.com?provider=accuweather`)
const resp = await main.fetch(req)
-
assert(resp.status === 503)
+ console.clear()
})
// Helpers
diff --git a/src/index.ts b/src/index.ts
index 378abc0..f53267f 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,10 +2,10 @@ import './parser.ts'
import * as foreca from './providers/foreca.ts'
import * as weathercom from './providers/weathercom.ts'
import * as accuweather from './providers/accuweather.ts'
-import toSimpleWeather from './providers/simple.ts'
-import { isAccuweather, isForeca } from './types.ts'
+import toSimpleWeather, { toSimpleLocations } from './providers/simple.ts'
+import { isAccuweather, isAccuweatherLocation, isForeca, isForecaLocation } from './types.ts'
-import type { AccuWeather, Foreca, QueryParams } from './types.ts'
+import type { AccuWeather, Foreca, QueryParams, Simple } from './types.ts'
/**
* Racle-météo can be called like a Cloudflare Worker, using fetch().
@@ -84,16 +84,21 @@ async function main(request: Request) {
}
if (params.geo && params.provider) {
- let list: AccuWeather.Locations | Foreca.Location = []
+ let list: unknown[] = []
- if (params.provider === 'accuweather') {
+ if (params.provider === 'accuweather' || params.provider === 'auto') {
list = await accuweather.geo(params)
}
-
- if (params.provider === 'foreca') {
+ if (params.provider === 'foreca' || (params.provider === 'auto' && list.length === 0)) {
list = await foreca.geo(params)
}
+ if (params.provider === 'auto' || params.data === 'simple') {
+ if (isAccuweatherLocation(list) || isForecaLocation(list)) {
+ list = toSimpleLocations(list)
+ }
+ }
+
return new Response(JSON.stringify(list), {
status,
headers: {
diff --git a/src/providers/accuweather.ts b/src/providers/accuweather.ts
index c49c129..2e0b2ce 100644
--- a/src/providers/accuweather.ts
+++ b/src/providers/accuweather.ts
@@ -16,7 +16,7 @@ export default async function accuweather(params: QueryParams): Promise {
+export async function geo(params: QueryParams): Promise {
return await geolocationFromQuery(params.query)
}
@@ -215,7 +215,7 @@ async function fetchPageContent(params: QueryParams): Promise {
return html
}
-async function geolocationFromQuery(query: string): Promise {
+async function geolocationFromQuery(query: string): Promise {
const headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:132.0) Gecko/20100101 Firefox/132.0',
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
@@ -226,7 +226,7 @@ async function geolocationFromQuery(query: string): Promise 1) {
return result
diff --git a/src/providers/foreca.ts b/src/providers/foreca.ts
index 5d5ae3e..25d90f8 100644
--- a/src/providers/foreca.ts
+++ b/src/providers/foreca.ts
@@ -19,12 +19,14 @@ export default async function foreca(params: QueryParams): Promise {
- return await getForecaLocation({
- lat: params.lat,
- lon: params.lon,
- query: params.query,
- })
+export async function geo(params: QueryParams): Promise {
+ return [
+ await getForecaLocation({
+ lat: params.lat,
+ lon: params.lon,
+ query: params.query,
+ }),
+ ]
}
export async function debugContent(params: QueryParams): Promise {
@@ -213,11 +215,18 @@ export async function fetchPageContent({ lat, lon, query, lang, unit }: QueryPar
}
export async function getForecaLocation({ lat, lon, query }: Partial): Promise {
+ type LocationSearch = {
+ query: string
+ language: string
+ results: Foreca.Location[]
+ }
+
if (query) {
const path = `https://api.foreca.net/locations/search/${query}.json`
const resp = await fetch(path)
- const json = await resp.json()
- return json.results[0]
+ const json = await resp.json() as LocationSearch
+ const location = json.results[0]
+ return location
} else {
const path = `https://api.foreca.net/locations/${lon},${lat}.json`
const resp = await fetch(path)
@@ -226,8 +235,8 @@ export async function getForecaLocation({ lat, lon, query }: Partial ({ name: loc.name, detail: loc.longName }))
+ }
+
+ if (isForecaLocation(json)) {
+ return json.map((loc) => ({ name: loc.name, detail: loc.defaultName }))
+ }
+
+ throw new Error('Cannot get a valid location')
+}
+
function transformToSimpleIcon(id: string, provider: 'accuweather' | 'foreca'): string {
for (const [simpleId, providerIds] of Object.entries(SIMPLE_ICONS)) {
const list = providerIds[provider]
diff --git a/src/structs.ts b/src/structs.ts
index f15629b..d66bd9b 100644
--- a/src/structs.ts
+++ b/src/structs.ts
@@ -1,4 +1,4 @@
-export const SIMPLE_STRUCT = {
+const SIMPLE_STRUCT = {
meta: {
url: 'string',
lang: 'string',
@@ -29,7 +29,14 @@ export const SIMPLE_STRUCT = {
],
}
-export const ACCUWEATHER_STRUCT = {
+const SIMPLE_GEO_STRUCT = [
+ {
+ name: 'string',
+ details: 'string',
+ },
+]
+
+const ACCUWEATHER_STRUCT = {
meta: {
url: 'string',
lang: 'string',
@@ -69,7 +76,14 @@ export const ACCUWEATHER_STRUCT = {
],
}
-export const FORECA_STRUCT = {
+const ACCUWEATHER_GEO_STRUCT = [
+ {
+ name: 'string',
+ details: 'string',
+ },
+]
+
+const FORECA_STRUCT = {
meta: {
url: 'string',
lang: 'string',
@@ -102,3 +116,25 @@ export const FORECA_STRUCT = {
},
],
}
+
+const FORECA_GEO_STRUCT = [
+ {
+ name: 'string',
+ details: 'string',
+ },
+]
+
+export const STRUCTS = {
+ ACCUWEATHER: {
+ WEATHER: ACCUWEATHER_STRUCT,
+ GEO: ACCUWEATHER_GEO_STRUCT,
+ },
+ FORECA: {
+ WEATHER: FORECA_STRUCT,
+ GEO: FORECA_GEO_STRUCT,
+ },
+ SIMPLE: {
+ WEATHER: SIMPLE_STRUCT,
+ GEO: SIMPLE_GEO_STRUCT,
+ },
+}
diff --git a/src/types.ts b/src/types.ts
index ac53d1f..1e9780e 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -6,6 +6,14 @@ export function isForeca(json: AccuWeather.Weather | Foreca.Weather): json is Fo
return json?.meta?.provider === 'foreca'
}
+export function isAccuweatherLocation(json: unknown[]): json is AccuWeather.Location[] {
+ return !!(json[0] as AccuWeather.Location)?.key
+}
+
+export function isForecaLocation(json: unknown[]): json is Foreca.Location[] {
+ return !!(json[0] as Foreca.Location)?.id
+}
+
export interface QueryParams {
provider: 'accuweather' | 'foreca' | 'weathercom' | 'auto' | ''
debug: 'nodes' | 'content' | 'geo' | ''
@@ -18,10 +26,6 @@ export interface QueryParams {
geo?: unknown
}
-/*************
- Simple
-**************/
-
export declare namespace Simple {
interface Weather {
meta: {
@@ -54,14 +58,10 @@ export declare namespace Simple {
type Locations = {
name: string
- longName: string
+ detail: string
}[]
}
-/*****************
- Accuweather
-******************/
-
export declare namespace AccuWeather {
interface Weather {
meta: {
@@ -127,7 +127,7 @@ export declare namespace AccuWeather {
}[]
}
- type Locations = {
+ interface Location {
'key': string
'name': string
'longName': string
@@ -150,13 +150,9 @@ export declare namespace AccuWeather {
'country': string | null
'localizedName': string | null
'primaryPostalCode': string | null
- }[]
+ }
}
-/*************
- Foreca
-**************/
-
export declare namespace Foreca {
interface Weather {
meta: {