@tmlmobilidade/generate-offer-files 20250626.2300.25 → 20250627.1206.31

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.
Files changed (2) hide show
  1. package/dist/main.js +48 -114
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2,12 +2,11 @@
2
2
  import LOGGER from '@helperkits/logger';
3
3
  import TIMETRACKER from '@helperkits/timer';
4
4
  import { JsonWriter } from '@helperkits/writer';
5
- import { validateOperationalDate } from '@tmlmobilidade/types';
5
+ import { validateGtfsCalendar, validateGtfsCalendarDate, validateGtfsRouteExtended, validateGtfsStopExtended, validateGtfsStopTime, validateGtfsTripExtended } from '@tmlmobilidade/types';
6
6
  import { convertMetersOrKilometersToMeters, Dates, getOperationalDatesFromRange } from '@tmlmobilidade/utils';
7
7
  import { parse as csvParser } from 'csv-parse';
8
8
  import extract from 'extract-zip';
9
9
  import fs from 'fs';
10
- import { ExceptionType } from 'gtfs-types';
11
10
  /* * */
12
11
  export async function generateOfferOutput(filePath, startDate, endDate, outputDir, feedId) {
13
12
  try {
@@ -76,21 +75,13 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
76
75
  const parseEachRow = async (data) => {
77
76
  //
78
77
  //
79
- // Validate the start and end dates to ensure
80
- // they are of in the OperationalDate format
81
- let serviceIdStartDate;
82
- let serviceIdEndDate;
83
- try {
84
- serviceIdStartDate = validateOperationalDate(data.start_date);
85
- serviceIdEndDate = validateOperationalDate(data.end_date);
86
- }
87
- catch (error) {
88
- LOGGER.error(`Error creating operational date "${data.start_date}" or "${data.end_date}" for service_id "${data.service_id}"`, error);
89
- return;
90
- }
78
+ // Validate the current row against the proper type
79
+ const validatedData = validateGtfsCalendar(data);
91
80
  //
92
81
  // Check if this service_id is between the given start_date and end_date.
93
82
  // Clip the service_id's start and end dates to the given start and end dates.
83
+ let serviceIdStartDate = validatedData.start_date;
84
+ let serviceIdEndDate = validatedData.end_date;
94
85
  if (serviceIdEndDate < startDate || serviceIdStartDate > endDate)
95
86
  return;
96
87
  if (serviceIdStartDate < startDate)
@@ -105,24 +96,24 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
105
96
  const validOperationalDates = [];
106
97
  for (const currentDate of allOperationalDatesInRange) {
107
98
  const dayOfWeek = Dates.fromOperationalDate(currentDate, 'Europe/Lisbon').toFormat('c');
108
- if (dayOfWeek === '1' && String(data.monday) === '1')
99
+ if (dayOfWeek === '1' && validatedData.monday === 1)
109
100
  validOperationalDates.push(currentDate);
110
- if (dayOfWeek === '2' && String(data.tuesday) === '1')
101
+ if (dayOfWeek === '2' && validatedData.tuesday === 1)
111
102
  validOperationalDates.push(currentDate);
112
- if (dayOfWeek === '3' && String(data.wednesday) === '1')
103
+ if (dayOfWeek === '3' && validatedData.wednesday === 1)
113
104
  validOperationalDates.push(currentDate);
114
- if (dayOfWeek === '4' && String(data.thursday) === '1')
105
+ if (dayOfWeek === '4' && validatedData.thursday === 1)
115
106
  validOperationalDates.push(currentDate);
116
- if (dayOfWeek === '5' && String(data.friday) === '1')
107
+ if (dayOfWeek === '5' && validatedData.friday === 1)
117
108
  validOperationalDates.push(currentDate);
118
- if (dayOfWeek === '6' && String(data.saturday) === '1')
109
+ if (dayOfWeek === '6' && validatedData.saturday === 1)
119
110
  validOperationalDates.push(currentDate);
120
- if (dayOfWeek === '7' && String(data.sunday) === '1')
111
+ if (dayOfWeek === '7' && validatedData.sunday === 1)
121
112
  validOperationalDates.push(currentDate);
122
113
  }
123
114
  //
124
115
  // Save the valid operational dates for this service_id
125
- savedCalendarDates.set(data.service_id, validOperationalDates);
116
+ savedCalendarDates.set(validatedData.service_id, validOperationalDates);
126
117
  //
127
118
  };
128
119
  //
@@ -154,40 +145,33 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
154
145
  const parseEachRow = async (data) => {
155
146
  //
156
147
  //
157
- // Validate the date to ensure it is of type OperationalDate
158
- let currentOperationalDate;
159
- try {
160
- currentOperationalDate = validateOperationalDate(data.date);
161
- }
162
- catch (error) {
163
- LOGGER.error(`Error creating operational date "${data.date}" for service_id "${data.service_id}"`, error);
164
- return;
165
- }
148
+ // Validate the current row against the proper type
149
+ const validatedData = validateGtfsCalendarDate(data);
166
150
  //
167
151
  // Skip if this row's date is not between the given start and end dates
168
- if (currentOperationalDate < startDate || currentOperationalDate > endDate)
152
+ if (validatedData.date < startDate || validatedData.date > endDate)
169
153
  return;
170
154
  //
171
155
  // If we're here, it means the service_id is valid between the given dates.
172
156
  // Get the previously saved calendars and check if it exists for this service_id.
173
- const savedCalendar = savedCalendarDates.get(data.service_id);
157
+ const savedCalendar = savedCalendarDates.get(validatedData.service_id);
174
158
  if (savedCalendar) {
175
159
  // Create a new Set to avoid duplicated dates
176
160
  const updatedCalendar = new Set(savedCalendar);
177
161
  // If this service_id was previously saved, either add or remove the current date
178
162
  // to it based on the exception_type value for this row.
179
- if (Number(data.exception_type) === ExceptionType.SERVICE_ADDED)
180
- updatedCalendar.add(currentOperationalDate);
181
- else if (Number(data.exception_type) === ExceptionType.SERVICE_REMOVED)
182
- updatedCalendar.delete(currentOperationalDate);
163
+ if (validatedData.exception_type === 1)
164
+ updatedCalendar.add(validatedData.date);
165
+ else if (validatedData.exception_type === 2)
166
+ updatedCalendar.delete(validatedData.date);
183
167
  // Update the service_id with the new dates
184
- savedCalendarDates.set(data.service_id, Array.from(updatedCalendar));
168
+ savedCalendarDates.set(validatedData.service_id, Array.from(updatedCalendar));
185
169
  }
186
170
  else {
187
171
  // If this is the first time we're seeing this service_id, then it is only necessary
188
172
  // to initiate a new dates array if it is a service addition
189
- if (Number(data.exception_type) === ExceptionType.SERVICE_ADDED) {
190
- savedCalendarDates.set(data.service_id, [currentOperationalDate]);
173
+ if (validatedData.exception_type === 1) {
174
+ savedCalendarDates.set(validatedData.service_id, [validatedData.date]);
191
175
  }
192
176
  }
193
177
  //
@@ -219,31 +203,16 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
219
203
  //
220
204
  LOGGER.info(`Reading zip entry "trips.txt"...`);
221
205
  const parseEachRow = async (data) => {
222
- //
223
- //
206
+ // Validate the current row against the proper type
207
+ const validatedData = validateGtfsTripExtended(data);
224
208
  // For each trip, check if the associated service_id was saved
225
209
  // in the previous step or not. Include it if yes, skip otherwise.
226
- if (!savedCalendarDates.has(data.service_id))
210
+ if (!savedCalendarDates.has(validatedData.service_id))
227
211
  return;
228
- //
229
- // Format the exported row. Only include the minimum required data
230
- // to prevent memory bloat later on.
231
- const parsedRowData = {
232
- direction_id: data.direction_id,
233
- pattern_id: data.pattern_id,
234
- route_id: data.route_id,
235
- service_id: data.service_id,
236
- shape_id: data.shape_id,
237
- trip_headsign: data.trip_headsign,
238
- trip_id: data.trip_id,
239
- wheelchair_accessible: data.wheelchair_accessible,
240
- };
241
- //
242
- // Save this trip for later and reference
243
- // the associated route_id to filter them later.
244
- savedTrips.set(data.trip_id, parsedRowData);
245
- referencedRouteIds.add(data.route_id);
246
- //
212
+ // Save the exported row
213
+ savedTrips.set(validatedData.trip_id, validatedData);
214
+ // Reference the associated entities to filter them later.
215
+ referencedRouteIds.add(validatedData.route_id);
247
216
  };
248
217
  //
249
218
  // Setup the CSV parsing operation
@@ -265,28 +234,14 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
265
234
  //
266
235
  LOGGER.info(`Reading zip entry "routes.txt"...`);
267
236
  const parseEachRow = async (data) => {
268
- //
269
- //
237
+ // Validate the current row against the proper type
238
+ const validatedData = validateGtfsRouteExtended(data);
270
239
  // For each route, only save the ones referenced
271
240
  // by the previously saved trips.
272
- if (!referencedRouteIds.has(data.route_id))
241
+ if (!referencedRouteIds.has(validatedData.route_id))
273
242
  return;
274
- //
275
- // Format and save the exported row
276
- const parsedRowData = {
277
- agency_id: data.agency_id,
278
- line_id: data.line_id,
279
- line_long_name: data.line_long_name,
280
- line_short_name: data.line_short_name,
281
- path_type: data.path_type,
282
- route_color: data.route_color,
283
- route_id: data.route_id,
284
- route_long_name: data.route_long_name,
285
- route_short_name: data.route_short_name,
286
- route_text_color: data.route_text_color,
287
- };
288
- savedRoutes.set(data.route_id, parsedRowData);
289
- //
243
+ // Save the exported row
244
+ savedRoutes.set(validatedData.route_id, validatedData);
290
245
  };
291
246
  //
292
247
  // Setup the CSV parsing operation
@@ -309,22 +264,10 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
309
264
  //
310
265
  LOGGER.info(`Reading zip entry "stops.txt"...`);
311
266
  const parseEachRow = async (data) => {
312
- //
313
- //
314
- // Save all stops, but only the mininum required data.
315
- const parsedRowData = {
316
- location_type: data.location_type,
317
- municipality_id: data.municipality_id,
318
- parent_station: data.parent_station,
319
- parish_id: data.parish_id,
320
- region_id: data.region_id,
321
- stop_id: data.stop_id,
322
- stop_lat: Number(data.stop_lat),
323
- stop_lon: Number(data.stop_lon),
324
- stop_name: data.stop_name,
325
- };
326
- savedStops.set(data.stop_id, parsedRowData);
327
- //
267
+ // Validate the current row against the proper type
268
+ const validatedData = validateGtfsStopExtended(data);
269
+ // Save the exported row
270
+ savedStops.set(validatedData.stop_id, validatedData);
328
271
  };
329
272
  //
330
273
  // Setup the CSV parsing operation
@@ -350,35 +293,26 @@ export async function generateOfferOutput(filePath, startDate, endDate, outputDi
350
293
  const parseEachRow = async (data) => {
351
294
  //
352
295
  //
296
+ // Validate the current row against the proper type
297
+ const validatedData = validateGtfsStopTime(data);
298
+ //
353
299
  // For each stopTime of each trip, check if the associated trip_id was saved
354
300
  // in the previous step or not. Skip if this row's trip_id was not saved before.
355
301
  // Also, check if the stop_id is valid and was saved before.
356
- const tripData = savedTrips.get(data.trip_id);
302
+ const tripData = savedTrips.get(validatedData.trip_id);
357
303
  if (!tripData)
358
304
  return;
359
- const stopData = savedStops.get(data.stop_id);
305
+ const stopData = savedStops.get(validatedData.stop_id);
360
306
  if (!stopData)
361
307
  return;
362
308
  //
363
309
  // Format the exported row. Only include the minimum required data
364
310
  // to prevent memory bloat later on, and include the stop data right away.
365
- const parsedRowData = {
366
- arrival_time: data.arrival_time,
367
- continuous_drop_off: data.continuous_drop_off,
368
- continuous_pickup: data.continuous_pickup,
369
- departure_time: data.departure_time,
370
- shape_dist_traveled: data.shape_dist_traveled,
371
- stop_headsign: data.stop_headsign,
372
- stop_id: data.stop_id,
373
- stop_sequence: data.stop_sequence,
374
- timepoint: data.timepoint,
375
- trip_id: data.trip_id,
376
- };
377
- const savedStopTime = savedStopTimes.get(data.trip_id);
311
+ const savedStopTime = savedStopTimes.get(validatedData.trip_id);
378
312
  if (savedStopTime)
379
- savedStopTimes.set(data.trip_id, [...savedStopTime, parsedRowData]);
313
+ savedStopTimes.set(validatedData.trip_id, [...savedStopTime, validatedData]);
380
314
  else
381
- savedStopTimes.set(data.trip_id, [parsedRowData]);
315
+ savedStopTimes.set(validatedData.trip_id, [validatedData]);
382
316
  //
383
317
  };
384
318
  //
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmlmobilidade/generate-offer-files",
3
- "version": "20250626.2300.25",
3
+ "version": "20250627.1206.31",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"