From 20a2c8de94ae0fcc0a7712517e124d720c037596 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Fri, 19 Jan 2018 16:58:39 +0100 Subject: [PATCH 01/24] fix via :bug:, add tests :white_check_mark: --- index.js | 2 +- test/db.js | 19 +++++++++++++++++++ test/oebb.js | 19 +++++++++++++++++++ test/vbb.js | 20 ++++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 5c5f3a6a..a15259f4 100644 --- a/index.js +++ b/index.js @@ -83,7 +83,7 @@ const createClient = (profile) => { maxChg: opt.transfers, minChgTime: opt.transferTime, depLocL: [from], - viaLocL: opt.via ? [opt.via] : null, + viaLocL: opt.via ? [{loc: opt.via}] : null, arrLocL: [to], jnyFltrL: filters, getTariff: !!opt.tickets, diff --git a/test/db.js b/test/db.js index e1d07c00..4fe749db 100644 --- a/test/db.js +++ b/test/db.js @@ -209,6 +209,25 @@ test('Berlin Jungfernheide to ATZE Musiktheater', co.wrap(function* (t) { t.end() })) +test('Berlin Hbf to München Hbf with stopover at Hannover Hbf', co.wrap(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.wrap(function* (t) { const deps = yield client.departures('8011167', { duration: 5, when diff --git a/test/oebb.js b/test/oebb.js index 261cb548..787eae15 100644 --- a/test/oebb.js +++ b/test/oebb.js @@ -252,6 +252,25 @@ test('Albertina to Salzburg Hbf', co.wrap(function* (t) { t.end() })) +test('Wien to Klagenfurt Hbf with stopover at Salzburg Hbf', co.wrap(function* (t) { + const wien = '1190100' + const klagenfurtHbf = '8100085' + const salzburgHbf = '8100002' + const [journey] = yield client.journeys(wien, klagenfurtHbf, { + via: salzburgHbf, + results: 1 + }) + + const i = journey.legs.findIndex(leg => leg.destination.id === salzburgHbf) + 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, salzburgHbf) + + t.end() +})) + test('leg details for Wien Westbahnhof to München Hbf', co.wrap(function* (t) { const wienWestbahnhof = '1291501' const muenchenHbf = '8000261' diff --git a/test/vbb.js b/test/vbb.js index e613bdf7..d04edfb3 100644 --- a/test/vbb.js +++ b/test/vbb.js @@ -241,6 +241,26 @@ test('journeys – station to POI', co.wrap(function* (t) { +test('journeys – with stopover', co.wrap(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.wrap(function* (t) { const deps = yield client.departures(spichernstr, {duration: 5, when}) From 393bc9b82b9d5edbba8eded31440a419652db2de Mon Sep 17 00:00:00 2001 From: Jannis R Date: Fri, 19 Jan 2018 16:58:52 +0100 Subject: [PATCH 02/24] 2.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7b0dbcf7..07500129 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hafas-client", "description": "JavaScript client for HAFAS public transport APIs.", - "version": "2.1.0", + "version": "2.1.1", "main": "index.js", "files": [ "index.js", From e13983267243420d5f52bc85f437440da1cf00e4 Mon Sep 17 00:00:00 2001 From: Nils Strelow Date: Sat, 20 Jan 2018 13:58:31 +0100 Subject: [PATCH 03/24] Correct wrapper library in table --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 8bcba40f..e27e8d71 100644 --- a/readme.md +++ b/readme.md @@ -4,8 +4,8 @@ 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) -[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) +[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) | [`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) [![npm version](https://img.shields.io/npm/v/hafas-client.svg)](https://www.npmjs.com/package/hafas-client) From e93d7fc5f44f7e4782c96b8a0f1bfc91c23e8ead Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 23 Jan 2018 00:37:09 +0100 Subject: [PATCH 04/24] allow for a custom request fn --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index a15259f4..5ca98593 100644 --- a/index.js +++ b/index.js @@ -5,9 +5,9 @@ const maxBy = require('lodash/maxBy') const validateProfile = require('./lib/validate-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) validateProfile(profile) From e2dca96a3880ad9b0fc832ee473930d7da90419f Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 23 Jan 2018 00:41:16 +0100 Subject: [PATCH 05/24] 2.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 07500129..1c4087fd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hafas-client", "description": "JavaScript client for HAFAS public transport APIs.", - "version": "2.1.1", + "version": "2.2.0", "main": "index.js", "files": [ "index.js", From 96448bf900f8c9988be4eb96c8285b9c49510331 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 23 Jan 2018 00:50:21 +0100 Subject: [PATCH 06/24] update deps --- p/vbb/index.js | 2 +- package.json | 8 ++++---- test/vbb.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/p/vbb/index.js b/p/vbb/index.js index 2c9325c6..a3fb5a94 100644 --- a/p/vbb/index.js +++ b/p/vbb/index.js @@ -63,7 +63,7 @@ const parseLocation = (profile, l) => { res.id = to12Digit(res.id) if (!res.location.latitude || !res.location.longitude) { const [s] = getStations(res.id) - if (s) Object.assign(res.location, s.coordinates) + if (s) Object.assign(res.location, s.location) } } return res diff --git a/package.json b/package.json index 07500129..a13c2d1d 100644 --- a/package.json +++ b/package.json @@ -33,14 +33,14 @@ "dependencies": { "fetch-ponyfill": "^4.1.0", "lodash": "^4.17.4", - "luxon": "^0.2.11", + "luxon": "^0.3.1", "pinkie-promise": "^2.0.1", "query-string": "^5.0.0", "slugg": "^1.2.0", - "vbb-parse-line": "^0.2.5", + "vbb-parse-line": "^0.3.0", "vbb-parse-ticket": "^0.2.1", "vbb-short-station-name": "^0.4.0", - "vbb-stations": "^5.9.0", + "vbb-stations": "^6.1.0", "vbb-translate-ids": "^3.1.0" }, "devDependencies": { @@ -52,7 +52,7 @@ "tape": "^4.8.0", "tape-promise": "^2.0.1", "validate-fptf": "^1.2.0", - "vbb-stations-autocomplete": "^2.11.0" + "vbb-stations-autocomplete": "^3.0.0" }, "scripts": { "test": "node test/index.js", diff --git a/test/vbb.js b/test/vbb.js index d04edfb3..b8031524 100644 --- a/test/vbb.js +++ b/test/vbb.js @@ -50,7 +50,7 @@ const assertValidLine = (t, l) => { } // todo -const findStation = (query) => stations(query, true, false) +const findStation = (query) => stations(query, true, false)[0] const test = tapePromise(tape) const client = createClient(vbbProfile) From a28ead4cc1206d09b72aae10bbdfd947985fcf6d Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 23 Jan 2018 01:24:37 +0100 Subject: [PATCH 07/24] nicer async stack traces --- lib/request.js | 34 +++++++++++++++++++++++----------- package.json | 3 ++- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/lib/request.js b/lib/request.js index 0eccbb52..5190a912 100644 --- a/lib/request.js +++ b/lib/request.js @@ -1,14 +1,13 @@ 'use strict' +let captureStackTrace = () => {} +if (process.env.NODE_ENV === 'dev') { + captureStackTrace = require('capture-stack-trace') +} const Promise = require('pinkie-promise') const {fetch} = require('fetch-ponyfill')({Promise}) const {stringify} = require('query-string') -const hafasError = (err) => { - err.isHafasError = true - return err -} - const request = (profile, data) => { const body = profile.transformReqBody({lang: 'en', svcReqL: [data]}) const req = profile.transformReq({ @@ -24,20 +23,33 @@ const request = (profile, data) => { }) const url = profile.endpoint + (req.query ? '?' + 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 + captureStackTrace(err) + return fetch(url, req) .then((res) => { + err.statusCode = res.status if (!res.ok) { - const err = new Error(res.statusText) - err.statusCode = res.status - throw hafasError(err) + err.message = res.statusText + throw err } return res.json() }) .then((b) => { - if (b.err) throw hafasError(new Error(b.err)) - if (!b.svcResL || !b.svcResL[0]) throw new Error('invalid response') + if (b.err) { + err.message = b.err + throw err + } + if (!b.svcResL || !b.svcResL[0]) { + err.message = 'invalid response' + throw err + } if (b.svcResL[0].err !== 'OK') { - throw hafasError(new Error(b.svcResL[0].errTxt)) + err.message = b.svcResL[0].errTxt + throw err } const d = b.svcResL[0].res const c = d.common || {} diff --git a/package.json b/package.json index a13c2d1d..daf7f0bb 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "node": ">=6" }, "dependencies": { + "capture-stack-trace": "^1.0.0", "fetch-ponyfill": "^4.1.0", "lodash": "^4.17.4", "luxon": "^0.3.1", @@ -55,7 +56,7 @@ "vbb-stations-autocomplete": "^3.0.0" }, "scripts": { - "test": "node test/index.js", + "test": "env NODE_ENV=dev node test/index.js", "prepublishOnly": "npm test | tap-spec" } } From 0ee53ff6242a53a57cd3670db6a49dda848bd622 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 23 Jan 2018 01:30:20 +0100 Subject: [PATCH 08/24] =?UTF-8?q?fix=20=C3=96BB=20tests=20:green=5Fheart:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/request.js | 2 +- test/oebb.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/request.js b/lib/request.js index 5190a912..1aefd2b4 100644 --- a/lib/request.js +++ b/lib/request.js @@ -4,9 +4,9 @@ let captureStackTrace = () => {} if (process.env.NODE_ENV === 'dev') { captureStackTrace = require('capture-stack-trace') } +const {stringify} = require('query-string') const Promise = require('pinkie-promise') const {fetch} = require('fetch-ponyfill')({Promise}) -const {stringify} = require('query-string') const request = (profile, data) => { const body = profile.transformReqBody({lang: 'en', svcReqL: [data]}) diff --git a/test/oebb.js b/test/oebb.js index 787eae15..7c9ba9a4 100644 --- a/test/oebb.js +++ b/test/oebb.js @@ -261,12 +261,12 @@ test('Wien to Klagenfurt Hbf with stopover at Salzburg Hbf', co.wrap(function* ( results: 1 }) - const i = journey.legs.findIndex(leg => leg.destination.id === salzburgHbf) - t.ok(i >= 0, 'no leg with Hannover Hbf as destination') + const i1 = journey.legs.findIndex(leg => leg.destination.id === salzburgHbf) + t.ok(i1 >= 0, 'no leg with Salzburg Hbf as destination') - const nextLeg = journey.legs[i + 1] - t.ok(nextLeg) - t.equal(nextLeg.origin.id, salzburgHbf) + 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() })) From f19a66df8a85dfb801e390898f4b3ad110e58bd2 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 23 Jan 2018 01:49:41 +0100 Subject: [PATCH 09/24] use coroutine from Babel --- package.json | 1 - test/co.js | 31 +++++++++++++++++++++++++++++++ test/db.js | 18 +++++++++--------- test/oebb.js | 20 ++++++++++---------- test/vbb.js | 28 ++++++++++++++-------------- 5 files changed, 64 insertions(+), 34 deletions(-) create mode 100644 test/co.js diff --git a/package.json b/package.json index daf7f0bb..d00e6347 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,6 @@ "vbb-translate-ids": "^3.1.0" }, "devDependencies": { - "co": "^4.6.0", "db-stations": "^1.34.0", "is-coordinates": "^2.0.2", "is-roughly-equal": "^0.1.0", diff --git a/test/co.js b/test/co.js new file mode 100644 index 00000000..595deb14 --- /dev/null +++ b/test/co.js @@ -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 diff --git a/test/db.js b/test/db.js index 4fe749db..8c04637c 100644 --- a/test/db.js +++ b/test/db.js @@ -3,9 +3,9 @@ const getStations = require('db-stations').full const tapePromise = require('tape-promise').default const tape = require('tape') -const co = require('co') const isRoughlyEqual = require('is-roughly-equal') +const co = require('./co') const createClient = require('..') const dbProfile = require('../p/db') const modes = require('../p/db/modes') @@ -92,7 +92,7 @@ const assertValidPrice = (t, p) => { const test = tapePromise(tape) 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', { when, passedStations: true }) @@ -151,7 +151,7 @@ test('Berlin Jungfernheide to München Hbf', co.wrap(function* (t) { 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', { type: 'location', address: 'Torfstraße 17', latitude: 52.5416823, longitude: 13.3491223 @@ -180,7 +180,7 @@ test('Berlin Jungfernheide to Torfstraße 17', co.wrap(function* (t) { 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', { type: 'location', id: '991598902', name: 'ATZE Musiktheater', latitude: 52.542417, longitude: 13.350437 @@ -209,7 +209,7 @@ test('Berlin Jungfernheide to ATZE Musiktheater', co.wrap(function* (t) { t.end() })) -test('Berlin Hbf to München Hbf with stopover at Hannover Hbf', 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' @@ -228,7 +228,7 @@ test('Berlin Hbf to München Hbf with stopover at Hannover Hbf', co.wrap(functio t.end() })) -test('departures at Berlin Jungfernheide', co.wrap(function* (t) { +test('departures at Berlin Jungfernheide', co(function* (t) { const deps = yield client.departures('8011167', { duration: 5, when }) @@ -247,7 +247,7 @@ test('departures at Berlin Jungfernheide', co.wrap(function* (t) { t.end() })) -test('departures with station object', co.wrap(function* (t) { +test('departures with station object', co(function* (t) { yield client.departures({ type: 'station', id: '8011167', @@ -263,7 +263,7 @@ test('departures with station object', co.wrap(function* (t) { t.end() })) -test('nearby Berlin Jungfernheide', co.wrap(function* (t) { +test('nearby Berlin Jungfernheide', co(function* (t) { const nearby = yield client.nearby({ type: 'location', latitude: 52.530273, @@ -287,7 +287,7 @@ test('nearby Berlin Jungfernheide', co.wrap(function* (t) { t.end() })) -test('locations named Jungfernheide', co.wrap(function* (t) { +test('locations named Jungfernheide', co(function* (t) { const locations = yield client.locations('Jungfernheide', { results: 10 }) diff --git a/test/oebb.js b/test/oebb.js index 7c9ba9a4..3b0fdfea 100644 --- a/test/oebb.js +++ b/test/oebb.js @@ -4,12 +4,12 @@ // const getStations = require('db-stations').full const tapePromise = require('tape-promise').default const tape = require('tape') -const co = require('co') const isRoughlyEqual = require('is-roughly-equal') const validateFptf = require('validate-fptf') const validateLineWithoutMode = require('./validate-line-without-mode') +const co = require('./co') const createClient = require('..') const oebbProfile = require('../p/oebb') const products = require('../p/oebb/products') @@ -110,7 +110,7 @@ const assertValidLine = (t, l) => { // with optional mode const test = tapePromise(tape) 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 wienWestbahnhof = '1291501' const journeys = yield client.journeys(salzburgHbf, wienWestbahnhof, { @@ -175,7 +175,7 @@ test('Salzburg Hbf to Wien Westbahnhof', co.wrap(function* (t) { 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 wagramerStr = { type: 'location', @@ -213,7 +213,7 @@ test('Salzburg Hbf to 1220 Wien, Wagramer Straße 5', co.wrap(function* (t) { t.end() })) -test('Albertina to Salzburg Hbf', co.wrap(function* (t) { +test('Albertina to Salzburg Hbf', co(function* (t) { const albertina = { type: 'location', latitude: 48.204699, @@ -252,7 +252,7 @@ test('Albertina to Salzburg Hbf', co.wrap(function* (t) { t.end() })) -test('Wien to Klagenfurt Hbf with stopover at Salzburg 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' @@ -271,7 +271,7 @@ test('Wien to Klagenfurt Hbf with stopover at Salzburg Hbf', co.wrap(function* ( t.end() })) -test('leg details for Wien Westbahnhof to München Hbf', co.wrap(function* (t) { +test('leg details for Wien Westbahnhof to München Hbf', co(function* (t) { const wienWestbahnhof = '1291501' const muenchenHbf = '8000261' const journeys = yield client.journeys(wienWestbahnhof, muenchenHbf, { @@ -297,7 +297,7 @@ test('leg details for Wien Westbahnhof to München Hbf', co.wrap(function* (t) { t.end() })) -test('departures at Salzburg Hbf', co.wrap(function* (t) { +test('departures at Salzburg Hbf', co(function* (t) { const salzburgHbf = '8100002' const deps = yield client.departures(salzburgHbf, { duration: 5, when @@ -318,7 +318,7 @@ test('departures at Salzburg Hbf', co.wrap(function* (t) { t.end() })) -test('nearby Salzburg Hbf', co.wrap(function* (t) { +test('nearby Salzburg Hbf', co(function* (t) { const salzburgHbfPosition = { type: 'location', longitude: 13.045604, @@ -343,7 +343,7 @@ test('nearby Salzburg Hbf', co.wrap(function* (t) { t.end() })) -test('locations named Salzburg', co.wrap(function* (t) { +test('locations named Salzburg', co(function* (t) { const locations = yield client.locations('Salzburg', { results: 10 }) @@ -361,7 +361,7 @@ test('locations named Salzburg', co.wrap(function* (t) { t.end() })) -test('radar Salzburg', co.wrap(function* (t) { +test('radar Salzburg', co(function* (t) { const vehicles = yield client.radar(47.827203, 13.001261, 47.773278, 13.07562, { duration: 5 * 60, when }) diff --git a/test/vbb.js b/test/vbb.js index b8031524..9be3e0b1 100644 --- a/test/vbb.js +++ b/test/vbb.js @@ -5,9 +5,9 @@ const isRoughlyEqual = require('is-roughly-equal') const stations = require('vbb-stations-autocomplete') const tapePromise = require('tape-promise').default const tape = require('tape') -const co = require('co') const shorten = require('vbb-short-station-name') +const co = require('./co') const createClient = require('..') const vbbProfile = require('../p/vbb') const { @@ -59,7 +59,7 @@ const amrumerStr = '900000009101' const spichernstr = '900000042101' 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, { results: 3, when, passedStations: true }) @@ -112,7 +112,7 @@ test('journeys – station to station', co.wrap(function* (t) { t.end() })) -test('journeys – only subway', co.wrap(function* (t) { +test('journeys – only subway', co(function* (t) { const journeys = yield client.journeys(spichernstr, bismarckstr, { results: 20, when, products: { @@ -141,7 +141,7 @@ test('journeys – only subway', co.wrap(function* (t) { t.end() })) -test('journeys – fails with no product', co.wrap(function* (t) { +test('journeys – fails with no product', co(function* (t) { try { yield client.journeys(spichernstr, bismarckstr, { when, @@ -161,7 +161,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, { results: 1, when }) @@ -187,7 +187,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, { type: 'location', address: 'Torfstraße 17', latitude: 52.5416823, longitude: 13.3491223 @@ -214,7 +214,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, { type: 'location', id: '9980720', name: 'ATZE Musiktheater', latitude: 52.543333, longitude: 13.351686 @@ -241,7 +241,7 @@ test('journeys – station to POI', co.wrap(function* (t) { -test('journeys – with stopover', co.wrap(function* (t) { +test('journeys – with stopover', co(function* (t) { const halleschesTor = '900000012103' const leopoldplatz = '900000009102' const [journey] = yield client.journeys(spichernstr, halleschesTor, { @@ -261,7 +261,7 @@ test('journeys – with stopover', co.wrap(function* (t) { -test('departures', co.wrap(function* (t) { +test('departures', co(function* (t) { const deps = yield client.departures(spichernstr, {duration: 5, when}) t.ok(Array.isArray(deps)) @@ -282,7 +282,7 @@ test('departures', co.wrap(function* (t) { t.end() })) -test('departures with station object', co.wrap(function* (t) { +test('departures with station object', co(function* (t) { yield client.departures({ type: 'station', id: spichernstr, @@ -298,7 +298,7 @@ test('departures with station object', co.wrap(function* (t) { 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 yield client.departures(eisenach, {when}) t.pass('did not fail') @@ -308,7 +308,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 const nearby = yield client.nearby({ type: 'location', @@ -337,7 +337,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}) t.ok(Array.isArray(locations)) @@ -356,7 +356,7 @@ test('locations', co.wrap(function* (t) { -test('radar', co.wrap(function* (t) { +test('radar', co(function* (t) { const vehicles = yield client.radar(52.52411, 13.41002, 52.51942, 13.41709, { duration: 5 * 60, when }) From 0408f92257b1af4d432dc636a93aec4e7daac74e Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 23 Jan 2018 02:26:53 +0100 Subject: [PATCH 10/24] handle unhelpful VBB directions without failing :green_heart: see also #16 --- test/vbb.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/test/vbb.js b/test/vbb.js index 9be3e0b1..bb271361 100644 --- a/test/vbb.js +++ b/test/vbb.js @@ -49,7 +49,6 @@ const assertValidLine = (t, l) => { if (l.night !== null) t.equal(typeof l.night, 'boolean') } -// todo const findStation = (query) => stations(query, true, false)[0] const test = tapePromise(tape) @@ -97,7 +96,11 @@ test('journeys – station to station', co(function* (t) { assertValidWhen(t, leg.arrival, when) 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(Array.isArray(leg.passed)) @@ -276,7 +279,11 @@ test('departures', co(function* (t) { t.strictEqual(dep.station.id, spichernstr) 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) } t.end() @@ -365,7 +372,11 @@ test('radar', co(function* (t) { t.ok(vehicles.length > 0) 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) t.equal(typeof v.location.latitude, 'number') From eddf110894570715c02ada853ef8e3c059dfa9e5 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 23 Jan 2018 02:37:08 +0100 Subject: [PATCH 11/24] parseLine: don't use prodCtx.num :bug: --- parse/departure.js | 2 +- parse/line.js | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/parse/departure.js b/parse/departure.js index a4fce0dd..e8f2d9bf 100644 --- a/parse/departure.js +++ b/parse/departure.js @@ -20,7 +20,7 @@ const createParseDeparture = (profile, stations, lines, remarks) => { remarks: d.remL ? d.remL.map(findRemark) : [], 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) { const realtime = profile.parseDateTime(profile, d.date, d.stbStop.dTimeR) diff --git a/parse/line.js b/parse/line.js index 47333a14..d4e7117e 100644 --- a/parse/line.js +++ b/parse/line.js @@ -12,11 +12,10 @@ const createParseLine = (profile, operators) => { name: p.line || p.name, 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. + // todo: find a better way else if (p.line) res.id = slugg(p.line.trim()) else if (p.name) res.id = slugg(p.name.trim()) From fe33866a1582f9f300c5717bd4994b3a0666d073 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 23 Jan 2018 02:37:46 +0100 Subject: [PATCH 12/24] 2.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d00e6347..a7165107 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hafas-client", "description": "JavaScript client for HAFAS public transport APIs.", - "version": "2.1.1", + "version": "2.1.2", "main": "index.js", "files": [ "index.js", From 7cd963c3443cc897d4378cb7f662b3e68c0b9fcf Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 23 Jan 2018 02:40:39 +0100 Subject: [PATCH 13/24] =?UTF-8?q?fix=20syntax=20error=20=F0=9F=A4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parse/line.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parse/line.js b/parse/line.js index d4e7117e..79300c08 100644 --- a/parse/line.js +++ b/parse/line.js @@ -16,7 +16,7 @@ const createParseLine = (profile, operators) => { // This is terrible, but FPTF demands an ID. Let's pray for VBB to expose an ID. // todo: find a better way - else if (p.line) res.id = slugg(p.line.trim()) + if (p.line) res.id = slugg(p.line.trim()) else if (p.name) res.id = slugg(p.name.trim()) if (p.cls) res.class = p.cls From 04fb329a7eda7db0072e74b7758734de9a68e259 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 23 Jan 2018 15:54:39 +0100 Subject: [PATCH 14/24] request throttling --- package.json | 1 + test/index.js | 1 + test/throttle.js | 27 +++++++++++++++++++++++++++ throttle.js | 13 +++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 test/throttle.js create mode 100644 throttle.js diff --git a/package.json b/package.json index 63a7beb0..ab7bebb8 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "fetch-ponyfill": "^4.1.0", "lodash": "^4.17.4", "luxon": "^0.3.1", + "p-throttle": "^1.1.0", "pinkie-promise": "^2.0.1", "query-string": "^5.0.0", "slugg": "^1.2.0", diff --git a/test/index.js b/test/index.js index 5675edb4..b278e8d2 100644 --- a/test/index.js +++ b/test/index.js @@ -3,3 +3,4 @@ require('./db') require('./vbb') require('./oebb') +require('./throttle') diff --git a/test/throttle.js b/test/throttle.js new file mode 100644 index 00000000..cc849218 --- /dev/null +++ b/test/throttle.js @@ -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 diff --git a/throttle.js b/throttle.js new file mode 100644 index 00000000..99fb3cc0 --- /dev/null +++ b/throttle.js @@ -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 From 1349e9b8a0863f9cb984759e6c3454cfd894ce88 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Wed, 24 Jan 2018 16:03:33 +0100 Subject: [PATCH 15/24] fix files field :bug:, 2.2.1 --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index ab7bebb8..2f421285 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "hafas-client", "description": "JavaScript client for HAFAS public transport APIs.", - "version": "2.2.0", + "version": "2.2.1", "main": "index.js", "files": [ "index.js", + "throttle.js", "lib", "parse", "format", From 831672eeb9ef7048b2be24c5f4c69cc15f55b2cd Mon Sep 17 00:00:00 2001 From: Jannis R Date: Wed, 24 Jan 2018 23:32:54 +0100 Subject: [PATCH 16/24] =?UTF-8?q?fix=20=C3=96BB=20tests=20:green=5Fheart:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/oebb.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/oebb.js b/test/oebb.js index 3b0fdfea..d790be34 100644 --- a/test/oebb.js +++ b/test/oebb.js @@ -258,7 +258,8 @@ test('Wien to Klagenfurt Hbf with stopover at Salzburg Hbf', co(function* (t) { const salzburgHbf = '8100002' const [journey] = yield client.journeys(wien, klagenfurtHbf, { via: salzburgHbf, - results: 1 + results: 1, + when }) const i1 = journey.legs.findIndex(leg => leg.destination.id === salzburgHbf) From 39636f12bf9fde8c245bba886903d88bfd2d2262 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Fri, 26 Jan 2018 16:25:13 +0100 Subject: [PATCH 17/24] parse lines at a location --- index.js | 2 +- lib/request.js | 7 ++++--- p/oebb/index.js | 4 ++-- p/vbb/index.js | 4 ++-- parse/location.js | 14 +++++++++++++- parse/nearby.js | 6 ++++-- test/util.js | 5 +++++ 7 files changed, 31 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index 5ca98593..aff36d06 100644 --- a/index.js +++ b/index.js @@ -133,7 +133,7 @@ const createClient = (profile, request = _request) => { .then((d) => { if (!d.match || !Array.isArray(d.match.locL)) return [] const parse = profile.parseLocation - return d.match.locL.map(loc => parse(profile, loc)) + return d.match.locL.map(loc => parse(profile, loc, d.lines)) }) } diff --git a/lib/request.js b/lib/request.js index 1aefd2b4..27838806 100644 --- a/lib/request.js +++ b/lib/request.js @@ -54,9 +54,6 @@ const request = (profile, data) => { const d = b.svcResL[0].res const c = d.common || {} - if (Array.isArray(c.locL)) { - d.locations = c.locL.map(loc => profile.parseLocation(profile, loc)) - } if (Array.isArray(c.remL)) { d.remarks = c.remL.map(rem => profile.parseRemark(profile, rem)) } @@ -67,6 +64,10 @@ const request = (profile, data) => { const parse = profile.parseLine(profile, d.operators) 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 }) } diff --git a/p/oebb/index.js b/p/oebb/index.js index 0063f2d9..13a61284 100644 --- a/p/oebb/index.js +++ b/p/oebb/index.js @@ -48,10 +48,10 @@ const createParseLine = (profile, operators) => { return parseLineWithMode } -const parseLocation = (profile, l) => { +const parseLocation = (profile, l, lines) => { // ÖBB has some 'stations' **in austria** with no departures/products, // like station entrances, that are actually POIs. - const res = _parseLocation(profile, l) + const res = _parseLocation(profile, l, lines) if ( res.type === 'station' && !res.products && diff --git a/p/vbb/index.js b/p/vbb/index.js index a3fb5a94..851647ce 100644 --- a/p/vbb/index.js +++ b/p/vbb/index.js @@ -55,8 +55,8 @@ const createParseLine = (profile, operators) => { return parseLineWithMode } -const parseLocation = (profile, l) => { - const res = _parseLocation(profile, l) +const parseLocation = (profile, l, lines) => { + const res = _parseLocation(profile, l, lines) if (res.type === 'station') { res.name = shorten(res.name) diff --git a/parse/location.js b/parse/location.js index b776b920..c0de893d 100644 --- a/parse/location.js +++ b/parse/location.js @@ -6,7 +6,9 @@ const ADDRESS = 'A' // todo: what is s.rRefL? // 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'} if (l.crd) { res.latitude = l.crd.y / 1000000 @@ -20,7 +22,17 @@ const parseLocation = (profile, l) => { name: l.name, location: res } + 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 } diff --git a/parse/nearby.js b/parse/nearby.js index e009b405..7c5b3b9a 100644 --- a/parse/nearby.js +++ b/parse/nearby.js @@ -5,8 +5,10 @@ // todo: what is s.pCls? // todo: what is s.wt? // 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 return res } diff --git a/test/util.js b/test/util.js index fbd0d8c5..d304a957 100644 --- a/test/util.js +++ b/test/util.js @@ -20,6 +20,11 @@ const assertValidStation = (t, s, coordsOptional = false) => { t.ok(s.location) assertValidLocation(t, s.location, coordsOptional) } + + if ('lines' in s) { + t.ok(Array.isArray(s.lines)) + for (let l of s.lines) assertValidLine(t, l) + } } const assertValidPoi = (t, p) => { From b79c2387dd298281423b0a5cb840c2fb891e46b1 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Fri, 26 Jan 2018 17:08:07 +0100 Subject: [PATCH 18/24] location method: implementation --- index.js | 22 +++++++++++++++++++++- test/db.js | 10 ++++++++++ test/oebb.js | 10 ++++++++++ test/util.js | 6 ++---- test/vbb.js | 9 +++++++++ 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index aff36d06..91c9cf50 100644 --- a/index.js +++ b/index.js @@ -137,6 +137,26 @@ const createClient = (profile, request = _request) => { }) } + 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) + }) + } + const nearby = (location, opt = {}) => { if ('object' !== typeof location || Array.isArray(location)) { throw new Error('location must be an object.') @@ -248,7 +268,7 @@ const createClient = (profile, request = _request) => { }) } - const client = {departures, journeys, locations, nearby} + const client = {departures, journeys, locations, location, nearby} if (profile.journeyLeg) client.journeyLeg = journeyLeg if (profile.radar) client.radar = radar Object.defineProperty(client, 'profile', {value: profile}) diff --git a/test/db.js b/test/db.js index 8c04637c..b60a4aa7 100644 --- a/test/db.js +++ b/test/db.js @@ -304,3 +304,13 @@ test('locations named Jungfernheide', co(function* (t) { 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.end() +})) diff --git a/test/oebb.js b/test/oebb.js index d790be34..90a7b350 100644 --- a/test/oebb.js +++ b/test/oebb.js @@ -362,6 +362,16 @@ test('locations named Salzburg', co(function* (t) { t.end() })) +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, { duration: 5 * 60, when diff --git a/test/util.js b/test/util.js index d304a957..d338f9bb 100644 --- a/test/util.js +++ b/test/util.js @@ -6,11 +6,9 @@ const {DateTime} = require('luxon') const isValidWGS84 = require('is-coordinates') const validateFptfWith = (t, item, allowedTypes, name) => { - try { + t.doesNotThrow(() => { validateFptf.recurse(allowedTypes, item, name) - } catch (err) { - t.ifError(err) - } + }) } const assertValidStation = (t, s, coordsOptional = false) => { diff --git a/test/vbb.js b/test/vbb.js index bb271361..95d34545 100644 --- a/test/vbb.js +++ b/test/vbb.js @@ -361,6 +361,15 @@ test('locations', co(function* (t) { t.end() })) +test('location', co(function* (t) { + const loc = yield client.location(spichernstr) + + assertValidStation(t, loc) + t.equal(loc.id, spichernstr) + + t.end() +})) + test('radar', co(function* (t) { From 3e0bb8e0c33dc5327de2d782d6025a615dec9316 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Fri, 26 Jan 2018 17:23:45 +0100 Subject: [PATCH 19/24] location method: docs :memo: --- docs/location.md | 86 +++++++++++++++++++++++++++++++++++++++++++++++ p/db/example.js | 1 + p/oebb/example.js | 1 + p/vbb/example.js | 1 + readme.md | 1 + 5 files changed, 90 insertions(+) create mode 100644 docs/location.md diff --git a/docs/location.md b/docs/location.md new file mode 100644 index 00000000..72cf9a40 --- /dev/null +++ b/docs/location.md @@ -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 + } ] +} +``` diff --git a/p/db/example.js b/p/db/example.js index 72742f8c..f740bea9 100644 --- a/p/db/example.js +++ b/p/db/example.js @@ -10,6 +10,7 @@ client.journeys('8011167', '8000261', {results: 1, tickets: true}) // client.departures('8011167', {duration: 1}) // client.locations('Berlin Jungfernheide') // client.locations('Atze Musiktheater', {poi: true, addressses: false, fuzzy: false}) +// client.location('8000309') // Regensburg Hbf // client.nearby(52.4751309, 13.3656537, {results: 1}) .then((data) => { diff --git a/p/oebb/example.js b/p/oebb/example.js index 9c656063..6a04412c 100644 --- a/p/oebb/example.js +++ b/p/oebb/example.js @@ -9,6 +9,7 @@ const client = createClient(oebbProfile) client.journeys('1291501', '8100002', {results: 1}) // client.departures('8100002', {duration: 1}) // client.locations('Salzburg', {results: 2}) +// client.location('8100173') // Graz Hbf // client.nearby(47.812851, 13.045604, {distance: 60}) // client.radar(47.827203, 13.001261, 47.773278, 13.07562, {results: 10}) diff --git a/p/vbb/example.js b/p/vbb/example.js index 089e5af2..079f85c3 100644 --- a/p/vbb/example.js +++ b/p/vbb/example.js @@ -9,6 +9,7 @@ const client = createClient(vbbProfile) client.journeys('900000003201', '900000024101', {results: 1}) // client.departures('900000013102', {duration: 1}) // client.locations('Alexanderplatz', {results: 2}) +// client.location('900000042101') // Spichernstr // client.nearby(52.5137344, 13.4744798, {distance: 60}) // client.radar(52.52411, 13.41002, 52.51942, 13.41709, {results: 10}) diff --git a/readme.md b/readme.md index e27e8d71..91aa8a52 100644 --- a/readme.md +++ b/readme.md @@ -34,6 +34,7 @@ npm install hafas-client - [`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 - [`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 - [`radar(query, [opt])`](docs/radar.md) – find all vehicles currently in a certain area From 5acd84b685c344108bf2408d5cbdce0c66d9fbcd Mon Sep 17 00:00:00 2001 From: Jannis R Date: Fri, 26 Jan 2018 17:26:55 +0100 Subject: [PATCH 20/24] 2.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2f421285..b1a23855 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hafas-client", "description": "JavaScript client for HAFAS public transport APIs.", - "version": "2.2.1", + "version": "2.3.0", "main": "index.js", "files": [ "index.js", From 031769b76960d1e1529a39b8e85fe0185a617731 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Fri, 26 Jan 2018 17:40:14 +0100 Subject: [PATCH 21/24] =?UTF-8?q?fix=20build=20=F0=9F=92=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently, ÖBB doesn't have info about the lines of a station. --- test/db.js | 5 +++++ test/util.js | 11 ++++------- test/vbb.js | 5 +++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/test/db.js b/test/db.js index b60a4aa7..d8a7d640 100644 --- a/test/db.js +++ b/test/db.js @@ -312,5 +312,10 @@ test('location', co(function* (t) { 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() })) diff --git a/test/util.js b/test/util.js index d338f9bb..fbd0d8c5 100644 --- a/test/util.js +++ b/test/util.js @@ -6,9 +6,11 @@ const {DateTime} = require('luxon') const isValidWGS84 = require('is-coordinates') const validateFptfWith = (t, item, allowedTypes, name) => { - t.doesNotThrow(() => { + try { validateFptf.recurse(allowedTypes, item, name) - }) + } catch (err) { + t.ifError(err) + } } const assertValidStation = (t, s, coordsOptional = false) => { @@ -18,11 +20,6 @@ const assertValidStation = (t, s, coordsOptional = false) => { t.ok(s.location) assertValidLocation(t, s.location, coordsOptional) } - - if ('lines' in s) { - t.ok(Array.isArray(s.lines)) - for (let l of s.lines) assertValidLine(t, l) - } } const assertValidPoi = (t, p) => { diff --git a/test/vbb.js b/test/vbb.js index 95d34545..e24a1ef8 100644 --- a/test/vbb.js +++ b/test/vbb.js @@ -367,6 +367,11 @@ test('location', co(function* (t) { 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() })) From a769291d953e7f7225ef190674110e74294b0a49 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Sun, 28 Jan 2018 14:12:52 +0100 Subject: [PATCH 22/24] fix HAFAS error messages :bug: --- lib/request.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/request.js b/lib/request.js index 27838806..52600212 100644 --- a/lib/request.js +++ b/lib/request.js @@ -48,7 +48,7 @@ const request = (profile, data) => { throw err } if (b.svcResL[0].err !== 'OK') { - err.message = b.svcResL[0].errTxt + err.message = b.svcResL[0].errTxt || b.svcResL[0].err throw err } const d = b.svcResL[0].res From be6d063cf317994faf35a44c7fb8416c65e94381 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Thu, 1 Feb 2018 15:10:37 +0100 Subject: [PATCH 23/24] journey leg: delay -> departureDelay/arrivalDelay as in docs :bug: --- parse/journey-leg.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/parse/journey-leg.js b/parse/journey-leg.js index 56630d15..fac9ac44 100644 --- a/parse/journey-leg.js +++ b/parse/journey-leg.js @@ -26,7 +26,12 @@ const createParseJourneyLeg = (profile, stations, lines, remarks) => { if (pt.dep.dTimeR && pt.dep.dTimeS) { const realtime = profile.parseDateTime(profile, j.date, pt.dep.dTimeR) 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') { @@ -70,12 +75,11 @@ const createParseJourneyLeg = (profile, stations, lines, remarks) => { // see also derhuerst/vbb-rest#19 if (pt.arr.aCncl) { res.cancelled = true - res.arrival = res.arrivalPlatform = null + res.arrival = res.arrivalPlatform = res.arrivalDelay = null } if (pt.dep.dCncl) { res.cancelled = true - res.departure = res.departurePlatform = null - res.delay = null + res.departure = res.departurePlatform = res.departureDelay = null } return res From 30fe3fccc35ec62333eb33654c8d1a60646ccb58 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Thu, 1 Feb 2018 15:10:47 +0100 Subject: [PATCH 24/24] 2.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b1a23855..f5d769c4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hafas-client", "description": "JavaScript client for HAFAS public transport APIs.", - "version": "2.3.0", + "version": "2.3.1", "main": "index.js", "files": [ "index.js",