mirror of
https://github.com/public-transport/db-vendo-client.git
synced 2025-02-23 15:19:35 +02:00
deal with some todos, add more
This commit is contained in:
parent
eacbd8ef01
commit
81c9411cfe
10 changed files with 78 additions and 43 deletions
17
index.js
17
index.js
|
@ -73,14 +73,13 @@ const createClient = (profile) => {
|
||||||
viaLocL: opt.via ? [opt.via] : null,
|
viaLocL: opt.via ? [opt.via] : null,
|
||||||
arrLocL: [to],
|
arrLocL: [to],
|
||||||
jnyFltrL: [products],
|
jnyFltrL: [products],
|
||||||
|
getTariff: !!opt.tickets,
|
||||||
|
|
||||||
// todo: what is req.gisFltrL?
|
// todo: what is req.gisFltrL?
|
||||||
// todo: what are all these for?
|
getPT: true, // todo: what is this?
|
||||||
getPT: true,
|
outFrwd: true, // todo: what is this?
|
||||||
outFrwd: true,
|
getIV: false, // todo: walk & bike as alternatives?
|
||||||
getTariff: !!opt.tickets,
|
getPolyline: false // todo: shape for displaying on a map?
|
||||||
getIV: false, // walk & bike as alternatives?
|
|
||||||
getPolyline: false // shape for displaying on a map?
|
|
||||||
}, opt)
|
}, opt)
|
||||||
|
|
||||||
return request(profile, {
|
return request(profile, {
|
||||||
|
@ -193,7 +192,8 @@ const createClient = (profile) => {
|
||||||
opt = Object.assign({
|
opt = Object.assign({
|
||||||
results: 256, // maximum number of vehicles
|
results: 256, // maximum number of vehicles
|
||||||
duration: 30, // compute frames for the next n seconds
|
duration: 30, // compute frames for the next n seconds
|
||||||
frames: 3 // nr of frames to compute
|
frames: 3, // nr of frames to compute
|
||||||
|
products: null // optionally an object of booleans
|
||||||
}, opt || {})
|
}, opt || {})
|
||||||
opt.when = opt.when || new Date()
|
opt.when = opt.when || new Date()
|
||||||
|
|
||||||
|
@ -211,8 +211,7 @@ const createClient = (profile) => {
|
||||||
perStep: Math.round(durationPerStep),
|
perStep: Math.round(durationPerStep),
|
||||||
ageOfReport: true, // todo: what is this?
|
ageOfReport: true, // todo: what is this?
|
||||||
jnyFltrL: [
|
jnyFltrL: [
|
||||||
// todo: use `profile.formatProducts(opt.products || {})`
|
profile.formatProducts(opt.products || {})
|
||||||
{type: 'PROD', mode: 'INC', value: '127'}
|
|
||||||
],
|
],
|
||||||
trainPosMode: 'CALC' // todo: what is this? what about realtime?
|
trainPosMode: 'CALC' // todo: what is this? what about realtime?
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ const types = {
|
||||||
transformReqBody: 'function',
|
transformReqBody: 'function',
|
||||||
transformJourneysQuery: 'function',
|
transformJourneysQuery: 'function',
|
||||||
|
|
||||||
|
products: 'object',
|
||||||
|
|
||||||
parseDateTime: 'function',
|
parseDateTime: 'function',
|
||||||
parseDeparture: 'function',
|
parseDeparture: 'function',
|
||||||
parseJourneyPart: 'function',
|
parseJourneyPart: 'function',
|
||||||
|
@ -37,6 +39,9 @@ const validateProfile = (profile) => {
|
||||||
if (type !== typeof profile[key]) {
|
if (type !== typeof profile[key]) {
|
||||||
throw new Error(`profile.${key} must be a ${type}.`)
|
throw new Error(`profile.${key} must be a ${type}.`)
|
||||||
}
|
}
|
||||||
|
if (type === 'object' && profile[key] === null) {
|
||||||
|
throw new Error(`profile.${key} must not be null.`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,8 @@ const dbProfile = {
|
||||||
transformReq,
|
transformReq,
|
||||||
transformJourneysQuery,
|
transformJourneysQuery,
|
||||||
|
|
||||||
|
products: modes.allProducts,
|
||||||
|
|
||||||
// todo: parseLocation
|
// todo: parseLocation
|
||||||
parseLine,
|
parseLine,
|
||||||
parseProducts: createParseBitmask(modes.bitmasks),
|
parseProducts: createParseBitmask(modes.bitmasks),
|
||||||
|
|
|
@ -91,4 +91,17 @@ m.bitmasks[128] = m.subway
|
||||||
m.bitmasks[256] = m.tram
|
m.bitmasks[256] = m.tram
|
||||||
m.bitmasks[512] = m.taxi
|
m.bitmasks[512] = m.taxi
|
||||||
|
|
||||||
|
m.allProducts = [
|
||||||
|
m.nationalExp,
|
||||||
|
m.national,
|
||||||
|
m.regionalExp,
|
||||||
|
m.regional,
|
||||||
|
m.suburban,
|
||||||
|
m.bus,
|
||||||
|
m.ferry,
|
||||||
|
m.subway,
|
||||||
|
m.tram,
|
||||||
|
m.taxi
|
||||||
|
]
|
||||||
|
|
||||||
module.exports = m
|
module.exports = m
|
||||||
|
|
|
@ -4,10 +4,12 @@ const shorten = require('vbb-short-station-name')
|
||||||
const {to12Digit, to9Digit} = require('vbb-translate-ids')
|
const {to12Digit, to9Digit} = require('vbb-translate-ids')
|
||||||
const parseLineName = require('vbb-parse-line')
|
const parseLineName = require('vbb-parse-line')
|
||||||
const parseTicket = require('vbb-parse-ticket')
|
const parseTicket = require('vbb-parse-ticket')
|
||||||
|
const getStations = require('vbb-stations')
|
||||||
|
|
||||||
const _parseLine = require('../../parse/line')
|
const _parseLine = require('../../parse/line')
|
||||||
const _parseLocation = require('../../parse/location')
|
const _parseLocation = require('../../parse/location')
|
||||||
const _createParseJourney = require('../../parse/journey')
|
const _createParseJourney = require('../../parse/journey')
|
||||||
|
const _createParseStopover = require('../../parse/stopover')
|
||||||
const _formatStation = require('../../format/station')
|
const _formatStation = require('../../format/station')
|
||||||
const createParseBitmask = require('../../parse/products-bitmask')
|
const createParseBitmask = require('../../parse/products-bitmask')
|
||||||
const createFormatBitmask = require('../../format/products-bitmask')
|
const createFormatBitmask = require('../../format/products-bitmask')
|
||||||
|
@ -53,7 +55,10 @@ const parseLocation = (profile, l) => {
|
||||||
if (res.type === 'station') {
|
if (res.type === 'station') {
|
||||||
res.name = shorten(res.name)
|
res.name = shorten(res.name)
|
||||||
res.id = to12Digit(res.id)
|
res.id = to12Digit(res.id)
|
||||||
// todo: https://github.com/derhuerst/vbb-hafas/blob/1c64bfe42422e2648b21016d233c808460250308/lib/parse.js#L67-L75
|
if (!res.location.latitude || !res.location.longitude) {
|
||||||
|
const [s] = getStations(res.id)
|
||||||
|
if (s) Object.assign(res.location, s.coordinates)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -88,6 +93,20 @@ const createParseJourney = (profile, stations, lines, remarks) => {
|
||||||
return parseJourneyWithTickets
|
return parseJourneyWithTickets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createParseStopover = (profile, stations, lines, remarks, connection) => {
|
||||||
|
const parseStopover = _createParseStopover(profile, stations, lines, remarks, connection)
|
||||||
|
|
||||||
|
const parseStopoverWithShorten = (st) => {
|
||||||
|
const res = parseStopover(st)
|
||||||
|
if (res.station && res.station.name) {
|
||||||
|
res.station.name = shorten(res.station.name)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseStopoverWithShorten
|
||||||
|
}
|
||||||
|
|
||||||
const isIBNR = /^\d{9,}$/
|
const isIBNR = /^\d{9,}$/
|
||||||
const formatStation = (id) => {
|
const formatStation = (id) => {
|
||||||
if (!isIBNR.test(id)) throw new Error('station ID must be an IBNR.')
|
if (!isIBNR.test(id)) throw new Error('station ID must be an IBNR.')
|
||||||
|
@ -119,11 +138,14 @@ const vbbProfile = {
|
||||||
endpoint: 'https://fahrinfo.vbb.de/bin/mgate.exe',
|
endpoint: 'https://fahrinfo.vbb.de/bin/mgate.exe',
|
||||||
transformReqBody,
|
transformReqBody,
|
||||||
|
|
||||||
|
products: modes.allProducts,
|
||||||
|
|
||||||
parseStationName: shorten,
|
parseStationName: shorten,
|
||||||
parseLocation,
|
parseLocation,
|
||||||
parseLine,
|
parseLine,
|
||||||
parseProducts: createParseBitmask(modes.bitmasks),
|
parseProducts: createParseBitmask(modes.bitmasks),
|
||||||
parseJourney: createParseJourney,
|
parseJourney: createParseJourney,
|
||||||
|
parseStopover: createParseStopover,
|
||||||
|
|
||||||
formatStation,
|
formatStation,
|
||||||
formatProducts,
|
formatProducts,
|
||||||
|
|
|
@ -95,6 +95,16 @@ m.categories = [
|
||||||
m.unknown
|
m.unknown
|
||||||
]
|
]
|
||||||
|
|
||||||
|
m.allProducts = [
|
||||||
|
m.suburban,
|
||||||
|
m.subway,
|
||||||
|
m.tram,
|
||||||
|
m.bus,
|
||||||
|
m.ferry,
|
||||||
|
m.express,
|
||||||
|
m.regional
|
||||||
|
]
|
||||||
|
|
||||||
// m.parseCategory = (category) => {
|
// m.parseCategory = (category) => {
|
||||||
// return m.categories[parseInt(category)] || m.unknown
|
// return m.categories[parseInt(category)] || m.unknown
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
"slugg": "^1.2.0",
|
"slugg": "^1.2.0",
|
||||||
"vbb-parse-ticket": "^0.2.1",
|
"vbb-parse-ticket": "^0.2.1",
|
||||||
"vbb-short-station-name": "^0.4.0",
|
"vbb-short-station-name": "^0.4.0",
|
||||||
|
"vbb-stations": "^5.8.0",
|
||||||
"vbb-translate-ids": "^3.1.0"
|
"vbb-translate-ids": "^3.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -5,22 +5,6 @@ const parseDateTime = require('./date-time')
|
||||||
const clone = obj => Object.assign({}, obj)
|
const clone = obj => Object.assign({}, obj)
|
||||||
|
|
||||||
const createParseJourneyPart = (profile, stations, lines, remarks) => {
|
const createParseJourneyPart = (profile, stations, lines, remarks) => {
|
||||||
const parseStopover = (j, st) => {
|
|
||||||
const res = {
|
|
||||||
station: stations[parseInt(st.locX)]
|
|
||||||
}
|
|
||||||
if (st.aTimeR || st.aTimeS) {
|
|
||||||
const arr = parseDateTime(profile, j.date, st.aTimeR || st.aTimeS)
|
|
||||||
res.arrival = arr.toISO()
|
|
||||||
}
|
|
||||||
if (st.dTimeR || st.dTimeS) {
|
|
||||||
const dep = parseDateTime(profile, j.date, st.dTimeR || st.dTimeS)
|
|
||||||
res.departure = dep.toISO()
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: finish parse/remark.js first
|
// todo: finish parse/remark.js first
|
||||||
const applyRemark = (j, rm) => {}
|
const applyRemark = (j, rm) => {}
|
||||||
|
|
||||||
|
@ -28,6 +12,7 @@ const createParseJourneyPart = (profile, stations, lines, remarks) => {
|
||||||
// todo: pt.dep.dProgType, pt.arr.dProgType
|
// todo: pt.dep.dProgType, pt.arr.dProgType
|
||||||
// todo: what is pt.jny.dirFlg?
|
// todo: what is pt.jny.dirFlg?
|
||||||
// todo: how does pt.freq work?
|
// todo: how does pt.freq work?
|
||||||
|
// todo: what is pt.himL?
|
||||||
const parseJourneyPart = (j, pt) => { // j = journey, pt = part
|
const parseJourneyPart = (j, pt) => { // j = journey, pt = part
|
||||||
const dep = profile.parseDateTime(profile, j.date, pt.dep.dTimeR || pt.dep.dTimeS)
|
const dep = profile.parseDateTime(profile, j.date, pt.dep.dTimeR || pt.dep.dTimeS)
|
||||||
const arr = profile.parseDateTime(profile, j.date, pt.arr.aTimeR || pt.arr.aTimeS)
|
const arr = profile.parseDateTime(profile, j.date, pt.arr.aTimeR || pt.arr.aTimeS)
|
||||||
|
@ -46,7 +31,9 @@ const createParseJourneyPart = (profile, stations, lines, remarks) => {
|
||||||
|
|
||||||
if (pt.type === 'WALK') {
|
if (pt.type === 'WALK') {
|
||||||
res.mode = 'walking'
|
res.mode = 'walking'
|
||||||
|
res.public = true
|
||||||
} else if (pt.type === 'JNY') {
|
} else if (pt.type === 'JNY') {
|
||||||
|
// todo: pull `public` value from `profile.products`
|
||||||
res.id = pt.jny.jid
|
res.id = pt.jny.jid
|
||||||
res.line = lines[parseInt(pt.jny.prodX)] || null
|
res.line = lines[parseInt(pt.jny.prodX)] || null
|
||||||
res.direction = profile.parseStationName(pt.jny.dirTxt)
|
res.direction = profile.parseStationName(pt.jny.dirTxt)
|
||||||
|
@ -55,7 +42,8 @@ const createParseJourneyPart = (profile, stations, lines, remarks) => {
|
||||||
if (pt.arr.aPlatfS) res.arrivalPlatform = pt.arr.aPlatfS
|
if (pt.arr.aPlatfS) res.arrivalPlatform = pt.arr.aPlatfS
|
||||||
|
|
||||||
if (pt.jny.stopL) {
|
if (pt.jny.stopL) {
|
||||||
res.passed = pt.jny.stopL.map(stopover => parseStopover(j, stopover))
|
const parse = profile.parseStopover(profile, stations, lines, remarks, j)
|
||||||
|
res.passed = pt.jny.stopL.map(parse)
|
||||||
}
|
}
|
||||||
if (Array.isArray(pt.jny.remL)) {
|
if (Array.isArray(pt.jny.remL)) {
|
||||||
for (let remark of pt.jny.remL) applyRemark(j, remark)
|
for (let remark of pt.jny.remL) applyRemark(j, remark)
|
||||||
|
@ -63,8 +51,8 @@ const createParseJourneyPart = (profile, stations, lines, remarks) => {
|
||||||
|
|
||||||
if (pt.jny.freq && pt.jny.freq.jnyL) {
|
if (pt.jny.freq && pt.jny.freq.jnyL) {
|
||||||
const parseAlternative = (a) => {
|
const parseAlternative = (a) => {
|
||||||
// todo: realtime
|
const t = a.stopL[0].dTimeS || a.stopL[0].dTimeR
|
||||||
const when = profile.parseDateTime(profile, j.date, a.stopL[0].dTimeS)
|
const when = profile.parseDateTime(profile, j.date, t)
|
||||||
return {
|
return {
|
||||||
line: lines[parseInt(a.prodX)] || null,
|
line: lines[parseInt(a.prodX)] || null,
|
||||||
when: when.toISO()
|
when: when.toISO()
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
// todo: what is p.number vs p.line?
|
// todo: are p.number and p.line ever different?
|
||||||
// todo: what is p.icoX?
|
// todo: operator from p.oprX?
|
||||||
// todo: what is p.oprX?
|
|
||||||
const parseLine = (profile, p) => {
|
const parseLine = (profile, p) => {
|
||||||
if (!p) return null // todo: handle this upstream
|
if (!p) return null // todo: handle this upstream
|
||||||
const res = {
|
const res = {
|
||||||
|
|
18
test/util.js
18
test/util.js
|
@ -24,12 +24,12 @@ const assertValidPoi = (t, p) => {
|
||||||
t.equal(typeof p.address, 'string')
|
t.equal(typeof p.address, 'string')
|
||||||
t.ok(p.address)
|
t.ok(p.address)
|
||||||
}
|
}
|
||||||
assertValidLocation(t, p, true) // todo: do POIs always have coords?
|
assertValidLocation(t, p, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const assertValidAddress = (t, a) => {
|
const assertValidAddress = (t, a) => {
|
||||||
t.equal(typeof a.address, 'string')
|
t.equal(typeof a.address, 'string')
|
||||||
assertValidLocation(t, a, true) // todo: do addresses always have coords?
|
assertValidLocation(t, a, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const assertValidLocation = (t, l, coordsOptional = false) => {
|
const assertValidLocation = (t, l, coordsOptional = false) => {
|
||||||
|
@ -58,18 +58,15 @@ const assertValidLocation = (t, l, coordsOptional = false) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: https://github.com/public-transport/friendly-public-transport-format/tree/babf2b82947ab0e655a4a0e1cbee6b5519af9172/spec#modes
|
const validLineModes = [
|
||||||
const isValidMode = (m) => {
|
'train', 'bus', 'ferry', 'taxi', 'gondola', 'aircraft',
|
||||||
return m === 'walking' ||
|
'car', 'bicycle', 'walking'
|
||||||
m === 'train' ||
|
]
|
||||||
m === 'bus' ||
|
|
||||||
m === 'ferry'
|
|
||||||
}
|
|
||||||
|
|
||||||
const assertValidLine = (t, l) => {
|
const assertValidLine = (t, l) => {
|
||||||
t.equal(l.type, 'line')
|
t.equal(l.type, 'line')
|
||||||
t.equal(typeof l.name, 'string')
|
t.equal(typeof l.name, 'string')
|
||||||
t.ok(isValidMode(l.mode), 'invalid mode ' + l.mode)
|
t.ok(validLineModes.includes(l.mode), 'invalid mode ' + l.mode)
|
||||||
t.equal(typeof l.product, 'string')
|
t.equal(typeof l.product, 'string')
|
||||||
t.equal(l.public, true)
|
t.equal(l.public, true)
|
||||||
}
|
}
|
||||||
|
@ -140,7 +137,6 @@ module.exports = {
|
||||||
assertValidPoi,
|
assertValidPoi,
|
||||||
assertValidAddress,
|
assertValidAddress,
|
||||||
assertValidLocation,
|
assertValidLocation,
|
||||||
isValidMode,
|
|
||||||
assertValidLine,
|
assertValidLine,
|
||||||
isValidDateTime,
|
isValidDateTime,
|
||||||
assertValidStopover,
|
assertValidStopover,
|
||||||
|
|
Loading…
Add table
Reference in a new issue