diff --git a/index.js b/index.js index 0b78d520..b9483260 100644 --- a/index.js +++ b/index.js @@ -45,15 +45,23 @@ const loadEnrichedStationData = (profile) => new Promise((resolve, reject) => { }); }); +const applyEnrichedStationData = async (ctx, shouldLoadEnrichedStationData) => { + const {profile, common} = ctx; + if (shouldLoadEnrichedStationData && !common.locations) { + const locations = await loadEnrichedStationData(profile); + common.locations = locations; + } +}; + const createClient = (profile, userAgent, opt = {}) => { profile = Object.assign({}, defaultProfile, profile); validateProfile(profile); const common = {}; - if (opt.enrichStations !== false) { - loadEnrichedStationData(profile) - .then(locations => { - common.locations = locations; - }); + let shouldLoadEnrichedStationData = false; + if (typeof opt.enrichStations === 'function') { + profile.enrichStation = opt.enrichStations; + } else if (opt.enrichStations !== false) { + shouldLoadEnrichedStationData = true; } if ('string' !== typeof userAgent) { @@ -64,6 +72,7 @@ const createClient = (profile, userAgent, opt = {}) => { } const _stationBoard = async (station, type, resultsField, parse, opt = {}) => { + await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData); if (isObj(station) && station.id) { station = station.id; } else if ('string' !== typeof station) { @@ -129,6 +138,7 @@ const createClient = (profile, userAgent, opt = {}) => { }; const journeys = async (from, to, opt = {}) => { + await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData); if ('earlierThan' in opt && 'laterThan' in opt) { throw new TypeError('opt.earlierThan and opt.laterThan are mutually exclusive.'); } @@ -211,6 +221,8 @@ const createClient = (profile, userAgent, opt = {}) => { }; const refreshJourney = async (refreshToken, opt = {}) => { + await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData); + if ('string' !== typeof refreshToken || !refreshToken) { throw new TypeError('refreshToken must be a non-empty string.'); } @@ -237,6 +249,8 @@ const createClient = (profile, userAgent, opt = {}) => { }; const locations = async (query, opt = {}) => { + await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData); + if (!isNonEmptyString(query)) { throw new TypeError('query must be a non-empty string.'); } @@ -263,6 +277,8 @@ const createClient = (profile, userAgent, opt = {}) => { }; const stop = async (stop, opt = {}) => { + await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData); + if (isObj(stop) && stop.id) { stop = stop.id; } else if ('string' !== typeof stop) { @@ -284,6 +300,8 @@ const createClient = (profile, userAgent, opt = {}) => { }; const nearby = async (location, opt = {}) => { + await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData); + validateLocation(location, 'location'); opt = Object.assign({ @@ -314,6 +332,8 @@ const createClient = (profile, userAgent, opt = {}) => { }; const trip = async (id, opt = {}) => { + await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData); + if (!isNonEmptyString(id)) { throw new TypeError('id must be a non-empty string.'); } @@ -341,6 +361,8 @@ const createClient = (profile, userAgent, opt = {}) => { // todo [breaking]: rename to trips()? const tripsByName = async (_lineNameOrFahrtNr = '*', _opt = {}) => { + await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData); + throw new Error('not implemented'); }; @@ -367,4 +389,5 @@ const createClient = (profile, userAgent, opt = {}) => { export { createClient, + loadEnrichedStationData, }; diff --git a/lib/default-profile.js b/lib/default-profile.js index 5c2e3e49..3cbb8f83 100644 --- a/lib/default-profile.js +++ b/lib/default-profile.js @@ -16,7 +16,7 @@ import {parseTrip} from '../parse/trip.js'; import {parseJourneyLeg} from '../parse/journey-leg.js'; import {parseJourney} from '../parse/journey.js'; import {parseLine} from '../parse/line.js'; -import {parseLocation} from '../parse/location.js'; +import {parseLocation, enrichStation} from '../parse/location.js'; import {parsePolyline} from '../parse/polyline.js'; import {parseOperator} from '../parse/operator.js'; import {parseRemarks, parseCancelled} from '../parse/remarks.js'; @@ -82,6 +82,7 @@ const defaultProfile = { parseLine, parseStationName: id, parseLocation, + enrichStation, parsePolyline, parseOperator, parseRemarks, diff --git a/parse/location.js b/parse/location.js index d15b9302..6a1f5e10 100644 --- a/parse/location.js +++ b/parse/location.js @@ -14,7 +14,7 @@ const parseLocation = (ctx, l) => { } const lid = parse(l.id || l.locationId, {delimiter: '@'}); - const res = { + let res = { type: 'location', id: (l.extId || l.evaNr || lid.L || l.evaNumber || l.evaNo || l.bahnhofsId || '').replace(leadingZeros, '') || null, }; @@ -46,13 +46,7 @@ const parseLocation = (ctx, l) => { stop.products = profile.parseProducts(ctx, l.products); } - if (common && common.locations && common.locations[stop.id]) { - delete stop.type; - stop = { - ...common.locations[stop.id], - ...stop, - }; - } + stop = profile.enrichStation(ctx, stop); // TODO isMeta // TODO entrances, lines @@ -70,6 +64,8 @@ const parseLocation = (ctx, l) => { } res.name = name; + res = enrichStation(ctx, res); + if (l.type === ADDRESS || lid.A == '2') { res.address = name; } @@ -80,6 +76,22 @@ const parseLocation = (ctx, l) => { return res; }; +const enrichStation = (ctx, stop, locations) => { + const {common} = ctx; + const locs = locations || common?.locations; + const rich = locs && (locs[stop.id] || locs[stop.name]); + if (rich) { + delete stop.type; + delete stop.id; + stop = { + ...rich, + ...stop, + }; + } + return stop; +}; + export { parseLocation, + enrichStation, }; diff --git a/test/dbweb-departures.js b/test/dbweb-departures.js index 3b4a1227..83344f66 100644 --- a/test/dbweb-departures.js +++ b/test/dbweb-departures.js @@ -10,7 +10,7 @@ import {profile as rawProfile} from '../p/dbweb/index.js'; const res = require('./fixtures/dbweb-departures.json'); import {dbwebDepartures as expected} from './fixtures/dbweb-departures.js'; -const client = createClient(rawProfile, 'public-transport/hafas-client:test', {enrichStations: true}); +const client = createClient(rawProfile, 'public-transport/hafas-client:test', {enrichStations: false}); const {profile} = client; const opt = { diff --git a/test/e2e/dbweb.js b/test/e2e/dbweb.js index 0c818635..4d2acbe8 100644 --- a/test/e2e/dbweb.js +++ b/test/e2e/dbweb.js @@ -395,17 +395,8 @@ tap.test('trip details', async (t) => { }); tap.test('departures at Berlin Schwedter Str.', async (t) => { - const res = await new Promise((resolve) => { - let interval = setInterval(async () => { // repeat evaluating `departures()` until stations are enriched - const res = await client.departures(blnSchwedterStr, { - duration: 5, when, - }); - - if (res.departures[0].stop.name !== undefined) { // ctx.common.locations have loaded - clearInterval(interval); - return resolve(res); - } - }, 4000); + const res = await client.departures(blnSchwedterStr, { + duration: 5, when, }); await testDepartures({ @@ -418,42 +409,24 @@ tap.test('departures at Berlin Schwedter Str.', async (t) => { }); tap.test('departures with station object', async (t) => { - const res = await new Promise((resolve) => { - let interval = setInterval(async () => { // repeat evaluating `departures()` until stations are enriched - const res = await client.departures({ - type: 'station', - id: jungfernheide, - name: 'Berlin Jungfernheide', - location: { - type: 'location', - latitude: 1.23, - longitude: 2.34, - }, - }, {when}); - - if (res.departures[0].stop.name !== undefined) { // ctx.common.locations have loaded - clearInterval(interval); - return resolve(res); - } - }, 4000); - }); + const res = await client.departures({ + type: 'station', + id: jungfernheide, + name: 'Berlin Jungfernheide', + location: { + type: 'location', + latitude: 1.23, + longitude: 2.34, + }, + }, {when}); validate(t, res, 'departuresResponse', 'res'); t.end(); }); tap.test('arrivals at Berlin Schwedter Str.', async (t) => { - const res = await new Promise((resolve) => { - let interval = setInterval(async () => { // repeat evaluating `arrivals()` until stations are enriched - const res = await client.arrivals(blnSchwedterStr, { - duration: 5, when, - }); - - if (res.arrivals[0].stop.name !== undefined) { // ctx.common.locations have loaded - clearInterval(interval); - return resolve(res); - } - }, 4000); + const res = await client.arrivals(blnSchwedterStr, { + duration: 5, when, }); await testArrivals({ diff --git a/test/parse/location.js b/test/parse/location.js index f2eb4fed..14cad45b 100644 --- a/test/parse/location.js +++ b/test/parse/location.js @@ -4,6 +4,7 @@ import {parseProducts} from '../../parse/products.js'; const profile = { parseLocation: parse, + enrichStation: (ctx, stop) => stop, parseStationName: (_, name) => name.toLowerCase(), parseProducts, products: [{