Skip to content

Commit

Permalink
refactor: add transformation code to
Browse files Browse the repository at this point in the history
TODO: properties etc
  • Loading branch information
danielpeintner committed Aug 23, 2023
1 parent 8e7917c commit 760b5be
Show file tree
Hide file tree
Showing 2 changed files with 194 additions and 10 deletions.
111 changes: 106 additions & 5 deletions packages/td-tools/src/util/asset-interface-description.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { SecurityScheme } from "wot-thing-description-types";
import * as TDParser from "../td-parser";

import debug from "debug";
import { ThingDescription } from "wot-typescript-definitions";
const namespace = "node-wot:td-tools:asset-interface-description-util";
const logDebug = debug(`${namespace}:debug`);
const logInfo = debug(`${namespace}:info`);
Expand Down Expand Up @@ -53,6 +54,17 @@ interface SubmodelInformation {
endpointMetadataArray: Array<Record<string, unknown>>;
}

// TODO can/shall we define als AAS/AID contructs? Difficult since idShort and value array is used *everywhere*
interface EndpointMetadata {

Check warning on line 58 in packages/td-tools/src/util/asset-interface-description.ts

View workflow job for this annotation

GitHub Actions / eslint

'EndpointMetadata' is defined but never used. Allowed unused vars must match /Test/u
idShort: "EndpointMetadata";
value: Array<EndpointMetadataValue>;
modelType: "SubmodelElementCollection";
}

interface EndpointMetadataValue {
idShort: string; // base, contentType, securityDefinitions
}

const noSecSS: SecurityScheme = { scheme: "nosec" };
const noSecName = 0 + "_sc";

Expand Down Expand Up @@ -565,9 +577,13 @@ export class AssetInterfaceDescriptionUtil {
* @param td input TD
* @returns transformed AID submodel definition in JSON format
*/
public transformTD2SM(td: string): string {
const thing = TDParser.parseTD(td);
console.log("TD " + thing.title + " parsed...");
public transformTD2SM(tdAsString: string): string {
const td: ThingDescription = TDParser.parseTD(tdAsString);

console.log("TD " + td.title + " parsed...");

// configuration
const submodelElementIdShort = "InterfaceHTTP";

// TODO
// value entry "idShort": "EndpointMetadata"
Expand All @@ -581,12 +597,97 @@ export class AssetInterfaceDescriptionUtil {
// TODO does this need to be an array or can it simply be a value
{
language: "en",
text: thing.title, // TODO should be description, where does title go to? later on in submodel?
text: td.title, // TODO should be description, where does title go to? later on in submodel?
},
],
submodels: [],
submodelElements: [
{
idShort: submodelElementIdShort,
// semanticId needed?
// embeddedDataSpecifications needed?
value: [
// support
this.createEndpointMetadata(td), // EndpointMetadata
this.createInterfaceMetadata(td), // InterfaceMetadata
// externalDescriptor ?
],
modelType: "SubmodelElementCollection",
},
],
modelType: "Submodel",
};

return JSON.stringify(aidObject);
}

private createEndpointMetadata(td: ThingDescription): Record<string, unknown> {
const values: Array<unknown> = [];

// base ?
if (td.base) {
values.push({
idShort: "base",
valueType: "xs:anyURI",
value: td.base, // TODO
modelType: "Property",
});
}

// TODO wrong place.. not allowed in TD spec?
/*
{
idShort: "contentType",
valueType: "xs:string",
value: "application/json", // TODO
modelType: "Property",
},
*/

// securityDefinitions
const secValues: Array<unknown> = [];
for (const secKey in td.securityDefinitions) {
const secValue: SecurityScheme = td.securityDefinitions[secKey];
secValues.push({
idShort: secValue.scheme,
modelType: "SubmodelElementCollection", // TODO correct or Property ?
// modelType: "Property"
});
}

values.push({
idShort: "securityDefinitions",
value: [
{
idShort: "scheme",
value: secValues,
modelType: "SubmodelElementCollection",
},
],
modelType: "SubmodelElementCollection",
});

const endpointMetadata: Record<string, unknown> = {
idShort: "EndpointMetadata",
// semanticId ?
// embeddedDataSpecifications ?
value: values,
modelType: "SubmodelElementCollection",
};

return endpointMetadata;
}

private createInterfaceMetadata(td: ThingDescription): Record<string, unknown> {
const interfaceMetadata: Record<string, unknown> = {
idShort: "InterfaceMetadata",
// semanticId ?
// embeddedDataSpecifications ?
value: [
// TODO
],
modelType: "SubmodelElementCollection",
};

return interfaceMetadata;
}
}
93 changes: 88 additions & 5 deletions packages/td-tools/test/AssetInterfaceDescriptionTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { expect } from "chai";

