From 97a6031d32c6f6d2f110a4da5f6570a2369614d5 Mon Sep 17 00:00:00 2001 From: Martin Karkowski Date: Sat, 5 Nov 2022 22:22:06 +0100 Subject: [PATCH] updating to version 1.4.6 --- CHANGELOG.md | 25 ++- contribute/VERSION | 2 +- .../typescript/analyzeTypescriptFiles.ts | 12 +- .../typescript/types/IAnalyzeResult.ts | 4 +- lib/decorators/container.ts | 4 +- lib/decorators/moduleDecorators.ts | 4 +- lib/demo/instances/HelloWorld.ts | 8 +- lib/demo/instances/IHellWorldModule.ts | 2 +- .../ConnectivityManager.spec.ts | 4 +- .../ConnectivityManager.ts | 8 +- .../InstanceManager/InstanceManager.spec.ts | 169 ++++++++++++++++ .../InstanceManager/InstanceManager.ts | 13 +- .../RpcManager/NopeRpcManager.spec.ts | 184 ++++++++++++++++-- lib/dispatcher/RpcManager/NopeRpcManager.ts | 4 +- lib/helpers/mapMethods.ts | 32 +-- lib/helpers/objectMethods.ts | 4 + lib/loader/generateNopeBasicPackage.ts | 2 +- lib/loader/nopePackageLoader.ts | 4 +- lib/module/BaseModule.ts | 20 +- lib/module/GenericWrapper.ts | 10 +- lib/parsers/open-api/OpenApiParser.ts | 4 +- lib/types/ISystemElements.ts | 4 +- lib/types/nope/nopeCommunication.interface.ts | 4 +- lib/types/nope/nopeDispatcher.interface.ts | 4 +- lib/types/nope/nopeModule.interface.ts | 32 +-- lib/types/nope/nopePackage.interface.ts | 8 +- lib/types/nope/nopeRpcManager.interface.ts | 8 +- lib/types/ui/helpers.interface.ts | 6 +- lib/ui/helpers.nodejs.ts | 10 +- package-lock.json | 4 +- package.json | 2 +- 31 files changed, 470 insertions(+), 131 deletions(-) create mode 100644 lib/dispatcher/InstanceManager/InstanceManager.spec.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index ea544a3..76a2d24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -326,4 +326,27 @@ Inital commit, which is working with the browser - Added: - `lib\demo\instances`: Added demo elements. (Instances.) - \ No newline at end of file +# 1.4.6 + - Fixes: + - `lib\dispatcher\ConnectivityManager\ConnectivityManager.ts`: + - Fixing Master Assignment. + - Only sending one Status on init. + - `lib/dispatcher/InstanceManager/InstanceManager.ts`: + - Fixing pathes of `constructors` variable. Now `amountOf` etc is working + - Fixing pathes of `constructorExists`. Now working with Type-Name. + - Only sending one Status on init. + - `lib/helpers/mapMethods.ts`: + - Fixing `tranformMap` in the case of only a `pathExtractedValue` or `pathExtractedKey` is given. + - `lib/helpers/objectMethods.ts`: + - fixing `rgetattr` -> Now correctly returns "null" in all cases. + - `lib\demo`: + - Fixing imports of demo instances. + - Modified: + - `lib\types`: + - renamed `IFunctionOptions` to `IServiceOptions` + - `lib/types/nope/nopeModule.interface.ts`: + - `listMethods` now returns a different array, where the attribute is named `method` instead of `func` -> Adaptions affect `BaseModule` and `GenericModule` + - Added: + - Added Tests for the Properties of NopeRpcManager, NopeConnectivityManager + + \ No newline at end of file diff --git a/contribute/VERSION b/contribute/VERSION index 03e5161..7b5753f 100644 --- a/contribute/VERSION +++ b/contribute/VERSION @@ -1 +1 @@ -1.4.5 \ No newline at end of file +1.4.6 \ No newline at end of file diff --git a/lib/analyzers/typescript/analyzeTypescriptFiles.ts b/lib/analyzers/typescript/analyzeTypescriptFiles.ts index 24aee5e..586ea72 100644 --- a/lib/analyzers/typescript/analyzeTypescriptFiles.ts +++ b/lib/analyzers/typescript/analyzeTypescriptFiles.ts @@ -9,7 +9,7 @@ import { ILogger } from "js-logger"; import { ISystemElements } from "../../types/ISystemElements"; import { - IFunctionOptions, + IServiceOptions, IEventOptions, } from "../../types/nope/nopeModule.interface"; import { @@ -81,7 +81,7 @@ export async function extractDefinitions( name: string; properties: IEventOptions[]; events: IEventOptions[]; - methods: IFunctionOptions[]; + methods: IServiceOptions[]; } = { name: mod.className, methods: [], @@ -96,17 +96,17 @@ export async function extractDefinitions( ); } - const methodDefintion: IFunctionOptions = method.decoratorSettings[ + const methodDefintion: IServiceOptions = method.decoratorSettings[ NAME_METHOD_DEC - ] as IFunctionOptions; + ] as IServiceOptions; methodDefintion.id = methodDefintion.id || method.name; if ( - (method.decoratorSettings[NAME_METHOD_DEC] as IFunctionOptions)?.schema + (method.decoratorSettings[NAME_METHOD_DEC] as IServiceOptions)?.schema ) { // a schema is present => Just use the Provided Schema. methodDefintion.schema = ( - method.decoratorSettings[NAME_METHOD_DEC] as IFunctionOptions + method.decoratorSettings[NAME_METHOD_DEC] as IServiceOptions )?.schema; } else if (method.decoratorSettings[NAME_METHOD_DEC]) { // Assign the Schema diff --git a/lib/analyzers/typescript/types/IAnalyzeResult.ts b/lib/analyzers/typescript/types/IAnalyzeResult.ts index 6acfbf8..a8b5fdd 100644 --- a/lib/analyzers/typescript/types/IAnalyzeResult.ts +++ b/lib/analyzers/typescript/types/IAnalyzeResult.ts @@ -7,14 +7,14 @@ */ import { IJsonSchema } from "../../../types/IJSONSchema"; -import { IFunctionOptions } from "../../../types/nope/nopeModule.interface"; +import { IServiceOptions } from "../../../types/nope/nopeModule.interface"; import { IClassAnalyzeResult } from "./IClassAnalyzeResult"; import { IExportedFunctionResult } from "./IExportedFunctionResult"; export interface IAnalyzeResult { classes: IClassAnalyzeResult[]; functions: (IExportedFunctionResult & { - decoratorSettings: IFunctionOptions; + decoratorSettings: IServiceOptions; })[]; generalModel: IJsonSchema; } diff --git a/lib/decorators/container.ts b/lib/decorators/container.ts index 37c8372..7b31abb 100644 --- a/lib/decorators/container.ts +++ b/lib/decorators/container.ts @@ -5,9 +5,9 @@ */ import { getSingleton } from "../helpers/singletonMethod"; -import { IFunctionOptions, INopeModule } from "../types"; +import { IServiceOptions, INopeModule } from "../types"; -export type IexportAsNopeServiceParameters = IFunctionOptions; +export type IexportAsNopeServiceParameters = IServiceOptions; /** * Return the central loger. This logger is a singleton (see {@link getSingleton}) diff --git a/lib/decorators/moduleDecorators.ts b/lib/decorators/moduleDecorators.ts index 10b600e..7807420 100644 --- a/lib/decorators/moduleDecorators.ts +++ b/lib/decorators/moduleDecorators.ts @@ -6,7 +6,7 @@ import { rgetattr, rsetattr } from "../helpers/objectMethods"; import { IEventOptions, - IFunctionOptions, + IServiceOptions, INopeModule, } from "../types/nope/nopeModule.interface"; import { getCentralDecoratedContainer } from "./container"; @@ -17,7 +17,7 @@ const CONTAINER = getCentralDecoratedContainer(); * Decorator, used to export the Method as Service to Nope.. * @param options The options used for linking. */ -export function nopeMethod(options: IFunctionOptions) { +export function nopeMethod(options: IServiceOptions) { // Now lets make shure, we are using the correct type // provide inputs and outputs. rsetattr(options, "schema/type", "function"); diff --git a/lib/demo/instances/HelloWorld.ts b/lib/demo/instances/HelloWorld.ts index 13b08b4..8f5e242 100644 --- a/lib/demo/instances/HelloWorld.ts +++ b/lib/demo/instances/HelloWorld.ts @@ -1,8 +1,8 @@ import { injectable } from "inversify"; -import { InjectableNopeBaseModule } from "../module"; -import { NopeObservable } from "../observables"; -import { NopePromise } from "../promise"; -import { INopeObservable } from "../types"; +import { InjectableNopeBaseModule } from "../../module"; +import { NopeObservable } from "../../observables"; +import { NopePromise } from "../../promise"; +import { INopeObservable } from "../../types"; import { IHelloWorlModule } from "./IHellWorldModule"; @injectable() diff --git a/lib/demo/instances/IHellWorldModule.ts b/lib/demo/instances/IHellWorldModule.ts index 442ed43..5d899fa 100644 --- a/lib/demo/instances/IHellWorldModule.ts +++ b/lib/demo/instances/IHellWorldModule.ts @@ -1,4 +1,4 @@ -import { INopeModule, INopeObservable, IValidPromise } from "../types"; +import { INopeModule, INopeObservable, IValidPromise } from "../../types"; export interface IHelloWorlModule extends INopeModule { testProp: INopeObservable; diff --git a/lib/dispatcher/ConnectivityManager/ConnectivityManager.spec.ts b/lib/dispatcher/ConnectivityManager/ConnectivityManager.spec.ts index f3024de..eb6e81f 100644 --- a/lib/dispatcher/ConnectivityManager/ConnectivityManager.spec.ts +++ b/lib/dispatcher/ConnectivityManager/ConnectivityManager.spec.ts @@ -1,8 +1,6 @@ /** * @author Martin Karkowski * @email m.karkowski@zema.de - * @create date 2022-01-04 10:03:41 - * @modify date 2022-01-04 12:38:45 * @desc [description] */ @@ -196,7 +194,7 @@ describe("NopeConnectivityManager", function () { // Dispose our Delay. first.dispose(true); - expect(end - adapted < 1).to.be.true("There should not be an delta."); + assert(end - adapted < 5, "There should not be an delta."); }); it("master", async () => { diff --git a/lib/dispatcher/ConnectivityManager/ConnectivityManager.ts b/lib/dispatcher/ConnectivityManager/ConnectivityManager.ts index 5adf882..560be72 100644 --- a/lib/dispatcher/ConnectivityManager/ConnectivityManager.ts +++ b/lib/dispatcher/ConnectivityManager/ConnectivityManager.ts @@ -331,7 +331,7 @@ export class NopeConnectivityManager implements INopeConnectivityManager { public get master(): INopeStatusInfo { const candidates = this._getPossibleMasterCandidates(); const masters = candidates.filter((item) => { - return item.isMaster; + return item.isMaster && item.isMasterForced; }); if (masters.length === 0) { @@ -419,15 +419,13 @@ export class NopeConnectivityManager implements INopeConnectivityManager { _this.dispatchers.update(); }); - await this._sendStatus(); + await this.emitBonjour(); + await this._sendStatus(true); if (this._logger) { this._logger.info("core.connectivity-manager", this.id, "initialized"); } - await this.emitBonjour(); - await this._sendStatus(); - this.ready.setContent(true); } diff --git a/lib/dispatcher/InstanceManager/InstanceManager.spec.ts b/lib/dispatcher/InstanceManager/InstanceManager.spec.ts new file mode 100644 index 0000000..c5f2ed9 --- /dev/null +++ b/lib/dispatcher/InstanceManager/InstanceManager.spec.ts @@ -0,0 +1,169 @@ +/** + * @author Martin Karkowski + * @email m.karkowski@zema.de + * @create date 2022-01-05 17:50:44 + * @modify date 2022-01-05 17:50:44 + * @desc [description] + */ + +import { expect, assert } from "chai"; +import { describe, it } from "mocha"; +import "reflect-metadata"; +import { getLayer } from "../../communication/getLayer.nodejs"; +import { NopeEventEmitter } from "../../eventEmitter"; +import { sleep } from "../../helpers/async"; +import { NopeBaseModule } from "../../module"; +import { NopeObservable } from "../../observables/nopeObservable"; +import { NopeInstanceManager } from "./InstanceManager"; + +describe("NopeInstanceManager", function () { + // Describe the required Test: + let manager: NopeInstanceManager; + manager = new NopeInstanceManager( + { + communicator: getLayer("event", "", false), + logger: false, + }, + () => new NopeEventEmitter(), + () => new NopeObservable(), + async () => "test", + "test", + undefined, + undefined, + manager as any + ); + + it("registering instance", async () => { + let called = false; + let calledService = false; + + class TestModule extends NopeBaseModule { + // We can not provide a service. + // @nopeMethod({ + // id: "service", + // schema: {}, + // }) + // public async service() { + // calledService = true; + // return "called"; + // } + + public async dispose(): Promise { + await super.dispose(); + called = true; + } + + public async init(p1: string, p2: string): Promise { + this.author = { + forename: "test", + surename: "test", + mail: "test", + }; + this.version = { + date: new Date(), + version: 1, + }; + this.description = "test"; + + assert(p1 == "p1" && p2 == "p2", "parameters where matched wrong"), + await super.init(); + } + } + + await manager.ready.waitFor(); + + // Now we register the Service + await manager.registerConstructor( + "TestModule", + async (core, identifier) => { + assert( + identifier === "instance", + "The identifier has not been transmitted" + ); + return new TestModule(core); + } + ); + + await sleep(10); + + // Check the Constructors + const constructors = manager.constructors.extractedKey; + expect(constructors).to.include("TestModule"); + assert( + manager.constructors.amountOf.get("TestModule") == 1, + "There should be one Provider for this constructor" + ); + assert( + manager.constructors.keyMappingReverse.get("TestModule").size == 1, + "There should be one Provider for this constructor" + ); + assert( + manager.constructors.conflicts.size == 0, + "There should be no conflict" + ); + assert( + manager.constructorExists("TestModule"), + "Constructor should be known!" + ); + assert( + manager.constructorExists("unkown") == false, + "Constructor should not be known!" + ); + assert( + Array.from(manager.constructors.keyMappingReverse.get("TestModule"))[0] == + "test", + "The Provider should be 'test'" + ); + + const instance = await manager.createInstance({ + identifier: "instance", + type: "TestModule", + params: ["p1", "p2"], + }); + + assert( + manager.instanceExists("instance", false) == true, + "The instance should be known!" + ); + assert( + manager.instanceExists("instance", true) == false, + "No external manager is present!" + ); + assert( + manager.internalInstances.getContent().includes("instance"), + "The instance should be listed as internal instance." + ); + assert( + Array.from(manager.instances.keyMappingReverse.get("instance"))[0] == + "test", + "The Provider should be 'test'" + ); + + // Now test the instance wrapper + // assert( + // (await instance.service()) === "called", + // "The result should be called" + // ); + // assert(calledService, "The service flag should be different now."); + assert( + (await instance.listEvents()).length === 0, + "No event has been defined" + ); + assert( + (await instance.listProperties()).length === 0, + "No property has been defined" + ); + assert( + (await instance.listMethods()).length === 0, + "No Method should be known" + ); + assert( + Object.keys(instance.dynamicInstanceMethods).length === 0, + "No Method should be known" + ); + assert( + Object.keys(instance.methods).length === 0, + "No Method should be known" + ); + }); +}); diff --git a/lib/dispatcher/InstanceManager/InstanceManager.ts b/lib/dispatcher/InstanceManager/InstanceManager.ts index 1890fb4..70f3672 100644 --- a/lib/dispatcher/InstanceManager/InstanceManager.ts +++ b/lib/dispatcher/InstanceManager/InstanceManager.ts @@ -206,6 +206,7 @@ export class NopeInstanceManager implements INopeInstanceManager { this._mappingOfRemoteDispatchersAndGenerators = new Map(); this.constructors = new MapBasedMergeData( this._mappingOfRemoteDispatchersAndGenerators, + "+", "+" ) as MapBasedMergeData; @@ -219,6 +220,8 @@ export class NopeInstanceManager implements INopeInstanceManager { this.internalInstances = new NopeObservable(); this.internalInstances.setContent([]); + const ctorStart = `nope${SPLITCHAR}core${SPLITCHAR}constructor${SPLITCHAR}`; + // We will subscribe to some generators. this._rpcManager.services.data.subscribe((_) => { // Clear the Mapping of the Generators @@ -230,12 +233,10 @@ export class NopeInstanceManager implements INopeInstanceManager { // Filter the Generators based on the existing services const generators = services.services .filter((svc) => { - return svc?.id.startsWith( - `nope${SPLITCHAR}core${SPLITCHAR}constructor${SPLITCHAR}` - ); + return svc?.id.startsWith(ctorStart); }) .map((item) => { - return item.id; + return item.id.slice(ctorStart.length); }); // If the Dispatcher has a generator we will add it. @@ -479,6 +480,7 @@ export class NopeInstanceManager implements INopeInstanceManager { // Create an Instance const _instance = await cb(_this._core, data.identifier); + _instance.identifier = data.identifier; // Make shure the Data is expressed as Array. if (!Array.isArray(data.params)) { @@ -698,8 +700,7 @@ export class NopeInstanceManager implements INopeInstanceManager { // See interface description public constructorExists(typeIdentifier: string): boolean { - const ctorName = this.getServiceName(typeIdentifier, "constructor"); - return this.constructors.data.getContent().includes(ctorName); + return this.constructors.data.getContent().includes(typeIdentifier); } // See interface description diff --git a/lib/dispatcher/RpcManager/NopeRpcManager.spec.ts b/lib/dispatcher/RpcManager/NopeRpcManager.spec.ts index 154f06d..c495448 100644 --- a/lib/dispatcher/RpcManager/NopeRpcManager.spec.ts +++ b/lib/dispatcher/RpcManager/NopeRpcManager.spec.ts @@ -6,7 +6,7 @@ * @desc [description] */ -import { expect } from "chai"; +import { expect, assert } from "chai"; import { beforeEach, describe, it } from "mocha"; import "reflect-metadata"; import { getLayer } from "../../communication/getLayer.nodejs"; @@ -42,7 +42,7 @@ describe("NopeRpcManager", function () { manager.ready.waitFor().then(() => done()); }); - const helloWorld = async (greetings: string) => { + const helloworld = async (greetings: string) => { return "Hello " + greetings + "!"; }; @@ -54,8 +54,8 @@ describe("NopeRpcManager", function () { it("registering service", async () => { await manager.ready.waitFor(); // Now we register the Service - const r = manager.registerService(helloWorld, { - id: "helloWorld", + await manager.registerService(helloworld, { + id: "helloworld", schema: { description: "Hello World Service", }, @@ -64,13 +64,36 @@ describe("NopeRpcManager", function () { await sleep(10); // Get the Services const services = manager.services.extractedKey; - expect(services).to.include("helloWorld"); + expect(services).to.include("helloworld"); + + assert( + manager.services.amountOf.get("helloworld") == 1, + "There should be one Provider for this service" + ); + assert( + manager.services.keyMappingReverse.get("helloworld").size == 1, + "There should be one Provider for this service" + ); + assert( + manager.services.conflicts.size == 0, + "There should be no conflict" + ); + assert(manager.serviceExists("helloworld"), "Service should be known!"); + assert( + manager.serviceExists("helloworld2") == false, + "Service should not be known!" + ); + assert( + Array.from(manager.services.keyMappingReverse.get("helloworld"))[0] == + "test", + "The Provider should be 'test'" + ); }); it("call service", async () => { await manager.ready.waitFor(); - const r = manager.registerService(helloWorld, { + await manager.registerService(helloworld, { id: "helloworld", schema: { description: "Hello World Service", @@ -86,7 +109,7 @@ describe("NopeRpcManager", function () { it("call service via methodInterface", async () => { await manager.ready.waitFor(); - const r = manager.registerService(helloWorld, { + await manager.registerService(helloworld, { id: "helloworld", schema: { description: "Hello World Service", @@ -102,7 +125,7 @@ describe("NopeRpcManager", function () { it("call service with a timeout", async () => { await manager.ready.waitFor(); - const r = manager.registerService(delay, { + await manager.registerService(delay, { id: "helloworld", schema: { description: "Hello World Service", @@ -131,13 +154,13 @@ describe("NopeRpcManager", function () { it("multi-call", async () => { await manager.ready.waitFor(); - manager.registerService(helloWorld, { + manager.registerService(helloworld, { id: "helloworld_00", schema: { description: "Hello World Service", }, }); - manager.registerService(helloWorld, { + manager.registerService(helloworld, { id: "helloworld_01", schema: { description: "Hello World Service", @@ -163,12 +186,16 @@ describe("NopeRpcManager", function () { }, () => new NopeObservable(), async () => "test", - "test" + "caller" ); beforeEach(() => { const communicator = getLayer("event", "", false); + if (manager) { + manager.dispose(); + } + // Create a new Observer manager = new NopeRpcManager( { @@ -180,6 +207,10 @@ describe("NopeRpcManager", function () { "test" ); + if (caller) { + caller.dispose(); + } + caller = new NopeRpcManager( { communicator, @@ -187,11 +218,11 @@ describe("NopeRpcManager", function () { }, () => new NopeObservable(), async () => "test", - "test" + "caller" ); }); - const helloWorld = async (greetings: string) => { + const helloworld = async (greetings: string) => { return "Hello " + greetings + "!"; }; @@ -204,8 +235,8 @@ describe("NopeRpcManager", function () { await manager.ready.waitFor(); await caller.ready.waitFor(); - const r = manager.registerService(helloWorld, { - id: "helloWorld", + await manager.registerService(helloworld, { + id: "helloworld", schema: { description: "Hello World Service", }, @@ -215,17 +246,41 @@ describe("NopeRpcManager", function () { // Get the Services const services = caller.services.extractedKey; - expect(services).to.include("helloWorld"); + expect(caller.services.extractedKey).to.include("helloworld"); + assert( + caller.services.amountOf.get("helloworld") == 1, + "There should be one Provider for this service" + ); + assert( + caller.services.keyMappingReverse.get("helloworld").size == 1, + "There should be one Provider for this service" + ); + assert( + caller.services.conflicts.size == 0, + "There should be no conflict" + ); + assert(caller.serviceExists("helloworld"), "Service should be known!"); + assert( + caller.serviceExists("helloworld2") == false, + "Service should not be known!" + ); + assert( + Array.from(caller.services.keyMappingReverse.get("helloworld"))[0] == + "test", + "The Provider should be 'test'" + ); }); it("registering service - dynamic id", async () => { await manager.ready.waitFor(); await caller.ready.waitFor(); - const r = manager.registerService(helloWorld, { + const r = await manager.registerService(helloworld, { schema: {}, }); + assert((r as any).id !== "helloworld", "There should be an dynamic id"); + await sleep(10); // Get the Services const services = caller.services.extractedKey; @@ -237,7 +292,7 @@ describe("NopeRpcManager", function () { await manager.ready.waitFor(); await caller.ready.waitFor(); - const r = manager.registerService(helloWorld, { + await manager.registerService(helloworld, { id: "helloworld", schema: { description: "Hello World Service", @@ -254,7 +309,7 @@ describe("NopeRpcManager", function () { await manager.ready.waitFor(); await caller.ready.waitFor(); - const r = manager.registerService(helloWorld, { + await manager.registerService(helloworld, { id: "helloworld", schema: { description: "Hello World Service", @@ -271,7 +326,7 @@ describe("NopeRpcManager", function () { await manager.ready.waitFor(); await caller.ready.waitFor(); - const r = manager.registerService(delay, { + await manager.registerService(delay, { id: "helloworld", schema: { description: "Hello World Service", @@ -296,5 +351,94 @@ describe("NopeRpcManager", function () { } } }); + + it("providing multiple providers", async () => { + await manager.ready.waitFor(); + await caller.ready.waitFor(); + + await manager.registerService(delay, { + id: "helloworld", + schema: { + description: "Hello World Service", + }, + }); + + await caller.registerService(delay, { + id: "helloworld", + schema: { + description: "Hello World Service", + }, + }); + + await sleep(10); + + expect(manager.services.extractedKey).to.include("helloworld"); + assert( + manager.services.amountOf.get("helloworld") == 2, + "There should be two Provider for this service" + ); + assert( + manager.services.keyMappingReverse.get("helloworld").size == 2, + "There should be two Provider for this service" + ); + assert( + manager.services.conflicts.size == 0, + "There should be no conflict" + ); + assert(manager.serviceExists("helloworld"), "Service should be known!"); + assert( + manager.serviceExists("helloworld2") == false, + "Service should not be known!" + ); + + let providers = Array.from( + manager.services.keyMappingReverse.get("helloworld") + ); + + assert(providers.includes("test"), "The Provider should be 'test'"); + assert(providers.includes("caller"), "The Provider should be 'test'"); + + expect(caller.services.extractedKey).to.include("helloworld"); + assert( + caller.services.amountOf.get("helloworld") == 2, + "There should be two Provider for this service" + ); + assert( + caller.services.keyMappingReverse.get("helloworld").size == 2, + "There should be two Provider for this service" + ); + assert( + caller.services.conflicts.size == 0, + "There should be no conflict" + ); + assert(caller.serviceExists("helloworld"), "Service should be known!"); + assert( + caller.serviceExists("helloworld2") == false, + "Service should not be known!" + ); + + providers = Array.from( + caller.services.keyMappingReverse.get("helloworld") + ); + + assert(providers.includes("test"), "The Provider should be 'test'"); + assert(providers.includes("caller"), "The Provider should be 'test'"); + + const err = Error("Error not thrown"); + + try { + const result = await caller.methodInterfaceWithOptions.helloworld( + { + timeout: 50, + }, + "Mocha" + ); + throw err; + } catch (e) { + if (e == err) { + throw err; + } + } + }); }); }); diff --git a/lib/dispatcher/RpcManager/NopeRpcManager.ts b/lib/dispatcher/RpcManager/NopeRpcManager.ts index bca632d..a422d9f 100644 --- a/lib/dispatcher/RpcManager/NopeRpcManager.ts +++ b/lib/dispatcher/RpcManager/NopeRpcManager.ts @@ -21,7 +21,7 @@ import { ICallOptions, ICommunicationBridge, IExtraData, - IFunctionOptions, + IServiceOptions, IMapBasedMergeData, INopeDispatcherOptions, INopeEventEmitter, @@ -47,7 +47,7 @@ import { * @export * @class nopeDispatcher */ -export class NopeRpcManager +export class NopeRpcManager implements INopeRpcManager { protected _logger: ILogger; diff --git a/lib/helpers/mapMethods.ts b/lib/helpers/mapMethods.ts index 8fe3784..5f763d2 100644 --- a/lib/helpers/mapMethods.ts +++ b/lib/helpers/mapMethods.ts @@ -12,7 +12,6 @@ import { SPLITCHAR, } from "./objectMethods"; import { getLeastCommonPathSegment } from "./path"; -import { comparePatternAndPath } from "./pathMatchingMethods"; const __sentinal = { unique: "value", @@ -181,8 +180,8 @@ export function tranformMap< ); } else { const data: { - key: ExtractedKey; - value: ExtractedValue; + key: ExtractedKey[]; + value: ExtractedValue[]; } = { key: null, value: null, @@ -193,26 +192,37 @@ export function tranformMap< if (typeof pathExtractedKey === "string") { if (pathExtractedKey.length > 0) { - data.key = rgetattr(v, pathExtractedKey); + data.key = rqueryAttr(v, pathExtractedKey).map( + (item) => item.data + ); } else { - data.key = v; + data.key = [v]; } } else { - data.key = k as any; + data.key = [k] as any; } if (typeof pathExtractedValue === "string") { if (pathExtractedValue.length > 0) { - data.value = rgetattr(v, pathExtractedValue); + data.value = rqueryAttr(v, pathExtractedValue).map( + (item) => item.data + ); } else { - data.value = v; + data.value = [v]; } } else { - data.value = v as any; + data.value = [v] as Array; } - // Manually push the items. - extracted.push(data); + // For every key push the data. + for (const key of data.key) { + data.value.map((item) => + extracted.push({ + key: key, + value: item, + }) + ); + } } // Store the Key. diff --git a/lib/helpers/objectMethods.ts b/lib/helpers/objectMethods.ts index 0f235bc..ca0a08f 100644 --- a/lib/helpers/objectMethods.ts +++ b/lib/helpers/objectMethods.ts @@ -54,6 +54,10 @@ export function rgetattr( } else { /** Otherwise just return the Element */ if (_obj[_path] == null || _obj[_path] == undefined) { + if (_default == _sentinel) { + return null; + } + return _default; } diff --git a/lib/loader/generateNopeBasicPackage.ts b/lib/loader/generateNopeBasicPackage.ts index c2f7bc3..e263604 100644 --- a/lib/loader/generateNopeBasicPackage.ts +++ b/lib/loader/generateNopeBasicPackage.ts @@ -111,7 +111,7 @@ export function generateNopeBasicPackage( }, }, ], - providedFunctions: [], + providedServices: [], requiredPackages: [], types: TYPES, }; diff --git a/lib/loader/nopePackageLoader.ts b/lib/loader/nopePackageLoader.ts index 0612511..7f160ea 100644 --- a/lib/loader/nopePackageLoader.ts +++ b/lib/loader/nopePackageLoader.ts @@ -602,9 +602,9 @@ export class NopePackageLoader implements INopePackageLoader { } // Iterate over the provided Functions: - for (const func of element.providedFunctions) { + for (const func of element.providedServices) { await this.dispatcher.rpcManager.registerService( - func.function, + func.service, func.options ); } diff --git a/lib/module/BaseModule.ts b/lib/module/BaseModule.ts index 561265f..bb1479a 100644 --- a/lib/module/BaseModule.ts +++ b/lib/module/BaseModule.ts @@ -18,7 +18,7 @@ import { INopeCore, INopeEventEmitter } from "../types/nope"; import { IAuthor, IEventOptions, - IFunctionOptions, + IServiceOptions, INopeModule, INopeModuleDescription, IVersion, @@ -73,7 +73,7 @@ export class NopeBaseModule implements INopeModule { string, { method: (...args: any[]) => Promise; - options: IFunctionOptions; + options: IServiceOptions; } >; @@ -100,7 +100,7 @@ export class NopeBaseModule implements INopeModule { * @memberof BaseModule */ public get methods() { - const ret: { [index: string]: IFunctionOptions } = {}; + const ret: { [index: string]: IServiceOptions } = {}; for (const [name, funcs] of this._registeredMethods.entries()) { ret[name] = funcs.options; @@ -151,7 +151,7 @@ export class NopeBaseModule implements INopeModule { public _markedElements: Array<{ accessor: string; - options: IEventOptions | IFunctionOptions; + options: IEventOptions | IServiceOptions; type: "method" | "prop" | "event"; }>; @@ -299,14 +299,14 @@ export class NopeBaseModule implements INopeModule { * * @param {string} name Name of the Method, which is used during registration at the dispatcher * @param {(...args: any[]) => Promise} method The function itself. It must be async. - * @param {IFunctionOptions} options The Options, used for registering. + * @param {IServiceOptions} options The Options, used for registering. * @return {*} {Promise} * @memberof NopeBaseModule */ public async registerMethod( name: string, method: (...args: any[]) => Promise, - options: IFunctionOptions + options: IServiceOptions ): Promise { // Unregister the Function await this.unregisterFunction(name); @@ -386,12 +386,10 @@ export class NopeBaseModule implements INopeModule { /** * Function to return all available Methods. * - * @return {*} {Promise<{ func: (...args: any[]) => Promise; options: IFunctionOptions; }[]>} + * @return {*} {Promise<{ func: (...args: any[]) => Promise; options: IServiceOptions; }[]>} * @memberof NopeBaseModule */ - public async listMethods(): Promise< - { func: (...args: any[]) => Promise; options: IFunctionOptions }[] - > { + public async listMethods() { return Array.from(this._registeredMethods.values()); } @@ -467,7 +465,7 @@ export class NopeBaseModule implements INopeModule { (...args) => { return _this[entry.accessor](...args); }, - entry.options as IFunctionOptions + entry.options as IServiceOptions ); break; case "prop": diff --git a/lib/module/GenericWrapper.ts b/lib/module/GenericWrapper.ts index defa5b6..dc8ecd4 100644 --- a/lib/module/GenericWrapper.ts +++ b/lib/module/GenericWrapper.ts @@ -8,7 +8,7 @@ import { getNopeLogger } from "../logger/getLogger"; import { ICallOptions, INopeCore, INopeEventEmitter } from "../types"; import { IEventOptions, - IFunctionOptions, + IServiceOptions, INopeModuleDescription, } from "../types/nope/nopeModule.interface"; import { INopeObservable } from "../types/nope/nopeObservable.interface"; @@ -260,14 +260,12 @@ export class NopeGenericWrapper extends NopeBaseModule { super(_core); } - public async listMethods(): Promise< - { func: (...args: any[]) => Promise; options: IFunctionOptions }[] - > { + public async listMethods() { const _this = this; return Object.getOwnPropertyNames(this.dynamicInstanceMethods).map( (name) => { return { - func: _this.dynamicInstanceMethods[name], + method: _this.dynamicInstanceMethods[name], options: null, }; } @@ -285,7 +283,7 @@ export class NopeGenericWrapper extends NopeBaseModule { public async registerMethod( name: string, func: (...args: any[]) => Promise, - options: IFunctionOptions + options: IServiceOptions ): Promise { throw Error("Function Should not be called on remote!"); } diff --git a/lib/parsers/open-api/OpenApiParser.ts b/lib/parsers/open-api/OpenApiParser.ts index b6acbc3..594f2ed 100644 --- a/lib/parsers/open-api/OpenApiParser.ts +++ b/lib/parsers/open-api/OpenApiParser.ts @@ -16,7 +16,7 @@ import { replaceAll } from "../../helpers/stringMethods"; import { IJsonSchema } from "../../types/IJSONSchema"; import { INopeDescriptorFunctionParameter } from "../../types/nope/nopeDescriptor.interface"; import { - IFunctionOptions, + IServiceOptions, IParsableDescription, } from "../../types/nope/nopeModule.interface"; @@ -211,7 +211,7 @@ export async function parseModuleToOpenAPI( * @param options */ export async function parseFunctionToOpenAPI( - description: IFunctionOptions, + description: IServiceOptions, options: { outputDir: string; sharedDefinitions: boolean; diff --git a/lib/types/ISystemElements.ts b/lib/types/ISystemElements.ts index 5ad9adb..5a24171 100644 --- a/lib/types/ISystemElements.ts +++ b/lib/types/ISystemElements.ts @@ -1,11 +1,11 @@ import { IJsonSchema } from "./IJSONSchema"; import { - IFunctionOptions, + IServiceOptions, IParsableDescription, } from "./nope/nopeModule.interface"; export interface ISystemElements { modules: IParsableDescription[]; - services: IFunctionOptions[]; + services: IServiceOptions[]; generalInformationModel: IJsonSchema; } diff --git a/lib/types/nope/nopeCommunication.interface.ts b/lib/types/nope/nopeCommunication.interface.ts index a95d47a..50baf48 100644 --- a/lib/types/nope/nopeCommunication.interface.ts +++ b/lib/types/nope/nopeCommunication.interface.ts @@ -5,7 +5,7 @@ import { INopeStatusInfo } from "./nopeConnectivityManager.interface"; import { - IFunctionOptions, + IServiceOptions, INopeModuleDescription, } from "./nopeModule.interface"; import { INopeObservable } from "./nopeObservable.interface"; @@ -206,7 +206,7 @@ export interface IAvailableServicesMsg { * * @type {string[]} */ - services: IFunctionOptions[]; + services: IServiceOptions[]; } export type ITaskCancelationMsg = { diff --git a/lib/types/nope/nopeDispatcher.interface.ts b/lib/types/nope/nopeDispatcher.interface.ts index 2a3ba60..f2e09e3 100644 --- a/lib/types/nope/nopeDispatcher.interface.ts +++ b/lib/types/nope/nopeDispatcher.interface.ts @@ -5,7 +5,7 @@ * @modify date 2021-11-13 14:09:15 * @desc [description] */ -import { IFunctionOptions } from "."; +import { IServiceOptions } from "."; import { IHost, INopeINopeConnectivityOptions, @@ -104,7 +104,7 @@ export interface INopeDispatcherDescription extends INopeStatusInfo { /** * The hosted Services of the Dispatcher */ - services: IFunctionOptions[]; + services: IServiceOptions[]; /** * Events */ diff --git a/lib/types/nope/nopeModule.interface.ts b/lib/types/nope/nopeModule.interface.ts index 2baee43..5b05156 100644 --- a/lib/types/nope/nopeModule.interface.ts +++ b/lib/types/nope/nopeModule.interface.ts @@ -82,10 +82,10 @@ export interface INopeModuleDescription { * * > **key** = `id` of the function * - * @type {{ [index: string]: IFunctionOptions }} + * @type {{ [index: string]: IServiceOptions }} * @memberof INopeModuleDescription */ - readonly methods: { [index: string]: IFunctionOptions }; + readonly methods: { [index: string]: IServiceOptions }; readonly events: { [index: string]: IEventOptions }; @@ -110,15 +110,15 @@ export interface INopeModule extends INopeModuleDescription { * Function used to register a Function * * @param {string} name Name of the Function - * @param {(...args) => Promise} func The Function - * @param {IFunctionOptions} options The Options used during subscription + * @param {(...args) => Promise} method The Function + * @param {IServiceOptions} options The Options used during subscription * @return {*} {Promise} * @memberof IBaseModule */ registerMethod( name: string, - func: (...args) => Promise, - options: IFunctionOptions + method: (...args) => Promise, + options: IServiceOptions ): Promise; /** @@ -162,11 +162,11 @@ export interface INopeModule extends INopeModuleDescription { * Function to list the available Functions of the module. This will hold all available functions * (dynamic and static functions). * - * @return {Promise>} + * @return {Promise>} * @memberof IBaseModule */ listMethods(): Promise< - Array<{ func: (...args) => Promise; options: IFunctionOptions }> + Array<{ method: (...args) => Promise; options: IServiceOptions }> >; /** @@ -207,12 +207,12 @@ export interface INopeModule extends INopeModuleDescription { * Internal Element, which is used to store elements, that should be added * automaticallay. * - * @type {(Array<{accessor: string, options:IEventOptions | IFunctionOptions}>)} + * @type {(Array<{accessor: string, options:IEventOptions | IServiceOptions}>)} * @memberof INopeModule */ _markedElements: Array<{ accessor: string; - options: IEventOptions | IFunctionOptions; + options: IEventOptions | IServiceOptions; type: "method" | "prop" | "event"; }>; } @@ -275,14 +275,14 @@ export interface IEventOptions { * Options, used to register a Function. * * @export - * @interface IFunctionOptions + * @interface IServiceOptions */ -export interface IFunctionOptions extends Partial { +export interface IServiceOptions extends Partial { /** * Instead of generating a uuid an id could be provided * * @type {string} - * @memberof IFunctionOptions + * @memberof IServiceOptions */ id?: string; @@ -290,7 +290,7 @@ export interface IFunctionOptions extends Partial { * Schema of the Function. * * @type {INopeDescriptor} - * @memberof IFunctionOptions + * @memberof IServiceOptions */ schema: INopeDescriptor; @@ -322,7 +322,7 @@ export interface IFunctionOptions extends Partial { * Flag, to indicate, that the Item is dynamic. * * @type {boolean} - * @memberof IFunctionOptions + * @memberof IServiceOptions */ isDynamic?: boolean; } @@ -333,5 +333,5 @@ export interface IFunctionOptions extends Partial { export interface IParsableDescription { name: string; properties: IEventOptions[]; - methods: IFunctionOptions[]; + methods: IServiceOptions[]; } diff --git a/lib/types/nope/nopePackage.interface.ts b/lib/types/nope/nopePackage.interface.ts index 7d1dc81..2e21854 100644 --- a/lib/types/nope/nopePackage.interface.ts +++ b/lib/types/nope/nopePackage.interface.ts @@ -2,7 +2,7 @@ import { interfaces } from "inversify"; import { TInstanceManagerPage, TRenderInstancePage } from "../ui"; import { IInstanceCreationMsg } from "./nopeCommunication.interface"; import { IValidPromise } from "./nopeDispatcher.interface"; -import { IFunctionOptions, INopeModule } from "./nopeModule.interface"; +import { IServiceOptions, INopeModule } from "./nopeModule.interface"; export interface IClassDescriptor { /** @@ -111,9 +111,9 @@ export interface IPackageDescription< * * @memberof IPackageDescription */ - providedFunctions: Array<{ - function: (...args) => IValidPromise; - options: IFunctionOptions; + providedServices: Array<{ + service: (...args) => IValidPromise; + options: IServiceOptions; }>; /** diff --git a/lib/types/nope/nopeRpcManager.interface.ts b/lib/types/nope/nopeRpcManager.interface.ts index cb9a2f9..1e2debe 100644 --- a/lib/types/nope/nopeRpcManager.interface.ts +++ b/lib/types/nope/nopeRpcManager.interface.ts @@ -6,7 +6,7 @@ * @desc [description] */ -import { IFunctionOptions, INopeEventEmitter, INopeObservable } from "."; +import { IServiceOptions, INopeEventEmitter, INopeObservable } from "."; import { IAvailableServicesMsg, ICallOptions, @@ -69,9 +69,7 @@ export interface IRequestTaskWithCallback extends IRequestRpcMsg { * @export * @interface INopeRpcManager */ -export interface INopeRpcManager< - T extends IFunctionOptions = IFunctionOptions -> { +export interface INopeRpcManager { /** * Flag, to show, that the System is ready * @@ -209,7 +207,7 @@ export interface INopeRpcManager< func: (...args) => Promise, options: { addNopeServiceIdPrefix?: boolean; - } & IFunctionOptions + } & IServiceOptions ): (...args) => Promise; /** diff --git a/lib/types/ui/helpers.interface.ts b/lib/types/ui/helpers.interface.ts index e70679e..4af401c 100644 --- a/lib/types/ui/helpers.interface.ts +++ b/lib/types/ui/helpers.interface.ts @@ -9,7 +9,7 @@ import * as plotly from "plotly.js"; import { IJsonSchema } from "../IJSONSchema"; import { IClassDescription, - IFunctionOptions, + IServiceOptions, INopeDispatcher, INopeObservable, } from "../nope/index"; @@ -163,7 +163,7 @@ export interface IUiDefinition { /** * The provided UI-Functions */ - ui: IFunctionOptions["ui"]; + ui: IServiceOptions["ui"]; /** * Original ID of the Function. */ @@ -198,7 +198,7 @@ export interface IUiDefinition { * The Methods of the class */ methods: { - [index: string]: IFunctionOptions["ui"]; + [index: string]: IServiceOptions["ui"]; }; }; }; diff --git a/lib/ui/helpers.nodejs.ts b/lib/ui/helpers.nodejs.ts index 9d5c8c0..5706e8e 100644 --- a/lib/ui/helpers.nodejs.ts +++ b/lib/ui/helpers.nodejs.ts @@ -9,7 +9,7 @@ import "reflect-metadata"; import { createFile } from "../helpers/fileMethods"; import { getCentralDecoratedContainer, - IFunctionOptions, + IServiceOptions, stringifyWithFunctions, } from "../index.browser"; import { listFunctions, listPackages } from "../index.nodejs"; @@ -63,10 +63,8 @@ export async function writeUiFile( CONTAINER.classes.get(cls.description.name)?._markedElements || []; for (const srv of services) { - if (srv.type === "method" && (srv.options as IFunctionOptions).ui) { - itemToAdd.methods[srv.accessor] = ( - srv.options as IFunctionOptions - ).ui; + if (srv.type === "method" && (srv.options as IServiceOptions).ui) { + itemToAdd.methods[srv.accessor] = (srv.options as IServiceOptions).ui; } } @@ -81,7 +79,7 @@ export async function writeUiFile( } // Iterate over the functions and provide their uis. - item.package.providedFunctions.map((funcs) => { + item.package.providedServices.map((funcs) => { if (funcs.options.ui) { // Store the UI definition in the config file. uiFile.functions[funcs.options.id] = { diff --git a/package-lock.json b/package-lock.json index 30140ba..979940e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nope", - "version": "1.4.1", + "version": "1.4.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "nope", - "version": "1.4.1", + "version": "1.4.5", "license": "MIT", "dependencies": { "argparse": "^2.0.1", diff --git a/package.json b/package.json index 663456c..9af50f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nope", - "version": "1.4.3", + "version": "1.4.5", "description": "NoPE Runtime for Nodejs. For Browser-Support please use nope-browser", "files": [ "dist-nodejs/**/*",