Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add guard-for-in eslint rule #1210

Merged
merged 1 commit into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module.exports = {
"@typescript-eslint/prefer-nullish-coalescing": "error",
"unused-imports/no-unused-imports": "error",
"@typescript-eslint/strict-boolean-expressions": "error",
"guard-for-in": "error",
"unused-imports/no-unused-vars": [
"warn",
{
Expand Down
4 changes: 2 additions & 2 deletions packages/binding-coap/src/mdns-introducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ export class MdnsIntroducer {
private determineTarget(): string {
const interfaces = networkInterfaces();

for (const iface in interfaces) {
for (const entry of interfaces[iface] ?? []) {
for (const iface of Object.values(interfaces ?? {})) {
for (const entry of iface ?? []) {
if (entry.internal === false) {
if (entry.family === this.ipAddressFamily) {
return entry.address;
Expand Down
4 changes: 2 additions & 2 deletions packages/binding-http/src/http-browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ export class HttpForm extends TD.Form {

Headers.prototype.raw = function () {
const result: { [key: string]: string[] } = {};
for (const h in this.entries()) {
result[h[0]] = h[1].split(",");
for (const [headerKey, headerValue] of this.entries()) {
result[headerKey] = headerValue.split(",");
}
return result;
};
Expand Down
32 changes: 14 additions & 18 deletions packages/binding-http/src/routes/thing-description.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,31 @@ function resetMultiLangInteraction(
interactions: ThingDescription["properties"] | ThingDescription["actions"] | ThingDescription["events"],
prefLang: string
) {
if (interactions) {
for (const interName in interactions) {
if (interactions != null) {
for (const interaction of Object.values(interactions)) {
// unset any current title and/or description
delete interactions[interName].title;
delete interactions[interName].description;
delete interaction.title;
delete interaction.description;

// use new language title
const titles = interactions[interName].titles;
if (titles) {
for (const titleLang in titles) {
if (titleLang.startsWith(prefLang)) {
interactions[interName].title = titles[titleLang];
}
for (const [titleLang, titleValue] of Object.entries(interaction.titles ?? {})) {
if (titleLang.startsWith(prefLang)) {
interaction.title = titleValue;
break;
}
}

// use new language description
const descriptions = interactions[interName].descriptions;
if (descriptions) {
for (const descLang in descriptions) {
if (descLang.startsWith(prefLang)) {
interactions[interName].description = descriptions[descLang];
}
for (const [descLang, descriptionValue] of Object.entries(interaction.descriptions ?? {})) {
if (descLang.startsWith(prefLang)) {
interaction.description = descriptionValue;
break;
}
}

// unset any multilanguage titles and/or descriptions
delete interactions[interName].titles;
delete interactions[interName].descriptions;
delete interaction.titles;
delete interaction.descriptions;
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/binding-mqtt/src/mqtt-broker-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,15 @@ export default class MqttBrokerServer implements ProtocolServer {

this.things.set(name, thing);

for (const propertyName in thing.properties) {
for (const propertyName of Object.keys(thing.properties)) {
this.exposeProperty(name, propertyName, thing);
}

for (const actionName in thing.actions) {
for (const actionName of Object.keys(thing.actions)) {
this.exposeAction(name, actionName, thing);
}

for (const eventName in thing.events) {
for (const eventName of Object.keys(thing.events)) {
this.exposeEvent(name, eventName, thing);
}

Expand Down
5 changes: 3 additions & 2 deletions packages/binding-netconf/src/codecs/netconf-codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,9 @@ export default class NetconfCodec {
let nsFound = false;
let aliasNs = "";
let value;
for (const key in properties) {
const el = properties[key];
// TODO: Use correct type for el
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const [key, el] of Object.entries(properties) as [string, any]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PropertyElement doesn't work here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, DataSchema is currently defined as an object whose values are typed as any :/ So in this case, we would need to cast. Note also that these are the properties of the DataSchema and not Property Affordances. In any case, the typing here needs to be revisited.

const payloadField = payload[key];
if (payloadField == null) {
throw new Error(`Payload is missing '${key}' field specified in TD`);
Expand Down
17 changes: 6 additions & 11 deletions packages/binding-websockets/src/ws-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ export default class WebSocketServer implements ProtocolServer {
public stop(): Promise<void> {
debug(`WebSocketServer stopping on port ${this.port}`);
return new Promise<void>((resolve, reject) => {
for (const pathSocket in this.socketServers) {
this.socketServers[pathSocket].close();
for (const socketServer of Object.values(this.socketServers)) {
socketServer.close();
}

// stop promise handles all errors from now on
Expand Down Expand Up @@ -162,15 +162,14 @@ export default class WebSocketServer implements ProtocolServer {

// TODO more efficient routing to ExposedThing without ResourceListeners in each server

for (const propertyName in thing.properties) {
for (const [propertyName, property] of Object.entries(thing.properties)) {
const path =
"/" +
encodeURIComponent(urlPath) +
"/" +
this.PROPERTY_DIR +
"/" +
encodeURIComponent(propertyName);
const property = thing.properties[propertyName];

// Populate forms related to the property
for (const address of Helpers.getAddresses()) {
Expand Down Expand Up @@ -231,26 +230,22 @@ export default class WebSocketServer implements ProtocolServer {
});
}

for (const actionName in thing.actions) {
for (const [actionName, action] of Object.entries(thing.actions)) {
const path =
"/" + encodeURIComponent(urlPath) + "/" + this.ACTION_DIR + "/" + encodeURIComponent(actionName);
// eslint-disable-next-line unused-imports/no-unused-vars
const action = thing.actions[actionName];

for (const address of Helpers.getAddresses()) {
const href = `${this.scheme}://${address}:${this.getPort()}${path}`;
const form = new TD.Form(href, ContentSerdes.DEFAULT);
form.op = ["invokeaction"];
thing.actions[actionName].forms.push(form);
action.forms.push(form);
debug(`WebSocketServer on port ${this.getPort()} assigns '${href}' to Action '${actionName}'`);
}
}

for (const eventName in thing.events) {
for (const [eventName, event] of Object.entries(thing.events)) {
const path =
"/" + encodeURIComponent(urlPath) + "/" + this.EVENT_DIR + "/" + encodeURIComponent(eventName);
// eslint-disable-next-line unused-imports/no-unused-vars
const event = thing.events[eventName];

// Populate forms related to the event
for (const address of Helpers.getAddresses()) {
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/codecs/netconf-codec.ts
Copy link
Member Author

@JKRhb JKRhb Jul 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way: I just fully realized only now that there are two netconf-codec.ts files, one in the core package and one in the binding-netconf package. I wonder if we should remove one of them (probably the one in the core package)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uiii, strange and bad. I checked them

and they are similar but not the same at all 🙈

It seems the one in binding-netconf seems more sophisticated. @lukesmolo?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked them

* https://github.com/eclipse-thingweb/node-wot/blob/master/packages/binding-netconf/src/codecs/netconf-codec.ts
  vs.

* https://github.com/eclipse-thingweb/node-wot/blob/master/packages/core/src/codecs/netconf-codec.ts

and they are similar but not the same at all 🙈

Hmm, yeah, if I see it correctly, commit 56797cd intended to move the codec to the binding directory but also left it in the core package 😅

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be moved to its own issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created #1304.
@JKRhb shall we fix it independently and you merge in master in this PR? Would that be okay for you?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this one is already merged, I think we can continue in #1305 independently :)

Copy link
Member

@danielpeintner danielpeintner Jul 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1305 has been merged. @JKRhb maybe you can merge in master and we can continue with merging this PR ...

Copy link
Member

@danielpeintner danielpeintner Jul 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I missed that the PR is already merged 🙈

Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,9 @@ export default class NetconfCodec implements ContentCodec {
let nsFound = false;
let aliasNs = "";
let value;
for (const key in properties) {
const el = properties[key];
// TODO: Use correct type for el
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const [key, el] of Object.entries(properties) as [string, any]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above?

if (payload[key] == null) {
throw new Error(`Payload is missing '${key}' field specified in TD`);
}
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/codecs/octetstream-codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -604,11 +604,12 @@ export default class OctetstreamCodec implements ContentCodec {
}

result = result ?? Buffer.alloc(length);
for (const propertyName in schema.properties) {
// TODO: Use correct type for propertySchema
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const [propertyName, propertySchema] of Object.entries(schema.properties) as [string, any]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing TODO. can't we try to use the inferred type from the removed line below?

const propertySchema = schema.properties[propertyName];

Copy link
Member Author

@JKRhb JKRhb Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing TODO.

Thank you, should be fixed now :)

can't we try to use the inferred type from the removed line below?

const propertySchema = schema.properties[propertyName];

Unfortunately, the type of propertySchema was any here :/ DataSchema seems to be defined like this at the moment in the wot-typescript-definitions:

type DataSchema = { [key: string]: any; };

if (Object.hasOwnProperty.call(value, propertyName) === false) {
throw new Error(`Missing property '${propertyName}'`);
}
const propertySchema = schema.properties[propertyName];
const propertyValue = value[propertyName];
const propertyOffset = parseInt(propertySchema["ex:bitOffset"]);
const propertyLength = parseInt(propertySchema["ex:bitLength"]);
Expand Down
26 changes: 11 additions & 15 deletions packages/core/src/consumed-thing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,19 +381,16 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {
}

extendInteractions(): void {
for (const propertyName in this.properties) {
const newProp = Helpers.extend(
this.properties[propertyName],
new ConsumedThingProperty(propertyName, this)
);
for (const [propertyName, property] of Object.entries(this.properties)) {
const newProp = Helpers.extend(property, new ConsumedThingProperty(propertyName, this));
this.properties[propertyName] = newProp;
}
for (const actionName in this.actions) {
const newAction = Helpers.extend(this.actions[actionName], new ConsumedThingAction(actionName, this));
for (const [actionName, action] of Object.entries(this.actions)) {
const newAction = Helpers.extend(action, new ConsumedThingAction(actionName, this));
this.actions[actionName] = newAction;
}
for (const eventName in this.events) {
const newEvent = Helpers.extend(this.events[eventName], new ConsumedThingEvent(eventName, this));
for (const [eventName, event] of Object.entries(this.events)) {
const newEvent = Helpers.extend(event, new ConsumedThingEvent(eventName, this));
this.events[eventName] = newEvent;
}
}
Expand Down Expand Up @@ -612,14 +609,15 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {

readAllProperties(options?: WoT.InteractionOptions): Promise<WoT.PropertyReadMap> {
const propertyNames: string[] = [];
for (const propertyName in this.properties) {

for (const [propertyName, property] of Object.entries(this.properties)) {
// collect attributes that are "readable" only
const tp = this.properties[propertyName];
const { form } = this.getClientFor(tp.forms, "readproperty", Affordance.PropertyAffordance, options);
const { form } = this.getClientFor(property.forms, "readproperty", Affordance.PropertyAffordance, options);
if (form != null) {
propertyNames.push(propertyName);
}
}

return this._readProperties(propertyNames);
}

Expand Down Expand Up @@ -656,9 +654,7 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {
async writeMultipleProperties(valueMap: WoT.PropertyWriteMap, options?: WoT.InteractionOptions): Promise<void> {
// collect all single promises into array
const promises: Promise<void>[] = [];
for (const propertyName in valueMap) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const value = valueMap.get(propertyName)!;
for (const [propertyName, value] of valueMap.entries()) {
promises.push(this.writeProperty(propertyName, value));
}
// wait for all promises to succeed and create response
Expand Down
12 changes: 4 additions & 8 deletions packages/core/src/exposed-thing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,10 +458,7 @@ export default class ExposedThing extends TD.Thing implements WoT.ExposedThing {
public async handleReadAllProperties(
options: WoT.InteractionOptions & { formIndex: number }
): Promise<PropertyContentMap> {
const propertyNames: string[] = [];
for (const propertyName in this.properties) {
propertyNames.push(propertyName);
}
const propertyNames = Object.keys(this.properties);
return await this._handleReadProperties(propertyNames, options);
}

Expand Down Expand Up @@ -513,16 +510,15 @@ export default class ExposedThing extends TD.Thing implements WoT.ExposedThing {
): Promise<void> {
// collect all single promises into array
const promises: Promise<void>[] = [];
for (const propertyName in valueMap) {
for (const [propertyName, property] of Object.entries(valueMap)) {
// Note: currently only DataSchema properties are supported
const form = this.properties[propertyName].forms.find(
(form) => form.contentType === "application/json" || form.contentType == null
);
if (!form) {
if (form == null) {
continue;
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we know that the property exists
promises.push(this.handleWriteProperty(propertyName, valueMap.get(propertyName)!, options));
promises.push(this.handleWriteProperty(propertyName, property, options));
}
try {
await Promise.all(promises);
Expand Down
22 changes: 10 additions & 12 deletions packages/core/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ export default class Helpers implements Resolver {
} else {
const interfaces = os.networkInterfaces();

for (const iface in interfaces) {
interfaces[iface]?.forEach((entry) => {
for (const iface of Object.values(interfaces)) {
iface?.forEach((entry) => {
debug(`AddressHelper found ${entry.address}`);
if (entry.internal === false) {
if (entry.family === "IPv4") {
Expand Down Expand Up @@ -197,12 +197,12 @@ export default class Helpers implements Resolver {
*/
public static extend<T, U>(first: T, second: U): T & U {
const result = <T & U>{};
for (const id in first) {
(<Record<string, unknown>>result)[id] = (<Record<string, unknown>>first)[id];
for (const [id, value] of Object.entries(first as Record<string, unknown>)) {
(<Record<string, unknown>>result)[id] = value;
}
for (const id in second) {
for (const [id, value] of Object.entries(second as Record<string, unknown>)) {
if (!Object.prototype.hasOwnProperty.call(result, id)) {
(<Record<string, unknown>>result)[id] = (<Record<string, unknown>>second)[id];
(<Record<string, unknown>>result)[id] = value;
}
}
return result;
Expand Down Expand Up @@ -242,9 +242,9 @@ export default class Helpers implements Resolver {
}
}

if (tdSchemaCopy.definitions !== undefined) {
for (const prop in tdSchemaCopy.definitions) {
tdSchemaCopy.definitions[prop] = this.createExposeThingInitSchema(tdSchemaCopy.definitions[prop]);
if (tdSchemaCopy.definitions != null) {
for (const [prop, propValue] of Object.entries(tdSchemaCopy.definitions) ?? []) {
tdSchemaCopy.definitions[prop] = this.createExposeThingInitSchema(propValue);
}
}

Expand Down Expand Up @@ -307,9 +307,7 @@ export default class Helpers implements Resolver {
options = { uriVariables: {} };
}

for (const varKey in thingUriVariables) {
const varValue = thingUriVariables[varKey];

for (const [varKey, varValue] of Object.entries(thingUriVariables)) {
if (!(varKey in uriVariables) && "default" in varValue) {
uriVariables[varKey] = varValue.default;
}
Expand Down
27 changes: 12 additions & 15 deletions packages/core/src/servient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,20 @@ export default class Servient {

// initializing forms fields
thing.forms = [];
for (const name in thing.properties) {
for (const property of Object.values(thing.properties)) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
thing.properties[name].forms = [];
property.forms = [];
}
for (const name in thing.actions) {
for (const action of Object.values(thing.actions)) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
thing.actions[name].forms = [];
action.forms = [];
}
for (const name in thing.events) {
for (const event of Object.values(thing.events)) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
thing.events[name].forms = [];
event.forms = [];
}

const serverPromises: Promise<void>[] = [];
Expand Down Expand Up @@ -178,16 +178,13 @@ export default class Servient {
}

public addCredentials(credentials: Record<string, unknown>): void {
if (typeof credentials === "object") {
for (const i in credentials) {
debug(`Servient storing credentials for '${i}'`);
let currentCredentials = this.credentialStore.get(i);
if (!currentCredentials) {
currentCredentials = [];
this.credentialStore.set(i, currentCredentials);
}
currentCredentials.push(credentials[i]);
for (const [credentialKey, credentialValue] of Object.entries(credentials ?? {})) {
debug(`Servient storing credentials for '${credentialKey}'`);
const currentCredentials = this.credentialStore.get(credentialKey) ?? [];
if (currentCredentials.length === 0) {
this.credentialStore.set(credentialKey, currentCredentials);
}
currentCredentials.push(credentialValue);
}
}

Expand Down
Loading
Loading