mirror of
https://github.com/public-transport/db-vendo-client.git
synced 2025-02-23 07:09:35 +02:00
adapt profiles to ctx-based parse fns
This commit is contained in:
parent
7b7293efea
commit
9fc6664302
13 changed files with 303 additions and 363 deletions
25
lib/profile-hooks.js
Normal file
25
lib/profile-hooks.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
'use strict'
|
||||
|
||||
// For any type of "thing to parse", there's >=1 parse functions.
|
||||
// By composing custom parse function(s) with the default ones, one
|
||||
// can customize the behaviour of hafas-client. Profiles extensively
|
||||
// use this mechanism.
|
||||
|
||||
// Each parse function has the following signature:
|
||||
// ({opt, profile, common, res}, ...raw) => newParsed
|
||||
|
||||
// Compose a new/custom parse function with the old/existing parse
|
||||
// function, so that the new fn will be called with the output of the
|
||||
// old fn.
|
||||
const parseHook = (oldParse, newParse) => {
|
||||
return (ctx, ...args) => {
|
||||
return newParse({
|
||||
...ctx,
|
||||
parsed: oldParse({...ctx, parsed: {}}, ...args)
|
||||
}, ...args)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
parseHook
|
||||
}
|
140
p/bvg/index.js
140
p/bvg/index.js
|
@ -4,16 +4,17 @@ const shorten = require('vbb-short-station-name')
|
|||
const {to12Digit, to9Digit} = require('vbb-translate-ids')
|
||||
const parseLineName = require('vbb-parse-line')
|
||||
const getStations = require('vbb-stations')
|
||||
const {parseHook} = require('../../lib/profile-hooks')
|
||||
|
||||
const _createParseLine = require('../../parse/line')
|
||||
const _parseLine = require('../../parse/line')
|
||||
const _parseLocation = require('../../parse/location')
|
||||
const _createParseDeparture = require('../../parse/departure')
|
||||
const _createParseJourneyLeg = require('../../parse/journey-leg')
|
||||
const _parseDeparture = require('../../parse/departure')
|
||||
const _parseJourneyLeg = require('../../parse/journey-leg')
|
||||
const _formatStation = require('../../format/station')
|
||||
|
||||
const products = require('./products')
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
body.client = {type: 'IPA', id: 'BVG', name: 'FahrInfo', v: '6020000'}
|
||||
body.ext = 'BVG.1'
|
||||
body.ver = '1.21'
|
||||
|
@ -22,89 +23,72 @@ const transformReqBody = (body) => {
|
|||
return body
|
||||
}
|
||||
|
||||
const createParseLine = (profile, opt, data) => {
|
||||
const parseLine = _createParseLine(profile, opt, data)
|
||||
const parseLineWithMoreDetails = ({parsed}, p) => {
|
||||
parsed.name = p.name.replace(/^(bus|tram)\s+/i, '')
|
||||
const details = parseLineName(parsed.name)
|
||||
parsed.symbol = details.symbol
|
||||
parsed.nr = details.nr
|
||||
parsed.metro = details.metro
|
||||
parsed.express = details.express
|
||||
parsed.night = details.night
|
||||
|
||||
const parseLineWithMoreDetails = (l) => {
|
||||
const res = parseLine(l)
|
||||
|
||||
res.name = l.name.replace(/^(bus|tram)\s+/i, '')
|
||||
const details = parseLineName(res.name)
|
||||
res.symbol = details.symbol
|
||||
res.nr = details.nr
|
||||
res.metro = details.metro
|
||||
res.express = details.express
|
||||
res.night = details.night
|
||||
|
||||
return res
|
||||
}
|
||||
return parseLineWithMoreDetails
|
||||
return parsed
|
||||
}
|
||||
|
||||
const parseLocation = (profile, opt, data, l) => {
|
||||
const res = _parseLocation(profile, opt, data, l)
|
||||
|
||||
if (res.type === 'stop' || res.type === 'station') {
|
||||
res.name = shorten(res.name)
|
||||
res.id = to12Digit(res.id)
|
||||
if (!res.location.latitude || !res.location.longitude) {
|
||||
const [s] = getStations(res.id)
|
||||
if (s) Object.assign(res.location, s.location)
|
||||
const parseLocation = ({parsed}, l) => {
|
||||
if (parsed.type === 'stop' || parsed.type === 'station') {
|
||||
parsed.name = shorten(parsed.name)
|
||||
parsed.id = to12Digit(parsed.id)
|
||||
if (!parsed.location.latitude || !parsed.location.longitude) {
|
||||
const [s] = getStations(parsed.id)
|
||||
if (s) Object.assign(parsed.location, s.location)
|
||||
}
|
||||
}
|
||||
return res
|
||||
return parsed
|
||||
}
|
||||
|
||||
const createParseDeparture = (profile, opt, data) => {
|
||||
const parseDeparture = _createParseDeparture(profile, opt, data)
|
||||
|
||||
const ringbahnClockwise = /^ringbahn s\s?41$/i
|
||||
const ringbahnAnticlockwise = /^ringbahn s\s?42$/i
|
||||
const parseDepartureRenameRingbahn = (j) => {
|
||||
const res = parseDeparture(j)
|
||||
|
||||
if (res.line && res.line.product === 'suburban') {
|
||||
const d = res.direction && res.direction.trim()
|
||||
if (ringbahnClockwise.test(d)) res.direction = 'Ringbahn S41 ⟳'
|
||||
else if (ringbahnAnticlockwise.test(d)) res.direction = 'Ringbahn S42 ⟲'
|
||||
const ringbahnClockwise = /^ringbahn s\s?41$/i
|
||||
const ringbahnAnticlockwise = /^ringbahn s\s?42$/i
|
||||
const parseDepartureRenameRingbahn = ({parsed}) => {
|
||||
if (parsed.line && parsed.line.product === 'suburban') {
|
||||
const d = parsed.direction && parsed.direction.trim()
|
||||
if (ringbahnClockwise.test(d)) {
|
||||
parsed.direction = 'Ringbahn S41 ⟳'
|
||||
} else if (ringbahnAnticlockwise.test(d)) {
|
||||
parsed.direction = 'Ringbahn S42 ⟲'
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
return parseDepartureRenameRingbahn
|
||||
return parsed
|
||||
}
|
||||
|
||||
const createParseJourneyLeg = (profile, opt, data) => {
|
||||
const _parseJourneyLeg = _createParseJourneyLeg(profile, opt, data)
|
||||
const parseJourneyLeg = (journey, leg, parseStopovers = true) => {
|
||||
if (leg.type === 'KISS') {
|
||||
const icon = data.icons[leg.icoX]
|
||||
if (icon && icon.type === 'prod_berl') {
|
||||
const res = _parseJourneyLeg(journey, {...leg, type: 'WALK'}, parseStopovers)
|
||||
delete res.walking
|
||||
const parseJourneyLegWithBerlkönig = (ctx, leg, date) => {
|
||||
if (leg.type === 'KISS') {
|
||||
const icon = ctx.common.icons[leg.icoX]
|
||||
if (icon && icon.type === 'prod_berl') {
|
||||
const res = _parseJourneyLeg(ctx, {
|
||||
...leg, type: 'WALK'
|
||||
}, date)
|
||||
delete res.walking
|
||||
|
||||
const mcp = leg.dep.mcp || {}
|
||||
const mcpData = mcp.mcpData || {}
|
||||
// todo: mcp.lid
|
||||
// todo: mcpData.occupancy, mcpData.type
|
||||
// todo: journey.trfRes.bkgData
|
||||
res.line = {
|
||||
type: 'line',
|
||||
id: null, // todo
|
||||
// todo: fahrtNr?
|
||||
name: mcpData.providerName,
|
||||
public: true,
|
||||
mode: 'taxi',
|
||||
product: 'berlkoenig'
|
||||
// todo: operator
|
||||
}
|
||||
return res
|
||||
const mcp = leg.dep.mcp || {}
|
||||
const mcpData = mcp.mcpData || {}
|
||||
// todo: mcp.lid
|
||||
// todo: mcpData.occupancy, mcpData.type
|
||||
// todo: journey.trfRes.bkgData
|
||||
res.line = {
|
||||
type: 'line',
|
||||
id: null, // todo
|
||||
// todo: fahrtNr?
|
||||
name: mcpData.providerName,
|
||||
public: true,
|
||||
mode: 'taxi',
|
||||
product: 'berlkoenig'
|
||||
// todo: operator
|
||||
}
|
||||
return res
|
||||
}
|
||||
return _parseJourneyLeg(journey, leg, parseStopovers)
|
||||
}
|
||||
return parseJourneyLeg
|
||||
return _parseJourneyLeg(ctx, leg, date)
|
||||
}
|
||||
|
||||
const validIBNR = /^\d+$/
|
||||
|
@ -121,7 +105,7 @@ const formatStation = (id) => {
|
|||
}
|
||||
|
||||
// use the Berlkönig ride sharing service?
|
||||
const requestJourneysWithBerlkoenig = (query, opt) => {
|
||||
const requestJourneysWithBerlkoenig = ({opt}, query) => {
|
||||
if (('numF' in query) && opt.berlkoenig) {
|
||||
// todo: check if this is still true
|
||||
throw new Error('The `berlkoenig` and `results` options are mutually exclusive.')
|
||||
|
@ -144,11 +128,11 @@ const bvgProfile = {
|
|||
|
||||
products,
|
||||
|
||||
parseStationName: shorten,
|
||||
parseLocation,
|
||||
parseLine: createParseLine,
|
||||
parseDeparture: createParseDeparture,
|
||||
parseJourneyLeg: createParseJourneyLeg,
|
||||
parseLine: parseHook(_parseLine, parseLineWithMoreDetails),
|
||||
parseLocation: parseHook(_parseLocation, parseLocation),
|
||||
parseStationName: (ctx, name) => shorten(name),
|
||||
parseDeparture: parseHook(_parseDeparture, parseDepartureRenameRingbahn),
|
||||
parseJourneyLeg: parseJourneyLegWithBerlkönig,
|
||||
|
||||
formatStation,
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
const products = require('./products')
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
body.client = {
|
||||
type: 'IPH',
|
||||
id: 'HAFAS',
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
const products = require('./products')
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
body.client = {
|
||||
type: 'IPH',
|
||||
id: 'CMTA',
|
||||
|
|
166
p/db/index.js
166
p/db/index.js
|
@ -1,12 +1,13 @@
|
|||
'use strict'
|
||||
|
||||
const trim = require('lodash/trim')
|
||||
const {parseHook} = require('../../lib/profile-hooks')
|
||||
|
||||
const _createParseArrival = require('../../parse/arrival')
|
||||
const _createParseDeparture = require('../../parse/departure')
|
||||
const _createParseJourney = require('../../parse/journey')
|
||||
const _createParseJourneyLeg = require('../../parse/journey-leg')
|
||||
const _createParseLine = require('../../parse/line')
|
||||
const _parseJourney = require('../../parse/journey')
|
||||
const _parseJourneyLeg = require('../../parse/journey-leg')
|
||||
const _parseLine = require('../../parse/line')
|
||||
const _parseArrival = require('../../parse/arrival')
|
||||
const _parseDeparture = require('../../parse/departure')
|
||||
const _parseHint = require('../../parse/hint')
|
||||
const _formatStation = require('../../format/station')
|
||||
const {bike} = require('../../format/filters')
|
||||
|
@ -14,7 +15,7 @@ const {bike} = require('../../format/filters')
|
|||
const products = require('./products')
|
||||
const formatLoyaltyCard = require('./loyalty-cards').format
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
const req = body.svcReqL[0] || {}
|
||||
|
||||
// see https://pastebin.com/qZ9WS3Cx
|
||||
|
@ -41,24 +42,15 @@ const parseLoadFactor = (opt, tcocL, tcocX) => {
|
|||
return load && loadFactors[load.r] || null
|
||||
}
|
||||
|
||||
const createParseArrOrDep = (createParse) => (profile, opt, data) => {
|
||||
const parse = createParse(profile, opt, data)
|
||||
const parseWithLoadFactor = (d) => {
|
||||
const result = parse(d)
|
||||
if (d.stbStop.dTrnCmpSX && Array.isArray(d.stbStop.dTrnCmpSX.tcocX)) {
|
||||
const {tcocL} = data.common
|
||||
const load = parseLoadFactor(opt, tcocL, d.stbStop.dTrnCmpSX.tcocX)
|
||||
if (load) result.loadFactor = load
|
||||
}
|
||||
return result
|
||||
const parseArrOrDepWithLoadFactor = ({parsed, res, opt}, d) => {
|
||||
if (d.stbStop.dTrnCmpSX && Array.isArray(d.stbStop.dTrnCmpSX.tcocX)) {
|
||||
const load = parseLoadFactor(opt, res.common.tcocL || [], d.stbStop.dTrnCmpSX.tcocX)
|
||||
if (load) parsed.loadFactor = load
|
||||
}
|
||||
return parseWithLoadFactor
|
||||
return parsed
|
||||
}
|
||||
|
||||
const createParseArrival = createParseArrOrDep(_createParseArrival)
|
||||
const createParseDeparture = createParseArrOrDep(_createParseDeparture)
|
||||
|
||||
const transformJourneysQuery = (query, opt) => {
|
||||
const transformJourneysQuery = ({opt}, query) => {
|
||||
const filters = query.jnyFltrL
|
||||
if (opt.bike) filters.push(bike)
|
||||
|
||||
|
@ -76,76 +68,58 @@ const transformJourneysQuery = (query, opt) => {
|
|||
return query
|
||||
}
|
||||
|
||||
const createParseLine = (profile, opt, data) => {
|
||||
const parseLine = _createParseLine(profile, opt, data)
|
||||
const parseLineWithAdditionalName = (l) => {
|
||||
const res = parseLine(l)
|
||||
if (l.nameS && ['bus', 'tram', 'ferry'].includes(res.product)) {
|
||||
res.name = l.nameS
|
||||
}
|
||||
if (l.addName) {
|
||||
res.additionalName = res.name
|
||||
res.name = l.addName
|
||||
}
|
||||
return res
|
||||
const parseLineWithAdditionalName = ({parsed}, l) => {
|
||||
if (l.nameS && ['bus', 'tram', 'ferry'].includes(l.product)) {
|
||||
parsed.name = l.nameS
|
||||
}
|
||||
return parseLineWithAdditionalName
|
||||
if (l.addName) {
|
||||
parsed.additionalName = parsed.name
|
||||
parsed.name = l.addName
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
const createParseJourney = (profile, opt, data) => {
|
||||
const parseJourney = _createParseJourney(profile, opt, data)
|
||||
|
||||
// todo: j.sotRating, j.conSubscr, j.isSotCon, j.showARSLink, k.sotCtxt
|
||||
// todo: j.conSubscr, j.showARSLink, j.useableTime
|
||||
const parseJourneyWithPrice = (j) => {
|
||||
const res = parseJourney(j)
|
||||
|
||||
res.price = null
|
||||
// todo: find cheapest, find discounts
|
||||
// todo: write a parser like vbb-parse-ticket
|
||||
// [ {
|
||||
// prc: 15000,
|
||||
// isFromPrice: true,
|
||||
// isBookable: true,
|
||||
// isUpsell: false,
|
||||
// targetCtx: 'D',
|
||||
// buttonText: 'To offer selection'
|
||||
// } ]
|
||||
if (
|
||||
j.trfRes &&
|
||||
Array.isArray(j.trfRes.fareSetL) &&
|
||||
j.trfRes.fareSetL[0] &&
|
||||
Array.isArray(j.trfRes.fareSetL[0].fareL) &&
|
||||
j.trfRes.fareSetL[0].fareL[0]
|
||||
) {
|
||||
const tariff = j.trfRes.fareSetL[0].fareL[0]
|
||||
if (tariff.prc >= 0) { // wat
|
||||
res.price = {
|
||||
amount: tariff.prc / 100,
|
||||
currency: 'EUR',
|
||||
hint: null
|
||||
}
|
||||
// todo: sotRating, conSubscr, isSotCon, showARSLink, sotCtxt
|
||||
// todo: conSubscr, showARSLink, useableTime
|
||||
const parseJourneyWithPrice = ({parsed}, raw) => {
|
||||
parsed.price = null
|
||||
// todo: find cheapest, find discounts
|
||||
// todo: write a parser like vbb-parse-ticket
|
||||
// [ {
|
||||
// prc: 15000,
|
||||
// isFromPrice: true,
|
||||
// isBookable: true,
|
||||
// isUpsell: false,
|
||||
// targetCtx: 'D',
|
||||
// buttonText: 'To offer selection'
|
||||
// } ]
|
||||
if (
|
||||
raw.trfRes &&
|
||||
Array.isArray(raw.trfRes.fareSetL) &&
|
||||
raw.trfRes.fareSetL[0] &&
|
||||
Array.isArray(raw.trfRes.fareSetL[0].fareL) &&
|
||||
raw.trfRes.fareSetL[0].fareL[0]
|
||||
) {
|
||||
const tariff = raw.trfRes.fareSetL[0].fareL[0]
|
||||
if (tariff.prc >= 0) { // wat
|
||||
parsed.price = {
|
||||
amount: tariff.prc / 100,
|
||||
currency: 'EUR',
|
||||
hint: null
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
return parseJourneyWithPrice
|
||||
return parsed
|
||||
}
|
||||
|
||||
const createParseJourneyLeg = (profile, opt, data) => {
|
||||
const parseJourneyLeg = _createParseJourneyLeg(profile, opt, data)
|
||||
const parseJourneyLegWithLoadFactor = (j, pt, parseStopovers) => {
|
||||
const result = parseJourneyLeg(j, pt, parseStopovers)
|
||||
if (pt.jny && pt.jny.dTrnCmpSX && Array.isArray(pt.jny.dTrnCmpSX.tcocX)) {
|
||||
const {tcocL} = data.common
|
||||
const load = parseLoadFactor(opt, tcocL, pt.jny.dTrnCmpSX.tcocX)
|
||||
if (load) result.loadFactor = load
|
||||
}
|
||||
return result
|
||||
const parseJourneyLegWithLoadFactor = ({parsed, res, opt}, raw) => {
|
||||
const tcocX = raw.jny && raw.jny.dTrnCmpSX && raw.jny.dTrnCmpSX.tcocX
|
||||
if (Array.isArray(tcocX) && Array.isArray(res.tcocL)) {
|
||||
const load = parseLoadFactor(opt, res.tcocL, tcocX)
|
||||
if (load) parsed.loadFactor = load
|
||||
}
|
||||
return parseJourneyLegWithLoadFactor
|
||||
return parsed
|
||||
}
|
||||
|
||||
// todo:
|
||||
|
@ -349,20 +323,20 @@ const codesByText = Object.assign(Object.create(null), {
|
|||
'platform change': 'changed platform', // todo: use dash, German variant
|
||||
})
|
||||
|
||||
const parseHint = (profile, h, icons) => {
|
||||
if (h.type === 'A') {
|
||||
const hint = hintsByCode[h.code && h.code.trim().toLowerCase()]
|
||||
const parseHintByCode = ({parsed}, raw) => {
|
||||
if (raw.type === 'A') {
|
||||
const hint = hintsByCode[raw.code && raw.code.trim().toLowerCase()]
|
||||
if (hint) {
|
||||
return Object.assign({text: h.txtN}, hint)
|
||||
return Object.assign({text: raw.txtN}, hint)
|
||||
}
|
||||
}
|
||||
|
||||
const res = _parseHint(profile, h, icons)
|
||||
if (res && h.txtN) {
|
||||
const text = trim(h.txtN.toLowerCase(), ' ()')
|
||||
if (codesByText[text]) res.code = codesByText[text]
|
||||
if (parsed && raw.txtN) {
|
||||
const text = trim(raw.txtN.toLowerCase(), ' ()')
|
||||
if (codesByText[text]) parsed.code = codesByText[text]
|
||||
}
|
||||
return res
|
||||
|
||||
return parsed
|
||||
}
|
||||
|
||||
const isIBNR = /^\d{6,}$/
|
||||
|
@ -387,12 +361,12 @@ const dbProfile = {
|
|||
products: products,
|
||||
|
||||
// todo: parseLocation
|
||||
parseJourney: createParseJourney,
|
||||
parseJourneyLeg: createParseJourneyLeg,
|
||||
parseLine: createParseLine,
|
||||
parseArrival: createParseArrival,
|
||||
parseDeparture: createParseDeparture,
|
||||
parseHint,
|
||||
parseJourney: parseHook(_parseJourney, parseJourneyWithPrice),
|
||||
parseJourneyLeg: parseHook(_parseJourneyLeg, parseJourneyLegWithLoadFactor),
|
||||
parseLine: parseHook(_parseLine, parseLineWithAdditionalName),
|
||||
parseArrival: parseHook(_parseArrival, parseArrOrDepWithLoadFactor),
|
||||
parseDeparture: parseHook(_parseDeparture, parseArrOrDepWithLoadFactor),
|
||||
parseHint: parseHook(_parseHint, parseHintByCode),
|
||||
|
||||
formatStation,
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
const products = require('./products')
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
body.client = {type: 'AND', id: 'HVV', name: 'HVVPROD_ADHOC', v: '4020100'}
|
||||
body.ext = 'HVV.1'
|
||||
body.ver = '1.16'
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
const products = require('./products')
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
body.client = {
|
||||
type: 'IPH',
|
||||
id: 'NASA',
|
||||
|
|
105
p/nahsh/index.js
105
p/nahsh/index.js
|
@ -1,14 +1,15 @@
|
|||
'use strict'
|
||||
|
||||
const _parseLocation = require('../../parse/location')
|
||||
const _createParseJourney = require('../../parse/journey')
|
||||
const _createParseMovement = require('../../parse/movement')
|
||||
const {parseHook} = require('../../lib/profile-hooks')
|
||||
|
||||
const _parseLocation = require('../../parse/location')
|
||||
const _parseJourney = require('../../parse/journey')
|
||||
const _parseMovement = require('../../parse/movement')
|
||||
const products = require('./products')
|
||||
|
||||
// todo: journey prices
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
body.client = {
|
||||
id: 'NAHSH',
|
||||
name: 'NAHSHPROD',
|
||||
|
@ -21,74 +22,60 @@ const transformReqBody = (body) => {
|
|||
return body
|
||||
}
|
||||
|
||||
const parseLocation = (profile, opt, data, l) => {
|
||||
const res = _parseLocation(profile, opt, data, l)
|
||||
const fixLocation = ({parsed}, l) => {
|
||||
// weird fix for empty lines, e.g. IC/EC at Flensburg Hbf
|
||||
if (res.lines) {
|
||||
res.lines = res.lines.filter(x => x.id && x.name)
|
||||
if (parsed.lines) {
|
||||
parsed.lines = parsed.lines.filter(x => x.id && x.name)
|
||||
}
|
||||
|
||||
// remove leading zeroes, todo
|
||||
if (res.id && res.id.length > 0) {
|
||||
res.id = res.id.replace(/^0+/, '')
|
||||
if (parsed.id && parsed.id.length > 0) {
|
||||
parsed.id = parsed.id.replace(/^0+/, '')
|
||||
}
|
||||
|
||||
return res
|
||||
return parsed
|
||||
}
|
||||
|
||||
const createParseJourney = (profile, opt, data) => {
|
||||
const parseJourney = _createParseJourney(profile, opt, data)
|
||||
const parseJourneyWithTickets = ({parsed}, j) => {
|
||||
if (
|
||||
j.trfRes &&
|
||||
Array.isArray(j.trfRes.fareSetL) &&
|
||||
j.trfRes.fareSetL.length > 0
|
||||
) {
|
||||
parsed.tickets = []
|
||||
|
||||
const parseJourneyWithTickets = (j) => {
|
||||
const res = parseJourney(j)
|
||||
|
||||
if (
|
||||
j.trfRes &&
|
||||
Array.isArray(j.trfRes.fareSetL) &&
|
||||
j.trfRes.fareSetL.length > 0
|
||||
) {
|
||||
res.tickets = []
|
||||
|
||||
for (let t of j.trfRes.fareSetL) {
|
||||
const tariff = t.desc
|
||||
if (!tariff || !Array.isArray(t.fareL)) continue
|
||||
for (let v of t.fareL) {
|
||||
const variant = v.name
|
||||
if(!variant) continue
|
||||
const ticket = {
|
||||
name: [tariff, variant].join(' - '),
|
||||
tariff,
|
||||
variant
|
||||
}
|
||||
if (v.prc && Number.isInteger(v.prc) && v.cur) {
|
||||
ticket.amount = v.prc/100
|
||||
ticket.currency = v.cur
|
||||
} else {
|
||||
ticket.amount = null
|
||||
ticket.hint = 'No pricing information available.'
|
||||
}
|
||||
res.tickets.push(ticket)
|
||||
for (let t of j.trfRes.fareSetL) {
|
||||
const tariff = t.desc
|
||||
if (!tariff || !Array.isArray(t.fareL)) continue
|
||||
for (let v of t.fareL) {
|
||||
const variant = v.name
|
||||
if(!variant) continue
|
||||
const ticket = {
|
||||
name: [tariff, variant].join(' - '),
|
||||
tariff,
|
||||
variant
|
||||
}
|
||||
if (v.prc && Number.isInteger(v.prc) && v.cur) {
|
||||
ticket.amount = v.prc/100
|
||||
ticket.currency = v.cur
|
||||
} else {
|
||||
ticket.amount = null
|
||||
ticket.hint = 'No pricing information available.'
|
||||
}
|
||||
parsed.tickets.push(ticket)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
return parseJourneyWithTickets
|
||||
return parsed
|
||||
}
|
||||
|
||||
const createParseMovement = (profile, opt, data) => {
|
||||
const _parseMovement = _createParseMovement(profile, opt, data)
|
||||
const parseMovement = (m) => {
|
||||
const res = _parseMovement(m)
|
||||
// filter out empty nextStopovers entries
|
||||
res.nextStopovers = res.nextStopovers.filter((f) => {
|
||||
return f.stop !== null || f.arrival !== null || f.departure !== null
|
||||
})
|
||||
return res
|
||||
}
|
||||
return parseMovement
|
||||
const fixMovement = ({parsed}, m) => {
|
||||
// filter out empty nextStopovers entries
|
||||
parsed.nextStopovers = parsed.nextStopovers.filter((f) => {
|
||||
return f.stop !== null || f.arrival !== null || f.departure !== null
|
||||
})
|
||||
return parsed
|
||||
}
|
||||
|
||||
const nahshProfile = {
|
||||
|
@ -99,9 +86,9 @@ const nahshProfile = {
|
|||
|
||||
products,
|
||||
|
||||
parseLocation,
|
||||
parseJourney: createParseJourney,
|
||||
parseMovement: createParseMovement,
|
||||
parseLocation: parseHook(_parseLocation, fixLocation),
|
||||
parseJourney: parseHook(_parseJourney, parseJourneyWithTickets),
|
||||
parseMovement: parseHook(_parseMovement, fixMovement),
|
||||
|
||||
trip: true,
|
||||
radar: true, // todo: see #34
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
const products = require('./products')
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
body.client = {
|
||||
type: 'IPH',
|
||||
id: 'NVV',
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
// 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
|
||||
|
||||
const _parseLocation = require('../../parse/location')
|
||||
const _createParseMovement = require('../../parse/movement')
|
||||
const {parseHook} = require('../../lib/profile-hooks')
|
||||
|
||||
const _parseLocation = require('../../parse/location')
|
||||
const _parseMovement = require('../../parse/movement')
|
||||
const products = require('./products')
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
// todo: necessary headers?
|
||||
body.client = {
|
||||
type: 'IPA',
|
||||
|
@ -25,46 +26,40 @@ const transformReqBody = (body) => {
|
|||
return body
|
||||
}
|
||||
|
||||
const parseLocation = (profile, opt, data, l) => {
|
||||
// ÖBB has some 'stations' **in austria** with no departures/products,
|
||||
// like station entrances, that are actually POIs.
|
||||
const res = _parseLocation(profile, opt, data, l)
|
||||
// ÖBB has some 'stations' **in austria** with no departures/products,
|
||||
// like station entrances, that are actually POIs.
|
||||
const fixWeirdPOIs = ({parsed}) => {
|
||||
if (
|
||||
(res.type === 'station' || res.type === 'stop') &&
|
||||
!res.products &&
|
||||
res.name &&
|
||||
res.id && res.id.length !== 7
|
||||
(parsed.type === 'station' || parsed.type === 'stop') &&
|
||||
!parsed.products &&
|
||||
parsed.name &&
|
||||
parsed.id && parsed.id.length !== 7
|
||||
) {
|
||||
return Object.assign({
|
||||
type: 'location',
|
||||
id: res.id,
|
||||
id: parsed.id,
|
||||
poi: true,
|
||||
name: res.name
|
||||
}, res.location)
|
||||
name: parsed.name
|
||||
}, parsed.location)
|
||||
}
|
||||
return res
|
||||
return parsed
|
||||
}
|
||||
|
||||
const createParseMovement = (profile, opt, data) => {
|
||||
const _parseMovement = _createParseMovement(profile, opt, data)
|
||||
const parseMovement = (m) => {
|
||||
const res = _parseMovement(m)
|
||||
// filter out POIs
|
||||
// todo: make use of them, as some of them specify fare zones
|
||||
res.nextStopovers = res.nextStopovers.filter(st => {
|
||||
const s = st.stop || {}
|
||||
if (s.station) {
|
||||
s = s.station
|
||||
if (s.station.type === 'stop' || s.station.type === 'station') return true
|
||||
}
|
||||
return s.type === 'stop' || s.type === 'station'
|
||||
})
|
||||
res.frames = res.frames.filter((f) => {
|
||||
return f.origin.type !== 'location' && f.destination.type !== 'location'
|
||||
})
|
||||
return res
|
||||
}
|
||||
return parseMovement
|
||||
const fixMovement = ({parsed}, m) => {
|
||||
// filter out POIs
|
||||
// todo: make use of them, as some of them specify fare zones
|
||||
parsed.nextStopovers = parsed.nextStopovers.filter(st => {
|
||||
const s = st.stop || {}
|
||||
if (s.station) {
|
||||
s = s.station
|
||||
if (s.station.type === 'stop' || s.station.type === 'station') return true
|
||||
}
|
||||
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 oebbProfile = {
|
||||
|
@ -76,8 +71,8 @@ const oebbProfile = {
|
|||
|
||||
products: products,
|
||||
|
||||
parseLocation,
|
||||
parseMovement: createParseMovement,
|
||||
parseLocation: parseHook(_parseLocation, fixWeirdPOIs),
|
||||
parseMovement: parseHook(_parseMovement, fixMovement),
|
||||
|
||||
journeysNumF: false,
|
||||
trip: true,
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
'use strict'
|
||||
|
||||
const _createParseMovement = require('../../parse/movement')
|
||||
const {parseHook} = require('../../lib/profile-hooks')
|
||||
|
||||
const _parseMovement = require('../../parse/movement')
|
||||
const products = require('./products')
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
body.client = {
|
||||
type: 'AND',
|
||||
id: 'ZPS-SAAR',
|
||||
|
@ -18,15 +20,10 @@ const transformReqBody = (body) => {
|
|||
return body
|
||||
}
|
||||
|
||||
const createParseMovement = (profile, opt, data) => {
|
||||
const _parseMovement = _createParseMovement(profile, opt, data)
|
||||
const parseMovement = (m) => {
|
||||
const res = _parseMovement(m)
|
||||
// filter out empty stopovers
|
||||
res.nextStopovers = res.nextStopovers.filter(st => !!st.stop)
|
||||
return res
|
||||
}
|
||||
return parseMovement
|
||||
const fixMovement = ({parsed}, m) => {
|
||||
// filter out empty stopovers
|
||||
parsed.nextStopovers = parsed.nextStopovers.filter(st => !!st.stop)
|
||||
return parsed
|
||||
}
|
||||
|
||||
const saarfahrplanProfile = {
|
||||
|
@ -41,7 +38,7 @@ const saarfahrplanProfile = {
|
|||
|
||||
products: products,
|
||||
|
||||
parseMovement: createParseMovement,
|
||||
parseMovement: parseHook(_parseMovement, fixMovement),
|
||||
|
||||
departuresGetPasslist: false,
|
||||
departuresStbFltrEquiv: false,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
const products = require('./products')
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
body.client = {type: 'IPH', id: 'DB-REGIO-MVV', name: 'MuenchenNavigator', v: '5010100'}
|
||||
body.ext = 'DB.R15.12.a'
|
||||
body.ver = '1.18'
|
||||
|
|
128
p/vbb/index.js
128
p/vbb/index.js
|
@ -5,16 +5,17 @@ const {to12Digit, to9Digit} = require('vbb-translate-ids')
|
|||
const parseLineName = require('vbb-parse-line')
|
||||
const parseTicket = require('vbb-parse-ticket')
|
||||
const getStations = require('vbb-stations')
|
||||
const {parseHook} = require('../../lib/profile-hooks')
|
||||
|
||||
const _createParseLine = require('../../parse/line')
|
||||
const _parseLine = require('../../parse/line')
|
||||
const _parseLocation = require('../../parse/location')
|
||||
const _createParseJourney = require('../../parse/journey')
|
||||
const _createParseDeparture = require('../../parse/departure')
|
||||
const _parseJourney = require('../../parse/journey')
|
||||
const _parseDeparture = require('../../parse/departure')
|
||||
const _formatStation = require('../../format/station')
|
||||
|
||||
const products = require('./products')
|
||||
|
||||
const transformReqBody = (body) => {
|
||||
const transformReqBody = (ctx, body) => {
|
||||
body.client = {type: 'IPA', id: 'VBB', name: 'vbbPROD', v: '4010300'}
|
||||
body.ext = 'VBB.1'
|
||||
body.ver = '1.16'
|
||||
|
@ -23,87 +24,64 @@ const transformReqBody = (body) => {
|
|||
return body
|
||||
}
|
||||
|
||||
const createParseLine = (profile, opt, data) => {
|
||||
const parseLine = _createParseLine(profile, opt, data)
|
||||
const parseLineWithMoreDetails = ({parsed}, p) => {
|
||||
parsed.name = p.name.replace(/^(bus|tram)\s+/i, '')
|
||||
const details = parseLineName(parsed.name)
|
||||
parsed.symbol = details.symbol
|
||||
parsed.nr = details.nr
|
||||
parsed.metro = details.metro
|
||||
parsed.express = details.express
|
||||
parsed.night = details.night
|
||||
|
||||
const parseLineWithMoreDetails = (l) => {
|
||||
const res = parseLine(l)
|
||||
|
||||
res.name = l.name.replace(/^(bus|tram)\s+/i, '')
|
||||
const details = parseLineName(res.name)
|
||||
res.symbol = details.symbol
|
||||
res.nr = details.nr
|
||||
res.metro = details.metro
|
||||
res.express = details.express
|
||||
res.night = details.night
|
||||
|
||||
return res
|
||||
}
|
||||
return parseLineWithMoreDetails
|
||||
return parsed
|
||||
}
|
||||
|
||||
const parseLocation = (profile, opt, data, l) => {
|
||||
const res = _parseLocation(profile, opt, data, l)
|
||||
|
||||
if (res.type === 'stop' || res.type === 'station') {
|
||||
res.name = shorten(res.name)
|
||||
res.id = to12Digit(res.id)
|
||||
if (!res.location.latitude || !res.location.longitude) {
|
||||
const [s] = getStations(res.id)
|
||||
if (s) Object.assign(res.location, s.location)
|
||||
const parseLocation = ({parsed}, l) => {
|
||||
if (parsed.type === 'stop' || parsed.type === 'station') {
|
||||
parsed.name = shorten(parsed.name)
|
||||
parsed.id = to12Digit(parsed.id)
|
||||
if (!parsed.location.latitude || !parsed.location.longitude) {
|
||||
const [s] = getStations(parsed.id)
|
||||
if (s) Object.assign(parsed.location, s.location)
|
||||
}
|
||||
}
|
||||
return res
|
||||
return parsed
|
||||
}
|
||||
|
||||
const createParseJourney = (profile, opt, data) => {
|
||||
const parseJourney = _createParseJourney(profile, opt, data)
|
||||
|
||||
const parseJourneyWithTickets = (j) => {
|
||||
const res = parseJourney(j)
|
||||
|
||||
if (
|
||||
j.trfRes &&
|
||||
Array.isArray(j.trfRes.fareSetL) &&
|
||||
j.trfRes.fareSetL[0] &&
|
||||
Array.isArray(j.trfRes.fareSetL[0].fareL)
|
||||
) {
|
||||
res.tickets = []
|
||||
const sets = j.trfRes.fareSetL[0].fareL
|
||||
for (let s of sets) {
|
||||
if (!Array.isArray(s.ticketL) || s.ticketL.length === 0) continue
|
||||
for (let t of s.ticketL) {
|
||||
const ticket = parseTicket(t)
|
||||
ticket.name = s.name + ' – ' + ticket.name
|
||||
res.tickets.push(ticket)
|
||||
}
|
||||
const parseJourneyWithTickets = ({parsed}, j) => {
|
||||
if (
|
||||
j.trfRes &&
|
||||
Array.isArray(j.trfRes.fareSetL) &&
|
||||
j.trfRes.fareSetL[0] &&
|
||||
Array.isArray(j.trfRes.fareSetL[0].fareL)
|
||||
) {
|
||||
parsed.tickets = []
|
||||
const sets = j.trfRes.fareSetL[0].fareL
|
||||
for (let s of sets) {
|
||||
if (!Array.isArray(s.ticketL) || s.ticketL.length === 0) continue
|
||||
for (let t of s.ticketL) {
|
||||
const ticket = parseTicket(t)
|
||||
ticket.name = s.name + ' – ' + ticket.name
|
||||
parsed.tickets.push(ticket)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
return parseJourneyWithTickets
|
||||
return parsed
|
||||
}
|
||||
|
||||
const createParseDeparture = (profile, opt, data) => {
|
||||
const parseDeparture = _createParseDeparture(profile, opt, data)
|
||||
|
||||
const ringbahnClockwise = /^ringbahn s\s?41$/i
|
||||
const ringbahnAnticlockwise = /^ringbahn s\s?42$/i
|
||||
const parseDepartureRenameRingbahn = (j) => {
|
||||
const res = parseDeparture(j)
|
||||
|
||||
if (res.line && res.line.product === 'suburban') {
|
||||
const d = res.direction && res.direction.trim()
|
||||
if (ringbahnClockwise.test(d)) res.direction = 'Ringbahn S41 ⟳'
|
||||
else if (ringbahnAnticlockwise.test(d)) res.direction = 'Ringbahn S42 ⟲'
|
||||
const ringbahnClockwise = /^ringbahn s\s?41$/i
|
||||
const ringbahnAnticlockwise = /^ringbahn s\s?42$/i
|
||||
const parseDepartureRenameRingbahn = ({parsed}) => {
|
||||
if (parsed.line && parsed.line.product === 'suburban') {
|
||||
const d = parsed.direction && parsed.direction.trim()
|
||||
if (ringbahnClockwise.test(d)) {
|
||||
parsed.direction = 'Ringbahn S41 ⟳'
|
||||
} else if (ringbahnAnticlockwise.test(d)) {
|
||||
parsed.direction = 'Ringbahn S42 ⟲'
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
return parseDepartureRenameRingbahn
|
||||
return parsed
|
||||
}
|
||||
|
||||
const validIBNR = /^\d+$/
|
||||
|
@ -133,11 +111,11 @@ const vbbProfile = {
|
|||
|
||||
products: products,
|
||||
|
||||
parseStationName: shorten,
|
||||
parseLocation,
|
||||
parseLine: createParseLine,
|
||||
parseJourney: createParseJourney,
|
||||
parseDeparture: createParseDeparture,
|
||||
parseLine: parseHook(_parseLine, parseLineWithMoreDetails),
|
||||
parseLocation: parseHook(_parseLocation, parseLocation),
|
||||
parseStationName: (ctx, name) => shorten(name),
|
||||
parseJourney: parseHook(_parseJourney, parseJourneyWithTickets),
|
||||
parseDeparture: parseHook(_parseDeparture, parseDepartureRenameRingbahn),
|
||||
|
||||
formatStation,
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue