UNPKG

ojp-sdk-next

Version:

OJP (Open Journey Planner) Javascript SDK

1,433 lines (1,422 loc) 45.2 kB
// 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 };