ojp-sdk-next
Version:
OJP (Open Journey Planner) Javascript SDK
1,578 lines (1,557 loc) • 63.8 kB
JavaScript
// src/helpers/xml/builder.ts
import * as OJP_Types from "ojp-shared-types";
import { XMLBuilder } from "fast-xml-parser";
// src/constants.ts
var SDK_VERSION = "0.21.4";
var mapNS = {
"ojp": "http://www.vdv.de/ojp",
"siri": "http://www.siri.org.uk/siri"
};
var DefaultXML_Config = {
ojpVersion: "2.0",
defaultNS: "ojp",
mapNS
};
var XML_BuilderConfigOJPv1 = {
ojpVersion: "1.0",
defaultNS: "siri",
mapNS
};
var XML_ParserConfigOJPv1 = {
ojpVersion: "1.0",
defaultNS: "ojp",
mapNS
};
// 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 parentKey = path.at(-1) ?? null;
if (parentKey !== null) {
const tagNS_Key = parentKey.replace(/^.*:/, "") + "." + newKey;
const tagNS = (() => {
const tagNSConfig = OJP_Types.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/xml/parser.ts
import * as OJP_Types2 from "ojp-shared-types";
import { XMLParser } from "fast-xml-parser";
// 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;
}
static transformTagName(tagName) {
if (tagName.startsWith("OJP")) {
return tagName;
}
if (tagName.toUpperCase() === tagName) {
return tagName;
}
let newTagName = tagName.replace(/[-_](.)/g, (_, char) => char.toUpperCase());
newTagName = newTagName.replace(/^([A-Z])/, (match) => match.toLowerCase());
return newTagName;
}
};
// src/helpers/xml/parser.ts
var mapArrayTags = Object.assign({}, OJP_Types2.OpenAPI_Dependencies.MapArrayTags);
var mapLegacyArrayTags = Object.assign({}, OJP_Types2.OpenAPI_Dependencies.MapArrayTags);
for (const key in OJP_Types2.OpenAPI_Dependencies.MapLegacyArrayTags) {
mapLegacyArrayTags[key] = OJP_Types2.OpenAPI_Dependencies.MapLegacyArrayTags[key];
}
function computeMapParentArrayTags(mapArrayTags2) {
const mapParentArrayTags = {};
for (const key in mapArrayTags2) {
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);
}
return mapParentArrayTags;
}
var MapParentArrayTags = computeMapParentArrayTags(mapArrayTags);
var MapLegacyParentArrayTags = computeMapParentArrayTags(mapLegacyArrayTags);
function transformJsonInPlace(root, ojpVersion) {
const hashTextKey = "#text";
const isOJP_v2 = ojpVersion === "2.0";
const mapParentArrayTags = isOJP_v2 ? MapParentArrayTags : MapLegacyParentArrayTags;
function isHashKeyObject(v) {
if (typeof v !== "object") {
return false;
}
if (Array.isArray(v)) {
return false;
}
const hasKey = hashTextKey in v;
return hasKey;
}
function normalizeValue(value, path) {
if (path.length < 2) {
return value;
}
const pathSuffix = path.slice(-2).join(".");
if (pathSuffix in OJP_Types2.OpenAPI_Dependencies.MapStringValues && typeof value !== "string") {
return String(value);
}
return value;
}
function visit(node, path) {
const currentNodeKey = path.at(-1);
if (Array.isArray(node)) {
for (let i = 0; i < node.length; i++) {
visit(node[i], path);
}
return;
}
if (node && typeof node === "object") {
const rec = node;
const keys = Object.keys(rec);
for (const key of keys) {
let value = rec[key];
const valuePath = [...path, key];
if (isHashKeyObject(value)) {
const inner = value;
rec[key] = inner[hashTextKey];
for (const innerKey of Object.keys(inner)) {
if (innerKey === hashTextKey) {
continue;
}
const flatKey = `${key}.${innerKey}`;
rec[flatKey] = inner[innerKey];
}
continue;
}
if (Array.isArray(value) && value.length > 0 && value.every(isHashKeyObject)) {
const arr = value;
const basePath = valuePath;
rec[key] = arr.map((o) => normalizeValue(o[hashTextKey], basePath));
const extraKeys = /* @__PURE__ */ new Set();
for (const o of arr) {
for (const k of Object.keys(o)) {
if (k !== hashTextKey) {
extraKeys.add(k);
}
}
}
for (const extraKey of extraKeys) {
const flatKey = `${key}.${extraKey}`;
rec[flatKey] = arr.map((o) => o[extraKey]);
}
continue;
}
value = normalizeValue(value, valuePath);
rec[key] = value;
visit(value, valuePath);
}
if (currentNodeKey !== void 0) {
const expectedPropAsArray = mapParentArrayTags[currentNodeKey] ?? [];
expectedPropAsArray.forEach((prop) => {
if (!(prop in rec)) {
rec[prop] = [];
}
});
}
}
}
visit(root, []);
}
var transformTagNameHandler = (tagName) => {
return XmlSerializer.transformTagName(tagName);
};
var isArrayHandler = (tagName, jPath, ojpVersion) => {
const isOJP_v2 = ojpVersion === "2.0";
const targetMapArrayTags = isOJP_v2 ? mapArrayTags : mapLegacyArrayTags;
const jPathParts = jPath.split(".");
if (jPathParts.length >= 2) {
const pathPart = jPathParts.slice(-2).join(".");
if (pathPart in targetMapArrayTags) {
return true;
}
}
return false;
};
function parseXML(xml, ojpVersion) {
const parser = new XMLParser({
ignoreAttributes: false,
removeNSPrefix: true,
transformTagName: transformTagNameHandler,
isArray: (tagName, jPath) => {
return isArrayHandler(tagName, jPath, ojpVersion);
}
// parseTagValue: false,
});
const response = parser.parse(xml);
transformJsonInPlace(response, ojpVersion);
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;
}
asGeoPositionSchema() {
const schema = {
longitude: this.longitude,
latitude: this.latitude
};
return schema;
}
};
// 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;
}
}
asOJPv1Schema() {
const legacyPlaceRef = {
stopPointRef: this.stopPointRef,
stopPlaceRef: this.stopPlaceRef,
geoPosition: this.geoPosition,
locationName: this.name
};
return legacyPlaceRef;
}
};
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, "2.0");
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;
attribute;
placeType;
constructor(stopPoint, stopPlace, topographicPlace, pointOfInterest, address, name, geoPosition, mode, attribute) {
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.attribute = attribute;
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, placeSchema.attribute);
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, "2.0");
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, "2.0");
const result = new _StopEventResult(parsedObj.stopEventResult.id, parsedObj.stopEventResult.stopEvent);
return result;
}
};
// src/helpers/request-helpers.ts
import axios, { AxiosHeaders } from "axios";
var RequestHelpers = class _RequestHelpers {
static computeRequestTimestamp() {
const now = /* @__PURE__ */ new Date();
const requestTimestamp = now.toISOString();
return requestTimestamp;
}
static async computeResponse(request, sdk, xmlConfig) {
const requestXML = (() => {
if (request.mockRequestXML) {
return request.mockRequestXML;
}
const xml = request.buildRequestXML(sdk.language, sdk.requestorRef, 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 _RequestHelpers.fetchResponseXML(requestXML, sdk.httpConfig);
return xml;
})();
request.requestInfo.responseDateTime = /* @__PURE__ */ new Date();
request.requestInfo.responseXML = responseXML;
return responseXML;
}
static async fetchResponseXML(requestXML, httpConfig) {
const headers = new AxiosHeaders();
headers.set("Accept", "application/xml");
headers.set("Content-Type", "application/xml");
if (httpConfig.authToken !== null) {
headers.set("Authorization", "Bearer " + httpConfig.authToken);
}
const requestConfig = {
method: "POST",
url: httpConfig.url,
headers
};
if (requestConfig.method === "POST") {
requestConfig.data = requestXML;
}
const response = await axios.request(requestConfig);
const responseXML = response.data;
return responseXML;
}
};
// src/versions/current/requests/base.ts
var BaseRequest = class {
requestInfo;
mockRequestXML;
mockResponseXML;
constructor() {
const now = /* @__PURE__ */ new Date();
this.requestInfo = {
requestDateTime: null,
requestXML: null,
responseDateTime: null,
responseXML: null,
parseDateTime: null
};
this.mockRequestXML = null;
this.mockResponseXML = null;
}
static initWithRequestMock(mockText) {
const instance = this.Default();
instance.mockRequestXML = mockText;
return instance;
}
static initWithResponseMock(mockText) {
const instance = this.Default();
instance.mockResponseXML = mockText;
return instance;
}
async fetchResponse(sdk) {
const response = await this._fetchResponse(sdk);
return response;
}
};
// src/versions/current/requests/lir.shared.ts
var SharedLocationInformationRequest = class extends BaseRequest {
static DefaultRestrictionParams() {
const restrictionParams = {
type: [],
numberOfResults: void 0,
modes: void 0,
includePtModes: true
};
return restrictionParams;
}
updateRestrictions(restrictions, placeTypes, numberOfResults) {
if (placeTypes.length > 0) {
restrictions.type = placeTypes;
}
if (numberOfResults !== null) {
restrictions.numberOfResults = numberOfResults;
}
}
static computeGeoRestriction(bboxData) {
const bboxDataParts = (() => {
if (Array.isArray(bboxData)) {
return bboxData;
}
return bboxData.split(",").map((el) => Number(el));
})();
if (bboxDataParts.length !== 4) {
return null;
}
const minLongitude = bboxDataParts[0];
const minLatitude = bboxDataParts[1];
const maxLongitude = bboxDataParts[2];
const maxLatitude = bboxDataParts[3];
const geoRestrictionsSchema = {
rectangle: {
upperLeft: {
longitude: minLongitude,
latitude: maxLatitude
},
lowerRight: {
longitude: maxLongitude,
latitude: minLatitude
}
}
};
return geoRestrictionsSchema;
}
};
// src/versions/current/requests/lir.ts
var LocationInformationRequest = class _LocationInformationRequest extends SharedLocationInformationRequest {
payload;
constructor(restrictions) {
super();
this.payload = {
requestTimestamp: RequestHelpers.computeRequestTimestamp(),
initialInput: void 0,
placeRef: void 0,
restrictions
};
}
static Default() {
const restrictions = SharedLocationInformationRequest.DefaultRestrictionParams();
const request = new _LocationInformationRequest(restrictions);
return request;
}
static initWithLocationName(name, placeTypes = [], numberOfResults = 10) {
const request = _LocationInformationRequest.Default();
request.payload.initialInput = {
name
};
if (request.payload.restrictions) {
request.updateRestrictions(request.payload.restrictions, placeTypes, numberOfResults);
}
return request;
}
static initWithPlaceRef(placeRefOrCoords, numberOfResults = 10) {
const request = _LocationInformationRequest.Default();
request.payload.placeRef = PlaceRef.initWithPlaceRefsOrCoords(placeRefOrCoords);
if (request.payload.restrictions) {
request.updateRestrictions(request.payload.restrictions, ["stop"], numberOfResults);
}
return request;
}
static initWithBBOX(bboxData, placeTypes = [], numberOfResults = 10) {
const request = _LocationInformationRequest.Default();
const geoRestriction = this.computeGeoRestriction(bboxData);
if (geoRestriction) {
request.payload.initialInput = {
name: void 0,
geoRestriction
};
}
if (request.payload.restrictions) {
request.updateRestrictions(request.payload.restrictions, placeTypes, numberOfResults);
}
return request;
}
buildRequestXML(language, requestorRef, xmlConfig) {
this.payload.requestTimestamp = RequestHelpers.computeRequestTimestamp();
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp: this.payload.requestTimestamp,
requestorRef,
OJPLocationInformationRequest: this.payload
}
}
};
const xmlS = buildRootXML(requestOJP, xmlConfig);
return xmlS;
}
async _fetchResponse(sdk) {
const xmlConfig = sdk.version === "2.0" ? DefaultXML_Config : XML_BuilderConfigOJPv1;
const responseXML = await RequestHelpers.computeResponse(this, sdk, xmlConfig);
try {
const parsedObj = parseXML(responseXML, sdk.version);
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPLocationInformationDelivery;
if (response === void 0) {
console.log(responseXML);
throw new Error("Parse error");
}
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
};
// src/versions/current/requests/ser.shared.ts
var SharedStopEventRequest = class extends BaseRequest {
static DefaultRequestParams(version = "2.0") {
const params = {
includeAllRestrictedLines: void 0,
// this works only with OJP v2
numberOfResults: 10,
stopEventType: "departure",
includePreviousCalls: true,
includeOnwardCalls: true,
useRealtimeData: "explanatory"
};
if (version === "2.0") {
params.includeAllRestrictedLines = true;
}
return params;
}
};
// src/versions/current/requests/ser.ts
var StopEventRequest = class _StopEventRequest extends SharedStopEventRequest {
payload;
constructor(location, params = void 0) {
super();
this.payload = {
requestTimestamp: RequestHelpers.computeRequestTimestamp(),
location,
params
};
}
// Used by Base.initWithRequestMock / initWithResponseMock
static Default() {
const date = /* @__PURE__ */ new Date();
const location = {
placeRef: {
stopPointRef: "8507000",
name: {
text: "n/a"
}
},
depArrTime: date.toISOString()
};
const requestParams = SharedStopEventRequest.DefaultRequestParams();
const request = new _StopEventRequest(location, requestParams);
return request;
}
static initWithPlaceRefAndDate(placeRefS, date = /* @__PURE__ */ new Date()) {
const location = {
placeRef: {
stopPointRef: placeRefS,
name: {
text: "n/a"
}
},
depArrTime: date.toISOString()
};
const params = SharedStopEventRequest.DefaultRequestParams();
const request = new _StopEventRequest(location, params);
return request;
}
buildRequestXML(language, requestorRef, xmlConfig) {
this.payload.requestTimestamp = RequestHelpers.computeRequestTimestamp();
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp: this.payload.requestTimestamp,
requestorRef,
OJPStopEventRequest: this.payload
}
}
};
const xmlS = buildRootXML(requestOJP, xmlConfig);
return xmlS;
}
async _fetchResponse(sdk) {
const xmlConfig = sdk.version === "2.0" ? DefaultXML_Config : XML_BuilderConfigOJPv1;
const responseXML = await RequestHelpers.computeResponse(this, sdk, xmlConfig);
try {
const parsedObj = parseXML(responseXML, sdk.version);
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPStopEventDelivery;
if (response === void 0) {
console.log(responseXML);
throw new Error("Parse error");
}
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
};
// 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/versions/current/requests/tir.shared.ts
var SharedTripInfoRequest = class extends BaseRequest {
static DefaultRequestParams() {
const params = {
includeCalls: true,
includeService: true,
includeTrackProjection: false,
includePlacesContext: true,
includeSituationsContext: true
};
return params;
}
};
// src/versions/current/requests/tir.ts
var TripInfoRequest = class _TripInfoRequest extends SharedTripInfoRequest {
payload;
constructor(journeyRef, operatingDayRef, params) {
super();
this.payload = {
requestTimestamp: RequestHelpers.computeRequestTimestamp(),
journeyRef,
operatingDayRef,
params
};
}
// Used by Base.initWithRequestMock / initWithResponseMock
static Default() {
const request = new _TripInfoRequest("n/a", "n/a", SharedTripInfoRequest.DefaultRequestParams());
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;
}
enableTrackProjection() {
if (this.payload.params) {
this.payload.params.includeTrackProjection = true;
}
}
buildRequestXML(language, requestorRef, xmlConfig) {
this.payload.requestTimestamp = RequestHelpers.computeRequestTimestamp();
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp: this.payload.requestTimestamp,
requestorRef,
OJPTripInfoRequest: this.payload
}
}
};
const xmlS = buildRootXML(requestOJP, xmlConfig);
return xmlS;
}
async _fetchResponse(sdk) {
const xmlConfig = sdk.version === "2.0" ? DefaultXML_Config : XML_BuilderConfigOJPv1;
const responseXML = await RequestHelpers.computeResponse(this, sdk, xmlConfig);
try {
const parsedObj = parseXML(responseXML, sdk.version);
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPTripInfoDelivery;
if (response === void 0) {
console.log(responseXML);
throw new Error("Parse error");
}
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
};
// src/versions/current/requests/trr.ts
var TripRefineRequest = class _TripRefineRequest extends BaseRequest {
payload;
constructor(tripResult, refineParams) {
super();
this.payload = {
requestTimestamp: RequestHelpers.computeRequestTimestamp(),
refineParams,
tripResult
};
}
static DefaultRequestParams() {
const params = {
includeLegProjection: true,
includeTurnDescription: true,
includeIntermediateStops: true
};
return params;
}
// Used by Base.initWithRequestMock / initWithResponseMock
static Default() {
const fakeTripResult = {};
const params = _TripRefineRequest.DefaultRequestParams();
const request = new _TripRefineRequest(fakeTripResult, params);
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) {
this.payload.requestTimestamp = RequestHelpers.computeRequestTimestamp();
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp: this.payload.requestTimestamp,
requestorRef,
OJPTripRefineRequest: this.payload
}
}
};
const xmlS = buildRootXML(requestOJP, xmlConfig);
return xmlS;
}
async _fetchResponse(sdk) {
const xmlConfig = sdk.version === "2.0" ? DefaultXML_Config : XML_BuilderConfigOJPv1;
const responseXML = await RequestHelpers.computeResponse(this, sdk, xmlConfig);
try {
const parsedObj = parseXML(responseXML, sdk.version);
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPTripRefineDelivery;
if (response === void 0) {
console.log(responseXML);
throw new Error("Parse error");
}
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
};
// src/versions/current/requests/tr.shared.ts
var SharedTripRequest = class extends BaseRequest {
};
// src/versions/current/requests/tr.ts
var TripRequest = class _TripRequest extends SharedTripRequest {
payload;
constructor(origin, destination, via = [], params = null) {
super();
this.payload = {
requestTimestamp: RequestHelpers.computeRequestTimestamp(),
origin,
destination,
via,
params: params ??= {}
};
}
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;
}
// Used by Base.initWithRequestMock / initWithResponseMock
static Default() {
const date = /* @__PURE__ */ new Date();
const origin = {
placeRef: PlaceRef.initWithPlaceRefsOrCoords("8503000", "Z\xFCrich"),
depArrTime: date.toISOString(),
individualTransportOption: []
};
const destination = {
placeRef: PlaceRef.initWithPlaceRefsOrCoords("8507000", "Bern"),
individualTransportOption: []
};
const params = _TripRequest.DefaultRequestParams();
const request = new _TripRequest(origin, destination, [], params);
return request;
}
static initWithPlaceRefsOrCoords(originPlaceRefS, destinationPlaceRefS) {
const origin = {
placeRef: PlaceRef.initWithPlaceRefsOrCoords(originPlaceRefS),
individualTransportOption: []
};
const destination = {
placeRef: PlaceRef.initWithPlaceRefsOrCoords(destinationPlaceRefS),
individualTransportOption: []
};
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.payload.origin.depArrTime;
this.payload.destination.depArrTime = newDatetime.toISOString();
}
setDepartureDatetime(newDatetime = /* @__PURE__ */ new Date()) {
delete this.payload.destination.depArrTime;
this.payload.origin.depArrTime = newDatetime.toISOString();
}
setPublicTransportRequest(motFilter = null) {
if (!this.payload.params) {
return;
}
this.payload.params.modeAndModeOfOperationFilter = void 0;
if (motFilter !== null && motFilter.length > 0) {
this.payload.params.modeAndModeOfOperationFilter = [
{
exclude: false,
ptMode: motFilter,
personalMode: []
}
];
}
}
disableLinkProkection() {
if (!this.payload.params) {
return;
}
this.payload.params.includeLegProjection = false;
}
enableLinkProkection() {
if (!this.payload.params) {
return;
}
this.payload.params.includeLegProjection = true;
}
setCarRequest() {
if (!this.payload.params) {
return;
}
this.payload.params.numberOfResults = 0;
this.payload.params.modeAndModeOfOperationFilter = [
{
ptMode: [],
personalMode: [],
railSubmode: "vehicleTunnelTransportRailService",
waterSubmode: "localCarFerry"
}
];
}
setMaxDurationWalkingTime(maxDurationMinutes = void 0, endpointType = "both") {
if (!maxDurationMinutes) {
maxDurationMinutes = 30;
}
const maxDuration = "PT" + maxDurationMinutes + "M";
const individualTransportOption = {
maxDuration,
itModeAndModeOfOperation: {
personalMode: "foot",
personalModeOfOperation: ["own"]
}
};
if (endpointType === "origin" || endpointType === "both") {
this.payload.origin.individualTransportOption = [individualTransportOption];
}
if (endpointType === "destination" || endpointType === "both") {
this.payload.destination.individualTransportOption = [individualTransportOption];
}
}
// https://vdvde.github.io/OJP/develop/documentation-tables/siri.html#type_siri__RailSubmodesOfTransportEnumeration
setRailSubmodes(railSubmodes) {
if (!Array.isArray(railSubmodes)) {
railSubmodes = [railSubmodes];
}
if (!this.payload.params) {
return;
}
this.payload.params.modeAndModeOfOperationFilter = [];
const modeFilters = [];
railSubmodes.forEach((railSubmode) => {
const modeFilter = {
exclude: false,
ptMode: [],
personalMode: [],
railSubmode
};
modeFilters.push(modeFilter);
});
this.payload.params.modeAndModeOfOperationFilter = modeFilters;
}
setNumberOfResults(resultsNo) {
if (!this.payload.params) {
return;
}
this.payload.params.numberOfResults = resultsNo ?? void 0;
}
setNumberOfResultsAfter(resultsNo) {
if (!this.payload.params) {
return;
}
this.payload.params.numberOfResultsAfter = resultsNo;
}
setNumberOfResultsBefore(resultsNo) {
if (!this.payload.params) {
return;
}
this.payload.params.numberOfResultsBefore = resultsNo;
}
setEndpointDurationDistanceRestrictions(placeContext, minDuration, maxDuration, minDistance, maxDistance) {
if (minDuration === null && maxDuration === null && minDistance === null && maxDistance === null) {
return;
}
const transportOption = {
itModeAndModeOfOperation: {
personalMode: "foot",
personalModeOfOperation: ["own"]
}
};
if (minDuration !== null) {
transportOption.minDuration = "PT" + minDuration + "M";
}
if (maxDuration !== null) {
transportOption.maxDuration = "PT" + maxDuration + "M";
}
if (minDistance !== null) {
transportOption.minDistance = minDistance;
}
if (maxDistance !== null) {
transportOption.maxDistance = maxDistance;
}
placeContext.individualTransportOption = [transportOption];
}
setOriginDurationDistanceRestrictions(minDuration, maxDuration, minDistance, maxDistance) {
const placeContext = this.payload.origin;
this.setEndpointDurationDistanceRestrictions(placeContext, minDuration, maxDuration, minDistance, maxDistance);
}
setDestinationDurationDistanceRestrictions(minDuration, maxDuration, minDistance, maxDistance) {
const placeContext = this.payload.destination;
this.setEndpointDurationDistanceRestrictions(placeContext, minDuration, maxDuration, minDistance, maxDistance);
}
setWalkSpeedDeviation(walkSpeedPercent) {
if (!this.payload.params) {
return;
}
this.payload.params.walkSpeed = walkSpeedPercent;
}
setViaPlace(place, dwellTime) {
const placeRefS = place.asStopPlaceRefOrCoords();
const placeRef = PlaceRef.initWithPlaceRefsOrCoords(placeRefS);
const viaPointSchema = {
viaPoint: placeRef
};
if (dwellTime !== null) {
const dwellTimeS = "PT" + dwellTime.toString() + "M";
viaPointSchema.dwellTime = dwellTimeS;
}
this.payload.via = [viaPointSchema];
}
buildRequestXML(language, requestorRef, xmlConfig) {
this.payload.requestTimestamp = RequestHelpers.computeRequestTimestamp();
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp: this.payload.requestTimestamp,
requestorRef,
OJPTripRequest: this.payload
}
}
};
const xmlS = buildRootXML(requestOJP, xmlConfig);
return xmlS;
}
async _fetchResponse(sdk) {
const xmlConfig = sdk.version === "2.0" ? DefaultXML_Config : XML_BuilderConfigOJPv1;
const responseXML = await RequestHelpers.computeResponse(this, sdk, xmlConfig);
try {
const parsedObj = parseXML(responseXML, sdk.version);
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPTripDelivery;
if (response === void 0) {
console.log(responseXML);
throw new Error("Parse error");
}
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
};
// src/versions/legacy/v1/requests/fr.ts
var OJPv1_FareRequest = class _OJPv1_FareRequest extends BaseRequest {
payload;
constructor(items) {
super();
this.payload = 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;
}
// Used by Base.initWithRequestMock / initWithResponseMock
static Default() {
const request = new _OJPv1_FareRequest([]);
return request;
}
static cleanTripForFareRequest(trip) {
trip.tripLeg.forEach((leg) => {
if (leg.continuousLeg) {
leg.continuousLeg = {
legStart: {
locationName: leg.continuousLeg.legStart.locationName
},
legEnd: {
locationName: leg.continuousLeg.legEnd.locationName
},
service: {
personalMode: "foot",
personalModeOfOperation: "own"
},
duration: leg.continuousLeg.duration
};
}
if (leg.transferLeg) {
leg.transferLeg = {
transferType: leg.transferLeg.transferType,
legStart: {
locationName: leg.transferLeg.legStart.locationName
},
legEnd: {
locationName: leg.transferLeg.legEnd.locationName
},
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: leg.timedLeg.service.attribute,
operatorRef: leg.timedLeg.service.operatorRef
}
};
}
});
}
static initWithOJPv1Trips(trips) {
trips.map((tripV1) => {
_OJPv1_FareRequest.cleanTripForFareRequest(tripV1);
});
const now = /* @__PURE__ */ new Date();
const requestTimestamp = now.toISOString();
const fareRequests = [];
trips.forEach((trip) => {
const fareRequest = {
requestTimestamp,
tripFareRequest: {
trip
},
params: _OJPv1_FareRequest.DefaultRequestParams()
};
fareRequests.push(fareRequest);
});
const request = new _OJPv1_FareRequest(fareRequests);
return request;
}
buildRequestXML(language, requestorRef, xmlConfig) {
if (xmlConfig.ojpVersion !== "1.0") {
throw new Error("FareRequest can be consructed only with OJPv1 XML_Config");
}
const requestTimestamp = RequestHelpers.computeRequestTimestamp();
this.payload.forEach((fareRequestPayload) => {
fareRequestPayload.requestTimestamp = requestTimestamp;
});
const requestOJP = {
OJPRequest: {
serviceRequest: {
serviceRequestContext: {
language
},
requestTimestamp,
requestorRef,
OJPFareRequest: this.payload
}
}
};
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"];
if (siriPrefix + "OperatorRef" in service) {
service[ojpPrefix + "OperatorRef"] = service[siriPrefix + "OperatorRef"];
delete service[siriPrefix + "OperatorRef"];
}
}
});
});
}));
return xmlS;
}
async _fetchResponse(sdk) {
const xmlConfig = sdk.version === "2.0" ? DefaultXML_Config : XML_BuilderConfigOJPv1;
const responseXML = await RequestHelpers.computeResponse(this, sdk, xmlConfig);
try {
const parsedObj = parseXML(responseXML, sdk.version);
const response = parsedObj.OJP.OJPResponse.serviceDelivery.OJPFareDelivery;
if (response === void 0) {
console.log(responseXML);
throw new Error("Parse error");
}
return {
ok: true,
value: response
};
} catch (error) {
return {
ok: false,
error: error instanceof Error ? error : new Error("Unknown error")
};
}
}
};
// src/versions/legacy/v1/requests/lir.ts
var OJPv1_LocationInformationRequest = class _OJPv1_LocationInformationRequest extends SharedLocationInformationRequest {
payload;
constructor(restrictions) {
super();
this.payload = {
requestTimestamp: RequestHelpers.computeRequestTimestamp(),
initialInput: void 0,
placeRef: void 0,
restrictions
};
}
static Default() {
const restrictions = SharedLocationInformationRequest.DefaultRestrictionParams();
const request = new _OJPv1_LocationInformationRequest(restrictions);
return request;
}
static initWithLocationName(name, placeTypes = [], numberOfResults = 10) {
const request = _OJPv1_LocationInformationRequest.Default();
request.payload.initialInput = {
locationName: name
};
if (request.payload.restrictions) {
request.updateRestrictions(request.payload.restrictions, placeTypes, numberOfResults);
}
return request;
}
static initWithPlaceRef(placeRefOrCoords, numberOfResults = 10) {
const request = _OJPv1_LocationInformationRequest.Default();
const placeRef = PlaceRef.initWithPlaceRefsOrCoords(placeRefOrCoords);
request.payload.placeRef = placeRef.asOJPv1Schema();
if (request.payload.restrictions) {
request.updateRestrictions(request.payload.restrictions, ["s