sabre-client 0.5.0 → 0.6.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/README.es.md +70 -11
- package/README.md +70 -11
- package/dist/anonymize.d.ts +54 -0
- package/dist/anonymize.js +111 -0
- package/dist/anonymize.js.map +1 -0
- package/dist/index.d.ts +61 -10
- package/dist/index.js +82 -17
- package/dist/index.js.map +1 -1
- package/dist/{reservation-history-bKDqkf8T.d.ts → reservation-history-C6giSdFd.d.ts} +33 -3
- package/dist/testing.d.ts +20 -57
- package/dist/testing.js +423 -24
- package/dist/testing.js.map +1 -1
- package/package.json +5 -1
package/dist/testing.js
CHANGED
|
@@ -126,6 +126,304 @@ function lineFields(value) {
|
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
// src/queue/host-date.ts
|
|
130
|
+
var MONTHS = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
|
|
131
|
+
var DAY_MS = 864e5;
|
|
132
|
+
var HALF_YEAR_DAYS = 184;
|
|
133
|
+
function resolveHostDate(text2, referenceDate, options = {}) {
|
|
134
|
+
const reference = referenceDay(referenceDate);
|
|
135
|
+
const direction = options.direction ?? "past";
|
|
136
|
+
if (direction !== "past" && direction !== "nearest") {
|
|
137
|
+
throw new TypeError("sabre-client: direction debe ser 'past' o 'nearest'");
|
|
138
|
+
}
|
|
139
|
+
if (typeof text2 !== "string") return void 0;
|
|
140
|
+
const parsed = parseHostDate(text2.trim().toUpperCase());
|
|
141
|
+
if (parsed === void 0) return void 0;
|
|
142
|
+
const year = parsed.year ?? resolveYear(parsed.month, parsed.day, reference, direction);
|
|
143
|
+
if (year === void 0 || !isValidDate(year, parsed.month, parsed.day)) return void 0;
|
|
144
|
+
const date = `${pad(year, 4)}-${pad(parsed.month, 2)}-${pad(parsed.day, 2)}`;
|
|
145
|
+
return parsed.time === void 0 ? date : `${date}T${parsed.time}`;
|
|
146
|
+
}
|
|
147
|
+
function parseHostDate(text2) {
|
|
148
|
+
let match = /^(\d{1,2})([A-Z]{3})(\d{2})?$/.exec(text2);
|
|
149
|
+
if (match !== null) {
|
|
150
|
+
const month2 = MONTHS.indexOf(match[2]) + 1;
|
|
151
|
+
if (month2 === 0) return void 0;
|
|
152
|
+
return {
|
|
153
|
+
...match[3] !== void 0 && { year: 2e3 + Number(match[3]) },
|
|
154
|
+
month: month2,
|
|
155
|
+
day: Number(match[1])
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
match = /^(?:(\d{4})-)?(\d{2})-(\d{2})(?:T(\d{2}):(\d{2}))?$/.exec(text2);
|
|
159
|
+
if (match === null) return void 0;
|
|
160
|
+
const [, year, month, day, hours, minutes] = match;
|
|
161
|
+
if (hours !== void 0 && (Number(hours) > 23 || Number(minutes) > 59)) return void 0;
|
|
162
|
+
return {
|
|
163
|
+
...year !== void 0 && { year: Number(year) },
|
|
164
|
+
month: Number(month),
|
|
165
|
+
day: Number(day),
|
|
166
|
+
...hours !== void 0 && { time: `${hours}:${minutes}` }
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function resolveYear(month, day, reference, direction) {
|
|
170
|
+
const year = new Date(reference).getUTCFullYear();
|
|
171
|
+
if (direction === "past") {
|
|
172
|
+
for (let candidate = year; candidate >= year - 8; candidate--) {
|
|
173
|
+
if (isValidDate(candidate, month, day) && dayNumber(candidate, month, day) <= reference) return candidate;
|
|
174
|
+
}
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
let best;
|
|
178
|
+
for (const candidate of [year + 1, year, year - 1]) {
|
|
179
|
+
if (!isValidDate(candidate, month, day)) continue;
|
|
180
|
+
const distance = Math.abs(dayNumber(candidate, month, day) - reference);
|
|
181
|
+
if (best === void 0 || distance < best.distance) best = { year: candidate, distance };
|
|
182
|
+
}
|
|
183
|
+
return best !== void 0 && best.distance <= HALF_YEAR_DAYS * DAY_MS ? best.year : void 0;
|
|
184
|
+
}
|
|
185
|
+
function referenceDay(referenceDate) {
|
|
186
|
+
if (referenceDate instanceof Date) {
|
|
187
|
+
const time = referenceDate.getTime();
|
|
188
|
+
if (Number.isNaN(time)) throw new TypeError("sabre-client: referenceDate es un Date inv\xE1lido");
|
|
189
|
+
return time - (time % DAY_MS + DAY_MS) % DAY_MS;
|
|
190
|
+
}
|
|
191
|
+
if (typeof referenceDate === "string") {
|
|
192
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})(?:T.*)?$/.exec(referenceDate.trim());
|
|
193
|
+
if (match !== null) {
|
|
194
|
+
const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
195
|
+
if (isValidDate(year, month, day)) return dayNumber(year, month, day);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
throw new TypeError("sabre-client: referenceDate es obligatoria, como 'YYYY-MM-DD' o un Date v\xE1lido");
|
|
199
|
+
}
|
|
200
|
+
function dayNumber(year, month, day) {
|
|
201
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
202
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
203
|
+
return date.getTime();
|
|
204
|
+
}
|
|
205
|
+
function isValidDate(year, month, day) {
|
|
206
|
+
if (month < 1 || month > 12 || day < 1) return false;
|
|
207
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
208
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
209
|
+
return date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
|
|
210
|
+
}
|
|
211
|
+
function pad(value, length) {
|
|
212
|
+
return String(value).padStart(length, "0");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// src/queue/queue-paragraph.ts
|
|
216
|
+
var MESSAGE = /^\s*(\d{3})\s{2,}(\S.*?)\s*$/;
|
|
217
|
+
var PASSENGER_LINE = /^\s*\d+\.\d+[A-Z]/;
|
|
218
|
+
var PASSENGER_SPLIT = /\s+(?=\d+\.\d+[A-Z])/;
|
|
219
|
+
var PASSENGER = /^(\d+\.\d+)([^/*]+?)\s*(?:\/([^*]*?))?\s*(?:\*(.*?))?\s*$/;
|
|
220
|
+
var AIR_SEGMENT = /^\s*(\d{1,2})\s+([A-Z0-9]{2})\s*(\d{1,4})([A-Z])\s+(\d{2}[A-Z]{3})\s+[A-Z0-9]\s+([A-Z]{3})([A-Z]{3})\s+([A-Z]{2})(\d{1,3})(?=\s|$)(.*)$/;
|
|
221
|
+
var SEGMENT_TIMES = /^\s+(\d{3,4}[APNM]?)\s+(\d{3,4}[APNM]?)(?=\s|$)/;
|
|
222
|
+
var OTHER_SEGMENT = /^\s*(\d{1,2})\s+([A-Z]{3})\s+([A-Z0-9]{2})\s+(\d{2}[A-Z]{3})\s+[A-Z0-9]\s+([A-Z]{2})(\d{1,3})(?=\s|$)/;
|
|
223
|
+
var NO_ITINERARY = /^\s*NO ITIN\s*$/;
|
|
224
|
+
var TICKETING_HEADER = /^\s*TKT\/TIME LIMIT\s*$/;
|
|
225
|
+
var TICKETING_ENTRY = /^\s*(\d+)\.(.*?)\s*$/;
|
|
226
|
+
var TICKETED = /^T-(\d{2}[A-Z]{3})?(?:-([A-Z0-9]{3,4})\*([A-Z0-9]+))?(?:\/.*)?$/;
|
|
227
|
+
var ARRANGEMENT = /^(TA[WCMTX])([A-Z0-9]{3,4})?(\d{2}[A-Z]{3})?\d{0,3}\/.*$/;
|
|
228
|
+
var TICKET = /^(TE|TK)\s+(\d{13})\b/;
|
|
229
|
+
var RECEIVED = /^\s*RECEIVED FROM -\s?(.*?)\s*$/;
|
|
230
|
+
var SIGNATURE = /^\s*([A-Z0-9]{3,4})\.(\S+)\s+(\d{2})(\d{2})\/(\d{2}[A-Z]{3}\d{2})\s+([A-Z0-9]{6})\s+H\s*$/;
|
|
231
|
+
var Phase = { Messages: 0, Passengers: 1, Segments: 2, Body: 3 };
|
|
232
|
+
function parseQueueParagraph(lines, options) {
|
|
233
|
+
if (!Array.isArray(lines)) throw new TypeError("sabre-client: lines debe ser un array de strings");
|
|
234
|
+
if (typeof options !== "object" || options === null) {
|
|
235
|
+
throw new TypeError("sabre-client: referenceDate es obligatoria, como 'YYYY-MM-DD' o un Date v\xE1lido");
|
|
236
|
+
}
|
|
237
|
+
const { referenceDate } = options;
|
|
238
|
+
referenceDay(referenceDate);
|
|
239
|
+
const result = { messages: [], passengers: [], segments: [], unparsed: [] };
|
|
240
|
+
const signatureIndex = lastSignatureIndex(lines);
|
|
241
|
+
let phase = Phase.Messages;
|
|
242
|
+
let inTicketing = false;
|
|
243
|
+
lines.forEach((value, index) => {
|
|
244
|
+
const line = typeof value === "string" ? value : "";
|
|
245
|
+
if (line.trim() === "") return;
|
|
246
|
+
if (index === signatureIndex) {
|
|
247
|
+
result.receivedFrom = { ...result.receivedFrom, ...parseSignature(line, referenceDate) };
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (inTicketing) {
|
|
251
|
+
const entry = TICKETING_ENTRY.exec(line);
|
|
252
|
+
if (entry !== null) {
|
|
253
|
+
const parsed = parseTicketingEntry(Number(entry[1]), entry[2], referenceDate);
|
|
254
|
+
if (parsed === void 0) result.unparsed.push(line);
|
|
255
|
+
else result.ticketing.entries.push(parsed);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
inTicketing = false;
|
|
259
|
+
}
|
|
260
|
+
if (TICKETING_HEADER.test(line)) {
|
|
261
|
+
phase = Phase.Body;
|
|
262
|
+
inTicketing = true;
|
|
263
|
+
result.ticketing ??= { entries: [], issued: false };
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
const received = RECEIVED.exec(line);
|
|
267
|
+
if (received !== null) {
|
|
268
|
+
phase = Phase.Body;
|
|
269
|
+
result.receivedFrom = { ...result.receivedFrom, ...received[1] !== "" && { name: received[1] } };
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (phase === Phase.Messages) {
|
|
273
|
+
const message = MESSAGE.exec(line);
|
|
274
|
+
if (message !== null) {
|
|
275
|
+
result.messages.push({ instructionCode: Number(message[1]), text: message[2] });
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (phase <= Phase.Passengers && PASSENGER_LINE.test(line)) {
|
|
280
|
+
const passengers = parsePassengers(line);
|
|
281
|
+
if (passengers !== void 0) {
|
|
282
|
+
phase = Phase.Passengers;
|
|
283
|
+
result.passengers.push(...passengers);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (phase <= Phase.Segments) {
|
|
288
|
+
if (NO_ITINERARY.test(line)) {
|
|
289
|
+
phase = Phase.Segments;
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const segment = parseSegment(line, referenceDate);
|
|
293
|
+
if (segment !== void 0) {
|
|
294
|
+
phase = Phase.Segments;
|
|
295
|
+
result.segments.push(segment);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
result.unparsed.push(line);
|
|
300
|
+
});
|
|
301
|
+
if (result.ticketing !== void 0) {
|
|
302
|
+
result.ticketing.issued = result.ticketing.entries.some((entry) => entry.ticketNumber !== void 0);
|
|
303
|
+
}
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
function parsePassengers(line) {
|
|
307
|
+
const passengers = [];
|
|
308
|
+
for (const part of line.trim().split(PASSENGER_SPLIT)) {
|
|
309
|
+
const match = PASSENGER.exec(part);
|
|
310
|
+
if (match === null) return void 0;
|
|
311
|
+
const [, nameNumber, surname, givenName, nameRemark] = match;
|
|
312
|
+
passengers.push({
|
|
313
|
+
nameNumber,
|
|
314
|
+
surname: surname.trim(),
|
|
315
|
+
...givenName !== void 0 && givenName !== "" && { givenName },
|
|
316
|
+
...nameRemark !== void 0 && nameRemark !== "" && { nameRemark },
|
|
317
|
+
text: part.slice(nameNumber.length).trim()
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return passengers;
|
|
321
|
+
}
|
|
322
|
+
function parseSegment(line, referenceDate) {
|
|
323
|
+
const air = AIR_SEGMENT.exec(line);
|
|
324
|
+
if (air !== null) {
|
|
325
|
+
const [, number2, airlineCode, flightNumber, bookingClass, date2, from, to, status2, quantity2, rest] = air;
|
|
326
|
+
const times = SEGMENT_TIMES.exec(rest);
|
|
327
|
+
const departureTime = times === null ? void 0 : hostTime(times[1]);
|
|
328
|
+
const arrivalTime = times === null ? void 0 : hostTime(times[2]);
|
|
329
|
+
return {
|
|
330
|
+
kind: "air",
|
|
331
|
+
number: Number(number2),
|
|
332
|
+
...withDate(date2, referenceDate),
|
|
333
|
+
status: status2,
|
|
334
|
+
quantity: Number(quantity2),
|
|
335
|
+
airlineCode,
|
|
336
|
+
flightNumber: Number(flightNumber),
|
|
337
|
+
bookingClass,
|
|
338
|
+
fromAirportCode: from,
|
|
339
|
+
toAirportCode: to,
|
|
340
|
+
...departureTime !== void 0 && { departureTime },
|
|
341
|
+
...arrivalTime !== void 0 && { arrivalTime },
|
|
342
|
+
text: line.trim()
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
const other = OTHER_SEGMENT.exec(line);
|
|
346
|
+
if (other === null) return void 0;
|
|
347
|
+
const [, number, segmentType, vendorCode, date, status, quantity] = other;
|
|
348
|
+
return {
|
|
349
|
+
kind: "other",
|
|
350
|
+
number: Number(number),
|
|
351
|
+
...withDate(date, referenceDate),
|
|
352
|
+
status,
|
|
353
|
+
quantity: Number(quantity),
|
|
354
|
+
segmentType,
|
|
355
|
+
vendorCode,
|
|
356
|
+
text: line.trim()
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function parseTicketingEntry(number, text2, referenceDate) {
|
|
360
|
+
const ticketed = TICKETED.exec(text2);
|
|
361
|
+
if (ticketed !== null) {
|
|
362
|
+
const [, date, pseudoCityCode, agentSine] = ticketed;
|
|
363
|
+
return {
|
|
364
|
+
number,
|
|
365
|
+
code: "T-",
|
|
366
|
+
...date !== void 0 && withDate(date, referenceDate),
|
|
367
|
+
...pseudoCityCode !== void 0 && { pseudoCityCode },
|
|
368
|
+
...agentSine !== void 0 && { agentSine },
|
|
369
|
+
text: text2
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
const arrangement = ARRANGEMENT.exec(text2);
|
|
373
|
+
if (arrangement !== null) {
|
|
374
|
+
const [, code, pseudoCityCode, date] = arrangement;
|
|
375
|
+
return {
|
|
376
|
+
number,
|
|
377
|
+
code,
|
|
378
|
+
...date !== void 0 && withDate(date, referenceDate),
|
|
379
|
+
...pseudoCityCode !== void 0 && { pseudoCityCode },
|
|
380
|
+
text: text2
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
const ticket = TICKET.exec(text2);
|
|
384
|
+
if (ticket !== null) return { number, code: ticket[1], ticketNumber: ticket[2], text: text2 };
|
|
385
|
+
return void 0;
|
|
386
|
+
}
|
|
387
|
+
function lastSignatureIndex(lines) {
|
|
388
|
+
for (let index = lines.length - 1; index >= 0; index--) {
|
|
389
|
+
const line = lines[index];
|
|
390
|
+
if (typeof line === "string" && SIGNATURE.test(line)) return index;
|
|
391
|
+
}
|
|
392
|
+
return -1;
|
|
393
|
+
}
|
|
394
|
+
function parseSignature(line, referenceDate) {
|
|
395
|
+
const [, pseudoCityCode, sign, hours, minutes, date, locator] = SIGNATURE.exec(line);
|
|
396
|
+
const agentSine = /\*([A-Z0-9]+)$/.exec(sign)?.[1];
|
|
397
|
+
const day = Number(hours) <= 23 && Number(minutes) <= 59 ? resolveHostDate(date, referenceDate) : void 0;
|
|
398
|
+
return {
|
|
399
|
+
pseudoCityCode,
|
|
400
|
+
...agentSine !== void 0 && { agentSine },
|
|
401
|
+
...day !== void 0 && { receivedAt: `${day}T${hours}:${minutes}` },
|
|
402
|
+
locator
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
function withDate(text2, referenceDate) {
|
|
406
|
+
const date = resolveHostDate(text2, referenceDate, { direction: "nearest" });
|
|
407
|
+
return date === void 0 ? {} : { date };
|
|
408
|
+
}
|
|
409
|
+
function hostTime(text2) {
|
|
410
|
+
const match = /^(\d{1,2})(\d{2})([APNM])?$/.exec(text2);
|
|
411
|
+
if (match === null) return void 0;
|
|
412
|
+
let hours = Number(match[1]);
|
|
413
|
+
const minutes = Number(match[2]);
|
|
414
|
+
const suffix = match[3];
|
|
415
|
+
if (minutes > 59) return void 0;
|
|
416
|
+
if (suffix === void 0) {
|
|
417
|
+
if (hours > 23) return void 0;
|
|
418
|
+
} else {
|
|
419
|
+
if (hours < 1 || hours > 12) return void 0;
|
|
420
|
+
if (suffix === "A" || suffix === "M") hours %= 12;
|
|
421
|
+
else if (suffix === "P") hours = hours % 12 + 12;
|
|
422
|
+
else if (hours !== 12) return void 0;
|
|
423
|
+
}
|
|
424
|
+
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
|
|
425
|
+
}
|
|
426
|
+
|
|
129
427
|
// src/queue/queue-place.ts
|
|
130
428
|
var SIGNATURE_LINE = /\s\d{4}\/\d{2}[A-Z]{3}\d{2}\s+([A-Z0-9]{6})\s+H\s*$/;
|
|
131
429
|
function signatureLocator(lines) {
|
|
@@ -142,6 +440,15 @@ var STL_NAMESPACE = "http://services.sabre.com/STL/v01";
|
|
|
142
440
|
var SIGNATURE_DATE = "1200/01JAN26";
|
|
143
441
|
var LOCATOR = /^[A-Z0-9]{6}$/;
|
|
144
442
|
var NAVIGATION = { I: "ignore", QR: "remove", QXI: "exit" };
|
|
443
|
+
var QUEUE_FAKE_SELECTION_FUNCTIONS = ["QD", "AK", "AL", "PI", "AC"];
|
|
444
|
+
var LIST_SELECTION_FUNCTIONS = ["QD", "AK"];
|
|
445
|
+
var MONTHS2 = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
|
|
446
|
+
function placedOn(placedAt, criteria) {
|
|
447
|
+
const date = /^(\d{1,2})([A-Z]{3})$/.exec(criteria.toUpperCase());
|
|
448
|
+
const placed = /(\d{2})-(\d{2})T/.exec(placedAt ?? "");
|
|
449
|
+
if (date === null || placed === null) return false;
|
|
450
|
+
return Number(placed[1]) === MONTHS2.indexOf(date[2]) + 1 && Number(placed[2]) === Number(date[1]);
|
|
451
|
+
}
|
|
145
452
|
function fail(message) {
|
|
146
453
|
throw new TypeError(`sabre-client/testing: ${message}`);
|
|
147
454
|
}
|
|
@@ -188,9 +495,9 @@ function refOfKey(key) {
|
|
|
188
495
|
if (key.startsWith(NAME_PREFIX)) return { name: key.slice(NAME_PREFIX.length) };
|
|
189
496
|
return /^\d+$/.test(key) ? Number(key) : key;
|
|
190
497
|
}
|
|
191
|
-
function keyAttribute(key,
|
|
498
|
+
function keyAttribute(key, pad2 = false) {
|
|
192
499
|
if (key.startsWith(NAME_PREFIX)) return `Name="${escape(key.slice(NAME_PREFIX.length))}"`;
|
|
193
|
-
return `Number="${escape(
|
|
500
|
+
return `Number="${escape(pad2 && /^\d+$/.test(key) ? key.padStart(4, "0") : key)}"`;
|
|
194
501
|
}
|
|
195
502
|
function validateKey(key) {
|
|
196
503
|
if (/^\d+$/.test(key)) {
|
|
@@ -438,7 +745,43 @@ function createQueueFake(options = {}) {
|
|
|
438
745
|
const placeRS = (inner) => `<QueuePlaceRS xmlns="${SWS_NAMESPACE}" xmlns:stl="${STL_NAMESPACE}" Version="2.0.4">${inner}</QueuePlaceRS>`;
|
|
439
746
|
const accessError = (message) => accessRS(results("NotProcessed", hostResult("Error", message)));
|
|
440
747
|
const placeError = (message) => placeRS(results("NotProcessed", hostResult("Error", message)));
|
|
748
|
+
const matchesFilter = (entry, fn, criteria) => {
|
|
749
|
+
if (entry.message !== void 0) return false;
|
|
750
|
+
const wanted = criteria.trim().toUpperCase();
|
|
751
|
+
const paragraph = () => parseQueueParagraph(pnrs.get(entry.locator)?.paragraph ?? [], { referenceDate: now() });
|
|
752
|
+
switch (fn.toUpperCase()) {
|
|
753
|
+
case "QD":
|
|
754
|
+
return placedOn(entry.placedAt, wanted);
|
|
755
|
+
case "AK":
|
|
756
|
+
return `${entry.placedBy?.pseudoCityCode ?? ""}${entry.placedBy?.agentSine ?? ""}`.toUpperCase() === wanted;
|
|
757
|
+
case "AL":
|
|
758
|
+
return paragraph().segments.some((segment) => segment.kind === "air" && segment.airlineCode === wanted);
|
|
759
|
+
case "AC":
|
|
760
|
+
return paragraph().segments.some((segment) => segment.status.startsWith(wanted));
|
|
761
|
+
case "PI": {
|
|
762
|
+
const code = Number(wanted);
|
|
763
|
+
if (entry.instructionCode !== void 0) return entry.instructionCode === code;
|
|
764
|
+
return paragraph().messages.some((message) => message.instructionCode === code);
|
|
765
|
+
}
|
|
766
|
+
default:
|
|
767
|
+
return void 0;
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
const selectionOf = (rq, allowed) => {
|
|
771
|
+
const filters = nodes(rq.Selection).map((selection) => ({ fn: (attr(selection, "Function") ?? "").toUpperCase(), criteria: attr(selection, "Criteria") ?? "" }));
|
|
772
|
+
if (filters.length === 0) return {};
|
|
773
|
+
const unsupported = filters.find((filter) => !allowed.includes(filter.fn));
|
|
774
|
+
if (unsupported !== void 0) return { error: `sabre-client/testing: selection ${unsupported.fn} no est\xE1 simulado (simula ${allowed.join(", ")})` };
|
|
775
|
+
return { matches: (entry) => filters.every((filter) => matchesFilter(entry, filter.fn, filter.criteria) === true) };
|
|
776
|
+
};
|
|
777
|
+
const advance = (session) => {
|
|
778
|
+
const inside = session.inside;
|
|
779
|
+
if (inside?.matches === void 0) return;
|
|
780
|
+
const entries = queue(inside.key);
|
|
781
|
+
while (inside.index < entries.length && !inside.matches(entries[inside.index])) inside.index += 1;
|
|
782
|
+
};
|
|
441
783
|
const step = (session) => {
|
|
784
|
+
advance(session);
|
|
442
785
|
const inside = session.inside;
|
|
443
786
|
const entry = inside === void 0 ? void 0 : queue(inside.key)[inside.index];
|
|
444
787
|
if (entry === void 0) {
|
|
@@ -452,19 +795,51 @@ function createQueueFake(options = {}) {
|
|
|
452
795
|
return accessRS(`${results("Complete", success)}${lineXml(entry)}<Paragraph>${textLines2(pnr.paragraph)}</Paragraph>`);
|
|
453
796
|
};
|
|
454
797
|
const waiting = (session, key, entries) => entries.length - (session.inside?.key === key && entries[session.inside.index] !== void 0 ? 1 : 0);
|
|
798
|
+
const countRS = (inner) => `<QueueCountRS xmlns="${SWS_NAMESPACE}" xmlns:stl="${STL_NAMESPACE}" Version="2.2.1">${inner}</QueueCountRS>`;
|
|
455
799
|
const count = (session, rq) => {
|
|
456
|
-
const
|
|
800
|
+
const identifier = node2(node2(rq.QueueInfo)?.QueueIdentifier);
|
|
801
|
+
const pcc = attr(identifier, "PseudoCityCode") ?? "";
|
|
802
|
+
const countError = (message) => countRS(results("NotProcessed", hostResult("Error", message)));
|
|
803
|
+
const range = node2(identifier?.Range);
|
|
804
|
+
const requested = requestedKey(identifier);
|
|
805
|
+
const { matches, error } = selectionOf(rq, QUEUE_FAKE_SELECTION_FUNCTIONS);
|
|
806
|
+
if (matches !== void 0 || error !== void 0) {
|
|
807
|
+
if (range !== void 0) return countError("KEYS NOT ALLOWED");
|
|
808
|
+
if (requested === void 0) return countError("QUEUE SELECTED NOT VALID OR CLOSED");
|
|
809
|
+
if (error !== void 0) return countError(error);
|
|
810
|
+
}
|
|
811
|
+
const info = (identifiers2) => `${results("Complete", success)}<QueueInfo DateTime="${shortDate(now())}" PseudoCityCode="${escape(pcc)}">${identifiers2.join("")}</QueueInfo>`;
|
|
812
|
+
const totalsXml = (messages2, pnrs2) => `<Totals Count="${messages2}" Type="MESSAGES"/><Totals Count="0" Type="SPECIALS"/><Totals Count="${pnrs2}" Type="PNRS"/>`;
|
|
813
|
+
const waitingIn = (key) => waiting(session, key, queues.get(key) ?? []);
|
|
814
|
+
if (range !== void 0) {
|
|
815
|
+
const start = Number(attr(range, "Start"));
|
|
816
|
+
const end = Number(attr(range, "End"));
|
|
817
|
+
const identifiers2 = [];
|
|
818
|
+
let pnrsTotal2 = 0;
|
|
819
|
+
for (let number = start; number <= end; number++) {
|
|
820
|
+
const total = waitingIn(String(number));
|
|
821
|
+
identifiers2.push(`<QueueIdentifier Count="${total}" Number="${number}"/>`);
|
|
822
|
+
pnrsTotal2 += total;
|
|
823
|
+
}
|
|
824
|
+
return countRS(`${info(identifiers2)}${totalsXml(0, pnrsTotal2)}`);
|
|
825
|
+
}
|
|
826
|
+
if (requested !== void 0) {
|
|
827
|
+
if (matches === void 0) return countRS(info([`<QueueIdentifier Count="${waitingIn(requested)}" ${keyAttribute(requested)}/>`]));
|
|
828
|
+
const onScreen = session.inside?.key === requested ? queue(requested)[session.inside.index] : void 0;
|
|
829
|
+
const matching = (queues.get(requested) ?? []).filter((entry) => entry !== onScreen && matches(entry)).length;
|
|
830
|
+
return countRS(`${info([`<QueueIdentifier Count="${matching}" ${keyAttribute(requested)}/>`])}<Totals Count="${waitingIn(requested)}"/>`);
|
|
831
|
+
}
|
|
457
832
|
let pnrsTotal = 0;
|
|
458
833
|
let messages = 0;
|
|
459
834
|
const identifiers = [];
|
|
460
|
-
for (const [
|
|
461
|
-
const total = waiting(session,
|
|
835
|
+
for (const [queueKey2, entries] of queues) {
|
|
836
|
+
const total = waiting(session, queueKey2, entries);
|
|
462
837
|
if (total <= 0) continue;
|
|
463
|
-
identifiers.push(`<QueueIdentifier Count="${total}" ${keyAttribute(
|
|
464
|
-
if (ALPHA_KEY.test(
|
|
838
|
+
identifiers.push(`<QueueIdentifier Count="${total}" ${keyAttribute(queueKey2)}/>`);
|
|
839
|
+
if (ALPHA_KEY.test(queueKey2)) messages += total;
|
|
465
840
|
else pnrsTotal += total;
|
|
466
841
|
}
|
|
467
|
-
return
|
|
842
|
+
return countRS(`${info(identifiers)}${totalsXml(messages, pnrsTotal)}`);
|
|
468
843
|
};
|
|
469
844
|
const access = (session, rq) => {
|
|
470
845
|
const navigation = attr(rq.Navigation, "Action");
|
|
@@ -474,15 +849,20 @@ function createQueueFake(options = {}) {
|
|
|
474
849
|
if (key === void 0) return accessError("sabre-client/testing: QueueIdentifier sin Number ni Name");
|
|
475
850
|
const isList = node2(identifier?.List) !== void 0;
|
|
476
851
|
calls.push({ command: isList ? "list" : "access", queue: refOfKey(key) });
|
|
477
|
-
if (nodes(rq.Selection).
|
|
852
|
+
if (isList && nodes(rq.Selection).some((selection) => !LIST_SELECTION_FUNCTIONS.includes((attr(selection, "Function") ?? "").toUpperCase()))) {
|
|
853
|
+
return accessError("VALID SELECTION CODE FOR QUEUE LIST ARE QD OR AK");
|
|
854
|
+
}
|
|
855
|
+
const { matches, error } = selectionOf(rq, QUEUE_FAKE_SELECTION_FUNCTIONS);
|
|
856
|
+
if (error !== void 0) return accessError(error);
|
|
478
857
|
const entries = queue(key);
|
|
479
858
|
if (entries.length === 0) return accessError(QUEUE_EMPTY);
|
|
480
859
|
if (isList) {
|
|
481
860
|
const passenger = attr(identifier?.List, "PrimaryPassenger") === "true";
|
|
482
|
-
const
|
|
861
|
+
const listed = matches === void 0 ? entries : entries.filter(matches);
|
|
862
|
+
const lines = listed.map((entry, index) => lineXml(entry, { number: index + 1, passenger })).join("");
|
|
483
863
|
return accessRS(`${results("Complete", success)}${lines}`);
|
|
484
864
|
}
|
|
485
|
-
session.inside = { key, index: 0 };
|
|
865
|
+
session.inside = { key, index: 0, ...matches === void 0 ? {} : { matches } };
|
|
486
866
|
return step(session);
|
|
487
867
|
};
|
|
488
868
|
const navigate = (session, rq, action) => {
|
|
@@ -532,10 +912,12 @@ function createQueueFake(options = {}) {
|
|
|
532
912
|
const add = (locator, target) => {
|
|
533
913
|
const entries = queue(target.key);
|
|
534
914
|
if (entries.some((entry) => entry.locator === locator)) return;
|
|
915
|
+
const code = Number(target.instructionCode);
|
|
535
916
|
entries.push({
|
|
536
917
|
locator,
|
|
537
918
|
placedAt: longDate(at),
|
|
538
|
-
placedBy: target.pcc === void 0 ? void 0 : { pseudoCityCode: target.pcc }
|
|
919
|
+
placedBy: target.pcc === void 0 ? void 0 : { pseudoCityCode: target.pcc },
|
|
920
|
+
...Number.isInteger(code) ? { instructionCode: code } : {}
|
|
539
921
|
});
|
|
540
922
|
};
|
|
541
923
|
if (moving) {
|
|
@@ -543,6 +925,7 @@ function createQueueFake(options = {}) {
|
|
|
543
925
|
if (current === void 0) return placeError("sabre-client/testing: no hay PNR en pantalla");
|
|
544
926
|
queue(inside.key).splice(inside.index, 1);
|
|
545
927
|
for (const target of targets) add(current.locator, target);
|
|
928
|
+
advance(session);
|
|
546
929
|
const next = queue(inside.key)[inside.index];
|
|
547
930
|
if (next === void 0) {
|
|
548
931
|
session.inside = void 0;
|
|
@@ -565,22 +948,37 @@ function createQueueFake(options = {}) {
|
|
|
565
948
|
};
|
|
566
949
|
const analyze = (session, rq) => {
|
|
567
950
|
calls.push({ command: "activity" });
|
|
568
|
-
const
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
const identifiers = [];
|
|
572
|
-
for (const key of /* @__PURE__ */ new Set([...queues.keys(), ...activity.keys()])) {
|
|
951
|
+
const identifier = node2(node2(rq.QueueInfo)?.QueueIdentifier);
|
|
952
|
+
const pcc = attr(identifier, "PseudoCityCode") ?? "";
|
|
953
|
+
const countersOf = (key) => {
|
|
573
954
|
const seeded = activity.get(key) ?? {};
|
|
574
955
|
const counters = { NumMessages: waiting(session, key, queues.get(key) ?? []) };
|
|
575
956
|
for (const [name, element2] of ACTIVITY_COUNTERS) counters[element2] = seeded[name] ?? 0;
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
957
|
+
return counters;
|
|
958
|
+
};
|
|
959
|
+
const countersXml = (counters) => Object.entries(counters).map(([element2, value]) => `<${element2} Count="${value}"/>`).join("");
|
|
960
|
+
let keys;
|
|
961
|
+
let withTotals = true;
|
|
962
|
+
const range = node2(identifier?.Range);
|
|
963
|
+
const requested = requestedKey(identifier);
|
|
964
|
+
if (range !== void 0) {
|
|
965
|
+
keys = [];
|
|
966
|
+
for (let number = Number(attr(range, "Start")); number <= Number(attr(range, "End")); number++) keys.push(String(number));
|
|
967
|
+
} else if (requested !== void 0) {
|
|
968
|
+
keys = [requested];
|
|
969
|
+
withTotals = false;
|
|
970
|
+
} else {
|
|
971
|
+
keys = [.../* @__PURE__ */ new Set([...queues.keys(), ...activity.keys()])].filter((key) => Object.values(countersOf(key)).some((value) => value !== 0));
|
|
581
972
|
}
|
|
582
|
-
const
|
|
583
|
-
|
|
973
|
+
const totals = { NumMessages: 0 };
|
|
974
|
+
for (const [, element2] of ACTIVITY_COUNTERS) totals[element2] = 0;
|
|
975
|
+
const identifiers = keys.map((key) => {
|
|
976
|
+
const counters = countersOf(key);
|
|
977
|
+
for (const [element2, value] of Object.entries(counters)) totals[element2] = (totals[element2] ?? 0) + value;
|
|
978
|
+
return `<QueueIdentifier ${keyAttribute(key)}>${countersXml(counters)}</QueueIdentifier>`;
|
|
979
|
+
});
|
|
980
|
+
const totalsXml = withTotals ? `<Totals>${countersXml(totals)}</Totals>` : "";
|
|
981
|
+
return `<QueueAnalysisRS xmlns="${SWS_NAMESPACE}" xmlns:stl="${STL_NAMESPACE}" Version="2.0.0">${results("Complete", success)}<QueueInfo DateTime="${shortDate(now())}" PseudoCityCode="${escape(pcc)}">${identifiers.join("")}</QueueInfo>${totalsXml}</QueueAnalysisRS>`;
|
|
584
982
|
};
|
|
585
983
|
const history = (session, rq) => {
|
|
586
984
|
const locator = attr(rq.UniqueID, "ID") ?? "";
|
|
@@ -3283,6 +3681,7 @@ var queueFixtures = Object.freeze({
|
|
|
3283
3681
|
placeWithoutInstructionCodeInside: fixture(queue_production_place_sin_pic_adentro_default)
|
|
3284
3682
|
});
|
|
3285
3683
|
export {
|
|
3684
|
+
QUEUE_FAKE_SELECTION_FUNCTIONS,
|
|
3286
3685
|
createAnonymizer,
|
|
3287
3686
|
createQueueFake,
|
|
3288
3687
|
isSafeHostLine,
|