@transportme/load-ptv-gtfs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/unit-test.yml +46 -0
- package/lib/constants.mjs +18 -0
- package/lib/gtfs-package/PTVGTFS.mjs +96 -0
- package/lib/gtfs-parser/GTFSAgency.mjs +15 -0
- package/lib/gtfs-parser/GTFSCalendar.mjs +63 -0
- package/lib/gtfs-parser/GTFSCalendarDate.mjs +15 -0
- package/lib/gtfs-parser/GTFSRoute.mjs +106 -0
- package/lib/gtfs-parser/GTFSShape.mjs +39 -0
- package/lib/gtfs-parser/GTFSStop.mjs +212 -0
- package/lib/gtfs-parser/GTFSStopTime.mjs +30 -0
- package/lib/gtfs-parser/GTFSTrip.mjs +169 -0
- package/lib/gtfs-parser/readers/GTFSAgencyReader.mjs +27 -0
- package/lib/gtfs-parser/readers/GTFSCalendarDatesReader.mjs +25 -0
- package/lib/gtfs-parser/readers/GTFSCalendarReader.mjs +63 -0
- package/lib/gtfs-parser/readers/GTFSReader.mjs +48 -0
- package/lib/gtfs-parser/readers/GTFSRouteReader.mjs +35 -0
- package/lib/gtfs-parser/readers/GTFSShapeReader.mjs +75 -0
- package/lib/gtfs-parser/readers/GTFSStopTimesReader.mjs +85 -0
- package/lib/gtfs-parser/readers/GTFSStopsReader.mjs +36 -0
- package/lib/gtfs-parser/readers/GTFSTripReader.mjs +61 -0
- package/lib/gtfs-parser/readers/line-reader.mjs +112 -0
- package/lib/loader/RouteLoader.mjs +101 -0
- package/lib/loader/ShapeLoader.mjs +86 -0
- package/lib/loader/StopsLoader.mjs +139 -0
- package/lib/loader/TripLoader.mjs +187 -0
- package/lib/post-processing/merge-stops.mjs +85 -0
- package/lib/post-processing/set-route-stops.mjs +73 -0
- package/lib/post-processing/set-stop-services.mjs +64 -0
- package/lib/utils.mjs +16 -0
- package/package.json +27 -0
- package/test/gtfs-calendar.test.mjs +182 -0
- package/test/gtfs-route-loader.test.mjs +190 -0
- package/test/gtfs-routes.test.mjs +77 -0
- package/test/gtfs-shapes-loader.test.mjs +105 -0
- package/test/gtfs-shapes.test.mjs +23 -0
- package/test/gtfs-stop-loader-metro.test.mjs +49 -0
- package/test/gtfs-stop-loader.test.mjs +223 -0
- package/test/gtfs-stop-times.test.mjs +37 -0
- package/test/gtfs-stops.test.mjs +290 -0
- package/test/gtfs-trip-loader.test.mjs +142 -0
- package/test/gtfs-trips.test.mjs +109 -0
- package/test/line-reader.test.mjs +94 -0
- package/test/merge-stops.test.mjs +376 -0
- package/test/ptv-gtfs.test.mjs +106 -0
- package/test/sample-data/calendar/calendar.txt +34 -0
- package/test/sample-data/calendar/calendar_dates.txt +26 -0
- package/test/sample-data/gtfs-splitting/force_unique_stops_bus.txt +7 -0
- package/test/sample-data/gtfs-splitting/force_unique_stops_tram.txt +3 -0
- package/test/sample-data/gtfs-splitting/line_reader_test.txt +8 -0
- package/test/sample-data/gtfs-splitting/name_overrides.txt +4 -0
- package/test/sample-data/gtfs-splitting/nov_2024_train_data.txt +6 -0
- package/test/sample-data/gtfs-splitting/sample_stops.txt +20 -0
- package/test/sample-data/gtfs-splitting/special_chars_stops_csv.txt +6 -0
- package/test/sample-data/gtfs-splitting/stops_without_secondary.txt +6 -0
- package/test/sample-data/gtfs-unzipping/gtfs.zip +0 -0
- package/test/sample-data/one_line.csv +2 -0
- package/test/sample-data/routes/agency.txt +11 -0
- package/test/sample-data/routes/metro_bus_routes.txt +4 -0
- package/test/sample-data/routes/metro_lines.txt +5 -0
- package/test/sample-data/routes/regional_bus_routes.txt +7 -0
- package/test/sample-data/routes/vline.txt +7 -0
- package/test/sample-data/routes/west_gipp_transit.txt +20 -0
- package/test/sample-data/shapes/shapes.txt +89 -0
- package/test/sample-data/shapes/stop_times.txt +9 -0
- package/test/sample-data/shapes/stops.txt +4 -0
- package/test/sample-data/shapes/trips.txt +4 -0
- package/test/sample-data/stop-data/name-overrides.json +25 -0
- package/test/sample-data/stop-data/unique-stops.json +1 -0
- package/test/sample-data/suburbs.json +77 -0
- package/test/sample-data/trips/bus_trips.txt +5 -0
- package/test/sample-data/trips/stop_times.txt +29 -0
- package/test/sample-data/trips/stop_times_new.txt +8 -0
- package/test/sample-data/trips/stops.txt +8 -0
- package/test/sample-data/trips/trips.txt +5 -0
- package/test/sample-data/trips/trips_new.txt +2 -0
- package/test/set-stop-services.test.mjs +69 -0
- package/test/utils-test.mjs +26 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { TRANSIT_MODES } from '../constants.mjs'
|
|
2
|
+
import GTFSCalendar from './GTFSCalendar.mjs'
|
|
3
|
+
|
|
4
|
+
export default class GTFSTrip {
|
|
5
|
+
|
|
6
|
+
#routeGTFSID
|
|
7
|
+
#operationDays
|
|
8
|
+
#tripID
|
|
9
|
+
#shapeID
|
|
10
|
+
#headsign
|
|
11
|
+
#direction
|
|
12
|
+
#block
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} param0 The trip data
|
|
17
|
+
* @param {string} param0.routeGTFSID The route ID associated with the trip. This should be the raw ID, eg "6-123-mjp-1"
|
|
18
|
+
* @param {GTFSCalendar} param0.calendar The calendar type
|
|
19
|
+
* @param {string} param0.id The unique trip ID
|
|
20
|
+
* @param {string} param0.shapeID The shape ID associate with the trip
|
|
21
|
+
* @param {string} param0.headsign The headsign on the vehicle serving the trip
|
|
22
|
+
* @param {string} param0.direction The direction of the trip. "0" for outbound and "1" for inbound trips.
|
|
23
|
+
* @param {string} param0.block The block ID of the trip.
|
|
24
|
+
*/
|
|
25
|
+
constructor({ routeGTFSID, calendar, id, shapeID, headsign, direction, block }) {
|
|
26
|
+
this.#routeGTFSID = routeGTFSID
|
|
27
|
+
this.#operationDays = calendar.getOperationDays()
|
|
28
|
+
this.#tripID = id
|
|
29
|
+
this.#shapeID = shapeID
|
|
30
|
+
this.#headsign = headsign
|
|
31
|
+
this.#direction = direction
|
|
32
|
+
this.#block = block
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Checks if the GTFSTrip (or subclass) is able to process the given trip data
|
|
37
|
+
* @param {Object} data The trip being checked
|
|
38
|
+
* @returns true if the class is able to process the trip
|
|
39
|
+
*/
|
|
40
|
+
static canProcess(data) {
|
|
41
|
+
return true
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Creates a new GTFSTrip with the trip data that was passed in
|
|
46
|
+
* @param {Object} data The trip data being created
|
|
47
|
+
* @param {string} mode The transit mode
|
|
48
|
+
* @returns {GTFSTrip} A trip instance representing the data being passed in
|
|
49
|
+
*/
|
|
50
|
+
static create(data, mode) {
|
|
51
|
+
let types = [ SmartrakTrip, MetroTrip, GTFSTrip ]
|
|
52
|
+
for (let type of types) {
|
|
53
|
+
if (type.canProcess(data, mode)) return new type(data)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Gets the trip data in a database friendly format
|
|
59
|
+
* @returns {Object} The trip data that will be saved into the database
|
|
60
|
+
*/
|
|
61
|
+
getTripData() {
|
|
62
|
+
return {
|
|
63
|
+
routeGTFSID: this.getRouteGTFSID(),
|
|
64
|
+
operationDays: this.getOperationDays(),
|
|
65
|
+
tripID: this.getTripID(),
|
|
66
|
+
shapeID: this.getShapeID(),
|
|
67
|
+
block: this.getBlock(),
|
|
68
|
+
gtfsDirection: this.getGTFSDirection()
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
getBlock() {
|
|
73
|
+
return this.#block || null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getOperationDays() {
|
|
77
|
+
return this.#operationDays
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
getRouteGTFSID() {
|
|
81
|
+
return this.#routeGTFSID
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
getShapeID() {
|
|
85
|
+
return this.#shapeID
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
getTripID() {
|
|
89
|
+
return this.#tripID
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
getHeadsign() {
|
|
93
|
+
return this.#headsign
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
getGTFSDirection() {
|
|
97
|
+
return parseInt(this.#direction)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Used to represent a Smartrak bus trip.
|
|
103
|
+
*
|
|
104
|
+
* Trip IDs are of the form DEPOT-ROUTE--ROUTE_VARIANT-ROSTER-TRIP_ID
|
|
105
|
+
*
|
|
106
|
+
* Example: 13-476--1-Sat5-34737060
|
|
107
|
+
*/
|
|
108
|
+
export class SmartrakTrip extends GTFSTrip {
|
|
109
|
+
|
|
110
|
+
#depotID
|
|
111
|
+
|
|
112
|
+
constructor(data) {
|
|
113
|
+
super(data)
|
|
114
|
+
|
|
115
|
+
let depotID = data.id.match(/^(\d{2})-\w+/)
|
|
116
|
+
this.#depotID = depotID[1]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static canProcess(data, mode) {
|
|
120
|
+
return mode === TRANSIT_MODES.bus && data.id.match(/^(\d{2})-\w+/)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
getTripData() {
|
|
124
|
+
return {
|
|
125
|
+
...super.getTripData(),
|
|
126
|
+
depotID: this.getDepotID()
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getDepotID() {
|
|
131
|
+
return parseInt(this.#depotID)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Used to represent a Metro train trip.
|
|
138
|
+
*
|
|
139
|
+
* Trip IDs are of the form 02-ROUTE--ROUTE_VARIANT-ROSTER-TDN. Note that TDNs are alphanumeric
|
|
140
|
+
*
|
|
141
|
+
* Example: 02-BEG--58-T5_n4-3651
|
|
142
|
+
*/
|
|
143
|
+
export class MetroTrip extends GTFSTrip {
|
|
144
|
+
|
|
145
|
+
#runID
|
|
146
|
+
|
|
147
|
+
constructor(data) {
|
|
148
|
+
super(data)
|
|
149
|
+
|
|
150
|
+
let runID = data.id.match(/^02-\w{3}-.*-(\w\d{3})$/)
|
|
151
|
+
this.#runID = runID[1]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
static canProcess(data, mode) {
|
|
155
|
+
return mode === TRANSIT_MODES.metroTrain && data.id.match(/^02-\w{3}-.*-(\w\d{3})$/)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
getTripData() {
|
|
159
|
+
return {
|
|
160
|
+
...super.getTripData(),
|
|
161
|
+
runID: this.getRunID()
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
getRunID() {
|
|
166
|
+
return this.#runID
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import GTFSAgency from '../GTFSAgency.mjs'
|
|
2
|
+
import GTFSReader from './GTFSReader.mjs'
|
|
3
|
+
|
|
4
|
+
export default class GTFSAgencyReader extends GTFSReader {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Converts a CSV row into an operator object
|
|
8
|
+
*
|
|
9
|
+
* @param {object} data A JSON object containing the following fields:
|
|
10
|
+
* - id: The operator ID
|
|
11
|
+
* - name: The operator name
|
|
12
|
+
* - website: The operator's website
|
|
13
|
+
* - phone: The operator's phone number
|
|
14
|
+
*
|
|
15
|
+
* @returns {GTFSAgency} An object representing the operator data
|
|
16
|
+
*/
|
|
17
|
+
processEntity(data) {
|
|
18
|
+
let agencyData = {
|
|
19
|
+
id: data.agency_id,
|
|
20
|
+
name: data.agency_name,
|
|
21
|
+
website: data.agency_url,
|
|
22
|
+
phone: data.agency_phone
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return new GTFSAgency(agencyData)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import GTFSCalendarDate from '../GTFSCalendarDate.mjs'
|
|
2
|
+
import GTFSReader from './GTFSReader.mjs'
|
|
3
|
+
|
|
4
|
+
export default class GTFSCalendarDateReader extends GTFSReader {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Converts a CSV row into an operator object
|
|
8
|
+
*
|
|
9
|
+
* @param {object} data A JSON object containing the following fields:
|
|
10
|
+
* @param {string} data.id The calendar ID
|
|
11
|
+
* @param {string} data.date The calendar date
|
|
12
|
+
* @param {string} data.type The exception type
|
|
13
|
+
*
|
|
14
|
+
* @returns {GTFSCalendarDate} An object representing the calendar date entry
|
|
15
|
+
*/
|
|
16
|
+
processEntity(data) {
|
|
17
|
+
let calendarDateData = {
|
|
18
|
+
id: data.service_id,
|
|
19
|
+
date: data.date,
|
|
20
|
+
type: data.exception_type
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return new GTFSCalendarDate(calendarDateData)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import GTFSCalendar from '../GTFSCalendar.mjs'
|
|
2
|
+
import GTFSCalendarDateReader from './GTFSCalendarDatesReader.mjs'
|
|
3
|
+
import GTFSReader from './GTFSReader.mjs'
|
|
4
|
+
|
|
5
|
+
export default class GTFSCalendarReader extends GTFSReader {
|
|
6
|
+
|
|
7
|
+
#calendarDateFile
|
|
8
|
+
#calendarDates = {}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Constructs a new GTFS Calendar reader.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} calendarFile The path to the GTFS Calendar file
|
|
14
|
+
* @param {string} calendarDateFile The path to the GTFS Calendar Dates file
|
|
15
|
+
*/
|
|
16
|
+
constructor(calendarFile, calendarDateFile) {
|
|
17
|
+
super(calendarFile)
|
|
18
|
+
this.#calendarDateFile = calendarDateFile
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async open() {
|
|
22
|
+
await super.open()
|
|
23
|
+
|
|
24
|
+
let calendarDateReader = new GTFSCalendarDateReader(this.#calendarDateFile)
|
|
25
|
+
await calendarDateReader.open()
|
|
26
|
+
while (calendarDateReader.available()) {
|
|
27
|
+
let calendarDate = await calendarDateReader.getNextEntity()
|
|
28
|
+
if (!this.#calendarDates[calendarDate.id]) this.#calendarDates[calendarDate.id] = []
|
|
29
|
+
this.#calendarDates[calendarDate.id].push(calendarDate)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Converts a CSV row into a calendar object
|
|
35
|
+
*
|
|
36
|
+
* @param {object} data A JSON object containing the following fields:
|
|
37
|
+
* @param {string} data.id The calendar ID
|
|
38
|
+
* @param {string} data.monday Indicates if a service will operate on a Monday within the given date range. "1" for operating and "0" for not operating.
|
|
39
|
+
* @param {string} data.tuesday Same as data.monday but for Tuesday
|
|
40
|
+
* @param {string} data.wednesday Same as data.monday but for Wednesday
|
|
41
|
+
* @param {string} data.thursday Same as data.monday but for Thursday
|
|
42
|
+
* @param {string} data.friday Same as data.monday but for Friday
|
|
43
|
+
* @param {string} data.saturday Same as data.monday but for Saturday
|
|
44
|
+
* @param {string} data.sunday Same as data.monday but for Sunday
|
|
45
|
+
* @param {string} data.startDay The start day of the calendar interval (inclusive).
|
|
46
|
+
* @param {string} data.endDay The end day of the calendar interval (inclusive).
|
|
47
|
+
*
|
|
48
|
+
* @returns {GTFSCalendar} An object representing the operator data
|
|
49
|
+
*/
|
|
50
|
+
processEntity(data) {
|
|
51
|
+
let calendarData = {
|
|
52
|
+
id: data.service_id,
|
|
53
|
+
daysOfWeek: [
|
|
54
|
+
data.monday, data.tuesday, data.wednesday, data.thursday,
|
|
55
|
+
data.friday, data.saturday, data.sunday
|
|
56
|
+
],
|
|
57
|
+
startDay: data.start_date,
|
|
58
|
+
endDay: data.end_date
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return new GTFSCalendar(calendarData, this.#calendarDates[data.service_id])
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import CSVLineReader from './line-reader.mjs'
|
|
2
|
+
|
|
3
|
+
export default class GTFSReader {
|
|
4
|
+
|
|
5
|
+
/** @type {string} */
|
|
6
|
+
#file
|
|
7
|
+
#reader
|
|
8
|
+
|
|
9
|
+
constructor(file) {
|
|
10
|
+
this.#file = file
|
|
11
|
+
this.#reader = new CSVLineReader(file)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Opens the underlying `CSVLineReader`
|
|
16
|
+
*/
|
|
17
|
+
async open() {
|
|
18
|
+
await this.#reader.open()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Checks if there is more data available for reading
|
|
23
|
+
*
|
|
24
|
+
* @returns {boolean} Returns true if there is more data available
|
|
25
|
+
*/
|
|
26
|
+
available() {
|
|
27
|
+
return this.#reader.available()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Gets the data of the next entity in the file.
|
|
32
|
+
*
|
|
33
|
+
* @returns {Promise<GTFSEntity>} The data of the next entity
|
|
34
|
+
*/
|
|
35
|
+
async getNextEntity() {
|
|
36
|
+
return this.processEntity(await this.#reader.nextLine())
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Converts a CSV row into its entity data
|
|
41
|
+
* @param {object} data The CSV row data
|
|
42
|
+
*
|
|
43
|
+
* @returns {GTFSEntity} An object representing the entity data
|
|
44
|
+
*/
|
|
45
|
+
processEntity(data) {
|
|
46
|
+
return null
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import GTFSRoute from '../GTFSRoute.mjs'
|
|
2
|
+
import GTFSReader from './GTFSReader.mjs'
|
|
3
|
+
|
|
4
|
+
export default class GTFSRouteReader extends GTFSReader {
|
|
5
|
+
|
|
6
|
+
/** @type {string} */
|
|
7
|
+
#mode
|
|
8
|
+
|
|
9
|
+
constructor(file, mode) {
|
|
10
|
+
super(file, mode)
|
|
11
|
+
this.#mode = mode
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Converts a CSV row into a route object
|
|
16
|
+
*
|
|
17
|
+
* @param {object} data A JSON object containing the following fields:
|
|
18
|
+
* - routeGTFSID: The route ID
|
|
19
|
+
* - agencyID: The route agency ID
|
|
20
|
+
* - routeNumber: The route number, or empty if it does not exist
|
|
21
|
+
* - routeName: The route name
|
|
22
|
+
* @param {string} mode The route mode (eg: bus, metro train)
|
|
23
|
+
* @returns {GTFSRoute} An object representing the route data
|
|
24
|
+
*/
|
|
25
|
+
processEntity(data) {
|
|
26
|
+
let routeData = {
|
|
27
|
+
routeGTFSID: data.route_id,
|
|
28
|
+
agencyID: data.agency_id,
|
|
29
|
+
routeNumber: data.route_short_name,
|
|
30
|
+
routeName: data.route_long_name
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return GTFSRoute.create(routeData, this.#mode)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { GTFSShape, GTFSShapePoint } from '../GTFSShape.mjs'
|
|
2
|
+
import CSVLineReader from './line-reader.mjs'
|
|
3
|
+
|
|
4
|
+
export default class GTFSShapeReader {
|
|
5
|
+
|
|
6
|
+
/** @type {string} */
|
|
7
|
+
#file
|
|
8
|
+
#reader
|
|
9
|
+
|
|
10
|
+
constructor(file) {
|
|
11
|
+
this.#file = file
|
|
12
|
+
this.#reader = new CSVLineReader(file)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Opens the underlying `CSVLineReader`
|
|
17
|
+
*/
|
|
18
|
+
async open() {
|
|
19
|
+
await this.#reader.open()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Checks if there is more data available for reading
|
|
24
|
+
*
|
|
25
|
+
* @returns {boolean} Returns true if there is more data available
|
|
26
|
+
*/
|
|
27
|
+
available() {
|
|
28
|
+
return this.#reader.available()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Gets the data of the next entity in the file.
|
|
33
|
+
*
|
|
34
|
+
* @returns {Promise<GTFSEntity>} The data of the next entity
|
|
35
|
+
*/
|
|
36
|
+
async getNextEntity() {
|
|
37
|
+
let firstLine = await this.#reader.nextLine()
|
|
38
|
+
let shapeID = firstLine.shape_id
|
|
39
|
+
|
|
40
|
+
let lines = [ firstLine ]
|
|
41
|
+
|
|
42
|
+
while (this.#reader.available()) {
|
|
43
|
+
let nextLine = await this.#reader.nextLine()
|
|
44
|
+
if (nextLine.shape_id !== shapeID) {
|
|
45
|
+
this.#reader.unreadLine()
|
|
46
|
+
break
|
|
47
|
+
} else {
|
|
48
|
+
lines.push(nextLine)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return new GTFSShape(shapeID, lines.map(line => this.processEntity(line)))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Converts a CSV row into a shape point object
|
|
57
|
+
*
|
|
58
|
+
* @param {object} data A JSON object containing the following fields:
|
|
59
|
+
* @param {string} data.shape_pt_lat The shape point's latitude
|
|
60
|
+
* @param {string} data.shape_pt_lon The shape point's longitude
|
|
61
|
+
* @param {string} data.shape_pt_sequence The shape point's sequence in the overall shape
|
|
62
|
+
* @param {string} data.shape_dist_traveled The distance travelled up to that point in the shape
|
|
63
|
+
*
|
|
64
|
+
* @returns {GTFSShapePoint} An object representing the shape data
|
|
65
|
+
*/
|
|
66
|
+
processEntity(data) {
|
|
67
|
+
let shapeData = {
|
|
68
|
+
latitude: parseFloat(data.shape_pt_lat),
|
|
69
|
+
longitude: parseFloat(data.shape_pt_lon),
|
|
70
|
+
distance: parseFloat(data.shape_dist_traveled)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return new GTFSShapePoint(shapeData)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { GTFSStopTime } from '../GTFSStopTime.mjs'
|
|
2
|
+
import CSVLineReader from './line-reader.mjs'
|
|
3
|
+
|
|
4
|
+
export default class GTFSStopTimesReader {
|
|
5
|
+
|
|
6
|
+
/** @type {string} */
|
|
7
|
+
#file
|
|
8
|
+
#reader
|
|
9
|
+
|
|
10
|
+
constructor(file) {
|
|
11
|
+
this.#file = file
|
|
12
|
+
this.#reader = new CSVLineReader(file)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Opens the underlying `CSVLineReader`
|
|
17
|
+
*/
|
|
18
|
+
async open() {
|
|
19
|
+
await this.#reader.open()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Checks if there is more data available for reading
|
|
24
|
+
*
|
|
25
|
+
* @returns {boolean} Returns true if there is more data available
|
|
26
|
+
*/
|
|
27
|
+
available() {
|
|
28
|
+
return this.#reader.available()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Gets the data of the next entity in the file.
|
|
33
|
+
*
|
|
34
|
+
* @returns {Promise<GTFSEntity>} The data of the next entity
|
|
35
|
+
*/
|
|
36
|
+
async getNextEntity() {
|
|
37
|
+
let firstLine = await this.#reader.nextLine()
|
|
38
|
+
let tripID = firstLine.trip_id
|
|
39
|
+
|
|
40
|
+
let lines = [ firstLine ]
|
|
41
|
+
|
|
42
|
+
while (this.#reader.available()) {
|
|
43
|
+
let nextLine = await this.#reader.nextLine()
|
|
44
|
+
if (nextLine.trip_id !== tripID) {
|
|
45
|
+
this.#reader.unreadLine()
|
|
46
|
+
break
|
|
47
|
+
} else {
|
|
48
|
+
lines.push(nextLine)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
tripID,
|
|
54
|
+
stops: lines.map(line => this.processEntity(line))
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Converts a CSV row into a stop time object
|
|
60
|
+
*
|
|
61
|
+
* @param {object} data A JSON object containing the following fields:
|
|
62
|
+
* @param {string} data.arrival_time The stop's arrival time
|
|
63
|
+
* @param {string} data.departure_time The stop's departure time
|
|
64
|
+
* @param {string} data.stop_id The stop ID
|
|
65
|
+
* @param {string} data.stop_sequence The stop sequence
|
|
66
|
+
* @param {string} data.pickup_type The pickup conditions. "0" for no restrictions and "1" for no pickup allowed
|
|
67
|
+
* @param {string} data.drop_off_type The dropoff conditions. "0" for no restrictions and "1" for no dropoff allowed
|
|
68
|
+
* @param {string} data.shape_dist_traveled The distance travelled along the shape
|
|
69
|
+
*
|
|
70
|
+
* @returns {GTFSStopTime} An object representing the stop data
|
|
71
|
+
*/
|
|
72
|
+
processEntity(data) {
|
|
73
|
+
let stopData = {
|
|
74
|
+
arrivalTime: data.arrival_time,
|
|
75
|
+
departureTime: data.departure_time,
|
|
76
|
+
stopID: data.stop_id,
|
|
77
|
+
stopSequence: data.stop_sequence,
|
|
78
|
+
pickup: data.pickup_type,
|
|
79
|
+
dropoff: data.drop_off_type,
|
|
80
|
+
distance: data.shape_dist_traveled
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return new GTFSStopTime(stopData)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { GTFSStop, GTFSPlatformStop } from '../GTFSStop.mjs'
|
|
2
|
+
import GTFSReader from './GTFSReader.mjs'
|
|
3
|
+
|
|
4
|
+
export default class GTFSStopsReader extends GTFSReader {
|
|
5
|
+
|
|
6
|
+
#suburbData
|
|
7
|
+
|
|
8
|
+
constructor(file, suburbData) {
|
|
9
|
+
super(file)
|
|
10
|
+
this.#suburbData = suburbData
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Converts a CSV row into a stop object
|
|
15
|
+
*
|
|
16
|
+
* @param {object} data A JSON object containing the following fields:
|
|
17
|
+
* @param {string} data.stop_id The stop ID
|
|
18
|
+
* @param {string} data.stop_name The stop's name
|
|
19
|
+
* @param {string} data.stop_lat The stop's latitude
|
|
20
|
+
* @param {string} data.stop_lon The stop's longitude
|
|
21
|
+
* @param {string} [data.platform] The stop's platform number. Optional, stops without a platform (eg bus stops) do not need to provide this
|
|
22
|
+
*
|
|
23
|
+
* @returns {GTFSStop} An object representing the stop data
|
|
24
|
+
*/
|
|
25
|
+
processEntity(data) {
|
|
26
|
+
let stopData = {
|
|
27
|
+
stopGTFSID: data.stop_id,
|
|
28
|
+
stopName: data.stop_name,
|
|
29
|
+
stopLat: data.stop_lat,
|
|
30
|
+
stopLon: data.stop_lon,
|
|
31
|
+
platform: data.platform_code
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return GTFSStop.create(stopData, this.#suburbData)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import GTFSTrip from '../GTFSTrip.mjs'
|
|
2
|
+
import GTFSReader from './GTFSReader.mjs'
|
|
3
|
+
|
|
4
|
+
export default class GTFSTripReader extends GTFSReader {
|
|
5
|
+
|
|
6
|
+
#calendars
|
|
7
|
+
#routeMappings
|
|
8
|
+
#mode
|
|
9
|
+
|
|
10
|
+
constructor(tripsFile, calendars, routeMappings, mode) {
|
|
11
|
+
super(tripsFile)
|
|
12
|
+
this.#calendars = calendars
|
|
13
|
+
this.#routeMappings = routeMappings
|
|
14
|
+
this.#mode = mode
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Sets the route ID mappings of the trip reader.
|
|
19
|
+
*
|
|
20
|
+
* @param {object} routeMappings The route ID mappings
|
|
21
|
+
*/
|
|
22
|
+
setRouteMappings(routeMappings) {
|
|
23
|
+
this.#routeMappings = routeMappings
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
* @param {object} calendars The calendar ID to GTFSCalendar mappings
|
|
29
|
+
*/
|
|
30
|
+
setCalendar(calendars) {
|
|
31
|
+
this.#calendars = calendars
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Converts a CSV row into a trip object
|
|
36
|
+
*
|
|
37
|
+
* @param {object} data A JSON object containing the following fields:
|
|
38
|
+
* @param {string} data.route_id The trip's route ID
|
|
39
|
+
* @param {string} data.service_id The trip's calendar ID
|
|
40
|
+
* @param {string} data.trip_id The trip's unique trip ID
|
|
41
|
+
* @param {string} data.shape_id The trip's shape ID
|
|
42
|
+
* @param {string} data.trip_headsign The trip's headsign
|
|
43
|
+
* @param {string} data.direction_id The trip's direction ID
|
|
44
|
+
* @param {string} data.block_id The trip's block ID
|
|
45
|
+
*
|
|
46
|
+
* @returns {GTFSTrip} An object representing the trip data
|
|
47
|
+
*/
|
|
48
|
+
processEntity(data) {
|
|
49
|
+
let tripData = {
|
|
50
|
+
routeGTFSID: this.#routeMappings[data.route_id],
|
|
51
|
+
calendar: this.#calendars[data.service_id],
|
|
52
|
+
id: data.trip_id,
|
|
53
|
+
shapeID: data.shape_id,
|
|
54
|
+
headsign: data.trip_headsign,
|
|
55
|
+
direction: data.direction_id,
|
|
56
|
+
block: data.block_id
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return GTFSTrip.create(tripData, this.#mode)
|
|
60
|
+
}
|
|
61
|
+
}
|