From 8089283c6b3364a626f045c3bbc1706396910761 Mon Sep 17 00:00:00 2001 From: danielpeintner Date: Tue, 7 Oct 2025 19:29:55 +0200 Subject: [PATCH 1/3] refactor: activate eslint typescript-eslint/no-floating-promises --- eslint.config.mjs | 2 +- packages/core/src/consumed-thing.ts | 2 +- packages/core/src/exposed-thing.ts | 12 ++++++------ packages/core/src/protocol-helpers.ts | 26 ++++++++++++++++++-------- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 6ffc45ab9..31194e93d 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -124,7 +124,7 @@ export default defineConfig([ "@typescript-eslint/no-require-imports": "off", // https://github.com/eclipse-thingweb/node-wot/issues/1430 "@typescript-eslint/prefer-nullish-coalescing": "off", // https://github.com/eclipse-thingweb/node-wot/issues/1430 "@typescript-eslint/no-empty-object-type": "off", // https://github.com/eclipse-thingweb/node-wot/issues/1430 - "@typescript-eslint/no-floating-promises": "off", // https://github.com/eclipse-thingweb/node-wot/issues/1430 + "@typescript-eslint/no-floating-promises": "error", // **************** Enforce usage of `const` over `let` wherever possible, to prevent accidental reassignments "prefer-const": "error", diff --git a/packages/core/src/consumed-thing.ts b/packages/core/src/consumed-thing.ts index c340b9ad8..c05c1633a 100644 --- a/packages/core/src/consumed-thing.ts +++ b/packages/core/src/consumed-thing.ts @@ -306,7 +306,7 @@ class InternalEventSubscription extends InternalSubscription { const formWithoutURIvariables = handleUriVariables(this.thing, te, form, options); debug(`ConsumedThing '${this.thing.title}' unsubscribing to ${form.href}`); - this.client.unlinkResource(formWithoutURIvariables); + await this.client.unlinkResource(formWithoutURIvariables); this.active = false; } diff --git a/packages/core/src/exposed-thing.ts b/packages/core/src/exposed-thing.ts index 51401068d..935a090c6 100644 --- a/packages/core/src/exposed-thing.ts +++ b/packages/core/src/exposed-thing.ts @@ -572,11 +572,11 @@ export default class ExposedThing extends TD.Thing implements WoT.ExposedThing { * * @experimental */ - public handleUnsubscribeEvent( + public async handleUnsubscribeEvent( name: string, listener: ContentListener, options: WoT.InteractionOptions & { formIndex: number } - ): void { + ): Promise { if (this.events[name] != null) { Helpers.validateInteractionOptions(this, this.events[name], options); @@ -595,7 +595,7 @@ export default class ExposedThing extends TD.Thing implements WoT.ExposedThing { } const unsubscribe = this.#eventHandlers.get(name)?.unsubscribe; if (unsubscribe) { - unsubscribe(options); + await unsubscribe(options); } debug(`ExposedThing '${this.title}' unsubscribes from event '${name}'`); } else { @@ -639,11 +639,11 @@ export default class ExposedThing extends TD.Thing implements WoT.ExposedThing { } } - public handleUnobserveProperty( + public async handleUnobserveProperty( name: string, listener: ContentListener, options: WoT.InteractionOptions & { formIndex: number } - ): void { + ): Promise { if (this.properties[name] != null) { Helpers.validateInteractionOptions(this, this.properties[name], options); const formIndex = ProtocolHelpers.getFormIndexForOperation( @@ -663,7 +663,7 @@ export default class ExposedThing extends TD.Thing implements WoT.ExposedThing { const unobserveHandler = this.#propertyHandlers.get(name)?.unobserveHandler; if (unobserveHandler) { - unobserveHandler(options); + await unobserveHandler(options); } } else { throw new Error(`ExposedThing '${this.title}', no property found for '${name}'`); diff --git a/packages/core/src/protocol-helpers.ts b/packages/core/src/protocol-helpers.ts index 1b568e122..97a90a9a1 100644 --- a/packages/core/src/protocol-helpers.ts +++ b/packages/core/src/protocol-helpers.ts @@ -215,17 +215,27 @@ export default class ProtocolHelpers { const reader = stream.getReader(); const result = new ManagedReadable({ read: (size) => { - reader.read().then((data) => { - result.push(data.value); - if (data.done) { - // signal end - result.push(null); - } - }); + reader + .read() + .then((data) => { + result.push(data.value); + if (data.done) { + // signal end + result.push(null); + } + }) + .catch((error) => { + throw error; + }); }, destroy: (error, callback) => { reader.releaseLock(); - stream.cancel(error).then(() => callback(error)); + stream + .cancel(error) + .then(() => callback(error)) + .catch((error) => { + throw error; + }); }, }); result.wotStream = stream as ReadableStream; From c656b00f67248838531e3968ff0eb8ed7de50a40 Mon Sep 17 00:00:00 2001 From: danielpeintner Date: Thu, 9 Oct 2025 12:12:41 +0200 Subject: [PATCH 2/3] fix: issues in core --- packages/core/test/client-test.ts | 65 +++++++++++++++++++++---------- packages/core/test/server-test.ts | 19 ++++++--- 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/packages/core/test/client-test.ts b/packages/core/test/client-test.ts index b640b8f5e..824b470c0 100644 --- a/packages/core/test/client-test.ts +++ b/packages/core/test/client-test.ts @@ -358,9 +358,14 @@ class WoTClientTest { this.clientFactory = new TrapClientFactory(); this.servient.addClientFactory(this.clientFactory); this.servient.addClientFactory(new TDClientFactory()); - this.servient.start().then((myWoT) => { - this.WoT = myWoT; - }); + this.servient + .start() + .then((myWoT) => { + this.WoT = myWoT; + }) + .catch((error) => { + throw error; + }); debug("started test suite"); } @@ -570,11 +575,17 @@ class WoTClientTest { expect(thing).to.have.property("title").that.equals("aThing"); expect(thing).to.have.property("events").that.has.property("anEvent"); return new Promise((resolve) => { - thing.subscribeEvent("anEvent", async (x) => { - const value = await x.value(); - expect(value).to.equal("triggered"); - resolve(true); - }); + thing + .subscribeEvent("anEvent", async (x) => { + const value = await x.value(); + expect(value).to.equal("triggered"); + resolve(true); + }) + .catch((error) => { + throw error; + }); + }).catch((error) => { + throw error; }); } @@ -626,17 +637,25 @@ class WoTClientTest { expect(thing).to.have.property("title").that.equals("aThing"); expect(thing).to.have.property("events").that.has.property("anEvent"); - const subscription = await thing.subscribeEvent("anEvent", () => { - /** */ - }); + const subscription = await thing + .subscribeEvent("anEvent", () => { + /** */ + }) + .catch((error) => { + throw error; + }); await subscription.stop(); return new Promise((resolve) => { - thing.subscribeEvent("anEvent", async (x) => { - const value = await x.value(); - expect(value).to.equal("triggered"); - resolve(true); - }); + thing + .subscribeEvent("anEvent", async (x) => { + const value = await x.value(); + expect(value).to.equal("triggered"); + resolve(true); + }) + .catch((error) => { + throw error; + }); }); } @@ -649,11 +668,15 @@ class WoTClientTest { expect(thing).to.have.property("title").that.equals("aThing"); expect(thing).to.have.property("properties").that.has.property("aPropertyToObserve"); return new Promise((resolve) => { - thing.observeProperty("aPropertyToObserve", async (data) => { - const value = await data.value(); - expect(value).to.equal(12); - resolve(true); - }); + thing + .observeProperty("aPropertyToObserve", async (data) => { + const value = await data.value(); + expect(value).to.equal(12); + resolve(true); + }) + .catch((error) => { + throw error; + }); }); } diff --git a/packages/core/test/server-test.ts b/packages/core/test/server-test.ts index 8216aa370..225cede49 100644 --- a/packages/core/test/server-test.ts +++ b/packages/core/test/server-test.ts @@ -68,9 +68,14 @@ class WoTServerTest { this.servient = new Servient(); this.server = new TestProtocolServer(); this.servient.addServer(this.server); - this.servient.start().then((WoTruntime) => { - this.WoT = WoTruntime; - }); + this.servient + .start() + .then((WoTruntime) => { + this.WoT = WoTruntime; + }) + .catch((error) => { + throw error; + }); debug("started test suite"); } @@ -889,7 +894,9 @@ class WoTServerTest { thing.setPropertyReadHandler("test", callback); - (thing as ExposedThing).handleObserveProperty("test", protocolListener, { formIndex: 0 }); + (thing as ExposedThing).handleObserveProperty("test", protocolListener, { formIndex: 0 }).catch((error) => { + throw error; + }); await (thing).emitPropertyChange("test"); @@ -964,7 +971,9 @@ class WoTServerTest { thing.setEventSubscribeHandler("test", handler); await (thing).handleSubscribeEvent("test", callback, { formIndex: 0 }); (thing).emitEvent("test", null); - (thing).handleUnsubscribeEvent("test", callback, { formIndex: 0 }); + (thing).handleUnsubscribeEvent("test", callback, { formIndex: 0 }).catch((error) => { + throw error; + }); (thing).emitEvent("test", null); return expect(callback).to.have.been.called.once; From c454306f53792f1b8cfaf7d20049d6c88204e895 Mon Sep 17 00:00:00 2001 From: danielpeintner Date: Thu, 9 Oct 2025 14:26:59 +0200 Subject: [PATCH 3/3] refactor: revert changing function signature --- packages/core/src/exposed-thing.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/core/src/exposed-thing.ts b/packages/core/src/exposed-thing.ts index 935a090c6..92e79ae94 100644 --- a/packages/core/src/exposed-thing.ts +++ b/packages/core/src/exposed-thing.ts @@ -572,11 +572,11 @@ export default class ExposedThing extends TD.Thing implements WoT.ExposedThing { * * @experimental */ - public async handleUnsubscribeEvent( + public handleUnsubscribeEvent( name: string, listener: ContentListener, options: WoT.InteractionOptions & { formIndex: number } - ): Promise { + ): void { if (this.events[name] != null) { Helpers.validateInteractionOptions(this, this.events[name], options); @@ -595,7 +595,9 @@ export default class ExposedThing extends TD.Thing implements WoT.ExposedThing { } const unsubscribe = this.#eventHandlers.get(name)?.unsubscribe; if (unsubscribe) { - await unsubscribe(options); + unsubscribe(options).catch((error) => { + throw error; + }); } debug(`ExposedThing '${this.title}' unsubscribes from event '${name}'`); } else { @@ -639,11 +641,11 @@ export default class ExposedThing extends TD.Thing implements WoT.ExposedThing { } } - public async handleUnobserveProperty( + public handleUnobserveProperty( name: string, listener: ContentListener, options: WoT.InteractionOptions & { formIndex: number } - ): Promise { + ): void { if (this.properties[name] != null) { Helpers.validateInteractionOptions(this, this.properties[name], options); const formIndex = ProtocolHelpers.getFormIndexForOperation( @@ -663,7 +665,9 @@ export default class ExposedThing extends TD.Thing implements WoT.ExposedThing { const unobserveHandler = this.#propertyHandlers.get(name)?.unobserveHandler; if (unobserveHandler) { - await unobserveHandler(options); + unobserveHandler(options).catch((error) => { + throw error; + }); } } else { throw new Error(`ExposedThing '${this.title}', no property found for '${name}'`);