Skip to content

Commit

Permalink
chore(core): enable eslint/strict-boolean-expressions & strictNullChe…
Browse files Browse the repository at this point in the history
…cks (#1096)



Co-authored-by: Jan Romann <[email protected]>
  • Loading branch information
danielpeintner and JKRhb authored Sep 27, 2023
1 parent ab1e20a commit 5265b46
Show file tree
Hide file tree
Showing 15 changed files with 128 additions and 138 deletions.
5 changes: 4 additions & 1 deletion packages/core/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"extends": "../../.eslintrc.js"
"extends": "../../.eslintrc.js",
"rules": {
"@typescript-eslint/strict-boolean-expressions": ["error"]
}
}
6 changes: 1 addition & 5 deletions packages/core/src/codecs/json-codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,7 @@ export default class JsonCodec implements ContentCodec {
private subMediaType: string;

constructor(subMediaType?: string) {
if (!subMediaType) {
this.subMediaType = ContentSerdes.DEFAULT; // 'application/json'
} else {
this.subMediaType = subMediaType;
}
this.subMediaType = subMediaType ?? ContentSerdes.DEFAULT;
}

getMediaType(): string {
Expand Down
16 changes: 8 additions & 8 deletions packages/core/src/codecs/netconf-codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,24 +73,24 @@ export default class NetconfCodec implements ContentCodec {
if (hasNamespace) {
// expect to have xmlns
const properties = schema.properties;
if (!properties) {
if (properties == null) {
throw new Error(`Missing "properties" field in TD`);
}
let nsFound = false;
let aliasNs = "";
let value;
for (const key in properties) {
const el = properties[key];
if (!payload[key]) {
if (payload[key] == null) {
throw new Error(`Payload is missing '${key}' field specified in TD`);
}
if (el["nc:attribute"] === true && payload[key]) {
if (el["nc:attribute"] === true && payload[key] != null) {
// if (el.format && el.format === 'urn')
const ns: string = payload[key] as string;
aliasNs = ns.split(":")[ns.split(":").length - 1];
NSs[aliasNs] = payload[key];
nsFound = true;
} else if (payload[key]) {
} else if (payload[key] != null) {
value = payload[key];
}
}
Expand All @@ -102,10 +102,10 @@ export default class NetconfCodec implements ContentCodec {
}
}

if (schema && schema.type && schema.type === "object" && schema.properties) {
if (schema?.type === "object" && schema.properties != null) {
// nested object, go down
let tmpObj;
if (schema.properties && schema["nc:container"]) {
if (schema["nc:container"] != null) {
// check the root level
tmpObj = this.getPayloadNamespaces(schema, payload, NSs, true); // root case
} else {
Expand All @@ -118,10 +118,10 @@ export default class NetconfCodec implements ContentCodec {

// once here schema is properties
for (const key in schema) {
if ((schema[key].type && schema[key].type === "object") || hasNamespace) {
if (schema[key].type === "object" || hasNamespace) {
// go down only if it is a nested object or it has a namespace
let tmpHasNamespace = false;
if (schema[key].properties && schema[key]["nc:container"]) {
if (schema[key].properties != null && schema[key]["nc:container"] != null) {
tmpHasNamespace = true;
}
const tmpObj = this.getPayloadNamespaces(
Expand Down
14 changes: 7 additions & 7 deletions packages/core/src/codecs/octetstream-codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ export default class OctetstreamCodec implements ContentCodec {
debug("OctetstreamCodec parsing", bytes);
debug("Parameters", parameters);

const bigendian = !parameters.byteSeq?.includes(Endianness.LITTLE_ENDIAN); // default to big endian
const bigendian = !(parameters.byteSeq?.includes(Endianness.LITTLE_ENDIAN) === true); // default to big endian
let signed = parameters.signed !== "false"; // default to signed

// check length if specified
if (parameters.length && parseInt(parameters.length) !== bytes.length) {
if (parameters.length != null && parseInt(parameters.length) !== bytes.length) {
throw new Error("Lengths do not match, required: " + parameters.length + " provided: " + bytes.length);
}

Expand All @@ -83,7 +83,7 @@ export default class OctetstreamCodec implements ContentCodec {
}

// Handle byte swapping
if (parameters.byteSeq?.includes("BYTE_SWAP") && dataLength > 1) {
if (parameters.byteSeq?.includes("BYTE_SWAP") === true && dataLength > 1) {
bytes.swap16();
}

Expand Down Expand Up @@ -184,13 +184,13 @@ export default class OctetstreamCodec implements ContentCodec {
valueToBytes(value: unknown, schema?: DataSchema, parameters: { [key: string]: string | undefined } = {}): Buffer {
debug(`OctetstreamCodec serializing '${value}'`);

if (!parameters.length) {
if (parameters.length == null) {
warn("Missing 'length' parameter necessary for write. I'll do my best");
}

const bigendian = !parameters.byteSeq?.includes(Endianness.LITTLE_ENDIAN); // default to bigendian
const bigendian = !(parameters.byteSeq?.includes(Endianness.LITTLE_ENDIAN) === true); // default to bigendian
let signed = parameters.signed !== "false"; // if signed is undefined -> true (default)
let length = parameters.length ? parseInt(parameters.length) : undefined;
let length = parameters.length != null ? parseInt(parameters.length) : undefined;

if (value === undefined) {
throw new Error("Undefined value");
Expand All @@ -212,7 +212,7 @@ export default class OctetstreamCodec implements ContentCodec {

switch (dataType) {
case "boolean":
return Buffer.alloc(length ?? 1, value ? 255 : 0);
return Buffer.alloc(length ?? 1, value != null ? 255 : 0);
case "byte":
case "short":
case "int":
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/codecs/text-codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default class TextCodec implements ContentCodec {
private subMediaType: string;

constructor(subMediaType?: string) {
this.subMediaType = !subMediaType ? "text/plain" : subMediaType;
this.subMediaType = subMediaType == null ? "text/plain" : subMediaType;
}

getMediaType(): string {
Expand Down
64 changes: 30 additions & 34 deletions packages/core/src/consumed-thing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,12 @@ class InternalPropertySubscription extends InternalSubscription {

public async unobserveProperty(options: WoT.InteractionOptions = {}): Promise<void> {
const tp = this.thing.properties[this.name];
if (!tp) {
if (tp == null) {
throw new Error(`ConsumedThing '${this.thing.title}' does not have property ${this.name}`);
}
if (!options.formIndex) {
options.formIndex = this.matchingUnsubscribeForm();
}
options.formIndex ??= this.matchingUnsubscribeForm();
const { form } = this.thing.getClientFor(tp.forms, "unobserveproperty", Affordance.PropertyAffordance, options);
if (!form) {
if (form == null) {
throw new Error(`ConsumedThing '${this.thing.title}' did not get suitable form`);
}

Expand Down Expand Up @@ -219,7 +217,7 @@ class InternalPropertySubscription extends InternalSubscription {
for (let i = 0; i < forms.length; i++) {
let score = 0;
const form = forms[i];
if (form.op === operation || (Array.isArray(form.op) && form.op.includes(operation))) {
if (form.op === operation || (form?.op?.includes(operation) === true && Array.isArray(form.op) === true)) {
score += 1;
}

Expand Down Expand Up @@ -256,7 +254,7 @@ function findFormIndexWithScoring(
for (let i = 0; i < forms.length; i++) {
let score = 0;
const form = forms[i];
if (form.op === operation || (Array.isArray(form.op) && form.op.includes(operation))) {
if (form.op === operation || (form?.op?.includes(operation) === true && Array.isArray(form.op) === true)) {
score += 1;
}

Expand Down Expand Up @@ -295,16 +293,14 @@ class InternalEventSubscription extends InternalSubscription {

public async unsubscribeEvent(options: WoT.InteractionOptions = {}): Promise<void> {
const te = this.thing.events[this.name];
if (!te) {
if (te == null) {
throw new Error(`ConsumedThing '${this.thing.title}' does not have event ${this.name}`);
}

if (!options.formIndex) {
options.formIndex = this.matchingUnsubscribeForm();
}
options.formIndex ??= this.matchingUnsubscribeForm();

const { form } = this.thing.getClientFor(te.forms, "unsubscribeevent", Affordance.EventAffordance, options);
if (!form) {
if (form == null) {
throw new Error(`ConsumedThing '${this.thing.title}' did not get suitable form`);
}

Expand All @@ -317,7 +313,7 @@ class InternalEventSubscription extends InternalSubscription {
private matchingUnsubscribeForm(): number {
const refForm = this.thing.events[this.name].forms[this.formIndex];
// Here we have to keep in mind that op default is ["subscribeevent", "unsubscribeevent"]
if (!refForm.op || (Array.isArray(refForm.op) && refForm.op.includes("unsubscribeevent"))) {
if (refForm.op == null || (Array.isArray(refForm.op) && refForm.op.includes("unsubscribeevent"))) {
// we can re-use the same form for unsubscribe
return this.formIndex;
}
Expand Down Expand Up @@ -450,19 +446,19 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {
for (const s of security) {
const ws = this.securityDefinitions[s + ""]; // String vs. string (fix wot-typescript-definitions?)
// also push nosec in case of proxy
if (ws) {
if (ws != null) {
scs.push(ws);
}
}
return scs;
}

ensureClientSecurity(client: ProtocolClient, form: TD.Form | undefined): void {
if (this.securityDefinitions) {
if (this.securityDefinitions != null) {
const logStatement = () =>
debug(`ConsumedThing '${this.title}' setting credentials for ${client} based on thing security`);

if (form && Array.isArray(form.security) && form.security.length > 0) {
if (form != null && Array.isArray(form.security) && form.security.length > 0) {
// Note security member in form objects overrides (i.e., completely replace) all definitions activated at the Thing level
// see https://www.w3.org/TR/wot-thing-description/#security-serialization-json

Expand All @@ -471,7 +467,7 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {
this.getSecuritySchemes(form.security),
this.getServient().retrieveCredentials(this.id)
);
} else if (this.security && Array.isArray(this.security) && this.security.length > 0) {
} else if (Array.isArray(this.security) && this.security.length > 0) {
logStatement();
client.setSecurity(
this.getSecuritySchemes(this.security as string[]),
Expand Down Expand Up @@ -551,15 +547,15 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {
async readProperty(propertyName: string, options?: WoT.InteractionOptions): Promise<WoT.InteractionOutput> {
// TODO pass expected form op to getClientFor()
const tp = this.properties[propertyName];
if (!tp) {
if (tp == null) {
throw new Error(`ConsumedThing '${this.title}' does not have property ${propertyName}`);
}

let { client, form } = this.getClientFor(tp.forms, "readproperty", Affordance.PropertyAffordance, options);
if (!form) {
if (form == null) {
throw new Error(`ConsumedThing '${this.title}' did not get suitable form`);
}
if (!client) {
if (client == null) {
throw new Error(`ConsumedThing '${this.title}' did not get suitable client for ${form.href}`);
}
debug(`ConsumedThing '${this.title}' reading ${form.href}`);
Expand Down Expand Up @@ -600,7 +596,7 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {
// collect attributes that are "readable" only
const tp = this.properties[propertyName];
const { form } = this.getClientFor(tp.forms, "readproperty", Affordance.PropertyAffordance, options);
if (form) {
if (form != null) {
propertyNames.push(propertyName);
}
}
Expand All @@ -618,14 +614,14 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {
): Promise<void> {
// TODO pass expected form op to getClientFor()
const tp = this.properties[propertyName];
if (!tp) {
if (tp == null) {
throw new Error(`ConsumedThing '${this.title}' does not have property ${propertyName}`);
}
let { client, form } = this.getClientFor(tp.forms, "writeproperty", Affordance.PropertyAffordance, options);
if (!form) {
if (form == null) {
throw new Error(`ConsumedThing '${this.title}' did not get suitable form`);
}
if (!client) {
if (client == null) {
throw new Error(`ConsumedThing '${this.title}' did not get suitable client for ${form.href}`);
}
debug(`ConsumedThing '${this.title}' writing ${form.href} with '${value}'`);
Expand Down Expand Up @@ -661,14 +657,14 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {
options?: WoT.InteractionOptions
): Promise<WoT.InteractionOutput> {
const ta = this.actions[actionName];
if (!ta) {
if (ta == null) {
throw new Error(`ConsumedThing '${this.title}' does not have action ${actionName}`);
}
let { client, form } = this.getClientFor(ta.forms, "invokeaction", Affordance.ActionAffordance, options);
if (!form) {
if (form == null) {
throw new Error(`ConsumedThing '${this.title}' did not get suitable form`);
}
if (!client) {
if (client == null) {
throw new Error(`ConsumedThing '${this.title}' did not get suitable client for ${form.href}`);
}
debug(
Expand All @@ -691,7 +687,7 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {
if (!content.type) content.type = form.contentType ?? "application/json";

// check if returned media type is the same as expected media type (from TD)
if (form.response) {
if (form.response != null) {
if (content.type !== form.response.contentType) {
throw new Error(`Unexpected type in response`);
}
Expand All @@ -714,14 +710,14 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {
options?: WoT.InteractionOptions
): Promise<Subscription> {
const tp = this.properties[name];
if (!tp) {
if (tp == null) {
throw new Error(`ConsumedThing '${this.title}' does not have property ${name}`);
}
const { client, form } = this.getClientFor(tp.forms, "observeproperty", Affordance.PropertyAffordance, options);
if (!form) {
if (form == null) {
throw new Error(`ConsumedThing '${this.title}' did not get suitable form`);
}
if (!client) {
if (client == null) {
throw new Error(`ConsumedThing '${this.title}' did not get suitable client for ${form.href}`);
}
if (this.observedProperties.has(name)) {
Expand Down Expand Up @@ -772,14 +768,14 @@ export default class ConsumedThing extends TD.Thing implements IConsumedThing {
options?: WoT.InteractionOptions
): Promise<Subscription> {
const te = this.events[name];
if (!te) {
if (te == null) {
throw new Error(`ConsumedThing '${this.title}' does not have event ${name}`);
}
const { client, form } = this.getClientFor(te.forms, "subscribeevent", Affordance.EventAffordance, options);
if (!form) {
if (form == null) {
throw new Error(`ConsumedThing '${this.title}' did not get suitable form`);
}
if (!client) {
if (client == null) {
throw new Error(`ConsumedThing '${this.title}' did not get suitable client for ${form.href}`);
}
if (this.subscribedEvents.has(name)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/content-serdes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class ContentSerdes {
private offered: Set<string> = new Set<string>();

public static get(): ContentSerdes {
if (!this.instance) {
if (this.instance == null) {
this.instance = new ContentSerdes();
// JSON
this.instance.addCodec(new JsonCodec(), true);
Expand Down
Loading

0 comments on commit 5265b46

Please sign in to comment.