mirror of
https://github.com/public-transport/db-vendo-client.git
synced 2025-02-22 22:59:35 +02:00
parent
228c72531b
commit
66d9fb5194
246 changed files with 12447 additions and 11915 deletions
|
@ -7,7 +7,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'ACME Commuter Rail',
|
name: 'ACME Commuter Rail',
|
||||||
short: 'CR',
|
short: 'CR',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'metro',
|
id: 'metro',
|
||||||
|
@ -15,9 +15,9 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Foo Bar Metro',
|
name: 'Foo Bar Metro',
|
||||||
short: 'M',
|
short: 'M',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
const transformReqBody = (body) => {
|
const transformReqBody = (body) => {
|
||||||
// get these from the recorded app requests
|
// get these from the recorded app requests
|
||||||
|
@ -25,8 +25,8 @@ const transformReqBody = (body) => {
|
||||||
// body.ver = …
|
// body.ver = …
|
||||||
// body.auth = { … }
|
// body.auth = { … }
|
||||||
// body.lang = …
|
// body.lang = …
|
||||||
return body
|
return body;
|
||||||
}
|
};
|
||||||
|
|
||||||
const insaProfile = {
|
const insaProfile = {
|
||||||
// locale: …,
|
// locale: …,
|
||||||
|
@ -37,9 +37,9 @@ const insaProfile = {
|
||||||
products: products,
|
products: products,
|
||||||
|
|
||||||
trip: false,
|
trip: false,
|
||||||
radar: false
|
radar: false,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
insaProfile,
|
insaProfile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,25 +1,27 @@
|
||||||
import {formatLocationIdentifier} from './location-identifier.js'
|
import {formatLocationIdentifier} from './location-identifier.js';
|
||||||
import {formatCoord} from './coord.js'
|
import {formatCoord} from './coord.js';
|
||||||
|
|
||||||
const formatAddress = (a) => {
|
const formatAddress = (a) => {
|
||||||
if (a.type !== 'location' || !a.latitude || !a.longitude || !a.address) {
|
if (a.type !== 'location' || !a.latitude || !a.longitude || !a.address) {
|
||||||
throw new TypeError('invalid address')
|
throw new TypeError('invalid address');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
A: '2', // address?
|
A: '2', // address?
|
||||||
O: a.address,
|
O: a.address,
|
||||||
X: formatCoord(a.longitude),
|
X: formatCoord(a.longitude),
|
||||||
Y: formatCoord(a.latitude)
|
Y: formatCoord(a.latitude),
|
||||||
|
};
|
||||||
|
if (a.id) {
|
||||||
|
data.L = a.id;
|
||||||
}
|
}
|
||||||
if (a.id) data.L = a.id
|
|
||||||
return {
|
return {
|
||||||
type: 'A', // address
|
type: 'A', // address
|
||||||
name: a.address,
|
name: a.address,
|
||||||
lid: formatLocationIdentifier(data)
|
lid: formatLocationIdentifier(data),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatAddress,
|
formatAddress,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const formatCoord = x => Math.round(x * 1000000)
|
const formatCoord = x => Math.round(x * 1000000);
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatCoord,
|
formatCoord,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
import {DateTime, IANAZone} from 'luxon'
|
import {DateTime, IANAZone} from 'luxon';
|
||||||
import {luxonIANAZonesByProfile as timezones} from '../lib/luxon-timezones.js'
|
import {luxonIANAZonesByProfile as timezones} from '../lib/luxon-timezones.js';
|
||||||
|
|
||||||
// todo: change to `(profile) => (when) => {}`
|
// todo: change to `(profile) => (when) => {}`
|
||||||
const formatDate = (profile, when) => {
|
const formatDate = (profile, when) => {
|
||||||
let timezone
|
let timezone;
|
||||||
if (timezones.has(profile)) timezone = timezones.get(profile)
|
if (timezones.has(profile)) {
|
||||||
else {
|
timezone = timezones.get(profile);
|
||||||
timezone = new IANAZone(profile.timezone)
|
} else {
|
||||||
timezones.set(profile, timezone)
|
timezone = new IANAZone(profile.timezone);
|
||||||
|
timezones.set(profile, timezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
return DateTime.fromMillis(+when, {
|
return DateTime
|
||||||
|
.fromMillis(Number(when), {
|
||||||
locale: profile.locale,
|
locale: profile.locale,
|
||||||
zone: timezone
|
zone: timezone,
|
||||||
}).toFormat('yyyyMMdd')
|
})
|
||||||
}
|
.toFormat('yyyyMMdd');
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatDate,
|
formatDate,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
const bike = {type: 'BC', mode: 'INC'}
|
const bike = {type: 'BC', mode: 'INC'};
|
||||||
|
|
||||||
const accessibility = {
|
const accessibility = {
|
||||||
none: {type: 'META', mode: 'INC', meta: 'notBarrierfree'},
|
none: {type: 'META', mode: 'INC', meta: 'notBarrierfree'},
|
||||||
partial: {type: 'META', mode: 'INC', meta: 'limitedBarrierfree'},
|
partial: {type: 'META', mode: 'INC', meta: 'limitedBarrierfree'},
|
||||||
complete: {type: 'META', mode: 'INC', meta: 'completeBarrierfree'}
|
complete: {type: 'META', mode: 'INC', meta: 'completeBarrierfree'},
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
bike,
|
bike,
|
||||||
accessibility,
|
accessibility,
|
||||||
}
|
};
|
||||||
|
|
|
@ -3,10 +3,10 @@ const formatLinesReq = (ctx, query) => {
|
||||||
meth: 'LineMatch',
|
meth: 'LineMatch',
|
||||||
req: {
|
req: {
|
||||||
input: query,
|
input: query,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatLinesReq,
|
formatLinesReq,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
const formatLocationFilter = (stops, addresses, poi) => {
|
const formatLocationFilter = (stops, addresses, poi) => {
|
||||||
if (stops && addresses && poi) return 'ALL'
|
if (stops && addresses && poi) {
|
||||||
return (stops ? 'S' : '') + (addresses ? 'A' : '') + (poi ? 'P' : '')
|
return 'ALL';
|
||||||
}
|
}
|
||||||
|
return (
|
||||||
|
(stops ? 'S' : '')
|
||||||
|
+ (addresses ? 'A' : '')
|
||||||
|
+ (poi ? 'P' : '')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatLocationFilter,
|
formatLocationFilter,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
const sep = '@'
|
const sep = '@';
|
||||||
|
|
||||||
const formatLocationIdentifier = (data) => {
|
const formatLocationIdentifier = (data) => {
|
||||||
let str = ''
|
let str = '';
|
||||||
for (let key in data) {
|
for (let key in data) {
|
||||||
if (!Object.prototype.hasOwnProperty.call(data, key)) continue
|
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
||||||
|
continue;
|
||||||
str += key + '=' + data[key] + sep // todo: escape, but how?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return str
|
str += key + '=' + data[key] + sep; // todo: escape, but how?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatLocationIdentifier,
|
formatLocationIdentifier,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,17 +1,25 @@
|
||||||
const formatLocation = (profile, l, name = 'location') => {
|
const formatLocation = (profile, l, name = 'location') => {
|
||||||
if ('string' === typeof l) return profile.formatStation(l)
|
if ('string' === typeof l) {
|
||||||
|
return profile.formatStation(l);
|
||||||
|
}
|
||||||
if ('object' === typeof l && !Array.isArray(l)) {
|
if ('object' === typeof l && !Array.isArray(l)) {
|
||||||
if (l.type === 'station' || l.type === 'stop') {
|
if (l.type === 'station' || l.type === 'stop') {
|
||||||
return profile.formatStation(l.id)
|
return profile.formatStation(l.id);
|
||||||
}
|
}
|
||||||
if (l.poi) return profile.formatPoi(l)
|
if (l.poi) {
|
||||||
if ('string' === typeof l.address) return profile.formatAddress(l)
|
return profile.formatPoi(l);
|
||||||
if (!l.type) throw new TypeError(`missing ${name}.type`)
|
|
||||||
throw new TypeError(`invalid ${name}.type: ${l.type}`)
|
|
||||||
}
|
}
|
||||||
throw new TypeError(name + ': valid station, address or poi required.')
|
if ('string' === typeof l.address) {
|
||||||
|
return profile.formatAddress(l);
|
||||||
}
|
}
|
||||||
|
if (!l.type) {
|
||||||
|
throw new TypeError(`missing ${name}.type`);
|
||||||
|
}
|
||||||
|
throw new TypeError(`invalid ${name}.type: ${l.type}`);
|
||||||
|
}
|
||||||
|
throw new TypeError(name + ': valid station, address or poi required.');
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatLocation,
|
formatLocation,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const formatLocationsReq = (ctx, query) => {
|
const formatLocationsReq = (ctx, query) => {
|
||||||
const {profile, opt} = ctx
|
const {profile, opt} = ctx;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cfg: {polyEnc: 'GPA'},
|
cfg: {polyEnc: 'GPA'},
|
||||||
|
@ -7,14 +7,16 @@ const formatLocationsReq = (ctx, query) => {
|
||||||
req: {input: {
|
req: {input: {
|
||||||
loc: {
|
loc: {
|
||||||
type: profile.formatLocationFilter(opt.stops, opt.addresses, opt.poi),
|
type: profile.formatLocationFilter(opt.stops, opt.addresses, opt.poi),
|
||||||
name: opt.fuzzy ? query + '?' : query
|
name: opt.fuzzy
|
||||||
|
? query + '?'
|
||||||
|
: query,
|
||||||
},
|
},
|
||||||
maxLoc: opt.results,
|
maxLoc: opt.results,
|
||||||
field: 'S' // todo: what is this?
|
field: 'S', // todo: what is this?
|
||||||
}}
|
}},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatLocationsReq,
|
formatLocationsReq,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const formatNearbyReq = (ctx, location) => {
|
const formatNearbyReq = (ctx, location) => {
|
||||||
const {profile, opt} = ctx
|
const {profile, opt} = ctx;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cfg: {polyEnc: 'GPA'},
|
cfg: {polyEnc: 'GPA'},
|
||||||
|
@ -8,21 +8,21 @@ const formatNearbyReq = (ctx, location) => {
|
||||||
ring: {
|
ring: {
|
||||||
cCrd: {
|
cCrd: {
|
||||||
x: profile.formatCoord(location.longitude),
|
x: profile.formatCoord(location.longitude),
|
||||||
y: profile.formatCoord(location.latitude)
|
y: profile.formatCoord(location.latitude),
|
||||||
},
|
},
|
||||||
maxDist: opt.distance || -1,
|
maxDist: opt.distance || -1,
|
||||||
minDist: 0
|
minDist: 0,
|
||||||
},
|
},
|
||||||
locFltrL: [
|
locFltrL: [
|
||||||
profile.formatProductsFilter(ctx, opt.products || {}),
|
profile.formatProductsFilter(ctx, opt.products || {}),
|
||||||
],
|
],
|
||||||
getPOIs: !!opt.poi,
|
getPOIs: Boolean(opt.poi),
|
||||||
getStops: !!opt.stops,
|
getStops: Boolean(opt.stops),
|
||||||
maxLoc: opt.results
|
maxLoc: opt.results,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatNearbyReq,
|
formatNearbyReq,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import {formatLocationIdentifier} from './location-identifier.js'
|
import {formatLocationIdentifier} from './location-identifier.js';
|
||||||
import {formatCoord} from './coord.js'
|
import {formatCoord} from './coord.js';
|
||||||
|
|
||||||
const formatPoi = (p) => {
|
const formatPoi = (p) => {
|
||||||
// todo: use Number.isFinite()!
|
// todo: use Number.isFinite()!
|
||||||
if (p.type !== 'location' || !p.latitude || !p.longitude || !p.id || !p.name) {
|
if (p.type !== 'location' || !p.latitude || !p.longitude || !p.id || !p.name) {
|
||||||
throw new TypeError('invalid POI')
|
throw new TypeError('invalid POI');
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -15,11 +15,11 @@ const formatPoi = (p) => {
|
||||||
O: p.name,
|
O: p.name,
|
||||||
L: p.id,
|
L: p.id,
|
||||||
X: formatCoord(p.longitude),
|
X: formatCoord(p.longitude),
|
||||||
Y: formatCoord(p.latitude)
|
Y: formatCoord(p.latitude),
|
||||||
})
|
}),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatPoi,
|
formatPoi,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,35 +1,45 @@
|
||||||
import isObj from 'lodash/isObject.js'
|
import isObj from 'lodash/isObject.js';
|
||||||
|
|
||||||
const hasProp = (o, k) => Object.prototype.hasOwnProperty.call(o, k)
|
const hasProp = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
|
||||||
|
|
||||||
const formatProductsFilter = (ctx, filter) => {
|
const formatProductsFilter = (ctx, filter) => {
|
||||||
if (!isObj(filter)) throw new TypeError('products filter must be an object')
|
if (!isObj(filter)) {
|
||||||
const {profile} = ctx
|
throw new TypeError('products filter must be an object');
|
||||||
|
}
|
||||||
|
const {profile} = ctx;
|
||||||
|
|
||||||
const byProduct = {}
|
const byProduct = {};
|
||||||
const defaultProducts = {}
|
const defaultProducts = {};
|
||||||
for (let product of profile.products) {
|
for (let product of profile.products) {
|
||||||
byProduct[product.id] = product
|
byProduct[product.id] = product;
|
||||||
defaultProducts[product.id] = product.default
|
defaultProducts[product.id] = product.default;
|
||||||
}
|
}
|
||||||
filter = Object.assign({}, defaultProducts, filter)
|
filter = Object.assign({}, defaultProducts, filter);
|
||||||
|
|
||||||
let res = 0, products = 0
|
let res = 0, products = 0;
|
||||||
for (let product in filter) {
|
for (let product in filter) {
|
||||||
if (!hasProp(filter, product) || filter[product] !== true) continue
|
if (!hasProp(filter, product) || filter[product] !== true) {
|
||||||
if (!byProduct[product]) throw new TypeError('unknown product ' + product)
|
continue;
|
||||||
products++
|
}
|
||||||
for (let bitmask of byProduct[product].bitmasks) res = res | bitmask
|
if (!byProduct[product]) {
|
||||||
|
throw new TypeError('unknown product ' + product);
|
||||||
|
}
|
||||||
|
products++;
|
||||||
|
for (let bitmask of byProduct[product].bitmasks) {
|
||||||
|
res = res | bitmask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (products === 0) {
|
||||||
|
throw new Error('no products used');
|
||||||
}
|
}
|
||||||
if (products === 0) throw new Error('no products used')
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'PROD',
|
type: 'PROD',
|
||||||
mode: 'INC',
|
mode: 'INC',
|
||||||
value: res + ''
|
value: String(res),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatProductsFilter,
|
formatProductsFilter,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const formatRadarReq = (ctx, north, west, south, east) => {
|
const formatRadarReq = (ctx, north, west, south, east) => {
|
||||||
const {profile, opt} = ctx
|
const {profile, opt} = ctx;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
meth: 'JourneyGeoPos',
|
meth: 'JourneyGeoPos',
|
||||||
|
@ -14,16 +14,16 @@ const formatRadarReq = (ctx, north, west, south, east) => {
|
||||||
perStep: Math.round(opt.duration / Math.max(opt.frames, 1) * 1000),
|
perStep: Math.round(opt.duration / Math.max(opt.frames, 1) * 1000),
|
||||||
ageOfReport: true, // todo: what is this?
|
ageOfReport: true, // todo: what is this?
|
||||||
jnyFltrL: [
|
jnyFltrL: [
|
||||||
profile.formatProductsFilter(ctx, opt.products || {})
|
profile.formatProductsFilter(ctx, opt.products || {}),
|
||||||
],
|
],
|
||||||
// todo: what is this? what about realtime?
|
// todo: what is this? what about realtime?
|
||||||
// - CALC
|
// - CALC
|
||||||
// - CALC_REPORT (as seen in the INSA Young app)
|
// - CALC_REPORT (as seen in the INSA Young app)
|
||||||
trainPosMode: 'CALC',
|
trainPosMode: 'CALC',
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatRadarReq,
|
formatRadarReq,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
const formatReachableFromReq = (ctx, address) => {
|
const formatReachableFromReq = (ctx, address) => {
|
||||||
const {profile, opt} = ctx
|
const {profile, opt} = ctx;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
meth: 'LocGeoReach',
|
meth: 'LocGeoReach',
|
||||||
req: {
|
req: {
|
||||||
loc: profile.formatLocation(profile, address, 'address'),
|
loc: profile.formatLocation(profile, address, 'address'),
|
||||||
maxDur: opt.maxDuration === null ? -1 : opt.maxDuration,
|
maxDur: opt.maxDuration === null
|
||||||
|
? -1
|
||||||
|
: opt.maxDuration,
|
||||||
maxChg: opt.maxTransfers,
|
maxChg: opt.maxTransfers,
|
||||||
date: profile.formatDate(profile, opt.when),
|
date: profile.formatDate(profile, opt.when),
|
||||||
time: profile.formatTime(profile, opt.when),
|
time: profile.formatTime(profile, opt.when),
|
||||||
period: 120, // todo: what is this?
|
period: 120, // todo: what is this?
|
||||||
jnyFltrL: [
|
jnyFltrL: [
|
||||||
profile.formatProductsFilter(ctx, opt.products || {})
|
profile.formatProductsFilter(ctx, opt.products || {}),
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatReachableFromReq,
|
formatReachableFromReq,
|
||||||
}
|
};
|
||||||
|
|
|
@ -2,15 +2,15 @@ const formatRectangle = (profile, north, west, south, east) => {
|
||||||
return {
|
return {
|
||||||
llCrd: {
|
llCrd: {
|
||||||
x: profile.formatCoord(west),
|
x: profile.formatCoord(west),
|
||||||
y: profile.formatCoord(south)
|
y: profile.formatCoord(south),
|
||||||
},
|
},
|
||||||
urCrd: {
|
urCrd: {
|
||||||
x: profile.formatCoord(east),
|
x: profile.formatCoord(east),
|
||||||
y: profile.formatCoord(north)
|
y: profile.formatCoord(north),
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatRectangle,
|
formatRectangle,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
const formatRefreshJourneyReq = (ctx, refreshToken) => {
|
const formatRefreshJourneyReq = (ctx, refreshToken) => {
|
||||||
// eslint-disable-next-line no-unused-vars
|
const {profile, opt} = ctx;
|
||||||
const {profile, opt} = ctx
|
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
getIST: true, // todo: make an option
|
getIST: true, // todo: make an option
|
||||||
getPasslist: !!opt.stopovers,
|
getPasslist: Boolean(opt.stopovers),
|
||||||
getPolyline: !!opt.polylines,
|
getPolyline: Boolean(opt.polylines),
|
||||||
getTariff: !!opt.tickets
|
getTariff: Boolean(opt.tickets),
|
||||||
}
|
};
|
||||||
if (profile.refreshJourneyUseOutReconL) {
|
if (profile.refreshJourneyUseOutReconL) {
|
||||||
req.outReconL = [{ctx: refreshToken}]
|
req.outReconL = [{ctx: refreshToken}];
|
||||||
} else {
|
} else {
|
||||||
req.ctxRecon = refreshToken
|
req.ctxRecon = refreshToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
meth: 'Reconstruction',
|
meth: 'Reconstruction',
|
||||||
req,
|
req,
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatRefreshJourneyReq,
|
formatRefreshJourneyReq,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,34 +1,38 @@
|
||||||
const formatRemarksReq = (ctx) => {
|
const formatRemarksReq = (ctx) => {
|
||||||
const {profile, opt} = ctx
|
const {profile, opt} = ctx;
|
||||||
|
|
||||||
const himFltrL = []
|
const himFltrL = [];
|
||||||
// todo: https://github.com/marudor/BahnhofsAbfahrten/blob/95fef0217d01344642dd423457473fe9b8b6056e/src/types/HAFAS/index.ts#L76-L91
|
// todo: https://github.com/marudor/BahnhofsAbfahrten/blob/95fef0217d01344642dd423457473fe9b8b6056e/src/types/HAFAS/index.ts#L76-L91
|
||||||
if (opt.products) {
|
if (opt.products) {
|
||||||
himFltrL.push(profile.formatProductsFilter(ctx, opt.products))
|
himFltrL.push(profile.formatProductsFilter(ctx, opt.products));
|
||||||
}
|
}
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
himFltrL,
|
himFltrL,
|
||||||
|
};
|
||||||
|
if (profile.remarksGetPolyline) {
|
||||||
|
req.getPolyline = Boolean(opt.polylines);
|
||||||
}
|
}
|
||||||
if (profile.remarksGetPolyline) req.getPolyline = !!opt.polylines
|
|
||||||
// todo: stLoc, dirLoc
|
// todo: stLoc, dirLoc
|
||||||
// todo: comp, dept, onlyHimId, onlyToday
|
// todo: comp, dept, onlyHimId, onlyToday
|
||||||
// todo: dailyB, dailyE
|
// todo: dailyB, dailyE
|
||||||
// see https://github.com/marudor/BahnhofsAbfahrten/blob/46a74957d68edc15713112df44e1a25150f5a178/src/types/HAFAS/HimSearch.ts#L3-L18
|
// see https://github.com/marudor/BahnhofsAbfahrten/blob/46a74957d68edc15713112df44e1a25150f5a178/src/types/HAFAS/HimSearch.ts#L3-L18
|
||||||
|
|
||||||
if (opt.results !== null) req.maxNum = opt.results
|
if (opt.results !== null) {
|
||||||
|
req.maxNum = opt.results;
|
||||||
|
}
|
||||||
if (opt.from !== null) {
|
if (opt.from !== null) {
|
||||||
req.dateB = profile.formatDate(profile, opt.from)
|
req.dateB = profile.formatDate(profile, opt.from);
|
||||||
req.timeB = profile.formatTime(profile, opt.from)
|
req.timeB = profile.formatTime(profile, opt.from);
|
||||||
}
|
}
|
||||||
if (opt.to !== null) {
|
if (opt.to !== null) {
|
||||||
req.dateE = profile.formatDate(profile, opt.to)
|
req.dateE = profile.formatDate(profile, opt.to);
|
||||||
req.timeE = profile.formatTime(profile, opt.to)
|
req.timeE = profile.formatTime(profile, opt.to);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {meth: 'HimSearch', req}
|
return {meth: 'HimSearch', req};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatRemarksReq,
|
formatRemarksReq,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
const formatStationBoardReq = (ctx, station, type) => {
|
const formatStationBoardReq = (ctx, station, type) => {
|
||||||
const {profile, opt} = ctx
|
const {profile, opt} = ctx;
|
||||||
|
|
||||||
const jnyFltrL = [
|
const jnyFltrL = [
|
||||||
profile.formatProductsFilter(ctx, opt.products || {})
|
profile.formatProductsFilter(ctx, opt.products || {}),
|
||||||
]
|
];
|
||||||
if (opt.line !== null) {
|
if (opt.line !== null) {
|
||||||
jnyFltrL.push({type: 'LINEID', mode: 'INC', value: opt.line})
|
jnyFltrL.push({type: 'LINEID', mode: 'INC', value: opt.line});
|
||||||
}
|
}
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
|
@ -13,22 +13,30 @@ const formatStationBoardReq = (ctx, station, type) => {
|
||||||
date: profile.formatDate(profile, opt.when),
|
date: profile.formatDate(profile, opt.when),
|
||||||
time: profile.formatTime(profile, opt.when),
|
time: profile.formatTime(profile, opt.when),
|
||||||
stbLoc: station,
|
stbLoc: station,
|
||||||
dirLoc: opt.direction ? profile.formatStation(opt.direction) : undefined,
|
dirLoc: opt.direction
|
||||||
|
? profile.formatStation(opt.direction)
|
||||||
|
: undefined,
|
||||||
jnyFltrL,
|
jnyFltrL,
|
||||||
dur: opt.duration
|
dur: opt.duration,
|
||||||
}
|
};
|
||||||
if (opt.results !== null) {
|
if (opt.results !== null) {
|
||||||
req.maxJny = opt.results === Infinity ? 10000 : opt.results
|
req.maxJny = opt.results === Infinity
|
||||||
|
? 10000
|
||||||
|
: opt.results;
|
||||||
|
}
|
||||||
|
if (profile.departuresGetPasslist) {
|
||||||
|
req.getPasslist = Boolean(opt.stopovers);
|
||||||
|
}
|
||||||
|
if (profile.departuresStbFltrEquiv) {
|
||||||
|
req.stbFltrEquiv = !opt.includeRelatedStations;
|
||||||
}
|
}
|
||||||
if (profile.departuresGetPasslist) req.getPasslist = !!opt.stopovers
|
|
||||||
if (profile.departuresStbFltrEquiv) req.stbFltrEquiv = !opt.includeRelatedStations
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
meth: 'StationBoard',
|
meth: 'StationBoard',
|
||||||
req
|
req,
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatStationBoardReq,
|
formatStationBoardReq,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {formatLocationIdentifier} from './location-identifier.js'
|
import {formatLocationIdentifier} from './location-identifier.js';
|
||||||
|
|
||||||
const formatStation = (id) => {
|
const formatStation = (id) => {
|
||||||
return {
|
return {
|
||||||
|
@ -6,12 +6,12 @@ const formatStation = (id) => {
|
||||||
// todo: name necessary?
|
// todo: name necessary?
|
||||||
lid: formatLocationIdentifier({
|
lid: formatLocationIdentifier({
|
||||||
A: '1', // station?
|
A: '1', // station?
|
||||||
L: id
|
L: id,
|
||||||
// todo: `p` – timestamp of when the ID was obtained
|
// todo: `p` – timestamp of when the ID was obtained
|
||||||
})
|
}),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatStation,
|
formatStation,
|
||||||
}
|
};
|
||||||
|
|
|
@ -3,11 +3,11 @@ const formatStopReq = (ctx, stopRef) => {
|
||||||
// todo: there's also `StationDetails`, are there differences?
|
// todo: there's also `StationDetails`, are there differences?
|
||||||
meth: 'LocDetails',
|
meth: 'LocDetails',
|
||||||
req: {
|
req: {
|
||||||
locL: [stopRef]
|
locL: [stopRef],
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatStopReq,
|
formatStopReq,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
import {DateTime, IANAZone} from 'luxon'
|
import {DateTime, IANAZone} from 'luxon';
|
||||||
import {luxonIANAZonesByProfile as timezones} from '../lib/luxon-timezones.js'
|
import {luxonIANAZonesByProfile as timezones} from '../lib/luxon-timezones.js';
|
||||||
|
|
||||||
// todo: change to `(profile) => (when) => {}`
|
// todo: change to `(profile) => (when) => {}`
|
||||||
const formatTime = (profile, when) => {
|
const formatTime = (profile, when) => {
|
||||||
let timezone
|
let timezone;
|
||||||
if (timezones.has(profile)) timezone = timezones.get(profile)
|
if (timezones.has(profile)) {
|
||||||
else {
|
timezone = timezones.get(profile);
|
||||||
timezone = new IANAZone(profile.timezone)
|
} else {
|
||||||
timezones.set(profile, timezone)
|
timezone = new IANAZone(profile.timezone);
|
||||||
|
timezones.set(profile, timezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
return DateTime.fromMillis(+when, {
|
return DateTime
|
||||||
|
.fromMillis(Number(when), {
|
||||||
locale: profile.locale,
|
locale: profile.locale,
|
||||||
zone: timezone
|
zone: timezone,
|
||||||
}).toFormat('HHmmss')
|
})
|
||||||
}
|
.toFormat('HHmmss');
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatTime,
|
formatTime,
|
||||||
}
|
};
|
||||||
|
|
|
@ -8,11 +8,11 @@ const formatTripReq = ({opt}, id) => {
|
||||||
// HAFAS apparently ignores the date in the trip ID and uses the `date` field.
|
// HAFAS apparently ignores the date in the trip ID and uses the `date` field.
|
||||||
// Thus, it will find a different trip if you pass the wrong date via `opt.when`.
|
// Thus, it will find a different trip if you pass the wrong date via `opt.when`.
|
||||||
// date: profile.formatDate(profile, opt.when),
|
// date: profile.formatDate(profile, opt.when),
|
||||||
getPolyline: !!opt.polyline
|
getPolyline: Boolean(opt.polyline),
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
formatTripReq,
|
formatTripReq,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,60 +1,60 @@
|
||||||
import {request} from '../lib/request.js'
|
import {request} from '../lib/request.js';
|
||||||
|
|
||||||
import {formatStationBoardReq} from '../format/station-board-req.js'
|
import {formatStationBoardReq} from '../format/station-board-req.js';
|
||||||
import {formatLocationsReq} from '../format/locations-req.js'
|
import {formatLocationsReq} from '../format/locations-req.js';
|
||||||
import {formatStopReq} from '../format/stop-req.js'
|
import {formatStopReq} from '../format/stop-req.js';
|
||||||
import {formatNearbyReq} from '../format/nearby-req.js'
|
import {formatNearbyReq} from '../format/nearby-req.js';
|
||||||
import {formatTripReq} from '../format/trip-req.js'
|
import {formatTripReq} from '../format/trip-req.js';
|
||||||
import {formatRadarReq} from '../format/radar-req.js'
|
import {formatRadarReq} from '../format/radar-req.js';
|
||||||
import {formatReachableFromReq} from '../format/reachable-from-req.js'
|
import {formatReachableFromReq} from '../format/reachable-from-req.js';
|
||||||
import {formatRefreshJourneyReq} from '../format/refresh-journey-req.js'
|
import {formatRefreshJourneyReq} from '../format/refresh-journey-req.js';
|
||||||
import {formatRemarksReq} from '../format/remarks-req.js'
|
import {formatRemarksReq} from '../format/remarks-req.js';
|
||||||
import {formatLinesReq} from '../format/lines-req.js'
|
import {formatLinesReq} from '../format/lines-req.js';
|
||||||
|
|
||||||
import {parseDateTime} from '../parse/date-time.js'
|
import {parseDateTime} from '../parse/date-time.js';
|
||||||
import {parsePlatform} from '../parse/platform.js'
|
import {parsePlatform} from '../parse/platform.js';
|
||||||
import {parseBitmask as parseProductsBitmask} from '../parse/products-bitmask.js'
|
import {parseBitmask as parseProductsBitmask} from '../parse/products-bitmask.js';
|
||||||
import {parseIcon} from '../parse/icon.js'
|
import {parseIcon} from '../parse/icon.js';
|
||||||
import {parseWhen} from '../parse/when.js'
|
import {parseWhen} from '../parse/when.js';
|
||||||
import {parsePrognosisType} from '../parse/prognosis-type.js'
|
import {parsePrognosisType} from '../parse/prognosis-type.js';
|
||||||
import {parseScheduledDays} from '../parse/scheduled-days.js'
|
import {parseScheduledDays} from '../parse/scheduled-days.js';
|
||||||
import {parseDeparture} from '../parse/departure.js'
|
import {parseDeparture} from '../parse/departure.js';
|
||||||
import {parseArrival} from '../parse/arrival.js'
|
import {parseArrival} from '../parse/arrival.js';
|
||||||
import {parseTrip} from '../parse/trip.js'
|
import {parseTrip} from '../parse/trip.js';
|
||||||
import {parseJourneyLeg} from '../parse/journey-leg.js'
|
import {parseJourneyLeg} from '../parse/journey-leg.js';
|
||||||
import {parseJourney} from '../parse/journey.js'
|
import {parseJourney} from '../parse/journey.js';
|
||||||
import {parseLine} from '../parse/line.js'
|
import {parseLine} from '../parse/line.js';
|
||||||
import {parseLocation} from '../parse/location.js'
|
import {parseLocation} from '../parse/location.js';
|
||||||
import {parseCommonData as parseCommon} from '../parse/common.js'
|
import {parseCommonData as parseCommon} from '../parse/common.js';
|
||||||
import {parsePolyline} from '../parse/polyline.js'
|
import {parsePolyline} from '../parse/polyline.js';
|
||||||
import {parseMovement} from '../parse/movement.js'
|
import {parseMovement} from '../parse/movement.js';
|
||||||
import {parseNearby} from '../parse/nearby.js'
|
import {parseNearby} from '../parse/nearby.js';
|
||||||
import {parseOperator} from '../parse/operator.js'
|
import {parseOperator} from '../parse/operator.js';
|
||||||
import {parseHint} from '../parse/hint.js'
|
import {parseHint} from '../parse/hint.js';
|
||||||
import {parseWarning} from '../parse/warning.js'
|
import {parseWarning} from '../parse/warning.js';
|
||||||
import {parseStopover} from '../parse/stopover.js'
|
import {parseStopover} from '../parse/stopover.js';
|
||||||
|
|
||||||
import {formatAddress} from '../format/address.js'
|
import {formatAddress} from '../format/address.js';
|
||||||
import {formatCoord} from '../format/coord.js'
|
import {formatCoord} from '../format/coord.js';
|
||||||
import {formatDate} from '../format/date.js'
|
import {formatDate} from '../format/date.js';
|
||||||
import {formatLocationFilter} from '../format/location-filter.js'
|
import {formatLocationFilter} from '../format/location-filter.js';
|
||||||
import {formatProductsFilter} from '../format/products-filter.js'
|
import {formatProductsFilter} from '../format/products-filter.js';
|
||||||
import {formatPoi} from '../format/poi.js'
|
import {formatPoi} from '../format/poi.js';
|
||||||
import {formatStation} from '../format/station.js'
|
import {formatStation} from '../format/station.js';
|
||||||
import {formatTime} from '../format/time.js'
|
import {formatTime} from '../format/time.js';
|
||||||
import {formatLocation} from '../format/location.js'
|
import {formatLocation} from '../format/location.js';
|
||||||
import {formatRectangle} from '../format/rectangle.js'
|
import {formatRectangle} from '../format/rectangle.js';
|
||||||
import * as filters from '../format/filters.js'
|
import * as filters from '../format/filters.js';
|
||||||
|
|
||||||
const DEBUG = /(^|,)hafas-client(,|$)/.test(process.env.DEBUG || '')
|
const DEBUG = (/(^|,)hafas-client(,|$)/).test(process.env.DEBUG || '');
|
||||||
const logRequest = DEBUG
|
const logRequest = DEBUG
|
||||||
? (_, req, reqId) => console.error(req.body + '')
|
? (_, req, reqId) => console.error(String(req.body))
|
||||||
: () => {}
|
: () => {};
|
||||||
const logResponse = DEBUG
|
const logResponse = DEBUG
|
||||||
? (_, res, body, reqId) => console.error(body)
|
? (_, res, body, reqId) => console.error(body)
|
||||||
: () => {}
|
: () => {};
|
||||||
|
|
||||||
const id = (ctx, x) => x
|
const id = (ctx, x) => x;
|
||||||
|
|
||||||
const defaultProfile = {
|
const defaultProfile = {
|
||||||
request,
|
request,
|
||||||
|
@ -133,8 +133,8 @@ const defaultProfile = {
|
||||||
// `remarks()` method: support for `getPolyline` field?
|
// `remarks()` method: support for `getPolyline` field?
|
||||||
remarksGetPolyline: true, // `remarks()` method: support for `getPolyline` field?
|
remarksGetPolyline: true, // `remarks()` method: support for `getPolyline` field?
|
||||||
lines: true,
|
lines: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
defaultProfile,
|
defaultProfile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,59 +1,59 @@
|
||||||
const ACCESS_DENIED = 'ACCESS_DENIED'
|
const ACCESS_DENIED = 'ACCESS_DENIED';
|
||||||
const INVALID_REQUEST = 'INVALID_REQUEST'
|
const INVALID_REQUEST = 'INVALID_REQUEST';
|
||||||
const NOT_FOUND = 'NOT_FOUND'
|
const NOT_FOUND = 'NOT_FOUND';
|
||||||
const SERVER_ERROR = 'SERVER_ERROR'
|
const SERVER_ERROR = 'SERVER_ERROR';
|
||||||
|
|
||||||
class HafasError extends Error {
|
class HafasError extends Error {
|
||||||
constructor (cleanMessage, hafasCode, props) {
|
constructor (cleanMessage, hafasCode, props) {
|
||||||
const msg = hafasCode
|
const msg = hafasCode
|
||||||
? hafasCode + ': ' + cleanMessage
|
? hafasCode + ': ' + cleanMessage
|
||||||
: cleanMessage
|
: cleanMessage;
|
||||||
super(msg)
|
super(msg);
|
||||||
|
|
||||||
// generic props
|
// generic props
|
||||||
this.isHafasError = true
|
this.isHafasError = true;
|
||||||
|
|
||||||
// error-specific props
|
// error-specific props
|
||||||
this.code = null
|
this.code = null;
|
||||||
// By default, we take the blame, unless we know for sure.
|
// By default, we take the blame, unless we know for sure.
|
||||||
this.isCausedByServer = false
|
this.isCausedByServer = false;
|
||||||
this.hafasCode = hafasCode
|
this.hafasCode = hafasCode;
|
||||||
Object.assign(this, props)
|
Object.assign(this, props);
|
||||||
|
|
||||||
return this
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HafasAccessDeniedError extends HafasError {
|
class HafasAccessDeniedError extends HafasError {
|
||||||
constructor (cleanMessage, hafasCode, props) {
|
constructor (cleanMessage, hafasCode, props) {
|
||||||
super(cleanMessage, hafasCode, props)
|
super(cleanMessage, hafasCode, props);
|
||||||
this.code = ACCESS_DENIED
|
this.code = ACCESS_DENIED;
|
||||||
return this
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HafasInvalidRequestError extends HafasError {
|
class HafasInvalidRequestError extends HafasError {
|
||||||
constructor (cleanMessage, hafasCode, props) {
|
constructor (cleanMessage, hafasCode, props) {
|
||||||
super(cleanMessage, hafasCode, props)
|
super(cleanMessage, hafasCode, props);
|
||||||
this.code = INVALID_REQUEST
|
this.code = INVALID_REQUEST;
|
||||||
return this
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HafasNotFoundError extends HafasError {
|
class HafasNotFoundError extends HafasError {
|
||||||
constructor (cleanMessage, hafasCode, props) {
|
constructor (cleanMessage, hafasCode, props) {
|
||||||
super(cleanMessage, hafasCode, props)
|
super(cleanMessage, hafasCode, props);
|
||||||
this.code = NOT_FOUND
|
this.code = NOT_FOUND;
|
||||||
return this
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HafasServerError extends HafasError {
|
class HafasServerError extends HafasError {
|
||||||
constructor (cleanMessage, hafasCode, props) {
|
constructor (cleanMessage, hafasCode, props) {
|
||||||
super(cleanMessage, hafasCode, props)
|
super(cleanMessage, hafasCode, props);
|
||||||
this.code = SERVER_ERROR
|
this.code = SERVER_ERROR;
|
||||||
this.isCausedByServer = true
|
this.isCausedByServer = true;
|
||||||
return this
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,8 +285,8 @@ const byErrorCode = Object.assign(Object.create(null), {
|
||||||
props: {
|
props: {
|
||||||
shouldRetry: true,
|
shouldRetry: true,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ACCESS_DENIED,
|
ACCESS_DENIED,
|
||||||
|
@ -299,4 +299,4 @@ export {
|
||||||
HafasNotFoundError,
|
HafasNotFoundError,
|
||||||
HafasServerError,
|
HafasServerError,
|
||||||
byErrorCode,
|
byErrorCode,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
import objectScan from 'object-scan'
|
import objectScan from 'object-scan';
|
||||||
|
|
||||||
const createFindInTree = (needles) => {
|
const createFindInTree = (needles) => {
|
||||||
const scanner = objectScan(needles, {
|
const scanner = objectScan(needles, {
|
||||||
filterFn: ({value, parents, matchedBy, context}) => {
|
filterFn: ({value, parents, matchedBy, context}) => {
|
||||||
matchedBy.forEach((needle) => {
|
matchedBy.forEach((needle) => {
|
||||||
context[needle].push([value, parents])
|
context[needle].push([value, parents]);
|
||||||
})
|
});
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
return (haystack) => {
|
return (haystack) => {
|
||||||
const context = Object.create(null)
|
const context = Object.create(null);
|
||||||
needles.forEach((needle) => {
|
needles.forEach((needle) => {
|
||||||
context[needle] = []
|
context[needle] = [];
|
||||||
})
|
});
|
||||||
return scanner(haystack, context)
|
return scanner(haystack, context);
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
createFindInTree,
|
createFindInTree,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// hafas-client profile -> luxon.IANAZone
|
// hafas-client profile -> luxon.IANAZone
|
||||||
const luxonIANAZonesByProfile = new WeakMap()
|
const luxonIANAZonesByProfile = new WeakMap();
|
||||||
|
|
||||||
export {
|
export {
|
||||||
luxonIANAZonesByProfile,
|
luxonIANAZonesByProfile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -13,11 +13,11 @@ const parseHook = (oldParse, newParse) => {
|
||||||
return (ctx, ...args) => {
|
return (ctx, ...args) => {
|
||||||
return newParse({
|
return newParse({
|
||||||
...ctx,
|
...ctx,
|
||||||
parsed: oldParse({...ctx, parsed: {}}, ...args)
|
parsed: oldParse({...ctx, parsed: {}}, ...args),
|
||||||
}, ...args)
|
}, ...args);
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
parseHook,
|
parseHook,
|
||||||
}
|
};
|
||||||
|
|
170
lib/request.js
170
lib/request.js
|
@ -1,105 +1,118 @@
|
||||||
import ProxyAgent from 'https-proxy-agent'
|
import ProxyAgent from 'https-proxy-agent';
|
||||||
import {isIP} from 'net'
|
import {isIP} from 'net';
|
||||||
import {Agent as HttpsAgent} from 'https'
|
import {Agent as HttpsAgent} from 'https';
|
||||||
import roundRobin from '@derhuerst/round-robin-scheduler'
|
import roundRobin from '@derhuerst/round-robin-scheduler';
|
||||||
import {randomBytes} from 'crypto'
|
import {randomBytes} from 'crypto';
|
||||||
import createHash from 'create-hash'
|
import createHash from 'create-hash';
|
||||||
import {Buffer} from 'node:buffer'
|
import {Buffer} from 'node:buffer';
|
||||||
import {stringify} from 'qs'
|
import {stringify} from 'qs';
|
||||||
import {Request, fetch} from 'cross-fetch'
|
import {Request, fetch} from 'cross-fetch';
|
||||||
import {parse as parseContentType} from 'content-type'
|
import {parse as parseContentType} from 'content-type';
|
||||||
import {HafasError, byErrorCode} from './errors.js'
|
import {HafasError, byErrorCode} from './errors.js';
|
||||||
|
|
||||||
const proxyAddress = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || null
|
const proxyAddress = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || null;
|
||||||
const localAddresses = process.env.LOCAL_ADDRESS || null
|
const localAddresses = process.env.LOCAL_ADDRESS || null;
|
||||||
|
|
||||||
if (proxyAddress && localAddresses) {
|
if (proxyAddress && localAddresses) {
|
||||||
console.error('Both env vars HTTPS_PROXY/HTTP_PROXY and LOCAL_ADDRESS are not supported.')
|
console.error('Both env vars HTTPS_PROXY/HTTP_PROXY and LOCAL_ADDRESS are not supported.');
|
||||||
process.exit(1)
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const plainAgent = new HttpsAgent({
|
const plainAgent = new HttpsAgent({
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
})
|
});
|
||||||
let getAgent = () => plainAgent
|
let getAgent = () => plainAgent;
|
||||||
|
|
||||||
if (proxyAddress) {
|
if (proxyAddress) {
|
||||||
const agent = new ProxyAgent(proxyAddress, {
|
const agent = new ProxyAgent(proxyAddress, {
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
keepAliveMsecs: 10 * 1000, // 10s
|
keepAliveMsecs: 10 * 1000, // 10s
|
||||||
})
|
});
|
||||||
getAgent = () => agent
|
getAgent = () => agent;
|
||||||
} else if (localAddresses) {
|
} else if (localAddresses) {
|
||||||
const agents = process.env.LOCAL_ADDRESS.split(',')
|
const agents = process.env.LOCAL_ADDRESS.split(',')
|
||||||
.map((addr) => {
|
.map((addr) => {
|
||||||
const family = isIP(addr)
|
const family = isIP(addr);
|
||||||
if (family === 0) throw new Error('invalid local address:' + addr)
|
if (family === 0) {
|
||||||
|
throw new Error('invalid local address:' + addr);
|
||||||
|
}
|
||||||
return new HttpsAgent({
|
return new HttpsAgent({
|
||||||
localAddress: addr, family,
|
localAddress: addr, family,
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
const pool = roundRobin(agents)
|
const pool = roundRobin(agents);
|
||||||
getAgent = () => pool.get()
|
getAgent = () => pool.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = randomBytes(3).toString('hex')
|
const id = randomBytes(3)
|
||||||
|
.toString('hex');
|
||||||
const randomizeUserAgent = (userAgent) => {
|
const randomizeUserAgent = (userAgent) => {
|
||||||
let ua = userAgent
|
let ua = userAgent;
|
||||||
for (
|
for (
|
||||||
let i = Math.round(5 + Math.random() * 5);
|
let i = Math.round(5 + Math.random() * 5);
|
||||||
i < ua.length;
|
i < ua.length;
|
||||||
i += Math.round(5 + Math.random() * 5)
|
i += Math.round(5 + Math.random() * 5)
|
||||||
) {
|
) {
|
||||||
ua = ua.slice(0, i) + id + ua.slice(i)
|
ua = ua.slice(0, i) + id + ua.slice(i);
|
||||||
i += id.length
|
i += id.length;
|
||||||
}
|
|
||||||
return ua
|
|
||||||
}
|
}
|
||||||
|
return ua;
|
||||||
|
};
|
||||||
|
|
||||||
const md5 = input => createHash('md5').update(input).digest()
|
const md5 = input => createHash('md5')
|
||||||
|
.update(input)
|
||||||
|
.digest();
|
||||||
|
|
||||||
const checkIfResponseIsOk = (_) => {
|
const checkIfResponseIsOk = (_) => {
|
||||||
const {
|
const {
|
||||||
body,
|
body,
|
||||||
errProps: baseErrProps,
|
errProps: baseErrProps,
|
||||||
} = _
|
} = _;
|
||||||
|
|
||||||
const errProps = {
|
const errProps = {
|
||||||
...baseErrProps,
|
...baseErrProps,
|
||||||
|
};
|
||||||
|
if (body.id) {
|
||||||
|
errProps.hafasResponseId = body.id;
|
||||||
}
|
}
|
||||||
if (body.id) errProps.hafasResponseId = body.id
|
|
||||||
|
|
||||||
// Because we want more accurate stack traces, we don't construct the error here,
|
// Because we want more accurate stack traces, we don't construct the error here,
|
||||||
// but only return the constructor & error message.
|
// but only return the constructor & error message.
|
||||||
const getError = (_) => {
|
const getError = (_) => {
|
||||||
// mutating here is ugly but pragmatic
|
// mutating here is ugly but pragmatic
|
||||||
if (_.errTxt) errProps.hafasMessage = _.errTxt
|
if (_.errTxt) {
|
||||||
if (_.errTxtOut) errProps.hafasDescription = _.errTxtOut
|
errProps.hafasMessage = _.errTxt;
|
||||||
|
}
|
||||||
|
if (_.errTxtOut) {
|
||||||
|
errProps.hafasDescription = _.errTxtOut;
|
||||||
|
}
|
||||||
|
|
||||||
if (_.err in byErrorCode) return byErrorCode[_.err]
|
if (_.err in byErrorCode) {
|
||||||
|
return byErrorCode[_.err];
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
Error: HafasError,
|
Error: HafasError,
|
||||||
message: body.errTxt || 'unknown error',
|
message: body.errTxt || 'unknown error',
|
||||||
props: {},
|
props: {},
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
if (body.err && body.err !== 'OK') {
|
if (body.err && body.err !== 'OK') {
|
||||||
const {Error: HafasError, message, props} = getError(body)
|
const {Error: HafasError, message, props} = getError(body);
|
||||||
throw new HafasError(message, body.err, {...errProps, ...props})
|
throw new HafasError(message, body.err, {...errProps, ...props});
|
||||||
}
|
}
|
||||||
if (!body.svcResL || !body.svcResL[0]) {
|
if (!body.svcResL || !body.svcResL[0]) {
|
||||||
throw new HafasError('invalid/unsupported response structure', null, errProps)
|
throw new HafasError('invalid/unsupported response structure', null, errProps);
|
||||||
}
|
}
|
||||||
if (body.svcResL[0].err !== 'OK') {
|
if (body.svcResL[0].err !== 'OK') {
|
||||||
const {Error: HafasError, message, props} = getError(body.svcResL[0])
|
const {Error: HafasError, message, props} = getError(body.svcResL[0]);
|
||||||
throw new HafasError(message, body.svcResL[0].err, {...errProps, ...props})
|
throw new HafasError(message, body.svcResL[0].err, {...errProps, ...props});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const request = async (ctx, userAgent, reqData) => {
|
const request = async (ctx, userAgent, reqData) => {
|
||||||
const {profile, opt} = ctx
|
const {profile, opt} = ctx;
|
||||||
|
|
||||||
const rawReqBody = profile.transformReqBody(ctx, {
|
const rawReqBody = profile.transformReqBody(ctx, {
|
||||||
// todo: is it `eng` actually?
|
// todo: is it `eng` actually?
|
||||||
|
@ -111,7 +124,7 @@ const request = async (ctx, userAgent, reqData) => {
|
||||||
ext: profile.ext, // ?
|
ext: profile.ext, // ?
|
||||||
ver: profile.ver, // HAFAS protocol version
|
ver: profile.ver, // HAFAS protocol version
|
||||||
auth: profile.auth, // static authentication
|
auth: profile.auth, // static authentication
|
||||||
})
|
});
|
||||||
|
|
||||||
const req = profile.transformReq(ctx, {
|
const req = profile.transformReq(ctx, {
|
||||||
agent: getAgent(),
|
agent: getAgent(),
|
||||||
|
@ -128,39 +141,40 @@ const request = async (ctx, userAgent, reqData) => {
|
||||||
'connection': 'keep-alive', // prevent excessive re-connecting
|
'connection': 'keep-alive', // prevent excessive re-connecting
|
||||||
},
|
},
|
||||||
redirect: 'follow',
|
redirect: 'follow',
|
||||||
query: {}
|
query: {},
|
||||||
})
|
});
|
||||||
|
|
||||||
if (profile.addChecksum || profile.addMicMac) {
|
if (profile.addChecksum || profile.addMicMac) {
|
||||||
if (!Buffer.isBuffer(profile.salt) && 'string' !== typeof profile.salt) {
|
if (!Buffer.isBuffer(profile.salt) && 'string' !== typeof profile.salt) {
|
||||||
throw new TypeError('profile.salt must be a Buffer or a string.')
|
throw new TypeError('profile.salt must be a Buffer or a string.');
|
||||||
}
|
}
|
||||||
// Buffer.from(buf, 'hex') just returns buf
|
// Buffer.from(buf, 'hex') just returns buf
|
||||||
const salt = Buffer.from(profile.salt, 'hex')
|
const salt = Buffer.from(profile.salt, 'hex');
|
||||||
|
|
||||||
if (profile.addChecksum) {
|
if (profile.addChecksum) {
|
||||||
const checksum = md5(Buffer.concat([
|
const checksum = md5(Buffer.concat([
|
||||||
Buffer.from(req.body, 'utf8'),
|
Buffer.from(req.body, 'utf8'),
|
||||||
salt,
|
salt,
|
||||||
]))
|
]));
|
||||||
req.query.checksum = checksum.toString('hex')
|
req.query.checksum = checksum.toString('hex');
|
||||||
}
|
}
|
||||||
if (profile.addMicMac) {
|
if (profile.addMicMac) {
|
||||||
const mic = md5(Buffer.from(req.body, 'utf8'))
|
const mic = md5(Buffer.from(req.body, 'utf8'));
|
||||||
req.query.mic = mic.toString('hex')
|
req.query.mic = mic.toString('hex');
|
||||||
|
|
||||||
const micAsHex = Buffer.from(mic.toString('hex'), 'utf8')
|
const micAsHex = Buffer.from(mic.toString('hex'), 'utf8');
|
||||||
const mac = md5(Buffer.concat([micAsHex, salt]))
|
const mac = md5(Buffer.concat([micAsHex, salt]));
|
||||||
req.query.mac = mac.toString('hex')
|
req.query.mac = mac.toString('hex');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const reqId = randomBytes(3).toString('hex')
|
const reqId = randomBytes(3)
|
||||||
const url = profile.endpoint + '?' + stringify(req.query)
|
.toString('hex');
|
||||||
const fetchReq = new Request(url, req)
|
const url = profile.endpoint + '?' + stringify(req.query);
|
||||||
profile.logRequest(ctx, fetchReq, reqId)
|
const fetchReq = new Request(url, req);
|
||||||
|
profile.logRequest(ctx, fetchReq, reqId);
|
||||||
|
|
||||||
const res = await fetch(url, req)
|
const res = await fetch(url, req);
|
||||||
|
|
||||||
const errProps = {
|
const errProps = {
|
||||||
// todo [breaking]: assign as non-enumerable property
|
// todo [breaking]: assign as non-enumerable property
|
||||||
|
@ -168,40 +182,40 @@ const request = async (ctx, userAgent, reqData) => {
|
||||||
// todo [breaking]: assign as non-enumerable property
|
// todo [breaking]: assign as non-enumerable property
|
||||||
response: res,
|
response: res,
|
||||||
url,
|
url,
|
||||||
}
|
};
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
// todo [breaking]: make this a FetchError or a HafasClientError?
|
// todo [breaking]: make this a FetchError or a HafasClientError?
|
||||||
const err = new Error(res.statusText)
|
const err = new Error(res.statusText);
|
||||||
Object.assign(err, errProps)
|
Object.assign(err, errProps);
|
||||||
throw err
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cType = res.headers.get('content-type')
|
let cType = res.headers.get('content-type');
|
||||||
if (cType) {
|
if (cType) {
|
||||||
const {type} = parseContentType(cType)
|
const {type} = parseContentType(cType);
|
||||||
if (type !== 'application/json') {
|
if (type !== 'application/json') {
|
||||||
throw new HafasError('invalid/unsupported response content-type: ' + cType, null, errProps)
|
throw new HafasError('invalid/unsupported response content-type: ' + cType, null, errProps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const body = await res.text()
|
const body = await res.text();
|
||||||
profile.logResponse(ctx, res, body, reqId)
|
profile.logResponse(ctx, res, body, reqId);
|
||||||
|
|
||||||
const b = JSON.parse(body)
|
const b = JSON.parse(body);
|
||||||
checkIfResponseIsOk({
|
checkIfResponseIsOk({
|
||||||
body: b,
|
body: b,
|
||||||
errProps,
|
errProps,
|
||||||
})
|
});
|
||||||
|
|
||||||
const svcRes = b.svcResL[0].res
|
const svcRes = b.svcResL[0].res;
|
||||||
return {
|
return {
|
||||||
res: svcRes,
|
res: svcRes,
|
||||||
common: profile.parseCommon({...ctx, res: svcRes}),
|
common: profile.parseCommon({...ctx, res: svcRes}),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
checkIfResponseIsOk,
|
checkIfResponseIsOk,
|
||||||
request,
|
request,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,47 +1,63 @@
|
||||||
const findById = (needle) => {
|
const findById = (needle) => {
|
||||||
const needleStopId = needle.id
|
const needleStopId = needle.id;
|
||||||
const needleStationId = needle.station ? needle.station.id : null
|
const needleStationId = needle.station
|
||||||
|
? needle.station.id
|
||||||
|
: null;
|
||||||
|
|
||||||
return (stop) => {
|
return (stop) => {
|
||||||
if (needleStopId === stop.id) return true
|
if (needleStopId === stop.id) {
|
||||||
const stationId = stop.station ? stop.station.id : null
|
return true;
|
||||||
if (needleStationId && stationId && needleStationId === stationId) return true
|
}
|
||||||
|
const stationId = stop.station
|
||||||
|
? stop.station.id
|
||||||
|
: null;
|
||||||
|
if (needleStationId && stationId && needleStationId === stationId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
// todo: `needleStationId === stop.id`? `needleStopId === stationId`?
|
// todo: `needleStationId === stop.id`? `needleStopId === stationId`?
|
||||||
return false
|
return false;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const sliceLeg = (leg, from, to) => {
|
const sliceLeg = (leg, from, to) => {
|
||||||
if (!Array.isArray(leg.stopovers)) throw new Error('leg.stopovers must be an array.')
|
if (!Array.isArray(leg.stopovers)) {
|
||||||
|
throw new Error('leg.stopovers must be an array.');
|
||||||
const stops = leg.stopovers.map(st => st.stop)
|
|
||||||
const fromI = stops.findIndex(findById(from))
|
|
||||||
if (fromI === -1) throw new Error('from not found in stopovers')
|
|
||||||
const fromStopover = leg.stopovers[fromI]
|
|
||||||
|
|
||||||
const toI = stops.findIndex(findById(to))
|
|
||||||
if (toI === -1) throw new Error('to not found in stopovers')
|
|
||||||
const toStopover = leg.stopovers[toI]
|
|
||||||
|
|
||||||
if (fromI === 0 && toI === leg.stopovers.length - 1) return leg
|
|
||||||
const newLeg = Object.assign({}, leg)
|
|
||||||
newLeg.stopovers = leg.stopovers.slice(fromI, toI + 1)
|
|
||||||
|
|
||||||
newLeg.origin = fromStopover.stop
|
|
||||||
newLeg.departure = fromStopover.departure
|
|
||||||
newLeg.departureDelay = fromStopover.departureDelay
|
|
||||||
newLeg.scheduledDeparture = fromStopover.scheduledDeparture
|
|
||||||
newLeg.departurePlatform = fromStopover.departurePlatform
|
|
||||||
|
|
||||||
newLeg.destination = toStopover.stop
|
|
||||||
newLeg.arrival = toStopover.arrival
|
|
||||||
newLeg.arrivalDelay = toStopover.arrivalDelay
|
|
||||||
newLeg.scheduledArrival = toStopover.scheduledArrival
|
|
||||||
newLeg.arrivalPlatform = toStopover.arrivalPlatform
|
|
||||||
|
|
||||||
return newLeg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stops = leg.stopovers.map(st => st.stop);
|
||||||
|
const fromI = stops.findIndex(findById(from));
|
||||||
|
if (fromI === -1) {
|
||||||
|
throw new Error('from not found in stopovers');
|
||||||
|
}
|
||||||
|
const fromStopover = leg.stopovers[fromI];
|
||||||
|
|
||||||
|
const toI = stops.findIndex(findById(to));
|
||||||
|
if (toI === -1) {
|
||||||
|
throw new Error('to not found in stopovers');
|
||||||
|
}
|
||||||
|
const toStopover = leg.stopovers[toI];
|
||||||
|
|
||||||
|
if (fromI === 0 && toI === leg.stopovers.length - 1) {
|
||||||
|
return leg;
|
||||||
|
}
|
||||||
|
const newLeg = Object.assign({}, leg);
|
||||||
|
newLeg.stopovers = leg.stopovers.slice(fromI, toI + 1);
|
||||||
|
|
||||||
|
newLeg.origin = fromStopover.stop;
|
||||||
|
newLeg.departure = fromStopover.departure;
|
||||||
|
newLeg.departureDelay = fromStopover.departureDelay;
|
||||||
|
newLeg.scheduledDeparture = fromStopover.scheduledDeparture;
|
||||||
|
newLeg.departurePlatform = fromStopover.departurePlatform;
|
||||||
|
|
||||||
|
newLeg.destination = toStopover.stop;
|
||||||
|
newLeg.arrival = toStopover.arrival;
|
||||||
|
newLeg.arrivalDelay = toStopover.arrivalDelay;
|
||||||
|
newLeg.scheduledArrival = toStopover.scheduledArrival;
|
||||||
|
newLeg.arrivalPlatform = toStopover.arrivalPlatform;
|
||||||
|
|
||||||
|
return newLeg;
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
sliceLeg,
|
sliceLeg,
|
||||||
}
|
};
|
||||||
|
|
|
@ -43,53 +43,55 @@ const types = {
|
||||||
formatStation: 'function',
|
formatStation: 'function',
|
||||||
formatTime: 'function',
|
formatTime: 'function',
|
||||||
formatLocation: 'function',
|
formatLocation: 'function',
|
||||||
formatRectangle: 'function'
|
formatRectangle: 'function',
|
||||||
}
|
};
|
||||||
|
|
||||||
const validateProfile = (profile) => {
|
const validateProfile = (profile) => {
|
||||||
for (let key of Object.keys(types)) {
|
for (let key of Object.keys(types)) {
|
||||||
const type = types[key]
|
const type = types[key];
|
||||||
if (type === 'array') {
|
if (type === 'array') {
|
||||||
if (!Array.isArray(profile[key])) {
|
if (!Array.isArray(profile[key])) {
|
||||||
throw new TypeError(`profile.${key} must be an array.`)
|
throw new TypeError(`profile.${key} must be an array.`);
|
||||||
}
|
}
|
||||||
} else if (type !== typeof profile[key]) {
|
} else if (type !== typeof profile[key]) {
|
||||||
throw new TypeError(`profile.${key} must be a ${type}.`)
|
throw new TypeError(`profile.${key} must be a ${type}.`);
|
||||||
}
|
}
|
||||||
if (type === 'object' && profile[key] === null) {
|
if (type === 'object' && profile[key] === null) {
|
||||||
throw new TypeError(`profile.${key} must not be null.`)
|
throw new TypeError(`profile.${key} must not be null.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray(profile.products)) {
|
if (!Array.isArray(profile.products)) {
|
||||||
throw new TypeError('profile.products must be an array.')
|
throw new TypeError('profile.products must be an array.');
|
||||||
|
}
|
||||||
|
if (profile.products.length === 0) {
|
||||||
|
throw new Error('profile.products is empty.');
|
||||||
}
|
}
|
||||||
if (profile.products.length === 0) throw new Error('profile.products is empty.')
|
|
||||||
for (let product of profile.products) {
|
for (let product of profile.products) {
|
||||||
if ('string' !== typeof product.id) {
|
if ('string' !== typeof product.id) {
|
||||||
throw new TypeError('profile.products[].id must be a string.')
|
throw new TypeError('profile.products[].id must be a string.');
|
||||||
}
|
}
|
||||||
if ('boolean' !== typeof product.default) {
|
if ('boolean' !== typeof product.default) {
|
||||||
throw new TypeError('profile.products[].default must be a boolean.')
|
throw new TypeError('profile.products[].default must be a boolean.');
|
||||||
}
|
}
|
||||||
if (!Array.isArray(product.bitmasks)) {
|
if (!Array.isArray(product.bitmasks)) {
|
||||||
throw new TypeError(product.id + '.bitmasks must be an array.')
|
throw new TypeError(product.id + '.bitmasks must be an array.');
|
||||||
}
|
}
|
||||||
for (let bitmask of product.bitmasks) {
|
for (let bitmask of product.bitmasks) {
|
||||||
if ('number' !== typeof bitmask) {
|
if ('number' !== typeof bitmask) {
|
||||||
throw new TypeError(product.id + '.bitmasks[] must be a number.')
|
throw new TypeError(product.id + '.bitmasks[] must be a number.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('trip' in profile && 'boolean' !== typeof profile.trip) {
|
if ('trip' in profile && 'boolean' !== typeof profile.trip) {
|
||||||
throw new Error('profile.trip must be a boolean.')
|
throw new Error('profile.trip must be a boolean.');
|
||||||
}
|
}
|
||||||
if ('journeyLeg' in profile) {
|
if ('journeyLeg' in profile) {
|
||||||
throw new Error('profile.journeyLeg has been removed. Use profile.trip.')
|
throw new Error('profile.journeyLeg has been removed. Use profile.trip.');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
validateProfile,
|
validateProfile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'regional-train',
|
id: 'regional-train',
|
||||||
|
@ -82,7 +82,7 @@ const products = [{
|
||||||
name: 'Fähre',
|
name: 'Fähre',
|
||||||
short: 'Fähre',
|
short: 'Fähre',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -98,8 +98,8 @@ const profile = {
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
remarks: true,
|
remarks: true,
|
||||||
remarksGetPolyline: false,
|
remarksGetPolyline: false,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'bart',
|
id: 'bart',
|
||||||
|
@ -47,7 +47,7 @@ const products = [{
|
||||||
name: 'cable car',
|
name: 'cable car',
|
||||||
short: 'cable car',
|
short: 'cable car',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -62,8 +62,8 @@ const profile = {
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
|
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'ice',
|
id: 'ice',
|
||||||
|
@ -75,7 +75,7 @@ const products = [{
|
||||||
name: 'Autoverlad',
|
name: 'Autoverlad',
|
||||||
short: 'Autoverlad',
|
short: 'Autoverlad',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -89,8 +89,8 @@ const profile = {
|
||||||
radar: true,
|
radar: true,
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
130
p/bvg/index.js
130
p/bvg/index.js
|
@ -1,97 +1,99 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
import {parseHook} from '../../lib/profile-hooks.js'
|
import {parseHook} from '../../lib/profile-hooks.js';
|
||||||
|
|
||||||
import {parseAndAddLocationDHID} from '../vbb/parse-loc-dhid.js'
|
import {parseAndAddLocationDHID} from '../vbb/parse-loc-dhid.js';
|
||||||
|
|
||||||
import {parseLocation as _parseLocation} from '../../parse/location.js'
|
import {parseLocation as _parseLocation} from '../../parse/location.js';
|
||||||
import {parseArrival as _parseArrival} from '../../parse/arrival.js'
|
import {parseArrival as _parseArrival} from '../../parse/arrival.js';
|
||||||
import {parseDeparture as _parseDeparture} from '../../parse/departure.js'
|
import {parseDeparture as _parseDeparture} from '../../parse/departure.js';
|
||||||
import {parseStopover as _parseStopover} from '../../parse/stopover.js'
|
import {parseStopover as _parseStopover} from '../../parse/stopover.js';
|
||||||
import {parseJourneyLeg as _parseJourneyLeg} from '../../parse/journey-leg.js'
|
import {parseJourneyLeg as _parseJourneyLeg} from '../../parse/journey-leg.js';
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
// todo: there's also a referenced icon `{"res":"occup_fig_{low,mid}"}`
|
// todo: there's also a referenced icon `{"res":"occup_fig_{low,mid}"}`
|
||||||
const addOccupancy = (item, occupancyCodes) => {
|
const addOccupancy = (item, occupancyCodes) => {
|
||||||
const remIdx = (item.remarks || [])
|
const remIdx = (item.remarks || [])
|
||||||
.findIndex(r => r.code && occupancyCodes.has(r.code))
|
.findIndex(r => r.code && occupancyCodes.has(r.code));
|
||||||
if (remIdx < 0) return;
|
if (remIdx < 0) {
|
||||||
const rem = item.remarks[remIdx]
|
return;
|
||||||
|
}
|
||||||
|
const rem = item.remarks[remIdx];
|
||||||
|
|
||||||
item.occupancy = occupancyCodes.get(rem.code)
|
item.occupancy = occupancyCodes.get(rem.code);
|
||||||
item.remarks = [
|
item.remarks = [
|
||||||
...item.remarks.slice(0, remIdx),
|
...item.remarks.slice(0, remIdx),
|
||||||
...item.remarks.slice(remIdx + 1),
|
...item.remarks.slice(remIdx + 1),
|
||||||
]
|
];
|
||||||
}
|
};
|
||||||
const stopoverOccupancyCodes = new Map([
|
const stopoverOccupancyCodes = new Map([
|
||||||
['text.occup.loc.max.11', 'low'],
|
['text.occup.loc.max.11', 'low'],
|
||||||
['text.occup.loc.max.12', 'medium'],
|
['text.occup.loc.max.12', 'medium'],
|
||||||
['text.occup.loc.max.13', 'high'],
|
['text.occup.loc.max.13', 'high'],
|
||||||
])
|
]);
|
||||||
const journeyLegOccupancyCodes = new Map([
|
const journeyLegOccupancyCodes = new Map([
|
||||||
['text.occup.jny.max.11', 'low'],
|
['text.occup.jny.max.11', 'low'],
|
||||||
['text.occup.jny.max.12', 'medium'],
|
['text.occup.jny.max.12', 'medium'],
|
||||||
['text.occup.jny.max.13', 'high'],
|
['text.occup.jny.max.13', 'high'],
|
||||||
])
|
]);
|
||||||
|
|
||||||
const parseLocation = ({parsed}, l) => {
|
const parseLocation = ({parsed}, l) => {
|
||||||
parseAndAddLocationDHID(parsed, l)
|
parseAndAddLocationDHID(parsed, l);
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
// todo: S45, S46?
|
// todo: S45, S46?
|
||||||
const ringbahnClockwise = /^ringbahn s\s?41$/i
|
const ringbahnClockwise = /^ringbahn s\s?41$/i;
|
||||||
const ringbahnAnticlockwise = /^ringbahn s\s?42$/i
|
const ringbahnAnticlockwise = /^ringbahn s\s?42$/i;
|
||||||
const parseDepartureRenameRingbahn = ({parsed}, dep) => {
|
const parseDepartureRenameRingbahn = ({parsed}, dep) => {
|
||||||
if (parsed.line && parsed.line.product === 'suburban') {
|
if (parsed.line && parsed.line.product === 'suburban') {
|
||||||
const d = parsed.direction && parsed.direction.trim()
|
const d = parsed.direction && parsed.direction.trim();
|
||||||
if (ringbahnClockwise.test(d)) {
|
if (ringbahnClockwise.test(d)) {
|
||||||
parsed.direction = 'Ringbahn S41 ⟳'
|
parsed.direction = 'Ringbahn S41 ⟳';
|
||||||
} else if (ringbahnAnticlockwise.test(d)) {
|
} else if (ringbahnAnticlockwise.test(d)) {
|
||||||
parsed.direction = 'Ringbahn S42 ⟲'
|
parsed.direction = 'Ringbahn S42 ⟲';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
const parseArrivalRenameRingbahn = ({parsed}, arr) => {
|
const parseArrivalRenameRingbahn = ({parsed}, arr) => {
|
||||||
if (parsed.line && parsed.line.product === 'suburban') {
|
if (parsed.line && parsed.line.product === 'suburban') {
|
||||||
const p = parsed.provenance && parsed.provenance.trim()
|
const p = parsed.provenance && parsed.provenance.trim();
|
||||||
if (ringbahnClockwise.test(p)) {
|
if (ringbahnClockwise.test(p)) {
|
||||||
parsed.provenance = 'Ringbahn S41 ⟳'
|
parsed.provenance = 'Ringbahn S41 ⟳';
|
||||||
} else if (ringbahnAnticlockwise.test(p)) {
|
} else if (ringbahnAnticlockwise.test(p)) {
|
||||||
parsed.provenance = 'Ringbahn S42 ⟲'
|
parsed.provenance = 'Ringbahn S42 ⟲';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const parseArrDepWithOccupancy = ({parsed}, d) => {
|
const parseArrDepWithOccupancy = ({parsed}, d) => {
|
||||||
addOccupancy(parsed, stopoverOccupancyCodes)
|
addOccupancy(parsed, stopoverOccupancyCodes);
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const parseStopoverWithOccupancy = ({parsed}, st, date) => {
|
const parseStopoverWithOccupancy = ({parsed}, st, date) => {
|
||||||
addOccupancy(parsed, stopoverOccupancyCodes)
|
addOccupancy(parsed, stopoverOccupancyCodes);
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const parseJourneyLegWithBerlkönig = (ctx, leg, date) => {
|
const parseJourneyLegWithBerlkönig = (ctx, leg, date) => {
|
||||||
if (leg.type === 'KISS') {
|
if (leg.type === 'KISS') {
|
||||||
const icon = ctx.common.icons[leg.icoX]
|
const icon = ctx.common.icons[leg.icoX];
|
||||||
if (icon && icon.type === 'prod_berl') {
|
if (icon && icon.type === 'prod_berl') {
|
||||||
const res = _parseJourneyLeg(ctx, {
|
const res = _parseJourneyLeg(ctx, {
|
||||||
...leg, type: 'WALK'
|
...leg, type: 'WALK',
|
||||||
}, date)
|
}, date);
|
||||||
delete res.walking
|
delete res.walking;
|
||||||
|
|
||||||
const mcp = leg.dep.mcp || {}
|
const mcp = leg.dep.mcp || {};
|
||||||
const mcpData = mcp.mcpData || {}
|
const mcpData = mcp.mcpData || {};
|
||||||
// todo: mcp.lid
|
// todo: mcp.lid
|
||||||
// todo: mcpData.occupancy, mcpData.type
|
// todo: mcpData.occupancy, mcpData.type
|
||||||
// todo: journey.trfRes.bkgData
|
// todo: journey.trfRes.bkgData
|
||||||
|
@ -102,33 +104,35 @@ const parseJourneyLegWithBerlkönig = (ctx, leg, date) => {
|
||||||
name: mcpData.providerName,
|
name: mcpData.providerName,
|
||||||
public: true,
|
public: true,
|
||||||
mode: 'taxi',
|
mode: 'taxi',
|
||||||
product: 'berlkoenig'
|
product: 'berlkoenig',
|
||||||
// todo: operator
|
// todo: operator
|
||||||
}
|
};
|
||||||
return res
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _parseJourneyLeg(ctx, leg, date)
|
return _parseJourneyLeg(ctx, leg, date);
|
||||||
}
|
};
|
||||||
const parseJourneyLegWithOccupancy = ({parsed}, leg, date) => {
|
const parseJourneyLegWithOccupancy = ({parsed}, leg, date) => {
|
||||||
if (leg.type === 'JNY') {
|
if (leg.type === 'JNY') {
|
||||||
addOccupancy(parsed, journeyLegOccupancyCodes)
|
addOccupancy(parsed, journeyLegOccupancyCodes);
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
}
|
||||||
|
return parsed;
|
||||||
|
};
|
||||||
|
|
||||||
// use the Berlkönig ride sharing service?
|
// use the Berlkönig ride sharing service?
|
||||||
// todo: https://github.com/alexander-albers/tripkit/issues/26#issuecomment-825437320
|
// todo: https://github.com/alexander-albers/tripkit/issues/26#issuecomment-825437320
|
||||||
const requestJourneysWithBerlkoenig = ({opt}, query) => {
|
const requestJourneysWithBerlkoenig = ({opt}, query) => {
|
||||||
if (('numF' in query) && opt.berlkoenig) {
|
if ('numF' in query && opt.berlkoenig) {
|
||||||
// todo: check if this is still true
|
// todo: check if this is still true
|
||||||
throw new Error('The `berlkoenig` and `results` options are mutually exclusive.')
|
throw new Error('The `berlkoenig` and `results` options are mutually exclusive.');
|
||||||
}
|
}
|
||||||
query.jnyFltrL.push({type: 'GROUP', mode: 'INC', value: 'OEV'})
|
query.jnyFltrL.push({type: 'GROUP', mode: 'INC', value: 'OEV'});
|
||||||
if (opt.berlkoenig) query.jnyFltrL.push({type: 'GROUP', mode: 'INC', value: 'BERLKOENIG'})
|
if (opt.berlkoenig) {
|
||||||
query.gisFltrL = [{meta: 'foot_speed_normal', type: 'M', mode: 'FB'}]
|
query.jnyFltrL.push({type: 'GROUP', mode: 'INC', value: 'BERLKOENIG'});
|
||||||
return query
|
|
||||||
}
|
}
|
||||||
|
query.gisFltrL = [{meta: 'foot_speed_normal', type: 'M', mode: 'FB'}];
|
||||||
|
return query;
|
||||||
|
};
|
||||||
|
|
||||||
// todo: adapt/extend `vbb-parse-ticket` to support the BVG markup
|
// todo: adapt/extend `vbb-parse-ticket` to support the BVG markup
|
||||||
|
|
||||||
|
@ -160,9 +164,9 @@ const profile = {
|
||||||
trip: true,
|
trip: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
refreshJourney: true,
|
refreshJourney: true,
|
||||||
reachableFrom: true
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'subway',
|
id: 'subway',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'T',
|
short: 'T',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'B',
|
short: 'B',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ferry',
|
id: 'ferry',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'Fähre',
|
name: 'Fähre',
|
||||||
short: 'F',
|
short: 'F',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'express',
|
id: 'express',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'IC/ICE',
|
name: 'IC/ICE',
|
||||||
short: 'E',
|
short: 'E',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional',
|
id: 'regional',
|
||||||
|
@ -53,10 +53,10 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'RB/RE',
|
name: 'RB/RE',
|
||||||
short: 'R',
|
short: 'R',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -19,8 +19,8 @@ const profile = {
|
||||||
radar: true,
|
radar: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
remarksGetPolyline: false,
|
remarksGetPolyline: false,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@ const products = [
|
||||||
bitmasks: [1, 2],
|
bitmasks: [1, 2],
|
||||||
name: 'TGV, ICE, EuroCity',
|
name: 'TGV, ICE, EuroCity',
|
||||||
short: 'TGV/ICE/EC',
|
short: 'TGV/ICE/EC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'local-train',
|
id: 'local-train',
|
||||||
|
@ -14,7 +14,7 @@ const products = [
|
||||||
bitmasks: [8, 16],
|
bitmasks: [8, 16],
|
||||||
name: 'local trains',
|
name: 'local trains',
|
||||||
short: 'local',
|
short: 'local',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -22,7 +22,7 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'tram',
|
name: 'tram',
|
||||||
short: 'tram',
|
short: 'tram',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -30,7 +30,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'bus',
|
name: 'bus',
|
||||||
short: 'bus',
|
short: 'bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gondola',
|
id: 'gondola',
|
||||||
|
@ -38,10 +38,10 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'Fun', // taken from the horaires.cfl.lu website
|
name: 'Fun', // taken from the horaires.cfl.lu website
|
||||||
short: 'Fun', // abbreviation for funicular?
|
short: 'Fun', // abbreviation for funicular?
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -19,8 +19,8 @@ const profile = {
|
||||||
refreshJourney: true,
|
refreshJourney: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
remarks: true, // `.svcResL[0].res.msgL[]` is missing though 🤔
|
remarks: true, // `.svcResL[0].res.msgL[]` is missing though 🤔
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'MetroBus',
|
name: 'MetroBus',
|
||||||
short: 'B',
|
short: 'B',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'rapid',
|
id: 'rapid',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [4096],
|
bitmasks: [4096],
|
||||||
name: 'MetroRapid',
|
name: 'MetroRapid',
|
||||||
short: 'R',
|
short: 'R',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'rail',
|
id: 'rail',
|
||||||
|
@ -21,10 +21,10 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'MetroRail',
|
name: 'MetroRail',
|
||||||
short: 'M',
|
short: 'M',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -12,7 +12,7 @@ const products = [{
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -25,8 +25,8 @@ const profile = {
|
||||||
trip: true,
|
trip: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
// DB Busradar NRW app does not allow selecting specific modes of transport to filter results,
|
// DB Busradar NRW app does not allow selecting specific modes of transport to filter results,
|
||||||
// so the bitmasks had to be determined by querying some stations and looking at the results..
|
// so the bitmasks had to be determined by querying some stations and looking at the results..
|
||||||
|
@ -14,7 +14,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'InterCityExpress',
|
name: 'InterCityExpress',
|
||||||
short: 'ICE',
|
short: 'ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'national',
|
id: 'national',
|
||||||
|
@ -22,7 +22,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'InterCity & EuroCity',
|
name: 'InterCity & EuroCity',
|
||||||
short: 'IC/EC',
|
short: 'IC/EC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
// todo: not always true when a station has RE stopping at it
|
// todo: not always true when a station has RE stopping at it
|
||||||
// maybe something else?
|
// maybe something else?
|
||||||
|
@ -32,7 +32,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'Regionalexpress',
|
name: 'Regionalexpress',
|
||||||
short: 'RE',
|
short: 'RE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
// todo: also used for replacement service incl. S-Bahn replacement
|
// todo: also used for replacement service incl. S-Bahn replacement
|
||||||
{
|
{
|
||||||
|
@ -41,7 +41,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Regionalzug',
|
name: 'Regionalzug',
|
||||||
short: 'RB/RE',
|
short: 'RB/RE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'suburban',
|
id: 'suburban',
|
||||||
|
@ -49,7 +49,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -57,7 +57,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ferry',
|
id: 'ferry',
|
||||||
|
@ -65,7 +65,7 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'Ferry',
|
name: 'Ferry',
|
||||||
short: 'F',
|
short: 'F',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
// todo: are `128` & `256` unused?
|
// todo: are `128` & `256` unused?
|
||||||
{
|
{
|
||||||
|
@ -74,9 +74,9 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'AnrufSammelTaxi',
|
name: 'AnrufSammelTaxi',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -91,8 +91,8 @@ const profile = {
|
||||||
radar: true,
|
radar: true,
|
||||||
remarks: true, // `.svcResL[0].res.msgL[]` is missing though 🤔
|
remarks: true, // `.svcResL[0].res.msgL[]` is missing though 🤔
|
||||||
lines: false, // `.svcResL[0].res.lineL[]` is missing 🤔
|
lines: false, // `.svcResL[0].res.lineL[]` is missing 🤔
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -9,26 +9,31 @@ const ageGroup = {
|
||||||
CHILD: 15,
|
CHILD: 15,
|
||||||
YOUNG: 27,
|
YOUNG: 27,
|
||||||
ADULT: 65,
|
ADULT: 65,
|
||||||
SENIOR: Infinity
|
SENIOR: Infinity,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const ageGroupFromAge = (age) => {
|
const ageGroupFromAge = (age) => {
|
||||||
const {upperBoundOf} = ageGroup
|
const {upperBoundOf} = ageGroup;
|
||||||
if (age < upperBoundOf.BABY)
|
if (age < upperBoundOf.BABY) {
|
||||||
return ageGroup.BABY
|
return ageGroup.BABY;
|
||||||
if (age < upperBoundOf.CHILD)
|
|
||||||
return ageGroup.CHILD
|
|
||||||
if (age < upperBoundOf.YOUNG)
|
|
||||||
return ageGroup.YOUNG
|
|
||||||
if (age < upperBoundOf.ADULT)
|
|
||||||
return ageGroup.ADULT
|
|
||||||
if (age < upperBoundOf.SENIOR)
|
|
||||||
return ageGroup.SENIOR
|
|
||||||
throw new TypeError(`Invalid age '${age}'`)
|
|
||||||
}
|
}
|
||||||
|
if (age < upperBoundOf.CHILD) {
|
||||||
|
return ageGroup.CHILD;
|
||||||
|
}
|
||||||
|
if (age < upperBoundOf.YOUNG) {
|
||||||
|
return ageGroup.YOUNG;
|
||||||
|
}
|
||||||
|
if (age < upperBoundOf.ADULT) {
|
||||||
|
return ageGroup.ADULT;
|
||||||
|
}
|
||||||
|
if (age < upperBoundOf.SENIOR) {
|
||||||
|
return ageGroup.SENIOR;
|
||||||
|
}
|
||||||
|
throw new TypeError(`Invalid age '${age}'`);
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ageGroup,
|
ageGroup,
|
||||||
ageGroupFromAge,
|
ageGroupFromAge,
|
||||||
}
|
};
|
||||||
|
|
377
p/db/index.js
377
p/db/index.js
|
@ -1,70 +1,72 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
import trim from 'lodash/trim.js'
|
import trim from 'lodash/trim.js';
|
||||||
import uniqBy from 'lodash/uniqBy.js'
|
import uniqBy from 'lodash/uniqBy.js';
|
||||||
import slugg from 'slugg'
|
import slugg from 'slugg';
|
||||||
import without from 'lodash/without.js'
|
import without from 'lodash/without.js';
|
||||||
import {parseHook} from '../../lib/profile-hooks.js'
|
import {parseHook} from '../../lib/profile-hooks.js';
|
||||||
|
|
||||||
import {parseJourney as _parseJourney} from '../../parse/journey.js'
|
import {parseJourney as _parseJourney} from '../../parse/journey.js';
|
||||||
import {parseJourneyLeg as _parseJourneyLeg} from '../../parse/journey-leg.js'
|
import {parseJourneyLeg as _parseJourneyLeg} from '../../parse/journey-leg.js';
|
||||||
import {parseLine as _parseLine} from '../../parse/line.js'
|
import {parseLine as _parseLine} from '../../parse/line.js';
|
||||||
import {parseArrival as _parseArrival} from '../../parse/arrival.js'
|
import {parseArrival as _parseArrival} from '../../parse/arrival.js';
|
||||||
import {parseDeparture as _parseDeparture} from '../../parse/departure.js'
|
import {parseDeparture as _parseDeparture} from '../../parse/departure.js';
|
||||||
import {parseHint as _parseHint} from '../../parse/hint.js'
|
import {parseHint as _parseHint} from '../../parse/hint.js';
|
||||||
import {parseLocation as _parseLocation} from '../../parse/location.js'
|
import {parseLocation as _parseLocation} from '../../parse/location.js';
|
||||||
import {formatStation as _formatStation} from '../../format/station.js'
|
import {formatStation as _formatStation} from '../../format/station.js';
|
||||||
import {bike} from '../../format/filters.js'
|
import {bike} from '../../format/filters.js';
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
import {formatLoyaltyCard} from './loyalty-cards.js'
|
import {formatLoyaltyCard} from './loyalty-cards.js';
|
||||||
import {ageGroup, ageGroupFromAge} from './ageGroup.js'
|
import {ageGroup, ageGroupFromAge} from './ageGroup.js';
|
||||||
import {routingModes} from './routing-modes.js'
|
import {routingModes} from './routing-modes.js';
|
||||||
|
|
||||||
const transformReqBody = (ctx, body) => {
|
const transformReqBody = (ctx, body) => {
|
||||||
const req = body.svcReqL[0] || {}
|
const req = body.svcReqL[0] || {};
|
||||||
|
|
||||||
// see https://pastebin.com/qZ9WS3Cx
|
// see https://pastebin.com/qZ9WS3Cx
|
||||||
const rtMode = ('routingMode' in ctx.opt) ? ctx.opt.routingMode : routingModes.REALTIME
|
const rtMode = 'routingMode' in ctx.opt
|
||||||
|
? ctx.opt.routingMode
|
||||||
|
: routingModes.REALTIME;
|
||||||
|
|
||||||
req.cfg = {
|
req.cfg = {
|
||||||
...req.cfg,
|
...req.cfg,
|
||||||
rtMode,
|
rtMode,
|
||||||
}
|
};
|
||||||
|
|
||||||
return body
|
return body;
|
||||||
}
|
};
|
||||||
|
|
||||||
const transformReq = (ctx, req) => {
|
const transformReq = (ctx, req) => {
|
||||||
const body = JSON.parse(req.body)
|
const body = JSON.parse(req.body);
|
||||||
// stop() a.k.a. LocDetails seems broken with ver >1.16, all other methods work
|
// stop() a.k.a. LocDetails seems broken with ver >1.16, all other methods work
|
||||||
if (body.svcReqL[0].meth === 'LocDetails') {
|
if (body.svcReqL[0].meth === 'LocDetails') {
|
||||||
req.body = JSON.stringify({
|
req.body = JSON.stringify({
|
||||||
...body,
|
...body,
|
||||||
ver: '1.16',
|
ver: '1.16',
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return req
|
return req;
|
||||||
}
|
};
|
||||||
|
|
||||||
const slices = (n, arr) => {
|
const slices = (n, arr) => {
|
||||||
const initialState = {slices: [], count: Infinity}
|
const initialState = {slices: [], count: Infinity};
|
||||||
return arr.reduce(({slices, count}, item) => {
|
return arr.reduce(({slices, count}, item) => {
|
||||||
if (count >= n) {
|
if (count >= n) {
|
||||||
slices.push([item])
|
slices.push([item]);
|
||||||
count = 1
|
count = 1;
|
||||||
} else {
|
} else {
|
||||||
slices[slices.length - 1].push(item)
|
slices[slices.length - 1].push(item);
|
||||||
count++
|
count++;
|
||||||
}
|
|
||||||
return {slices, count}
|
|
||||||
}, initialState).slices
|
|
||||||
}
|
}
|
||||||
|
return {slices, count};
|
||||||
|
}, initialState).slices;
|
||||||
|
};
|
||||||
|
|
||||||
const parseGrid = (g) => {
|
const parseGrid = (g) => {
|
||||||
// todo: g.type, e.g. `S`
|
// todo: g.type, e.g. `S`
|
||||||
|
@ -78,13 +80,12 @@ const parseGrid = (g) => {
|
||||||
// iterative process.
|
// iterative process.
|
||||||
return {
|
return {
|
||||||
title: g.title,
|
title: g.title,
|
||||||
rows: slices(g.nCols, g.itemL.map(item => (
|
rows: slices(g.nCols, g.itemL.map(item => Array.isArray(item.hints) && item.hints[0]
|
||||||
Array.isArray(item.hints) && item.hints[0] ||
|
|| Array.isArray(item.remarkRefs) && item.remarkRefs[0] && item.remarkRefs[0].hint
|
||||||
Array.isArray(item.remarkRefs) && item.remarkRefs[0] && item.remarkRefs[0].hint ||
|
|| {},
|
||||||
{}
|
)),
|
||||||
))),
|
};
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const ausstattungKeys = Object.assign(Object.create(null), {
|
const ausstattungKeys = Object.assign(Object.create(null), {
|
||||||
'3-s-zentrale': '3SZentrale',
|
'3-s-zentrale': '3SZentrale',
|
||||||
|
@ -96,115 +97,142 @@ const ausstattungKeys = Object.assign(Object.create(null), {
|
||||||
'reisebedarf': 'travelShop',
|
'reisebedarf': 'travelShop',
|
||||||
'stufenfreier-zugang': 'stepFreeAccess',
|
'stufenfreier-zugang': 'stepFreeAccess',
|
||||||
'ein-umsteigehilfe': 'boardingAid',
|
'ein-umsteigehilfe': 'boardingAid',
|
||||||
'taxi-am-bahnhof': 'taxis'
|
'taxi-am-bahnhof': 'taxis',
|
||||||
})
|
});
|
||||||
const parseAusstattungVal = (val) => {
|
const parseAusstattungVal = (val) => {
|
||||||
val = val.toLowerCase()
|
val = val.toLowerCase();
|
||||||
return val === 'ja' ? true : (val === 'nein' ? false : val)
|
return val === 'ja'
|
||||||
}
|
? true
|
||||||
|
: val === 'nein'
|
||||||
|
? false
|
||||||
|
: val;
|
||||||
|
};
|
||||||
|
|
||||||
const parseAusstattungGrid = (g) => {
|
const parseAusstattungGrid = (g) => {
|
||||||
// filter duplicate hint rows
|
// filter duplicate hint rows
|
||||||
const rows = uniqBy(g.rows, ([key, val]) => key + ':' + val)
|
const rows = uniqBy(g.rows, ([key, val]) => key + ':' + val);
|
||||||
|
|
||||||
const res = {}
|
const res = {};
|
||||||
Object.defineProperty(res, 'raw', {value: rows})
|
Object.defineProperty(res, 'raw', {value: rows});
|
||||||
for (let [key, val] of rows) {
|
for (let [key, val] of rows) {
|
||||||
key = ausstattungKeys[slugg(key)]
|
key = ausstattungKeys[slugg(key)];
|
||||||
if (key) res[key] = parseAusstattungVal(val)
|
if (key) {
|
||||||
|
res[key] = parseAusstattungVal(val);
|
||||||
}
|
}
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
const parseReisezentrumÖffnungszeiten = (g) => {
|
const parseReisezentrumÖffnungszeiten = (g) => {
|
||||||
const res = {}
|
const res = {};
|
||||||
for (const [dayOfWeek, val] of g.rows) res[dayOfWeek] = val
|
for (const [dayOfWeek, val] of g.rows) {
|
||||||
res.raw = g.rows
|
res[dayOfWeek] = val;
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
res.raw = g.rows;
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
const parseLocWithDetails = ({parsed, common}, l) => {
|
const parseLocWithDetails = ({parsed, common}, l) => {
|
||||||
if (!parsed) return parsed
|
if (!parsed) {
|
||||||
if (parsed.type !== 'stop' && parsed.type !== 'station') return parsed
|
return parsed;
|
||||||
|
}
|
||||||
|
if (parsed.type !== 'stop' && parsed.type !== 'station') {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
if (Array.isArray(l.gridL)) {
|
if (Array.isArray(l.gridL)) {
|
||||||
const resolveCells = grid => ({
|
const resolveCells = grid => ({
|
||||||
...grid,
|
...grid,
|
||||||
rows: grid.rows.map(row => row.map(cell => cell && cell.text)),
|
rows: grid.rows.map(row => row.map(cell => cell && cell.text)),
|
||||||
})
|
});
|
||||||
|
|
||||||
let grids = l.gridL
|
let grids = l.gridL
|
||||||
.map(grid => parseGrid(grid, common))
|
.map(grid => parseGrid(grid, common))
|
||||||
.map(resolveCells)
|
.map(resolveCells);
|
||||||
|
|
||||||
const ausstattung = grids.find(g => slugg(g.title) === 'ausstattung')
|
const ausstattung = grids.find(g => slugg(g.title) === 'ausstattung');
|
||||||
if (ausstattung) {
|
if (ausstattung) {
|
||||||
parsed.facilities = parseAusstattungGrid(ausstattung)
|
parsed.facilities = parseAusstattungGrid(ausstattung);
|
||||||
}
|
}
|
||||||
const öffnungszeiten = grids.find(g => slugg(g.title) === 'offnungszeiten-reisezentrum')
|
const öffnungszeiten = grids.find(g => slugg(g.title) === 'offnungszeiten-reisezentrum');
|
||||||
if (öffnungszeiten) {
|
if (öffnungszeiten) {
|
||||||
parsed.reisezentrumOpeningHours = parseReisezentrumÖffnungszeiten(öffnungszeiten)
|
parsed.reisezentrumOpeningHours = parseReisezentrumÖffnungszeiten(öffnungszeiten);
|
||||||
}
|
}
|
||||||
|
|
||||||
grids = without(grids, ausstattung, öffnungszeiten)
|
grids = without(grids, ausstattung, öffnungszeiten);
|
||||||
if (grids.length > 0) parsed.grids = grids
|
if (grids.length > 0) {
|
||||||
|
parsed.grids = grids;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
// https://www.bahn.de/p/view/service/buchung/auslastungsinformation.shtml
|
// https://www.bahn.de/p/view/service/buchung/auslastungsinformation.shtml
|
||||||
const loadFactors = []
|
const loadFactors = [];
|
||||||
loadFactors[1] = 'low-to-medium'
|
loadFactors[1] = 'low-to-medium';
|
||||||
loadFactors[2] = 'high'
|
loadFactors[2] = 'high';
|
||||||
loadFactors[3] = 'very-high'
|
loadFactors[3] = 'very-high';
|
||||||
loadFactors[4] = 'exceptionally-high'
|
loadFactors[4] = 'exceptionally-high';
|
||||||
|
|
||||||
const parseLoadFactor = (opt, tcocL, tcocX) => {
|
const parseLoadFactor = (opt, tcocL, tcocX) => {
|
||||||
const cls = opt.firstClass ? 'FIRST' : 'SECOND'
|
const cls = opt.firstClass
|
||||||
const load = tcocX.map(i => tcocL[i]).find(lf => lf.c === cls)
|
? 'FIRST'
|
||||||
return load && loadFactors[load.r] || null
|
: 'SECOND';
|
||||||
}
|
const load = tcocX.map(i => tcocL[i])
|
||||||
|
.find(lf => lf.c === cls);
|
||||||
|
return load && loadFactors[load.r] || null;
|
||||||
|
};
|
||||||
|
|
||||||
const parseArrOrDepWithLoadFactor = ({parsed, res, opt}, d) => {
|
const parseArrOrDepWithLoadFactor = ({parsed, res, opt}, d) => {
|
||||||
if (d.stbStop.dTrnCmpSX && Array.isArray(d.stbStop.dTrnCmpSX.tcocX)) {
|
if (d.stbStop.dTrnCmpSX && Array.isArray(d.stbStop.dTrnCmpSX.tcocX)) {
|
||||||
const load = parseLoadFactor(opt, res.common.tcocL || [], d.stbStop.dTrnCmpSX.tcocX)
|
const load = parseLoadFactor(opt, res.common.tcocL || [], d.stbStop.dTrnCmpSX.tcocX);
|
||||||
if (load) parsed.loadFactor = load
|
if (load) {
|
||||||
|
parsed.loadFactor = load;
|
||||||
}
|
}
|
||||||
return parsed
|
|
||||||
}
|
}
|
||||||
|
return parsed;
|
||||||
|
};
|
||||||
|
|
||||||
const transformJourneysQuery = ({opt}, query) => {
|
const transformJourneysQuery = ({opt}, query) => {
|
||||||
const filters = query.jnyFltrL
|
const filters = query.jnyFltrL;
|
||||||
if (opt.bike) filters.push(bike)
|
if (opt.bike) {
|
||||||
|
filters.push(bike);
|
||||||
if (('age' in opt) && ('ageGroup' in opt)) {
|
|
||||||
throw new TypeError(`\
|
|
||||||
opt.age and opt.ageGroup are mutually exclusive.
|
|
||||||
Pass in just opt.age, and the age group will calculated automatically.`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const tvlrAgeGroup = ('age' in opt) ? ageGroupFromAge(opt.age) : opt.ageGroup
|
if ('age' in opt && 'ageGroup' in opt) {
|
||||||
|
throw new TypeError(`\
|
||||||
|
opt.age and opt.ageGroup are mutually exclusive.
|
||||||
|
Pass in just opt.age, and the age group will calculated automatically.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tvlrAgeGroup = 'age' in opt
|
||||||
|
? ageGroupFromAge(opt.age)
|
||||||
|
: opt.ageGroup;
|
||||||
|
|
||||||
query.trfReq = {
|
query.trfReq = {
|
||||||
// todo: what are these?
|
// todo: what are these?
|
||||||
// "directESuiteCall": true,
|
// "directESuiteCall": true,
|
||||||
// "rType": "DB-PE",
|
// "rType": "DB-PE",
|
||||||
|
|
||||||
jnyCl: opt.firstClass === true ? 1 : 2,
|
jnyCl: opt.firstClass === true
|
||||||
|
? 1
|
||||||
|
: 2,
|
||||||
// todo [breaking]: support multiple travelers
|
// todo [breaking]: support multiple travelers
|
||||||
tvlrProf: [{
|
tvlrProf: [{
|
||||||
type: tvlrAgeGroup || ageGroup.ADULT,
|
type: tvlrAgeGroup || ageGroup.ADULT,
|
||||||
...(('age' in opt) ? {age: opt.age} : {}),
|
...'age' in opt
|
||||||
|
? {age: opt.age}
|
||||||
|
: {},
|
||||||
redtnCard: opt.loyaltyCard
|
redtnCard: opt.loyaltyCard
|
||||||
? formatLoyaltyCard(opt.loyaltyCard)
|
? formatLoyaltyCard(opt.loyaltyCard)
|
||||||
: null
|
: null,
|
||||||
}],
|
}],
|
||||||
cType: 'PK'
|
cType: 'PK',
|
||||||
}
|
};
|
||||||
|
|
||||||
return query
|
return query;
|
||||||
}
|
};
|
||||||
|
|
||||||
// todo: fix this
|
// todo: fix this
|
||||||
// line: {
|
// line: {
|
||||||
|
@ -219,19 +247,19 @@ Pass in just opt.age, and the age group will calculated automatically.`)
|
||||||
// }
|
// }
|
||||||
const parseLineWithAdditionalName = ({parsed}, l) => {
|
const parseLineWithAdditionalName = ({parsed}, l) => {
|
||||||
if (l.nameS && ['bus', 'tram', 'ferry'].includes(l.product)) {
|
if (l.nameS && ['bus', 'tram', 'ferry'].includes(l.product)) {
|
||||||
parsed.name = l.nameS
|
parsed.name = l.nameS;
|
||||||
}
|
}
|
||||||
if (l.addName) {
|
if (l.addName) {
|
||||||
parsed.additionalName = parsed.name
|
parsed.additionalName = parsed.name;
|
||||||
parsed.name = l.addName
|
parsed.name = l.addName;
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
}
|
||||||
|
return parsed;
|
||||||
|
};
|
||||||
|
|
||||||
// todo: sotRating, conSubscr, isSotCon, showARSLink, sotCtxt
|
// todo: sotRating, conSubscr, isSotCon, showARSLink, sotCtxt
|
||||||
// todo: conSubscr, showARSLink, useableTime
|
// todo: conSubscr, showARSLink, useableTime
|
||||||
const parseJourneyWithPrice = ({parsed}, raw) => {
|
const parseJourneyWithPrice = ({parsed}, raw) => {
|
||||||
parsed.price = null
|
parsed.price = null;
|
||||||
// todo: find cheapest, find discounts
|
// todo: find cheapest, find discounts
|
||||||
// todo: write a parser like vbb-parse-ticket
|
// todo: write a parser like vbb-parse-ticket
|
||||||
// {
|
// {
|
||||||
|
@ -274,33 +302,35 @@ const parseJourneyWithPrice = ({parsed}, raw) => {
|
||||||
// }
|
// }
|
||||||
// ]
|
// ]
|
||||||
if (
|
if (
|
||||||
raw.trfRes &&
|
raw.trfRes
|
||||||
Array.isArray(raw.trfRes.fareSetL) &&
|
&& Array.isArray(raw.trfRes.fareSetL)
|
||||||
raw.trfRes.fareSetL[0] &&
|
&& raw.trfRes.fareSetL[0]
|
||||||
Array.isArray(raw.trfRes.fareSetL[0].fareL) &&
|
&& Array.isArray(raw.trfRes.fareSetL[0].fareL)
|
||||||
raw.trfRes.fareSetL[0].fareL[0]
|
&& raw.trfRes.fareSetL[0].fareL[0]
|
||||||
) {
|
) {
|
||||||
const tariff = raw.trfRes.fareSetL[0].fareL[0]
|
const tariff = raw.trfRes.fareSetL[0].fareL[0];
|
||||||
if (tariff.price && tariff.price.amount >= 0) { // wat
|
if (tariff.price && tariff.price.amount >= 0) { // wat
|
||||||
parsed.price = {
|
parsed.price = {
|
||||||
amount: tariff.price.amount / 100,
|
amount: tariff.price.amount / 100,
|
||||||
currency: 'EUR',
|
currency: 'EUR',
|
||||||
hint: null
|
hint: null,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const parseJourneyLegWithLoadFactor = ({parsed, res, opt}, raw) => {
|
const parseJourneyLegWithLoadFactor = ({parsed, res, opt}, raw) => {
|
||||||
const tcocX = raw.jny && raw.jny.dTrnCmpSX && raw.jny.dTrnCmpSX.tcocX
|
const tcocX = raw.jny && raw.jny.dTrnCmpSX && raw.jny.dTrnCmpSX.tcocX;
|
||||||
if (Array.isArray(tcocX) && Array.isArray(res.common.tcocL)) {
|
if (Array.isArray(tcocX) && Array.isArray(res.common.tcocL)) {
|
||||||
const load = parseLoadFactor(opt, res.common.tcocL, tcocX)
|
const load = parseLoadFactor(opt, res.common.tcocL, tcocX);
|
||||||
if (load) parsed.loadFactor = load
|
if (load) {
|
||||||
|
parsed.loadFactor = load;
|
||||||
}
|
}
|
||||||
return parsed
|
|
||||||
}
|
}
|
||||||
|
return parsed;
|
||||||
|
};
|
||||||
|
|
||||||
// todo:
|
// todo:
|
||||||
// [ { type: 'hint',
|
// [ { type: 'hint',
|
||||||
|
@ -310,189 +340,189 @@ const hintsByCode = Object.assign(Object.create(null), {
|
||||||
fb: {
|
fb: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'bicycle-conveyance',
|
code: 'bicycle-conveyance',
|
||||||
summary: 'bicycles conveyed'
|
summary: 'bicycles conveyed',
|
||||||
},
|
},
|
||||||
fr: {
|
fr: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'bicycle-conveyance-reservation',
|
code: 'bicycle-conveyance-reservation',
|
||||||
summary: 'bicycles conveyed, subject to reservation'
|
summary: 'bicycles conveyed, subject to reservation',
|
||||||
},
|
},
|
||||||
nf: {
|
nf: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'no-bicycle-conveyance',
|
code: 'no-bicycle-conveyance',
|
||||||
summary: 'bicycles not conveyed'
|
summary: 'bicycles not conveyed',
|
||||||
},
|
},
|
||||||
k2: {
|
k2: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: '2nd-class-only',
|
code: '2nd-class-only',
|
||||||
summary: '2. class only'
|
summary: '2. class only',
|
||||||
},
|
},
|
||||||
eh: {
|
eh: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'boarding-ramp',
|
code: 'boarding-ramp',
|
||||||
summary: 'vehicle-mounted boarding ramp available'
|
summary: 'vehicle-mounted boarding ramp available',
|
||||||
},
|
},
|
||||||
ro: {
|
ro: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'wheelchairs-space',
|
code: 'wheelchairs-space',
|
||||||
summary: 'space for wheelchairs'
|
summary: 'space for wheelchairs',
|
||||||
},
|
},
|
||||||
oa: {
|
oa: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'wheelchairs-space-reservation',
|
code: 'wheelchairs-space-reservation',
|
||||||
summary: 'space for wheelchairs, subject to reservation'
|
summary: 'space for wheelchairs, subject to reservation',
|
||||||
},
|
},
|
||||||
wv: {
|
wv: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'wifi',
|
code: 'wifi',
|
||||||
summary: 'WiFi available'
|
summary: 'WiFi available',
|
||||||
},
|
},
|
||||||
wi: {
|
wi: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'wifi',
|
code: 'wifi',
|
||||||
summary: 'WiFi available'
|
summary: 'WiFi available',
|
||||||
},
|
},
|
||||||
sn: {
|
sn: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'snacks',
|
code: 'snacks',
|
||||||
summary: 'snacks available for purchase'
|
summary: 'snacks available for purchase',
|
||||||
},
|
},
|
||||||
mb: {
|
mb: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'snacks',
|
code: 'snacks',
|
||||||
summary: 'snacks available for purchase'
|
summary: 'snacks available for purchase',
|
||||||
},
|
},
|
||||||
mp: {
|
mp: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'snacks',
|
code: 'snacks',
|
||||||
summary: 'snacks available for purchase at the seat'
|
summary: 'snacks available for purchase at the seat',
|
||||||
},
|
},
|
||||||
bf: {
|
bf: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'barrier-free',
|
code: 'barrier-free',
|
||||||
summary: 'barrier-free'
|
summary: 'barrier-free',
|
||||||
},
|
},
|
||||||
rg: {
|
rg: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'barrier-free-vehicle',
|
code: 'barrier-free-vehicle',
|
||||||
summary: 'barrier-free vehicle'
|
summary: 'barrier-free vehicle',
|
||||||
},
|
},
|
||||||
bt: {
|
bt: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'on-board-bistro',
|
code: 'on-board-bistro',
|
||||||
summary: 'Bordbistro available'
|
summary: 'Bordbistro available',
|
||||||
},
|
},
|
||||||
br: {
|
br: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'on-board-restaurant',
|
code: 'on-board-restaurant',
|
||||||
summary: 'Bordrestaurant available'
|
summary: 'Bordrestaurant available',
|
||||||
},
|
},
|
||||||
ki: {
|
ki: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'childrens-area',
|
code: 'childrens-area',
|
||||||
summary: `children's area available`
|
summary: 'children\'s area available',
|
||||||
},
|
},
|
||||||
kk: {
|
kk: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'parents-childrens-compartment',
|
code: 'parents-childrens-compartment',
|
||||||
summary: `parent-and-children compartment available`
|
summary: 'parent-and-children compartment available',
|
||||||
},
|
},
|
||||||
kr: {
|
kr: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'kids-service',
|
code: 'kids-service',
|
||||||
summary: 'DB Kids Service available'
|
summary: 'DB Kids Service available',
|
||||||
},
|
},
|
||||||
ls: {
|
ls: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'power-sockets',
|
code: 'power-sockets',
|
||||||
summary: 'power sockets available'
|
summary: 'power sockets available',
|
||||||
},
|
},
|
||||||
ev: {
|
ev: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'replacement-service',
|
code: 'replacement-service',
|
||||||
summary: 'replacement service'
|
summary: 'replacement service',
|
||||||
},
|
},
|
||||||
kl: {
|
kl: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'air-conditioned',
|
code: 'air-conditioned',
|
||||||
summary: 'air-conditioned vehicle'
|
summary: 'air-conditioned vehicle',
|
||||||
},
|
},
|
||||||
r0: {
|
r0: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'upward-escalator',
|
code: 'upward-escalator',
|
||||||
summary: 'upward escalator'
|
summary: 'upward escalator',
|
||||||
},
|
},
|
||||||
au: {
|
au: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'elevator',
|
code: 'elevator',
|
||||||
summary: 'elevator available'
|
summary: 'elevator available',
|
||||||
},
|
},
|
||||||
ck: {
|
ck: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'komfort-checkin',
|
code: 'komfort-checkin',
|
||||||
summary: 'Komfort-Checkin available'
|
summary: 'Komfort-Checkin available',
|
||||||
},
|
},
|
||||||
it: {
|
it: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'ice-sprinter',
|
code: 'ice-sprinter',
|
||||||
summary: 'ICE Sprinter service'
|
summary: 'ICE Sprinter service',
|
||||||
},
|
},
|
||||||
rp: {
|
rp: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'compulsory-reservation',
|
code: 'compulsory-reservation',
|
||||||
summary: 'compulsory seat reservation'
|
summary: 'compulsory seat reservation',
|
||||||
},
|
},
|
||||||
rm: {
|
rm: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'optional-reservation',
|
code: 'optional-reservation',
|
||||||
summary: 'optional seat reservation'
|
summary: 'optional seat reservation',
|
||||||
},
|
},
|
||||||
scl: {
|
scl: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'all-2nd-class-seats-reserved',
|
code: 'all-2nd-class-seats-reserved',
|
||||||
summary: 'all 2nd class seats reserved'
|
summary: 'all 2nd class seats reserved',
|
||||||
},
|
},
|
||||||
acl: {
|
acl: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'all-seats-reserved',
|
code: 'all-seats-reserved',
|
||||||
summary: 'all seats reserved'
|
summary: 'all seats reserved',
|
||||||
},
|
},
|
||||||
sk: {
|
sk: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'oversize-luggage-forbidden',
|
code: 'oversize-luggage-forbidden',
|
||||||
summary: 'oversize luggage not allowed'
|
summary: 'oversize luggage not allowed',
|
||||||
},
|
},
|
||||||
hu: {
|
hu: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'animals-forbidden',
|
code: 'animals-forbidden',
|
||||||
summary: 'animals not allowed, except guide dogs'
|
summary: 'animals not allowed, except guide dogs',
|
||||||
},
|
},
|
||||||
ik: {
|
ik: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'baby-cot-required',
|
code: 'baby-cot-required',
|
||||||
summary: 'baby cot/child seat required'
|
summary: 'baby cot/child seat required',
|
||||||
},
|
},
|
||||||
ee: {
|
ee: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'on-board-entertainment',
|
code: 'on-board-entertainment',
|
||||||
summary: 'on-board entertainment available'
|
summary: 'on-board entertainment available',
|
||||||
},
|
},
|
||||||
toilet: {
|
toilet: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'toilet',
|
code: 'toilet',
|
||||||
summary: 'toilet available'
|
summary: 'toilet available',
|
||||||
},
|
},
|
||||||
oc: {
|
oc: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'wheelchair-accessible-toilet',
|
code: 'wheelchair-accessible-toilet',
|
||||||
summary: 'wheelchair-accessible toilet available'
|
summary: 'wheelchair-accessible toilet available',
|
||||||
},
|
},
|
||||||
iz: {
|
iz: {
|
||||||
type: 'hint',
|
type: 'hint',
|
||||||
code: 'intercity-2',
|
code: 'intercity-2',
|
||||||
summary: 'Intercity 2'
|
summary: 'Intercity 2',
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const codesByText = Object.assign(Object.create(null), {
|
const codesByText = Object.assign(Object.create(null), {
|
||||||
'journey cancelled': 'journey-cancelled', // todo: German variant
|
'journey cancelled': 'journey-cancelled', // todo: German variant
|
||||||
|
@ -501,34 +531,39 @@ const codesByText = Object.assign(Object.create(null), {
|
||||||
'signalstörung': 'signal-failure',
|
'signalstörung': 'signal-failure',
|
||||||
'additional stop': 'additional-stopover', // todo: German variant
|
'additional stop': 'additional-stopover', // todo: German variant
|
||||||
'platform change': 'changed platform', // todo: use dash, German variant
|
'platform change': 'changed platform', // todo: use dash, German variant
|
||||||
})
|
});
|
||||||
|
|
||||||
const parseHintByCode = ({parsed}, raw) => {
|
const parseHintByCode = ({parsed}, raw) => {
|
||||||
// plain-text hints used e.g. for stop metadata
|
// plain-text hints used e.g. for stop metadata
|
||||||
if (raw.type === 'K') {
|
if (raw.type === 'K') {
|
||||||
return {type: 'hint', text: raw.txtN}
|
return {type: 'hint', text: raw.txtN};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raw.type === 'A') {
|
if (raw.type === 'A') {
|
||||||
const hint = hintsByCode[raw.code && raw.code.trim().toLowerCase()]
|
const hint = hintsByCode[raw.code && raw.code.trim()
|
||||||
|
.toLowerCase()];
|
||||||
if (hint) {
|
if (hint) {
|
||||||
return Object.assign({text: raw.txtN}, hint)
|
return Object.assign({text: raw.txtN}, hint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed && raw.txtN) {
|
if (parsed && raw.txtN) {
|
||||||
const text = trim(raw.txtN.toLowerCase(), ' ()')
|
const text = trim(raw.txtN.toLowerCase(), ' ()');
|
||||||
if (codesByText[text]) parsed.code = codesByText[text]
|
if (codesByText[text]) {
|
||||||
|
parsed.code = codesByText[text];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const isIBNR = /^\d{6,}$/
|
const isIBNR = /^\d{6,}$/;
|
||||||
const formatStation = (id) => {
|
const formatStation = (id) => {
|
||||||
if (!isIBNR.test(id)) throw new Error('station ID must be an IBNR.')
|
if (!isIBNR.test(id)) {
|
||||||
return _formatStation(id)
|
throw new Error('station ID must be an IBNR.');
|
||||||
}
|
}
|
||||||
|
return _formatStation(id);
|
||||||
|
};
|
||||||
|
|
||||||
// todo: find option for absolute number of results
|
// todo: find option for absolute number of results
|
||||||
|
|
||||||
|
@ -560,8 +595,8 @@ const profile = {
|
||||||
radar: true,
|
radar: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
lines: false, // `.svcResL[0].res.lineL[]` is missing 🤔
|
lines: false, // `.svcResL[0].res.lineL[]` is missing 🤔
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -6,24 +6,46 @@ const c = {
|
||||||
HALBTAXABO: Symbol('HalbtaxAbo'),
|
HALBTAXABO: Symbol('HalbtaxAbo'),
|
||||||
VOORDEELURENABO: Symbol('Voordeelurenabo'),
|
VOORDEELURENABO: Symbol('Voordeelurenabo'),
|
||||||
SHCARD: Symbol('SH-Card'),
|
SHCARD: Symbol('SH-Card'),
|
||||||
GENERALABONNEMENT: Symbol('General-Abonnement')
|
GENERALABONNEMENT: Symbol('General-Abonnement'),
|
||||||
}
|
};
|
||||||
|
|
||||||
// see https://gist.github.com/juliuste/202bb04f450a79f8fa12a2ec3abcd72d
|
// see https://gist.github.com/juliuste/202bb04f450a79f8fa12a2ec3abcd72d
|
||||||
const formatLoyaltyCard = (data) => {
|
const formatLoyaltyCard = (data) => {
|
||||||
if (data.type === c.BAHNCARD) {
|
if (data.type === c.BAHNCARD) {
|
||||||
if (data.discount === 25) return data.class === 1 ? 1 : 2
|
if (data.discount === 25) {
|
||||||
if (data.discount === 50) return data.class === 1 ? 3 : 4
|
return data.class === 1
|
||||||
|
? 1
|
||||||
|
: 2;
|
||||||
}
|
}
|
||||||
if (data.type === c.VORTEILSCARD) return 9
|
if (data.discount === 50) {
|
||||||
if (data.type === c.HALBTAXABO) return data.railplus ? 10 : 11
|
return data.class === 1
|
||||||
if (data.type === c.VOORDEELURENABO) return data.railplus ? 12 : 13
|
? 3
|
||||||
if (data.type === c.SHCARD) return 14
|
: 4;
|
||||||
if (data.type === c.GENERALABONNEMENT) return 15
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (data.type === c.VORTEILSCARD) {
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
if (data.type === c.HALBTAXABO) {
|
||||||
|
return data.railplus
|
||||||
|
? 10
|
||||||
|
: 11;
|
||||||
|
}
|
||||||
|
if (data.type === c.VOORDEELURENABO) {
|
||||||
|
return data.railplus
|
||||||
|
? 12
|
||||||
|
: 13;
|
||||||
|
}
|
||||||
|
if (data.type === c.SHCARD) {
|
||||||
|
return 14;
|
||||||
|
}
|
||||||
|
if (data.type === c.GENERALABONNEMENT) {
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
c as data,
|
c as data,
|
||||||
formatLoyaltyCard,
|
formatLoyaltyCard,
|
||||||
}
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'InterCityExpress',
|
name: 'InterCityExpress',
|
||||||
short: 'ICE',
|
short: 'ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'national',
|
id: 'national',
|
||||||
|
@ -14,7 +14,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'InterCity & EuroCity',
|
name: 'InterCity & EuroCity',
|
||||||
short: 'IC/EC',
|
short: 'IC/EC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regionalExpress',
|
id: 'regionalExpress',
|
||||||
|
@ -22,7 +22,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'RegionalExpress & InterRegio',
|
name: 'RegionalExpress & InterRegio',
|
||||||
short: 'RE/IR',
|
short: 'RE/IR',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional',
|
id: 'regional',
|
||||||
|
@ -30,7 +30,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Regio',
|
name: 'Regio',
|
||||||
short: 'RB',
|
short: 'RB',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'suburban',
|
id: 'suburban',
|
||||||
|
@ -38,7 +38,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -46,7 +46,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'B',
|
short: 'B',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ferry',
|
id: 'ferry',
|
||||||
|
@ -54,7 +54,7 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'Ferry',
|
name: 'Ferry',
|
||||||
short: 'F',
|
short: 'F',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'subway',
|
id: 'subway',
|
||||||
|
@ -62,7 +62,7 @@ const products = [
|
||||||
bitmasks: [128],
|
bitmasks: [128],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -70,7 +70,7 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'T',
|
short: 'T',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'taxi',
|
id: 'taxi',
|
||||||
|
@ -78,10 +78,10 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'Group Taxi',
|
name: 'Group Taxi',
|
||||||
short: 'Taxi',
|
short: 'Taxi',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -6,8 +6,8 @@ const routingModes = {
|
||||||
REALTIME: 'REALTIME',
|
REALTIME: 'REALTIME',
|
||||||
SERVER_DEFAULT: 'SERVER_DEFAULT',
|
SERVER_DEFAULT: 'SERVER_DEFAULT',
|
||||||
HYBRID: 'HYBRID',
|
HYBRID: 'HYBRID',
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
routingModes,
|
routingModes,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -17,8 +17,8 @@ const profile = {
|
||||||
radar: true,
|
radar: true,
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'InterCityExpress',
|
name: 'InterCityExpress',
|
||||||
short: 'ICE',
|
short: 'ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'national',
|
id: 'national',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'InterCity & EuroCity',
|
name: 'InterCity & EuroCity',
|
||||||
short: 'IC/EC',
|
short: 'IC/EC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional',
|
id: 'regional',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'RegionalExpress & RegionalBahn',
|
name: 'RegionalExpress & RegionalBahn',
|
||||||
short: 'RE/RB',
|
short: 'RE/RB',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'suburban',
|
id: 'suburban',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'T',
|
short: 'T',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [64, 128],
|
bitmasks: [64, 128],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'B',
|
short: 'B',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tourismTrain',
|
id: 'tourismTrain',
|
||||||
|
@ -53,10 +53,10 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Tourism Train',
|
name: 'Tourism Train',
|
||||||
short: 'TT',
|
short: 'TT',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -17,8 +17,8 @@ const profile = {
|
||||||
trip: true,
|
trip: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
refreshJourney: true,
|
refreshJourney: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@ const products = [
|
||||||
bitmasks: [1, 16],
|
bitmasks: [1, 16],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true // the other `bus` has `false`
|
default: true, // the other `bus` has `false`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'express-train',
|
id: 'express-train',
|
||||||
|
@ -14,7 +14,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'High-speed train',
|
name: 'High-speed train',
|
||||||
short: 'Train',
|
short: 'Train',
|
||||||
default: false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional-train',
|
id: 'regional-train',
|
||||||
|
@ -22,7 +22,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'Regional train',
|
name: 'Regional train',
|
||||||
short: 'Train',
|
short: 'Train',
|
||||||
default: false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'local-train',
|
id: 'local-train',
|
||||||
|
@ -30,7 +30,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Nahverkehrszug',
|
name: 'Nahverkehrszug',
|
||||||
short: 'Zug',
|
short: 'Zug',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ferry',
|
id: 'ferry',
|
||||||
|
@ -38,7 +38,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Ferry',
|
name: 'Ferry',
|
||||||
short: 'Ferry',
|
short: 'Ferry',
|
||||||
default: false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'subway',
|
id: 'subway',
|
||||||
|
@ -46,7 +46,7 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'Subway',
|
name: 'Subway',
|
||||||
short: 'Subway',
|
short: 'Subway',
|
||||||
default: false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -54,7 +54,7 @@ const products = [
|
||||||
bitmasks: [128],
|
bitmasks: [128],
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'Tram',
|
short: 'Tram',
|
||||||
default: false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'on-demand',
|
id: 'on-demand',
|
||||||
|
@ -62,10 +62,10 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'On-demand traffic',
|
name: 'On-demand traffic',
|
||||||
short: 'on demand',
|
short: 'on demand',
|
||||||
default: false
|
default: false,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -19,8 +19,8 @@ const profile = {
|
||||||
refreshJourney: false, // fails with `CGI_READ_FAILED`
|
refreshJourney: false, // fails with `CGI_READ_FAILED`
|
||||||
trip: true,
|
trip: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'InterCity',
|
name: 'InterCity',
|
||||||
short: 'IC',
|
short: 'IC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
// todo: 4
|
// todo: 4
|
||||||
{
|
{
|
||||||
|
@ -14,7 +14,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Commuter',
|
name: 'Commuter',
|
||||||
short: 'Commuter',
|
short: 'Commuter',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'suburban',
|
id: 'suburban',
|
||||||
|
@ -22,7 +22,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'Dublin Area Rapid Transit',
|
name: 'Dublin Area Rapid Transit',
|
||||||
short: 'DART',
|
short: 'DART',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
// todo: 32
|
// todo: 32
|
||||||
{
|
{
|
||||||
|
@ -31,10 +31,10 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'LUAS Tram',
|
name: 'LUAS Tram',
|
||||||
short: 'LUAS',
|
short: 'LUAS',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
import {readFileSync} from 'fs'
|
import {readFileSync} from 'fs';
|
||||||
import {Agent} from 'https'
|
import {Agent} from 'https';
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'train-and-s-bahn',
|
id: 'train-and-s-bahn',
|
||||||
|
@ -77,14 +77,14 @@ const products = [{
|
||||||
name: 'Anrufsammeltaxi',
|
name: 'Anrufsammeltaxi',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
// `fahrplan.ivb.at:443` doesn't provide the necessary CA certificate chain for
|
// `fahrplan.ivb.at:443` doesn't provide the necessary CA certificate chain for
|
||||||
// Node.js to trust the certificate, so we manually add it.
|
// Node.js to trust the certificate, so we manually add it.
|
||||||
// todo: fix this properly, e.g. by letting them know
|
// todo: fix this properly, e.g. by letting them know
|
||||||
const ca = readFileSync(new URL('./digicert-tls-rsa-sha256-2020-ca1.crt.pem', import.meta.url).pathname)
|
const ca = readFileSync(new URL('./digicert-tls-rsa-sha256-2020-ca1.crt.pem', import.meta.url).pathname);
|
||||||
const agent = new Agent({ca})
|
const agent = new Agent({ca});
|
||||||
const transformReq = (ctx, req) => ({...req, agent})
|
const transformReq = (ctx, req) => ({...req, agent});
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -99,8 +99,8 @@ const profile = {
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
trip: true,
|
trip: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
import {readFileSync} from 'fs'
|
import {readFileSync} from 'fs';
|
||||||
import {Agent} from 'https'
|
import {Agent} from 'https';
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'stadtbahn',
|
id: 'stadtbahn',
|
||||||
|
@ -49,14 +49,14 @@ const products = [{
|
||||||
name: 'Fernverkehr',
|
name: 'Fernverkehr',
|
||||||
short: 'Fernverkehr',
|
short: 'Fernverkehr',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
// `auskunft.kvb.koeln:443` doesn't provide the necessary CA certificate chain for
|
// `auskunft.kvb.koeln:443` doesn't provide the necessary CA certificate chain for
|
||||||
// Node.js to trust the certificate, so we manually add it.
|
// Node.js to trust the certificate, so we manually add it.
|
||||||
// todo: fix this properly, e.g. by letting them know
|
// todo: fix this properly, e.g. by letting them know
|
||||||
const ca = readFileSync(new URL('./thawte-rsa-ca-2018.pem', import.meta.url).pathname)
|
const ca = readFileSync(new URL('./thawte-rsa-ca-2018.pem', import.meta.url).pathname);
|
||||||
const agent = new Agent({ca})
|
const agent = new Agent({ca});
|
||||||
const transformReq = (ctx, req) => ({...req, agent})
|
const transformReq = (ctx, req) => ({...req, agent});
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -69,8 +69,8 @@ const profile = {
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
trip: true,
|
trip: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -18,8 +18,8 @@ const profile = {
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
remarks: true,
|
remarks: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -72,9 +72,9 @@ const products = [
|
||||||
name: 'EC/IC',
|
name: 'EC/IC',
|
||||||
short: 'EC/IC',
|
short: 'EC/IC',
|
||||||
default: true,
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -18,8 +18,8 @@ const profile = {
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
|
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'local train (TGV/ICE)',
|
name: 'local train (TGV/ICE)',
|
||||||
short: 'TGV/ICE',
|
short: 'TGV/ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'national-train',
|
id: 'national-train',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [2, 4],
|
bitmasks: [2, 4],
|
||||||
name: 'national train (IC/RE/IRE)',
|
name: 'national train (IC/RE/IRE)',
|
||||||
short: 'IC/RE/IRE',
|
short: 'IC/RE/IRE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'local-train',
|
id: 'local-train',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'local train (RB/TER)',
|
name: 'local train (RB/TER)',
|
||||||
short: 'RB/TER',
|
short: 'RB/TER',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -37,10 +37,10 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'Tram',
|
short: 'Tram',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,73 +1,77 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
import {parseHook} from '../../lib/profile-hooks.js'
|
import {parseHook} from '../../lib/profile-hooks.js';
|
||||||
|
|
||||||
import {parseLocation as _parseLocation} from '../../parse/location.js'
|
import {parseLocation as _parseLocation} from '../../parse/location.js';
|
||||||
import {parseJourney as _parseJourney} from '../../parse/journey.js'
|
import {parseJourney as _parseJourney} from '../../parse/journey.js';
|
||||||
import {parseMovement as _parseMovement} from '../../parse/movement.js'
|
import {parseMovement as _parseMovement} from '../../parse/movement.js';
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
// todo: journey prices
|
// todo: journey prices
|
||||||
|
|
||||||
const fixLocation = ({parsed}, l) => {
|
const fixLocation = ({parsed}, l) => {
|
||||||
// weird fix for empty lines, e.g. IC/EC at Flensburg Hbf
|
// weird fix for empty lines, e.g. IC/EC at Flensburg Hbf
|
||||||
if (parsed.lines) {
|
if (parsed.lines) {
|
||||||
parsed.lines = parsed.lines.filter(x => x.id && x.name)
|
parsed.lines = parsed.lines.filter(x => x.id && x.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove leading zeroes, todo
|
// remove leading zeroes, todo
|
||||||
if (parsed.id && parsed.id.length > 0) {
|
if (parsed.id && parsed.id.length > 0) {
|
||||||
parsed.id = parsed.id.replace(/^0+/, '')
|
parsed.id = parsed.id.replace(/^0+/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const parseJourneyWithTickets = ({parsed}, j) => {
|
const parseJourneyWithTickets = ({parsed}, j) => {
|
||||||
if (
|
if (
|
||||||
j.trfRes &&
|
j.trfRes
|
||||||
Array.isArray(j.trfRes.fareSetL) &&
|
&& Array.isArray(j.trfRes.fareSetL)
|
||||||
j.trfRes.fareSetL.length > 0
|
&& j.trfRes.fareSetL.length > 0
|
||||||
) {
|
) {
|
||||||
parsed.tickets = []
|
parsed.tickets = [];
|
||||||
|
|
||||||
for (let t of j.trfRes.fareSetL) {
|
for (let t of j.trfRes.fareSetL) {
|
||||||
const tariff = t.desc
|
const tariff = t.desc;
|
||||||
if (!tariff || !Array.isArray(t.fareL)) continue
|
if (!tariff || !Array.isArray(t.fareL)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (let v of t.fareL) {
|
for (let v of t.fareL) {
|
||||||
const variant = v.name
|
const variant = v.name;
|
||||||
if(!variant) continue
|
if (!variant) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const ticket = {
|
const ticket = {
|
||||||
name: [tariff, variant].join(' - '),
|
name: [tariff, variant].join(' - '),
|
||||||
tariff,
|
tariff,
|
||||||
variant
|
variant,
|
||||||
}
|
};
|
||||||
if (v.prc && Number.isInteger(v.prc) && v.cur) {
|
if (v.prc && Number.isInteger(v.prc) && v.cur) {
|
||||||
ticket.amount = v.prc/100
|
ticket.amount = v.prc / 100;
|
||||||
ticket.currency = v.cur
|
ticket.currency = v.cur;
|
||||||
} else {
|
} else {
|
||||||
ticket.amount = null
|
ticket.amount = null;
|
||||||
ticket.hint = 'No pricing information available.'
|
ticket.hint = 'No pricing information available.';
|
||||||
}
|
}
|
||||||
parsed.tickets.push(ticket)
|
parsed.tickets.push(ticket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const fixMovement = ({parsed}, m) => {
|
const fixMovement = ({parsed}, m) => {
|
||||||
// filter out empty nextStopovers entries
|
// filter out empty nextStopovers entries
|
||||||
parsed.nextStopovers = parsed.nextStopovers.filter((f) => {
|
parsed.nextStopovers = parsed.nextStopovers.filter((f) => {
|
||||||
return f.stop !== null || f.arrival !== null || f.departure !== null
|
return f.stop !== null || f.arrival !== null || f.departure !== null;
|
||||||
})
|
});
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -84,8 +88,8 @@ const profile = {
|
||||||
trip: true,
|
trip: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'High-speed rail',
|
name: 'High-speed rail',
|
||||||
short: 'ICE/HSR',
|
short: 'ICE/HSR',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'national',
|
id: 'national',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'InterCity & EuroCity',
|
name: 'InterCity & EuroCity',
|
||||||
short: 'IC/EC',
|
short: 'IC/EC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{ // todo: also includes EN?
|
{ // todo: also includes EN?
|
||||||
id: 'interregional',
|
id: 'interregional',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'Interregional',
|
name: 'Interregional',
|
||||||
short: 'IR',
|
short: 'IR',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional',
|
id: 'regional',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Regional & RegionalExpress',
|
name: 'Regional & RegionalExpress',
|
||||||
short: 'RB/RE',
|
short: 'RB/RE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'suburban',
|
id: 'suburban',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'B',
|
short: 'B',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ferry',
|
id: 'ferry',
|
||||||
|
@ -53,7 +53,7 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'Ferry',
|
name: 'Ferry',
|
||||||
short: 'F',
|
short: 'F',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'subway',
|
id: 'subway',
|
||||||
|
@ -61,7 +61,7 @@ const products = [
|
||||||
bitmasks: [128],
|
bitmasks: [128],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -69,7 +69,7 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'T',
|
short: 'T',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'onCall',
|
id: 'onCall',
|
||||||
|
@ -77,10 +77,10 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'On-call transit',
|
name: 'On-call transit',
|
||||||
short: 'on-call',
|
short: 'on-call',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -17,8 +17,8 @@ const profile = {
|
||||||
trip: true,
|
trip: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'InterCityExpress',
|
name: 'InterCityExpress',
|
||||||
short: 'ICE',
|
short: 'ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'national',
|
id: 'national',
|
||||||
|
@ -14,7 +14,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'EuroCity/InterCity',
|
name: 'EuroCity/InterCity',
|
||||||
short: 'EC/IC',
|
short: 'EC/IC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional',
|
id: 'regional',
|
||||||
|
@ -22,7 +22,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'Regionalzug',
|
name: 'Regionalzug',
|
||||||
short: 'RE/RB',
|
short: 'RE/RB',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regiotram',
|
id: 'regiotram',
|
||||||
|
@ -30,7 +30,7 @@ const products = [
|
||||||
bitmasks: [1024, 16, 8], // it is `1048` actually
|
bitmasks: [1024, 16, 8], // it is `1048` actually
|
||||||
name: 'RegioTram',
|
name: 'RegioTram',
|
||||||
short: 'RegioTram',
|
short: 'RegioTram',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -38,7 +38,7 @@ const products = [
|
||||||
bitmasks: [4, 32],
|
bitmasks: [4, 32],
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'Tram',
|
short: 'Tram',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -46,7 +46,7 @@ const products = [
|
||||||
bitmasks: [128, 64], // it is `192` actually
|
bitmasks: [128, 64], // it is `192` actually
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'on-call',
|
id: 'on-call',
|
||||||
|
@ -54,10 +54,10 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'AnrufSammelTaxi',
|
name: 'AnrufSammelTaxi',
|
||||||
short: 'Sammeltaxi',
|
short: 'Sammeltaxi',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,50 +1,52 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
// todo: https://gist.github.com/anonymous/a5fc856bc80ae7364721943243f934f4#file-haf_config_base-properties-L5
|
// todo: https://gist.github.com/anonymous/a5fc856bc80ae7364721943243f934f4#file-haf_config_base-properties-L5
|
||||||
// todo: https://gist.github.com/anonymous/a5fc856bc80ae7364721943243f934f4#file-haf_config_base-properties-L47-L234
|
// todo: https://gist.github.com/anonymous/a5fc856bc80ae7364721943243f934f4#file-haf_config_base-properties-L47-L234
|
||||||
|
|
||||||
import {parseHook} from '../../lib/profile-hooks.js'
|
import {parseHook} from '../../lib/profile-hooks.js';
|
||||||
|
|
||||||
import {parseLocation as _parseLocation} from '../../parse/location.js'
|
import {parseLocation as _parseLocation} from '../../parse/location.js';
|
||||||
import {parseMovement as _parseMovement} from '../../parse/movement.js'
|
import {parseMovement as _parseMovement} from '../../parse/movement.js';
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
// ÖBB has some 'stations' **in austria** with no departures/products,
|
// ÖBB has some 'stations' **in austria** with no departures/products,
|
||||||
// like station entrances, that are actually POIs.
|
// like station entrances, that are actually POIs.
|
||||||
const fixWeirdPOIs = ({parsed}) => {
|
const fixWeirdPOIs = ({parsed}) => {
|
||||||
if (
|
if (
|
||||||
(parsed.type === 'station' || parsed.type === 'stop') &&
|
(parsed.type === 'station' || parsed.type === 'stop')
|
||||||
!parsed.products &&
|
&& !parsed.products
|
||||||
parsed.name &&
|
&& parsed.name
|
||||||
parsed.id && parsed.id.length !== 7
|
&& parsed.id && parsed.id.length !== 7
|
||||||
) {
|
) {
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
type: 'location',
|
type: 'location',
|
||||||
id: parsed.id,
|
id: parsed.id,
|
||||||
poi: true,
|
poi: true,
|
||||||
name: parsed.name
|
name: parsed.name,
|
||||||
}, parsed.location)
|
}, parsed.location);
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
}
|
||||||
|
return parsed;
|
||||||
|
};
|
||||||
|
|
||||||
const fixMovement = ({parsed}, m) => {
|
const fixMovement = ({parsed}, m) => {
|
||||||
// filter out POIs
|
// filter out POIs
|
||||||
// todo: make use of them, as some of them specify fare zones
|
// todo: make use of them, as some of them specify fare zones
|
||||||
parsed.nextStopovers = parsed.nextStopovers.filter(st => {
|
parsed.nextStopovers = parsed.nextStopovers.filter(st => {
|
||||||
let s = st.stop || {}
|
let s = st.stop || {};
|
||||||
if (s.station) s = s.station
|
if (s.station) {
|
||||||
return s.type === 'stop' || s.type === 'station'
|
s = s.station;
|
||||||
})
|
|
||||||
parsed.frames = parsed.frames.filter((f) => {
|
|
||||||
return f.origin.type !== 'location' && f.destination.type !== 'location'
|
|
||||||
})
|
|
||||||
return parsed
|
|
||||||
}
|
}
|
||||||
|
return s.type === 'stop' || s.type === 'station';
|
||||||
|
});
|
||||||
|
parsed.frames = parsed.frames.filter((f) => {
|
||||||
|
return f.origin.type !== 'location' && f.destination.type !== 'location';
|
||||||
|
});
|
||||||
|
return parsed;
|
||||||
|
};
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -62,8 +64,8 @@ const profile = {
|
||||||
radar: true,
|
radar: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
// lines: false, // `.svcResL[0].res.lineL[]` is missing 🤔
|
// lines: false, // `.svcResL[0].res.lineL[]` is missing 🤔
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'InterCityExpress & RailJet',
|
name: 'InterCityExpress & RailJet',
|
||||||
short: 'ICE/RJ',
|
short: 'ICE/RJ',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'national',
|
id: 'national',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [2, 4],
|
bitmasks: [2, 4],
|
||||||
name: 'InterCity & EuroCity',
|
name: 'InterCity & EuroCity',
|
||||||
short: 'IC/EC',
|
short: 'IC/EC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'interregional',
|
id: 'interregional',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [8, 4096],
|
bitmasks: [8, 4096],
|
||||||
name: 'Durchgangszug & EuroNight',
|
name: 'Durchgangszug & EuroNight',
|
||||||
short: 'D/EN',
|
short: 'D/EN',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional',
|
id: 'regional',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'Regional & RegionalExpress',
|
name: 'Regional & RegionalExpress',
|
||||||
short: 'R/REX',
|
short: 'R/REX',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'suburban',
|
id: 'suburban',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'B',
|
short: 'B',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ferry',
|
id: 'ferry',
|
||||||
|
@ -53,7 +53,7 @@ const products = [
|
||||||
bitmasks: [128],
|
bitmasks: [128],
|
||||||
name: 'Ferry',
|
name: 'Ferry',
|
||||||
short: 'F',
|
short: 'F',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'subway',
|
id: 'subway',
|
||||||
|
@ -61,7 +61,7 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -69,7 +69,7 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'T',
|
short: 'T',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'onCall',
|
id: 'onCall',
|
||||||
|
@ -77,10 +77,10 @@ const products = [
|
||||||
bitmasks: [2048],
|
bitmasks: [2048],
|
||||||
name: 'on-call transit, lifts, etc',
|
name: 'on-call transit, lifts, etc',
|
||||||
short: 'on-call/lift',
|
short: 'on-call/lift',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'train-and-s-bahn',
|
id: 'train-and-s-bahn',
|
||||||
|
@ -75,7 +75,7 @@ const products = [{
|
||||||
name: 'Anrufsammeltaxi',
|
name: 'Anrufsammeltaxi',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -96,8 +96,8 @@ const profile = {
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
trip: true,
|
trip: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
import {parseHook} from '../../lib/profile-hooks.js'
|
import {parseHook} from '../../lib/profile-hooks.js';
|
||||||
|
|
||||||
import {parseLocation} from '../../parse/location.js'
|
import {parseLocation} from '../../parse/location.js';
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const trimStopName = ({parsed}, l) => {
|
const trimStopName = ({parsed}, l) => {
|
||||||
if (parsed.type === 'stop' || parsed.type === 'station' && parsed.name) {
|
if (parsed.type === 'stop' || parsed.type === 'station' && parsed.name) {
|
||||||
parsed.name = parsed.name.replace(/(^-|-$)/g, '')
|
parsed.name = parsed.name.replace(/(^-|-$)/g, '');
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
}
|
||||||
|
return parsed;
|
||||||
|
};
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -30,8 +30,8 @@ const profile = {
|
||||||
refreshJourney: false,
|
refreshJourney: false,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
remarks: false, // seems like ver >= 1.20 is required
|
remarks: false, // seems like ver >= 1.20 is required
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1, 2],
|
bitmasks: [1, 2],
|
||||||
name: 'ExpressInterCity & ExpressInterCity Premium & InterCityExpress',
|
name: 'ExpressInterCity & ExpressInterCity Premium & InterCityExpress',
|
||||||
short: 'EIC/EIP/ICE',
|
short: 'EIC/EIP/ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'long-distance-train',
|
id: 'long-distance-train',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'InterCity & Twoje Linie Kolejowe & EuroCity & EuroNight',
|
name: 'InterCity & Twoje Linie Kolejowe & EuroCity & EuroNight',
|
||||||
short: 'IC/TLK/EC/EN',
|
short: 'IC/TLK/EC/EN',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional-train',
|
id: 'regional-train',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Regional',
|
name: 'Regional',
|
||||||
short: 'R',
|
short: 'R',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -29,10 +29,10 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'B',
|
short: 'B',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -16,8 +16,8 @@ const profile = {
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
trip: true,
|
trip: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -38,9 +38,9 @@ const products = [
|
||||||
name: 'S-Tog A/B/Bx/C/E/F/H',
|
name: 'S-Tog A/B/Bx/C/E/F/H',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true,
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -18,8 +18,8 @@ const profile = {
|
||||||
radar: true,
|
radar: true,
|
||||||
refreshJourney: true,
|
refreshJourney: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'InterCityExpress/Fernzug',
|
name: 'InterCityExpress/Fernzug',
|
||||||
short: 'ICE',
|
short: 'ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'long-distance-train',
|
id: 'long-distance-train',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'EuroCity/InterCity/EuroNight/InterRegio',
|
name: 'EuroCity/InterCity/EuroNight/InterRegio',
|
||||||
short: 'EC/IC/EN/IR',
|
short: 'EC/IC/EN/IR',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regiona-train',
|
id: 'regiona-train',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'RegionalExpress/Regionalbahn',
|
name: 'RegionalExpress/Regionalbahn',
|
||||||
short: 'RE/RB',
|
short: 'RE/RB',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 's-bahn',
|
id: 's-bahn',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'u-bahn',
|
id: 'u-bahn',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Straßenbahn',
|
name: 'Straßenbahn',
|
||||||
short: 'Tram',
|
short: 'Tram',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -53,7 +53,7 @@ const products = [
|
||||||
bitmasks: [64, 128],
|
bitmasks: [64, 128],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'watercraft',
|
id: 'watercraft',
|
||||||
|
@ -61,7 +61,7 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Schiff',
|
name: 'Schiff',
|
||||||
short: 'Schiff',
|
short: 'Schiff',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ast',
|
id: 'ast',
|
||||||
|
@ -69,7 +69,7 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'Anruf-Sammel-Taxi',
|
name: 'Anruf-Sammel-Taxi',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'cable-car',
|
id: 'cable-car',
|
||||||
|
@ -77,11 +77,11 @@ const products = [
|
||||||
bitmasks: [1024],
|
bitmasks: [1024],
|
||||||
name: 'Seilbahn',
|
name: 'Seilbahn',
|
||||||
short: 'Seilbahn',
|
short: 'Seilbahn',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
// todo: remaining bitmask `1015`
|
// todo: remaining bitmask `1015`
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -17,8 +17,8 @@ const profile = {
|
||||||
radar: true,
|
radar: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'InterCityExpress',
|
name: 'InterCityExpress',
|
||||||
short: 'ICE',
|
short: 'ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ic-ec',
|
id: 'ic-ec',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'InterCity & EuroCity',
|
name: 'InterCity & EuroCity',
|
||||||
short: 'IC/EC',
|
short: 'IC/EC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'long-distance-train',
|
id: 'long-distance-train',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'InterRegio/high-speed train',
|
name: 'InterRegio/high-speed train',
|
||||||
short: 'IR/other',
|
short: 'IR/other',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional-train', // todo: rename
|
id: 'regional-train', // todo: rename
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'regional train',
|
name: 'regional train',
|
||||||
short: 'RE/RB',
|
short: 'RE/RB',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 's-bahn',
|
id: 's-bahn',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'B',
|
short: 'B',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ferry',
|
id: 'ferry',
|
||||||
|
@ -53,7 +53,7 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'Schiff',
|
name: 'Schiff',
|
||||||
short: 'F',
|
short: 'F',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'u-bahn',
|
id: 'u-bahn',
|
||||||
|
@ -61,7 +61,7 @@ const products = [
|
||||||
bitmasks: [128],
|
bitmasks: [128],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -69,7 +69,7 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'T',
|
short: 'T',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'on-call',
|
id: 'on-call',
|
||||||
|
@ -77,10 +77,10 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'Taxi/on-call vehicle',
|
name: 'Taxi/on-call vehicle',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
import {parseHook} from '../../lib/profile-hooks.js'
|
import {parseHook} from '../../lib/profile-hooks.js';
|
||||||
|
|
||||||
import {parseMovement as _parseMovement} from '../../parse/movement.js'
|
import {parseMovement as _parseMovement} from '../../parse/movement.js';
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const fixMovement = ({parsed}, m) => {
|
const fixMovement = ({parsed}, m) => {
|
||||||
// filter out empty stopovers
|
// filter out empty stopovers
|
||||||
parsed.nextStopovers = parsed.nextStopovers.filter(st => !!st.stop)
|
parsed.nextStopovers = parsed.nextStopovers.filter(st => Boolean(st.stop));
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -29,9 +29,9 @@ const profile = {
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
trip: true,
|
trip: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
reachableFrom: true
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [8192],
|
bitmasks: [8192],
|
||||||
name: 'Hochgeschwindigkeitszug',
|
name: 'Hochgeschwindigkeitszug',
|
||||||
short: 'ICE',
|
short: 'ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'national',
|
id: 'national',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [4096],
|
bitmasks: [4096],
|
||||||
name: 'InterCity & EuroCity',
|
name: 'InterCity & EuroCity',
|
||||||
short: 'IC/EC',
|
short: 'IC/EC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'interregional',
|
id: 'interregional',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [2048],
|
bitmasks: [2048],
|
||||||
name: 'InterRegio',
|
name: 'InterRegio',
|
||||||
short: 'IR',
|
short: 'IR',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional',
|
id: 'regional',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [1024],
|
bitmasks: [1024],
|
||||||
name: 'Regionalzug',
|
name: 'Regionalzug',
|
||||||
short: 'RB ?', // todo
|
short: 'RB ?', // todo
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'suburban',
|
id: 'suburban',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S-Bahn',
|
short: 'S-Bahn',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'subway',
|
id: 'subway',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'saarbahn',
|
id: 'saarbahn',
|
||||||
|
@ -53,7 +53,7 @@ const products = [
|
||||||
bitmasks: [128],
|
bitmasks: [128],
|
||||||
name: 'Saarbahn',
|
name: 'Saarbahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -61,7 +61,7 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'watercraft',
|
id: 'watercraft',
|
||||||
|
@ -69,7 +69,7 @@ const products = [
|
||||||
bitmasks: [32], // todo: correct?
|
bitmasks: [32], // todo: correct?
|
||||||
name: 'Schiff',
|
name: 'Schiff',
|
||||||
short: 'Schiff',
|
short: 'Schiff',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'onCall',
|
id: 'onCall',
|
||||||
|
@ -77,7 +77,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'Anruf-Sammel-Taxi',
|
name: 'Anruf-Sammel-Taxi',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'school-bus',
|
id: 'school-bus',
|
||||||
|
@ -85,11 +85,11 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Schulbus',
|
name: 'Schulbus',
|
||||||
short: 'Schulbus',
|
short: 'Schulbus',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
// todo: `1`, `2`, `4` bitmasks?
|
// todo: `1`, `2`, `4` bitmasks?
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'train-and-s-bahn',
|
id: 'train-and-s-bahn',
|
||||||
|
@ -75,7 +75,7 @@ const products = [{
|
||||||
name: 'Anrufsammeltaxi',
|
name: 'Anrufsammeltaxi',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -89,8 +89,8 @@ const profile = {
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
trip: true,
|
trip: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -19,9 +19,9 @@ const profile = {
|
||||||
trip: true,
|
trip: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
refreshJourney: true,
|
refreshJourney: true,
|
||||||
reachableFrom: true
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'InterCityExpress',
|
name: 'InterCityExpress',
|
||||||
short: 'ICE',
|
short: 'ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ic-ec',
|
id: 'ic-ec',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'InterCity/EuroCity',
|
name: 'InterCity/EuroCity',
|
||||||
short: 'IC/EC',
|
short: 'IC/EC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ir-d',
|
id: 'ir-d',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'Interregio/Schnellzug',
|
name: 'Interregio/Schnellzug',
|
||||||
short: 'IRE',
|
short: 'IRE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'region',
|
id: 'region',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Regio- und Nahverkehr',
|
name: 'Regio- und Nahverkehr',
|
||||||
short: 'RE/RB',
|
short: 'RE/RB',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'sbahn',
|
id: 'sbahn',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
// todo: 64
|
// todo: 64
|
||||||
{
|
{
|
||||||
|
@ -54,7 +54,7 @@ const products = [
|
||||||
bitmasks: [128],
|
bitmasks: [128],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -62,7 +62,7 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Straßenbahn',
|
name: 'Straßenbahn',
|
||||||
short: 'Tram',
|
short: 'Tram',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'on-call',
|
id: 'on-call',
|
||||||
|
@ -70,10 +70,10 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'Anrufsammeltaxi',
|
name: 'Anrufsammeltaxi',
|
||||||
short: 'Sammeltaxi',
|
short: 'Sammeltaxi',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,51 +1,57 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
import {readFileSync} from 'fs'
|
import {readFileSync} from 'fs';
|
||||||
import {Agent} from 'https'
|
import {Agent} from 'https';
|
||||||
import {strictEqual as eql} from 'assert'
|
import {strictEqual as eql} from 'assert';
|
||||||
import {parseHook} from '../../lib/profile-hooks.js'
|
import {parseHook} from '../../lib/profile-hooks.js';
|
||||||
import {parseLine} from '../../parse/line.js'
|
import {parseLine} from '../../parse/line.js';
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
// `www.belgianrail.be:443` doesn't provide the necessary CA certificate
|
// `www.belgianrail.be:443` doesn't provide the necessary CA certificate
|
||||||
// chain for Node.js to trust the certificate, so we manually add it.
|
// chain for Node.js to trust the certificate, so we manually add it.
|
||||||
// todo: fix this properly, e.g. by letting them know
|
// todo: fix this properly, e.g. by letting them know
|
||||||
const ca = readFileSync(new URL('./digicert-sha2-secure-server-ca.crt.pem', import.meta.url).pathname)
|
const ca = readFileSync(new URL('./digicert-sha2-secure-server-ca.crt.pem', import.meta.url).pathname);
|
||||||
const agent = new Agent({ca})
|
const agent = new Agent({ca});
|
||||||
const transformReq = (ctx, req) => ({...req, agent})
|
const transformReq = (ctx, req) => ({...req, agent});
|
||||||
|
|
||||||
// todo: this is ugly
|
// todo: this is ugly
|
||||||
const lineNameWithoutFahrtNr = ({parsed}) => {
|
const lineNameWithoutFahrtNr = ({parsed}) => {
|
||||||
const {name, fahrtNr} = parsed
|
const {name, fahrtNr} = parsed;
|
||||||
if (!name || !fahrtNr || !/s\d/i.test(name)) return parsed
|
if (!name || !fahrtNr || !(/s\d/i).test(name)) {
|
||||||
const i = name.indexOf(fahrtNr)
|
return parsed;
|
||||||
if (i < 0) return parsed
|
}
|
||||||
|
const i = name.indexOf(fahrtNr);
|
||||||
|
if (i < 0) {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
/\s/.test(name[i - 1] || '') && // space before
|
(/\s/).test(name[i - 1] || '') // space before
|
||||||
name.length === i + fahrtNr.length // nothing behind
|
&& name.length === i + fahrtNr.length // nothing behind
|
||||||
) return {
|
) {
|
||||||
|
return {
|
||||||
...parsed,
|
...parsed,
|
||||||
name: name.slice(0, i - 1) + name.slice(i + fahrtNr.length + 1),
|
name: name.slice(0, i - 1) + name.slice(i + fahrtNr.length + 1),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
eql(lineNameWithoutFahrtNr({
|
eql(lineNameWithoutFahrtNr({
|
||||||
parsed: {name: 'THA 123', fahrtNr: '123'}
|
parsed: {name: 'THA 123', fahrtNr: '123'},
|
||||||
}).name, 'THA 123')
|
}).name, 'THA 123');
|
||||||
eql(lineNameWithoutFahrtNr({
|
eql(lineNameWithoutFahrtNr({
|
||||||
parsed: {name: 'S1 123', fahrtNr: '123'}
|
parsed: {name: 'S1 123', fahrtNr: '123'},
|
||||||
}).name, 'S1')
|
}).name, 'S1');
|
||||||
eql(lineNameWithoutFahrtNr({
|
eql(lineNameWithoutFahrtNr({
|
||||||
parsed: {name: 'S1-123', fahrtNr: '123'}
|
parsed: {name: 'S1-123', fahrtNr: '123'},
|
||||||
}).name, 'S1-123')
|
}).name, 'S1-123');
|
||||||
eql(lineNameWithoutFahrtNr({
|
eql(lineNameWithoutFahrtNr({
|
||||||
parsed: {name: 'S1 123a', fahrtNr: '123'}
|
parsed: {name: 'S1 123a', fahrtNr: '123'},
|
||||||
}).name, 'S1 123a')
|
}).name, 'S1 123a');
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -62,8 +68,8 @@ const profile = {
|
||||||
refreshJourney: true,
|
refreshJourney: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@ const products = [ // todo: 2, 8, 32, 128
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'high-speed train',
|
name: 'high-speed train',
|
||||||
short: 'HST',
|
short: 'HST',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'intercity-p',
|
id: 'intercity-p',
|
||||||
|
@ -14,7 +14,7 @@ const products = [ // todo: 2, 8, 32, 128
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'InterCity/Peak',
|
name: 'InterCity/Peak',
|
||||||
short: 'IC/P',
|
short: 'IC/P',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 's-train',
|
id: 's-train',
|
||||||
|
@ -22,7 +22,7 @@ const products = [ // todo: 2, 8, 32, 128
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'S-train',
|
name: 'S-train',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'local-train',
|
id: 'local-train',
|
||||||
|
@ -30,7 +30,7 @@ const products = [ // todo: 2, 8, 32, 128
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'local train',
|
name: 'local train',
|
||||||
short: 'L',
|
short: 'L',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'metro',
|
id: 'metro',
|
||||||
|
@ -38,7 +38,7 @@ const products = [ // todo: 2, 8, 32, 128
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Metro',
|
name: 'Metro',
|
||||||
short: 'M',
|
short: 'M',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -46,7 +46,7 @@ const products = [ // todo: 2, 8, 32, 128
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'bus',
|
name: 'bus',
|
||||||
short: 'bus',
|
short: 'bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -54,10 +54,10 @@ const products = [ // todo: 2, 8, 32, 128
|
||||||
bitmasks: [1024],
|
bitmasks: [1024],
|
||||||
name: 'tram',
|
name: 'tram',
|
||||||
short: 'tram',
|
short: 'tram',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'train-and-s-bahn',
|
id: 'train-and-s-bahn',
|
||||||
|
@ -75,7 +75,7 @@ const products = [{
|
||||||
name: 'Anrufsammeltaxi',
|
name: 'Anrufsammeltaxi',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -87,8 +87,8 @@ const profile = {
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
trip: true,
|
trip: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -17,8 +17,8 @@ const profile = {
|
||||||
refreshJourney: true,
|
refreshJourney: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1, 2],
|
bitmasks: [1, 2],
|
||||||
name: 'Bahn & S-Bahn',
|
name: 'Bahn & S-Bahn',
|
||||||
short: 'S/Zug',
|
short: 'S/Zug',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'u-bahn',
|
id: 'u-bahn',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'strassenbahn',
|
id: 'strassenbahn',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'Strassenbahn',
|
name: 'Strassenbahn',
|
||||||
short: 'Str',
|
short: 'Str',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'fernbus',
|
id: 'fernbus',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Fernbus',
|
name: 'Fernbus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regionalbus',
|
id: 'regionalbus',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'Regionalbus',
|
name: 'Regionalbus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'stadtbus',
|
id: 'stadtbus',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [128],
|
bitmasks: [128],
|
||||||
name: 'Stadtbus',
|
name: 'Stadtbus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'seilbahn-zahnradbahn',
|
id: 'seilbahn-zahnradbahn',
|
||||||
|
@ -53,7 +53,7 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Seil-/Zahnradbahn',
|
name: 'Seil-/Zahnradbahn',
|
||||||
short: 'Seil-/Zahnradbahn',
|
short: 'Seil-/Zahnradbahn',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'schiff',
|
id: 'schiff',
|
||||||
|
@ -61,10 +61,10 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'Schiff',
|
name: 'Schiff',
|
||||||
short: 'F',
|
short: 'F',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'tgv',
|
id: 'tgv',
|
||||||
|
@ -68,7 +68,7 @@ const products = [{
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'Tram',
|
short: 'Tram',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -82,8 +82,8 @@ const profile = {
|
||||||
radar: true,
|
radar: true,
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,38 +1,40 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
import {parseHook} from '../../lib/profile-hooks.js'
|
import {parseHook} from '../../lib/profile-hooks.js';
|
||||||
|
|
||||||
import {parseAndAddLocationDHID} from './parse-loc-dhid.js'
|
import {parseAndAddLocationDHID} from './parse-loc-dhid.js';
|
||||||
import {parseLine as _parseLine} from '../../parse/line.js'
|
import {parseLine as _parseLine} from '../../parse/line.js';
|
||||||
import {parseLocation as _parseLocation} from '../../parse/location.js'
|
import {parseLocation as _parseLocation} from '../../parse/location.js';
|
||||||
import {parseJourney as _parseJourney} from '../../parse/journey.js'
|
import {parseJourney as _parseJourney} from '../../parse/journey.js';
|
||||||
import {parseDeparture as _parseDeparture} from '../../parse/departure.js'
|
import {parseDeparture as _parseDeparture} from '../../parse/departure.js';
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const parseLineWithShortName = ({parsed}, p) => {
|
const parseLineWithShortName = ({parsed}, p) => {
|
||||||
parsed.name = p.name.replace(/^(bus|tram)\s+/i, '')
|
parsed.name = p.name.replace(/^(bus|tram)\s+/i, '');
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const parseLocation = ({parsed}, l) => {
|
const parseLocation = ({parsed}, l) => {
|
||||||
parseAndAddLocationDHID(parsed, l)
|
parseAndAddLocationDHID(parsed, l);
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
// todo: move this to parse/tickets.js?
|
// todo: move this to parse/tickets.js?
|
||||||
const parseJourneyWithTickets = ({parsed}, j) => {
|
const parseJourneyWithTickets = ({parsed}, j) => {
|
||||||
if (
|
if (
|
||||||
j.trfRes &&
|
j.trfRes
|
||||||
Array.isArray(j.trfRes.fareSetL)
|
&& Array.isArray(j.trfRes.fareSetL)
|
||||||
) {
|
) {
|
||||||
parsed.tickets = j.trfRes.fareSetL
|
parsed.tickets = j.trfRes.fareSetL
|
||||||
.map((s) => {
|
.map((s) => {
|
||||||
if (!Array.isArray(s.fareL) || s.fareL.length === 0) return null
|
if (!Array.isArray(s.fareL) || s.fareL.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
name: s.name,
|
name: s.name,
|
||||||
description: s.desc,
|
description: s.desc,
|
||||||
|
@ -41,30 +43,30 @@ const parseJourneyWithTickets = ({parsed}, j) => {
|
||||||
name: f.name,
|
name: f.name,
|
||||||
price: f.price,
|
price: f.price,
|
||||||
})),
|
})),
|
||||||
}
|
};
|
||||||
})
|
})
|
||||||
.filter(set => !!set)
|
.filter(set => Boolean(set));
|
||||||
|
|
||||||
// todo: j.trfRes.totalPrice
|
// todo: j.trfRes.totalPrice
|
||||||
// todo: j.trfRes.msgL
|
// todo: j.trfRes.msgL
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const ringbahnClockwise = /^ringbahn s\s?41$/i
|
const ringbahnClockwise = /^ringbahn s\s?41$/i;
|
||||||
const ringbahnAnticlockwise = /^ringbahn s\s?42$/i
|
const ringbahnAnticlockwise = /^ringbahn s\s?42$/i;
|
||||||
const parseDepartureRenameRingbahn = ({parsed}) => {
|
const parseDepartureRenameRingbahn = ({parsed}) => {
|
||||||
if (parsed.line && parsed.line.product === 'suburban') {
|
if (parsed.line && parsed.line.product === 'suburban') {
|
||||||
const d = parsed.direction && parsed.direction.trim()
|
const d = parsed.direction && parsed.direction.trim();
|
||||||
if (ringbahnClockwise.test(d)) {
|
if (ringbahnClockwise.test(d)) {
|
||||||
parsed.direction = 'Ringbahn S41 ⟳'
|
parsed.direction = 'Ringbahn S41 ⟳';
|
||||||
} else if (ringbahnAnticlockwise.test(d)) {
|
} else if (ringbahnAnticlockwise.test(d)) {
|
||||||
parsed.direction = 'Ringbahn S42 ⟲'
|
parsed.direction = 'Ringbahn S42 ⟲';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parsed
|
return parsed;
|
||||||
}
|
};
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -83,8 +85,8 @@ const profile = {
|
||||||
trip: true,
|
trip: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,19 +1,23 @@
|
||||||
const dhidPrefix = 'A×'
|
const dhidPrefix = 'A×';
|
||||||
|
|
||||||
const parseAndAddLocationDHID = (loc, l) => {
|
const parseAndAddLocationDHID = (loc, l) => {
|
||||||
if (!Array.isArray(l.gidL)) return;
|
if (!Array.isArray(l.gidL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const dhidGid = l.gidL.find(gid => gid.slice(0, dhidPrefix.length) === dhidPrefix)
|
const dhidGid = l.gidL.find(gid => gid.slice(0, dhidPrefix.length) === dhidPrefix);
|
||||||
if (!dhidGid) return;
|
if (!dhidGid) {
|
||||||
const dhid = dhidGid.slice(dhidPrefix.length)
|
return;
|
||||||
|
}
|
||||||
|
const dhid = dhidGid.slice(dhidPrefix.length);
|
||||||
|
|
||||||
// It seems that the DHID of the parent station is being used, not of the stop.
|
// It seems that the DHID of the parent station is being used, not of the stop.
|
||||||
// if (!loc.ids) loc.ids = {}
|
// if (!loc.ids) loc.ids = {}
|
||||||
// loc.ids.dhid = dhid
|
// loc.ids.dhid = dhid
|
||||||
// todo: use loc.ids.stationDHID instead?
|
// todo: use loc.ids.stationDHID instead?
|
||||||
loc.stationDHID = dhid
|
loc.stationDHID = dhid;
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
parseAndAddLocationDHID,
|
parseAndAddLocationDHID,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'subway',
|
id: 'subway',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'T',
|
short: 'T',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'B',
|
short: 'B',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ferry',
|
id: 'ferry',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'Fähre',
|
name: 'Fähre',
|
||||||
short: 'F',
|
short: 'F',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'express',
|
id: 'express',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'IC/ICE',
|
name: 'IC/ICE',
|
||||||
short: 'E',
|
short: 'E',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional',
|
id: 'regional',
|
||||||
|
@ -53,10 +53,10 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'RB/RE',
|
name: 'RB/RE',
|
||||||
short: 'R',
|
short: 'R',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -21,8 +21,8 @@ const profile = {
|
||||||
radar: true,
|
radar: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'InterCityExpress',
|
name: 'InterCityExpress',
|
||||||
short: 'ICE',
|
short: 'ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'national-train',
|
id: 'national-train',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [2, 4],
|
bitmasks: [2, 4],
|
||||||
name: 'InterCity, EuroCity, CityNightLine, InterRegio',
|
name: 'InterCity, EuroCity, CityNightLine, InterRegio',
|
||||||
short: 'IC/EC/CNL/IR',
|
short: 'IC/EC/CNL/IR',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'local-train',
|
id: 'local-train',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Nahverkehr',
|
name: 'Nahverkehr',
|
||||||
short: 'Nahv.',
|
short: 'Nahv.',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'suburban',
|
id: 'suburban',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'watercraft',
|
id: 'watercraft',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'Schiff',
|
name: 'Schiff',
|
||||||
short: 'Schiff',
|
short: 'Schiff',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'subway',
|
id: 'subway',
|
||||||
|
@ -53,7 +53,7 @@ const products = [
|
||||||
bitmasks: [128],
|
bitmasks: [128],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -61,7 +61,7 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Tram',
|
name: 'Tram',
|
||||||
short: 'Tram',
|
short: 'Tram',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'dial-a-ride',
|
id: 'dial-a-ride',
|
||||||
|
@ -69,10 +69,10 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Anrufverkehr',
|
name: 'Anrufverkehr',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{ // todo: what is `8`?
|
const products = [{ // todo: what is `8`?
|
||||||
id: 'trains',
|
id: 'trains',
|
||||||
|
@ -75,7 +75,7 @@ const products = [{ // todo: what is `8`?
|
||||||
name: 'Anrufsammeltaxi',
|
name: 'Anrufsammeltaxi',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -88,8 +88,8 @@ const profile = {
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
trip: true,
|
trip: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -21,8 +21,8 @@ const profile = {
|
||||||
trip: true,
|
trip: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
remarks: false, // seems like ver >= 1.20 is required
|
remarks: false, // seems like ver >= 1.20 is required
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@ const products = [
|
||||||
bitmasks: [1, 2, 4],
|
bitmasks: [1, 2, 4],
|
||||||
name: 'long-distance train',
|
name: 'long-distance train',
|
||||||
short: 'ICE/IC/EC',
|
short: 'ICE/IC/EC',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional-train',
|
id: 'regional-train',
|
||||||
|
@ -15,7 +15,7 @@ const products = [
|
||||||
bitmasks: [8, 16],
|
bitmasks: [8, 16],
|
||||||
name: 'regional train',
|
name: 'regional train',
|
||||||
short: 'RE/RB',
|
short: 'RE/RB',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -23,7 +23,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'tram',
|
name: 'tram',
|
||||||
short: 'tram',
|
short: 'tram',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
// todo: what are `64` & `128`?
|
// todo: what are `64` & `128`?
|
||||||
{
|
{
|
||||||
|
@ -32,10 +32,10 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'bus',
|
name: 'bus',
|
||||||
short: 'bus',
|
short: 'bus',
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'train-and-s-bahn',
|
id: 'train-and-s-bahn',
|
||||||
|
@ -75,7 +75,7 @@ const products = [{
|
||||||
name: 'Anrufsammeltaxi',
|
name: 'Anrufsammeltaxi',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -96,8 +96,8 @@ const profile = {
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
trip: true,
|
trip: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
|
|
||||||
const products = [{
|
const products = [{
|
||||||
id: 'ice',
|
id: 'ice',
|
||||||
|
@ -75,7 +75,7 @@ const products = [{
|
||||||
name: 'Anrufverkehr',
|
name: 'Anrufverkehr',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true,
|
default: true,
|
||||||
}]
|
}];
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -89,8 +89,8 @@ const profile = {
|
||||||
radar: true,
|
radar: true,
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -18,8 +18,8 @@ const profile = {
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
refreshJourney: true,
|
refreshJourney: true,
|
||||||
refreshJourneyUseOutReconL: true,
|
refreshJourneyUseOutReconL: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -56,8 +56,8 @@ const products = [
|
||||||
short: 'ICE/IC/EC/EN',
|
short: 'ICE/IC/EC/EN',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// todo: use import assertions once they're supported by Node.js & ESLint
|
// todo: use import assertions once they're supported by Node.js & ESLint
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
import {createRequire} from 'module'
|
import {createRequire} from 'module';
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const baseProfile = require('./base.json')
|
const baseProfile = require('./base.json');
|
||||||
import {products} from './products.js'
|
import {products} from './products.js';
|
||||||
|
|
||||||
const profile = {
|
const profile = {
|
||||||
...baseProfile,
|
...baseProfile,
|
||||||
|
@ -21,8 +21,8 @@ const profile = {
|
||||||
trip: true,
|
trip: true,
|
||||||
radar: true,
|
radar: true,
|
||||||
reachableFrom: true,
|
reachableFrom: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
profile,
|
profile,
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const products = [
|
||||||
bitmasks: [1],
|
bitmasks: [1],
|
||||||
name: 'InterCityExpress',
|
name: 'InterCityExpress',
|
||||||
short: 'ICE',
|
short: 'ICE',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'national',
|
id: 'national',
|
||||||
|
@ -13,7 +13,7 @@ const products = [
|
||||||
bitmasks: [2],
|
bitmasks: [2],
|
||||||
name: 'Fernzug',
|
name: 'Fernzug',
|
||||||
short: 'IC/EC/CNL',
|
short: 'IC/EC/CNL',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regionalExpress',
|
id: 'regionalExpress',
|
||||||
|
@ -21,7 +21,7 @@ const products = [
|
||||||
bitmasks: [4],
|
bitmasks: [4],
|
||||||
name: 'RegionalExpress & InterRegio',
|
name: 'RegionalExpress & InterRegio',
|
||||||
short: 'RE/IR',
|
short: 'RE/IR',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'regional',
|
id: 'regional',
|
||||||
|
@ -29,7 +29,7 @@ const products = [
|
||||||
bitmasks: [8],
|
bitmasks: [8],
|
||||||
name: 'Nahverhehr',
|
name: 'Nahverhehr',
|
||||||
short: 'NV',
|
short: 'NV',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'suburban',
|
id: 'suburban',
|
||||||
|
@ -37,7 +37,7 @@ const products = [
|
||||||
bitmasks: [16],
|
bitmasks: [16],
|
||||||
name: 'S-Bahn',
|
name: 'S-Bahn',
|
||||||
short: 'S',
|
short: 'S',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bus',
|
id: 'bus',
|
||||||
|
@ -45,7 +45,7 @@ const products = [
|
||||||
bitmasks: [32],
|
bitmasks: [32],
|
||||||
name: 'Bus',
|
name: 'Bus',
|
||||||
short: 'Bus',
|
short: 'Bus',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ferry',
|
id: 'ferry',
|
||||||
|
@ -53,7 +53,7 @@ const products = [
|
||||||
bitmasks: [64],
|
bitmasks: [64],
|
||||||
name: 'Schiff',
|
name: 'Schiff',
|
||||||
short: 'F',
|
short: 'F',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'subway',
|
id: 'subway',
|
||||||
|
@ -61,7 +61,7 @@ const products = [
|
||||||
bitmasks: [128],
|
bitmasks: [128],
|
||||||
name: 'U-Bahn',
|
name: 'U-Bahn',
|
||||||
short: 'U',
|
short: 'U',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tram',
|
id: 'tram',
|
||||||
|
@ -69,7 +69,7 @@ const products = [
|
||||||
bitmasks: [256],
|
bitmasks: [256],
|
||||||
name: 'Straßen-/Stadtbahn',
|
name: 'Straßen-/Stadtbahn',
|
||||||
short: 'T',
|
short: 'T',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'anrufSammelTaxi',
|
id: 'anrufSammelTaxi',
|
||||||
|
@ -77,10 +77,10 @@ const products = [
|
||||||
bitmasks: [512],
|
bitmasks: [512],
|
||||||
name: 'Anruf-Sammel-Taxi',
|
name: 'Anruf-Sammel-Taxi',
|
||||||
short: 'AST',
|
short: 'AST',
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export {
|
export {
|
||||||
products,
|
products,
|
||||||
}
|
};
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue