Files
diplomarbeit-code/lib/src/AIMCMapper.ts
T

157 lines
6.3 KiB
TypeScript

import type { types } from "@aas-core-works/aas-core3.0-typescript";
import type { AIMCMap } from "./types/aimcConf";
import type { ConnectionConfiguration } from "./types/requests";
import type { InterfaceAction, InterfaceActionForm, InterfaceEvent, InterfaceEventForm, InterfaceProperty, InterfacePropertyForm } from "./types/aidConf";
import AIMCParser from "./parser/AIMCParser";
import Traverser from "./helper/traverser";
import AIDParser from "./parser/AIDParser";
/**
* The AIMC Mapper.
* @remarks
* This class is used to map properties to endpoints.
* @public
*/
export default class AIMCMapper {
/**
* The map.
* @private
*/
private map: AIMCMap = new Map();
/**
* Creates the mapper.
* @param env The AAS Environment
* @public
*/
public constructor(private readonly env: types.Environment) {
this.generate();
}
/**
* Generates the map from the AAS Environment.
* @private
*/
private generate(): void {
const aimc = AIMCParser.parse(this.env);
if (aimc === null) return;
for (const endpointConf of Object.values(aimc)) {
for (const entry of endpointConf) {
const ep = AIDParser.parseEndpointMetaData(entry.EndpointMetaDataReference);
if (ep === null) continue;
for (const mapping of entry.MappingConfiguration) {
//const ifm = AIDParser.parseInterfaceMetaData(mapping.InterfaceMetaDataReference);
//if (ifm === null) continue;
// Why do we need this? We already have the interface metadata reference in every ssm
for (const ssm of mapping.SourceSinkMappings) {
const resolved = Traverser.resolveRelationship(this.env, ssm);
if (resolved === null) continue;
// To know if we currently view a property, action or event, they reference keys can help us.
// We know the third to last must be the "InterfaceMetadata" and the second to last must be the "Properties", "Actions" or "Events".
// As we _maybe_ don't know if the first and second reference are switched we can check for the third to last.
const elemType = (ssm as types.RelationshipElement).first.keys.at(-3)?.value.toLocaleLowerCase() === "interfacemetadata" ? (ssm as types.RelationshipElement).first.keys.at(-2)?.value : (ssm as types.RelationshipElement).second.keys.at(-2)?.value;
let {first, second} = resolved;
let parsedPropConf: InterfaceProperty | InterfaceAction | InterfaceEvent | null = null;
switch (elemType?.toLocaleLowerCase()) {
case "properties":
parsedPropConf = AIDParser.parseInterfaceMetadataProperty(first as types.SubmodelElementCollection);
break;
case "actions":
parsedPropConf = AIDParser.parseInterfaceMetadataAction(first as types.SubmodelElementCollection);
break;
case "events":
parsedPropConf = AIDParser.parseInterfaceMetadataEvent(first as types.SubmodelElementCollection);
break;
default:
// Error. We have not found a valid type of element to parse.
continue;
}
if (parsedPropConf === null) {
// maybe the property is in the first element
[first, second] = [second, first];
switch (elemType?.toLocaleLowerCase()) {
case "properties":
parsedPropConf = AIDParser.parseInterfaceMetadataProperty(first as types.SubmodelElementCollection);
break;
case "actions":
parsedPropConf = AIDParser.parseInterfaceMetadataAction(first as types.SubmodelElementCollection);
break;
case "events":
parsedPropConf = AIDParser.parseInterfaceMetadataEvent(first as types.SubmodelElementCollection);
break;
}
}
if (parsedPropConf === null) continue;
this.map.set(second, ({
...ep,
...parsedPropConf
} as any as ConnectionConfiguration));
}
}
}
}
}
/**
*
* @returns The complete map
* @public
*/
public getMap(): AIMCMap {
return this.map;
}
/**
* Get endpoint for a specific Element
* @param element Element
* @returns Endpoint description or undefined if not found
* @public
*/
public get(element: types.Class): ConnectionConfiguration | undefined {
return this.map.get(element);
}
/**
* Returns all endpoints for a idShort
* Can return multiple as idShorts are not necessarily unique
* @param idShort idShort of the element
* @returns Endpoints descriptions of elements with that idShort
* @public
*/
public getByIdShort(idShort: string): ConnectionConfiguration[] {
const result = [];
for (const [e, cc] of this.map.entries()) {
if ((e as any).idShort?.toLocaleLowerCase() === idShort.toLocaleLowerCase()) result.push(cc);
}
return result;
}
/**
* Get an element by its endpoint
* @param path Absolute endpoint path
* @returns Elements that use that path
* @public
*/
public reverseGet(path: string): types.Class[] {
const result = [];
for (const [e, cc] of this.map.entries()) {
const formsPaths = cc.forms.map((f: InterfaceActionForm | InterfacePropertyForm | InterfaceEventForm) => cc.base + f.href);
if (formsPaths.includes(path)) result.push(e);
}
return result;
}
}