simplify how db profile works

This commit is contained in:
dabund24 2025-02-07 16:22:17 +01:00
parent 5b6be58f60
commit 3bac066fad
4 changed files with 97 additions and 174 deletions

View file

@ -1,80 +0,0 @@
{
"journeys": {
"profileName": "dbnav",
"profileMethods": [
{
"methodName": "formatJourneysReq",
"moduleName": "journeys-req.js"
}
],
"baseKeys": ["journeysEndpoint"]
},
"refreshJourneys": {
"profileName": "dbnav",
"profileMethods": [
{
"methodName": "formatRefreshJourneyReq",
"moduleName": "journeys-req.js"
}
],
"baseKeys": ["refreshJourneysEndpointTickets", "refreshJourneysEndpointPolyline"]
},
"locations": {
"profileName": "dbnav",
"profileMethods": [
{
"methodName": "formatLocationFilter",
"moduleName": "location-filter.js"
},
{
"methodName": "formatLocationsReq",
"moduleName": "locations-req.js"
}
],
"baseKeys": ["locationsEndpoint"]
},
"stop": {
"profileName": "dbnav",
"profileMethods": [
{
"methodName": "formatStopReq",
"moduleName": "stop-req.js"
},
{
"methodName": "parseStop",
"moduleName": "parse-stop.js"
}
],
"baseKeys": ["stopEndpoint"]
},
"nearby": {
"profileName": "dbnav",
"profileMethods": [
{
"methodName": "formatNearbyReq",
"moduleName": "nearby-req.js"
}
],
"baseKeys": ["nearbyEndpoint"]
},
"trip": {
"profileName": "db",
"profileMethods": [
{
"methodName": "formatTripReq",
"moduleName": "trip-req.js"
}
],
"baseKeys": ["tripEndpoint"]
},
"board": {
"profileName": "dbregioguide",
"profileMethods": [
{
"methodName": "formatStationBoardReq",
"moduleName": "station-board-req.js"
}
],
"baseKeys": ["boardEndpoint"]
}
}

View file

