]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor(utils): audit fixes — dedup, data-driven config, lazy logger, DRY
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 6 Mar 2026 20:50:55 +0000 (21:50 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 6 Mar 2026 20:51:30 +0000 (21:51 +0100)
17 files changed:
src/charging-station/ChargingStation.ts
src/charging-station/IdTagsCache.ts
src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts
src/charging-station/ocpp/auth/services/OCPPAuthServiceFactory.ts
src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts
src/charging-station/ocpp/auth/strategies/CertificateAuthStrategy.ts
src/charging-station/ocpp/auth/strategies/LocalAuthStrategy.ts
src/charging-station/ocpp/auth/strategies/RemoteAuthStrategy.ts
src/charging-station/ocpp/auth/utils/ConfigValidator.ts
src/utils/ChargingStationConfigurationUtils.ts
src/utils/Configuration.ts
src/utils/ConfigurationUtils.ts
src/utils/FileUtils.ts
src/utils/Logger.ts
src/utils/MessageChannelUtils.ts
src/utils/Utils.ts
tests/utils/ConfigurationUtils.test.ts

index f3df70b3c47b01c58fd39e93b1b529584b3f37b4..ef8014f49bac75dd39cec0954556bcf9e5a4bf89 100644 (file)
@@ -922,7 +922,6 @@ export class ChargingStation extends EventEmitter {
           this.templateFile,
           FileType.ChargingStationTemplate,
           this.logPrefix(),
-          undefined,
           (event, filename): void => {
             if (isNotEmptyString(filename) && event === 'change') {
               try {
index 9c94872ab081476238b3d8df2b2108d47daf0d54..6aed7fb615f24e1212363307690f5cf757e15518 100644 (file)
@@ -176,7 +176,6 @@ export class IdTagsCache {
         file,
         FileType.Authorization,
         this.logPrefix(file),
-        undefined,
         (event, filename) => {
           if (isNotEmptyString(filename) && event === 'change') {
             try {
index 7f76a18e3f82e79d2291db8e2c3d4cdbab913751..44f3a2daa514d1bc05edf236ead9ec5f3f2f9903 100644 (file)
@@ -1,7 +1,7 @@
 import type { AuthCache, CacheStats } from '../interfaces/OCPPAuthService.js'
 import type { AuthorizationResult } from '../types/AuthTypes.js'
 
-import { logger } from '../../../../utils/Logger.js'
+import { logger } from '../../../../utils/index.js'
 import { AuthorizationStatus } from '../types/AuthTypes.js'
 
 /**
index da36b3096c4cc10b892233128097f66d3cbe260a..8f4414dfe67bc960802a62bd42d82b3b37a74334 100644 (file)
@@ -3,7 +3,7 @@ import type { OCPPAuthService } from '../interfaces/OCPPAuthService.js'
 
 import { OCPPError } from '../../../../exception/OCPPError.js'
 import { ErrorType } from '../../../../types/index.js'
-import { logger } from '../../../../utils/Logger.js'
+import { logger } from '../../../../utils/index.js'
 import { OCPPAuthServiceImpl } from './OCPPAuthServiceImpl.js'
 
 const moduleName = 'OCPPAuthServiceFactory'
index 8f3533f2772a950f4663345553ea6a358a0118e0..3a926e3452986fe59821c7db6b6ff0bd2a39d997 100644 (file)
@@ -4,7 +4,7 @@ import type { OCPP20AuthAdapter } from '../adapters/OCPP20AuthAdapter.js'
 import { OCPPError } from '../../../../exception/OCPPError.js'
 import { ErrorType } from '../../../../types/index.js'
 import { OCPPVersion } from '../../../../types/ocpp/OCPPVersion.js'
-import { logger } from '../../../../utils/Logger.js'
+import { logger } from '../../../../utils/index.js'
 import { type ChargingStation } from '../../../ChargingStation.js'
 import { AuthComponentFactory } from '../factories/AuthComponentFactory.js'
 import {
index f207acaef0ad045aa1f937f99cbda44b9d5c774a..758f531cc3b465707898e4f12a9c085480646789 100644 (file)
@@ -8,8 +8,7 @@ import type {
 } from '../types/AuthTypes.js'
 
 import { OCPPVersion } from '../../../../types/index.js'
-import { isNotEmptyString, sleep } from '../../../../utils/index.js'
-import { logger } from '../../../../utils/Logger.js'
+import { isNotEmptyString, logger, sleep } from '../../../../utils/index.js'
 import { AuthenticationMethod, AuthorizationStatus, IdentifierType } from '../types/AuthTypes.js'
 
 /**
index 200199b83114bc41b6d14c6c3ff1e6e5fc7f5c9c..415c21277c3777b063d1e135a903aa9bb8c5d912 100644 (file)
@@ -5,7 +5,7 @@ import type {
 } from '../interfaces/OCPPAuthService.js'
 import type { AuthConfiguration, AuthorizationResult, AuthRequest } from '../types/AuthTypes.js'
 
-import { logger } from '../../../../utils/Logger.js'
+import { logger } from '../../../../utils/index.js'
 import {
   AuthContext,
   AuthenticationError,
index 7a31eaa4dd773ff4ff305df6cbb5c97baa2691b6..b0f917b8e21de466b0d819ae5dedaf2cb1de5a3e 100644 (file)
@@ -7,7 +7,7 @@ import type {
 import type { AuthConfiguration, AuthorizationResult, AuthRequest } from '../types/AuthTypes.js'
 
 import { OCPPVersion } from '../../../../types/ocpp/OCPPVersion.js'
-import { logger } from '../../../../utils/Logger.js'
+import { logger } from '../../../../utils/index.js'
 import {
   AuthenticationError,
   AuthenticationMethod,
index e1bec914181f8a603cd910e19334f90fdc7dd601..fa6607eacd503679b36cb9042e4c25b3b88b1e42 100644 (file)
@@ -1,4 +1,4 @@
-import { logger } from '../../../../utils/Logger.js'
+import { logger } from '../../../../utils/index.js'
 import { type AuthConfiguration, AuthenticationError, AuthErrorCode } from '../types/AuthTypes.js'
 
 /**
index 38c48a327790c75847aacbe60ffe4492b301fc14..19a62cdbd347de27b65d3a825dfca5131e23b619 100644 (file)
@@ -39,7 +39,6 @@ export const buildEvsesStatus = (
   chargingStation: ChargingStation,
   outputFormat: OutputFormat = OutputFormat.configuration
 ): (EvseStatusConfiguration | EvseStatusWorkerType)[] => {
-  // eslint-disable-next-line array-callback-return
   return [...chargingStation.evses.values()].map(evseStatus => {
     const connectorsStatus = [...evseStatus.connectors.values()].map(
       ({
@@ -49,20 +48,22 @@ export const buildEvsesStatus = (
         ...connectorStatus
       }) => connectorStatus
     )
-    let status: EvseStatusConfiguration
     switch (outputFormat) {
-      case OutputFormat.configuration:
-        status = {
+      case OutputFormat.configuration: {
+        const status: EvseStatusConfiguration = {
           ...evseStatus,
           connectorsStatus,
         }
         delete (status as EvseStatusWorkerType).connectors
         return status
+      }
       case OutputFormat.worker:
         return {
           ...evseStatus,
           connectors: connectorsStatus,
         }
+      default:
+        throw new RangeError(`Unknown output format: ${outputFormat as string}`)
     }
   })
 }
index ea1640998ea8ddf17a4d10e85a631ae035e78d7b..b4eb5538a18a59a3e77707f736b78f551c8ec3d6 100644 (file)
@@ -30,10 +30,10 @@ import {
   buildPerformanceUriFilePath,
   checkWorkerElementsPerWorker,
   getDefaultPerformanceStorageUri,
-  handleFileException,
   logPrefix,
 } from './ConfigurationUtils.js'
 import { Constants } from './Constants.js'
+import { handleFileException } from './ErrorUtils.js'
 import { has, isCFEnvironment, mergeDeepRight, once } from './Utils.js'
 
 type ConfigurationSectionType =
@@ -142,7 +142,8 @@ export class Configuration {
           Configuration.configurationFile,
           FileType.Configuration,
           error as NodeJS.ErrnoException,
-          logPrefix()
+          logPrefix(),
+          { consoleOut: true }
         )
       }
     }
@@ -201,53 +202,31 @@ export class Configuration {
   }
 
   private static buildLogSection (): LogConfiguration {
-    const deprecatedLogConfiguration: LogConfiguration = {
-      ...(has('logEnabled', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        enabled: Configuration.getConfigurationData()?.logEnabled,
-      }),
-      ...(has('logFile', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        file: Configuration.getConfigurationData()?.logFile,
-      }),
-      ...(has('logErrorFile', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        errorFile: Configuration.getConfigurationData()?.logErrorFile,
-      }),
-      ...(has('logStatisticsInterval', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        statisticsInterval: Configuration.getConfigurationData()?.logStatisticsInterval,
-      }),
-      ...(has('logLevel', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        level: Configuration.getConfigurationData()?.logLevel,
-      }),
-      ...(has('logConsole', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        console: Configuration.getConfigurationData()?.logConsole,
-      }),
-      ...(has('logFormat', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        format: Configuration.getConfigurationData()?.logFormat,
-      }),
-      ...(has('logRotate', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        rotate: Configuration.getConfigurationData()?.logRotate,
-      }),
-      ...(has('logMaxFiles', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        maxFiles: Configuration.getConfigurationData()?.logMaxFiles,
-      }),
-      ...(has('logMaxSize', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        maxSize: Configuration.getConfigurationData()?.logMaxSize,
-      }),
+    const configData = Configuration.getConfigurationData()
+    const deprecatedLogKeyMap: [string, string][] = [
+      ['logEnabled', 'enabled'],
+      ['logFile', 'file'],
+      ['logErrorFile', 'errorFile'],
+      ['logStatisticsInterval', 'statisticsInterval'],
+      ['logLevel', 'level'],
+      ['logConsole', 'console'],
+      ['logFormat', 'format'],
+      ['logRotate', 'rotate'],
+      ['logMaxFiles', 'maxFiles'],
+      ['logMaxSize', 'maxSize'],
+    ]
+    const deprecatedLogConfiguration: Record<string, unknown> = {}
+    for (const [deprecatedKey, newKey] of deprecatedLogKeyMap) {
+      if (has(deprecatedKey, configData)) {
+        deprecatedLogConfiguration[newKey] = (configData as unknown as Record<string, unknown>)[
+          deprecatedKey
+        ]
+      }
     }
     const logConfiguration: LogConfiguration = {
       ...defaultLogConfiguration,
-      ...deprecatedLogConfiguration,
-      ...(has(ConfigurationSection.log, Configuration.getConfigurationData()) &&
-        Configuration.getConfigurationData()?.log),
+      ...(deprecatedLogConfiguration as Partial<LogConfiguration>),
+      ...(has(ConfigurationSection.log, configData) && configData?.log),
     }
     return logConfiguration
   }
@@ -310,44 +289,34 @@ export class Configuration {
   }
 
   private static buildWorkerSection (): WorkerConfiguration {
-    const deprecatedWorkerConfiguration: WorkerConfiguration = {
-      ...(has('workerProcess', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        processType: Configuration.getConfigurationData()?.workerProcess,
-      }),
-      ...(has('workerStartDelay', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        startDelay: Configuration.getConfigurationData()?.workerStartDelay,
-      }),
-      ...(has('chargingStationsPerWorker', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        elementsPerWorker: Configuration.getConfigurationData()?.chargingStationsPerWorker,
-      }),
-      ...(has('elementAddDelay', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        elementAddDelay: Configuration.getConfigurationData()?.elementAddDelay,
-      }),
-      ...(has('elementStartDelay', Configuration.getConfigurationData()?.worker) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        elementAddDelay: Configuration.getConfigurationData()?.worker?.elementStartDelay,
-      }),
-      ...(has('workerPoolMinSize', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        poolMinSize: Configuration.getConfigurationData()?.workerPoolMinSize,
-      }),
-      ...(has('workerPoolMaxSize', Configuration.getConfigurationData()) && {
-        // eslint-disable-next-line @typescript-eslint/no-deprecated
-        poolMaxSize: Configuration.getConfigurationData()?.workerPoolMaxSize,
-      }),
+    const configData = Configuration.getConfigurationData()
+    const deprecatedWorkerKeyMap: [string, string][] = [
+      ['workerProcess', 'processType'],
+      ['workerStartDelay', 'startDelay'],
+      ['chargingStationsPerWorker', 'elementsPerWorker'],
+      ['elementAddDelay', 'elementAddDelay'],
+      ['workerPoolMinSize', 'poolMinSize'],
+      ['workerPoolMaxSize', 'poolMaxSize'],
+    ]
+    const deprecatedWorkerConfiguration: Record<string, unknown> = {}
+    for (const [deprecatedKey, newKey] of deprecatedWorkerKeyMap) {
+      if (has(deprecatedKey, configData)) {
+        deprecatedWorkerConfiguration[newKey] = (configData as unknown as Record<string, unknown>)[
+          deprecatedKey
+        ]
+      }
+    }
+    if (has('elementStartDelay', configData?.worker)) {
+      deprecatedWorkerConfiguration.elementAddDelay = (
+        configData?.worker as unknown as Record<string, unknown>
+      ).elementStartDelay
     }
-    has('workerPoolStrategy', Configuration.getConfigurationData()) &&
-      // eslint-disable-next-line @typescript-eslint/no-deprecated
-      delete Configuration.getConfigurationData()?.workerPoolStrategy
+    has('workerPoolStrategy', configData) &&
+      delete (configData as unknown as Record<string, unknown>).workerPoolStrategy
     const workerConfiguration: WorkerConfiguration = {
       ...defaultWorkerConfiguration,
-      ...deprecatedWorkerConfiguration,
-      ...(has(ConfigurationSection.worker, Configuration.getConfigurationData()) &&
-        Configuration.getConfigurationData()?.worker),
+      ...(deprecatedWorkerConfiguration as Partial<WorkerConfiguration>),
+      ...(has(ConfigurationSection.worker, configData) && configData?.worker),
     }
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
     checkWorkerProcessType(workerConfiguration.processType!)
@@ -382,29 +351,133 @@ export class Configuration {
   }
 
   private static checkDeprecatedConfigurationKeys (): void {
-    // connection timeout
-    Configuration.warnDeprecatedConfigurationKey(
-      'autoReconnectTimeout',
-      undefined,
-      "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead"
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'connectionTimeout',
-      undefined,
-      "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead"
-    )
-    // connection retries
-    Configuration.warnDeprecatedConfigurationKey(
-      'autoReconnectMaxRetries',
-      undefined,
-      'Use it in charging station template instead'
-    )
-    // station template url(s)
-    Configuration.warnDeprecatedConfigurationKey(
-      'stationTemplateURLs',
-      undefined,
-      "Use 'stationTemplateUrls' instead"
-    )
+    const deprecatedKeys: [string, ConfigurationSection | undefined, string][] = [
+      // connection timeout
+      [
+        'autoReconnectTimeout',
+        undefined,
+        "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead",
+      ],
+      [
+        'connectionTimeout',
+        undefined,
+        "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead",
+      ],
+      // connection retries
+      ['autoReconnectMaxRetries', undefined, 'Use it in charging station template instead'],
+      // station template url(s)
+      ['stationTemplateURLs', undefined, "Use 'stationTemplateUrls' instead"],
+      // supervision url(s)
+      ['supervisionURLs', undefined, "Use 'supervisionUrls' instead"],
+      // supervision urls distribution
+      ['distributeStationToTenantEqually', undefined, "Use 'supervisionUrlDistribution' instead"],
+      ['distributeStationsToTenantsEqually', undefined, "Use 'supervisionUrlDistribution' instead"],
+      // worker section
+      [
+        'useWorkerPool',
+        undefined,
+        `Use '${ConfigurationSection.worker}' section to define the type of worker process model instead`,
+      ],
+      [
+        'workerProcess',
+        undefined,
+        `Use '${ConfigurationSection.worker}' section to define the type of worker process model instead`,
+      ],
+      [
+        'workerStartDelay',
+        undefined,
+        `Use '${ConfigurationSection.worker}' section to define the worker start delay instead`,
+      ],
+      [
+        'chargingStationsPerWorker',
+        undefined,
+        `Use '${ConfigurationSection.worker}' section to define the number of element(s) per worker instead`,
+      ],
+      [
+        'elementAddDelay',
+        undefined,
+        `Use '${ConfigurationSection.worker}' section to define the worker's element add delay instead`,
+      ],
+      [
+        'workerPoolMinSize',
+        undefined,
+        `Use '${ConfigurationSection.worker}' section to define the worker pool minimum size instead`,
+      ],
+      [
+        'workerPoolSize',
+        undefined,
+        `Use '${ConfigurationSection.worker}' section to define the worker pool maximum size instead`,
+      ],
+      [
+        'workerPoolMaxSize',
+        undefined,
+        `Use '${ConfigurationSection.worker}' section to define the worker pool maximum size instead`,
+      ],
+      [
+        'workerPoolStrategy',
+        undefined,
+        `Use '${ConfigurationSection.worker}' section to define the worker pool strategy instead`,
+      ],
+      ['poolStrategy', ConfigurationSection.worker, 'Not publicly exposed to end users'],
+      ['elementStartDelay', ConfigurationSection.worker, "Use 'elementAddDelay' instead"],
+      // log section
+      [
+        'logEnabled',
+        undefined,
+        `Use '${ConfigurationSection.log}' section to define the logging enablement instead`,
+      ],
+      [
+        'logFile',
+        undefined,
+        `Use '${ConfigurationSection.log}' section to define the log file instead`,
+      ],
+      [
+        'logErrorFile',
+        undefined,
+        `Use '${ConfigurationSection.log}' section to define the log error file instead`,
+      ],
+      [
+        'logConsole',
+        undefined,
+        `Use '${ConfigurationSection.log}' section to define the console logging enablement instead`,
+      ],
+      [
+        'logStatisticsInterval',
+        undefined,
+        `Use '${ConfigurationSection.log}' section to define the log statistics interval instead`,
+      ],
+      [
+        'logLevel',
+        undefined,
+        `Use '${ConfigurationSection.log}' section to define the log level instead`,
+      ],
+      [
+        'logFormat',
+        undefined,
+        `Use '${ConfigurationSection.log}' section to define the log format instead`,
+      ],
+      [
+        'logRotate',
+        undefined,
+        `Use '${ConfigurationSection.log}' section to define the log rotation enablement instead`,
+      ],
+      [
+        'logMaxFiles',
+        undefined,
+        `Use '${ConfigurationSection.log}' section to define the log maximum files instead`,
+      ],
+      [
+        'logMaxSize',
+        undefined,
+        `Use '${ConfigurationSection.log}' section to define the log maximum size instead`,
+      ],
+      // performanceStorage section
+      ['URI', ConfigurationSection.performanceStorage, "Use 'uri' instead"],
+    ]
+    for (const [key, section, msg] of deprecatedKeys) {
+      Configuration.warnDeprecatedConfigurationKey(key, section, msg)
+    }
+    // station template url(s) remapping
     Configuration.getConfigurationData()?.['stationTemplateURLs' as keyof ConfigurationData] !=
       null &&
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -424,79 +497,7 @@ export class Configuration {
         }
       }
     )
-    // supervision url(s)
-    Configuration.warnDeprecatedConfigurationKey(
-      'supervisionURLs',
-      undefined,
-      "Use 'supervisionUrls' instead"
-    )
-    // supervision urls distribution
-    Configuration.warnDeprecatedConfigurationKey(
-      'distributeStationToTenantEqually',
-      undefined,
-      "Use 'supervisionUrlDistribution' instead"
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'distributeStationsToTenantsEqually',
-      undefined,
-      "Use 'supervisionUrlDistribution' instead"
-    )
-    // worker section
-    Configuration.warnDeprecatedConfigurationKey(
-      'useWorkerPool',
-      undefined,
-      `Use '${ConfigurationSection.worker}' section to define the type of worker process model instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'workerProcess',
-      undefined,
-      `Use '${ConfigurationSection.worker}' section to define the type of worker process model instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'workerStartDelay',
-      undefined,
-      `Use '${ConfigurationSection.worker}' section to define the worker start delay instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'chargingStationsPerWorker',
-      undefined,
-      `Use '${ConfigurationSection.worker}' section to define the number of element(s) per worker instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'elementAddDelay',
-      undefined,
-      `Use '${ConfigurationSection.worker}' section to define the worker's element add delay instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'workerPoolMinSize',
-      undefined,
-      `Use '${ConfigurationSection.worker}' section to define the worker pool minimum size instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'workerPoolSize',
-      undefined,
-      `Use '${ConfigurationSection.worker}' section to define the worker pool maximum size instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'workerPoolMaxSize',
-      undefined,
-      `Use '${ConfigurationSection.worker}' section to define the worker pool maximum size instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'workerPoolStrategy',
-      undefined,
-      `Use '${ConfigurationSection.worker}' section to define the worker pool strategy instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'poolStrategy',
-      ConfigurationSection.worker,
-      'Not publicly exposed to end users'
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'elementStartDelay',
-      ConfigurationSection.worker,
-      "Use 'elementAddDelay' instead"
-    )
+    // worker section: staticPool check
     if (
       Configuration.getConfigurationData()?.worker?.processType ===
       ('staticPool' as WorkerProcessType)
@@ -507,63 +508,6 @@ export class Configuration {
         )}`
       )
     }
-    // log section
-    Configuration.warnDeprecatedConfigurationKey(
-      'logEnabled',
-      undefined,
-      `Use '${ConfigurationSection.log}' section to define the logging enablement instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'logFile',
-      undefined,
-      `Use '${ConfigurationSection.log}' section to define the log file instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'logErrorFile',
-      undefined,
-      `Use '${ConfigurationSection.log}' section to define the log error file instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'logConsole',
-      undefined,
-      `Use '${ConfigurationSection.log}' section to define the console logging enablement instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'logStatisticsInterval',
-      undefined,
-      `Use '${ConfigurationSection.log}' section to define the log statistics interval instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'logLevel',
-      undefined,
-      `Use '${ConfigurationSection.log}' section to define the log level instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'logFormat',
-      undefined,
-      `Use '${ConfigurationSection.log}' section to define the log format instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'logRotate',
-      undefined,
-      `Use '${ConfigurationSection.log}' section to define the log rotation enablement instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'logMaxFiles',
-      undefined,
-      `Use '${ConfigurationSection.log}' section to define the log maximum files instead`
-    )
-    Configuration.warnDeprecatedConfigurationKey(
-      'logMaxSize',
-      undefined,
-      `Use '${ConfigurationSection.log}' section to define the log maximum size instead`
-    )
-    // performanceStorage section
-    Configuration.warnDeprecatedConfigurationKey(
-      'URI',
-      ConfigurationSection.performanceStorage,
-      "Use 'uri' instead"
-    )
     // uiServer section
     if (has('uiWebSocketServer', Configuration.getConfigurationData())) {
       console.error(
@@ -617,7 +561,8 @@ export class Configuration {
         Configuration.configurationFile,
         FileType.Configuration,
         error as NodeJS.ErrnoException,
-        logPrefix()
+        logPrefix(),
+        { consoleOut: true }
       )
     }
   }
index f1f5c0cc5929f924f777fc5b490ccac253ff6201..9cd6a59c5744be51e467eafaa17c69e9afde67e1 100644 (file)
@@ -1,10 +1,9 @@
-import chalk from 'chalk'
 import { dirname, join, resolve } from 'node:path'
 import { fileURLToPath, pathToFileURL } from 'node:url'
 
-import { type ElementsPerWorkerType, type FileType, StorageType } from '../types/index.js'
+import { type ElementsPerWorkerType, StorageType } from '../types/index.js'
 import { Constants } from './Constants.js'
-import { isNotEmptyString, logPrefix as utilsLogPrefix } from './Utils.js'
+import { logPrefix as utilsLogPrefix } from './Utils.js'
 
 export const logPrefix = (): string => {
   return utilsLogPrefix(' Simulator configuration |')
@@ -35,46 +34,6 @@ export const getDefaultPerformanceStorageUri = (storageType: StorageType): strin
   }
 }
 
-export const handleFileException = (
-  file: string,
-  fileType: FileType,
-  error: NodeJS.ErrnoException,
-  logPfx: string
-): void => {
-  const prefix = isNotEmptyString(logPfx) ? `${logPfx} ` : ''
-  let logMsg: string
-  switch (error.code) {
-    case 'EACCES':
-      logMsg = `${fileType} file ${file} access denied: `
-      break
-    case 'EEXIST':
-      logMsg = `${fileType} file ${file} already exists: `
-      break
-    case 'EISDIR':
-      logMsg = `${fileType} file ${file} is a directory: `
-      break
-    case 'ENOENT':
-      logMsg = `${fileType} file ${file} not found: `
-      break
-    case 'ENOSPC':
-      logMsg = `${fileType} file ${file} no space left on device: `
-      break
-    case 'ENOTDIR':
-      logMsg = `${fileType} file ${file} parent is not a directory: `
-      break
-    case 'EPERM':
-      logMsg = `${fileType} file ${file} permission denied: `
-      break
-    case 'EROFS':
-      logMsg = `${fileType} file ${file} read-only file system: `
-      break
-    default:
-      logMsg = `${fileType} file ${file} error: `
-  }
-  console.error(`${chalk.green(prefix)}${chalk.red(logMsg)}`, error)
-  throw error
-}
-
 export const checkWorkerElementsPerWorker = (
   elementsPerWorker: ElementsPerWorkerType | undefined
 ): void => {
index d2e62036b4257c78f6521f069c73baf62fac2695..769f5da71489a443a26c010b6b2a47a9c8ca8b5f 100644 (file)
@@ -1,29 +1,16 @@
-import { type FSWatcher, readFileSync, watch, type WatchListener } from 'node:fs'
+import { type FSWatcher, watch, type WatchListener } from 'node:fs'
 
-import type { FileType, JsonType } from '../types/index.js'
+import type { FileType } from '../types/index.js'
 
 import { handleFileException } from './ErrorUtils.js'
 import { logger } from './Logger.js'
 import { isNotEmptyString } from './Utils.js'
 
-export const watchJsonFile = <T extends JsonType>(
+export const watchJsonFile = (
   file: string,
   fileType: FileType,
   logPrefix: string,
-  refreshedVariable?: T,
-  listener: WatchListener<string> = (event, filename) => {
-    if (isNotEmptyString(filename) && event === 'change') {
-      try {
-        logger.debug(`${logPrefix} ${fileType} file ${file} has changed, reload`)
-        refreshedVariable != null &&
-          (refreshedVariable = JSON.parse(readFileSync(file, 'utf8')) as T)
-      } catch (error) {
-        handleFileException(file, fileType, error as NodeJS.ErrnoException, logPrefix, {
-          throwError: false,
-        })
-      }
-    }
-  }
+  listener: WatchListener<string>
 ): FSWatcher | undefined => {
   if (isNotEmptyString(file)) {
     try {
index e8b3af6450e5a3d64ee042413fc3c3677a72ccdd..fd282638d7282eb8f32a025231f4e94c06a6352d 100644 (file)
 import type { FormatWrap } from 'logform'
 
-import { createLogger, format, type transport, transports as WinstonTransports } from 'winston'
+import {
+  createLogger,
+  format,
+  type transport,
+  type Logger as WinstonLogger,
+  transports as WinstonTransports,
+} from 'winston'
 import DailyRotateFile from 'winston-daily-rotate-file'
 
 import { ConfigurationSection, type LogConfiguration } from '../types/index.js'
 import { Configuration } from './Configuration.js'
 import { insertAt, isNotEmptyString } from './Utils.js'
 
-const logConfiguration = Configuration.getConfigurationSection<LogConfiguration>(
-  ConfigurationSection.log
-)
-const transports: transport[] = []
-if (logConfiguration.rotate === true) {
-  const logMaxFiles = logConfiguration.maxFiles
-  const logMaxSize = logConfiguration.maxSize
-  if (isNotEmptyString(logConfiguration.errorFile)) {
-    transports.push(
-      new DailyRotateFile({
-        filename: insertAt(
-          logConfiguration.errorFile,
-          '-%DATE%',
-          logConfiguration.errorFile.indexOf('.log')
-        ),
-        level: 'error',
-        ...(logMaxFiles != null && { maxFiles: logMaxFiles }),
-        ...(logMaxSize != null && { maxSize: logMaxSize }),
-      })
-    )
-  }
-  if (isNotEmptyString(logConfiguration.file)) {
-    transports.push(
-      new DailyRotateFile({
-        filename: insertAt(logConfiguration.file, '-%DATE%', logConfiguration.file.indexOf('.log')),
-        ...(logMaxFiles != null && { maxFiles: logMaxFiles }),
-        ...(logMaxSize != null && { maxSize: logMaxSize }),
-      })
-    )
+let loggerInstance: undefined | WinstonLogger
+
+const getLoggerInstance = (): WinstonLogger => {
+  if (loggerInstance !== undefined) {
+    return loggerInstance
   }
-} else {
-  if (isNotEmptyString(logConfiguration.errorFile)) {
-    transports.push(
-      new WinstonTransports.File({
-        filename: logConfiguration.errorFile,
-        level: 'error',
-      })
-    )
+  const logConfiguration = Configuration.getConfigurationSection<LogConfiguration>(
+    ConfigurationSection.log
+  )
+  const logTransports: transport[] = []
+  if (logConfiguration.rotate === true) {
+    const logMaxFiles = logConfiguration.maxFiles
+    const logMaxSize = logConfiguration.maxSize
+    if (isNotEmptyString(logConfiguration.errorFile)) {
+      logTransports.push(
+        new DailyRotateFile({
+          filename: insertAt(
+            logConfiguration.errorFile,
+            '-%DATE%',
+            logConfiguration.errorFile.indexOf('.log')
+          ),
+          level: 'error',
+          ...(logMaxFiles != null && { maxFiles: logMaxFiles }),
+          ...(logMaxSize != null && { maxSize: logMaxSize }),
+        })
+      )
+    }
+    if (isNotEmptyString(logConfiguration.file)) {
+      logTransports.push(
+        new DailyRotateFile({
+          filename: insertAt(
+            logConfiguration.file,
+            '-%DATE%',
+            logConfiguration.file.indexOf('.log')
+          ),
+          ...(logMaxFiles != null && { maxFiles: logMaxFiles }),
+          ...(logMaxSize != null && { maxSize: logMaxSize }),
+        })
+      )
+    }
+  } else {
+    if (isNotEmptyString(logConfiguration.errorFile)) {
+      logTransports.push(
+        new WinstonTransports.File({
+          filename: logConfiguration.errorFile,
+          level: 'error',
+        })
+      )
+    }
+    if (isNotEmptyString(logConfiguration.file)) {
+      logTransports.push(
+        new WinstonTransports.File({
+          filename: logConfiguration.file,
+        })
+      )
+    }
   }
-  if (isNotEmptyString(logConfiguration.file)) {
-    transports.push(
-      new WinstonTransports.File({
-        filename: logConfiguration.file,
+  const logFormat = format.combine(
+    format.splat(),
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    (format[logConfiguration.format! as keyof FormatWrap] as FormatWrap)()
+  )
+  loggerInstance = createLogger({
+    format: logFormat,
+    level: logConfiguration.level,
+    silent: logConfiguration.enabled === false || logTransports.length === 0,
+    transports: logTransports,
+  })
+  //
+  // If enabled, log to the `console` with the format:
+  // `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
+  //
+  if (logConfiguration.console === true) {
+    loggerInstance.add(
+      new WinstonTransports.Console({
+        format: logFormat,
       })
     )
   }
+  return loggerInstance
 }
 
-const logFormat = format.combine(
-  format.splat(),
-  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-  (format[logConfiguration.format! as keyof FormatWrap] as FormatWrap)()
-)
-
-const logger = createLogger({
-  format: logFormat,
-  level: logConfiguration.level,
-  silent: logConfiguration.enabled === false || transports.length === 0,
-  transports,
+export const logger = new Proxy({} as WinstonLogger, {
+  get (target, property, receiver): unknown {
+    if (Reflect.has(target, property)) {
+      return Reflect.get(target, property, receiver) as unknown
+    }
+    return Reflect.get(getLoggerInstance(), property, receiver) as unknown
+  },
+  getOwnPropertyDescriptor (target, property) {
+    return (
+      Reflect.getOwnPropertyDescriptor(target, property) ??
+      Reflect.getOwnPropertyDescriptor(getLoggerInstance(), property)
+    )
+  },
+  getPrototypeOf () {
+    return Reflect.getPrototypeOf(getLoggerInstance())
+  },
+  has (target, property) {
+    return Reflect.has(target, property) || Reflect.has(getLoggerInstance(), property)
+  },
+  set (target, property, value, receiver) {
+    return Reflect.set(target, property, value, receiver)
+  },
 })
-
-//
-// If enabled, log to the `console` with the format:
-// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
-//
-if (logConfiguration.console === true) {
-  logger.add(
-    new WinstonTransports.Console({
-      format: logFormat,
-    })
-  )
-}
-
-export { logger }
index 41c380c7d5b3b43c2e4c8f0bd45b010638af4fdc..f40795e7e0b8aed4c779879fca9fe5eaab027ee2 100644 (file)
@@ -16,49 +16,59 @@ import {
   OutputFormat,
 } from './ChargingStationConfigurationUtils.js'
 
-export const buildAddedMessage = (
-  chargingStation: ChargingStation
+const buildChargingStationWorkerMessage = (
+  chargingStation: ChargingStation,
+  event: ChargingStationWorkerMessageEvents
 ): ChargingStationWorkerMessage<ChargingStationData> => {
   return {
     data: buildChargingStationDataPayload(chargingStation),
-    event: ChargingStationWorkerMessageEvents.added,
+    event,
   }
 }
 
+export const buildAddedMessage = (
+  chargingStation: ChargingStation
+): ChargingStationWorkerMessage<ChargingStationData> => {
+  return buildChargingStationWorkerMessage(
+    chargingStation,
+    ChargingStationWorkerMessageEvents.added
+  )
+}
+
 export const buildDeletedMessage = (
   chargingStation: ChargingStation
 ): ChargingStationWorkerMessage<ChargingStationData> => {
-  return {
-    data: buildChargingStationDataPayload(chargingStation),
-    event: ChargingStationWorkerMessageEvents.deleted,
-  }
+  return buildChargingStationWorkerMessage(
+    chargingStation,
+    ChargingStationWorkerMessageEvents.deleted
+  )
 }
 
 export const buildStartedMessage = (
   chargingStation: ChargingStation
 ): ChargingStationWorkerMessage<ChargingStationData> => {
-  return {
-    data: buildChargingStationDataPayload(chargingStation),
-    event: ChargingStationWorkerMessageEvents.started,
-  }
+  return buildChargingStationWorkerMessage(
+    chargingStation,
+    ChargingStationWorkerMessageEvents.started
+  )
 }
 
 export const buildStoppedMessage = (
   chargingStation: ChargingStation
 ): ChargingStationWorkerMessage<ChargingStationData> => {
-  return {
-    data: buildChargingStationDataPayload(chargingStation),
-    event: ChargingStationWorkerMessageEvents.stopped,
-  }
+  return buildChargingStationWorkerMessage(
+    chargingStation,
+    ChargingStationWorkerMessageEvents.stopped
+  )
 }
 
 export const buildUpdatedMessage = (
   chargingStation: ChargingStation
 ): ChargingStationWorkerMessage<ChargingStationData> => {
-  return {
-    data: buildChargingStationDataPayload(chargingStation),
-    event: ChargingStationWorkerMessageEvents.updated,
-  }
+  return buildChargingStationWorkerMessage(
+    chargingStation,
+    ChargingStationWorkerMessageEvents.updated
+  )
 }
 
 export const buildPerformanceStatisticsMessage = (
index 504ceb15a943a3eedfb67dbeddc96b539bdc2640..bc723324ab6f642ec37408c1c4b73e9e6c8d416a 100644 (file)
@@ -343,6 +343,9 @@ export const clone = <T>(object: T): T => {
 
 type AsyncFunctionType<A extends unknown[], R> = (...args: A) => PromiseLike<R>
 
+// eslint-disable-next-line @typescript-eslint/no-empty-function
+const AsyncFunctionConstructor = (async () => {}).constructor
+
 /**
  * Detects whether the given value is an asynchronous function or not.
  * @param fn - Unknown value.
@@ -350,8 +353,7 @@ type AsyncFunctionType<A extends unknown[], R> = (...args: A) => PromiseLike<R>
  * @internal
  */
 export const isAsyncFunction = (fn: unknown): fn is AsyncFunctionType<unknown[], unknown> => {
-  // eslint-disable-next-line @typescript-eslint/no-empty-function
-  return fn?.constructor === (async () => {}).constructor
+  return fn?.constructor === AsyncFunctionConstructor
 }
 
 export const isCFEnvironment = (): boolean => {
index 61d193144311e68acaca6c143ca3c209d24d5c54..983d87eaa9f222ce235e64abe92a7be3c43f4fe9 100644 (file)
@@ -10,9 +10,9 @@ import {
   buildPerformanceUriFilePath,
   checkWorkerElementsPerWorker,
   getDefaultPerformanceStorageUri,
-  handleFileException,
   logPrefix,
 } from '../../src/utils/ConfigurationUtils.js'
+import { handleFileException } from '../../src/utils/ErrorUtils.js'
 import { standardCleanup } from '../helpers/TestLifecycleHelpers.js'
 
 await describe('ConfigurationUtils', async () => {
@@ -52,7 +52,9 @@ await describe('ConfigurationUtils', async () => {
     const error = new Error() as NodeJS.ErrnoException
     error.code = 'ENOENT'
     expect(() => {
-      handleFileException('path/to/module.js', FileType.Authorization, error, 'log prefix |')
+      handleFileException('path/to/module.js', FileType.Authorization, error, 'log prefix |', {
+        consoleOut: true,
+      })
     }).toThrow(error)
     expect(mockConsoleError.mock.calls.length).toBe(1)
   })