import { AssetInterfaceDescriptionUtil } from "../src/util/asset-interface-description";
import { promises as fs } from "fs";
import { ThingDescription } from "wot-typescript-definitions";

@suite("tests to verify the Asset Interface Description Utils")
class AssetInterfaceDescriptionUtilTest {
Expand Down Expand Up @@ -363,13 +364,95 @@ class AssetInterfaceDescriptionUtilTest {
}

@test async "should correctly transform sample TD into JSON submodel"() {
const td = `{"title": "testTD"}`;
const sm = this.assetInterfaceDescriptionUtil.transformTD2SM(td);
const base = "https://www.example.com/";
const td: ThingDescription = {
"@context": "https://www.w3.org/2022/wot/td/v1.1",
title: "testTD",
securityDefinitions: {
basic_sc: {
scheme: "basic",
in: "header",
},
},
security: "basic_sc",
base: base,
properties: {
status: {
type: "string",
observable: true,
forms: [
{
href: "stat",
},
],
},
},
};
const sm = this.assetInterfaceDescriptionUtil.transformTD2SM(JSON.stringify(td));

const smObj = JSON.parse(sm);
expect(smObj).to.have.property("idShort").that.equals("AssetInterfacesDescription");

// TODO EndpointMetadata and InterfaceMetadata
expect(smObj).to.have.property("submodelElements").to.be.an("array").to.have.lengthOf.greaterThan(0);
const smInterface = smObj.submodelElements[0];
expect(smInterface).to.have.property("value").to.be.an("array").to.have.lengthOf.greaterThan(0);
let hasEndpointMetadata = false;
for (const smValue of smInterface.value) {
if (smValue.idShort === "EndpointMetadata") {
hasEndpointMetadata = true;
const endpointMetadata = smValue;
expect(endpointMetadata).to.have.property("value").to.be.an("array").to.have.lengthOf.greaterThan(0);
let hasBase = false;
let hasContentType = false;
let hasSecurityDefinitions = false;
for (const endpointMetadataValue of endpointMetadata.value) {
if (endpointMetadataValue.idShort === "base") {
hasBase = true;
expect(endpointMetadataValue.value).to.equal(base);
} else if (endpointMetadataValue.idShort === "contentType") {
hasContentType = true;
} else if (endpointMetadataValue.idShort === "securityDefinitions") {
hasSecurityDefinitions = true;
expect(endpointMetadataValue)
.to.have.property("value")
.to.be.an("array")
.to.have.lengthOf.greaterThan(0);
let hasScheme = false;
for (const securityDefinitionValue of endpointMetadataValue.value) {
if (securityDefinitionValue.idShort === "scheme") {
hasScheme = true;
expect(securityDefinitionValue)
.to.have.property("value")
.to.be.an("array")
.to.have.lengthOf.greaterThan(0);
let hasBasic = false;
for (const sec of securityDefinitionValue.value) {
if (sec.idShort === "basic") {
hasBasic = true;
}
}
expect(hasBasic).to.equal(true);
}
}
expect(hasScheme).to.equal(true);

// expect(endpointMetadataValue.value).to.equal("basic");
}
}
expect(hasBase).to.equal(true);
expect(hasContentType).to.equal(false);
expect(hasBase).to.equal(hasSecurityDefinitions);
}
}
expect(hasEndpointMetadata, "No EndpointMetadata").to.equal(true);

// TODO InterfaceMetadata with properties etc
let hasInterfaceMetadata = false;
for (const smValue of smInterface.value) {
if (smValue.idShort === "InterfaceMetadata") {
hasInterfaceMetadata = true;
}
}
expect(hasInterfaceMetadata, "No InterfaceMetadata").to.equal(true);
}

@test async "should correctly transform sample TD into JSON AAS"() {
Expand All @@ -378,7 +461,7 @@ class AssetInterfaceDescriptionUtilTest {

const aasObj = JSON.parse(sm);
expect(aasObj).to.have.property("assetAdministrationShells").to.be.an("array");
expect(aasObj).to.have.property("submodels").to.be.an("array");
expect(aasObj).to.have.property("submodels").to.be.an("array").to.have.lengthOf(1);

// TODO more checks
}
Expand Down

0 comments on commit 760b5be

Please sign in to comment.