157 lines
6.3 KiB
TypeScript
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;
|
|
}
|
|
} |