@tmlmobilidade/normalizers 20251202.1817.5
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/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/normalize-ride.d.ts +48 -0
- package/dist/normalize-ride.js +148 -0
- package/package.json +49 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './normalize-ride.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './normalize-ride.js';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { DelayStatusSchema, type Ride, type RideAnalysisGrade, type RideNormalized } from '@tmlmobilidade/types';
|
|
2
|
+
/**
|
|
3
|
+
* This function normalizes a Ride object by adding additional properties
|
|
4
|
+
* such as delay status, operational status, seen status, and formatted start times.
|
|
5
|
+
* @param ride The Ride object to normalize.
|
|
6
|
+
* @returns The normalized Ride object.
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalizeRide(ride: Ride): RideNormalized;
|
|
9
|
+
/**
|
|
10
|
+
* This function returns the analysis grade for a given Ride, based on its operational status and the provided grade.
|
|
11
|
+
* @param operationalStatus The operational status of the Ride.
|
|
12
|
+
* @param grade The grade to return if the operational status is not 'scheduled' or 'running'.
|
|
13
|
+
* @returns The analysis grade for the Ride.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getAnalysisGrade(operationalStatus: RideNormalized['operational_status'], grade?: RideAnalysisGrade): 'none' | RideAnalysisGrade;
|
|
16
|
+
/**
|
|
17
|
+
* This function extract the hour and minute components from a date string.
|
|
18
|
+
* @param timestamp The date string to extract the hour and minute components from.
|
|
19
|
+
* @returns The hour and minute components of the date string.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getDelayValueDisplay(timeScheduled: Ride['start_time_scheduled'], timeObserved: Ride['start_time_observed']): RideNormalized['delay_value_display'];
|
|
22
|
+
/**
|
|
23
|
+
* This function extract the hour and minute components from a date string.
|
|
24
|
+
* @param timestamp The date string to extract the hour and minute components from.
|
|
25
|
+
* @returns The hour and minute components of the date string.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getDelayStatus(timeScheduled: Ride['start_time_scheduled'], timeObserved: Ride['start_time_observed']): typeof DelayStatusSchema.options[number];
|
|
28
|
+
/**
|
|
29
|
+
* This function returns the correct operational status for a given Ride, base on its 'scheduled_start_time' and 'seen_last_at' values.
|
|
30
|
+
* A Ride can be considered 'scheduled', 'missed', 'running' or 'ended'.
|
|
31
|
+
* Value 'scheduled' means that the ride start time is still in the future, and no Vehicle Events were found for it.
|
|
32
|
+
* Value 'missed' means that the ride start time is at least 10 minutes ago, and no Vehicle Events were found for it.
|
|
33
|
+
* Value 'running' means that the value of seen_last_at is from less than 10 minutes ago.
|
|
34
|
+
* Value 'ended' means that the value of seen_last_at is from more than 10 minutes ago.
|
|
35
|
+
* @param startTimeScheduled The scheduled start time for the Ride.
|
|
36
|
+
* @param seenLastAt The timestamp of the most recent Vehicle Event for the Ride.
|
|
37
|
+
* @returns The operational status for the Ride.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getOperationalStatus(startTimeScheduled: Ride['start_time_scheduled'], seenLastAt: Ride['seen_last_at']): RideNormalized['operational_status'];
|
|
40
|
+
/**
|
|
41
|
+
* This function returns the seen status of a ride based on the timestamp of its most recent event.
|
|
42
|
+
* A ride is considered 'seen' if its most recent event is less than 30 seconds old;
|
|
43
|
+
* 'gone' if its most recent event is more than 30 seconds old;
|
|
44
|
+
* and 'unseen' if the ride has no events.
|
|
45
|
+
* @param seenLastAt The timestamp of the most recent event of the ride.
|
|
46
|
+
* @returns The seen status of the ride.
|
|
47
|
+
*/
|
|
48
|
+
export declare function getSeenStatus(seenLastAt?: Ride['seen_last_at']): RideNormalized['seen_status'];
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/* * */
|
|
2
|
+
import { Dates } from '@tmlmobilidade/dates';
|
|
3
|
+
/**
|
|
4
|
+
* This function normalizes a Ride object by adding additional properties
|
|
5
|
+
* such as delay status, operational status, seen status, and formatted start times.
|
|
6
|
+
* @param ride The Ride object to normalize.
|
|
7
|
+
* @returns The normalized Ride object.
|
|
8
|
+
*/
|
|
9
|
+
export function normalizeRide(ride) {
|
|
10
|
+
const operationalStatusValue = getOperationalStatus(ride.start_time_scheduled, ride.seen_last_at);
|
|
11
|
+
return {
|
|
12
|
+
...ride,
|
|
13
|
+
acceptance_status: ride['acceptance_status'] ?? 'none',
|
|
14
|
+
analysis_ended_at_last_stop_grade: getAnalysisGrade(operationalStatusValue, ride.analysis?.ENDED_AT_LAST_STOP?.grade),
|
|
15
|
+
analysis_expected_apex_validation_interval: getAnalysisGrade(operationalStatusValue, ride.analysis?.EXPECTED_APEX_VALIDATION_INTERVAL?.grade),
|
|
16
|
+
analysis_simple_three_vehicle_events_grade: getAnalysisGrade(operationalStatusValue, ride.analysis?.SIMPLE_THREE_VEHICLE_EVENTS?.grade),
|
|
17
|
+
analysis_transaction_sequentiality: getAnalysisGrade(operationalStatusValue, ride.analysis?.TRANSACTION_SEQUENTIALITY?.grade),
|
|
18
|
+
delay_status: getDelayStatus(ride.start_time_scheduled, ride.start_time_observed),
|
|
19
|
+
delay_value_display: getDelayValueDisplay(ride.start_time_scheduled, ride.start_time_observed),
|
|
20
|
+
end_delay_status: getDelayStatus(ride.end_time_scheduled, ride.end_time_observed),
|
|
21
|
+
end_delay_value_display: getDelayValueDisplay(ride.end_time_scheduled, ride.end_time_observed),
|
|
22
|
+
end_time_observed_display: ride.end_time_observed ? Dates.fromUnixTimestamp(ride.end_time_observed).setZone('Europe/Lisbon', 'offset_only').toFormat('HH:mm') : null,
|
|
23
|
+
end_time_scheduled_display: Dates.fromUnixTimestamp(ride.end_time_scheduled).setZone('Europe/Lisbon', 'offset_only').toFormat('HH:mm'),
|
|
24
|
+
operational_status: operationalStatusValue,
|
|
25
|
+
seen_status: getSeenStatus(ride.seen_last_at),
|
|
26
|
+
start_delay_status: getDelayStatus(ride.start_time_scheduled, ride.start_time_observed),
|
|
27
|
+
start_delay_value_display: getDelayValueDisplay(ride.start_time_scheduled, ride.start_time_observed),
|
|
28
|
+
start_time_observed_display: ride.start_time_observed ? Dates.fromUnixTimestamp(ride.start_time_observed).setZone('Europe/Lisbon', 'offset_only').toFormat('HH:mm') : null,
|
|
29
|
+
start_time_scheduled_display: Dates.fromUnixTimestamp(ride.start_time_scheduled).setZone('Europe/Lisbon', 'offset_only').toFormat('HH:mm'),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* This function returns the analysis grade for a given Ride, based on its operational status and the provided grade.
|
|
34
|
+
* @param operationalStatus The operational status of the Ride.
|
|
35
|
+
* @param grade The grade to return if the operational status is not 'scheduled' or 'running'.
|
|
36
|
+
* @returns The analysis grade for the Ride.
|
|
37
|
+
*/
|
|
38
|
+
export function getAnalysisGrade(operationalStatus, grade) {
|
|
39
|
+
//
|
|
40
|
+
if (operationalStatus === 'scheduled' || operationalStatus === 'running') {
|
|
41
|
+
return 'none';
|
|
42
|
+
}
|
|
43
|
+
return grade ?? 'none';
|
|
44
|
+
//
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* This function extract the hour and minute components from a date string.
|
|
48
|
+
* @param timestamp The date string to extract the hour and minute components from.
|
|
49
|
+
* @returns The hour and minute components of the date string.
|
|
50
|
+
*/
|
|
51
|
+
export function getDelayValueDisplay(timeScheduled, timeObserved) {
|
|
52
|
+
//
|
|
53
|
+
if (!timeScheduled || !timeObserved) {
|
|
54
|
+
return 'N/A';
|
|
55
|
+
}
|
|
56
|
+
const difference = timeObserved - timeScheduled;
|
|
57
|
+
const sign = difference < 0 ? '-' : '';
|
|
58
|
+
const absDiff = Math.abs(difference);
|
|
59
|
+
const minutes = Math.floor(absDiff / 60000);
|
|
60
|
+
const seconds = Math.floor((absDiff % 60000) / 1000);
|
|
61
|
+
if (minutes === 0) {
|
|
62
|
+
return `${sign}${seconds}s`;
|
|
63
|
+
}
|
|
64
|
+
return `${sign}${minutes}m ${seconds}s`;
|
|
65
|
+
//
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* This function extract the hour and minute components from a date string.
|
|
69
|
+
* @param timestamp The date string to extract the hour and minute components from.
|
|
70
|
+
* @returns The hour and minute components of the date string.
|
|
71
|
+
*/
|
|
72
|
+
export function getDelayStatus(timeScheduled, timeObserved) {
|
|
73
|
+
//
|
|
74
|
+
if (!timeScheduled || !timeObserved) {
|
|
75
|
+
return 'none';
|
|
76
|
+
}
|
|
77
|
+
const difference = timeObserved - timeScheduled;
|
|
78
|
+
// 5 minutes late
|
|
79
|
+
if (difference > 300000) {
|
|
80
|
+
return 'delayed';
|
|
81
|
+
}
|
|
82
|
+
// 1 minute early
|
|
83
|
+
if (difference < -60000) {
|
|
84
|
+
return 'early';
|
|
85
|
+
}
|
|
86
|
+
return 'ontime';
|
|
87
|
+
//
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* This function returns the correct operational status for a given Ride, base on its 'scheduled_start_time' and 'seen_last_at' values.
|
|
91
|
+
* A Ride can be considered 'scheduled', 'missed', 'running' or 'ended'.
|
|
92
|
+
* Value 'scheduled' means that the ride start time is still in the future, and no Vehicle Events were found for it.
|
|
93
|
+
* Value 'missed' means that the ride start time is at least 10 minutes ago, and no Vehicle Events were found for it.
|
|
94
|
+
* Value 'running' means that the value of seen_last_at is from less than 10 minutes ago.
|
|
95
|
+
* Value 'ended' means that the value of seen_last_at is from more than 10 minutes ago.
|
|
96
|
+
* @param startTimeScheduled The scheduled start time for the Ride.
|
|
97
|
+
* @param seenLastAt The timestamp of the most recent Vehicle Event for the Ride.
|
|
98
|
+
* @returns The operational status for the Ride.
|
|
99
|
+
*/
|
|
100
|
+
export function getOperationalStatus(startTimeScheduled, seenLastAt) {
|
|
101
|
+
//
|
|
102
|
+
//
|
|
103
|
+
// Check if the ride start time is in the future.
|
|
104
|
+
const nowInUnixMilliseconds = Dates.now('Europe/Lisbon').unix_timestamp;
|
|
105
|
+
const millisecondsFromRideStartToNow = nowInUnixMilliseconds - startTimeScheduled;
|
|
106
|
+
//
|
|
107
|
+
// If the ride start time is less than or equal to 10 minutes ago, or in the future,
|
|
108
|
+
// and there are no VehicleEvents for it, then the ride is considered 'scheduled'.
|
|
109
|
+
if (millisecondsFromRideStartToNow <= 600000 && !seenLastAt) {
|
|
110
|
+
return 'scheduled';
|
|
111
|
+
}
|
|
112
|
+
//
|
|
113
|
+
// If the ride start time is at least 10 minutes ago, and there are no VehicleEvents for it,
|
|
114
|
+
// then the ride is considered 'missed' and no further analysis is needed.
|
|
115
|
+
if (millisecondsFromRideStartToNow > 600000 && !seenLastAt) {
|
|
116
|
+
return 'missed';
|
|
117
|
+
}
|
|
118
|
+
//
|
|
119
|
+
// If there is seen_last_at for the ride, and the most recent one was received less than or exactly at 10 minutes ago,
|
|
120
|
+
// then the ride is considered 'running'. Else it is considered 'ended'.
|
|
121
|
+
const millisecondsFromMostRecentVehicleEventToNow = nowInUnixMilliseconds - (seenLastAt ?? 0);
|
|
122
|
+
if (millisecondsFromMostRecentVehicleEventToNow <= 600000) {
|
|
123
|
+
return 'running';
|
|
124
|
+
}
|
|
125
|
+
return 'ended';
|
|
126
|
+
//
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* This function returns the seen status of a ride based on the timestamp of its most recent event.
|
|
130
|
+
* A ride is considered 'seen' if its most recent event is less than 30 seconds old;
|
|
131
|
+
* 'gone' if its most recent event is more than 30 seconds old;
|
|
132
|
+
* and 'unseen' if the ride has no events.
|
|
133
|
+
* @param seenLastAt The timestamp of the most recent event of the ride.
|
|
134
|
+
* @returns The seen status of the ride.
|
|
135
|
+
*/
|
|
136
|
+
export function getSeenStatus(seenLastAt) {
|
|
137
|
+
//
|
|
138
|
+
if (!seenLastAt) {
|
|
139
|
+
return 'unseen';
|
|
140
|
+
}
|
|
141
|
+
const nowInUnixMilliseconds = Dates.now('Europe/Lisbon').unix_timestamp;
|
|
142
|
+
const millisecondsFromLastSeenToNow = nowInUnixMilliseconds - seenLastAt;
|
|
143
|
+
if (millisecondsFromLastSeenToNow <= 30_000) {
|
|
144
|
+
return 'seen';
|
|
145
|
+
}
|
|
146
|
+
return 'gone';
|
|
147
|
+
//
|
|
148
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tmlmobilidade/normalizers",
|
|
3
|
+
"version": "20251202.1817.5",
|
|
4
|
+
"author": {
|
|
5
|
+
"email": "iso@tmlmobilidade.pt",
|
|
6
|
+
"name": "TML-ISO"
|
|
7
|
+
},
|
|
8
|
+
"license": "AGPL-3.0-or-later",
|
|
9
|
+
"homepage": "https://github.com/tmlmobilidade/go#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/tmlmobilidade/go/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/tmlmobilidade/go.git"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"public transit",
|
|
19
|
+
"tml",
|
|
20
|
+
"transportes metropolitanos de lisboa",
|
|
21
|
+
"go"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"main": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc && resolve-tspaths",
|
|
34
|
+
"lint": "eslint ./src/ && tsc --noEmit",
|
|
35
|
+
"lint:fix": "eslint ./src/ --fix",
|
|
36
|
+
"watch": "tsc-watch --onSuccess 'resolve-tspaths'"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@tmlmobilidade/dates": "*",
|
|
40
|
+
"@tmlmobilidade/types": "*"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@tmlmobilidade/tsconfig": "*",
|
|
44
|
+
"@types/node": "24.10.1",
|
|
45
|
+
"resolve-tspaths": "0.8.23",
|
|
46
|
+
"tsc-watch": "7.2.0",
|
|
47
|
+
"typescript": "5.9.3"
|
|
48
|
+
}
|
|
49
|
+
}
|