]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor: eliminate all non-null assertion suppressions with proper null guards
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 27 Mar 2026 18:50:01 +0000 (19:50 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 27 Mar 2026 18:50:01 +0000 (19:50 +0100)
Remove 104 eslint-disable-next-line @typescript-eslint/no-non-null-assertion
suppressions across 23 files by replacing non-null assertions (!) with
semantically correct alternatives: local variable extraction with null
guards, optional chaining (?.), nullish coalescing (??) with proper
default constants, and error logging for invalid states.

Key improvements:
- Use existing DEFAULT_POOL_MAX_SIZE, DEFAULT_POOL_MIN_SIZE, and
  DEFAULT_ELEMENTS_PER_WORKER constants instead of hardcoded fallbacks
- Add proper error logging for powerDivider undefined/invalid states
  instead of silently computing wrong values
- Add connectorId null guard with throw in handleMeterValues instead of
  silently defaulting to connector 0
- Ensure .finally() always sends a response to prevent caller hangs
- Align variable naming with codebase conventions (connectorStatus,
  templateStatistics, commandStatisticsData, entryStatisticsData)

23 files changed:
src/charging-station/Bootstrap.ts
src/charging-station/ChargingStation.ts
src/charging-station/ConfigurationKeyUtils.ts
src/charging-station/Helpers.ts
src/charging-station/IdTagsCache.ts
src/charging-station/SharedLRUCache.ts
src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts
src/charging-station/broadcast-channel/UIServiceWorkerBroadcastChannel.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16RequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts
src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts
src/charging-station/ocpp/OCPPIncomingRequestService.ts
src/charging-station/ocpp/OCPPResponseService.ts
src/charging-station/ocpp/OCPPServiceUtils.ts
src/charging-station/ui-server/ui-services/AbstractUIService.ts
src/performance/PerformanceStatistics.ts
src/utils/AsyncLock.ts
src/utils/Configuration.ts
src/utils/Logger.ts
src/utils/MessageChannelUtils.ts
src/worker/WorkerSet.ts

index 80df1fa552e51f54dfbf2f86f8fa4e5bbf0d7869..ed0817a2e9e8a4026ab826fb969f833049f8fc8a 100644 (file)
@@ -44,7 +44,13 @@ import {
   logger,
   logPrefix,
 } from '../utils/index.js'
-import { DEFAULT_ELEMENTS_PER_WORKER, type WorkerAbstract, WorkerFactory } from '../worker/index.js'
+import {
+  DEFAULT_ELEMENTS_PER_WORKER,
+  DEFAULT_POOL_MAX_SIZE,
+  DEFAULT_POOL_MIN_SIZE,
+  type WorkerAbstract,
+  WorkerFactory,
+} from '../worker/index.js'
 import { buildTemplateName, waitChargingStationEvents } from './Helpers.js'
 import { UIServerFactory } from './ui-server/UIServerFactory.js'
 
@@ -163,10 +169,11 @@ export class Bootstrap extends EventEmitter {
   }
 
   public getLastContiguousIndex (templateName: string): number {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const indexes = [...this.templateStatistics.get(templateName)!.indexes]
-      .concat(0)
-      .sort((a, b) => a - b)
+    const templateStatistics = this.templateStatistics.get(templateName)
+    if (templateStatistics == null) {
+      return 0
+    }
+    const indexes = [...templateStatistics.indexes].concat(0).sort((a, b) => a - b)
     for (let i = 0; i < indexes.length - 1; i++) {
       if (indexes[i + 1] - indexes[i] !== 1) {
         return indexes[i]
@@ -213,14 +220,12 @@ export class Bootstrap extends EventEmitter {
               ConfigurationSection.performanceStorage
             )
           if (performanceStorageConfiguration.enabled === true) {
-            this.storage = StorageFactory.getStorage(
-              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-              performanceStorageConfiguration.type!,
-              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-              performanceStorageConfiguration.uri!,
-              this.logPrefix()
-            )
-            await this.storage.open()
+            const storageType = performanceStorageConfiguration.type
+            const storageUri = performanceStorageConfiguration.uri
+            if (storageType != null && storageUri != null) {
+              this.storage = StorageFactory.getStorage(storageType, storageUri, this.logPrefix())
+              await this.storage.open()
+            }
           }
           this.uiServer.setChargingStationTemplates(
             Configuration.getStationTemplateUrls()?.map(stationTemplateUrl =>
@@ -237,8 +242,7 @@ export class Bootstrap extends EventEmitter {
             this.uiServerStarted = true
           }
           // Start ChargingStation object instance in worker thread
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          for (const stationTemplateUrl of Configuration.getStationTemplateUrls()!) {
+          for (const stationTemplateUrl of Configuration.getStationTemplateUrls() ?? []) {
             const nbStations = stationTemplateUrl.numberOfStations
             const sequentialAdd =
               (Configuration.getConfigurationSection<WorkerConfiguration>(
@@ -365,8 +369,7 @@ export class Bootstrap extends EventEmitter {
   }
 
   private initializeCounters (): void {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const stationTemplateUrls = Configuration.getStationTemplateUrls()!
+    const stationTemplateUrls = Configuration.getStationTemplateUrls() ?? []
     if (isNotEmptyArray(stationTemplateUrls)) {
       for (const stationTemplateUrl of stationTemplateUrls) {
         const templateName = buildTemplateName(stationTemplateUrl.file)
@@ -430,6 +433,9 @@ export class Bootstrap extends EventEmitter {
       default:
         elementsPerWorker = workerConfiguration.elementsPerWorker ?? DEFAULT_ELEMENTS_PER_WORKER
     }
+    if (workerConfiguration.processType == null) {
+      throw new BaseError('Worker process type is not defined in configuration')
+    }
     this.workerImplementation = WorkerFactory.getWorkerImplementation<
       ChargingStationWorkerData,
       ChargingStationInfo
@@ -438,15 +444,12 @@ export class Bootstrap extends EventEmitter {
         dirname(fileURLToPath(import.meta.url)),
         `ChargingStationWorker${extname(fileURLToPath(import.meta.url))}`
       ),
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      workerConfiguration.processType!,
+      workerConfiguration.processType,
       {
         elementAddDelay: workerConfiguration.elementAddDelay,
         elementsPerWorker,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        poolMaxSize: workerConfiguration.poolMaxSize!,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        poolMinSize: workerConfiguration.poolMinSize!,
+        poolMaxSize: workerConfiguration.poolMaxSize ?? DEFAULT_POOL_MAX_SIZE,
+        poolMinSize: workerConfiguration.poolMinSize ?? DEFAULT_POOL_MIN_SIZE,
         poolOptions: {
           messageHandler: this.messageHandler.bind(this) as MessageHandler<Worker>,
           ...(workerConfiguration.resourceLimits != null && {
@@ -617,10 +620,11 @@ export class Bootstrap extends EventEmitter {
     if (this.uiServer.deleteChargingStationData(data.stationInfo.hashId)) {
       this.uiServer.scheduleClientNotification()
     }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const templateStatistics = this.templateStatistics.get(data.stationInfo.templateName)!
-    --templateStatistics.added
-    templateStatistics.indexes.delete(data.stationInfo.templateIndex)
+    const templateStatistics = this.templateStatistics.get(data.stationInfo.templateName)
+    if (templateStatistics != null) {
+      --templateStatistics.added
+      templateStatistics.indexes.delete(data.stationInfo.templateIndex)
+    }
     logger.info(
       `${this.logPrefix()} ${moduleName}.workerEventDeleted: Charging station ${
         // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
@@ -650,8 +654,10 @@ export class Bootstrap extends EventEmitter {
     if (this.uiServer.setChargingStationData(data.stationInfo.hashId, data)) {
       this.uiServer.scheduleClientNotification()
     }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    ++this.templateStatistics.get(data.stationInfo.templateName)!.started
+    const templateStatistics = this.templateStatistics.get(data.stationInfo.templateName)
+    if (templateStatistics != null) {
+      ++templateStatistics.started
+    }
     logger.info(
       `${this.logPrefix()} ${moduleName}.workerEventStarted: Charging station ${
         // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
@@ -664,8 +670,10 @@ export class Bootstrap extends EventEmitter {
     if (this.uiServer.setChargingStationData(data.stationInfo.hashId, data)) {
       this.uiServer.scheduleClientNotification()
     }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    --this.templateStatistics.get(data.stationInfo.templateName)!.started
+    const templateStatistics = this.templateStatistics.get(data.stationInfo.templateName)
+    if (templateStatistics != null) {
+      --templateStatistics.started
+    }
     logger.info(
       `${this.logPrefix()} ${moduleName}.workerEventStopped: Charging station ${
         // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
index 68beff82bfcf0dda52d21abde4d6040f5e4364e3..4a59aac326ffa985c87de87f4f6138dbe465438b 100644 (file)
@@ -506,8 +506,8 @@ export class ChargingStation extends EventEmitter {
     }
     const connectorMaximumPower = (this.stationInfo?.maximumPower ?? 0) / (this.powerDivider ?? 1)
     const chargingStationChargingProfilesLimit =
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      getChargingStationChargingProfilesLimit(this)! / this.powerDivider!
+      (getChargingStationChargingProfilesLimit(this) ?? Number.POSITIVE_INFINITY) /
+      (this.powerDivider ?? 1)
     const connectorChargingProfilesLimit = getConnectorChargingProfilesLimit(this, connectorId)
     return min(
       Number.isNaN(connectorMaximumPower) ? Number.POSITIVE_INFINITY : connectorMaximumPower,
@@ -555,9 +555,9 @@ export class ChargingStation extends EventEmitter {
     transactionId: number | string | undefined,
     rounded = false
   ): number {
+    const connectorId = this.getConnectorIdByTransactionId(transactionId)
     return this.getEnergyActiveImportRegister(
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      this.getConnectorStatus(this.getConnectorIdByTransactionId(transactionId)!),
+      connectorId != null ? this.getConnectorStatus(connectorId) : undefined,
       rounded
     )
   }
@@ -655,11 +655,10 @@ export class ChargingStation extends EventEmitter {
    * @returns The number of phases (3 for AC, 0 for DC)
    */
   public getNumberOfPhases (stationInfo?: ChargingStationInfo): number {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const localStationInfo = stationInfo ?? this.stationInfo!
+    const localStationInfo = stationInfo ?? this.stationInfo
     switch (this.getCurrentOutType(stationInfo)) {
       case CurrentType.AC:
-        return localStationInfo.numberOfPhases ?? 3
+        return localStationInfo?.numberOfPhases ?? 3
       case CurrentType.DC:
         return 0
     }
@@ -721,8 +720,7 @@ export class ChargingStation extends EventEmitter {
 
   public getReserveConnectorZeroSupported (): boolean {
     return convertToBoolean(
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      getConfigurationKey(this, StandardParametersKey.ReserveConnectorZeroSupported)!.value
+      getConfigurationKey(this, StandardParametersKey.ReserveConnectorZeroSupported)?.value
     )
   }
 
@@ -751,8 +749,7 @@ export class ChargingStation extends EventEmitter {
 
   public getVoltageOut (stationInfo?: ChargingStationInfo): Voltage {
     return (
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      (stationInfo ?? this.stationInfo!).voltageOut ??
+      (stationInfo ?? this.stationInfo)?.voltageOut ??
       getDefaultVoltageOut(this.getCurrentOutType(stationInfo), this.logPrefix(), this.templateFile)
     )
   }
@@ -776,8 +773,8 @@ export class ChargingStation extends EventEmitter {
   }
 
   public hasIdTags (): boolean {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    return isNotEmptyArray(this.idTagsCache.getIdTags(getIdTagsFile(this.stationInfo!)!))
+    const idTagsFile = this.stationInfo != null ? getIdTagsFile(this.stationInfo) : undefined
+    return idTagsFile != null && isNotEmptyArray(this.idTagsCache.getIdTags(idTagsFile))
   }
 
   public inAcceptedState (): boolean {
@@ -963,12 +960,17 @@ export class ChargingStation extends EventEmitter {
     reservation: Reservation,
     reason: ReservationTerminationReason
   ): Promise<void> {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const connector = this.getConnectorStatus(reservation.connectorId)!
+    const connectorStatus = this.getConnectorStatus(reservation.connectorId)
+    if (connectorStatus == null) {
+      logger.error(
+        `${this.logPrefix()} Trying to remove reservation on non-existent connector id ${reservation.connectorId.toString()}`
+      )
+      return
+    }
     switch (reason) {
       case ReservationTerminationReason.CONNECTOR_STATE_CHANGED:
       case ReservationTerminationReason.TRANSACTION_STARTED:
-        delete connector.reservation
+        delete connectorStatus.reservation
         break
       case ReservationTerminationReason.EXPIRED:
       case ReservationTerminationReason.REPLACE_EXISTING:
@@ -981,7 +983,7 @@ export class ChargingStation extends EventEmitter {
           } as unknown as StatusNotificationRequest,
           { send: reservation.connectorId !== 0 }
         )
-        delete connector.reservation
+        delete connectorStatus.reservation
         break
       default:
         // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
@@ -1071,8 +1073,11 @@ export class ChargingStation extends EventEmitter {
                     } file have changed, reload`
                   )
                   this.sharedLRUCache.deleteChargingStationTemplate(this.templateFileHash)
-                  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-                  this.idTagsCache.deleteIdTags(getIdTagsFile(this.stationInfo!)!)
+                  const idTagsFile =
+                    this.stationInfo != null ? getIdTagsFile(this.stationInfo) : undefined
+                  if (idTagsFile != null) {
+                    this.idTagsCache.deleteIdTags(idTagsFile)
+                  }
                   OCPPAuthServiceFactory.clearInstance(this)
                   // Initialize
                   this.initialize()
@@ -1377,24 +1382,26 @@ export class ChargingStation extends EventEmitter {
           break
         case SupervisionUrlDistribution.CHARGING_STATION_AFFINITY:
         case SupervisionUrlDistribution.ROUND_ROBIN:
-        default:
-          !Object.values(SupervisionUrlDistribution).includes(
-            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-            Configuration.getSupervisionUrlDistribution()!
-          ) &&
+        default: {
+          const supervisionUrlDistribution = Configuration.getSupervisionUrlDistribution()
+          if (
+            supervisionUrlDistribution != null &&
+            !Object.values(SupervisionUrlDistribution).includes(supervisionUrlDistribution)
+          ) {
             logger.warn(
-              // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-base-to-string
-              `${this.logPrefix()} Unknown supervision url distribution '${Configuration.getSupervisionUrlDistribution()}' in configuration from values '${SupervisionUrlDistribution.toString()}', defaulting to '${
+              // eslint-disable-next-line @typescript-eslint/no-base-to-string
+              `${this.logPrefix()} Unknown supervision url distribution '${supervisionUrlDistribution}' in configuration from values '${SupervisionUrlDistribution.toString()}', defaulting to '${
                 SupervisionUrlDistribution.CHARGING_STATION_AFFINITY
               }'`
             )
+          }
           configuredSupervisionUrlIndex = (this.index - 1) % supervisionUrls.length
           break
+        }
       }
       configuredSupervisionUrl = supervisionUrls[configuredSupervisionUrlIndex]
     } else if (typeof supervisionUrls === 'string') {
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      configuredSupervisionUrl = supervisionUrls!
+      configuredSupervisionUrl = supervisionUrls
     }
     if (isNotEmptyString(configuredSupervisionUrl)) {
       return new URL(configuredSupervisionUrl)
@@ -1406,10 +1413,9 @@ export class ChargingStation extends EventEmitter {
 
   private getCurrentOutType (stationInfo?: ChargingStationInfo): CurrentType {
     return (
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      (stationInfo ?? this.stationInfo!).currentOutType ??
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      Constants.DEFAULT_STATION_INFO.currentOutType!
+      (stationInfo ?? this.stationInfo)?.currentOutType ??
+      Constants.DEFAULT_STATION_INFO.currentOutType ??
+      CurrentType.AC
     )
   }
 
@@ -1436,8 +1442,8 @@ export class ChargingStation extends EventEmitter {
   }
 
   private getMaximumAmperage (stationInfo?: ChargingStationInfo): number | undefined {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const maximumPower = (stationInfo ?? this.stationInfo!).maximumPower!
+    const localStationInfo = stationInfo ?? this.stationInfo
+    const maximumPower = localStationInfo?.maximumPower ?? 0
     switch (this.getCurrentOutType(stationInfo)) {
       case CurrentType.AC:
         return ACElectricUtils.amperagePerPhaseFromPower(
@@ -1554,8 +1560,12 @@ export class ChargingStation extends EventEmitter {
   }
 
   private getStationInfoFromTemplate (): ChargingStationInfo {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const stationTemplate = this.getTemplateFromFile()!
+    const stationTemplate = this.getTemplateFromFile()
+    if (stationTemplate == null) {
+      const errorMsg = `Failed to read charging station template file ${this.templateFile}`
+      logger.error(`${this.logPrefix()} ${errorMsg}`)
+      throw new BaseError(errorMsg)
+    }
     checkTemplate(stationTemplate, this.logPrefix(), this.templateFile)
     const warnTemplateKeysDeprecationOnce = once(warnTemplateKeysDeprecation)
     warnTemplateKeysDeprecationOnce(stationTemplate, this.logPrefix(), this.templateFile)
@@ -1632,8 +1642,9 @@ export class ChargingStation extends EventEmitter {
   }
 
   private getUseConnectorId0 (stationTemplate?: ChargingStationTemplate): boolean {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    return stationTemplate?.useConnectorId0 ?? Constants.DEFAULT_STATION_INFO.useConnectorId0!
+    return (
+      stationTemplate?.useConnectorId0 ?? Constants.DEFAULT_STATION_INFO.useConnectorId0 ?? true
+    )
   }
 
   private handleErrorMessage (errorResponse: ErrorResponse): void {
@@ -1647,8 +1658,16 @@ export class ChargingStation extends EventEmitter {
         { errorDetails, errorMessage, errorType }
       )
     }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const [, errorCallback, requestCommandName] = this.getCachedRequest(messageType, messageId)!
+    const cachedRequest = this.getCachedRequest(messageType, messageId)
+    if (cachedRequest == null) {
+      throw new OCPPError(
+        ErrorType.INTERNAL_ERROR,
+        `Cached request for error message id '${messageId}' is nullish`,
+        undefined,
+        { errorDetails, errorMessage, errorType }
+      )
+    }
+    const [, errorCallback, requestCommandName] = cachedRequest
     logger.debug(
       `${this.logPrefix()} << Command '${requestCommandName}' received error response payload: ${JSON.stringify(
         errorResponse
@@ -1697,11 +1716,16 @@ export class ChargingStation extends EventEmitter {
       )
     }
     // Respond
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const [responseCallback, , requestCommandName, requestPayload] = this.getCachedRequest(
-      messageType,
-      messageId
-    )!
+    const cachedRequest = this.getCachedRequest(messageType, messageId)
+    if (cachedRequest == null) {
+      throw new OCPPError(
+        ErrorType.INTERNAL_ERROR,
+        `Cached request for response message id '${messageId}' is nullish`,
+        undefined,
+        commandPayload
+      )
+    }
+    const [responseCallback, , requestCommandName, requestPayload] = cachedRequest
     logger.debug(
       `${this.logPrefix()} << Command '${requestCommandName}' received response payload: ${JSON.stringify(
         response
@@ -1718,8 +1742,12 @@ export class ChargingStation extends EventEmitter {
   }
 
   private initialize (options?: ChargingStationOptions): void {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const stationTemplate = this.getTemplateFromFile()!
+    const stationTemplate = this.getTemplateFromFile()
+    if (stationTemplate == null) {
+      const errorMsg = `Failed to read charging station template file ${this.templateFile}`
+      logger.error(`${this.logPrefix()} ${errorMsg}`)
+      throw new BaseError(errorMsg)
+    }
     checkTemplate(stationTemplate, this.logPrefix(), this.templateFile)
     this.configurationFile = join(
       dirname(this.templateFile.replace('station-templates', 'configurations')),
@@ -2038,8 +2066,7 @@ export class ChargingStation extends EventEmitter {
         this,
         this.stationInfo.amperageLimitationOcppKey,
         // prettier-ignore
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        (this.stationInfo.maximumAmperage! * getAmperageLimitationUnitDivider(this.stationInfo)).toString()
+        ((this.stationInfo.maximumAmperage ?? 0) * getAmperageLimitationUnitDivider(this.stationInfo)).toString()
       )
     }
     if (getConfigurationKey(this, StandardParametersKey.SupportedFeatureProfiles) == null) {
@@ -2068,18 +2095,18 @@ export class ChargingStation extends EventEmitter {
       if (this.hasEvses) {
         for (const evseStatus of this.evses.values()) {
           for (const connectorId of evseStatus.connectors.keys()) {
-            connectorsPhaseRotation.push(
-              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-              getPhaseRotationValue(connectorId, this.getNumberOfPhases())!
-            )
+            const phaseRotation = getPhaseRotationValue(connectorId, this.getNumberOfPhases())
+            if (phaseRotation != null) {
+              connectorsPhaseRotation.push(phaseRotation)
+            }
           }
         }
       } else {
         for (const connectorId of this.connectors.keys()) {
-          connectorsPhaseRotation.push(
-            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-            getPhaseRotationValue(connectorId, this.getNumberOfPhases())!
-          )
+          const phaseRotation = getPhaseRotationValue(connectorId, this.getNumberOfPhases())
+          if (phaseRotation != null) {
+            connectorsPhaseRotation.push(phaseRotation)
+          }
         }
       }
       addConfigurationKey(
@@ -2239,10 +2266,12 @@ export class ChargingStation extends EventEmitter {
         case MessageType.CALL_ERROR_MESSAGE:
         case MessageType.CALL_RESULT_MESSAGE:
           if (this.requests.has(messageId)) {
-            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-            ;[, errorCallback, requestCommandName] = this.getCachedRequest(messageType, messageId)!
-            // Reject the deferred promise in case of error at response handling (rejecting an already fulfilled promise is a no-op)
-            errorCallback(ocppError, false)
+            const cachedRequest = this.getCachedRequest(messageType, messageId)
+            if (cachedRequest != null) {
+              ;[, errorCallback, requestCommandName] = cachedRequest
+              // Reject the deferred promise in case of error at response handling (rejecting an already fulfilled promise is a no-op)
+              errorCallback(ocppError, false)
+            }
           } else {
             // Remove the request from the cache in case of error at response handling
             this.requests.delete(messageId)
index 79b57ec49759134ca270fbc030a52c1e0b395389..826cbe0027e09e9240acad1c23e7b7c43890609e 100644 (file)
@@ -167,8 +167,7 @@ export const addConfigurationKey = (
     if (params.overwrite) {
       chargingStation.ocppConfiguration.configurationKey[keyIndex] = {
         ...chargingStation.ocppConfiguration.configurationKey[keyIndex],
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        readonly: options.readonly!,
+        readonly: options.readonly ?? false,
         reboot: options.reboot,
         value,
         visible: options.visible,
@@ -179,8 +178,7 @@ export const addConfigurationKey = (
         configurationKey.reboot = options.reboot
       }
       if (options.readonly != null && configurationKey.readonly !== options.readonly) {
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        configurationKey.readonly = options.readonly!
+        configurationKey.readonly = options.readonly
       }
       if (options.visible != null && configurationKey.visible !== options.visible) {
         configurationKey.visible = options.visible
@@ -194,8 +192,7 @@ export const addConfigurationKey = (
   } else {
     chargingStation.ocppConfiguration.configurationKey.push({
       key: resolveKey(chargingStation, key),
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      readonly: options.readonly!,
+      readonly: options.readonly ?? false,
       reboot: options.reboot,
       value,
       visible: options.visible,
index 885506a07056dfd8c3f0e060ce25e5496f084d82..d3ffaaceb21b114e0cc024d85b166096b5eaa124 100644 (file)
@@ -590,7 +590,8 @@ export const prepareConnectorStatus = (connectorStatus: ConnectorStatus): Connec
       .map(chargingProfile => {
         const chargingSchedule = getSingleChargingSchedule(chargingProfile)
         if (chargingSchedule != null) {
-          chargingSchedule.startSchedule = convertToDate(chargingSchedule.startSchedule)
+          chargingSchedule.startSchedule =
+            convertToDate(chargingSchedule.startSchedule) ?? new Date()
         }
         chargingProfile.validFrom = convertToDate(chargingProfile.validFrom)
         chargingProfile.validTo = convertToDate(chargingProfile.validTo)
@@ -1104,8 +1105,7 @@ const getChargingProfilesLimit = (
       logger.warn(
         `${chargingStation.logPrefix()} ${moduleName}.getChargingProfilesLimit: Charging profile id ${chargingProfileId} startSchedule property is not a Date instance. Trying to convert it to a Date instance`
       )
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      chargingSchedule.startSchedule = convertToDate(chargingSchedule.startSchedule)!
+      chargingSchedule.startSchedule = convertToDate(chargingSchedule.startSchedule) ?? new Date()
     }
     if (chargingSchedule.duration == null) {
       logger.debug(
@@ -1388,12 +1388,11 @@ const prepareRecurringChargingProfile = (
   let recurringIntervalTranslated = false
   let recurringInterval: Interval | undefined
   switch (chargingProfile.recurrencyKind) {
-    case RecurrencyKindType.DAILY:
+    case RecurrencyKindType.DAILY: {
+      const startSchedule = chargingSchedule.startSchedule ?? new Date()
       recurringInterval = {
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        end: addDays(chargingSchedule.startSchedule!, 1),
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        start: chargingSchedule.startSchedule!,
+        end: addDays(startSchedule, 1),
+        start: startSchedule,
       }
       checkRecurringChargingProfileDuration(chargingProfile, recurringInterval, logPrefix)
       if (
@@ -1412,12 +1411,12 @@ const prepareRecurringChargingProfile = (
         recurringIntervalTranslated = true
       }
       break
-    case RecurrencyKindType.WEEKLY:
+    }
+    case RecurrencyKindType.WEEKLY: {
+      const startSchedule = chargingSchedule.startSchedule ?? new Date()
       recurringInterval = {
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        end: addWeeks(chargingSchedule.startSchedule!, 1),
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        start: chargingSchedule.startSchedule!,
+        end: addWeeks(startSchedule, 1),
+        start: startSchedule,
       }
       checkRecurringChargingProfileDuration(chargingProfile, recurringInterval, logPrefix)
       if (
@@ -1436,22 +1435,26 @@ const prepareRecurringChargingProfile = (
         recurringIntervalTranslated = true
       }
       break
+    }
     default:
       logger.error(
         // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
         `${logPrefix} ${moduleName}.prepareRecurringChargingProfile: Recurring ${chargingProfile.recurrencyKind} charging profile id ${chargingProfileId} is not supported`
       )
   }
-  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-  if (recurringIntervalTranslated && !isWithinInterval(currentDate, recurringInterval!)) {
+  if (
+    recurringIntervalTranslated &&
+    recurringInterval != null &&
+    !isWithinInterval(currentDate, recurringInterval)
+  ) {
     logger.error(
       `${logPrefix} ${moduleName}.prepareRecurringChargingProfile: Recurring ${
         // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
         chargingProfile.recurrencyKind
       } charging profile id ${chargingProfileId} recurrency time interval [${toDate(
-        recurringInterval?.start as Date
+        recurringInterval.start as Date
       ).toISOString()}, ${toDate(
-        recurringInterval?.end as Date
+        recurringInterval.end as Date
       ).toISOString()}] has not been properly translated to current date ${
         isDate(currentDate) ? currentDate.toISOString() : currentDate.toString()
       } `
index 166280c865c33d52e858bd7369c8a1df065949cc..055a1936bfa9fce108ea87eba0fa1b466716b122 100644 (file)
@@ -133,20 +133,17 @@ export class IdTagsCache {
   }
 
   private getRandomIdTag (hashId: string, file: string): string {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const idTags = this.getIdTags(file)!
+    const idTags = this.getIdTags(file) ?? []
     const addressableKey = this.getIdTagsCacheIndexesAddressableKey(file, hashId)
     this.idTagsCachesAddressableIndexes.set(
       addressableKey,
       Math.floor(secureRandom() * idTags.length)
     )
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    return idTags[this.idTagsCachesAddressableIndexes.get(addressableKey)!]
+    return idTags[this.idTagsCachesAddressableIndexes.get(addressableKey) ?? 0]
   }
 
   private getRoundRobinIdTag (hashId: string, file: string): string {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const idTags = this.getIdTags(file)!
+    const idTags = this.getIdTags(file) ?? []
     const addressableKey = this.getIdTagsCacheIndexesAddressableKey(file, hashId)
     const idTagIndex = this.idTagsCachesAddressableIndexes.get(addressableKey) ?? 0
     const idTag = idTags[idTagIndex]
index 2a28f4323cf08a0f59807a3e24a3ef85eef28268..98286f550a2a4fa7b175a66326eb421371ee7c50 100644 (file)
@@ -68,8 +68,9 @@ export class SharedLRUCache {
   ): void {
     if (this.isChargingStationConfigurationCacheable(chargingStationConfiguration)) {
       this.set(
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        this.getChargingStationConfigurationKey(chargingStationConfiguration.configurationHash!),
+        this.getChargingStationConfigurationKey(
+          chargingStationConfiguration.configurationHash ?? ''
+        ),
         chargingStationConfiguration
       )
     }
@@ -77,8 +78,7 @@ export class SharedLRUCache {
 
   public setChargingStationTemplate (chargingStationTemplate: ChargingStationTemplate): void {
     this.set(
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      this.getChargingStationTemplateKey(chargingStationTemplate.templateHash!),
+      this.getChargingStationTemplateKey(chargingStationTemplate.templateHash ?? ''),
       chargingStationTemplate
     )
   }
index 74323b597a8fdbeb4477d6871e0da0bd5879b920..990afba4be829dff8a1bfbd5f8fd4b312491ee09 100644 (file)
@@ -270,8 +270,10 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne
   ): Promise<CommandResponse | void> {
     if (this.commandHandlers.has(command)) {
       this.cleanRequestPayload(command, requestPayload)
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      const commandHandler = this.commandHandlers.get(command)!
+      const commandHandler = this.commandHandlers.get(command)
+      if (commandHandler == null) {
+        throw new BaseError(`Unknown worker broadcast channel command: '${command}'`)
+      }
       if (isAsyncFunction(commandHandler)) {
         return await commandHandler(requestPayload)
       }
@@ -394,14 +396,18 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne
     requestPayload?: BroadcastChannelRequestPayload
   ): Promise<MeterValuesResponse> {
     const connectorId = requestPayload?.connectorId
+    if (connectorId == null) {
+      throw new BaseError(
+        `${this.chargingStation.logPrefix()} ${moduleName}.handleMeterValues: Missing connectorId in request payload`
+      )
+    }
     switch (this.chargingStation.stationInfo?.ocppVersion) {
       case OCPPVersion.VERSION_16: {
         const configuredMeterValueSampleInterval = getConfigurationKey(
           this.chargingStation,
           StandardParametersKey.MeterValueSampleInterval
         )
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        const transactionId = this.chargingStation.getConnectorStatus(connectorId!)?.transactionId
+        const transactionId = this.chargingStation.getConnectorStatus(connectorId)?.transactionId
         return await this.chargingStation.ocppRequestService.requestHandler<
           MeterValuesRequest,
           MeterValuesResponse
@@ -426,10 +432,8 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne
       case OCPPVersion.VERSION_20:
       case OCPPVersion.VERSION_201: {
         const alignedDataInterval = OCPP20ServiceUtils.getAlignedDataInterval(this.chargingStation)
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        const evseId = this.chargingStation.getEvseIdByConnectorId(connectorId!)
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        const transactionId = this.chargingStation.getConnectorStatus(connectorId!)?.transactionId
+        const evseId = this.chargingStation.getEvseIdByConnectorId(connectorId)
+        const transactionId = this.chargingStation.getConnectorStatus(connectorId)?.transactionId
         return await this.chargingStation.ocppRequestService.requestHandler<
           MeterValuesRequest,
           MeterValuesResponse
@@ -553,8 +557,14 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne
         return undefined
       })
       .finally(() => {
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        this.sendResponse([uuid, responsePayload!])
+        this.sendResponse([
+          uuid,
+          responsePayload ?? {
+            command,
+            hashId: this.chargingStation.stationInfo?.hashId,
+            status: ResponseStatus.FAILURE,
+          },
+        ])
       })
   }
 }
index b1bd85c6f0369e3a425464c752132aa4e931c74f..8037b67b322a2def5d04df2366ef415ddbf05bea 100644 (file)
@@ -96,21 +96,21 @@ export class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
         responsesReceived: 1,
       })
     } else {
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      const responses = this.responses.get(uuid)!
-      if (responses.responsesReceived < responses.responsesExpected) {
-        ++responses.responsesReceived
-        responses.responses.push(responsePayload)
-      } else {
-        logger.debug(
-          `${this.uiService.logPrefix(moduleName, 'responseHandler')} Received response after all expected responses:`,
-          { responsePayload, uuid }
-        )
+      const responses = this.responses.get(uuid)
+      if (responses != null) {
+        if (responses.responsesReceived < responses.responsesExpected) {
+          ++responses.responsesReceived
+          responses.responses.push(responsePayload)
+        } else {
+          logger.debug(
+            `${this.uiService.logPrefix(moduleName, 'responseHandler')} Received response after all expected responses:`,
+            { responsePayload, uuid }
+          )
+        }
       }
     }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const responses = this.responses.get(uuid)!
-    if (responses.responsesReceived >= responses.responsesExpected) {
+    const responses = this.responses.get(uuid)
+    if (responses != null && responses.responsesReceived >= responses.responsesExpected) {
       this.uiService.sendResponse(uuid, this.buildResponsePayload(uuid))
       this.responses.delete(uuid)
       this.uiService.deleteBroadcastChannelRequest(uuid)
index 4c8fad6e393681d6004a4ae28d2e4d416d33b5b1..8266f2898049e8639486f8e38da1a183ea585bd4 100644 (file)
@@ -618,14 +618,16 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
           chargingProfile.chargingSchedule.startSchedule
         )
       }
-      if (chargingProfile.chargingSchedule.duration == null) {
+      if (
+        chargingProfile.chargingSchedule.duration == null &&
+        chargingProfile.chargingSchedule.startSchedule != null
+      ) {
         logger.debug(
           `${chargingStation.logPrefix()} ${moduleName}.composeCompositeSchedule: Charging profile id ${chargingProfile.chargingProfileId.toString()} has no duration defined and will be set to the maximum time allowed`
         )
         chargingProfile.chargingSchedule.duration = differenceInSeconds(
           maxTime,
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          chargingProfile.chargingSchedule.startSchedule!
+          chargingProfile.chargingSchedule.startSchedule
         )
       }
       if (
@@ -1114,14 +1116,18 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         const logConfiguration = Configuration.getConfigurationSection<LogConfiguration>(
           ConfigurationSection.log
         )
+        const logFile = logConfiguration.file
+        if (logFile == null) {
+          logger.warn(
+            `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetDiagnostics: Cannot get diagnostics: log file not configured`
+          )
+          return OCPP16Constants.OCPP_RESPONSE_EMPTY
+        }
         const logFiles = readdirSync(
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          resolve((fileURLToPath(import.meta.url), '../', dirname(logConfiguration.file!)))
+          resolve((fileURLToPath(import.meta.url), '../', dirname(logFile)))
         )
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          .filter(file => file.endsWith(extname(logConfiguration.file!)))
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          .map(file => join(dirname(logConfiguration.file!), file))
+          .filter(file => file.endsWith(extname(logFile)))
+          .map(file => join(dirname(logFile), file))
         // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
         const diagnosticsArchive = `${chargingStation.stationInfo?.chargingStationId}_logs.tar.gz`
         create({ gzip: true }, logFiles).pipe(createWriteStream(diagnosticsArchive))
@@ -1535,11 +1541,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED
     }
     if (
+      connectorId != null &&
       !OCPP16ServiceUtils.isConnectorIdValid(
         chargingStation,
         OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        connectorId!
+        connectorId
       )
     ) {
       return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED
@@ -1609,8 +1615,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       )
       return OCPP16Constants.OCPP_RESPONSE_EMPTY
     }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    commandPayload.retrieveDate = convertToDate(commandPayload.retrieveDate)!
+    commandPayload.retrieveDate = convertToDate(commandPayload.retrieveDate) ?? new Date()
     if (
       chargingStation.stationInfo?.firmwareStatus === OCPP16FirmwareStatus.Downloading ||
       chargingStation.stationInfo?.firmwareStatus === OCPP16FirmwareStatus.Downloaded ||
index d55e10d7b2dfcee5dd3b740c7de7c843524a1455..75b15f1370a7291dbf96c1389b9355e93cab4ba0 100644 (file)
@@ -199,13 +199,12 @@ export class OCPP16RequestService extends OCPPRequestService {
             commandParams.connectorId as number,
             commandParams.idTag as string
           ) && {
-            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
             reservationId: chargingStation.getReservationBy(
               'connectorId',
               chargingStation.getConnectorStatus(0)?.status === OCPP16ChargePointStatus.Reserved
                 ? 0
                 : (commandParams.connectorId as number)
-            )!.reservationId,
+            )?.reservationId,
           }),
           ...commandParams,
         } as unknown as Request
@@ -227,15 +226,14 @@ export class OCPP16RequestService extends OCPPRequestService {
           idTag: chargingStation.getTransactionIdTag(commandParams.transactionId as number),
           meterStop: energyActiveImportRegister,
           timestamp: new Date(),
-          ...(chargingStation.stationInfo?.transactionDataMeterValues === true && {
+          ...(chargingStation.stationInfo?.transactionDataMeterValues === true &&
+            connectorId != null && {
             transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues(
-              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-              chargingStation.getConnectorStatus(connectorId!)!
-                .transactionBeginMeterValue! as OCPP16MeterValue,
+              chargingStation.getConnectorStatus(connectorId)
+                ?.transactionBeginMeterValue as OCPP16MeterValue,
               OCPP16ServiceUtils.buildTransactionEndMeterValue(
                 chargingStation,
-                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-                connectorId!,
+                connectorId,
                 energyActiveImportRegister
               ) as OCPP16MeterValue
             ),
index 7ed639567f43ea02dfbcb94f56cdc9449b988dd1..6960de749ac51669a08336555e53e39322277c94 100644 (file)
@@ -173,8 +173,10 @@ export class OCPP16ResponseService extends OCPPResponseService {
       }
     }
     if (authorizeConnectorId != null) {
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      const authorizeConnectorStatus = chargingStation.getConnectorStatus(authorizeConnectorId)!
+      const authorizeConnectorStatus = chargingStation.getConnectorStatus(authorizeConnectorId)
+      if (authorizeConnectorStatus == null) {
+        return
+      }
       if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
         authorizeConnectorStatus.idTagAuthorized = true
         logger.debug(
@@ -439,8 +441,13 @@ export class OCPP16ResponseService extends OCPPResponseService {
         }#${connectorId.toString()} for idTag '${truncateId(requestPayload.idTag)}'`
       )
       if (chargingStation.stationInfo?.powerSharedByConnectors === true) {
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        ++chargingStation.powerDivider!
+        if (chargingStation.powerDivider != null) {
+          ++chargingStation.powerDivider
+        } else {
+          logger.error(
+            `${chargingStation.logPrefix()} ${moduleName}.handleResponseStartTransaction: powerDivider is undefined, cannot increment`
+          )
+        }
       }
       const configuredMeterValueSampleInterval = getConfigurationKey(
         chargingStation,
@@ -517,8 +524,15 @@ export class OCPP16ResponseService extends OCPPResponseService {
       } as OCPP16StatusNotificationRequest)
     }
     if (chargingStation.stationInfo?.powerSharedByConnectors === true) {
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      chargingStation.powerDivider!--
+      if (chargingStation.powerDivider != null && chargingStation.powerDivider > 0) {
+        --chargingStation.powerDivider
+      } else {
+        logger.error(
+          `${chargingStation.logPrefix()} ${moduleName}.handleResponseStopTransaction: powerDivider is ${
+            chargingStation.powerDivider?.toString() ?? 'undefined'
+          }, cannot decrement`
+        )
+      }
     }
     const transactionConnectorStatus = chargingStation.getConnectorStatus(transactionConnectorId)
     resetConnectorStatus(transactionConnectorStatus)
index 0edd3aa216721becc9f1807dce4ea9b59f0c668b..057a8f406f595bf9143f50a73de752f078c46ee6 100644 (file)
@@ -144,8 +144,10 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
     for (const connectorId of connectorIds) {
       let response: OCPP16ChangeAvailabilityResponse =
         OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      const connectorStatus = chargingStation.getConnectorStatus(connectorId)!
+      const connectorStatus = chargingStation.getConnectorStatus(connectorId)
+      if (connectorStatus == null) {
+        continue
+      }
       if (connectorStatus.transactionStarted === true) {
         response = OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED
       }
@@ -551,8 +553,10 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
       logger.warn(
         `${chargingStation.logPrefix()} ${moduleName}.setChargingProfile: Trying to set a charging profile on connector id ${connectorId.toString()} with an uninitialized charging profiles array attribute, applying deferred initialization`
       )
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      chargingStation.getConnectorStatus(connectorId)!.chargingProfiles = []
+      const connectorStatus = chargingStation.getConnectorStatus(connectorId)
+      if (connectorStatus != null) {
+        connectorStatus.chargingProfiles = []
+      }
     }
     if (!Array.isArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)) {
       logger.warn(
@@ -699,11 +703,12 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
     chargingSchedule: OCPP16ChargingSchedule,
     compositeInterval: Interval
   ): OCPP16ChargingSchedule | undefined => {
+    if (chargingSchedule.startSchedule == null || chargingSchedule.duration == null) {
+      return undefined
+    }
     const chargingScheduleInterval: Interval = {
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      end: addSeconds(chargingSchedule.startSchedule!, chargingSchedule.duration!),
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      start: chargingSchedule.startSchedule!,
+      end: addSeconds(chargingSchedule.startSchedule, chargingSchedule.duration),
+      start: chargingSchedule.startSchedule,
     }
     if (areIntervalsOverlapping(chargingScheduleInterval, compositeInterval)) {
       chargingSchedule.chargingSchedulePeriod.sort((a, b) => a.startPeriod - b.startPeriod)
index 981a0fa8e7b51c7d5f6dbdf4e4215cd00c1e7f43..7f88d8feaba696ffbbd9e0c55e3f9c297c3cf174 100644 (file)
@@ -403,7 +403,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
       ) => {
         if (response.status === RequestStartStopStatusEnumType.Accepted) {
           const connectorId = chargingStation.getConnectorIdByTransactionId(response.transactionId)
-          if (connectorId != null) {
+          if (connectorId != null && response.transactionId != null) {
             const connectorStatus = chargingStation.getConnectorStatus(connectorId)
             const startedMeterValues =
               connectorStatus != null
@@ -414,8 +414,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
               OCPP20TransactionEventEnumType.Started,
               OCPP20TriggerReasonEnumType.RemoteStart,
               connectorId,
-              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-              response.transactionId!,
+              response.transactionId,
               startedMeterValues.length > 0 ? { meterValue: startedMeterValues } : undefined
             ).catch((error: unknown) => {
               logger.error(
@@ -1261,7 +1260,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
     )
     if (maxChainSizeKey?.value != null) {
       const maxChainSize = parseInt(maxChainSizeKey.value, 10)
-      if (!isNaN(maxChainSize) && maxChainSize > 0) {
+      if (!Number.isNaN(maxChainSize) && maxChainSize > 0) {
         const chainByteSize = Buffer.byteLength(certificateChain, 'utf8')
         if (chainByteSize > maxChainSize) {
           logger.warn(
@@ -3004,12 +3003,12 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
     idTokenString: string
   ): boolean {
     try {
+      const idTagsFile =
+        chargingStation.stationInfo != null ? getIdTagsFile(chargingStation.stationInfo) : undefined
       return (
         chargingStation.hasIdTags() &&
-        chargingStation.idTagsCache
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          .getIdTags(getIdTagsFile(chargingStation.stationInfo!)!)
-          ?.includes(idTokenString) === true
+        idTagsFile != null &&
+        chargingStation.idTagsCache.getIdTags(idTagsFile)?.includes(idTokenString) === true
       )
     } catch (error) {
       logger.error(
index ea7f2674413503f59afaa81741abf0d72d20a958..c3a13f7bb8de6cb4232388240d61f1bad5334e78 100644 (file)
@@ -99,8 +99,15 @@ export abstract class OCPPIncomingRequestService extends EventEmitter {
       ) {
         try {
           this.validateIncomingRequestPayload(chargingStation, commandName, commandPayload)
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          const incomingRequestHandler = this.incomingRequestHandlers.get(commandName)!
+          const incomingRequestHandler = this.incomingRequestHandlers.get(commandName)
+          if (incomingRequestHandler == null) {
+            throw new OCPPError(
+              ErrorType.NOT_IMPLEMENTED,
+              `${commandName} incoming request handler not found`,
+              commandName,
+              commandPayload
+            )
+          }
           if (isAsyncFunction(incomingRequestHandler)) {
             response = (await incomingRequestHandler(chargingStation, commandPayload)) as ResType
           } else {
index ca7994431842d3ef1ad54f157377aea5defd2a77..96d27f298d74fe9d960292044272389601fc54c1 100644 (file)
@@ -85,8 +85,15 @@ export abstract class OCPPResponseService {
           logger.debug(
             `${chargingStation.logPrefix()} ${this.moduleName}.responseHandler: Handling '${commandName}' response`
           )
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          const responseHandler = this.responseHandlers.get(commandName)!
+          const responseHandler = this.responseHandlers.get(commandName)
+          if (responseHandler == null) {
+            throw new OCPPError(
+              ErrorType.NOT_IMPLEMENTED,
+              `${commandName} response handler not found`,
+              commandName,
+              payload
+            )
+          }
           if (isAsyncFunction(responseHandler)) {
             await responseHandler(chargingStation, payload, requestPayload)
           } else {
index 9ed49dcb09636c13b6c46b87aa5aeadf658189e3..8beae8f6a68b17b7daf42456334db1f124bc0fb9 100644 (file)
@@ -249,14 +249,12 @@ export const isIdTagAuthorized = async (
 }
 
 const isIdTagLocalAuthorized = (chargingStation: ChargingStation, idTag: string): boolean => {
+  const idTagsFile =
+    chargingStation.stationInfo != null ? getIdTagsFile(chargingStation.stationInfo) : undefined
   return (
     chargingStation.hasIdTags() &&
-    isNotEmptyString(
-      chargingStation.idTagsCache
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        .getIdTags(getIdTagsFile(chargingStation.stationInfo!)!)
-        ?.find(tag => tag === idTag)
-    )
+    idTagsFile != null &&
+    isNotEmptyString(chargingStation.idTagsCache.getIdTags(idTagsFile)?.find(tag => tag === idTag))
   )
 }
 
@@ -265,8 +263,10 @@ const isIdTagRemoteAuthorized = async (
   connectorId: number,
   idTag: string
 ): Promise<boolean> => {
-  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-  chargingStation.getConnectorStatus(connectorId)!.authorizeIdTag = idTag
+  const connectorStatus = chargingStation.getConnectorStatus(connectorId)
+  if (connectorStatus != null) {
+    connectorStatus.authorizeIdTag = idTag
+  }
   switch (chargingStation.stationInfo?.ocppVersion) {
     case OCPPVersion.VERSION_16:
       return (
@@ -1997,16 +1997,15 @@ const getLimitFromSampledValueTemplateCustomValue = (
     return max(
       min(
         (!Number.isNaN(parsedValue) ? parsedValue : Number.POSITIVE_INFINITY) *
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          options.unitMultiplier!,
+          (options.unitMultiplier ?? 1),
         maxLimit
       ),
       minLimit
     )
   }
   return (
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    (!Number.isNaN(parsedValue) ? parsedValue : options.fallbackValue!) * options.unitMultiplier!
+    (!Number.isNaN(parsedValue) ? parsedValue : (options.fallbackValue ?? 0)) *
+    (options.unitMultiplier ?? 1)
   )
 }
 
index cddb5dcdd80ddffdea7a86b702c9d105c329c175..03b5780538152dbf0b3a8c5afff39d57a1cbb46b 100644 (file)
@@ -153,8 +153,10 @@ export abstract class AbstractUIService {
       }
 
       // Call the request handler to build the response payload
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      const requestHandler = this.requestHandlers.get(command)!
+      const requestHandler = this.requestHandlers.get(command)
+      if (requestHandler == null) {
+        throw new BaseError(`'${command}' request handler not found`)
+      }
       if (isAsyncFunction(requestHandler)) {
         responsePayload = await requestHandler(uuid, command, requestPayload)
       } else {
index 518ec8c402c0a0672bb78a5810eb71b879301b84..008350da93e4f20e4e7d46f48a86fd3d66e43ea8 100644 (file)
@@ -127,48 +127,42 @@ export class PerformanceStatistics {
     messageType: MessageType
   ): void {
     switch (messageType) {
-      case MessageType.CALL_ERROR_MESSAGE:
-        if (
-          this.statistics.statisticsData.has(command) &&
-          this.statistics.statisticsData.get(command)?.errorCount != null
-        ) {
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          ++this.statistics.statisticsData.get(command)!.errorCount!
+      case MessageType.CALL_ERROR_MESSAGE: {
+        const commandStatisticsData = this.statistics.statisticsData.get(command)
+        if (commandStatisticsData?.errorCount != null) {
+          ++commandStatisticsData.errorCount
         } else {
           this.statistics.statisticsData.set(command, {
-            ...this.statistics.statisticsData.get(command),
+            ...commandStatisticsData,
             errorCount: 1,
           })
         }
         break
-      case MessageType.CALL_MESSAGE:
-        if (
-          this.statistics.statisticsData.has(command) &&
-          this.statistics.statisticsData.get(command)?.requestCount != null
-        ) {
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          ++this.statistics.statisticsData.get(command)!.requestCount!
+      }
+      case MessageType.CALL_MESSAGE: {
+        const commandStatisticsData = this.statistics.statisticsData.get(command)
+        if (commandStatisticsData?.requestCount != null) {
+          ++commandStatisticsData.requestCount
         } else {
           this.statistics.statisticsData.set(command, {
-            ...this.statistics.statisticsData.get(command),
+            ...commandStatisticsData,
             requestCount: 1,
           })
         }
         break
-      case MessageType.CALL_RESULT_MESSAGE:
-        if (
-          this.statistics.statisticsData.has(command) &&
-          this.statistics.statisticsData.get(command)?.responseCount != null
-        ) {
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          ++this.statistics.statisticsData.get(command)!.responseCount!
+      }
+      case MessageType.CALL_RESULT_MESSAGE: {
+        const commandStatisticsData = this.statistics.statisticsData.get(command)
+        if (commandStatisticsData?.responseCount != null) {
+          ++commandStatisticsData.responseCount
         } else {
           this.statistics.statisticsData.set(command, {
-            ...this.statistics.statisticsData.get(command),
+            ...commandStatisticsData,
             responseCount: 1,
           })
         }
         break
+      }
       default:
         // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
         logger.error(`${this.logPrefix()} wrong message type ${messageType}`)
@@ -210,62 +204,45 @@ export class PerformanceStatistics {
     if (!this.statistics.statisticsData.has(entry.name)) {
       this.statistics.statisticsData.set(entry.name, {})
     }
-    // Update current statistics
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    this.statistics.statisticsData.get(entry.name)!.timeMeasurementCount =
-      (this.statistics.statisticsData.get(entry.name)?.timeMeasurementCount ?? 0) + 1
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    this.statistics.statisticsData.get(entry.name)!.currentTimeMeasurement = entry.duration
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    this.statistics.statisticsData.get(entry.name)!.minTimeMeasurement = min(
-      entry.duration,
-      this.statistics.statisticsData.get(entry.name)?.minTimeMeasurement ?? Number.POSITIVE_INFINITY
-    )
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    this.statistics.statisticsData.get(entry.name)!.maxTimeMeasurement = max(
-      entry.duration,
-      this.statistics.statisticsData.get(entry.name)?.maxTimeMeasurement ?? Number.NEGATIVE_INFINITY
-    )
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    this.statistics.statisticsData.get(entry.name)!.totalTimeMeasurement =
-      (this.statistics.statisticsData.get(entry.name)?.totalTimeMeasurement ?? 0) + entry.duration
-    if (
-      !(
-        this.statistics.statisticsData.get(entry.name)?.measurementTimeSeries instanceof
-        CircularBuffer
+    const entryStatisticsData = this.statistics.statisticsData.get(entry.name)
+    if (entryStatisticsData != null) {
+      // Update current statistics
+      entryStatisticsData.timeMeasurementCount = (entryStatisticsData.timeMeasurementCount ?? 0) + 1
+      entryStatisticsData.currentTimeMeasurement = entry.duration
+      entryStatisticsData.minTimeMeasurement = min(
+        entry.duration,
+        entryStatisticsData.minTimeMeasurement ?? Number.POSITIVE_INFINITY
       )
-    ) {
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      this.statistics.statisticsData.get(entry.name)!.measurementTimeSeries =
-        new CircularBuffer<TimestampedData>(
+      entryStatisticsData.maxTimeMeasurement = max(
+        entry.duration,
+        entryStatisticsData.maxTimeMeasurement ?? Number.NEGATIVE_INFINITY
+      )
+      entryStatisticsData.totalTimeMeasurement =
+        (entryStatisticsData.totalTimeMeasurement ?? 0) + entry.duration
+      if (!(entryStatisticsData.measurementTimeSeries instanceof CircularBuffer)) {
+        entryStatisticsData.measurementTimeSeries = new CircularBuffer<TimestampedData>(
           Array<TimestampedData>,
           Constants.DEFAULT_CIRCULAR_BUFFER_CAPACITY
         )
+      }
+      entryStatisticsData.measurementTimeSeries.push({
+        timestamp: entry.startTime,
+        value: entry.duration,
+      })
+      const timeMeasurementValues = extractTimeSeriesValues(
+        entryStatisticsData.measurementTimeSeries
+      )
+      entryStatisticsData.avgTimeMeasurement = average(timeMeasurementValues)
+      entryStatisticsData.medTimeMeasurement = median(timeMeasurementValues)
+      entryStatisticsData.ninetyFiveThPercentileTimeMeasurement = percentile(
+        timeMeasurementValues,
+        95
+      )
+      entryStatisticsData.stdTimeMeasurement = std(
+        timeMeasurementValues,
+        entryStatisticsData.avgTimeMeasurement
+      )
     }
-    this.statistics.statisticsData.get(entry.name)?.measurementTimeSeries?.push({
-      timestamp: entry.startTime,
-      value: entry.duration,
-    })
-    const timeMeasurementValues = extractTimeSeriesValues(
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      this.statistics.statisticsData.get(entry.name)!
-        .measurementTimeSeries as CircularBuffer<TimestampedData>
-    )
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    this.statistics.statisticsData.get(entry.name)!.avgTimeMeasurement =
-      average(timeMeasurementValues)
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    this.statistics.statisticsData.get(entry.name)!.medTimeMeasurement =
-      median(timeMeasurementValues)
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    this.statistics.statisticsData.get(entry.name)!.ninetyFiveThPercentileTimeMeasurement =
-      percentile(timeMeasurementValues, 95)
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    this.statistics.statisticsData.get(entry.name)!.stdTimeMeasurement = std(
-      timeMeasurementValues,
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      this.statistics.statisticsData.get(entry.name)!.avgTimeMeasurement
-    )
     this.statistics.updatedAt = new Date()
     if (
       Configuration.getConfigurationSection<StorageConfiguration>(
@@ -307,10 +284,7 @@ export class PerformanceStatistics {
       ConfigurationSection.log
     )
     const logStatisticsInterval =
-      logConfiguration.enabled === true
-        ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        logConfiguration.statisticsInterval!
-        : 0
+      logConfiguration.enabled === true ? (logConfiguration.statisticsInterval ?? 0) : 0
     if (logStatisticsInterval > 0 && this.displayInterval == null) {
       this.displayInterval = setInterval(() => {
         this.logStatistics()
index 4e2c815127d1b2a21942ebd3a074303e3ae94601..0c8298586bab022b7ff2f7d9ac5efbd86f655b1f 100644 (file)
@@ -46,11 +46,12 @@ export class AsyncLock {
   }
 
   private static getAsyncLock (type: AsyncLockType): AsyncLock {
-    if (!AsyncLock.asyncLocks.has(type)) {
-      AsyncLock.asyncLocks.set(type, new AsyncLock())
+    let asyncLock = AsyncLock.asyncLocks.get(type)
+    if (asyncLock == null) {
+      asyncLock = new AsyncLock()
+      AsyncLock.asyncLocks.set(type, asyncLock)
     }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    return AsyncLock.asyncLocks.get(type)!
+    return asyncLock
   }
 
   private static release (type: AsyncLockType): void {
index fbe027873766905e5c4581f7f8494c702b624937..a3a16cfebd387e644480f32ce3e260bf92865058 100644 (file)
@@ -196,10 +196,12 @@ export class Configuration {
   }
 
   public static workerPoolInUse (): boolean {
-    return [WorkerProcessType.dynamicPool, WorkerProcessType.fixedPool].includes(
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      Configuration.getConfigurationSection<WorkerConfiguration>(ConfigurationSection.worker)
-        .processType!
+    const processType = Configuration.getConfigurationSection<WorkerConfiguration>(
+      ConfigurationSection.worker
+    ).processType
+    return (
+      processType != null &&
+      [WorkerProcessType.dynamicPool, WorkerProcessType.fixedPool].includes(processType)
     )
   }
 
@@ -316,8 +318,9 @@ export class Configuration {
       ...(deprecatedWorkerConfiguration as Partial<WorkerConfiguration>),
       ...(has(ConfigurationSection.worker, configData) && configData?.worker),
     }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    checkWorkerProcessType(workerConfiguration.processType!)
+    if (workerConfiguration.processType != null) {
+      checkWorkerProcessType(workerConfiguration.processType)
+    }
     checkWorkerElementsPerWorker(workerConfiguration.elementsPerWorker)
     return workerConfiguration
   }
index 96c94a62b2e48f48f6bb6a65ca1f3d18882abe52..8e4d9dfe5bdfd9b5d4243ab19805e0b460759d7e 100644 (file)
@@ -72,8 +72,7 @@ const getLoggerInstance = (): WinstonLogger => {
   }
   const logFormat = format.combine(
     format.splat(),
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    (format[logConfiguration.format! as keyof FormatWrap] as FormatWrap)()
+    (format[(logConfiguration.format ?? 'simple') as keyof FormatWrap] as FormatWrap)()
   )
   loggerInstance = createLogger({
     format: logFormat,
index 9335c6448ed58619f81add9ed844cf15e25014ac..2ee6ccfec36558accb2b89afbbe477e60c0ba325 100644 (file)
@@ -4,6 +4,8 @@ import type { ChargingStation } from '../charging-station/index.js'
 
 import {
   type ChargingStationData,
+  type ChargingStationInfo,
+  type ChargingStationOcppConfiguration,
   type ChargingStationWorkerMessage,
   ChargingStationWorkerMessageEvents,
   type Statistics,
@@ -99,11 +101,10 @@ const buildChargingStationDataPayload = (chargingStation: ChargingStation): Char
     bootNotificationResponse: chargingStation.bootNotificationResponse,
     connectors: buildConnectorEntries(chargingStation),
     evses: buildEvseEntries(chargingStation),
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    ocppConfiguration: chargingStation.ocppConfiguration!,
+    ocppConfiguration:
+      chargingStation.ocppConfiguration ?? ({} as ChargingStationOcppConfiguration),
     started: chargingStation.started,
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    stationInfo: chargingStation.stationInfo!,
+    stationInfo: chargingStation.stationInfo ?? ({} as ChargingStationInfo),
     supervisionUrl: chargingStation.wsConnectionUrl.href,
     timestamp: Date.now(),
     wsState: chargingStation.wsConnection?.readyState,
index 78a47e72609ba02d47338849ef02ef038cb79099..b8e4ec24495fefc848ee8cf364543b390a9ab54b 100644 (file)
@@ -5,7 +5,7 @@ import { EventEmitterAsyncResource } from 'node:events'
 import { SHARE_ENV, Worker } from 'node:worker_threads'
 
 import { WorkerAbstract } from './WorkerAbstract.js'
-import { EMPTY_FUNCTION, workerSetVersion } from './WorkerConstants.js'
+import { DEFAULT_ELEMENTS_PER_WORKER, EMPTY_FUNCTION, workerSetVersion } from './WorkerConstants.js'
 import {
   type SetInfo,
   type UUIDv4,
@@ -33,8 +33,7 @@ export class WorkerSet<D extends WorkerData, R extends WorkerData> extends Worke
         (accumulator, workerSetElement) => accumulator + workerSetElement.numberOfWorkerElements,
         0
       ),
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      elementsPerWorker: this.maxElementsPerWorker!,
+      elementsPerWorker: this.maxElementsPerWorker ?? DEFAULT_ELEMENTS_PER_WORKER,
       size: this.size,
       started: this.started,
       type: 'set',
@@ -167,9 +166,12 @@ export class WorkerSet<D extends WorkerData, R extends WorkerData> extends Worke
     worker.on('message', (message: WorkerMessage<R>) => {
       const { data, event, uuid } = message
       if (this.promiseResponseMap.has(uuid)) {
+        const responseWrapper = this.promiseResponseMap.get(uuid)
+        if (responseWrapper == null) {
+          return
+        }
         let error: Error
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        const { reject, resolve, workerSetElement } = this.promiseResponseMap.get(uuid)!
+        const { reject, resolve, workerSetElement } = responseWrapper
         switch (event) {
           case WorkerMessageEvents.addedWorkerElement:
             ++workerSetElement.numberOfWorkerElements
@@ -241,8 +243,10 @@ export class WorkerSet<D extends WorkerData, R extends WorkerData> extends Worke
   private async getWorkerSetElement (): Promise<WorkerSetElement> {
     let chosenWorkerSetElement: undefined | WorkerSetElement
     for (const workerSetElement of this.workerSet) {
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      if (workerSetElement.numberOfWorkerElements < this.workerOptions.elementsPerWorker!) {
+      if (
+        workerSetElement.numberOfWorkerElements <
+        (this.workerOptions.elementsPerWorker ?? DEFAULT_ELEMENTS_PER_WORKER)
+      ) {
         chosenWorkerSetElement = workerSetElement
         break
       }