mirror of
https://github.com/public-transport/db-vendo-client.git
synced 2025-02-23 07:09:35 +02:00
2.3.1 into new-vbb-protocol
This commit is contained in:
commit
02e3e7f97e
22 changed files with 407 additions and 82 deletions
86
docs/location.md
Normal file
86
docs/location.md
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
# `location(station)`
|
||||||
|
|
||||||
|
`station` must be in one of these formats:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// a station ID, in a format compatible to the profile you use
|
||||||
|
'900000123456'
|
||||||
|
|
||||||
|
// an FPTF `station` object
|
||||||
|
{
|
||||||
|
type: 'station',
|
||||||
|
id: '900000123456',
|
||||||
|
name: 'foo station',
|
||||||
|
location: {
|
||||||
|
type: 'location',
|
||||||
|
latitude: 1.23,
|
||||||
|
longitude: 3.21
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response
|
||||||
|
|
||||||
|
As an example, we're going to use the [VBB profile](../p/vbb):
|
||||||
|
|
||||||
|
```js
|
||||||
|
const createClient = require('hafas-client')
|
||||||
|
const vbbProfile = require('hafas-client/p/vbb')
|
||||||
|
|
||||||
|
const client = createClient(vbbProfile)
|
||||||
|
|
||||||
|
client.location('900000042101') // U Spichernstr.
|
||||||
|
.then(console.log)
|
||||||
|
.catch(console.error)
|
||||||
|
```
|
||||||
|
|
||||||
|
The response may look like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
type: 'station',
|
||||||
|
id: '900000042101',
|
||||||
|
name: 'U Spichernstr.',
|
||||||
|
location: {
|
||||||
|
type: 'location',
|
||||||
|
latitude: 52.496581,
|
||||||
|
longitude: 13.330616
|
||||||
|
},
|
||||||
|
products: {
|
||||||
|
suburban: false,
|
||||||
|
subway: true,
|
||||||
|
tram: false,
|
||||||
|
bus: true,
|
||||||
|
ferry: false,
|
||||||
|
express: false,
|
||||||
|
regional: false
|
||||||
|
},
|
||||||
|
lines: [ {
|
||||||
|
type: 'line',
|
||||||
|
id: 'u1',
|
||||||
|
name: 'U1',
|
||||||
|
public: true,
|
||||||
|
class: 2,
|
||||||
|
product: 'subway',
|
||||||
|
mode: 'train',
|
||||||
|
symbol: 'U',
|
||||||
|
nr: 1,
|
||||||
|
metro: false,
|
||||||
|
express: false,
|
||||||
|
night: false },
|
||||||
|
// …
|
||||||
|
{ type: 'line',
|
||||||
|
id: 'n9',
|
||||||
|
name: 'N9',
|
||||||
|
public: true,
|
||||||
|
class: 8,
|
||||||
|
product: 'bus',
|
||||||
|
mode: 'bus',
|
||||||
|
symbol: 'N',
|
||||||
|
nr: 9,
|
||||||
|
metro: false,
|
||||||
|
express: false,
|
||||||
|
night: true
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
```
|
30
index.js
30
index.js
|
@ -5,9 +5,9 @@ const maxBy = require('lodash/maxBy')
|
||||||
|
|
||||||
const validateProfile = require('./lib/validate-profile')
|
const validateProfile = require('./lib/validate-profile')
|
||||||
const defaultProfile = require('./lib/default-profile')
|
const defaultProfile = require('./lib/default-profile')
|
||||||
const request = require('./lib/request')
|
const _request = require('./lib/request')
|
||||||
|
|
||||||
const createClient = (profile) => {
|
const createClient = (profile, request = _request) => {
|
||||||
profile = Object.assign({}, defaultProfile, profile)
|
profile = Object.assign({}, defaultProfile, profile)
|
||||||
validateProfile(profile)
|
validateProfile(profile)
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ const createClient = (profile) => {
|
||||||
maxChg: opt.transfers,
|
maxChg: opt.transfers,
|
||||||
minChgTime: opt.transferTime,
|
minChgTime: opt.transferTime,
|
||||||
depLocL: [from],
|
depLocL: [from],
|
||||||
viaLocL: opt.via ? [opt.via] : null,
|
viaLocL: opt.via ? [{loc: opt.via}] : null,
|
||||||
arrLocL: [to],
|
arrLocL: [to],
|
||||||
jnyFltrL: filters,
|
jnyFltrL: filters,
|
||||||
getTariff: !!opt.tickets,
|
getTariff: !!opt.tickets,
|
||||||
|
@ -133,7 +133,27 @@ const createClient = (profile) => {
|
||||||
.then((d) => {
|
.then((d) => {
|
||||||
if (!d.match || !Array.isArray(d.match.locL)) return []
|
if (!d.match || !Array.isArray(d.match.locL)) return []
|
||||||
const parse = profile.parseLocation
|
const parse = profile.parseLocation
|
||||||
return d.match.locL.map(loc => parse(profile, loc))
|
return d.match.locL.map(loc => parse(profile, loc, d.lines))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const location = (station) => {
|
||||||
|
if ('object' === typeof station) station = profile.formatStation(station.id)
|
||||||
|
else if ('string' === typeof station) station = profile.formatStation(station)
|
||||||
|
else throw new Error('station must be an object or a string.')
|
||||||
|
|
||||||
|
return request(profile, {
|
||||||
|
meth: 'LocDetails',
|
||||||
|
req: {
|
||||||
|
locL: [station]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((d) => {
|
||||||
|
if (!d || !Array.isArray(d.locL) || !d.locL[0]) {
|
||||||
|
// todo: proper stack trace?
|
||||||
|
throw new Error('invalid response')
|
||||||
|
}
|
||||||
|
return profile.parseLocation(profile, d.locL[0], d.lines)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +268,7 @@ const createClient = (profile) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = {departures, journeys, locations, nearby}
|
const client = {departures, journeys, locations, location, nearby}
|
||||||
if (profile.journeyLeg) client.journeyLeg = journeyLeg
|
if (profile.journeyLeg) client.journeyLeg = journeyLeg
|
||||||
if (profile.radar) client.radar = radar
|
if (profile.radar) client.radar = radar
|
||||||
Object.defineProperty(client, 'profile', {value: profile})
|
Object.defineProperty(client, 'profile', {value: profile})
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
|
let captureStackTrace = () => {}
|
||||||
|
if (process.env.NODE_ENV === 'dev') {
|
||||||
|
captureStackTrace = require('capture-stack-trace')
|
||||||
|
}
|
||||||
|
const {stringify} = require('query-string')
|
||||||
const Promise = require('pinkie-promise')
|
const Promise = require('pinkie-promise')
|
||||||
const {fetch} = require('fetch-ponyfill')({Promise})
|
const {fetch} = require('fetch-ponyfill')({Promise})
|
||||||
const {stringify} = require('query-string')
|
|
||||||
|
|
||||||
const hafasError = (err) => {
|
|
||||||
err.isHafasError = true
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
const md5 = input => crypto.createHash('md5').update(input).digest()
|
const md5 = input => crypto.createHash('md5').update(input).digest()
|
||||||
|
|
||||||
|
@ -47,28 +46,40 @@ const request = (profile, data) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = profile.endpoint +'?' + stringify(req.query)
|
const url = profile.endpoint + '?' + stringify(req.query)
|
||||||
|
|
||||||
|
// Async stack traces are not supported everywhere yet, so we create our own.
|
||||||
|
const err = new Error()
|
||||||
|
err.isHafasError = true
|
||||||
|
err.request = body
|
||||||
|
err.url = url
|
||||||
|
captureStackTrace(err)
|
||||||
|
|
||||||
return fetch(url, req)
|
return fetch(url, req)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
err.statusCode = res.status
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const err = new Error(res.statusText)
|
err.message = res.statusText
|
||||||
err.statusCode = res.status
|
throw err
|
||||||
throw hafasError(err)
|
|
||||||
}
|
}
|
||||||
return res.json()
|
return res.json()
|
||||||
})
|
})
|
||||||
.then((b) => {
|
.then((b) => {
|
||||||
if (b.err) throw hafasError(new Error(b.err))
|
if (b.err) {
|
||||||
if (!b.svcResL || !b.svcResL[0]) throw new Error('invalid response')
|
err.message = b.err
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
if (!b.svcResL || !b.svcResL[0]) {
|
||||||
|
err.message = 'invalid response'
|
||||||
|
throw err
|
||||||
|
}
|
||||||
if (b.svcResL[0].err !== 'OK') {
|
if (b.svcResL[0].err !== 'OK') {
|
||||||
throw hafasError(new Error(b.svcResL[0].errTxt))
|
err.message = b.svcResL[0].errTxt || b.svcResL[0].err
|
||||||
|
throw err
|
||||||
}
|
}
|
||||||
const d = b.svcResL[0].res
|
const d = b.svcResL[0].res
|
||||||
const c = d.common || {}
|
const c = d.common || {}
|
||||||
|
|
||||||
if (Array.isArray(c.locL)) {
|
|
||||||
d.locations = c.locL.map(loc => profile.parseLocation(profile, loc))
|
|
||||||
}
|
|
||||||
if (Array.isArray(c.remL)) {
|
if (Array.isArray(c.remL)) {
|
||||||
d.remarks = c.remL.map(rem => profile.parseRemark(profile, rem))
|
d.remarks = c.remL.map(rem => profile.parseRemark(profile, rem))
|
||||||
}
|
}
|
||||||
|
@ -79,6 +90,10 @@ const request = (profile, data) => {
|
||||||
const parse = profile.parseLine(profile, d.operators)
|
const parse = profile.parseLine(profile, d.operators)
|
||||||
d.lines = c.prodL.map(parse)
|
d.lines = c.prodL.map(parse)
|
||||||
}
|
}
|
||||||
|
if (Array.isArray(c.locL)) {
|
||||||
|
const parse = loc => profile.parseLocation(profile, loc, d.lines)
|
||||||
|
d.locations = c.locL.map(parse)
|
||||||
|
}
|
||||||
return d
|
return d
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ client.journeys('8011167', '8000261', {results: 1, tickets: true})
|
||||||
// client.departures('8011167', {duration: 1})
|
// client.departures('8011167', {duration: 1})
|
||||||
// client.locations('Berlin Jungfernheide')
|
// client.locations('Berlin Jungfernheide')
|
||||||
// client.locations('Atze Musiktheater', {poi: true, addressses: false, fuzzy: false})
|
// client.locations('Atze Musiktheater', {poi: true, addressses: false, fuzzy: false})
|
||||||
|
// client.location('8000309') // Regensburg Hbf
|
||||||
// client.nearby(52.4751309, 13.3656537, {results: 1})
|
// client.nearby(52.4751309, 13.3656537, {results: 1})
|
||||||
|
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
|
|
@ -9,6 +9,7 @@ const client = createClient(oebbProfile)
|
||||||
client.journeys('1291501', '8100002', {results: 1})
|
client.journeys('1291501', '8100002', {results: 1})
|
||||||
// client.departures('8100002', {duration: 1})
|
// client.departures('8100002', {duration: 1})
|
||||||
// client.locations('Salzburg', {results: 2})
|
// client.locations('Salzburg', {results: 2})
|
||||||
|
// client.location('8100173') // Graz Hbf
|
||||||
// client.nearby(47.812851, 13.045604, {distance: 60})
|
// client.nearby(47.812851, 13.045604, {distance: 60})
|
||||||
// client.radar(47.827203, 13.001261, 47.773278, 13.07562, {results: 10})
|
// client.radar(47.827203, 13.001261, 47.773278, 13.07562, {results: 10})
|
||||||
|
|
||||||
|
|
|
@ -48,10 +48,10 @@ const createParseLine = (profile, operators) => {
|
||||||
return parseLineWithMode
|
return parseLineWithMode
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseLocation = (profile, l) => {
|
const parseLocation = (profile, l, lines) => {
|
||||||
// ÖBB has some 'stations' **in austria** with no departures/products,
|
// ÖBB has some 'stations' **in austria** with no departures/products,
|
||||||
// like station entrances, that are actually POIs.
|
// like station entrances, that are actually POIs.
|
||||||
const res = _parseLocation(profile, l)
|
const res = _parseLocation(profile, l, lines)
|
||||||
if (
|
if (
|
||||||
res.type === 'station' &&
|
res.type === 'station' &&
|
||||||
!res.products &&
|
!res.products &&
|
||||||
|
|
|
@ -9,6 +9,7 @@ const client = createClient(vbbProfile)
|
||||||
client.journeys('900000003201', '900000024101', {results: 1})
|
client.journeys('900000003201', '900000024101', {results: 1})
|
||||||
// client.departures('900000013102', {duration: 1})
|
// client.departures('900000013102', {duration: 1})
|
||||||
// client.locations('Alexanderplatz', {results: 2})
|
// client.locations('Alexanderplatz', {results: 2})
|
||||||
|
// client.location('900000042101') // Spichernstr
|
||||||
// client.nearby(52.5137344, 13.4744798, {distance: 60})
|
// client.nearby(52.5137344, 13.4744798, {distance: 60})
|
||||||
// client.radar(52.52411, 13.41002, 52.51942, 13.41709, {results: 10})
|
// client.radar(52.52411, 13.41002, 52.51942, 13.41709, {results: 10})
|
||||||
|
|
||||||
|
|
|
@ -55,15 +55,15 @@ const createParseLine = (profile, operators) => {
|
||||||
return parseLineWithMode
|
return parseLineWithMode
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseLocation = (profile, l) => {
|
const parseLocation = (profile, l, lines) => {
|
||||||
const res = _parseLocation(profile, l)
|
const res = _parseLocation(profile, l, lines)
|
||||||
|
|
||||||
if (res.type === 'station') {
|
if (res.type === 'station') {
|
||||||
res.name = shorten(res.name)
|
res.name = shorten(res.name)
|
||||||
res.id = to12Digit(res.id)
|
res.id = to12Digit(res.id)
|
||||||
if (!res.location.latitude || !res.location.longitude) {
|
if (!res.location.latitude || !res.location.longitude) {
|
||||||
const [s] = getStations(res.id)
|
const [s] = getStations(res.id)
|
||||||
if (s) Object.assign(res.location, s.coordinates)
|
if (s) Object.assign(res.location, s.location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
|
|
16
package.json
16
package.json
|
@ -1,10 +1,11 @@
|
||||||
{
|
{
|
||||||
"name": "hafas-client",
|
"name": "hafas-client",
|
||||||
"description": "JavaScript client for HAFAS public transport APIs.",
|
"description": "JavaScript client for HAFAS public transport APIs.",
|
||||||
"version": "2.1.0",
|
"version": "2.3.1",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"files": [
|
"files": [
|
||||||
"index.js",
|
"index.js",
|
||||||
|
"throttle.js",
|
||||||
"lib",
|
"lib",
|
||||||
"parse",
|
"parse",
|
||||||
"format",
|
"format",
|
||||||
|
@ -31,20 +32,21 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"capture-stack-trace": "^1.0.0",
|
||||||
"fetch-ponyfill": "^4.1.0",
|
"fetch-ponyfill": "^4.1.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"luxon": "^0.2.11",
|
"luxon": "^0.3.1",
|
||||||
|
"p-throttle": "^1.1.0",
|
||||||
"pinkie-promise": "^2.0.1",
|
"pinkie-promise": "^2.0.1",
|
||||||
"query-string": "^5.0.0",
|
"query-string": "^5.0.0",
|
||||||
"slugg": "^1.2.0",
|
"slugg": "^1.2.0",
|
||||||
"vbb-parse-line": "^0.2.5",
|
"vbb-parse-line": "^0.3.0",
|
||||||
"vbb-parse-ticket": "^0.2.1",
|
"vbb-parse-ticket": "^0.2.1",
|
||||||
"vbb-short-station-name": "^0.4.0",
|
"vbb-short-station-name": "^0.4.0",
|
||||||
"vbb-stations": "^5.9.0",
|
"vbb-stations": "^6.1.0",
|
||||||
"vbb-translate-ids": "^3.1.0"
|
"vbb-translate-ids": "^3.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"co": "^4.6.0",
|
|
||||||
"db-stations": "^1.34.0",
|
"db-stations": "^1.34.0",
|
||||||
"is-coordinates": "^2.0.2",
|
"is-coordinates": "^2.0.2",
|
||||||
"is-roughly-equal": "^0.1.0",
|
"is-roughly-equal": "^0.1.0",
|
||||||
|
@ -52,10 +54,10 @@
|
||||||
"tape": "^4.8.0",
|
"tape": "^4.8.0",
|
||||||
"tape-promise": "^2.0.1",
|
"tape-promise": "^2.0.1",
|
||||||
"validate-fptf": "^1.2.0",
|
"validate-fptf": "^1.2.0",
|
||||||
"vbb-stations-autocomplete": "^2.11.0"
|
"vbb-stations-autocomplete": "^3.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node test/index.js",
|
"test": "env NODE_ENV=dev node test/index.js",
|
||||||
"prepublishOnly": "npm test | tap-spec"
|
"prepublishOnly": "npm test | tap-spec"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ const createParseDeparture = (profile, stations, lines, remarks) => {
|
||||||
remarks: d.remL ? d.remL.map(findRemark) : [],
|
remarks: d.remL ? d.remL.map(findRemark) : [],
|
||||||
trip: +d.jid.split('|')[1] // todo: this seems brittle
|
trip: +d.jid.split('|')[1] // todo: this seems brittle
|
||||||
}
|
}
|
||||||
// todo: res.trip from rawLine.prodCtx.num
|
// todo: res.trip from rawLine.prodCtx.num?
|
||||||
|
|
||||||
if (d.stbStop.dTimeR && d.stbStop.dTimeS) {
|
if (d.stbStop.dTimeR && d.stbStop.dTimeS) {
|
||||||
const realtime = profile.parseDateTime(profile, d.date, d.stbStop.dTimeR)
|
const realtime = profile.parseDateTime(profile, d.date, d.stbStop.dTimeR)
|
||||||
|
|
|
@ -26,7 +26,12 @@ const createParseJourneyLeg = (profile, stations, lines, remarks) => {
|
||||||
if (pt.dep.dTimeR && pt.dep.dTimeS) {
|
if (pt.dep.dTimeR && pt.dep.dTimeS) {
|
||||||
const realtime = profile.parseDateTime(profile, j.date, pt.dep.dTimeR)
|
const realtime = profile.parseDateTime(profile, j.date, pt.dep.dTimeR)
|
||||||
const planned = profile.parseDateTime(profile, j.date, pt.dep.dTimeS)
|
const planned = profile.parseDateTime(profile, j.date, pt.dep.dTimeS)
|
||||||
res.delay = Math.round((realtime - planned) / 1000)
|
res.departureDelay = Math.round((realtime - planned) / 1000)
|
||||||
|
}
|
||||||
|
if (pt.arr.aTimeR && pt.arr.aTimeS) {
|
||||||
|
const realtime = profile.parseDateTime(profile, j.date, pt.arr.aTimeR)
|
||||||
|
const planned = profile.parseDateTime(profile, j.date, pt.arr.aTimeS)
|
||||||
|
res.arrivalDelay = Math.round((realtime - planned) / 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pt.type === 'WALK') {
|
if (pt.type === 'WALK') {
|
||||||
|
@ -70,12 +75,11 @@ const createParseJourneyLeg = (profile, stations, lines, remarks) => {
|
||||||
// see also derhuerst/vbb-rest#19
|
// see also derhuerst/vbb-rest#19
|
||||||
if (pt.arr.aCncl) {
|
if (pt.arr.aCncl) {
|
||||||
res.cancelled = true
|
res.cancelled = true
|
||||||
res.arrival = res.arrivalPlatform = null
|
res.arrival = res.arrivalPlatform = res.arrivalDelay = null
|
||||||
}
|
}
|
||||||
if (pt.dep.dCncl) {
|
if (pt.dep.dCncl) {
|
||||||
res.cancelled = true
|
res.cancelled = true
|
||||||
res.departure = res.departurePlatform = null
|
res.departure = res.departurePlatform = res.departureDelay = null
|
||||||
res.delay = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
|
@ -12,12 +12,11 @@ const createParseLine = (profile, operators) => {
|
||||||
name: p.line || p.name,
|
name: p.line || p.name,
|
||||||
public: true
|
public: true
|
||||||
}
|
}
|
||||||
|
// todo: what is p.prodCtx && p.prodCtx.num?
|
||||||
|
|
||||||
// We don't get a proper line id from the API, so we use the trip nr here.
|
|
||||||
// todo: find a better way
|
|
||||||
if (p.prodCtx && p.prodCtx.num) res.id = p.prodCtx.num
|
|
||||||
// This is terrible, but FPTF demands an ID. Let's pray for VBB to expose an ID.
|
// This is terrible, but FPTF demands an ID. Let's pray for VBB to expose an ID.
|
||||||
else if (p.line) res.id = slugg(p.line.trim())
|
// todo: find a better way
|
||||||
|
if (p.line) res.id = slugg(p.line.trim())
|
||||||
else if (p.name) res.id = slugg(p.name.trim())
|
else if (p.name) res.id = slugg(p.name.trim())
|
||||||
|
|
||||||
if (p.cls) res.class = p.cls
|
if (p.cls) res.class = p.cls
|
||||||
|
|
|
@ -6,7 +6,9 @@ const ADDRESS = 'A'
|
||||||
|
|
||||||
// todo: what is s.rRefL?
|
// todo: what is s.rRefL?
|
||||||
// todo: is passing in profile necessary?
|
// todo: is passing in profile necessary?
|
||||||
const parseLocation = (profile, l) => {
|
|
||||||
|
// todo: [breaking] change to createParseLocation(profile, lines) => (l) => loc
|
||||||
|
const parseLocation = (profile, l, lines) => {
|
||||||
const res = {type: 'location'}
|
const res = {type: 'location'}
|
||||||
if (l.crd) {
|
if (l.crd) {
|
||||||
res.latitude = l.crd.y / 1000000
|
res.latitude = l.crd.y / 1000000
|
||||||
|
@ -20,7 +22,17 @@ const parseLocation = (profile, l) => {
|
||||||
name: l.name,
|
name: l.name,
|
||||||
location: res
|
location: res
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('pCls' in l) station.products = profile.parseProducts(l.pCls)
|
if ('pCls' in l) station.products = profile.parseProducts(l.pCls)
|
||||||
|
|
||||||
|
if (Array.isArray(l.pRefL) && Array.isArray(lines)) {
|
||||||
|
station.lines = []
|
||||||
|
for (let pRef of l.pRefL) {
|
||||||
|
const line = lines[pRef]
|
||||||
|
if (line) station.lines.push(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return station
|
return station
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
// todo: what is s.pCls?
|
// todo: what is s.pCls?
|
||||||
// todo: what is s.wt?
|
// todo: what is s.wt?
|
||||||
// todo: what is s.dur?
|
// todo: what is s.dur?
|
||||||
const parseNearby = (profile, n) => {
|
|
||||||
const res = profile.parseLocation(profile, n)
|
// todo: [breaking] change to createParseNearby(profile, lines) => (n) => nearby
|
||||||
|
const parseNearby = (profile, n, lines) => {
|
||||||
|
const res = profile.parseLocation(profile, n, lines)
|
||||||
res.distance = n.dist
|
res.distance = n.dist
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
HAFAS endpoint | wrapper library? | docs | example code | source code
|
HAFAS endpoint | wrapper library? | docs | example code | source code
|
||||||
---------------|------------------|------|---------|------------
|
---------------|------------------|------|---------|------------
|
||||||
[Deutsche Bahn](https://en.wikipedia.org/wiki/Deutsche_Bahn) | [`vbb-hafas`](https://github.com/derhuerst/vbb-hafas), which has additional features | [docs](p/db/readme.md) | [example code](p/db/example.js) | [src](p/db/index.js)
|
[Deutsche Bahn](https://en.wikipedia.org/wiki/Deutsche_Bahn) | [`db-hafas`](https://github.com/derhuerst/db-hafas), which has additional features | [docs](p/db/readme.md) | [example code](p/db/example.js) | [src](p/db/index.js)
|
||||||
[Berlin & Brandenburg public transport](https://en.wikipedia.org/wiki/Verkehrsverbund_Berlin-Brandenburg) | [`db-hafas`](https://github.com/derhuerst/db-hafas), which has additional features | [docs](p/vbb/readme.md) | [example code](p/vbb/example.js) | [src](p/vbb/index.js)
|
[Berlin & Brandenburg public transport](https://en.wikipedia.org/wiki/Verkehrsverbund_Berlin-Brandenburg) | [`vbb-hafas`](https://github.com/derhuerst/vbb-hafas), which has additional features | [docs](p/vbb/readme.md) | [example code](p/vbb/example.js) | [src](p/vbb/index.js)
|
||||||
[Österreichische Bundesbahnen (ÖBB)](https://en.wikipedia.org/wiki/Austrian_Federal_Railways) | – | [docs](p/oebb/readme.md) | [example code](p/oebb/example.js) | [src](p/oebb/index.js)
|
[Österreichische Bundesbahnen (ÖBB)](https://en.wikipedia.org/wiki/Austrian_Federal_Railways) | – | [docs](p/oebb/readme.md) | [example code](p/oebb/example.js) | [src](p/oebb/index.js)
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/hafas-client)
|
[](https://www.npmjs.com/package/hafas-client)
|
||||||
|
@ -34,6 +34,7 @@ npm install hafas-client
|
||||||
- [`journeyLeg(ref, lineName, [opt])`](docs/journey-leg.md) – get details for a leg of a journey
|
- [`journeyLeg(ref, lineName, [opt])`](docs/journey-leg.md) – get details for a leg of a journey
|
||||||
- [`departures(station, [opt])`](docs/departures.md) – query the next departures at a station
|
- [`departures(station, [opt])`](docs/departures.md) – query the next departures at a station
|
||||||
- [`locations(query, [opt])`](docs/locations.md) – find stations, POIs and addresses
|
- [`locations(query, [opt])`](docs/locations.md) – find stations, POIs and addresses
|
||||||
|
- [`location(id)`](docs/location.md) – get details about a location
|
||||||
- [`nearby(location, [opt])`](docs/nearby.md) – show stations & POIs around
|
- [`nearby(location, [opt])`](docs/nearby.md) – show stations & POIs around
|
||||||
- [`radar(query, [opt])`](docs/radar.md) – find all vehicles currently in a certain area
|
- [`radar(query, [opt])`](docs/radar.md) – find all vehicles currently in a certain area
|
||||||
|
|
||||||
|
|
31
test/co.js
Normal file
31
test/co.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// https://github.com/babel/babel/blob/3c8d831fe41f502cbe2459a271d19c7329ffe369/packages/babel-helpers/src/helpers.js#L242-L270
|
||||||
|
const co = (fn) => {
|
||||||
|
return function run () {
|
||||||
|
const self = this, args = arguments
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const gen = fn.apply(self, args)
|
||||||
|
const step = (key, arg) => {
|
||||||
|
try {
|
||||||
|
var info = gen[key](arg)
|
||||||
|
var value = info.value
|
||||||
|
} catch (error) {
|
||||||
|
reject(error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (info.done) resolve(value)
|
||||||
|
else Promise.resolve(value).then(_next, _throw)
|
||||||
|
}
|
||||||
|
|
||||||
|
const _next = (value) => {
|
||||||
|
step('next', value)
|
||||||
|
}
|
||||||
|
const _throw = (err) => {
|
||||||
|
step('throw', err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = co
|
50
test/db.js
50
test/db.js
|
@ -3,9 +3,9 @@
|
||||||
const getStations = require('db-stations').full
|
const getStations = require('db-stations').full
|
||||||
const tapePromise = require('tape-promise').default
|
const tapePromise = require('tape-promise').default
|
||||||
const tape = require('tape')
|
const tape = require('tape')
|
||||||
const co = require('co')
|
|
||||||
const isRoughlyEqual = require('is-roughly-equal')
|
const isRoughlyEqual = require('is-roughly-equal')
|
||||||
|
|
||||||
|
const co = require('./co')
|
||||||
const createClient = require('..')
|
const createClient = require('..')
|
||||||
const dbProfile = require('../p/db')
|
const dbProfile = require('../p/db')
|
||||||
const modes = require('../p/db/modes')
|
const modes = require('../p/db/modes')
|
||||||
|
@ -92,7 +92,7 @@ const assertValidPrice = (t, p) => {
|
||||||
const test = tapePromise(tape)
|
const test = tapePromise(tape)
|
||||||
const client = createClient(dbProfile)
|
const client = createClient(dbProfile)
|
||||||
|
|
||||||
test('Berlin Jungfernheide to München Hbf', co.wrap(function* (t) {
|
test('Berlin Jungfernheide to München Hbf', co(function* (t) {
|
||||||
const journeys = yield client.journeys('8011167', '8000261', {
|
const journeys = yield client.journeys('8011167', '8000261', {
|
||||||
when, passedStations: true
|
when, passedStations: true
|
||||||
})
|
})
|
||||||
|
@ -151,7 +151,7 @@ test('Berlin Jungfernheide to München Hbf', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('Berlin Jungfernheide to Torfstraße 17', co.wrap(function* (t) {
|
test('Berlin Jungfernheide to Torfstraße 17', co(function* (t) {
|
||||||
const journeys = yield client.journeys('8011167', {
|
const journeys = yield client.journeys('8011167', {
|
||||||
type: 'location', address: 'Torfstraße 17',
|
type: 'location', address: 'Torfstraße 17',
|
||||||
latitude: 52.5416823, longitude: 13.3491223
|
latitude: 52.5416823, longitude: 13.3491223
|
||||||
|
@ -180,7 +180,7 @@ test('Berlin Jungfernheide to Torfstraße 17', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('Berlin Jungfernheide to ATZE Musiktheater', co.wrap(function* (t) {
|
test('Berlin Jungfernheide to ATZE Musiktheater', co(function* (t) {
|
||||||
const journeys = yield client.journeys('8011167', {
|
const journeys = yield client.journeys('8011167', {
|
||||||
type: 'location', id: '991598902', name: 'ATZE Musiktheater',
|
type: 'location', id: '991598902', name: 'ATZE Musiktheater',
|
||||||
latitude: 52.542417, longitude: 13.350437
|
latitude: 52.542417, longitude: 13.350437
|
||||||
|
@ -209,7 +209,26 @@ test('Berlin Jungfernheide to ATZE Musiktheater', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('departures at Berlin Jungfernheide', co.wrap(function* (t) {
|
test('Berlin Hbf to München Hbf with stopover at Hannover Hbf', co(function* (t) {
|
||||||
|
const berlinHbf = '8011160'
|
||||||
|
const münchenHbf = '8000261'
|
||||||
|
const hannoverHbf = '8000152'
|
||||||
|
const [journey] = yield client.journeys(berlinHbf, münchenHbf, {
|
||||||
|
via: hannoverHbf,
|
||||||
|
results: 1
|
||||||
|
})
|
||||||
|
|
||||||
|
const i = journey.legs.findIndex(leg => leg.destination.id === hannoverHbf)
|
||||||
|
t.ok(i >= 0, 'no leg with Hannover Hbf as destination')
|
||||||
|
|
||||||
|
const nextLeg = journey.legs[i + 1]
|
||||||
|
t.ok(nextLeg)
|
||||||
|
t.equal(nextLeg.origin.id, hannoverHbf)
|
||||||
|
|
||||||
|
t.end()
|
||||||
|
}))
|
||||||
|
|
||||||
|
test('departures at Berlin Jungfernheide', co(function* (t) {
|
||||||
const deps = yield client.departures('8011167', {
|
const deps = yield client.departures('8011167', {
|
||||||
duration: 5, when
|
duration: 5, when
|
||||||
})
|
})
|
||||||
|
@ -228,7 +247,7 @@ test('departures at Berlin Jungfernheide', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('departures with station object', co.wrap(function* (t) {
|
test('departures with station object', co(function* (t) {
|
||||||
yield client.departures({
|
yield client.departures({
|
||||||
type: 'station',
|
type: 'station',
|
||||||
id: '8011167',
|
id: '8011167',
|
||||||
|
@ -244,7 +263,7 @@ test('departures with station object', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('nearby Berlin Jungfernheide', co.wrap(function* (t) {
|
test('nearby Berlin Jungfernheide', co(function* (t) {
|
||||||
const nearby = yield client.nearby({
|
const nearby = yield client.nearby({
|
||||||
type: 'location',
|
type: 'location',
|
||||||
latitude: 52.530273,
|
latitude: 52.530273,
|
||||||
|
@ -268,7 +287,7 @@ test('nearby Berlin Jungfernheide', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('locations named Jungfernheide', co.wrap(function* (t) {
|
test('locations named Jungfernheide', co(function* (t) {
|
||||||
const locations = yield client.locations('Jungfernheide', {
|
const locations = yield client.locations('Jungfernheide', {
|
||||||
results: 10
|
results: 10
|
||||||
})
|
})
|
||||||
|
@ -285,3 +304,18 @@ test('locations named Jungfernheide', co.wrap(function* (t) {
|
||||||
|
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
test('location', co(function* (t) {
|
||||||
|
const regensburgHbf = '8000309'
|
||||||
|
const loc = yield client.location(regensburgHbf)
|
||||||
|
|
||||||
|
assertValidStation(t, loc)
|
||||||
|
t.equal(loc.id, regensburgHbf)
|
||||||
|
|
||||||
|
t.ok(Array.isArray(loc.lines))
|
||||||
|
if (Array.isArray(loc.lines)) {
|
||||||
|
for (let line of loc.lines) assertValidLine(t, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.end()
|
||||||
|
}))
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
require('./db')
|
require('./db')
|
||||||
require('./vbb')
|
require('./vbb')
|
||||||
require('./oebb')
|
require('./oebb')
|
||||||
|
require('./throttle')
|
||||||
|
|
48
test/oebb.js
48
test/oebb.js
|
@ -4,12 +4,12 @@
|
||||||
// const getStations = require('db-stations').full
|
// const getStations = require('db-stations').full
|
||||||
const tapePromise = require('tape-promise').default
|
const tapePromise = require('tape-promise').default
|
||||||
const tape = require('tape')
|
const tape = require('tape')
|
||||||
const co = require('co')
|
|
||||||
const isRoughlyEqual = require('is-roughly-equal')
|
const isRoughlyEqual = require('is-roughly-equal')
|
||||||
const validateFptf = require('validate-fptf')
|
const validateFptf = require('validate-fptf')
|
||||||
|
|
||||||
const validateLineWithoutMode = require('./validate-line-without-mode')
|
const validateLineWithoutMode = require('./validate-line-without-mode')
|
||||||
|
|
||||||
|
const co = require('./co')
|
||||||
const createClient = require('..')
|
const createClient = require('..')
|
||||||
const oebbProfile = require('../p/oebb')
|
const oebbProfile = require('../p/oebb')
|
||||||
const products = require('../p/oebb/products')
|
const products = require('../p/oebb/products')
|
||||||
|
@ -110,7 +110,7 @@ const assertValidLine = (t, l) => { // with optional mode
|
||||||
const test = tapePromise(tape)
|
const test = tapePromise(tape)
|
||||||
const client = createClient(oebbProfile)
|
const client = createClient(oebbProfile)
|
||||||
|
|
||||||
test('Salzburg Hbf to Wien Westbahnhof', co.wrap(function* (t) {
|
test('Salzburg Hbf to Wien Westbahnhof', co(function* (t) {
|
||||||
const salzburgHbf = '8100002'
|
const salzburgHbf = '8100002'
|
||||||
const wienWestbahnhof = '1291501'
|
const wienWestbahnhof = '1291501'
|
||||||
const journeys = yield client.journeys(salzburgHbf, wienWestbahnhof, {
|
const journeys = yield client.journeys(salzburgHbf, wienWestbahnhof, {
|
||||||
|
@ -175,7 +175,7 @@ test('Salzburg Hbf to Wien Westbahnhof', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('Salzburg Hbf to 1220 Wien, Wagramer Straße 5', co.wrap(function* (t) {
|
test('Salzburg Hbf to 1220 Wien, Wagramer Straße 5', co(function* (t) {
|
||||||
const salzburgHbf = '8100002'
|
const salzburgHbf = '8100002'
|
||||||
const wagramerStr = {
|
const wagramerStr = {
|
||||||
type: 'location',
|
type: 'location',
|
||||||
|
@ -213,7 +213,7 @@ test('Salzburg Hbf to 1220 Wien, Wagramer Straße 5', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('Albertina to Salzburg Hbf', co.wrap(function* (t) {
|
test('Albertina to Salzburg Hbf', co(function* (t) {
|
||||||
const albertina = {
|
const albertina = {
|
||||||
type: 'location',
|
type: 'location',
|
||||||
latitude: 48.204699,
|
latitude: 48.204699,
|
||||||
|
@ -252,7 +252,27 @@ test('Albertina to Salzburg Hbf', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('leg details for Wien Westbahnhof to München Hbf', co.wrap(function* (t) {
|
test('Wien to Klagenfurt Hbf with stopover at Salzburg Hbf', co(function* (t) {
|
||||||
|
const wien = '1190100'
|
||||||
|
const klagenfurtHbf = '8100085'
|
||||||
|
const salzburgHbf = '8100002'
|
||||||
|
const [journey] = yield client.journeys(wien, klagenfurtHbf, {
|
||||||
|
via: salzburgHbf,
|
||||||
|
results: 1,
|
||||||
|
when
|
||||||
|
})
|
||||||
|
|
||||||
|
const i1 = journey.legs.findIndex(leg => leg.destination.id === salzburgHbf)
|
||||||
|
t.ok(i1 >= 0, 'no leg with Salzburg Hbf as destination')
|
||||||
|
|
||||||
|
const i2 = journey.legs.findIndex(leg => leg.origin.id === salzburgHbf)
|
||||||
|
t.ok(i2 >= 0, 'no leg with Salzburg Hbf as origin')
|
||||||
|
t.ok(i2 > i1, 'leg with Salzburg Hbf as origin must be after leg to it')
|
||||||
|
|
||||||
|
t.end()
|
||||||
|
}))
|
||||||
|
|
||||||
|
test('leg details for Wien Westbahnhof to München Hbf', co(function* (t) {
|
||||||
const wienWestbahnhof = '1291501'
|
const wienWestbahnhof = '1291501'
|
||||||
const muenchenHbf = '8000261'
|
const muenchenHbf = '8000261'
|
||||||
const journeys = yield client.journeys(wienWestbahnhof, muenchenHbf, {
|
const journeys = yield client.journeys(wienWestbahnhof, muenchenHbf, {
|
||||||
|
@ -278,7 +298,7 @@ test('leg details for Wien Westbahnhof to München Hbf', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('departures at Salzburg Hbf', co.wrap(function* (t) {
|
test('departures at Salzburg Hbf', co(function* (t) {
|
||||||
const salzburgHbf = '8100002'
|
const salzburgHbf = '8100002'
|
||||||
const deps = yield client.departures(salzburgHbf, {
|
const deps = yield client.departures(salzburgHbf, {
|
||||||
duration: 5, when
|
duration: 5, when
|
||||||
|
@ -299,7 +319,7 @@ test('departures at Salzburg Hbf', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('nearby Salzburg Hbf', co.wrap(function* (t) {
|
test('nearby Salzburg Hbf', co(function* (t) {
|
||||||
const salzburgHbfPosition = {
|
const salzburgHbfPosition = {
|
||||||
type: 'location',
|
type: 'location',
|
||||||
longitude: 13.045604,
|
longitude: 13.045604,
|
||||||
|
@ -324,7 +344,7 @@ test('nearby Salzburg Hbf', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('locations named Salzburg', co.wrap(function* (t) {
|
test('locations named Salzburg', co(function* (t) {
|
||||||
const locations = yield client.locations('Salzburg', {
|
const locations = yield client.locations('Salzburg', {
|
||||||
results: 10
|
results: 10
|
||||||
})
|
})
|
||||||
|
@ -342,7 +362,17 @@ test('locations named Salzburg', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('radar Salzburg', co.wrap(function* (t) {
|
test('location', co(function* (t) {
|
||||||
|
const grazHbf = '8100173'
|
||||||
|
const loc = yield client.location(grazHbf)
|
||||||
|
|
||||||
|
assertValidStation(t, loc)
|
||||||
|
t.equal(loc.id, grazHbf)
|
||||||
|
|
||||||
|
t.end()
|
||||||
|
}))
|
||||||
|
|
||||||
|
test('radar Salzburg', co(function* (t) {
|
||||||
const vehicles = yield client.radar(47.827203, 13.001261, 47.773278, 13.07562, {
|
const vehicles = yield client.radar(47.827203, 13.001261, 47.773278, 13.07562, {
|
||||||
duration: 5 * 60, when
|
duration: 5 * 60, when
|
||||||
})
|
})
|
||||||
|
|
27
test/throttle.js
Normal file
27
test/throttle.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const test = require('tape')
|
||||||
|
|
||||||
|
const createThrottledClient = require('../throttle')
|
||||||
|
const vbbProfile = require('../p/vbb')
|
||||||
|
|
||||||
|
const spichernstr = '900000042101'
|
||||||
|
|
||||||
|
test('throttle works', (t) => {
|
||||||
|
let calls = 0
|
||||||
|
const transformReqBody = (body) => {
|
||||||
|
calls++
|
||||||
|
return vbbProfile.transformReqBody(body)
|
||||||
|
}
|
||||||
|
const mockProfile = Object.assign({}, vbbProfile, {transformReqBody})
|
||||||
|
|
||||||
|
const client = createThrottledClient(mockProfile, 2, 1000)
|
||||||
|
for (let i = 0; i < 10; i++) client.departures(spichernstr, {duration: 1})
|
||||||
|
|
||||||
|
t.plan(3)
|
||||||
|
setTimeout(() => t.equal(calls, 2), 500)
|
||||||
|
setTimeout(() => t.equal(calls, 4), 1500)
|
||||||
|
setTimeout(() => t.equal(calls, 6), 2500)
|
||||||
|
})
|
||||||
|
|
||||||
|
// todo
|
81
test/vbb.js
81
test/vbb.js
|
@ -5,9 +5,9 @@ const isRoughlyEqual = require('is-roughly-equal')
|
||||||
const stations = require('vbb-stations-autocomplete')
|
const stations = require('vbb-stations-autocomplete')
|
||||||
const tapePromise = require('tape-promise').default
|
const tapePromise = require('tape-promise').default
|
||||||
const tape = require('tape')
|
const tape = require('tape')
|
||||||
const co = require('co')
|
|
||||||
const shorten = require('vbb-short-station-name')
|
const shorten = require('vbb-short-station-name')
|
||||||
|
|
||||||
|
const co = require('./co')
|
||||||
const createClient = require('..')
|
const createClient = require('..')
|
||||||
const vbbProfile = require('../p/vbb')
|
const vbbProfile = require('../p/vbb')
|
||||||
const {
|
const {
|
||||||
|
@ -49,8 +49,7 @@ const assertValidLine = (t, l) => {
|
||||||
if (l.night !== null) t.equal(typeof l.night, 'boolean')
|
if (l.night !== null) t.equal(typeof l.night, 'boolean')
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo
|
const findStation = (query) => stations(query, true, false)[0]
|
||||||
const findStation = (query) => stations(query, true, false)
|
|
||||||
|
|
||||||
const test = tapePromise(tape)
|
const test = tapePromise(tape)
|
||||||
const client = createClient(vbbProfile)
|
const client = createClient(vbbProfile)
|
||||||
|
@ -59,7 +58,7 @@ const amrumerStr = '900000009101'
|
||||||
const spichernstr = '900000042101'
|
const spichernstr = '900000042101'
|
||||||
const bismarckstr = '900000024201'
|
const bismarckstr = '900000024201'
|
||||||
|
|
||||||
test('journeys – station to station', co.wrap(function* (t) {
|
test('journeys – station to station', co(function* (t) {
|
||||||
const journeys = yield client.journeys(spichernstr, amrumerStr, {
|
const journeys = yield client.journeys(spichernstr, amrumerStr, {
|
||||||
results: 3, when, passedStations: true
|
results: 3, when, passedStations: true
|
||||||
})
|
})
|
||||||
|
@ -97,7 +96,11 @@ test('journeys – station to station', co.wrap(function* (t) {
|
||||||
assertValidWhen(t, leg.arrival, when)
|
assertValidWhen(t, leg.arrival, when)
|
||||||
|
|
||||||
assertValidLine(t, leg.line)
|
assertValidLine(t, leg.line)
|
||||||
t.ok(findStation(leg.direction))
|
if (!findStation(leg.direction)) {
|
||||||
|
const err = new Error('unknown direction: ' + leg.direction)
|
||||||
|
err.stack = err.stack.split('\n').slice(0, 2).join('\n')
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
t.ok(leg.direction.indexOf('(Berlin)') === -1)
|
t.ok(leg.direction.indexOf('(Berlin)') === -1)
|
||||||
|
|
||||||
t.ok(Array.isArray(leg.passed))
|
t.ok(Array.isArray(leg.passed))
|
||||||
|
@ -112,7 +115,7 @@ test('journeys – station to station', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('journeys – only subway', co.wrap(function* (t) {
|
test('journeys – only subway', co(function* (t) {
|
||||||
const journeys = yield client.journeys(spichernstr, bismarckstr, {
|
const journeys = yield client.journeys(spichernstr, bismarckstr, {
|
||||||
results: 20, when,
|
results: 20, when,
|
||||||
products: {
|
products: {
|
||||||
|
@ -141,7 +144,7 @@ test('journeys – only subway', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('journeys – fails with no product', co.wrap(function* (t) {
|
test('journeys – fails with no product', co(function* (t) {
|
||||||
try {
|
try {
|
||||||
yield client.journeys(spichernstr, bismarckstr, {
|
yield client.journeys(spichernstr, bismarckstr, {
|
||||||
when,
|
when,
|
||||||
|
@ -161,7 +164,7 @@ test('journeys – fails with no product', co.wrap(function* (t) {
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('journey leg details', co.wrap(function* (t) {
|
test('journey leg details', co(function* (t) {
|
||||||
const journeys = yield client.journeys(spichernstr, amrumerStr, {
|
const journeys = yield client.journeys(spichernstr, amrumerStr, {
|
||||||
results: 1, when
|
results: 1, when
|
||||||
})
|
})
|
||||||
|
@ -187,7 +190,7 @@ test('journey leg details', co.wrap(function* (t) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test('journeys – station to address', co.wrap(function* (t) {
|
test('journeys – station to address', co(function* (t) {
|
||||||
const journeys = yield client.journeys(spichernstr, {
|
const journeys = yield client.journeys(spichernstr, {
|
||||||
type: 'location', address: 'Torfstraße 17',
|
type: 'location', address: 'Torfstraße 17',
|
||||||
latitude: 52.5416823, longitude: 13.3491223
|
latitude: 52.5416823, longitude: 13.3491223
|
||||||
|
@ -214,7 +217,7 @@ test('journeys – station to address', co.wrap(function* (t) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test('journeys – station to POI', co.wrap(function* (t) {
|
test('journeys – station to POI', co(function* (t) {
|
||||||
const journeys = yield client.journeys(spichernstr, {
|
const journeys = yield client.journeys(spichernstr, {
|
||||||
type: 'location', id: '9980720', name: 'ATZE Musiktheater',
|
type: 'location', id: '9980720', name: 'ATZE Musiktheater',
|
||||||
latitude: 52.543333, longitude: 13.351686
|
latitude: 52.543333, longitude: 13.351686
|
||||||
|
@ -241,7 +244,27 @@ test('journeys – station to POI', co.wrap(function* (t) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test('departures', co.wrap(function* (t) {
|
test('journeys – with stopover', co(function* (t) {
|
||||||
|
const halleschesTor = '900000012103'
|
||||||
|
const leopoldplatz = '900000009102'
|
||||||
|
const [journey] = yield client.journeys(spichernstr, halleschesTor, {
|
||||||
|
via: leopoldplatz,
|
||||||
|
results: 1
|
||||||
|
})
|
||||||
|
|
||||||
|
const i = journey.legs.findIndex(leg => leg.destination.id === leopoldplatz)
|
||||||
|
t.ok(i >= 0, 'no leg with Leopoldplatz as destination')
|
||||||
|
|
||||||
|
const nextLeg = journey.legs[i + 1]
|
||||||
|
t.ok(nextLeg)
|
||||||
|
t.equal(nextLeg.origin.id, leopoldplatz)
|
||||||
|
|
||||||
|
t.end()
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
test('departures', co(function* (t) {
|
||||||
const deps = yield client.departures(spichernstr, {duration: 5, when})
|
const deps = yield client.departures(spichernstr, {duration: 5, when})
|
||||||
|
|
||||||
t.ok(Array.isArray(deps))
|
t.ok(Array.isArray(deps))
|
||||||
|
@ -256,13 +279,17 @@ test('departures', co.wrap(function* (t) {
|
||||||
t.strictEqual(dep.station.id, spichernstr)
|
t.strictEqual(dep.station.id, spichernstr)
|
||||||
|
|
||||||
assertValidWhen(t, dep.when, when)
|
assertValidWhen(t, dep.when, when)
|
||||||
t.ok(findStation(dep.direction))
|
if (!findStation(dep.direction)) {
|
||||||
|
const err = new Error('unknown direction: ' + dep.direction)
|
||||||
|
err.stack = err.stack.split('\n').slice(0, 2).join('\n')
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
assertValidLine(t, dep.line)
|
assertValidLine(t, dep.line)
|
||||||
}
|
}
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('departures with station object', co.wrap(function* (t) {
|
test('departures with station object', co(function* (t) {
|
||||||
yield client.departures({
|
yield client.departures({
|
||||||
type: 'station',
|
type: 'station',
|
||||||
id: spichernstr,
|
id: spichernstr,
|
||||||
|
@ -278,7 +305,7 @@ test('departures with station object', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
test('departures at 7-digit station', co.wrap(function* (t) {
|
test('departures at 7-digit station', co(function* (t) {
|
||||||
const eisenach = '8010097' // see derhuerst/vbb-hafas#22
|
const eisenach = '8010097' // see derhuerst/vbb-hafas#22
|
||||||
yield client.departures(eisenach, {when})
|
yield client.departures(eisenach, {when})
|
||||||
t.pass('did not fail')
|
t.pass('did not fail')
|
||||||
|
@ -288,7 +315,7 @@ test('departures at 7-digit station', co.wrap(function* (t) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test('nearby', co.wrap(function* (t) {
|
test('nearby', co(function* (t) {
|
||||||
// Berliner Str./Bundesallee
|
// Berliner Str./Bundesallee
|
||||||
const nearby = yield client.nearby({
|
const nearby = yield client.nearby({
|
||||||
type: 'location',
|
type: 'location',
|
||||||
|
@ -317,7 +344,7 @@ test('nearby', co.wrap(function* (t) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
test('locations', co.wrap(function* (t) {
|
test('locations', co(function* (t) {
|
||||||
const locations = yield client.locations('Alexanderplatz', {results: 10})
|
const locations = yield client.locations('Alexanderplatz', {results: 10})
|
||||||
|
|
||||||
t.ok(Array.isArray(locations))
|
t.ok(Array.isArray(locations))
|
||||||
|
@ -334,9 +361,23 @@ test('locations', co.wrap(function* (t) {
|
||||||
t.end()
|
t.end()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
test('location', co(function* (t) {
|
||||||
|
const loc = yield client.location(spichernstr)
|
||||||
|
|
||||||
|
assertValidStation(t, loc)
|
||||||
|
t.equal(loc.id, spichernstr)
|
||||||
|
|
||||||
|
t.ok(Array.isArray(loc.lines))
|
||||||
|
if (Array.isArray(loc.lines)) {
|
||||||
|
for (let line of loc.lines) assertValidLine(t, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.end()
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
test('radar', co.wrap(function* (t) {
|
|
||||||
|
test('radar', co(function* (t) {
|
||||||
const vehicles = yield client.radar(52.52411, 13.41002, 52.51942, 13.41709, {
|
const vehicles = yield client.radar(52.52411, 13.41002, 52.51942, 13.41709, {
|
||||||
duration: 5 * 60, when
|
duration: 5 * 60, when
|
||||||
})
|
})
|
||||||
|
@ -345,7 +386,11 @@ test('radar', co.wrap(function* (t) {
|
||||||
t.ok(vehicles.length > 0)
|
t.ok(vehicles.length > 0)
|
||||||
for (let v of vehicles) {
|
for (let v of vehicles) {
|
||||||
|
|
||||||
t.ok(findStation(v.direction))
|
if (!findStation(v.direction)) {
|
||||||
|
const err = new Error('unknown direction: ' + v.direction)
|
||||||
|
err.stack = err.stack.split('\n').slice(0, 2).join('\n')
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
assertValidLine(t, v.line)
|
assertValidLine(t, v.line)
|
||||||
|
|
||||||
t.equal(typeof v.location.latitude, 'number')
|
t.equal(typeof v.location.latitude, 'number')
|
||||||
|
|
13
throttle.js
Normal file
13
throttle.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const throttle = require('p-throttle')
|
||||||
|
|
||||||
|
const request = require('./lib/request')
|
||||||
|
const createClient = require('.')
|
||||||
|
|
||||||
|
const createThrottledClient = (profile, limit = 5, interval = 1000) => {
|
||||||
|
const throttledRequest = throttle(request, limit, interval)
|
||||||
|
return createClient(profile, throttledRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = createThrottledClient
|
Loading…
Add table
Reference in a new issue