@ -1,50 +1,66 @@
import {createRequire} from 'module'; import {createRequire} from 'module';
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
const dynamicProfileData = require('./dynamicProfileData.json');
const dbnavBase = require('../dbnav/base.json'); const dbnavBase = require('../dbnav/base.json');
const dbregioguideBase = require('../dbregioguide/base.json'); const dbregioguideBase = require('../dbregioguide/base.json');
const dbwebBase = require('../dbweb/base.json');
import {products} from '../../lib/products.js'; import {products} from '../../lib/products.js';
// journeys()
import {formatJourneysReq} from '../dbnav/journeys-req.js';
const {journeysEndpoint} = dbnavBase;
// refreshJourneys()
import {formatRefreshJourneyReq} from '../dbnav/journeys-req.js';
const {refreshJourneysEndpointTickets, refreshJourneysEndpointPolyline} = dbnavBase;
// locations()
import {formatLocationsReq} from '../dbnav/locations-req.js';
import {formatLocationFilter} from '../dbnav/location-filter.js';
const {locationsEndpoint} = dbnavBase;
// stop()
import {formatStopReq} from '../dbnav/stop-req.js';
import {parseStop} from '../dbnav/parse-stop.js';
const {stopEndpoint} = dbnavBase;
// nearby()
import {formatNearbyReq} from '../dbnav/nearby-req.js';
const {nearbyEndpoint} = dbnavBase;
// trip()
import {formatTripReq} from './trip-req.js';
const tripEndpoint_dbnav = dbnavBase.tripEndpoint;
const tripEndpoint_dbregioguide = dbregioguideBase.tripEndpoint;
// arrivals(), departures()
const {boardEndpoint} = dbregioguideBase;
const profile = { const profile = {
locale: 'de-DE', locale: 'de-DE',
timezone: 'Europe/Berlin', timezone: 'Europe/Berlin',
products, products,
formatJourneysReq,
journeysEndpoint,
formatRefreshJourneyReq,
refreshJourneysEndpointTickets, refreshJourneysEndpointPolyline,
formatLocationsReq, formatLocationFilter,
locationsEndpoint,
formatStopReq, parseStop,
stopEndpoint,
formatNearbyReq,
nearbyEndpoint,
formatTripReq,
tripEndpoint_dbnav, tripEndpoint_dbregioguide,
boardEndpoint,
}; };
// add profile methods
for (const {profileName, profileMethods} of Object.values(dynamicProfileData)) {
for (const {methodName, moduleName} of profileMethods) {
try {
// TODO use `import()` with top-level await once updated to es2022
profile[methodName] = require(`../${profileName}/${moduleName}`)[methodName];
} catch { /* use implementation from default profile if module doesn't exist */ }
}
}
const bases = {
dbnav: dbnavBase,
dbregioguide: dbregioguideBase,
dbweb: dbwebBase,
};
// add endpoint bases
for (const {profileName, baseKeys} of Object.values(dynamicProfileData)) {
if (profileName !== 'db') { // only add endpoint(s) from specified profile
for (const baseKey of baseKeys) {
profile[baseKey] = bases[profileName][baseKey];
}
continue;
}
// add endpoints from all profiles with the profile names as key suffixes and dynamically decide which to use later
for (const [profileName, profileBases] of Object.entries(bases)) {
for (const baseKey of baseKeys) {
profile[`${baseKey}_${profileName}`] = profileBases[baseKey];
}
}
}
export { export {
profile, profile,

View file

@ -1,60 +0,0 @@
import {createRequire} from 'module';
const require = createRequire(import.meta.url);
import {createClient} from '../index.js';
import {profile as rawProfile} from '../p/db/index.js';
const dynamicProfileData = require('../p/db/dynamicProfileData.json');
const dbnavBase = require('../p/dbnav/base.json');
const dbwebBase = require('../p/dbweb/base.json');
const dbregioguideBase = require('../p/dbregioguide/base.json');
import tap from 'tap';
const client = createClient(rawProfile, 'public-transport/hafas-client:test');
tap.test('db: determine base urls', (t) => {
const fqdns = {
dbnav: 'app.vendo.noncd.db.de',
dbregioguide: 'regio-guide.de',
dbweb: 'int.bahn.de',
};
for (const {profileName, baseKeys} of Object.values(dynamicProfileData)) {
if (profileName !== 'db') { // endpoint(s) is(/are) static. Check if correct fqdn is contained in base(s)
for (const baseKey of baseKeys) {
t.ok(client.profile[baseKey].includes(fqdns[profileName]), [`base url for ${profileName} profile should include ${fqdns[profileName]}`]);
}
continue;
}
// endpoint(s) is(/are) dynamic. Check if actual base key does not exist yet. Also check, if bases for all profiles are properly stored in other aux entries for later use
for (const baseKey of baseKeys) {
for (const [profileName, fqdn] of Object.entries(fqdns)) {
t.notHas(client.profile, baseKey, [`db profile should not contain the key ${baseKey}, since it is dynamically dispatched at runtime`]);
t.ok(client.profile[`${baseKey}_${profileName}`].includes(fqdn), [`key ${baseKey}_${profileName} of db profile should include ${fqdns[profileName]}`]);
}
}
}
t.end();
});
tap.test('db: dynamic client method', async (t) => {
t.equal(dynamicProfileData.trip.profileName, 'db', ['if this fails, check a different client method in this test']);
t.equal(client.profile.formatTripReq, (await import('../p/db/trip-req.js')).formatTripReq);
t.notHas(client.profile, 'tripEndpoint');
t.equal(client.profile.tripEndpoint_dbnav, dbnavBase.tripEndpoint);
t.equal(client.profile.tripEndpoint_dbweb, dbwebBase.tripEndpoint);
t.equal(client.profile.tripEndpoint_dbregioguide, dbregioguideBase.tripEndpoint);
t.end();
});
tap.test('db: static client method', async (t) => {
t.equal(dynamicProfileData.nearby.profileName, 'dbnav', ['if this fails, check a different client method in this test']);
t.equal(client.profile.formatNearbyReq, (await import('../p/dbnav/nearby-req.js')).formatNearbyReq);
t.equal(client.profile.nearbyEndpoint, dbnavBase.nearbyEndpoint);
t.end();
});

47
test/format/db-trip.js Normal file
View file

@ -0,0 +1,47 @@
import tap from 'tap';
import {profile as rawProfile} from '../../p/db/index.js';
import {createClient} from '../../index.js';
const client = createClient(rawProfile, 'public-transport/hafas-client:test', {enrichStations: false});
const {profile} = client;
const opt = {
stopovers: true,
polyline: false,
remarks: true,
language: 'en',
};
const tripIdHafas = '2|#VN#1#ST#1738783727#PI#0#ZI#222242#TA#0#DA#70225#1S#8000237#1T#1317#LS#8000261#LT#2002#PU#80#RT#1#CA#ICE#ZE#1007#ZB#ICE 1007#PC#0#FR#8000237#FT#1317#TO#8000261#TT#2002#';
const tripIdRis = '20250207-e6b2807e-bb48-39f9-89eb-8491ebc4b32c';
const reqDbNavExpected = {
endpoint: 'https://app.vendo.noncd.db.de/mob/zuglauf/',
path: '2%7C%23VN%231%23ST%231738783727%23PI%230%23ZI%23222242%23TA%230%23DA%2370225%231S%238000237%231T%231317%23LS%238000261%23LT%232002%23PU%2380%23RT%231%23CA%23ICE%23ZE%231007%23ZB%23ICE%201007%23PC%230%23FR%238000237%23FT%231317%23TO%238000261%23TT%232002%23',
headers: {
'Accept': 'application/x.db.vendo.mob.zuglauf.v2+json',
'Content-Type': 'application/x.db.vendo.mob.zuglauf.v2+json',
},
method: 'get',
};
const reqDbRegioGuideExpected = {
endpoint: 'https://regio-guide.de/@prd/zupo-travel-information/api/public/ri/journey/',
path: '20250207-e6b2807e-bb48-39f9-89eb-8491ebc4b32c',
method: 'get',
};
tap.test('db trip(): dynamic request formatting', (t) => {
const ctx = {profile, opt};
t.notHas(client.profile, 'tripEndpoint');
const reqDbNav = profile.formatTripReq(ctx, tripIdHafas);
delete reqDbNav.headers['X-Correlation-ID'];
const reqDbRegioGuide = profile.formatTripReq(ctx, tripIdRis);
t.same(reqDbNav, reqDbNavExpected);
t.same(reqDbRegioGuide, reqDbRegioGuideExpected);
t.end();
});