mirror of
https://github.com/public-transport/db-vendo-client.git
synced 2025-02-23 07:09:35 +02:00
parseProductsBitmask via profile, pass ctx into parse fns 💥
This commit is contained in:
parent
29d7bd4299
commit
fb7a5653e3
30 changed files with 501 additions and 487 deletions
4
index.js
4
index.js
|
@ -7,7 +7,6 @@ const sortBy = require('lodash/sortBy')
|
|||
const pRetry = require('p-retry')
|
||||
|
||||
const defaultProfile = require('./lib/default-profile')
|
||||
const createParseBitmask = require('./parse/products-bitmask')
|
||||
const createFormatProductsFilter = require('./format/products-filter')
|
||||
const validateProfile = require('./lib/validate-profile')
|
||||
const _request = require('./lib/request')
|
||||
|
@ -32,9 +31,6 @@ const defaults = {
|
|||
|
||||
const createClient = (profile, userAgent, opt = {}) => {
|
||||
profile = Object.assign({}, defaultProfile, profile)
|
||||
if (!profile.parseProducts) {
|
||||
profile.parseProducts = createParseBitmask(profile)
|
||||
}
|
||||
if (!profile.formatProductsFilter) {
|
||||
profile.formatProductsFilter = createFormatProductsFilter(profile)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
const parseDateTime = require('../parse/date-time')
|
||||
const parsePlatform = require('../parse/platform')
|
||||
const parseProductsBitmask = require('../parse/products-bitmask')
|
||||
const parseIcon = require('../parse/icon')
|
||||
const parseWhen = require('../parse/when')
|
||||
const parseDeparture = require('../parse/departure')
|
||||
|
@ -44,6 +45,7 @@ const defaultProfile = {
|
|||
|
||||
parseDateTime,
|
||||
parsePlatform,
|
||||
parseProductsBitmask,
|
||||
parseIcon,
|
||||
parseWhen,
|
||||
parseDeparture,
|
||||
|
@ -51,7 +53,7 @@ const defaultProfile = {
|
|||
parseJourneyLeg,
|
||||
parseJourney,
|
||||
parseLine,
|
||||
parseStationName: id,
|
||||
parseStationName: (_, name) => name,
|
||||
parseLocation,
|
||||
parseCommon,
|
||||
parsePolyline,
|
||||
|
|
|
@ -10,22 +10,26 @@ const DEPARTURE = 'd'
|
|||
// todo: what is d.jny.dirFlg?
|
||||
// todo: d.stbStop.dProgType/d.stbStop.aProgType
|
||||
|
||||
const createParseArrOrDep = (profile, opt, data, prefix) => {
|
||||
const createParseArrOrDep = (prefix) => {
|
||||
if (prefix !== ARRIVAL && prefix !== DEPARTURE) throw new Error('invalid prefix')
|
||||
|
||||
const parseArrOrDep = (d) => {
|
||||
const parseArrOrDep = (ctx, d) => { // d = raw arrival/departure
|
||||
const {profile, opt} = ctx
|
||||
|
||||
const tPlanned = d.stbStop[prefix + 'TimeS']
|
||||
const tPrognosed = d.stbStop[prefix + 'TimeR']
|
||||
const tzOffset = d.stbStop[prefix + 'TZOffset'] || null
|
||||
const cancelled = !!d.stbStop[prefix + 'Cncl']
|
||||
const plPlanned = d.stbStop[prefix + 'PlatfS']
|
||||
const plPrognosed = d.stbStop[prefix + 'PlatfR']
|
||||
|
||||
const res = {
|
||||
tripId: d.jid,
|
||||
stop: d.stbStop.location || null,
|
||||
...parseWhen(profile, d.date, tPlanned, tPrognosed, tzOffset, cancelled),
|
||||
...parsePlatform(profile, d.stbStop[prefix + 'PlatfS'], d.stbStop[prefix + 'PlatfR'], cancelled),
|
||||
...profile.parseWhen(ctx, d.date, tPlanned, tPrognosed, tzOffset, cancelled),
|
||||
...profile.parsePlatform(ctx, plPlanned, plPrognosed, cancelled),
|
||||
// todo: for arrivals, this is the *origin*, not the *direction*
|
||||
direction: prefix === DEPARTURE && d.dirTxt && profile.parseStationName(d.dirTxt) || null,
|
||||
direction: prefix === DEPARTURE && d.dirTxt && profile.parseStationName(ctx, d.dirTxt) || null,
|
||||
line: d.line || null,
|
||||
remarks: []
|
||||
}
|
||||
|
@ -43,9 +47,10 @@ const createParseArrOrDep = (profile, opt, data, prefix) => {
|
|||
}
|
||||
|
||||
if (opt.stopovers && Array.isArray(d.stopL)) {
|
||||
const parse = profile.parseStopover(profile, opt, data, d.date)
|
||||
// Filter stations the train passes without stopping, as this doesn't comply with FPTF (yet).
|
||||
const stopovers = d.stopL.map(parse).filter(st => !st.passBy)
|
||||
const stopovers = d.stopL
|
||||
.map(st => profile.parseStopover(ctx, st, d.date))
|
||||
.filter(st => !st.passBy)
|
||||
if (prefix === ARRIVAL) res.previousStopovers = stopovers
|
||||
else if (prefix === DEPARTURE) res.nextStopovers = stopovers
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
const createParseArrOrDep = require('./arrival-or-departure')
|
||||
|
||||
const ARRIVAL = 'a'
|
||||
const createParseArrival = (profile, opt, data) => {
|
||||
return createParseArrOrDep(profile, opt, data, ARRIVAL)
|
||||
}
|
||||
const parseArrival = createParseArrOrDep(ARRIVAL)
|
||||
|
||||
module.exports = createParseArrival
|
||||
module.exports = parseArrival
|
||||
|
|
|
@ -3,102 +3,103 @@
|
|||
const get = require('lodash/get')
|
||||
const findInTree = require('../lib/find-in-tree')
|
||||
|
||||
const parseCommonData = (profile, opt, res) => {
|
||||
const parseCommonData = (_ctx) => {
|
||||
const {profile, opt, res} = _ctx
|
||||
const c = res.common || {}
|
||||
|
||||
res.operators = []
|
||||
const common = {}
|
||||
const ctx = {..._ctx, common}
|
||||
|
||||
common.operators = []
|
||||
if (Array.isArray(c.opL)) {
|
||||
res.operators = c.opL.map(op => profile.parseOperator(profile, op))
|
||||
common.operators = c.opL.map(op => profile.parseOperator(ctx, op))
|
||||
findInTree(res, '**.oprX', (idx, parent) => {
|
||||
if ('number' === typeof idx) parent.operator = res.operators[idx]
|
||||
if ('number' === typeof idx) parent.operator = common.operators[idx]
|
||||
})
|
||||
}
|
||||
|
||||
res.icons = []
|
||||
common.icons = []
|
||||
if (Array.isArray(c.icoL)) {
|
||||
res.icons = c.icoL.map(icon => profile.parseIcon(profile, icon))
|
||||
common.icons = c.icoL.map(icon => profile.parseIcon(ctx, icon))
|
||||
findInTree(res, '**.icoX', (idx, parent) => {
|
||||
if ('number' === typeof idx) parent.icon = res.icons[idx]
|
||||
if ('number' === typeof idx) parent.icon = common.icons[idx]
|
||||
})
|
||||
}
|
||||
|
||||
res.lines = []
|
||||
common.lines = []
|
||||
if (Array.isArray(c.prodL)) {
|
||||
const parse = profile.parseLine(profile, opt, res)
|
||||
res.lines = c.prodL.map(parse)
|
||||
common.lines = c.prodL.map(l => profile.parseLine(ctx, l))
|
||||
|
||||
findInTree(res, '**.prodX', (idx, parent) => {
|
||||
if ('number' === typeof idx) parent.line = res.lines[idx]
|
||||
if ('number' === typeof idx) parent.line = common.lines[idx]
|
||||
})
|
||||
findInTree(res, '**.pRefL', (idxs, parent) => {
|
||||
parent.lines = idxs.filter(idx => !!res.lines[idx]).map(idx => res.lines[idx])
|
||||
parent.lines = idxs.filter(idx => !!common.lines[idx]).map(idx => common.lines[idx])
|
||||
})
|
||||
// todo
|
||||
// **.dep.dProdX: departureLine -> res.lines[idx]
|
||||
// **.arr.aProdX: arrivalLine -> res.lines[idx]
|
||||
// **.dep.dProdX: departureLine -> common.lines[idx]
|
||||
// **.arr.aProdX: arrivalLine -> common.lines[idx]
|
||||
}
|
||||
|
||||
res.locations = []
|
||||
common.locations = []
|
||||
if (Array.isArray(c.locL)) {
|
||||
const parse = loc => profile.parseLocation(profile, opt, res, loc)
|
||||
res.locations = c.locL.map(parse)
|
||||
common.locations = c.locL.map(loc => profile.parseLocation(ctx, loc))
|
||||
|
||||
for (let i = 0; i < res.locations.length; i++) {
|
||||
for (let i = 0; i < common.locations.length; i++) {
|
||||
const raw = c.locL[i]
|
||||
const loc = res.locations[i]
|
||||
const loc = common.locations[i]
|
||||
if ('number' === typeof raw.mMastLocX) {
|
||||
loc.station = Object.assign({}, res.locations[raw.mMastLocX])
|
||||
loc.station = Object.assign({}, common.locations[raw.mMastLocX])
|
||||
loc.station.type = 'station'
|
||||
} else if (raw.isMainMast) loc.type = 'station'
|
||||
}
|
||||
|
||||
// todo: correct props?
|
||||
findInTree(res, '**.locX', (idx, parent) => {
|
||||
if ('number' === typeof idx) parent.location = res.locations[idx]
|
||||
if ('number' === typeof idx) parent.location = common.locations[idx]
|
||||
})
|
||||
findInTree(res, '**.ani.fLocX', (idxs, parent) => {
|
||||
parent.fromLocations = idxs.map(idx => res.locations[idx])
|
||||
parent.fromLocations = idxs.map(idx => common.locations[idx])
|
||||
})
|
||||
findInTree(res, '**.ani.tLocX', (idxs, parent) => {
|
||||
parent.toLocations = idxs.map(idx => res.locations[idx])
|
||||
parent.toLocations = idxs.map(idx => common.locations[idx])
|
||||
})
|
||||
findInTree(res, '**.fLocX', (idx, parent) => {
|
||||
if ('number' === typeof idx) parent.fromLocation = res.locations[idx]
|
||||
if ('number' === typeof idx) parent.fromLocation = common.locations[idx]
|
||||
})
|
||||
findInTree(res, '**.tLocX', (idx, parent) => {
|
||||
if ('number' === typeof idx) parent.toLocation = res.locations[idx]
|
||||
if ('number' === typeof idx) parent.toLocation = common.locations[idx]
|
||||
})
|
||||
}
|
||||
|
||||
res.hints = []
|
||||
common.hints = []
|
||||
if (opt.remarks && Array.isArray(c.remL)) {
|
||||
res.hints = c.remL.map(hint => profile.parseHint(profile, hint, {...c, ...res}))
|
||||
common.hints = c.remL.map(hint => profile.parseHint(ctx, hint))
|
||||
findInTree(res, '**.remX', (idx, parent) => {
|
||||
if ('number' === typeof idx) parent.hint = res.hints[idx]
|
||||
if ('number' === typeof idx) parent.hint = common.hints[idx]
|
||||
})
|
||||
}
|
||||
res.warnings = []
|
||||
common.warnings = []
|
||||
if (opt.remarks && Array.isArray(c.himL)) {
|
||||
res.warnings = c.himL.map(w => profile.parseWarning(profile, w, {...c, ...res}))
|
||||
common.warnings = c.himL.map(w => profile.parseWarning(ctx, w))
|
||||
findInTree(res, '**.himX', (idx, parent) => {
|
||||
if ('number' === typeof idx) parent.warning = res.warnings[idx]
|
||||
if ('number' === typeof idx) parent.warning = common.warnings[idx]
|
||||
})
|
||||
}
|
||||
|
||||
res.polylines = []
|
||||
common.polylines = []
|
||||
if (opt.polylines && Array.isArray(c.polyL)) {
|
||||
const parse = profile.parsePolyline(profile, opt, res)
|
||||
res.polylines = c.polyL.map(parse)
|
||||
common.polylines = c.polyL.map(p => profile.parsePolyline(ctx, p))
|
||||
// todo: **.ani.poly -> parsePolyline()
|
||||
|
||||
findInTree(res, '**.polyG.polyXL', (idxs, _, path) => {
|
||||
const idx = idxs.find(idx => !!res.polylines[idx]) // find any given polyline
|
||||
const idx = idxs.find(idx => !!common.polylines[idx]) // find any given polyline
|
||||
const jny = get(res, path.slice(0, -2))
|
||||
jny.polyline = res.polylines[idx]
|
||||
jny.polyline = common.polylines[idx]
|
||||
})
|
||||
}
|
||||
|
||||
return res
|
||||
return common
|
||||
}
|
||||
|
||||
module.exports = parseCommonData
|
||||
|
|
|
@ -4,8 +4,7 @@ const {DateTime, FixedOffsetZone, IANAZone} = require('luxon')
|
|||
|
||||
const timezones = new WeakMap()
|
||||
|
||||
// todo: change to `(profile) => (date, time) => {}`
|
||||
const parseDateTime = (profile, date, time, tzOffset = null, timestamp = false) => {
|
||||
const parseDateTime = ({profile}, date, time, tzOffset = null, timestamp = false) => {
|
||||
const pDate = [date.substr(-8, 4), date.substr(-4, 2), date.substr(-2, 2)]
|
||||
if (!pDate[0] || !pDate[1] || !pDate[2]) {
|
||||
throw new Error('invalid date format: ' + date)
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
const createParseArrOrDep = require('./arrival-or-departure')
|
||||
|
||||
const DEPARTURE = 'd'
|
||||
const createParseDeparture = (profile, opt, data) => {
|
||||
return createParseArrOrDep(profile, opt, data, DEPARTURE)
|
||||
}
|
||||
const parseDeparture = createParseArrOrDep(DEPARTURE)
|
||||
|
||||
module.exports = createParseDeparture
|
||||
module.exports = parseDeparture
|
||||
|
|
|
@ -4,7 +4,6 @@ const codesByIcon = Object.assign(Object.create(null), {
|
|||
cancel: 'cancelled'
|
||||
})
|
||||
|
||||
// todo: is passing in profile necessary?
|
||||
// todo: pass in tag list from hint reference, e.g.:
|
||||
// "tagL": [
|
||||
// "RES_JNY_H3" // H3 = level 3 heading? shown on overview
|
||||
|
@ -13,7 +12,7 @@ const codesByIcon = Object.assign(Object.create(null), {
|
|||
// "RES_JNY_DTL" // only shown in journey detail
|
||||
// ]
|
||||
// todo: https://github.com/public-transport/hafas-client/issues/5
|
||||
const parseHint = (profile, h, _) => {
|
||||
const parseHint = (ctx, h) => {
|
||||
// todo: C
|
||||
|
||||
const text = h.txtN && h.txtN.trim() || ''
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
const parseIcon = (profile, i) => {
|
||||
const parseIcon = (ctx, i) => {
|
||||
const res = {
|
||||
type: i.res || null,
|
||||
title: i.text || i.txt || i.txtS || null
|
||||
|
|
|
@ -32,120 +32,116 @@ const applyRemarks = (leg, refs) => {
|
|||
}
|
||||
}
|
||||
|
||||
const createParseJourneyLeg = (profile, opt, data) => {
|
||||
// todo: pt.status, pt.isPartCncl
|
||||
// todo: pt.isRchbl, pt.chRatingRT, pt.chgDurR, pt.minChg
|
||||
// todo: pt.dep.dProgType, pt.arr.dProgType
|
||||
// todo: what is pt.jny.dirFlg?
|
||||
// todo: what is pt.recState?
|
||||
// todo: what is `sty: 'UNDEF'`?
|
||||
// todo: pt.prodL
|
||||
// todo: pt.parJnyL (list of coupled trains)
|
||||
// todo: pt.status, pt.isPartCncl
|
||||
// todo: pt.isRchbl, pt.chRatingRT, pt.chgDurR, pt.minChg
|
||||
// todo: pt.dep.dProgType, pt.arr.dProgType
|
||||
// todo: what is pt.jny.dirFlg?
|
||||
// todo: what is pt.recState?
|
||||
// todo: what is `sty: 'UNDEF'`?
|
||||
// todo: pt.prodL
|
||||
// todo: pt.parJnyL (list of coupled trains)
|
||||
// todo: pt.planrtTS
|
||||
|
||||
// j = journey, pt = part
|
||||
// todo: pt.planrtTS
|
||||
const parseJourneyLeg = (j, pt, parseStopovers = true) => {
|
||||
const res = {
|
||||
origin: clone(pt.dep.location) || null,
|
||||
destination: clone(pt.arr.location)
|
||||
}
|
||||
const parseJourneyLeg = (ctx, pt, date) => { // pt = raw leg
|
||||
const {profile, opt} = ctx
|
||||
|
||||
const arr = parseWhen(profile, j.date, pt.arr.aTimeS, pt.arr.aTimeR, pt.arr.aTZOffset, pt.arr.aCncl)
|
||||
res.arrival = arr.when
|
||||
res.plannedArrival = arr.plannedWhen
|
||||
res.arrivalDelay = arr.delay
|
||||
if (arr.prognosedWhen) res.prognosedArrival = arr.prognosedWhen
|
||||
|
||||
const dep = parseWhen(profile, j.date, pt.dep.dTimeS, pt.dep.dTimeR, pt.dep.dTZOffset, pt.dep.dCncl)
|
||||
res.departure = dep.when
|
||||
res.plannedDeparture = dep.plannedWhen
|
||||
res.departureDelay = dep.delay
|
||||
if (dep.prognosedWhen) res.prognosedDeparture = dep.prognosedWhen
|
||||
|
||||
if (pt.jny) {
|
||||
res.reachable = !!pt.jny.isRchbl
|
||||
}
|
||||
|
||||
if (pt.jny && pt.jny.polyline) {
|
||||
res.polyline = pt.jny.polyline || null
|
||||
}
|
||||
|
||||
if (pt.type === 'WALK' || pt.type === 'TRSF') {
|
||||
res.public = true
|
||||
res.walking = true
|
||||
res.distance = pt.gis && pt.gis.dist || null
|
||||
if (pt.type === 'TRSF') res.transfer = true
|
||||
|
||||
// https://gist.github.com/derhuerst/426d4b95aeae701843b1e9c23105b8d4#file-tripsearch-2018-12-05-http-L4207-L4229
|
||||
if (opt.remarks && Array.isArray(pt.gis.msgL)) {
|
||||
applyRemarks(res, pt.gis.msgL)
|
||||
}
|
||||
} else if (pt.type === 'JNY') {
|
||||
// todo: pull `public` value from `profile.products`
|
||||
res.tripId = pt.jny.jid
|
||||
res.line = pt.jny.line || null
|
||||
res.direction = pt.jny.dirTxt && profile.parseStationName(pt.jny.dirTxt) || null
|
||||
|
||||
const arrPl = parsePlatform(profile, pt.arr.aPlatfS, pt.arr.aPlatfR, pt.arr.aCncl)
|
||||
res.arrivalPlatform = arrPl.platform
|
||||
res.plannedArrivalPlatform = arrPl.plannedPlatform
|
||||
if (arrPl.prognosedPlatform) res.prognosedArrivalPlatform = arrPl.prognosedPlatform
|
||||
|
||||
const depPl = parsePlatform(profile, pt.dep.dPlatfS, pt.dep.dPlatfR, pt.dep.dCncl)
|
||||
res.departurePlatform = depPl.platform
|
||||
res.plannedDeparturePlatform = depPl.plannedPlatform
|
||||
if (depPl.prognosedPlatform) res.prognosedDeparturePlatform = depPl.prognosedPlatform
|
||||
|
||||
if (parseStopovers && pt.jny.stopL) {
|
||||
const parse = profile.parseStopover(profile, opt, data, j.date)
|
||||
const stopL = pt.jny.stopL
|
||||
res.stopovers = stopL.map(parse)
|
||||
|
||||
if (opt.remarks && Array.isArray(pt.jny.msgL)) {
|
||||
// todo: apply leg-wide remarks if `parseStopovers` is false
|
||||
applyRemarks(res, pt.jny.msgL)
|
||||
}
|
||||
|
||||
// filter stations the train passes without stopping, as this doesn't comply with fptf (yet)
|
||||
res.stopovers = res.stopovers.filter((x) => !x.passBy)
|
||||
}
|
||||
|
||||
const freq = pt.jny.freq || {}
|
||||
// todo: expose `res.cycle` even if only one field exists (breaking)
|
||||
if (freq.minC && freq.maxC) {
|
||||
res.cycle = {
|
||||
min: freq.minC * 60,
|
||||
max: freq.maxC * 60
|
||||
}
|
||||
// nr of connections in this frequency, from now on
|
||||
if (freq.numC) res.cycle.nr = freq.numC
|
||||
}
|
||||
|
||||
if (freq.jnyL) {
|
||||
const parseAlternative = (a) => {
|
||||
// todo: parse this just like a `leg` (breaking)
|
||||
// todo: parse `a.stopL`, `a.ctxRecon`, `a.msgL`
|
||||
const st0 = a.stopL[0] || {}
|
||||
return {
|
||||
tripId: a.jid,
|
||||
line: a.line || null,
|
||||
direction: a.dirTxt || null,
|
||||
...parseWhen(profile, j.date, st0.dTimeS, st0.dTimeR, st0.dTZOffset, st0.dCncl)
|
||||
}
|
||||
}
|
||||
res.alternatives = freq.jnyL.map(parseAlternative)
|
||||
}
|
||||
}
|
||||
|
||||
if (pt.arr.aCncl || pt.dep.dCncl) {
|
||||
res.cancelled = true
|
||||
Object.defineProperty(res, 'canceled', {value: true})
|
||||
}
|
||||
|
||||
return res
|
||||
const res = {
|
||||
origin: clone(pt.dep.location) || null,
|
||||
destination: clone(pt.arr.location)
|
||||
}
|
||||
|
||||
return parseJourneyLeg
|
||||
const arr = profile.parseWhen(ctx, date, pt.arr.aTimeS, pt.arr.aTimeR, pt.arr.aTZOffset, pt.arr.aCncl)
|
||||
res.arrival = arr.when
|
||||
res.plannedArrival = arr.plannedWhen
|
||||
res.arrivalDelay = arr.delay
|
||||
if (arr.prognosedWhen) res.prognosedArrival = arr.prognosedWhen
|
||||
|
||||
const dep = profile.parseWhen(ctx, date, pt.dep.dTimeS, pt.dep.dTimeR, pt.dep.dTZOffset, pt.dep.dCncl)
|
||||
res.departure = dep.when
|
||||
res.plannedDeparture = dep.plannedWhen
|
||||
res.departureDelay = dep.delay
|
||||
if (dep.prognosedWhen) res.prognosedDeparture = dep.prognosedWhen
|
||||
|
||||
if (pt.jny) {
|
||||
res.reachable = !!pt.jny.isRchbl
|
||||
}
|
||||
|
||||
if (pt.jny && pt.jny.polyline) {
|
||||
res.polyline = pt.jny.polyline || null
|
||||
}
|
||||
|
||||
if (pt.type === 'WALK' || pt.type === 'TRSF') {
|
||||
res.public = true
|
||||
res.walking = true
|
||||
res.distance = pt.gis && pt.gis.dist || null
|
||||
if (pt.type === 'TRSF') res.transfer = true
|
||||
|
||||
// https://gist.github.com/derhuerst/426d4b95aeae701843b1e9c23105b8d4#file-tripsearch-2018-12-05-http-L4207-L4229
|
||||
if (opt.remarks && Array.isArray(pt.gis.msgL)) {
|
||||
applyRemarks(res, pt.gis.msgL)
|
||||
}
|
||||
} else if (pt.type === 'JNY') {
|
||||
// todo: pull `public` value from `profile.products`
|
||||
res.tripId = pt.jny.jid
|
||||
res.line = pt.jny.line || null
|
||||
res.direction = pt.jny.dirTxt && profile.parseStationName(ctx, pt.jny.dirTxt) || null
|
||||
|
||||
const arrPl = profile.parsePlatform(ctx, pt.arr.aPlatfS, pt.arr.aPlatfR, pt.arr.aCncl)
|
||||
res.arrivalPlatform = arrPl.platform
|
||||
res.plannedArrivalPlatform = arrPl.plannedPlatform
|
||||
if (arrPl.prognosedPlatform) res.prognosedArrivalPlatform = arrPl.prognosedPlatform
|
||||
|
||||
const depPl = profile.parsePlatform(ctx, pt.dep.dPlatfS, pt.dep.dPlatfR, pt.dep.dCncl)
|
||||
res.departurePlatform = depPl.platform
|
||||
res.plannedDeparturePlatform = depPl.plannedPlatform
|
||||
if (depPl.prognosedPlatform) res.prognosedDeparturePlatform = depPl.prognosedPlatform
|
||||
|
||||
if (opt.stopovers && pt.jny.stopL) {
|
||||
const stopL = pt.jny.stopL
|
||||
res.stopovers = stopL.map(s => profile.parseStopover(ctx, s, date))
|
||||
|
||||
if (opt.remarks && Array.isArray(pt.jny.msgL)) {
|
||||
// todo: apply leg-wide remarks if `opt.stopovers` is false
|
||||
applyRemarks(res, pt.jny.msgL)
|
||||
}
|
||||
|
||||
// filter stations the train passes without stopping, as this doesn't comply with fptf (yet)
|
||||
res.stopovers = res.stopovers.filter((x) => !x.passBy)
|
||||
}
|
||||
|
||||
const freq = pt.jny.freq || {}
|
||||
// todo: expose `res.cycle` even if only one field exists (breaking)
|
||||
if (freq.minC && freq.maxC) {
|
||||
res.cycle = {
|
||||
min: freq.minC * 60,
|
||||
max: freq.maxC * 60
|
||||
}
|
||||
// nr of connections in this frequency, from now on
|
||||
if (freq.numC) res.cycle.nr = freq.numC
|
||||
}
|
||||
|
||||
if (freq.jnyL) {
|
||||
const parseAlternative = (a) => {
|
||||
// todo: parse this just like a `leg` (breaking)
|
||||
// todo: parse `a.stopL`, `a.ctxRecon`, `a.msgL`
|
||||
const st0 = a.stopL[0] || {}
|
||||
return {
|
||||
tripId: a.jid,
|
||||
line: a.line || null,
|
||||
direction: a.dirTxt || null,
|
||||
...profile.parseWhen(ctx, date, st0.dTimeS, st0.dTimeR, st0.dTZOffset, st0.dCncl)
|
||||
}
|
||||
}
|
||||
res.alternatives = freq.jnyL.map(parseAlternative)
|
||||
}
|
||||
}
|
||||
|
||||
if (pt.arr.aCncl || pt.dep.dCncl) {
|
||||
res.cancelled = true
|
||||
Object.defineProperty(res, 'canceled', {value: true})
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
module.exports = createParseJourneyLeg
|
||||
module.exports = parseJourneyLeg
|
||||
|
|
|
@ -22,47 +22,44 @@ const parseScheduledDays = (sDaysB, year, profile) => {
|
|||
return res
|
||||
}
|
||||
|
||||
const createParseJourney = (profile, opt, data) => {
|
||||
const parseLeg = profile.parseJourneyLeg(profile, opt, data)
|
||||
// todo: c.conSubscr
|
||||
// todo: c.trfRes x vbb-parse-ticket
|
||||
// todo: c.sotRating, c.isSotCon, c.sotCtxt
|
||||
// todo: c.showARSLink
|
||||
// todo: c.useableTime
|
||||
// todo: c.cksum
|
||||
// todo: c.isNotRdbl
|
||||
// todo: c.badSecRefX
|
||||
// todo: c.bfATS, c.bfIOSTS
|
||||
const parseJourney = (j) => {
|
||||
const legs = j.secL.map(leg => parseLeg(j, leg))
|
||||
const res = {
|
||||
type: 'journey',
|
||||
legs,
|
||||
refreshToken: j.ctxRecon || null
|
||||
}
|
||||
// todo: c.conSubscr
|
||||
// todo: c.trfRes x vbb-parse-ticket
|
||||
// todo: c.sotRating, c.isSotCon, c.sotCtxt
|
||||
// todo: c.showARSLink
|
||||
// todo: c.useableTime
|
||||
// todo: c.cksum
|
||||
// todo: c.isNotRdbl
|
||||
// todo: c.badSecRefX
|
||||
// todo: c.bfATS, c.bfIOSTS
|
||||
const parseJourney = (ctx, j) => { // j = raw jouney
|
||||
const {profile, opt} = ctx
|
||||
|
||||
const freq = j.freq || {}
|
||||
if (freq.minC || freq.maxC) {
|
||||
res.cycle = {}
|
||||
if (freq.minC) res.cycle.min = freq.minC * 60
|
||||
if (freq.maxC) res.cycle.max = freq.maxC * 60
|
||||
// nr of connections in this frequency, from now on
|
||||
if (freq.numC) res.cycle.nr = freq.numC
|
||||
}
|
||||
|
||||
if (opt.remarks && Array.isArray(j.msgL)) {
|
||||
res.remarks = findRemarks(j.msgL).map(([remark]) => remark)
|
||||
}
|
||||
|
||||
if (opt.scheduledDays) {
|
||||
const year = parseInt(j.date.slice(0, 4))
|
||||
res.scheduledDays = parseScheduledDays(j.sDays.sDaysB, year, profile)
|
||||
}
|
||||
|
||||
return res
|
||||
const legs = j.secL.map(l => profile.parseJourneyLeg(ctx, l, j.date))
|
||||
const res = {
|
||||
type: 'journey',
|
||||
legs,
|
||||
refreshToken: j.ctxRecon || null
|
||||
}
|
||||
|
||||
return parseJourney
|
||||
const freq = j.freq || {}
|
||||
if (freq.minC || freq.maxC) {
|
||||
res.cycle = {}
|
||||
if (freq.minC) res.cycle.min = freq.minC * 60
|
||||
if (freq.maxC) res.cycle.max = freq.maxC * 60
|
||||
// nr of connections in this frequency, from now on
|
||||
if (freq.numC) res.cycle.nr = freq.numC
|
||||
}
|
||||
|
||||
if (opt.remarks && Array.isArray(j.msgL)) {
|
||||
res.remarks = findRemarks(j.msgL).map(([remark]) => remark)
|
||||
}
|
||||
|
||||
if (opt.scheduledDays) {
|
||||
const year = parseInt(j.date.slice(0, 4))
|
||||
res.scheduledDays = parseScheduledDays(j.sDays.sDaysB, year, profile)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
module.exports = createParseJourney
|
||||
module.exports = parseJourney
|
||||
|
|
|
@ -2,45 +2,42 @@
|
|||
|
||||
const slugg = require('slugg')
|
||||
|
||||
const createParseLine = (profile, opt, _) => {
|
||||
const byBitmask = []
|
||||
for (let product of profile.products) {
|
||||
for (let bitmask of product.bitmasks) {
|
||||
byBitmask[bitmask] = product
|
||||
const parseLine = ({profile}, p) => {
|
||||
if (!p) return null // todo: handle this upstream
|
||||
const name = p.line || p.addName || p.name || null // wtf
|
||||
const res = {
|
||||
type: 'line',
|
||||
// This is terrible, but FPTF demands an ID. Let's pray for HAFAS.
|
||||
id: (
|
||||
p.prodCtx && p.prodCtx.lineId && slugg(p.prodCtx.lineId.trim())
|
||||
|| name && slugg(name.trim())
|
||||
|| null
|
||||
),
|
||||
// todo: what is p.prodCtx.matchId? use as `id`? expose it.
|
||||
fahrtNr: p.prodCtx && p.prodCtx.num || null,
|
||||
name,
|
||||
public: true
|
||||
}
|
||||
// todo: what is p.number?
|
||||
// todo: what is p.prodCtx.catCode?
|
||||
|
||||
if ('cls' in p) {
|
||||
// todo: use profile.products.find() for this
|
||||
const byBitmask = []
|
||||
for (let product of profile.products) {
|
||||
for (let bitmask of product.bitmasks) {
|
||||
byBitmask[bitmask] = product
|
||||
}
|
||||
}
|
||||
|
||||
// todo: what if `p.cls` is the sum of two bitmasks?
|
||||
const product = byBitmask[parseInt(p.cls)]
|
||||
res.mode = product && product.mode || null
|
||||
res.product = product && product.id || null
|
||||
}
|
||||
|
||||
// todo: p.himIdL
|
||||
const parseLine = (p) => {
|
||||
if (!p) return null // todo: handle this upstream
|
||||
const name = p.line || p.addName || p.name || null // wtf
|
||||
const res = {
|
||||
type: 'line',
|
||||
// This is terrible, but FPTF demands an ID. Let's pray for HAFAS.
|
||||
id: (
|
||||
p.prodCtx && p.prodCtx.lineId && slugg(p.prodCtx.lineId.trim())
|
||||
|| name && slugg(name.trim())
|
||||
|| null
|
||||
),
|
||||
// todo: what is p.prodCtx.matchId? use as `id`? expose it.
|
||||
fahrtNr: p.prodCtx && p.prodCtx.num || null,
|
||||
name,
|
||||
public: true
|
||||
}
|
||||
// todo: what is p.number?
|
||||
// todo: what is p.prodCtx.catCode?
|
||||
|
||||
if ('cls' in p) {
|
||||
// todo: what if `p.cls` is the sum of two bitmasks?
|
||||
const product = byBitmask[parseInt(p.cls)]
|
||||
res.mode = product && product.mode || null
|
||||
res.product = product && product.id || null
|
||||
}
|
||||
|
||||
if (p.operator) res.operator = p.operator // todo: move up
|
||||
return res
|
||||
}
|
||||
return parseLine
|
||||
if (p.operator) res.operator = p.operator // todo: move up
|
||||
return res
|
||||
}
|
||||
|
||||
module.exports = createParseLine
|
||||
module.exports = parseLine
|
||||
|
|
|
@ -9,7 +9,9 @@ const ADDRESS = 'A'
|
|||
const leadingZeros = /^0+/
|
||||
|
||||
// todo: what is s.rRefL?
|
||||
const parseLocation = (profile, opt, _, l) => {
|
||||
const parseLocation = (ctx, l) => {
|
||||
const {profile, opt} = ctx
|
||||
|
||||
const lid = parse(l.lid, {delimiter: '@'})
|
||||
const res = {
|
||||
type: 'location',
|
||||
|
@ -25,11 +27,11 @@ const parseLocation = (profile, opt, _, l) => {
|
|||
const stop = {
|
||||
type: l.isMainMast ? 'station' : 'stop',
|
||||
id: res.id,
|
||||
name: l.name || id.O ? profile.parseStationName(l.name || id.O) : null,
|
||||
name: l.name || id.O ? profile.parseStationName(ctx, l.name || id.O) : null,
|
||||
location: 'number' === typeof res.latitude ? res : null // todo: remove `.id`
|
||||
}
|
||||
|
||||
if ('pCls' in l) stop.products = profile.parseProducts(l.pCls)
|
||||
if ('pCls' in l) stop.products = profile.parseProductsBitmask(ctx, l.pCls)
|
||||
if ('meta' in l) stop.isMeta = !!l.meta
|
||||
|
||||
if (opt.linesOfStops && Array.isArray(l.lines)) {
|
||||
|
|
|
@ -1,53 +1,49 @@
|
|||
'use strict'
|
||||
|
||||
const createParseMovement = (profile, opt, data) => {
|
||||
// todo: what is m.dirGeo? maybe the speed?
|
||||
// todo: what is m.stopL?
|
||||
// todo: what is m.proc? wut?
|
||||
// todo: what is m.pos?
|
||||
// todo: what is m.ani.dirGeo[n]? maybe the speed?
|
||||
// todo: what is m.ani.proc[n]? wut?
|
||||
const parseMovement = (m) => {
|
||||
const pStopover = profile.parseStopover(profile, opt, data, m.date)
|
||||
// todo: what is m.dirGeo? maybe the speed?
|
||||
// todo: what is m.stopL?
|
||||
// todo: what is m.proc? wut?
|
||||
// todo: what is m.pos?
|
||||
// todo: what is m.ani.dirGeo[n]? maybe the speed?
|
||||
// todo: what is m.ani.proc[n]? wut?
|
||||
const parseMovement = (ctx, m) => { // m = raw movement
|
||||
const {profile, opt} = ctx
|
||||
|
||||
const res = {
|
||||
direction: m.dirTxt ? profile.parseStationName(m.dirTxt) : null,
|
||||
tripId: m.jid || null,
|
||||
line: m.line || null,
|
||||
location: m.pos ? {
|
||||
type: 'location',
|
||||
latitude: m.pos.y / 1000000,
|
||||
longitude: m.pos.x / 1000000
|
||||
} : null,
|
||||
// todo: stopL[0] is the first of the trip! -> filter out
|
||||
nextStopovers: m.stopL.map(pStopover),
|
||||
frames: []
|
||||
}
|
||||
|
||||
if (m.ani) {
|
||||
if (Array.isArray(m.ani.mSec)) {
|
||||
for (let i = 0; i < m.ani.mSec.length; i++) {
|
||||
res.frames.push({
|
||||
origin: m.ani.fromLocations[i] || null,
|
||||
destination: m.ani.toLocations[i] || null,
|
||||
t: m.ani.mSec[i]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.polylines) {
|
||||
if (m.ani.poly) {
|
||||
const parse = profile.parsePolyline(profile, opt, data)
|
||||
res.polyline = parse(m.ani.poly)
|
||||
} else if (m.ani.polyline) {
|
||||
res.polyline = m.ani.polyline
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
const res = {
|
||||
direction: m.dirTxt ? profile.parseStationName(ctx, m.dirTxt) : null,
|
||||
tripId: m.jid || null,
|
||||
line: m.line || null,
|
||||
location: m.pos ? {
|
||||
type: 'location',
|
||||
latitude: m.pos.y / 1000000,
|
||||
longitude: m.pos.x / 1000000
|
||||
} : null,
|
||||
// todo: stopL[0] is the first of the trip! -> filter out
|
||||
nextStopovers: m.stopL.map(s => profile.parseStopover(ctx, s, m.date)),
|
||||
frames: []
|
||||
}
|
||||
return parseMovement
|
||||
|
||||
if (m.ani) {
|
||||
if (Array.isArray(m.ani.mSec)) {
|
||||
for (let i = 0; i < m.ani.mSec.length; i++) {
|
||||
res.frames.push({
|
||||
origin: m.ani.fromLocations[i] || null,
|
||||
destination: m.ani.toLocations[i] || null,
|
||||
t: m.ani.mSec[i]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.polylines) {
|
||||
if (m.ani.poly) {
|
||||
res.polyline = profile.parsePolyline(ctx, m.ani.poly)
|
||||
} else if (m.ani.polyline) {
|
||||
res.polyline = m.ani.polyline
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
module.exports = createParseMovement
|
||||
module.exports = parseMovement
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
// todo: what is s.wt?
|
||||
// todo: what is s.dur?
|
||||
|
||||
// todo: [breaking] change to createParseNearby(profile, data) => (n) => nearby
|
||||
const parseNearby = (profile, opt, data, n) => {
|
||||
const res = profile.parseLocation(profile, opt, data, n)
|
||||
const parseNearby = (ctx, n) => { // n = raw nearby location
|
||||
const res = ctx.profile.parseLocation(ctx, n)
|
||||
res.distance = n.dist
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
const slugg = require('slugg')
|
||||
|
||||
const parseOperator = (profile, a) => {
|
||||
const parseOperator = (ctx, a) => {
|
||||
const name = a.name && a.name.trim()
|
||||
if (!name) return null
|
||||
return {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
const parsePlatform = (profile, platfS, platfR, cncl = false) => {
|
||||
const parsePlatform = (ctx, platfS, platfR, cncl = false) => {
|
||||
let planned = platfS || null
|
||||
let prognosed = platfR || null
|
||||
|
||||
|
|
|
@ -3,50 +3,47 @@
|
|||
const {toGeoJSON} = require('@mapbox/polyline')
|
||||
const distance = require('gps-distance')
|
||||
|
||||
const createParsePolyline = (profile, opt, _) => {
|
||||
// todo: what is p.delta?
|
||||
// todo: what is p.type?
|
||||
// todo: what is p.crdEncS?
|
||||
// todo: what is p.crdEncF?
|
||||
const parsePolyline = (p) => {
|
||||
const shape = toGeoJSON(p.crdEncYX)
|
||||
if (shape.coordinates.length === 0) return null
|
||||
// todo: what is p.delta?
|
||||
// todo: what is p.type?
|
||||
// todo: what is p.crdEncS?
|
||||
// todo: what is p.crdEncF?
|
||||
const parsePolyline = (ctx, p) => { // p = raw polyline
|
||||
const shape = toGeoJSON(p.crdEncYX)
|
||||
if (shape.coordinates.length === 0) return null
|
||||
|
||||
const res = shape.coordinates.map(crd => ({
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: crd
|
||||
}
|
||||
}))
|
||||
const res = shape.coordinates.map(crd => ({
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: crd
|
||||
}
|
||||
}))
|
||||
|
||||
if (Array.isArray(p.ppLocRefL)) {
|
||||
for (let ref of p.ppLocRefL) {
|
||||
const p = res[ref.ppIdx]
|
||||
if (p && ref.location) p.properties = ref.location
|
||||
}
|
||||
|
||||
// Often there is one more point right next to each point at a station.
|
||||
// We filter them here if they are < 5m from each other.
|
||||
for (let i = 1; i < res.length; i++) {
|
||||
const p1 = res[i - 1].geometry.coordinates
|
||||
const p2 = res[i].geometry.coordinates
|
||||
const d = distance(p1[1], p1[0], p2[1], p2[0])
|
||||
if (d >= .005) continue
|
||||
const l1 = Object.keys(res[i - 1].properties).length
|
||||
const l2 = Object.keys(res[i].properties).length
|
||||
if (l1 === 0 && l2 > 0) res.splice(i - 1, 1)
|
||||
else if (l2 === 0 && l1 > 0) res.splice(i, 1)
|
||||
}
|
||||
if (Array.isArray(p.ppLocRefL)) {
|
||||
for (let ref of p.ppLocRefL) {
|
||||
const p = res[ref.ppIdx]
|
||||
if (p && ref.location) p.properties = ref.location
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'FeatureCollection',
|
||||
features: res
|
||||
// Often there is one more point right next to each point at a station.
|
||||
// We filter them here if they are < 5m from each other.
|
||||
for (let i = 1; i < res.length; i++) {
|
||||
const p1 = res[i - 1].geometry.coordinates
|
||||
const p2 = res[i].geometry.coordinates
|
||||
const d = distance(p1[1], p1[0], p2[1], p2[0])
|
||||
if (d >= .005) continue
|
||||
const l1 = Object.keys(res[i - 1].properties).length
|
||||
const l2 = Object.keys(res[i].properties).length
|
||||
if (l1 === 0 && l2 > 0) res.splice(i - 1, 1)
|
||||
else if (l2 === 0 && l1 > 0) res.splice(i, 1)
|
||||
}
|
||||
}
|
||||
return parsePolyline
|
||||
|
||||
return {
|
||||
type: 'FeatureCollection',
|
||||
features: res
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = createParsePolyline
|
||||
module.exports = parsePolyline
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
'use strict'
|
||||
|
||||
const createParseBitmask = (profile) => {
|
||||
const defaultProducts = {}
|
||||
for (let product of profile.products) defaultProducts[product.id] = false
|
||||
const parseBitmask = ({profile}, bitmask) => {
|
||||
const res = {}
|
||||
for (let product of profile.products) res[product.id] = false
|
||||
|
||||
const parseBitmask = (bitmask) => {
|
||||
const res = Object.assign({}, defaultProducts)
|
||||
const bits = bitmask.toString(2).split('').map(i => parseInt(i)).reverse()
|
||||
for (let i = 0; i < bits.length; i++) {
|
||||
if (!bits[i]) continue // ignore `0`
|
||||
|
||||
const bits = bitmask.toString(2).split('').map(i => parseInt(i)).reverse()
|
||||
for (let i = 0; i < bits.length; i++) {
|
||||
if (!bits[i]) continue // ignore `0`
|
||||
|
||||
const product = profile.products.find(p => p.bitmasks.includes(Math.pow(2, i)))
|
||||
if (product) res[product.id] = true
|
||||
}
|
||||
return res
|
||||
const product = profile.products.find(p => p.bitmasks.includes(Math.pow(2, i)))
|
||||
if (product) res[product.id] = true
|
||||
}
|
||||
return parseBitmask
|
||||
return res
|
||||
}
|
||||
|
||||
module.exports = createParseBitmask
|
||||
module.exports = parseBitmask
|
||||
|
|
|
@ -4,48 +4,46 @@ const parseWhen = require('./when')
|
|||
const parsePlatform = require('./platform')
|
||||
const findRemarks = require('./find-remarks')
|
||||
|
||||
const createParseStopover = (profile, opt, data, date) => {
|
||||
const parseStopover = (st) => {
|
||||
const arr = parseWhen(profile, date, st.aTimeS, st.aTimeR, st.aTZOffset, st.aCncl)
|
||||
const arrPl = parsePlatform(profile, st.aPlatfS, st.aPlatfR, st.aCncl)
|
||||
const dep = parseWhen(profile, date, st.dTimeS, st.dTimeR, st.dTZOffset, st.dCncl)
|
||||
const depPl = parsePlatform(profile, st.dPlatfS, st.dPlatfR, st.dCncl)
|
||||
const parseStopover = (ctx, st, date) => { // st = raw stopover
|
||||
const {profile, opt} = ctx
|
||||
|
||||
const res = {
|
||||
stop: st.location || null,
|
||||
arrival: arr.when,
|
||||
plannedArrival: arr.plannedWhen,
|
||||
arrivalDelay: arr.delay,
|
||||
arrivalPlatform: arrPl.platform,
|
||||
plannedArrivalPlatform: arrPl.plannedPlatform,
|
||||
departure: dep.when,
|
||||
plannedDeparture: dep.plannedWhen,
|
||||
departureDelay: dep.delay,
|
||||
departurePlatform: depPl.platform,
|
||||
plannedDeparturePlatform: depPl.plannedPlatform
|
||||
}
|
||||
const arr = profile.parseWhen(ctx, date, st.aTimeS, st.aTimeR, st.aTZOffset, st.aCncl)
|
||||
const arrPl = profile.parsePlatform(ctx, st.aPlatfS, st.aPlatfR, st.aCncl)
|
||||
const dep = profile.parseWhen(ctx, date, st.dTimeS, st.dTimeR, st.dTZOffset, st.dCncl)
|
||||
const depPl = profile.parsePlatform(ctx, st.dPlatfS, st.dPlatfR, st.dCncl)
|
||||
|
||||
if (arr.prognosedWhen) res.prognosedArrival = arr.prognosedWhen
|
||||
if (arrPl.prognosedPlatform) res.prognosedArrivalPlatform = arrPl.prognosedPlatform
|
||||
if (dep.prognosedWhen) res.prognosedDeparture = dep.prognosedWhen
|
||||
if (depPl.prognosedPlatform) res.prognosedDeparturePlatform = depPl.prognosedPlatform
|
||||
|
||||
// mark stations the train passes without stopping
|
||||
if(st.dInS === false && st.aOutS === false) res.passBy = true
|
||||
|
||||
if (st.aCncl || st.dCncl) {
|
||||
res.cancelled = true
|
||||
Object.defineProperty(res, 'canceled', {value: true})
|
||||
}
|
||||
|
||||
if (opt.remarks && Array.isArray(st.msgL)) {
|
||||
res.remarks = findRemarks(st.msgL).map(([remark]) => remark)
|
||||
}
|
||||
|
||||
return res
|
||||
const res = {
|
||||
stop: st.location || null,
|
||||
arrival: arr.when,
|
||||
plannedArrival: arr.plannedWhen,
|
||||
arrivalDelay: arr.delay,
|
||||
arrivalPlatform: arrPl.platform,
|
||||
plannedArrivalPlatform: arrPl.plannedPlatform,
|
||||
departure: dep.when,
|
||||
plannedDeparture: dep.plannedWhen,
|
||||
departureDelay: dep.delay,
|
||||
departurePlatform: depPl.platform,
|
||||
plannedDeparturePlatform: depPl.plannedPlatform
|
||||
}
|
||||
|
||||
return parseStopover
|
||||
if (arr.prognosedWhen) res.prognosedArrival = arr.prognosedWhen
|
||||
if (arrPl.prognosedPlatform) res.prognosedArrivalPlatform = arrPl.prognosedPlatform
|
||||
if (dep.prognosedWhen) res.prognosedDeparture = dep.prognosedWhen
|
||||
if (depPl.prognosedPlatform) res.prognosedDeparturePlatform = depPl.prognosedPlatform
|
||||
|
||||
// mark stations the train passes without stopping
|
||||
if(st.dInS === false && st.aOutS === false) res.passBy = true
|
||||
|
||||
if (st.aCncl || st.dCncl) {
|
||||
res.cancelled = true
|
||||
Object.defineProperty(res, 'canceled', {value: true})
|
||||
}
|
||||
|
||||
if (opt.remarks && Array.isArray(st.msgL)) {
|
||||
res.remarks = findRemarks(st.msgL).map(([remark]) => remark)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
module.exports = createParseStopover
|
||||
module.exports = parseStopover
|
||||
|
|
|
@ -7,7 +7,7 @@ const typesByIcon = Object.assign(Object.create(null), {
|
|||
HimWarn: 'status'
|
||||
})
|
||||
|
||||
const parseMsgEdge = (profile) => (e) => {
|
||||
const parseMsgEdge = (ctx) => (e) => {
|
||||
const res = omit(e, [
|
||||
'icoX',
|
||||
'fLocX', 'fromLocation',
|
||||
|
@ -19,18 +19,20 @@ const parseMsgEdge = (profile) => (e) => {
|
|||
res.toLoc = e.toLocation || null
|
||||
return res
|
||||
}
|
||||
const parseMsgEvent = (profile) => (e) => {
|
||||
const parseMsgEvent = ({profile}) => (e) => {
|
||||
return {
|
||||
// todo: rename `Loc` -> `Location` [breaking]
|
||||
fromLoc: e.fromLocation || null,
|
||||
toLoc: e.toLocation || null,
|
||||
start: profile.parseDateTime(profile, e.fDate, e.fTime, null),
|
||||
end: profile.parseDateTime(profile, e.tDate, e.tTime, null),
|
||||
start: profile.parseDateTime(ctx, e.fDate, e.fTime, null),
|
||||
end: profile.parseDateTime(ctx, e.tDate, e.tTime, null),
|
||||
sections: e.sectionNums || [] // todo: parse
|
||||
}
|
||||
}
|
||||
|
||||
const parseWarning = (profile, w, data) => {
|
||||
const parseWarning = (ctx, w) => {
|
||||
const {profile, res: resp} = ctx
|
||||
|
||||
// todo: act, pub, lead, tckr, prod, comp,
|
||||
// todo: cat (1, 2), pubChL, rRefL, impactL
|
||||
// pubChL:
|
||||
|
@ -62,24 +64,24 @@ const parseWarning = (profile, w, data) => {
|
|||
priority: w.prio,
|
||||
category: w.cat || null // todo: parse to sth meaningful
|
||||
}
|
||||
if ('prod' in w) res.products = profile.parseProducts(w.prod)
|
||||
if ('prod' in w) res.products = profile.parseProductsBitmask(ctx, w.prod)
|
||||
|
||||
if (w.edgeRefL && data.himMsgEdgeL) {
|
||||
if (w.edgeRefL && resp.common && resp.common.himMsgEdgeL) {
|
||||
res.edges = w.edgeRefL
|
||||
.map(i => data.himMsgEdgeL[i])
|
||||
.map(i => resp.common.himMsgEdgeL[i])
|
||||
.filter(e => !!e)
|
||||
.map(parseMsgEdge(profile))
|
||||
.map(parseMsgEdge(ctx))
|
||||
}
|
||||
if (w.eventRefL && data.himMsgEventL) {
|
||||
if (w.eventRefL && resp.common && resp.common.himMsgEventL) {
|
||||
res.events = w.eventRefL
|
||||
.map(i => data.himMsgEventL[i])
|
||||
.map(i => resp.common.himMsgEventL[i])
|
||||
.filter(e => !!e)
|
||||
.map(parseMsgEvent(profile))
|
||||
.map(parseMsgEvent(ctx))
|
||||
}
|
||||
|
||||
if (w.sDate && w.sTime) res.validFrom = profile.parseDateTime(profile, w.sDate, w.sTime, null)
|
||||
if (w.eDate && w.eTime) res.validUntil = profile.parseDateTime(profile, w.eDate, w.eTime, null)
|
||||
if (w.lModDate && w.lModTime) res.modified = profile.parseDateTime(profile, w.lModDate, w.lModTime, null)
|
||||
if (w.sDate && w.sTime) res.validFrom = profile.parseDateTime(ctx, w.sDate, w.sTime, null)
|
||||
if (w.eDate && w.eTime) res.validUntil = profile.parseDateTime(ctx, w.eDate, w.eTime, null)
|
||||
if (w.lModDate && w.lModTime) res.modified = profile.parseDateTime(ctx, w.lModDate, w.lModTime, null)
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
'use strict'
|
||||
|
||||
const parseWhen = (profile, date, timeS, timeR, tzOffset, cncl = false) => {
|
||||
const parse = profile.parseDateTime
|
||||
const parseWhen = (ctx, date, timeS, timeR, tzOffset, cncl = false) => {
|
||||
const parse = ctx.profile.parseDateTime
|
||||
|
||||
let planned = timeS ? parse(profile, date, timeS, tzOffset, false) : null
|
||||
let prognosed = timeR ? parse(profile, date, timeR, tzOffset, false) : null
|
||||
let planned = timeS ? parse(ctx, date, timeS, tzOffset, false) : null
|
||||
let prognosed = timeR ? parse(ctx, date, timeR, tzOffset, false) : null
|
||||
let delay = null
|
||||
|
||||
if (planned && prognosed) {
|
||||
const tPlanned = parse(profile, date, timeS, tzOffset, true)
|
||||
const tPrognosed = parse(profile, date, timeR, tzOffset, true)
|
||||
const tPlanned = parse(ctx, date, timeS, tzOffset, true)
|
||||
const tPrognosed = parse(ctx, date, timeR, tzOffset, true)
|
||||
delay = Math.round((tPrognosed - tPlanned) / 1000)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,48 +3,53 @@
|
|||
const test = require('tape')
|
||||
const parse = require('../../parse/date-time')
|
||||
|
||||
const profile = {
|
||||
timezone: 'Europe/Berlin',
|
||||
locale: 'de-DE'
|
||||
const ctx = {
|
||||
common: {},
|
||||
opt: {},
|
||||
profile: {
|
||||
timezone: 'Europe/Berlin',
|
||||
locale: 'de-DE'
|
||||
}
|
||||
}
|
||||
|
||||
test('date & time parsing uses profile.timezone', (t) => {
|
||||
const iso = parse({
|
||||
...profile, timezone: 'Europe/Moscow'
|
||||
}, '20190819', '203000', undefined, false)
|
||||
t.equal(iso, '2019-08-19T20:30:00+03:00')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('date & time parsing returns a timestamp', (t) => {
|
||||
const iso = parse(profile, '20190819', '203000', undefined, false)
|
||||
const ts = parse(profile, '20190819', '203000', undefined, true)
|
||||
const iso = parse(ctx, '20190819', '203000', undefined, false)
|
||||
const ts = parse(ctx, '20190819', '203000', undefined, true)
|
||||
t.equal(ts, +new Date(iso))
|
||||
t.equal(ts, 1566239400 * 1000)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('date & time parsing uses tzOffset', (t) => {
|
||||
const iso = parse(profile, '20190819', '203000', -120, false)
|
||||
const iso = parse(ctx, '20190819', '203000', -120, false)
|
||||
t.equal(iso, '2019-08-19T20:30:00-02:00')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('date & time parsing works with day "overflow"', (t) => {
|
||||
const iso = parse(profile, '20190819', '02203000', undefined, false)
|
||||
const iso = parse(ctx, '20190819', '02203000', undefined, false)
|
||||
t.equal(iso, '2019-08-21T20:30:00+02:00')
|
||||
t.end()
|
||||
})
|
||||
|
||||
// #106
|
||||
test('date & time parsing works with day "overflow" & tzOffset', (t) => {
|
||||
const iso = parse(profile, '20190819', '02203000', -120, false)
|
||||
const iso = parse(ctx, '20190819', '02203000', -120, false)
|
||||
t.equal(iso, '2019-08-21T20:30:00-02:00')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('date & time parsing works with summer & winter time', (t) => {
|
||||
const iso = parse(profile, '20190219', '203000', undefined, false)
|
||||
const iso = parse(ctx, '20190219', '203000', undefined, false)
|
||||
t.equal(iso, '2019-02-19T20:30:00+01:00')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('date & time parsing uses profile.timezone', (t) => {
|
||||
const iso = parse({
|
||||
...ctx,
|
||||
profile: {...ctx.profile, timezone: 'Europe/Moscow'}
|
||||
}, '20190819', '203000', undefined, false)
|
||||
t.equal(iso, '2019-08-19T20:30:00+03:00')
|
||||
t.end()
|
||||
})
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
const test = require('tape')
|
||||
const parse = require('../../parse/hint')
|
||||
|
||||
const profile = {}
|
||||
const ctx = {
|
||||
data: {},
|
||||
opt: {},
|
||||
profile: {}
|
||||
}
|
||||
|
||||
test('parses hints correctly', (t) => {
|
||||
const input = {
|
||||
|
@ -18,20 +22,20 @@ test('parses hints correctly', (t) => {
|
|||
text: 'some text'
|
||||
}
|
||||
|
||||
t.deepEqual(parse(profile, input), expected)
|
||||
t.deepEqual(parse(profile, {
|
||||
t.deepEqual(parse(ctx, input), expected)
|
||||
t.deepEqual(parse(ctx, {
|
||||
...input, type: 'I'
|
||||
}), expected)
|
||||
|
||||
// alternative trip
|
||||
t.deepEqual(parse(profile, {
|
||||
t.deepEqual(parse(ctx, {
|
||||
...input, type: 'L', jid: 'trip id'
|
||||
}), {
|
||||
...expected, type: 'status', code: 'alternative-trip', tripId: 'trip id'
|
||||
})
|
||||
|
||||
// type: M
|
||||
t.deepEqual(parse(profile, {
|
||||
t.deepEqual(parse(ctx, {
|
||||
...input, type: 'M', txtS: 'some summary'
|
||||
}), {
|
||||
...expected, type: 'status', summary: 'some summary'
|
||||
|
@ -39,18 +43,18 @@ test('parses hints correctly', (t) => {
|
|||
|
||||
// type: D
|
||||
for (const type of ['D', 'U', 'R', 'N', 'Y']) {
|
||||
t.deepEqual(parse(profile, {...input, type}), {
|
||||
t.deepEqual(parse(ctx, {...input, type}), {
|
||||
...expected, type: 'status'
|
||||
})
|
||||
}
|
||||
|
||||
// .code via .icon
|
||||
t.deepEqual(parse(profile, {
|
||||
t.deepEqual(parse(ctx, {
|
||||
...input, code: null, icon: {type: 'cancel'}
|
||||
}), {...expected, code: 'cancelled'})
|
||||
|
||||
// invalid
|
||||
t.equal(parse(profile, {...input, type: 'X'}), null)
|
||||
t.equal(parse(ctx, {...input, type: 'X'}), null)
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
|
|
@ -3,14 +3,18 @@
|
|||
const test = require('tape')
|
||||
const parse = require('../../parse/icon')
|
||||
|
||||
test('parses icons correctly', (t) => {
|
||||
const profile = {}
|
||||
const ctx = {
|
||||
data: {},
|
||||
opt: {},
|
||||
profile: {}
|
||||
}
|
||||
|
||||
test('parses icons correctly', (t) => {
|
||||
const text = {
|
||||
"res": "BVG",
|
||||
"text": "Berliner Verkehrsbetriebe"
|
||||
}
|
||||
t.deepEqual(parse(profile, text), {
|
||||
t.deepEqual(parse(ctx, text), {
|
||||
type: 'BVG',
|
||||
title: 'Berliner Verkehrsbetriebe'
|
||||
})
|
||||
|
@ -19,7 +23,7 @@ test('parses icons correctly', (t) => {
|
|||
"res": "PROD_BUS",
|
||||
"txtS": "18"
|
||||
}
|
||||
t.deepEqual(parse(profile, txtS), {
|
||||
t.deepEqual(parse(ctx, txtS), {
|
||||
type: 'PROD_BUS',
|
||||
title: '18'
|
||||
})
|
||||
|
@ -28,7 +32,7 @@ test('parses icons correctly', (t) => {
|
|||
"res": "RBB",
|
||||
"txt": "Regionalbus Braunschweig GmbH"
|
||||
}
|
||||
t.deepEqual(parse(profile, txt), {
|
||||
t.deepEqual(parse(ctx, txt), {
|
||||
type: 'RBB',
|
||||
title: 'Regionalbus Braunschweig GmbH'
|
||||
})
|
||||
|
@ -36,7 +40,7 @@ test('parses icons correctly', (t) => {
|
|||
const noText = {
|
||||
"res": "attr_bike_r"
|
||||
}
|
||||
t.deepEqual(parse(profile, noText), {
|
||||
t.deepEqual(parse(ctx, noText), {
|
||||
type: 'attr_bike_r',
|
||||
title: null
|
||||
})
|
||||
|
@ -56,7 +60,7 @@ test('parses icons correctly', (t) => {
|
|||
"a": 255
|
||||
}
|
||||
}
|
||||
t.deepEqual(parse(profile, withColor), {
|
||||
t.deepEqual(parse(ctx, withColor), {
|
||||
type: 'prod_sub_t',
|
||||
title: null,
|
||||
fgColor: {r: 255, g: 255, b: 255, a: 255},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
const test = require('tape')
|
||||
const parser = require('../../parse/line')
|
||||
const parse = require('../../parse/line')
|
||||
|
||||
const profile = {
|
||||
products: [
|
||||
|
@ -10,8 +10,11 @@ const profile = {
|
|||
{id: 'bus', bitmasks: [4, 8]}
|
||||
]
|
||||
}
|
||||
const opt = {}
|
||||
const parse = parser(profile, opt, {})
|
||||
const ctx = {
|
||||
data: {},
|
||||
opt: {},
|
||||
profile
|
||||
}
|
||||
|
||||
test('parses lines correctly', (t) => {
|
||||
const input = {
|
||||
|
@ -29,23 +32,23 @@ test('parses lines correctly', (t) => {
|
|||
public: true
|
||||
}
|
||||
|
||||
t.deepEqual(parse(input), expected)
|
||||
t.deepEqual(parse(ctx, input), expected)
|
||||
|
||||
t.deepEqual(parse({
|
||||
t.deepEqual(parse(ctx, {
|
||||
...input, line: null, addName: input.line
|
||||
}), expected)
|
||||
t.deepEqual(parse({
|
||||
t.deepEqual(parse(ctx, {
|
||||
...input, line: null, name: input.line
|
||||
}), expected)
|
||||
|
||||
// no prodCtx.lineId
|
||||
t.deepEqual(parse({
|
||||
t.deepEqual(parse(ctx, {
|
||||
...input, prodCtx: {...input.prodCtx, lineId: null}
|
||||
}), {
|
||||
...expected, id: 'foo-line'
|
||||
})
|
||||
// no prodCtx
|
||||
t.deepEqual(parse({
|
||||
t.deepEqual(parse(ctx, {
|
||||
...input, prodCtx: undefined
|
||||
}), {
|
||||
...expected, id: 'foo-line', fahrtNr: null
|
||||
|
|
|
@ -5,11 +5,16 @@ const omit = require('lodash/omit')
|
|||
const parse = require('../../parse/location')
|
||||
|
||||
const profile = {
|
||||
parseStationName: name => name.toLowerCase(),
|
||||
parseProducts: bitmask => [bitmask]
|
||||
parseStationName: (_, name) => name.toLowerCase(),
|
||||
parseProductsBitmask: (_, bitmask) => [bitmask]
|
||||
}
|
||||
const opt = {
|
||||
linesOfStops: false
|
||||
|
||||
const ctx = {
|
||||
data: {},
|
||||
opt: {
|
||||
linesOfStops: false
|
||||
},
|
||||
profile
|
||||
}
|
||||
|
||||
test('parses an address correctly', (t) => {
|
||||
|
@ -20,7 +25,7 @@ test('parses an address correctly', (t) => {
|
|||
crd: {x: 13418027, y: 52515503}
|
||||
}
|
||||
|
||||
const address = parse(profile, opt, null, input)
|
||||
const address = parse(ctx, input)
|
||||
t.deepEqual(address, {
|
||||
type: 'location',
|
||||
id: 'some id',
|
||||
|
@ -40,7 +45,7 @@ test('parses a POI correctly', (t) => {
|
|||
crd: {x: 13418027, y: 52515503}
|
||||
}
|
||||
|
||||
const poi = parse(profile, opt, null, input)
|
||||
const poi = parse(ctx, input)
|
||||
t.deepEqual(poi, {
|
||||
type: 'location',
|
||||
poi: true,
|
||||
|
@ -50,10 +55,10 @@ test('parses a POI correctly', (t) => {
|
|||
longitude: 13.418027
|
||||
})
|
||||
|
||||
const withExtId = parse(profile, opt, null, {...input, extId: 'some ext id'})
|
||||
const withExtId = parse(ctx, {...input, extId: 'some ext id'})
|
||||
t.equal(withExtId.id, 'some ext id')
|
||||
|
||||
const withLeadingZero = parse(profile, opt, null, {...input, extId: '00some ext id'})
|
||||
const withLeadingZero = parse(ctx, {...input, extId: '00some ext id'})
|
||||
t.equal(withLeadingZero.id, 'some ext id')
|
||||
|
||||
t.end()
|
||||
|
@ -68,7 +73,7 @@ test('parses a stop correctly', (t) => {
|
|||
pCls: 123
|
||||
}
|
||||
|
||||
const stop = parse(profile, opt, null, input)
|
||||
const stop = parse(ctx, input)
|
||||
t.deepEqual(stop, {
|
||||
type: 'stop',
|
||||
id: 'foo stop',
|
||||
|
@ -82,17 +87,20 @@ test('parses a stop correctly', (t) => {
|
|||
products: [123]
|
||||
})
|
||||
|
||||
const withoutLoc = parse(profile, opt, null, omit(input, ['crd']))
|
||||
const withoutLoc = parse(ctx, omit(input, ['crd']))
|
||||
t.equal(withoutLoc.location, null)
|
||||
|
||||
const mainMast = parse(profile, opt, null, {...input, isMainMast: true})
|
||||
const mainMast = parse(ctx, {...input, isMainMast: true})
|
||||
t.equal(mainMast.type, 'station')
|
||||
|
||||
const meta = parse(profile, opt, null, {...input, meta: 1})
|
||||
const meta = parse(ctx, {...input, meta: 1})
|
||||
t.equal(meta.isMeta, true)
|
||||
|
||||
const lineA = {id: 'a'}
|
||||
const withLines = parse(profile, {...opt, linesOfStops: true}, null, {
|
||||
const withLines = parse({
|
||||
...ctx,
|
||||
opt: {...ctx.opt, linesOfStops: true}
|
||||
}, {
|
||||
...input, lines: [lineA]
|
||||
})
|
||||
t.deepEqual(withLines.lines, [lineA])
|
||||
|
|
|
@ -3,16 +3,19 @@
|
|||
const test = require('tape')
|
||||
const parse = require('../../parse/operator')
|
||||
|
||||
const ctx = {
|
||||
data: {},
|
||||
opt: {},
|
||||
profile: {}
|
||||
}
|
||||
test('parses an operator correctly', (t) => {
|
||||
const profile = {}
|
||||
|
||||
const op = {
|
||||
"name": "Berliner Verkehrsbetriebe",
|
||||
"icoX": 1,
|
||||
"id": "Berliner Verkehrsbetriebe"
|
||||
}
|
||||
|
||||
t.deepEqual(parse(profile, op), {
|
||||
t.deepEqual(parse(ctx, op), {
|
||||
type: 'operator',
|
||||
id: 'berliner-verkehrsbetriebe',
|
||||
name: 'Berliner Verkehrsbetriebe'
|
||||
|
|
|
@ -4,9 +4,14 @@ const test = require('tape')
|
|||
const parse = require('../../parse/warning')
|
||||
|
||||
const profile = {
|
||||
parseProducts: bitmask => [bitmask],
|
||||
parseProductsBitmask: (_, bitmask) => [bitmask],
|
||||
parseDateTime: (_, date, time) => date + ':' + time
|
||||
}
|
||||
const ctx = {
|
||||
data: {},
|
||||
opt: {},
|
||||
profile
|
||||
}
|
||||
|
||||
test('parses warnings correctly', (t) => {
|
||||
const input = {
|
||||
|
@ -27,26 +32,26 @@ test('parses warnings correctly', (t) => {
|
|||
category: 1
|
||||
}
|
||||
|
||||
t.deepEqual(parse(profile, input), expected)
|
||||
t.deepEqual(parse(ctx, input), expected)
|
||||
|
||||
// without basic fields
|
||||
t.deepEqual(parse(profile, {...input, hid: null}), {...expected, id: null})
|
||||
t.deepEqual(parse(profile, {...input, head: null}), {...expected, summary: null})
|
||||
t.deepEqual(parse(profile, {...input, text: null}), {...expected, text: null})
|
||||
t.deepEqual(parse(profile, {...input, cat: null}), {...expected, category: null})
|
||||
t.deepEqual(parse(ctx, {...input, hid: null}), {...expected, id: null})
|
||||
t.deepEqual(parse(ctx, {...input, head: null}), {...expected, summary: null})
|
||||
t.deepEqual(parse(ctx, {...input, text: null}), {...expected, text: null})
|
||||
t.deepEqual(parse(ctx, {...input, cat: null}), {...expected, category: null})
|
||||
|
||||
// without icon
|
||||
t.deepEqual(parse(profile, {...input, icon: null}), {
|
||||
t.deepEqual(parse(ctx, {...input, icon: null}), {
|
||||
...expected, type: 'warning', icon: null
|
||||
})
|
||||
|
||||
// with products
|
||||
t.deepEqual(parse(profile, {...input, prod: 123}), {
|
||||
t.deepEqual(parse(ctx, {...input, prod: 123}), {
|
||||
...expected, products: [123]
|
||||
})
|
||||
|
||||
// validFrom, validUntil, modified
|
||||
t.deepEqual(parse(profile, {
|
||||
t.deepEqual(parse(ctx, {
|
||||
...input,
|
||||
sDate: '20190101', sTime: '094020',
|
||||
eDate: '20190101', eTime: '114020',
|
||||
|
|
|
@ -4,11 +4,16 @@ const test = require('tape')
|
|||
const parse = require('../../parse/when')
|
||||
|
||||
const profile = {
|
||||
parseDateTime: (profile, date, time, tzOffset, timestamp = false) => {
|
||||
parseDateTime: ({profile}, date, time, tzOffset, timestamp = false) => {
|
||||
if (timestamp) return ((date + '' + time) - tzOffset * 60) * 1000
|
||||
return date + ':' + time
|
||||
}
|
||||
}
|
||||
const ctx = {
|
||||
data: {},
|
||||
opt: {},
|
||||
profile
|
||||
}
|
||||
|
||||
test('parseWhen works correctly', (t) => {
|
||||
const date = '20190606'
|
||||
|
@ -21,15 +26,15 @@ test('parseWhen works correctly', (t) => {
|
|||
delay: 130 // seconds
|
||||
}
|
||||
|
||||
t.deepEqual(parse(profile, date, timeS, timeR, tzOffset), expected)
|
||||
t.deepEqual(parse(ctx, date, timeS, timeR, tzOffset), expected)
|
||||
|
||||
// no realtime data
|
||||
t.deepEqual(parse(profile, date, timeS, null, tzOffset), {
|
||||
t.deepEqual(parse(ctx, date, timeS, null, tzOffset), {
|
||||
...expected, when: expected.plannedWhen, delay: null
|
||||
})
|
||||
|
||||
// cancelled
|
||||
t.deepEqual(parse(profile, date, timeS, timeR, tzOffset, true), {
|
||||
t.deepEqual(parse(ctx, date, timeS, timeR, tzOffset, true), {
|
||||
...expected,
|
||||
when: null,
|
||||
prognosedWhen: expected.when
|
||||
|
|
Loading…
Add table
Reference in a new issue