From 9fc666430217aca6d8345ec4fcca356009e28f5c Mon Sep 17 00:00:00 2001 From: Jannis R Date: Sun, 20 Oct 2019 00:19:52 +0200 Subject: [PATCH] adapt profiles to ctx-based parse fns --- lib/profile-hooks.js | 25 ++++++ p/bvg/index.js | 140 ++++++++++++++------------------ p/cfl/index.js | 2 +- p/cmta/index.js | 2 +- p/db/index.js | 166 ++++++++++++++++---------------------- p/hvv/index.js | 2 +- p/insa/index.js | 2 +- p/nahsh/index.js | 105 +++++++++++------------- p/nvv/index.js | 2 +- p/oebb/index.js | 69 ++++++++-------- p/saarfahrplan/index.js | 21 +++-- p/sbahn-muenchen/index.js | 2 +- p/vbb/index.js | 128 ++++++++++++----------------- 13 files changed, 303 insertions(+), 363 deletions(-) create mode 100644 lib/profile-hooks.js diff --git a/lib/profile-hooks.js b/lib/profile-hooks.js new file mode 100644 index 00000000..dd6a8089 --- /dev/null +++ b/lib/profile-hooks.js @@ -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 +} diff --git a/p/bvg/index.js b/p/bvg/index.js index f18e027c..a37f5463 100644 --- a/p/bvg/index.js +++ b/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, diff --git a/p/cfl/index.js b/p/cfl/index.js index dc165959..951fe76a 100644 --- a/p/cfl/index.js +++ b/p/cfl/index.js @@ -2,7 +2,7 @@ const products = require('./products') -const transformReqBody = (body) => { +const transformReqBody = (ctx, body) => { body.client = { type: 'IPH', id: 'HAFAS', diff --git a/p/cmta/index.js b/p/cmta/index.js index 949fb4d3..8e010955 100644 --- a/p/cmta/index.js +++ b/p/cmta/index.js @@ -2,7 +2,7 @@ const products = require('./products') -const transformReqBody = (body) => { +const transformReqBody = (ctx, body) => { body.client = { type: 'IPH', id: 'CMTA', diff --git a/p/db/index.js b/p/db/index.js index abcbf33c..2435f4ff 100644 --- a/p/db/index.js +++ b/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, diff --git a/p/hvv/index.js b/p/hvv/index.js index cafb3337..0da37f6e 100644 --- a/p/hvv/index.js +++ b/p/hvv/index.js @@ -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' diff --git a/p/insa/index.js b/p/insa/index.js index 441ee68b..17aa7262 100644 --- a/p/insa/index.js +++ b/p/insa/index.js @@ -2,7 +2,7 @@ const products = require('./products') -const transformReqBody = (body) => { +const transformReqBody = (ctx, body) => { body.client = { type: 'IPH', id: 'NASA', diff --git a/p/nahsh/index.js b/p/nahsh/index.js index ad6fb562..29662797 100644 --- a/p/nahsh/index.js +++ b/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 diff --git a/p/nvv/index.js b/p/nvv/index.js index 8ebfaca8..64cca155 100644 --- a/p/nvv/index.js +++ b/p/nvv/index.js @@ -2,7 +2,7 @@ const products = require('./products') -const transformReqBody = (body) => { +const transformReqBody = (ctx, body) => { body.client = { type: 'IPH', id: 'NVV', diff --git a/p/oebb/index.js b/p/oebb/index.js index 54e62058..93a0f279 100644 --- a/p/oebb/index.js +++ b/p/oebb/index.js @@ -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, diff --git a/p/saarfahrplan/index.js b/p/saarfahrplan/index.js index d1580af0..1be1b9cc 100644 --- a/p/saarfahrplan/index.js +++ b/p/saarfahrplan/index.js @@ -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, diff --git a/p/sbahn-muenchen/index.js b/p/sbahn-muenchen/index.js index da77b5d5..4b6ed9f1 100644 --- a/p/sbahn-muenchen/index.js +++ b/p/sbahn-muenchen/index.js @@ -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' diff --git a/p/vbb/index.js b/p/vbb/index.js index b7b98fcd..c3adbf4c 100644 --- a/p/vbb/index.js +++ b/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,