@ya-modbus/driver-loader
v0.7.0
Published
Dynamic driver loader for ya-modbus device drivers
Readme
@ya-modbus/driver-loader
Dynamic driver loader for ya-modbus device drivers.
Installation
npm install @ya-modbus/driver-loaderUsage
Auto-detect driver from current directory
import { loadDriver } from '@ya-modbus/driver-loader'
const driver = await loadDriver({})Load specific driver package
import { loadDriver } from '@ya-modbus/driver-loader'
const driver = await loadDriver({ driverPackage: '@ya-modbus/driver-xymd1' })Error Handling
The driver-loader exports custom error classes for type-safe error handling:
import {
loadDriver,
ValidationError,
DriverNotFoundError,
PackageJsonError,
} from '@ya-modbus/driver-loader'
try {
const driver = await loadDriver({ driverPackage: 'my-driver' })
} catch (error) {
// Type-safe error handling with instanceof
if (error instanceof DriverNotFoundError) {
console.error(`Package not found: ${error.packageName}`)
console.error(`Install with: npm install ${error.packageName}`)
} else if (error instanceof ValidationError) {
console.error(`Validation failed for field: ${error.field}`)
console.error(`Error: ${error.message}`)
} else if (error instanceof PackageJsonError) {
console.error('package.json issue:', error.message)
} else {
console.error('Unexpected error:', error)
}
}Error Types:
ValidationError: Driver configuration validation failedfield?: string- The configuration field that failed validation- Example: Invalid DEFAULT_CONFIG, missing createDriver function
DriverNotFoundError: Driver package not found or cannot be loadedpackageName: string- The package that couldn't be found- Example: Package not installed, wrong package name
PackageJsonError: package.json not found or invalid- Example: Missing package.json, invalid JSON, missing ya-modbus-driver keyword
Custom Logging
You can provide a custom logger to control warning and debug output:
import { loadDriver, type Logger } from '@ya-modbus/driver-loader'
const logger: Logger = {
warn: (msg) => myLogger.warning('[DRIVER]', msg),
debug: (msg) => myLogger.debug('[DRIVER]', msg), // Optional
}
const driver = await loadDriver({
driverPackage: 'my-driver',
logger,
})API
loadDriver(options?: LoadDriverOptions): Promise<LoadedDriver>
Loads a ya-modbus driver package and validates its exports.
Options:
driverPackage(optional): Name of the driver package to load. If omitted, auto-detects from current directory's package.json.
Returns:
LoadedDriverobject containing:createDriver: Factory function to create driver instances (required)devices: Device registry for multi-device drivers (optional)defaultConfig: Default configuration for serial or TCP (optional)supportedConfig: Configuration constraints (optional)
Throws:
- Error if driver package is not found
- Error if driver exports are invalid
- Error if configuration validation fails
clearDriverCache(): void
Clears the driver cache. Useful for testing or when you need to reload drivers.
When to use:
- In tests: Clear cache between test cases to ensure isolation
- After package updates: Force reload of updated driver packages
- During development: Reload drivers after making changes
import { clearDriverCache } from '@ya-modbus/driver-loader'
// In test setup
beforeEach(() => {
clearDriverCache() // Ensure each test starts with clean cache
})
// After updating a driver package
await updateDriver('my-driver')
clearDriverCache() // Force reload on next loadDriver callgetDriverCacheStats(): DriverCacheStats
Returns cache statistics including hits, misses, and current cache size.
Returns:
DriverCacheStatsobject containing:hits: Number of cache hitsmisses: Number of cache missessize: Number of cached drivers
Cache Behavior:
- Automatic caching: Drivers are cached by package name after first load
- Cache key: Package name (e.g., '@ya-modbus/driver-xymd1')
- Cache lifetime: Persists for the lifetime of the Node.js process
- Auto-detect mode: Even auto-detected drivers are cached by their package name
- No cache on errors: Failed loads are not cached, allowing retry
Example:
import { loadDriver, getDriverCacheStats } from '@ya-modbus/driver-loader'
// First load - cache miss
await loadDriver({ driverPackage: 'my-driver' })
console.log(getDriverCacheStats()) // { hits: 0, misses: 1, size: 1 }
// Second load - cache hit
await loadDriver({ driverPackage: 'my-driver' })
console.log(getDriverCacheStats()) // { hits: 1, misses: 1, size: 1 }Testing Utilities
The package provides testing utilities for applications using driver-loader.
import { createMockDriver, mockSystemDeps } from '@ya-modbus/driver-loader/testing'
// Create a mock driver
const mockDriver = createMockDriver({
defaultConfig: { baudRate: 9600 },
devices: { test: { manufacturer: 'Test', model: 'Model' } },
})
// Create mock system dependencies
const deps = mockSystemDeps({
importModule: jest.fn().mockResolvedValue(mockDriver),
})
// Use with loadDriver in tests
const driver = await loadDriver({ driverPackage: 'test-driver' }, deps)createMockDriver(options?: MockDriverOptions): LoadedDriver
Creates a mock driver for testing.
Options:
createDriver: Custom createDriver implementation (default: jest.fn())defaultConfig: Mock default configurationsupportedConfig: Mock supported configurationdevices: Mock device registry
mockSystemDeps(options?: MockSystemDepsOptions): SystemDependencies
Creates mock system dependencies for testing.
Options:
readFile: Custom readFile implementationimportModule: Custom importModule implementationgetCwd: Custom getCwd implementation (default: '/mock/cwd')
Troubleshooting
Package Not Found
If you encounter Driver package not found errors:
Verify the package is installed:
npm list ya-modbus-driver-<name>Install the driver package:
npm install ya-modbus-driver-<name>Check the package name:
- Ensure the package name in your code matches the actual npm package name
- Driver packages typically follow the naming convention:
ya-modbus-driver-<device>
Module Resolution Issues
If TypeScript or Node.js can't find @ya-modbus/driver-loader:
Check your package.json:
npm list @ya-modbus/driver-loaderReinstall dependencies:
npm installTypeScript module resolution:
- Ensure
"moduleResolution": "node"or"moduleResolution": "bundler"in tsconfig.json - Check that
"types"field isn't excluding driver-loader
- Ensure
For local driver development:
- The loader tries multiple import paths:
src/index.js,src/index.ts,dist/index.js - Build your driver before testing:
npm run build
- The loader tries multiple import paths:
Validation Failures
If driver validation fails with configuration errors:
ValidationError - Invalid DEFAULT_CONFIG:
// ❌ Wrong export const DEFAULT_CONFIG = { speed: 9600 } // Should be "baudRate" // ✅ Correct export const DEFAULT_CONFIG = { baudRate: 9600 }ValidationError - Invalid SUPPORTED_CONFIG:
// ❌ Wrong export const SUPPORTED_CONFIG = { baudRates: [9600] } // Should be "validBaudRates" // ✅ Correct export const SUPPORTED_CONFIG = { validBaudRates: [9600, 19200] }ValidationError - Missing createDriver:
// ❌ Wrong export function makeDriver() { ... } // ✅ Correct export function createDriver() { ... }PackageJsonError - Not a driver package:
Add the
ya-modbus-driverkeyword to your package.json:{ "name": "ya-modbus-driver-mydevice", "keywords": ["ya-modbus-driver"] }Configuration inconsistency warnings:
Ensure DEFAULT_CONFIG values are within SUPPORTED_CONFIG constraints:
// ❌ Inconsistent export const DEFAULT_CONFIG = { baudRate: 115200 } export const SUPPORTED_CONFIG = { validBaudRates: [9600, 19200] } // ✅ Consistent export const DEFAULT_CONFIG = { baudRate: 9600 } export const SUPPORTED_CONFIG = { validBaudRates: [9600, 19200] }
Getting More Help
For additional debugging:
Enable verbose logging:
const logger = { warn: (msg: string) => console.warn('[DRIVER]', msg), debug: (msg: string) => console.debug('[DRIVER]', msg), } const driver = await loadDriver({ logger })Check cache statistics:
import { getDriverCacheStats } from '@ya-modbus/driver-loader' console.log(getDriverCacheStats())Clear the cache:
import { clearDriverCache } from '@ya-modbus/driver-loader' clearDriverCache()
License
GPL-3.0-or-later
