@tmlmobilidade/dates 20260330.1453.3 → 20260330.1735.58

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.
@@ -38,3 +38,17 @@ export declare function buildRuleSummary(rule: ScheduleRule, options: {
38
38
  events?: Event[];
39
39
  periods?: YearPeriod[];
40
40
  }): RuleSummary;
41
+ /**
42
+ * GTFS-oriented rule token:
43
+ * - FER_DU
44
+ * - VER_SAB
45
+ * - ESC_DOM
46
+ * - ALL
47
+ * - ALL_DU
48
+ * - VER-FER_SAB-DOM
49
+ * - event title for event rules (temporary)
50
+ */
51
+ export declare function buildRuleSummaryGtfs(rule: ScheduleRule, options: {
52
+ events?: Event[];
53
+ periods?: YearPeriod[];
54
+ }): string;
@@ -175,3 +175,83 @@ function buildRuleSummaryTooltip(rule, options) {
175
175
  }
176
176
  return '';
177
177
  }
178
+ /**
179
+ * TEMP:
180
+ * Maps year period ids/names into GTFS abbreviations.
181
+ * Replace with a persisted abbreviation/code field when available.
182
+ */
183
+ function mapPeriodsToGtfsAbbreviation(periodIds) {
184
+ if (!periodIds?.length)
185
+ return 'ALL';
186
+ const map = {
187
+ '2KIUJ': 'FER',
188
+ '99H2R': 'ESC',
189
+ 'UW2U0': 'VER',
190
+ };
191
+ const abbreviations = periodIds.map((id) => {
192
+ const abbr = map[id];
193
+ if (!abbr)
194
+ throw new Error(`Unknown period id: ${id}`);
195
+ return abbr;
196
+ });
197
+ const unique = [...new Set(abbreviations)];
198
+ const allSet = new Set(['ESC', 'FER', 'VER']);
199
+ // If all three are present, return 'ALL'
200
+ if (unique.length === 3 && unique.every(x => allSet.has(x))) {
201
+ return 'ALL';
202
+ }
203
+ return unique.join('-');
204
+ }
205
+ function mapWeekdaysToGtfsAbbreviation(weekdays) {
206
+ if (!weekdays?.length)
207
+ return 'ALL';
208
+ const sorted = [...new Set(weekdays)].sort((a, b) => a - b);
209
+ const joined = sorted.join('-');
210
+ // Special cases
211
+ if (joined === '1-2-3-4-5')
212
+ return 'DU';
213
+ if (joined === '1-2-3-4-5-6-7')
214
+ return 'ALL';
215
+ const map = {
216
+ 1: 'SEG',
217
+ 2: 'TER',
218
+ 3: 'QUA',
219
+ 4: 'QUI',
220
+ 5: 'SEX',
221
+ 6: 'SAB',
222
+ 7: 'DOM',
223
+ };
224
+ return sorted.map(day => map[day] || String(day)).join('-');
225
+ }
226
+ /**
227
+ * GTFS-oriented rule token:
228
+ * - FER_DU
229
+ * - VER_SAB
230
+ * - ESC_DOM
231
+ * - ALL
232
+ * - ALL_DU
233
+ * - VER-FER_SAB-DOM
234
+ * - event title for event rules (temporary)
235
+ */
236
+ export function buildRuleSummaryGtfs(rule, options) {
237
+ if (isEventRestriction(rule) || isEventReplacement(rule)) {
238
+ return rule.event?.title ?? rule.name ?? rule._id;
239
+ }
240
+ if (rule.kind === 'manual' && rule.event_id) {
241
+ return getEventForManualRule(rule, options?.events)?.title ?? rule.name ?? rule._id;
242
+ }
243
+ const periodIds = rule.year_period_ids ?? [];
244
+ const weekdays = rule.weekdays ?? [];
245
+ const periodPart = mapPeriodsToGtfsAbbreviation(periodIds);
246
+ const weekdayPart = mapWeekdaysToGtfsAbbreviation(weekdays);
247
+ if (periodPart === 'ALL' && weekdayPart === 'ALL') {
248
+ return 'ALL';
249
+ }
250
+ if (periodPart === 'ALL') {
251
+ return `ALL_${weekdayPart}`;
252
+ }
253
+ if (weekdayPart === 'ALL') {
254
+ return periodPart;
255
+ }
256
+ return `${periodPart}_${weekdayPart}`;
257
+ }
@@ -34,26 +34,19 @@ export function computeRuleTimePoints(rule, allRules, periods, holidays, options
34
34
  }
35
35
  // For replacement rules: return timepoints from the TARGET weekdays
36
36
  if (rule.kind === 'event_replacement') {
37
- // When same_weekday is true, each event date maps to its own actual weekday
38
- const targetWeekdays = rule.same_weekday
39
- ? affectedWeekdays
40
- : new Set(rule.weekdays || []);
41
- const targetPeriods = new Set(rule.year_period_ids || []);
42
- // Find manual include rules that match the target pattern
43
- const timepoints = new Set();
44
- for (const r of allRules) {
45
- if (r.kind !== 'manual' || r.operating_mode !== 'include')
46
- continue;
47
- // Check if this manual rule applies to the target weekdays/periods
48
- const hasMatchingWeekday = r.weekdays?.some(w => targetWeekdays.has(w));
49
- const hasMatchingPeriod = r.year_period_ids?.some(p => targetPeriods.has(p));
50
- if (hasMatchingWeekday && hasMatchingPeriod) {
51
- for (const tp of r.timepoints || []) {
52
- timepoints.add(tp);
37
+ const addedTimepoints = new Set();
38
+ for (const date of rule.dates ?? []) {
39
+ const withRule = computeActiveRules(date, allRules, periods, holidays, options);
40
+ const withoutRule = computeActiveRules(date, allRules.filter(r => r._id !== rule._id), periods, holidays, options);
41
+ const withSet = new Set(withRule.timepoints);
42
+ const withoutSet = new Set(withoutRule.timepoints);
43
+ for (const tp of withSet) {
44
+ if (!withoutSet.has(tp)) {
45
+ addedTimepoints.add(tp);
53
46
  }
54
47
  }
55
48
  }
56
- return timepoints;
49
+ return addedTimepoints;
57
50
  }
58
51
  // For restriction rules: compute what was removed on affected weekdays
59
52
  // Generate a sample date range to check (1 year from now)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmlmobilidade/dates",
3
- "version": "20260330.1453.3",
3
+ "version": "20260330.1735.58",
4
4
  "author": {
5
5
  "email": "iso@tmlmobilidade.pt",
6
6
  "name": "TML-ISO"