ojp-sdk-next
Version:
OJP (Open Journey Planner) Javascript SDK
1,433 lines (1,422 loc) • 45.2 kB
JavaScript
// src/helpers/xml/parser.ts
import * as OJP_Types from "ojp-shared-types";
import { XMLParser } from "fast-xml-parser";
var MapParentArrayTags = {};
for (const key in OJP_Types.OpenAPI_Dependencies.MapArrayTags) {
const keyParts = key.split(".");
if (keyParts.length !== 2) {
console.error("invalid OpenAPI_Dependencies.MapArrayTags key: " + key);
continue;
}
const parentTagName = keyParts[0];
const childTagName = keyParts[1];
if (!(parentTagName in MapParentArrayTags)) {
MapParentArrayTags[parentTagName] = [];
}
MapParentArrayTags[parentTagName].push(childTagName);
}
var transformTagNameHandler = (tagName) => {
if (tagName.startsWith("OJP")) {
return tagName;
}
let newTagName = tagName.replace(/[-_](.)/g, (_, char) => char.toUpperCase());
newTagName = newTagName.replace(/^([A-Z])/, (match) => match.toLowerCase());
return newTagName;
};
var isArrayHandler = (tagName, jPath) => {
const jPathParts = jPath.split(".");
if (jPathParts.length >= 2) {
const pathPart = jPathParts.slice(-2).join(".");
if (pathPart in OJP_Types.OpenAPI_Dependencies.MapArrayTags) {
return true;
}
}
return false;
};
function traverseJSON(obj, path, callback) {
if (typeof obj !== "object" || obj === null) {
return;
}
if (Array.isArray(obj)) {
for (const item of obj) {
traverseJSON(item, path, callback);
}
} else {
for (const key in obj) {
const newPath = path.slice();
newPath.push(key);
callback(key, obj[key], newPath);
traverseJSON(obj[key], newPath, callback);
}
}
}
function parseXML(xml, parentPath = "") {
const parser = new XMLParser({
ignoreAttributes: false,
removeNSPrefix: true,
transformTagName: transformTagNameHandler,
isArray: isArrayHandler
// parseTagValue: false,
});
const response = parser.parse(xml);
traverseJSON(response, [parentPath], (key, value, path) => {
if (typeof value === "object") {
if (path.length >= 2) {
if (key in MapParentArrayTags) {
const enforceChildTags = MapParentArrayTags[key];
if (Array.isArray(value)) {
value.forEach((childValue) => {
enforceChildTags.forEach((childTagName) => {
childValue[childTagName] ??= [];
});
});
} else {
enforceChildTags.forEach((childTagName) => {
value[childTagName] ??= [];
});
}
}
}
for (const key1 in value) {
const lastItem = path.at(-1) ?? "";
const stringKey = lastItem + "." + key1;
if (stringKey in OJP_Types.OpenAPI_Dependencies.MapStringValues) {
value[key1] = String(value[key1]);
}
if (typeof value[key1] === "object") {
if (Object.keys(value[key1]).includes("#text")) {
const otherKeys = Object.keys(value[key1]).filter((el) => el !== "#text");
otherKeys.forEach((otherKey) => {
const newKey = key1 + otherKey;
value[newKey] = value[key1][otherKey];
});
value[key1] = value[key1]["#text"];
}
}
}
}
});
return response;
}
// src/models/geoposition.ts
var GeoPosition = class {
longitude;
latitude;
properties;
constructor(geoPositionArg, optionalLatitude = null) {
const invalidCoords = [Infinity, Infinity];
const coords = (() => {
if (typeof geoPositionArg === "number" && isNaN(geoPositionArg)) {
return invalidCoords;
}
if (typeof geoPositionArg === "number" && optionalLatitude !== null) {
const longitude = geoPositionArg;
const latitude = optionalLatitude;
return [longitude, latitude];
}
if (typeof geoPositionArg === "string") {
const stringParts = geoPositionArg.split(",");
if (stringParts.length < 2) {
return invalidCoords;
}
const longitude = parseFloat(stringParts[1]);
const latitude = parseFloat(stringParts[0]);
return [longitude, latitude];
}
if (Array.isArray(geoPositionArg) && geoPositionArg.length > 1) {
return geoPositionArg;
}
if (typeof geoPositionArg === "object") {
const geoPositionObj = geoPositionArg;
if (geoPositionObj.hasOwnProperty("longitude") && geoPositionObj.hasOwnProperty("latitude")) {
const longitude = geoPositionArg.longitude;
const latitude = geoPositionArg.latitude;
return [Number(longitude), Number(latitude)];
}
}
return invalidCoords;
})();
this.longitude = parseFloat(coords[0].toFixed(6));
this.latitude = parseFloat(coords[1].toFixed(6));
this.properties = {};
}
isValid() {
return this.longitude !== Infinity && this.latitude !== Infinity;
}
// From https://stackoverflow.com/a/27943
distanceFrom(pointB) {
const R = 6371;
const dLat = (pointB.latitude - this.latitude) * Math.PI / 180;
const dLon = (pointB.longitude - this.longitude) * Math.PI / 180;
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(this.latitude * Math.PI / 180) * Math.cos(pointB.latitude * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const d = R * c;
const dMeters = Math.round(d * 1e3);
return dMeters;
}
asLatLngString(roundCoords = true) {
let s = "";
if (roundCoords) {
s = this.latitude.toFixed(6) + "," + this.longitude.toFixed(6);
} else {
s = this.latitude + "," + this.longitude;
}
return s;
}
// For Mapbox LngLat constructs
asLngLat() {
const coords = [this.longitude, this.latitude];
return coords;
}
};
// src/models/ojp.ts
var PlaceRef = class _PlaceRef {
stopPointRef;
stopPlaceRef;
geoPosition;
name;
constructor(name) {
this.stopPointRef = void 0;
this.stopPlaceRef = void 0;
this.geoPosition = void 0;
this.name = name;
}
// TODO - introduce a PlaceRefOrCoordsLike type that handles
// - string (currently implemented)
// - PlaceRef (and /or Place)
// - GeoPosition (and /or GeoPositionLike)
static initWithPlaceRefsOrCoords(placeRefOrCoords, nameS = null) {
const geoPosition = new GeoPosition(placeRefOrCoords);
if (geoPosition.isValid()) {
const nameText = nameS ?? geoPosition.asLatLngString();
const placeRef = new _PlaceRef({
text: nameText
});
placeRef.geoPosition = geoPosition;
return placeRef;
} else {
const name = {
text: nameS ?? "n/a"
};
const placeRef = new _PlaceRef(name);
placeRef.stopPlaceRef = placeRefOrCoords;
return placeRef;
}
}
};
var Trip = class _Trip {
id;
duration;
startTime;
endTime;
transfers;
leg;
cancelled;
delayed;
deviation;
infeasible;
unplanned;
constructor(id, duration, startTime, endTime, transfers, leg, cancelled, delayed, deviation, infeasible, unplanned) {
this.id = id;
this.duration = duration;
this.startTime = startTime;
this.endTime = endTime;
this.transfers = transfers;
this.leg = leg;
this.cancelled = cancelled;
this.delayed = delayed;
this.deviation = deviation;
this.infeasible = infeasible;
this.unplanned = unplanned;
}
static initWithTripXML(rawXML) {
const parentTagName = "TripResult";
const parsedTrip = parseXML(rawXML, parentTagName);
const trip = new _Trip(
parsedTrip.trip.id,
parsedTrip.trip.duration,
parsedTrip.trip.startTime,
parsedTrip.trip.endTime,
parsedTrip.trip.transfers,
parsedTrip.trip.leg,
parsedTrip.trip.cancelled,
parsedTrip.trip.delayed,
parsedTrip.trip.deviation,
parsedTrip.trip.infeasible,
parsedTrip.trip.unplanned
);
return trip;
}
};
var Place = class _Place {
stopPoint;
stopPlace;
topographicPlace;
pointOfInterest;
address;
name;
geoPosition;
mode;
placeType;
constructor(stopPoint, stopPlace, topographicPlace, pointOfInterest, address, name, geoPosition, mode) {
this.stopPoint = stopPoint;
this.stopPlace = stopPlace;
this.topographicPlace = topographicPlace;
this.pointOfInterest = pointOfInterest;
this.address = address;
this.name = name;
this.geoPosition = geoPosition;
this.mode = mode;
this.placeType = geoPosition.isValid() ? "location" : null;
if (stopPoint || stopPlace) {
this.placeType = "stop";
}
if (topographicPlace) {
this.placeType = "topographicPlace";
}
if (pointOfInterest) {
this.placeType = "poi";
}
if (address) {
this.placeType = "address";
}
}
static initWithXMLSchema(placeSchema) {
const geoPosition = new GeoPosition(placeSchema.geoPosition);
const place = new _Place(placeSchema.stopPoint, placeSchema.stopPlace, placeSchema.topographicPlace, placeSchema.pointOfInterest, placeSchema.address, placeSchema.name, geoPosition, placeSchema.mode);
return place;
}
static initWithCoords(geoPositionArg, optionalLatitude = null) {
const geoPosition = new GeoPosition(geoPositionArg, optionalLatitude);
const name = {
text: geoPosition.latitude + "," + geoPosition.longitude
};
const place = new _Place(void 0, void 0, void 0, void 0, void 0, name, geoPosition, []);
return place;
}
static Empty() {
const name = {
text: "n/a Empty"
};
const geoPosition = new GeoPosition("0,0");
const place = new _Place(void 0, void 0, void 0, void 0, void 0, name, geoPosition, []);
return place;
}
findClosestPlace(otherPlaces) {
const geoPositionA = this.geoPosition;
let closestPlace = null;
otherPlaces.forEach((locationB) => {
const geoPositionB = locationB.geoPosition;
if (geoPositionB === null) {
return;
}
const dAB = geoPositionA.distanceFrom(geoPositionB);
if (closestPlace === null || dAB < closestPlace.distance) {
closestPlace = {
object: locationB,
distance: dAB
};
}
});
return closestPlace;
}
// used by TR
// TODO - logic should be added to Place.initWithPlaceRefsOrCoords
asStopPlaceRefOrCoords() {
const stopPlaceRef = this.stopPlace?.stopPlaceRef ?? null;
if (stopPlaceRef !== null) {
return stopPlaceRef;
}
const coordsS = this.geoPosition.asLatLngString();
return coordsS;
}
};
var PlaceResult = class _PlaceResult {
place;
complete;
probability;
constructor(place, complete, probability) {
this.place = place;
this.complete = complete;
this.probability = probability;
}
static initWithXMLSchema(placeResultSchema) {
const place = Place.initWithXMLSchema(placeResultSchema.place);
const placeResult = new _PlaceResult(place, placeResultSchema.complete, placeResultSchema.probability);
return placeResult;
}
static initWithXML(nodeXML) {
const parentTagName = "PlaceResult";
const parsedObj = parseXML(nodeXML, parentTagName);
const placeSchema = parsedObj.placeResult.place;
const place = Place.initWithXMLSchema(placeSchema);
const placeResult = new _PlaceResult(place, parsedObj.placeResult.complete, parsedObj.placeResult.probability);
return placeResult;
}
};
var StopEventResult = class _StopEventResult {
id;
stopEvent;
constructor(id, stopEvent) {
this.id = id;
this.stopEvent = stopEvent;
}
static initWithXML(nodeXML) {
const parentTagName = "StopEventResult";
const parsedObj = parseXML(nodeXML, parentTagName);
const result = new _StopEventResult(parsedObj.stopEventResult.id, parsedObj.stopEventResult.stopEvent);
return result;
}
};
// src/helpers/ojp-v1.ts
var OJPv1_Helpers = class {
static convertOJPv2Trip_to_v1Trip(tripV2) {
const tripV2Copy = JSON.parse(JSON.stringify(tripV2));
const trip1 = {
tripId: tripV2Copy.id,
duration: tripV2Copy.duration,
startTime: tripV2Copy.startTime,
endTime: tripV2Copy.endTime,
transfers: tripV2Copy.transfers,
tripLeg: []
};
tripV2Copy.leg.forEach((legV2) => {
const legV1 = {
legId: legV2.id,
duration: legV2.duration,
timedLeg: void 0,
transferLeg: legV2.transferLeg,
continuousLeg: legV2.continuousLeg
};
if (legV2.timedLeg) {
const timedLegServiceV1 = {
conventionalModeOfOperation: legV2.timedLeg.service.conventionalModeOfOperation,
operatingDayRef: legV2.timedLeg.service.operatingDayRef,
journeyRef: legV2.timedLeg.service.journeyRef,
publicCode: legV2.timedLeg.service.publicCode,
lineRef: legV2.timedLeg.service.lineRef,
directionRef: legV2.timedLeg.service.directionRef,
mode: legV2.timedLeg.service.mode,
productCategory: legV2.timedLeg.service.productCategory,
publishedLineName: legV2.timedLeg.service.publishedServiceName,
trainNumber: legV2.timedLeg.service.trainNumber,
attribute: legV2.timedLeg.service.attribute,
operatorRef: legV2.timedLeg.service.operatorRef,
destinationStopPointRef: legV2.timedLeg.service.destinationStopPointRef,
destinationText: legV2.timedLeg.service.destinationText,
unplanned: legV2.timedLeg.service.unplanned,
cancelled: legV2.timedLeg.service.cancelled,
deviation: legV2.timedLeg.service.deviation
};
const timedLegV1 = {
legBoard: legV2.timedLeg.legBoard,
legIntermediates: legV2.timedLeg.legIntermediate,
legAlight: legV2.timedLeg.legAlight,
service: timedLegServiceV1,
legTrack: legV2.timedLeg.legTrack
};
legV1.timedLeg = timedLegV1;
}
trip1.tripLeg.push(legV1);
});
return trip1;
}
// Keep minimum required nodes needed for nova service, strip everything else
static cleanTripForFareRequest(trip) {
trip.tripLeg.forEach((leg) => {
if (leg.continuousLeg) {
leg.continuousLeg = {
legStart: {
name: leg.continuousLeg.legStart.name
},
legEnd: {
name: leg.continuousLeg.legEnd.name
},
service: {},
duration: leg.continuousLeg.duration
};
}
if (leg.transferLeg) {
leg.transferLeg = {
transferType: leg.transferLeg.transferType,
legStart: {
name: leg.transferLeg.legStart.name
},
legEnd: {
name: leg.transferLeg.legEnd.name
},
duration: leg.transferLeg.duration
};
}
if (leg.timedLeg) {
const newLegIntermediates = leg.timedLeg.legIntermediates.map((el) => {
const newLeg = {
stopPointRef: el.stopPointRef,
stopPointName: el.stopPointName,
serviceArrival: el.serviceArrival,
serviceDeparture: el.serviceDeparture
};
return newLeg;
});
leg.timedLeg = {
legBoard: {
stopPointRef: leg.timedLeg.legBoard.stopPointRef,
stopPointName: leg.timedLeg.legBoard.stopPointName,
serviceDeparture: leg.timedLeg.legBoard.serviceDeparture
},
legIntermediates: newLegIntermediates,
legAlight: {
stopPointRef: leg.timedLeg.legAlight.stopPointRef,
stopPointName: leg.timedLeg.legAlight.stopPointName,
serviceArrival: leg.timedLeg.legAlight.serviceArrival
},
service: {
operatingDayRef: leg.timedLeg.service.operatingDayRef,
journeyRef: leg.timedLeg.service.journeyRef,
lineRef: leg.timedLeg.service.lineRef,
directionRef: leg.timedLeg.service.directionRef,
mode: leg.timedLeg.service.mode,
publishedLineName: leg.timedLeg.service.publishedLineName,
attribute: [],
operatorRef: leg.timedLeg.service.operatorRef
}
};
}
});
}
};
// src/helpers/xml/builder.ts
import * as OJP_Types2 from "ojp-shared-types";
import { XMLBuilder } from "fast-xml-parser";
// src/constants.ts
var SDK_VERSION = "0.20.21";
var DefaultXML_Config = {
ojpVersion: "2.0",
defaultNS: "ojp",
mapNS: {
"ojp": "http://www.vdv.de/ojp",
"siri": "http://www.siri.org.uk/siri"
}
};
// src/helpers/xml/builder.ts
function transformKeys(obj, path = [], callback) {
if (obj !== null && typeof obj === "object" && !Array.isArray(obj)) {
for (const key in obj) {
if (key.includes("@_")) {
delete obj[key];
}
}
}
return Object.entries(obj).reduce((acc, [key, value]) => {
const newKey = callback(key, value, path);
const newPath = path.concat([newKey]);
acc[newKey] = (() => {
if (value instanceof Object) {
if (Array.isArray(value)) {
value.forEach((el, idx) => {
if (el instanceof Object) {
value[idx] = transformKeys(el, newPath, callback);
}
});
} else {
return transformKeys(value, newPath, callback);
}
}
return value;
})();
return acc;
}, {});
}
function buildRootXML(obj, xmlConfig = DefaultXML_Config, callbackTransformedObj = null) {
const wrapperNodeName = "OJP";
const rootXML = buildXML(obj, wrapperNodeName, xmlConfig, (objTransformed) => {
const rootKeys = Object.keys(objTransformed);
if (typeof objTransformed === "object" && rootKeys.length === 1) {
const rootKeyParts = rootKeys[0].split(":");
if (rootKeyParts.length === 2) {
const oldKey = rootKeys[0];
const newKey = rootKeyParts[1];
objTransformed[newKey] = objTransformed[oldKey];
delete objTransformed[oldKey];
}
}
if (callbackTransformedObj) {
callbackTransformedObj(objTransformed);
}
});
const wrapperRootXML_Lines = [
'<?xml version="1.0" encoding="utf-8"?>',
rootXML
];
const wrapperRootXML = wrapperRootXML_Lines.join("\n");
return wrapperRootXML;
}
function buildXML(obj, wrapperNodeName = "OJP", xmlConfig = DefaultXML_Config, callbackTransformedObj = null) {
const objCopy = JSON.parse(JSON.stringify(obj));
const objTransformed = transformKeys(objCopy, [wrapperNodeName], (key, value, path) => {
let newKey = key.charAt(0).toUpperCase() + key.slice(1);
const keysToKeep = OJP_Types2.OpenAPI_Dependencies.MapModelKeepPropertiesXML[key] ?? null;
if (keysToKeep !== null) {
if (typeof value === "object") {
const objKeys = Object.keys(value);
objKeys.forEach((objKey) => {
if (keysToKeep.includes(objKey)) {
return;
}
delete value[objKey];
});
}
}
const parentKey = path.at(-1) ?? null;
if (parentKey !== null) {
const tagNS_Key = parentKey.replace(/^.*:/, "") + "." + newKey;
const tagNS = (() => {
const tagNSConfig = OJP_Types2.OpenAPI_Dependencies.MapNS_Tags[tagNS_Key] ?? "ojp";
if (xmlConfig.defaultNS === tagNSConfig) {
return "";
}
return tagNSConfig + ":";
})();
if (tagNS !== null) {
newKey = tagNS + newKey;
}
}
return newKey;
});
if (callbackTransformedObj) {
callbackTransformedObj(objTransformed);
}
const xmlParts = [];
const isRootNode = wrapperNodeName === "OJP";
if (isRootNode) {
const xmlAttrs = [];
for (const ns in xmlConfig.mapNS) {
const url = xmlConfig.mapNS[ns];
const attrNS = ns === xmlConfig.defaultNS ? "xmlns" : "xmlns:" + ns;
const xmlAttr = attrNS + '="' + url + '"';
xmlAttrs.push(xmlAttr);
}
const xmlVersionAttr = 'version="' + xmlConfig.ojpVersion + '"';
xmlAttrs.push(xmlVersionAttr);
xmlParts.push("<OJP " + xmlAttrs.join(" ") + ">");
} else {
xmlParts.push("<" + wrapperNodeName + ">");
}
const builder = new XMLBuilder({
format: true,
ignoreAttributes: false,
suppressEmptyNode: true
});
xmlParts.push(builder.build(objTransformed));
xmlParts.push("</" + wrapperNodeName + ">");
const xmlS = xmlParts.join("\n");
return xmlS;
}
// src/helpers/date-helpers.ts
var DateHelpers = class _DateHelpers {
// 2021-06-03 21:38:04
static formatDate(d) {
const date_parts = [
d.getFullYear(),
"-",
("00" + (d.getMonth() + 1)).slice(-2),
"-",
("00" + d.getDate()).slice(-2),
" ",
("00" + d.getHours()).slice(-2),
":",
("00" + d.getMinutes()).slice(-2),
":",
("00" + d.getSeconds()).slice(-2)
];
return date_parts.join("");
}
// 21:38
static formatTimeHHMM(d = /* @__PURE__ */ new Date()) {
const dateFormatted = _DateHelpers.formatDate(d);
return dateFormatted.substring(11, 16);
}
static computeDelayMinutes(timetableTimeS, estimatedTimeS) {
if (estimatedTimeS === null) {
return null;
}
const timetableTime = typeof timetableTimeS === "string" ? new Date(timetableTimeS) : timetableTimeS;
const estimatedTime = typeof estimatedTimeS === "string" ? new Date(estimatedTimeS) : estimatedTimeS;
const dateDiffSeconds = (estimatedTime.getTime() - timetableTime.getTime()) / 1e3;
const delayMinutes = Math.floor(dateDiffSeconds / 60);
return delayMinutes;
}
};
// src/models/request.ts
var BaseRequest = class {
requestInfo;
mockRequestXML;
mockResponseXML;
enableExtensions;
constructor() {
this.requestInfo = {
requestDateTime: null,
requestXML: null,
responseDateTime: null,
responseXML: null,
parseDateTime: null
};
this.mockRequestXML = null;
this.mockResponseXML = null;
this.enableExtensions = true;
}
};
var TripRequest = class _TripRequest extends BaseRequest {
requestTimestamp;
origin;
destination;
via;
params;
constructor(origin, destination, via = [], params = null) {
super();
const now = /* @__PURE__ */ new Date();
this.requestTimestamp = now.toISOString();
this.origin = origin;
this.destination = destination;
this.via = via;
this.params = params ??= {};
this.mockRequestXML = null;
this.mockResponseXML = null;
}
static DefaultRequestParams() {
const requestParams = {
modeAndModeOfOperationFilter: [],
numberOfResults: 5,
numberOfResultsBefore: void 0,
numberOfResultsAfter: void 0,
useRealtimeData: "explanatory",
includeAllRestrictedLines: true,
includeTrackSections: true,
includeLegProjection: false,
includeIntermediateStops: true
};
return requestParams;
}
static Default() {
const date = /* @__PURE__ */ new Date();
const origin = {
placeRef: PlaceRef.initWithPlaceRefsOrCoords("8503000", "Z\xFCrich"),
depArrTime: date.toISOString()
};
const destination = {
placeRef: PlaceRef.initWithPlaceRefsOrCoords("8507000", "Bern")
};
const params = _TripRequest.DefaultRequestParams();
const request = new _TripRequest(origin, destination, [], params);
return request;
}
static initWithRequestMock(mockText) {
const request = _TripRequest.Default();
request.mockRequestXML = mockText;
return request;
}
static initWithResponseMock(mockText) {
const request = _TripRequest.Default();
request.mockResponseXML = mockText;
return request;
}
static initWithPlaceRefsOrCoords(originPlaceRefS, destinationPlaceRefS) {
const origin = {
placeRef: PlaceRef.initWithPlaceRefsOrCoords(originPlaceRefS)
};
const destination = {
placeRef: PlaceRef.initWithPlaceRefsOrCoords(destinationPlaceRefS)
};
const params = _TripRequest.DefaultRequestParams();
const request = new _TripRequest(origin, destination, [], params);
request.setDepartureDatetime();
return request;
}
static initWithPlaces(origin, destination) {
const originPlaceRefS = origin.asStopPlaceRefOrCoords();
const destinationPlaceRefS = destination.asStopPlaceRefOrCoords();
const request = _TripRequest.initWithPlaceRefsOrCoords(originPlaceRefS, destinationPlaceRefS);
return request;
}
setArrivalDatetime(newDatetime = /* @__PURE__ */ new Date()) {
delete this.origin.depArrTime;
this.destination.depArrTime = newDatetime.toISOString();
}
setDepartureDatetime(newDatetime = /* @__PURE__ */ new Date()) {
delete this.destination.depArrTime;
this.origin.depArrTime = newDatetime.toISOString();
}
buildRequestXML(language, requestorRef, xmlConfig = DefaultXML_Config) {
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp: this.requestTimestamp,
requestorRef,
OJPTripRequest: this
}
}
};
const xmlS = buildRootXML(requestOJP, xmlConfig);
return xmlS;
}
};
var LocationInformationRequest = class _LocationInformationRequest extends BaseRequest {
requestTimestamp;
initialInput;
placeRef;
restrictions;
constructor(initialInput, placeRef, restrictions) {
super();
const now = /* @__PURE__ */ new Date();
this.requestTimestamp = now.toISOString();
this.initialInput = initialInput;
this.placeRef = placeRef;
this.restrictions = restrictions;
}
static DefaultRequestParams() {
const params = {
type: [],
numberOfResults: 10
};
return params;
}
static Default() {
const request = new _LocationInformationRequest(void 0, void 0, void 0);
request.restrictions = _LocationInformationRequest.DefaultRequestParams();
return request;
}
static initWithRequestMock(mockText) {
const request = _LocationInformationRequest.Default();
request.mockRequestXML = mockText;
return request;
}
static initWithResponseMock(mockText) {
const request = _LocationInformationRequest.Default();
request.mockResponseXML = mockText;
return request;
}
static initWithLocationName(name) {
const request = _LocationInformationRequest.Default();
request.initialInput = {
name
};
return request;
}
static initWithPlaceRef(placeRefOrCoords) {
const request = _LocationInformationRequest.Default();
request.placeRef = PlaceRef.initWithPlaceRefsOrCoords(placeRefOrCoords);
return request;
}
static initWithBBOX(bboxData, placeType, numberOfResults = 10) {
const bboxDataParts = (() => {
if (Array.isArray(bboxData)) {
return bboxData;
}
return bboxData.split(",").map((el) => Number(el));
})();
const request = _LocationInformationRequest.Default();
if (bboxDataParts.length !== 4) {
debugger;
return request;
}
const longMin = bboxDataParts[0];
const latMin = bboxDataParts[1];
const longMax = bboxDataParts[2];
const latMax = bboxDataParts[3];
request.initialInput = {
geoRestriction: {
rectangle: {
upperLeft: {
longitude: longMin,
latitude: latMax
},
lowerRight: {
longitude: longMax,
latitude: latMin
}
}
}
};
request.restrictions = {
type: placeType,
numberOfResults
};
return request;
}
buildRequestXML(language, requestorRef, xmlConfig) {
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp: this.requestTimestamp,
requestorRef,
OJPLocationInformationRequest: this
}
}
};
const xmlS = buildRootXML(requestOJP, xmlConfig);
return xmlS;
}
};
var StopEventRequest = class _StopEventRequest extends BaseRequest {
requestTimestamp;
location;
params;
constructor(location, params = void 0) {
super();
const now = /* @__PURE__ */ new Date();
this.requestTimestamp = now.toISOString();
this.location = location;
this.params = params;
}
static DefaultRequestParams() {
const params = {
includeAllRestrictedLines: true,
numberOfResults: 10,
stopEventType: "departure",
includePreviousCalls: true,
includeOnwardCalls: true,
useRealtimeData: "explanatory"
};
return params;
}
static Default() {
const date = /* @__PURE__ */ new Date();
const location = {
placeRef: {
stopPointRef: "8507000",
name: {
text: "n/a"
}
},
depArrTime: date.toISOString()
};
const requestParams = _StopEventRequest.DefaultRequestParams();
const request = new _StopEventRequest(location, requestParams);
return request;
}
static initWithRequestMock(mockText) {
const request = _StopEventRequest.Default();
request.mockRequestXML = mockText;
return request;
}
static initWithResponseMock(mockText) {
const request = _StopEventRequest.Default();
request.mockResponseXML = mockText;
return request;
}
static initWithPlaceRefAndDate(placeRefS, date = /* @__PURE__ */ new Date()) {
const location = {
placeRef: {
stopPointRef: placeRefS,
name: {
text: "n/a"
}
},
depArrTime: date.toISOString()
};
const params = _StopEventRequest.DefaultRequestParams();
const request = new _StopEventRequest(location, params);
return request;
}
buildRequestXML(language, requestorRef, xmlConfig) {
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp: this.requestTimestamp,
requestorRef,
OJPStopEventRequest: this
}
}
};
const xmlS = buildRootXML(requestOJP, xmlConfig);
return xmlS;
}
};
var TripRefineRequest = class _TripRefineRequest extends BaseRequest {
requestTimestamp;
refineParams;
tripResult;
constructor(tripResult, refineParams) {
super();
const now = /* @__PURE__ */ new Date();
this.requestTimestamp = now.toISOString();
this.refineParams = refineParams;
this.tripResult = tripResult;
}
static DefaultRequestParams() {
const params = {
numberOfResults: void 0,
useRealtimeData: "explanatory",
includeAllRestrictedLines: true,
includeIntermediateStops: true
};
return params;
}
static Default() {
const fakeTripResult = {};
const params = _TripRefineRequest.DefaultRequestParams();
const request = new _TripRefineRequest(fakeTripResult, params);
return request;
}
static initWithRequestMock(mockText) {
const request = _TripRefineRequest.Default();
request.mockRequestXML = mockText;
return request;
}
static initWithResponseMock(mockText) {
const request = _TripRefineRequest.Default();
request.mockResponseXML = mockText;
return request;
}
static initWithTrip(trip) {
const tripResult = {
id: trip.id,
trip
};
const params = _TripRefineRequest.DefaultRequestParams();
const request = new _TripRefineRequest(tripResult, params);
return request;
}
buildRequestXML(language, requestorRef, xmlConfig) {
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp: this.requestTimestamp,
requestorRef,
OJPTripRefineRequest: this
}
}
};
const xmlS = buildRootXML(requestOJP, xmlConfig);
return xmlS;
}
};
var FareRequest = class _FareRequest extends BaseRequest {
requestTimestamp;
itemsWrapper;
constructor(requestTimestamp, items) {
super();
this.requestTimestamp = requestTimestamp;
this.itemsWrapper = items;
}
static DefaultRequestParams() {
const params = {
fareAuthorityFilter: ["ch:1:NOVA"],
passengerCategory: ["Adult"],
travelClass: "second",
traveller: [
{
age: 25,
passengerCategory: "Adult",
entitlementProducts: {
entitlementProduct: [
{
fareAuthorityRef: "ch:1:NOVA",
entitlementProductRef: "HTA",
entitlementProductName: "Halbtax-Abonnement"
}
]
}
}
]
};
return params;
}
static Default() {
const now = /* @__PURE__ */ new Date();
const requestTimestamp = now.toISOString();
const request = new _FareRequest(requestTimestamp, []);
return request;
}
static initWithRequestMock(mockText) {
const request = _FareRequest.Default();
request.mockRequestXML = mockText;
return request;
}
static initWithResponseMock(mockText) {
const request = _FareRequest.Default();
request.mockResponseXML = mockText;
return request;
}
static initWithOJPv1Trips(trips) {
trips.map((tripV1) => {
OJPv1_Helpers.cleanTripForFareRequest(tripV1);
});
const now = /* @__PURE__ */ new Date();
const requestTimestamp = now.toISOString();
const fareRequests = [];
trips.forEach((trip) => {
const fareRequest = {
requestTimestamp,
tripFareRequest: {
trip
},
params: _FareRequest.DefaultRequestParams()
};
fareRequests.push(fareRequest);
});
const request = new _FareRequest(requestTimestamp, fareRequests);
return request;
}
static initWithOJPv2Trips(trips) {
const newTrips = [];
trips.forEach((trip) => {
const tripV1 = OJPv1_Helpers.convertOJPv2Trip_to_v1Trip(trip);
newTrips.push(tripV1);
});
const request = _FareRequest.initWithOJPv1Trips(newTrips);
return request;
}
buildRequestXML(language, requestorRef, xmlConfig = DefaultXML_Config) {
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp: this.requestTimestamp,
requestorRef,
OJPFareRequest: this.itemsWrapper
}
}
};
if (xmlConfig.ojpVersion !== "1.0") {
console.error("FareRequest.buildRequestXML() error - v1 XML_Config is missing");
}
const xmlS = buildRootXML(requestOJP, xmlConfig, (objTransformed) => {
const siriPrefix = xmlConfig.defaultNS !== "siri" ? "siri:" : "";
const ojpPrefix = xmlConfig.defaultNS !== "ojp" ? "ojp:" : "";
const fareRequests = objTransformed[siriPrefix + "OJPRequest"][siriPrefix + "ServiceRequest"][ojpPrefix + "OJPFareRequest"];
fareRequests.forEach((fareRequest) => {
const trip = fareRequest[ojpPrefix + "TripFareRequest"][ojpPrefix + "Trip"];
trip[ojpPrefix + "TripLeg"].forEach((leg) => {
if (ojpPrefix + "TimedLeg" in leg) {
const service = leg[ojpPrefix + "TimedLeg"][ojpPrefix + "Service"];
service[ojpPrefix + "OperatorRef"] = "ojp:" + service[siriPrefix + "OperatorRef"];
delete service[siriPrefix + "OperatorRef"];
}
});
});
});
return xmlS;
}
};
var TripInfoRequest = class _TripInfoRequest extends BaseRequest {
requestTimestamp;
journeyRef;
operatingDayRef;
params;
constructor(journeyRef, operatingDayRef, params) {
super();
const now = /* @__PURE__ */ new Date();
this.requestTimestamp = now.toISOString();
this.journeyRef = journeyRef;
this.operatingDayRef = operatingDayRef;
this.params = params;
}
static DefaultRequestParams() {
const params = {
includeCalls: true,
includeService: true,
includeTrackProjection: false,
includePlacesContext: true,
includeSituationsContext: true
};
return params;
}
static Default() {
const request = new _TripInfoRequest("n/a", "n/a", _TripInfoRequest.DefaultRequestParams());
return request;
}
static initWithRequestMock(mockText) {
const request = _TripInfoRequest.Default();
request.mockRequestXML = mockText;
return request;
}
static initWithResponseMock(mockText) {
const request = _TripInfoRequest.Default();
request.mockResponseXML = mockText;
return request;
}
static initWithJourneyRef(journeyRef, journeyDate = /* @__PURE__ */ new Date()) {
const operatingDayRef = DateHelpers.formatDate(journeyDate).substring(0, 10);
const params = _TripInfoRequest.DefaultRequestParams();
const request = new _TripInfoRequest(journeyRef, operatingDayRef, params);
return request;
}
buildRequestXML(language, requestorRef, xmlConfig) {
if (xmlConfig.ojpVersion === "1.0") {
this.patchV1();
}
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp: this.requestTimestamp,
requestorRef,
OJPTripInfoRequest: this
}
}
};
const xmlS = buildRootXML(requestOJP, xmlConfig);
return xmlS;
}
enableTrackProjection() {
if (this.params) {
this.params.includeTrackProjection = true;
}
}
// disable params that are not available on v1
patchV1() {
if (this.params) {
this.params.includeSituationsContext = void 0;
}
}
};
// src/models/xml-serializer.ts
var XmlSerializer = class {
xmlConfig;
constructor(xmlConfig = DefaultXML_Config) {
this.xmlConfig = xmlConfig;
}
serialize(obj, wrapperNodeName) {
const xml = buildXML(obj, wrapperNodeName, this.xmlConfig);
return xml;
}
};
// src/sdk.ts
import axios, { AxiosHeaders } from "axios";
var SDK = class {
requestorRef;
httpConfig;
language;
xmlConfig;
constructor(requestorRef, httpConfig, language, xmlConfig = DefaultXML_Config) {
this.requestorRef = requestorRef;
this.httpConfig = httpConfig;
this.language = language;
this.xmlConfig = xmlConfig;
}
async computeResponse(request) {
const requestXML = (() => {
if (request.mockRequestXML) {
return request.mockRequestXML;
}
const xml = request.buildRequestXML(this.language, this.requestorRef, this.xmlConfig);
return xml;
})();
request.requestInfo.requestDateTime = /* @__PURE__ */ new Date();
request.requestInfo.requestXML = requestXML;
const responseXML = await (async () => {
if (request.mockResponseXML) {
return request.mockResponseXML;
}
const xml = await this.fetchResponse(requestXML);
return xml;
})();
request.requestInfo.responseDateTime = /* @__PURE__ */ new Date();
request.requestInfo.responseXML = responseXML;
return responseXML;
}
async fetchResponse(requestXML) {
const headers = new AxiosHeaders();
headers.set("Accept", "application/xml");
headers.set("Content-Type", "application/xml");
if (this.httpConfig.authToken !== null) {
headers.set("Authorization", "Bearer " + this.httpConfig.authToken);
}
const requestConfig = {
method: "POST",
url: this.httpConfig.url,
headers
};
if (this.httpConfig.url.startsWith("http://localhost")) {
requestConfig.method = "GET";
}
if (requestConfig.method === "POST") {
requestConfig.data = requestXML;
}
const response = await axios.request(requestConfig);
const responseXML = response.data;
return responseXML;
}
async fetchTripRequestResponse(request) {
const responseXML = await this.computeResponse(request);
try {
const parsedObj = parseXML(responseXML, "OJP");
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPTripDelivery;
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
async fetchLocationInformationRequestResponse(request) {
const responseXML = await this.computeResponse(request);
try {
const parsedObj = parseXML(responseXML, "OJP");
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPLocationInformationDelivery;
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
async fetchStopEventRequestResponse(request) {
const responseXML = await this.computeResponse(request);
try {
const parsedObj = parseXML(responseXML, "OJP");
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPStopEventDelivery;
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
async fetchTripRefineRequestResponse(request) {
const responseXML = await this.computeResponse(request);
try {
const parsedObj = parseXML(responseXML, "OJP");
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPTripRefineDelivery;
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
async fetchTripInfoRequestResponse(request) {
const responseXML = await this.computeResponse(request);
try {
const parsedObj = parseXML(responseXML, "OJP");
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPTripInfoDelivery;
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
async fetchFareRequestResponse(request) {
const responseXML = await this.computeResponse(request);
try {
const parsedObj = parseXML(responseXML, "OJP");
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPFareDelivery;
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
// Deprecated methods below
async fetchTrips(tripRequest) {
console.log("WARNING: deprecated method, it might be removed at a later version, use fetchTripRequestResponse() instead");
const responseXML = await this.computeResponse(tripRequest);
const ojpPrefix = this.xmlConfig.defaultNS === "ojp" ? "" : "ojp:";
const tripPattern = "<" + ojpPrefix + "Trip\\b[^>]*>.*?<\\/" + ojpPrefix + "Trip>";
const tripRegexp = new RegExp(tripPattern, "gs");
const tripMatches = responseXML.match(tripRegexp) ?? [];
const trips = [];
tripMatches.forEach((tripXML, idx1) => {
const trip = Trip.initWithTripXML(tripXML);
trips.push(trip);
});
tripRequest.requestInfo.parseDateTime = /* @__PURE__ */ new Date();
return trips;
}
async fetchPlaceResults(lirRequest) {
console.log("WARNING: deprecated method, it might be removed at a later version, use fetchLocationInformationRequestResponse() instead");
const responseXML = await this.computeResponse(lirRequest);
const placeResultMatches = responseXML.match(/<PlaceResult\b[^>]*>.*?<\/PlaceResult>/gs) ?? [];
const placeResults = [];
placeResultMatches.forEach((nodeXML, idx1) => {
const placeResult = PlaceResult.initWithXML(nodeXML);
placeResults.push(placeResult);
});
lirRequest.requestInfo.parseDateTime = /* @__PURE__ */ new Date();
return placeResults;
}
async fetchStopEvents(request) {
console.log("WARNING: deprecated method, it might be removed at a later version, use fetchStopEventRequestResponse() instead");
const responseXML = await this.computeResponse(request);
const resultMatches = responseXML.match(/<StopEventResult\b[^>]*>.*?<\/StopEventResult>/gs) ?? [];
const results = [];
resultMatches.forEach((nodeXML, idx1) => {
const result = StopEventResult.initWithXML(nodeXML);
results.push(result);
});
request.requestInfo.parseDateTime = /* @__PURE__ */ new Date();
return results;
}
async fetchTRR_Trips(request) {
console.log("WARNING: deprecated method, it might be removed at a later version, use fetchTripRefineRequestResponse() instead");
const responseXML = await this.computeResponse(request);
const tripMatches = responseXML.match(/<Trip\b[^>]*>.*?<\/Trip>/gs) ?? [];
const trips = [];
tripMatches.forEach((tripXML, idx1) => {
const trip = Trip.initWithTripXML(tripXML);
trips.push(trip);
});
request.requestInfo.parseDateTime = /* @__PURE__ */ new Date();
return trips;
}
};
export {
DateHelpers,
FareRequest,
GeoPosition,
LocationInformationRequest,
Place,
PlaceResult,
SDK,
SDK_VERSION,
StopEventRequest,
StopEventResult,
Trip,
TripInfoRequest,
TripRefineRequest,
TripRequest,
XmlSerializer
};