refactor: convert home made helpers to rambda ones
authorJérôme Benoit <jerome.benoit@sap.com>
Mon, 11 Mar 2024 22:51:26 +0000 (23:51 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Mon, 11 Mar 2024 22:51:26 +0000 (23:51 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ChargingStation.ts
src/charging-station/Helpers.ts
src/charging-station/SharedLRUCache.ts
src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/utils/Configuration.ts
src/utils/Utils.ts
src/utils/index.ts
tests/utils/Utils.test.ts

index 31ce3342f660d35e7598cca46c60c11f1b75c342..2f758aa3518d6b39f71429b17294ba5134596d6e 100644 (file)
@@ -8,7 +8,7 @@ import { URL } from 'node:url'
 import { parentPort } from 'node:worker_threads'
 
 import { millisecondsToSeconds, secondsToMilliseconds } from 'date-fns'
-import { mergeDeepRight } from 'rambda'
+import { mergeDeepRight, once } from 'rambda'
 import { type RawData, WebSocket } from 'ws'
 
 import { BaseError, OCPPError } from '../exception/index.js'
@@ -96,7 +96,6 @@ import {
   logger,
   logPrefix,
   min,
-  once,
   roundTo,
   secureRandom,
   sleep,
@@ -1156,7 +1155,7 @@ export class ChargingStation extends EventEmitter {
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
     const stationTemplate = this.getTemplateFromFile()!
     checkTemplate(stationTemplate, this.logPrefix(), this.templateFile)
-    const warnTemplateKeysDeprecationOnce = once(warnTemplateKeysDeprecation, this)
+    const warnTemplateKeysDeprecationOnce = once(warnTemplateKeysDeprecation)
     warnTemplateKeysDeprecationOnce(stationTemplate, this.logPrefix(), this.templateFile)
     if (stationTemplate.Connectors != null) {
       checkConnectorsConfiguration(stationTemplate, this.logPrefix(), this.templateFile)
index 726a0ab3a23f4fabbd5291aca49cc7ebc059c8b6..916cf499ecedaadfe821719658a1608aefbdf880 100644 (file)
@@ -21,6 +21,7 @@ import {
   toDate
 } from 'date-fns'
 import { maxTime } from 'date-fns/constants'
+import { isEmpty } from 'rambda'
 
 import { BaseError } from '../exception/index.js'
 import {
@@ -60,8 +61,6 @@ import {
   convertToInt,
   DCElectricUtils,
   isArraySorted,
-  isEmptyObject,
-  isEmptyString,
   isNotEmptyArray,
   isNotEmptyString,
   isValidDate,
@@ -254,12 +253,12 @@ export const checkTemplate = (
     logger.error(`${logPrefix} ${errorMsg}`)
     throw new BaseError(errorMsg)
   }
-  if (isEmptyObject(stationTemplate)) {
+  if (isEmpty(stationTemplate)) {
     const errorMsg = `Empty charging station information from template file ${templateFile}`
     logger.error(`${logPrefix} ${errorMsg}`)
     throw new BaseError(errorMsg)
   }
-  if (stationTemplate.idTagsFile == null || isEmptyString(stationTemplate.idTagsFile)) {
+  if (stationTemplate.idTagsFile == null || isEmpty(stationTemplate.idTagsFile)) {
     logger.warn(
       `${logPrefix} Missing id tags file in template file ${templateFile}. That can lead to issues with the Automatic Transaction Generator`
     )
@@ -276,7 +275,7 @@ export const checkConfiguration = (
     logger.error(`${logPrefix} ${errorMsg}`)
     throw new BaseError(errorMsg)
   }
-  if (isEmptyObject(stationConfiguration)) {
+  if (isEmpty(stationConfiguration)) {
     const errorMsg = `Empty charging station configuration from file ${configurationFile}`
     logger.error(`${logPrefix} ${errorMsg}`)
     throw new BaseError(errorMsg)
index b2a90e0ff16438057a9e3fb045b79dacf68f4c5c..7f459a4fa1b875bcf1c668d67ac53eaf9a43731f 100644 (file)
@@ -1,7 +1,8 @@
 import { LRUMapWithDelete as LRUCache } from 'mnemonist'
+import { isEmpty } from 'rambda'
 
 import type { ChargingStationConfiguration, ChargingStationTemplate } from '../types/index.js'
-import { isEmptyObject, isNotEmptyArray, isNotEmptyString } from '../utils/index.js'
+import { isNotEmptyArray, isNotEmptyString } from '../utils/index.js'
 import { Bootstrap } from './Bootstrap.js'
 
 enum CacheType {
@@ -116,8 +117,8 @@ export class SharedLRUCache {
       chargingStationConfiguration.automaticTransactionGenerator != null &&
       chargingStationConfiguration.configurationHash != null &&
       isNotEmptyArray(chargingStationConfiguration.configurationKey) &&
-      !isEmptyObject(chargingStationConfiguration.stationInfo) &&
-      !isEmptyObject(chargingStationConfiguration.automaticTransactionGenerator) &&
+      !isEmpty(chargingStationConfiguration.stationInfo) &&
+      !isEmpty(chargingStationConfiguration.automaticTransactionGenerator) &&
       isNotEmptyString(chargingStationConfiguration.configurationHash)
     )
   }
index 1a825e39186e3bc94178507917ff966cd99b3db5..cb152baf7fbfc8e75766a6f7313ca390ea19f1d8 100644 (file)
@@ -1,4 +1,5 @@
 import { secondsToMilliseconds } from 'date-fns'
+import { isEmpty } from 'rambda'
 
 import { BaseError, type OCPPError } from '../../exception/index.js'
 import {
@@ -36,13 +37,7 @@ import {
   type StopTransactionRequest,
   type StopTransactionResponse
 } from '../../types/index.js'
-import {
-  Constants,
-  convertToInt,
-  isAsyncFunction,
-  isEmptyObject,
-  logger
-} from '../../utils/index.js'
+import { Constants, convertToInt, isAsyncFunction, logger } from '../../utils/index.js'
 import type { ChargingStation } from '../ChargingStation.js'
 import { getConfigurationKey } from '../ConfigurationKeyUtils.js'
 import { buildMeterValue } from '../ocpp/index.js'
@@ -293,7 +288,7 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne
     let responsePayload: BroadcastChannelResponsePayload | undefined
     this.commandHandler(command, requestPayload)
       .then(commandResponse => {
-        if (commandResponse == null || isEmptyObject(commandResponse)) {
+        if (commandResponse == null || isEmpty(commandResponse)) {
           responsePayload = {
             hashId: this.chargingStation.stationInfo?.hashId,
             status: ResponseStatus.SUCCESS
@@ -420,7 +415,7 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne
         return ResponseStatus.FAILURE
       case BroadcastChannelProcedureName.STATUS_NOTIFICATION:
       case BroadcastChannelProcedureName.METER_VALUES:
-        if (isEmptyObject(commandResponse)) {
+        if (isEmpty(commandResponse)) {
           return ResponseStatus.SUCCESS
         }
         return ResponseStatus.FAILURE
index a61cb21995b2bd845e2eb0519f10007cd5febf08..0418266499bcc5b787a72e1ef70d29c05f880812 100644 (file)
@@ -14,6 +14,7 @@ import {
   secondsToMilliseconds
 } from 'date-fns'
 import { maxTime } from 'date-fns/constants'
+import { isEmpty } from 'rambda'
 import { create } from 'tar'
 
 import {
@@ -105,7 +106,6 @@ import {
   formatDurationMilliSeconds,
   getRandomInteger,
   isAsyncFunction,
-  isEmptyArray,
   isNotEmptyArray,
   isNotEmptyString,
   logger,
@@ -943,8 +943,8 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     }
     const connectorStatus = chargingStation.getConnectorStatus(connectorId)
     if (
-      isEmptyArray(connectorStatus?.chargingProfiles) &&
-      isEmptyArray(chargingStation.getConnectorStatus(0)?.chargingProfiles)
+      isEmpty(connectorStatus?.chargingProfiles) &&
+      isEmpty(chargingStation.getConnectorStatus(0)?.chargingProfiles)
     ) {
       return OCPP16Constants.OCPP_RESPONSE_REJECTED
     }
index 46ad889c7fca2e4fd772558c38270c3caf31e87d..0b2fa3486ccd041fa3fcb837fac7ba9a6d313a91 100644 (file)
@@ -4,7 +4,7 @@ import { env } from 'node:process'
 import { fileURLToPath } from 'node:url'
 
 import chalk from 'chalk'
-import { mergeDeepRight } from 'rambda'
+import { mergeDeepRight, once } from 'rambda'
 
 import {
   ApplicationProtocol,
@@ -36,7 +36,7 @@ import {
   logPrefix
 } from './ConfigurationUtils.js'
 import { Constants } from './Constants.js'
-import { hasOwnProp, isCFEnvironment, once } from './Utils.js'
+import { hasOwnProp, isCFEnvironment } from './Utils.js'
 
 type ConfigurationSectionType =
   | LogConfiguration
@@ -82,8 +82,7 @@ export class Configuration {
 
   public static getStationTemplateUrls (): StationTemplateUrl[] | undefined {
     const checkDeprecatedConfigurationKeysOnce = once(
-      Configuration.checkDeprecatedConfigurationKeys.bind(Configuration),
-      Configuration
+      Configuration.checkDeprecatedConfigurationKeys.bind(Configuration)
     )
     checkDeprecatedConfigurationKeysOnce()
     return Configuration.getConfigurationData()?.stationTemplateUrls
@@ -567,7 +566,7 @@ export class Configuration {
           event === 'change'
         ) {
           Configuration.configurationFileReloading = true
-          const consoleWarnOnce = once(console.warn, this)
+          const consoleWarnOnce = once(console.warn)
           consoleWarnOnce(
             `${chalk.green(logPrefix())} ${chalk.yellow(
               `${FileType.Configuration} ${this.configurationFile} file have changed, reload`
index 4c4c20f234ff02faf4f79974db7913858b0c0dd7..fc3cf9a9cb55fba343d3739d14fbd2766c456604 100644 (file)
@@ -14,7 +14,6 @@ import {
 } from 'date-fns'
 
 import {
-  type EmptyObject,
   type JsonType,
   MapStringifyFormat,
   type TimestampedData,
@@ -233,19 +232,6 @@ export const isObject = (value: unknown): value is object => {
   return value != null && typeof value === 'object' && !Array.isArray(value)
 }
 
-export const isEmptyObject = (object: object): object is EmptyObject => {
-  if (object.constructor !== Object) {
-    return false
-  }
-  // Iterates over the keys of an object, if
-  // any exist, return false.
-  // eslint-disable-next-line no-unreachable-loop
-  for (const _ in object) {
-    return false
-  }
-  return true
-}
-
 export const hasOwnProp = (value: unknown, property: PropertyKey): boolean => {
   return isObject(value) && Object.hasOwn(value, property)
 }
@@ -258,18 +244,10 @@ const isString = (value: unknown): value is string => {
   return typeof value === 'string'
 }
 
-export const isEmptyString = (value: unknown): value is '' | undefined | null => {
-  return value == null || (isString(value) && value.trim().length === 0)
-}
-
 export const isNotEmptyString = (value: unknown): value is string => {
   return isString(value) && value.trim().length > 0
 }
 
-export const isEmptyArray = (value: unknown): value is [] => {
-  return Array.isArray(value) && value.length === 0
-}
-
 export const isNotEmptyArray = (value: unknown): value is unknown[] => {
   return Array.isArray(value) && value.length > 0
 }
@@ -368,22 +346,6 @@ export const isArraySorted = <T>(array: T[], compareFn: (a: T, b: T) => number):
   return true
 }
 
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-export const once = <T, A extends any[], R>(
-  fn: (...args: A) => R,
-  context: T
-): ((...args: A) => R) => {
-  let result: R
-  return (...args: A) => {
-    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
-    if (fn != null) {
-      result = fn.apply<T, A, R>(context, args)
-      ;(fn as unknown as undefined) = (context as unknown as undefined) = undefined
-    }
-    return result
-  }
-}
-
 export const min = (...args: number[]): number =>
   args.reduce((minimum, num) => (minimum < num ? minimum : num), Infinity)
 
index daa67094d76ed4126fc9a57df1dd8e51dd137053..726a69db5985bf8577f9cc79527333008f9ce159 100644 (file)
@@ -45,9 +45,6 @@ export {
   getWebSocketCloseEventStatusString,
   isArraySorted,
   isAsyncFunction,
-  isEmptyArray,
-  isEmptyObject,
-  isEmptyString,
   isNotEmptyArray,
   isNotEmptyString,
   isValidDate,
@@ -55,7 +52,6 @@ export {
   logPrefix,
   max,
   min,
-  once,
   roundTo,
   secureRandom,
   sleep,
index 0ed7d6b67a54eea7d96aff3ed2a40c2675a99413..630831a8d3e29d52d88cedf204d22789aa61a06b 100644 (file)
@@ -21,16 +21,12 @@ import {
   hasOwnProp,
   isArraySorted,
   isAsyncFunction,
-  isEmptyArray,
-  isEmptyObject,
-  isEmptyString,
   isNotEmptyArray,
   isNotEmptyString,
   isObject,
   isValidDate,
   max,
   min,
-  once,
   roundTo,
   secureRandom,
   sleep,
@@ -375,24 +371,6 @@ await describe('Utils test suite', async () => {
     expect(hasOwnProp({ 1: '1' }, 2)).toBe(false)
   })
 
-  await it('Verify isEmptyString()', () => {
-    expect(isEmptyString('')).toBe(true)
-    expect(isEmptyString(' ')).toBe(true)
-    expect(isEmptyString('     ')).toBe(true)
-    expect(isEmptyString('test')).toBe(false)
-    expect(isEmptyString(' test')).toBe(false)
-    expect(isEmptyString('test ')).toBe(false)
-    expect(isEmptyString(undefined)).toBe(true)
-    expect(isEmptyString(null)).toBe(true)
-    expect(isEmptyString(0)).toBe(false)
-    expect(isEmptyString({})).toBe(false)
-    expect(isEmptyString([])).toBe(false)
-    expect(isEmptyString(new Map())).toBe(false)
-    expect(isEmptyString(new Set())).toBe(false)
-    expect(isEmptyString(new WeakMap())).toBe(false)
-    expect(isEmptyString(new WeakSet())).toBe(false)
-  })
-
   await it('Verify isNotEmptyString()', () => {
     expect(isNotEmptyString('')).toBe(false)
     expect(isNotEmptyString(' ')).toBe(false)
@@ -411,22 +389,6 @@ await describe('Utils test suite', async () => {
     expect(isNotEmptyString(new WeakSet())).toBe(false)
   })
 
-  await it('Verify isEmptyArray()', () => {
-    expect(isEmptyArray([])).toBe(true)
-    expect(isEmptyArray([1, 2])).toBe(false)
-    expect(isEmptyArray(['1', '2'])).toBe(false)
-    expect(isEmptyArray(undefined)).toBe(false)
-    expect(isEmptyArray(null)).toBe(false)
-    expect(isEmptyArray('')).toBe(false)
-    expect(isEmptyArray('test')).toBe(false)
-    expect(isEmptyArray(0)).toBe(false)
-    expect(isEmptyArray({})).toBe(false)
-    expect(isEmptyArray(new Map())).toBe(false)
-    expect(isEmptyArray(new Set())).toBe(false)
-    expect(isEmptyArray(new WeakMap())).toBe(false)
-    expect(isEmptyArray(new WeakSet())).toBe(false)
-  })
-
   await it('Verify isNotEmptyArray()', () => {
     expect(isNotEmptyArray([])).toBe(false)
     expect(isNotEmptyArray([1, 2])).toBe(true)
@@ -443,17 +405,6 @@ await describe('Utils test suite', async () => {
     expect(isNotEmptyArray(new WeakSet())).toBe(false)
   })
 
-  await it('Verify isEmptyObject()', () => {
-    expect(isEmptyObject({})).toBe(true)
-    expect(isEmptyObject({ 1: 1, 2: 2 })).toBe(false)
-    expect(isEmptyObject([])).toBe(false)
-    expect(isEmptyObject([1, 2])).toBe(false)
-    expect(isEmptyObject(new Map())).toBe(false)
-    expect(isEmptyObject(new Set())).toBe(false)
-    expect(isEmptyObject(new WeakMap())).toBe(false)
-    expect(isEmptyObject(new WeakSet())).toBe(false)
-  })
-
   await it('Verify isArraySorted()', () => {
     expect(
       isArraySorted([], (a, b) => {
@@ -470,21 +421,6 @@ await describe('Utils test suite', async () => {
     expect(isArraySorted<number>([2, 1, 3, 4, 5], (a, b) => a - b)).toBe(false)
   })
 
-  await it('Verify once()', () => {
-    let called = 0
-    const fn = (): number => ++called
-    const onceFn = once(fn, this)
-    const result1 = onceFn()
-    expect(called).toBe(1)
-    expect(result1).toBe(1)
-    const result2 = onceFn()
-    expect(called).toBe(1)
-    expect(result2).toBe(1)
-    const result3 = onceFn()
-    expect(called).toBe(1)
-    expect(result3).toBe(1)
-  })
-
   await it('Verify min()', () => {
     expect(min()).toBe(Infinity)
     expect(min(0, 1)).toBe(0)