@ya-modbus/driver-loader 0.4.1-refactor-scope-driver-packages.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/LICENSE +674 -0
- package/README.md +353 -0
- package/dist/config-validator.d.ts +53 -0
- package/dist/config-validator.d.ts.map +1 -0
- package/dist/config-validator.js +315 -0
- package/dist/config-validator.js.map +1 -0
- package/dist/errors.d.ts +69 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +89 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +122 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +242 -0
- package/dist/loader.js.map +1 -0
- package/dist/testing/index.d.ts +21 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +25 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing.d.ts +64 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +74 -0
- package/dist/testing.js.map +1 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# @ya-modbus/driver-loader
|
|
2
|
+
|
|
3
|
+
Dynamic driver loader for ya-modbus device drivers.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ya-modbus/driver-loader
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Auto-detect driver from current directory
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { loadDriver } from '@ya-modbus/driver-loader'
|
|
17
|
+
|
|
18
|
+
const driver = await loadDriver({})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Load specific driver package
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { loadDriver } from '@ya-modbus/driver-loader'
|
|
25
|
+
|
|
26
|
+
const driver = await loadDriver({ driverPackage: '@ya-modbus/driver-xymd1' })
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Error Handling
|
|
30
|
+
|
|
31
|
+
The driver-loader exports custom error classes for type-safe error handling:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import {
|
|
35
|
+
loadDriver,
|
|
36
|
+
ValidationError,
|
|
37
|
+
DriverNotFoundError,
|
|
38
|
+
PackageJsonError,
|
|
39
|
+
} from '@ya-modbus/driver-loader'
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const driver = await loadDriver({ driverPackage: 'my-driver' })
|
|
43
|
+
} catch (error) {
|
|
44
|
+
// Type-safe error handling with instanceof
|
|
45
|
+
if (error instanceof DriverNotFoundError) {
|
|
46
|
+
console.error(`Package not found: ${error.packageName}`)
|
|
47
|
+
console.error(`Install with: npm install ${error.packageName}`)
|
|
48
|
+
} else if (error instanceof ValidationError) {
|
|
49
|
+
console.error(`Validation failed for field: ${error.field}`)
|
|
50
|
+
console.error(`Error: ${error.message}`)
|
|
51
|
+
} else if (error instanceof PackageJsonError) {
|
|
52
|
+
console.error('package.json issue:', error.message)
|
|
53
|
+
} else {
|
|
54
|
+
console.error('Unexpected error:', error)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Error Types:**
|
|
60
|
+
|
|
61
|
+
- **`ValidationError`**: Driver configuration validation failed
|
|
62
|
+
- `field?: string` - The configuration field that failed validation
|
|
63
|
+
- Example: Invalid DEFAULT_CONFIG, missing createDriver function
|
|
64
|
+
|
|
65
|
+
- **`DriverNotFoundError`**: Driver package not found or cannot be loaded
|
|
66
|
+
- `packageName: string` - The package that couldn't be found
|
|
67
|
+
- Example: Package not installed, wrong package name
|
|
68
|
+
|
|
69
|
+
- **`PackageJsonError`**: package.json not found or invalid
|
|
70
|
+
- Example: Missing package.json, invalid JSON, missing ya-modbus-driver keyword
|
|
71
|
+
|
|
72
|
+
### Custom Logging
|
|
73
|
+
|
|
74
|
+
You can provide a custom logger to control warning and debug output:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { loadDriver, type Logger } from '@ya-modbus/driver-loader'
|
|
78
|
+
|
|
79
|
+
const logger: Logger = {
|
|
80
|
+
warn: (msg) => myLogger.warning('[DRIVER]', msg),
|
|
81
|
+
debug: (msg) => myLogger.debug('[DRIVER]', msg), // Optional
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const driver = await loadDriver({
|
|
85
|
+
driverPackage: 'my-driver',
|
|
86
|
+
logger,
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## API
|
|
91
|
+
|
|
92
|
+
### `loadDriver(options?: LoadDriverOptions): Promise<LoadedDriver>`
|
|
93
|
+
|
|
94
|
+
Loads a ya-modbus driver package and validates its exports.
|
|
95
|
+
|
|
96
|
+
**Options:**
|
|
97
|
+
|
|
98
|
+
- `driverPackage` (optional): Name of the driver package to load. If omitted, auto-detects from current directory's package.json.
|
|
99
|
+
|
|
100
|
+
**Returns:**
|
|
101
|
+
|
|
102
|
+
- `LoadedDriver` object containing:
|
|
103
|
+
- `createDriver`: Factory function to create driver instances (required)
|
|
104
|
+
- `devices`: Device registry for multi-device drivers (optional)
|
|
105
|
+
- `defaultConfig`: Default configuration for serial or TCP (optional)
|
|
106
|
+
- `supportedConfig`: Configuration constraints (optional)
|
|
107
|
+
|
|
108
|
+
**Throws:**
|
|
109
|
+
|
|
110
|
+
- Error if driver package is not found
|
|
111
|
+
- Error if driver exports are invalid
|
|
112
|
+
- Error if configuration validation fails
|
|
113
|
+
|
|
114
|
+
### `clearDriverCache(): void`
|
|
115
|
+
|
|
116
|
+
Clears the driver cache. Useful for testing or when you need to reload drivers.
|
|
117
|
+
|
|
118
|
+
**When to use:**
|
|
119
|
+
|
|
120
|
+
- **In tests:** Clear cache between test cases to ensure isolation
|
|
121
|
+
- **After package updates:** Force reload of updated driver packages
|
|
122
|
+
- **During development:** Reload drivers after making changes
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { clearDriverCache } from '@ya-modbus/driver-loader'
|
|
126
|
+
|
|
127
|
+
// In test setup
|
|
128
|
+
beforeEach(() => {
|
|
129
|
+
clearDriverCache() // Ensure each test starts with clean cache
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
// After updating a driver package
|
|
133
|
+
await updateDriver('my-driver')
|
|
134
|
+
clearDriverCache() // Force reload on next loadDriver call
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `getDriverCacheStats(): DriverCacheStats`
|
|
138
|
+
|
|
139
|
+
Returns cache statistics including hits, misses, and current cache size.
|
|
140
|
+
|
|
141
|
+
**Returns:**
|
|
142
|
+
|
|
143
|
+
- `DriverCacheStats` object containing:
|
|
144
|
+
- `hits`: Number of cache hits
|
|
145
|
+
- `misses`: Number of cache misses
|
|
146
|
+
- `size`: Number of cached drivers
|
|
147
|
+
|
|
148
|
+
**Cache Behavior:**
|
|
149
|
+
|
|
150
|
+
- **Automatic caching:** Drivers are cached by package name after first load
|
|
151
|
+
- **Cache key:** Package name (e.g., '@ya-modbus/driver-xymd1')
|
|
152
|
+
- **Cache lifetime:** Persists for the lifetime of the Node.js process
|
|
153
|
+
- **Auto-detect mode:** Even auto-detected drivers are cached by their package name
|
|
154
|
+
- **No cache on errors:** Failed loads are not cached, allowing retry
|
|
155
|
+
|
|
156
|
+
**Example:**
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { loadDriver, getDriverCacheStats } from '@ya-modbus/driver-loader'
|
|
160
|
+
|
|
161
|
+
// First load - cache miss
|
|
162
|
+
await loadDriver({ driverPackage: 'my-driver' })
|
|
163
|
+
console.log(getDriverCacheStats()) // { hits: 0, misses: 1, size: 1 }
|
|
164
|
+
|
|
165
|
+
// Second load - cache hit
|
|
166
|
+
await loadDriver({ driverPackage: 'my-driver' })
|
|
167
|
+
console.log(getDriverCacheStats()) // { hits: 1, misses: 1, size: 1 }
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Testing Utilities
|
|
171
|
+
|
|
172
|
+
The package provides testing utilities for applications using driver-loader.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { createMockDriver, mockSystemDeps } from '@ya-modbus/driver-loader/testing'
|
|
176
|
+
|
|
177
|
+
// Create a mock driver
|
|
178
|
+
const mockDriver = createMockDriver({
|
|
179
|
+
defaultConfig: { baudRate: 9600 },
|
|
180
|
+
devices: { test: { manufacturer: 'Test', model: 'Model' } },
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
// Create mock system dependencies
|
|
184
|
+
const deps = mockSystemDeps({
|
|
185
|
+
importModule: jest.fn().mockResolvedValue(mockDriver),
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
// Use with loadDriver in tests
|
|
189
|
+
const driver = await loadDriver({ driverPackage: 'test-driver' }, deps)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### `createMockDriver(options?: MockDriverOptions): LoadedDriver`
|
|
193
|
+
|
|
194
|
+
Creates a mock driver for testing.
|
|
195
|
+
|
|
196
|
+
**Options:**
|
|
197
|
+
|
|
198
|
+
- `createDriver`: Custom createDriver implementation (default: jest.fn())
|
|
199
|
+
- `defaultConfig`: Mock default configuration
|
|
200
|
+
- `supportedConfig`: Mock supported configuration
|
|
201
|
+
- `devices`: Mock device registry
|
|
202
|
+
|
|
203
|
+
### `mockSystemDeps(options?: MockSystemDepsOptions): SystemDependencies`
|
|
204
|
+
|
|
205
|
+
Creates mock system dependencies for testing.
|
|
206
|
+
|
|
207
|
+
**Options:**
|
|
208
|
+
|
|
209
|
+
- `readFile`: Custom readFile implementation
|
|
210
|
+
- `importModule`: Custom importModule implementation
|
|
211
|
+
- `getCwd`: Custom getCwd implementation (default: '/mock/cwd')
|
|
212
|
+
|
|
213
|
+
## Troubleshooting
|
|
214
|
+
|
|
215
|
+
### Package Not Found
|
|
216
|
+
|
|
217
|
+
If you encounter `Driver package not found` errors:
|
|
218
|
+
|
|
219
|
+
1. **Verify the package is installed:**
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
npm list ya-modbus-driver-<name>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
2. **Install the driver package:**
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
npm install ya-modbus-driver-<name>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
3. **Check the package name:**
|
|
232
|
+
- Ensure the package name in your code matches the actual npm package name
|
|
233
|
+
- Driver packages typically follow the naming convention: `ya-modbus-driver-<device>`
|
|
234
|
+
|
|
235
|
+
### Module Resolution Issues
|
|
236
|
+
|
|
237
|
+
If TypeScript or Node.js can't find `@ya-modbus/driver-loader`:
|
|
238
|
+
|
|
239
|
+
1. **Check your package.json:**
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
npm list @ya-modbus/driver-loader
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
2. **Reinstall dependencies:**
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
npm install
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
3. **TypeScript module resolution:**
|
|
252
|
+
- Ensure `"moduleResolution": "node"` or `"moduleResolution": "bundler"` in tsconfig.json
|
|
253
|
+
- Check that `"types"` field isn't excluding driver-loader
|
|
254
|
+
|
|
255
|
+
4. **For local driver development:**
|
|
256
|
+
- The loader tries multiple import paths: `src/index.js`, `src/index.ts`, `dist/index.js`
|
|
257
|
+
- Build your driver before testing: `npm run build`
|
|
258
|
+
|
|
259
|
+
### Validation Failures
|
|
260
|
+
|
|
261
|
+
If driver validation fails with configuration errors:
|
|
262
|
+
|
|
263
|
+
1. **ValidationError - Invalid DEFAULT_CONFIG:**
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// ❌ Wrong
|
|
267
|
+
export const DEFAULT_CONFIG = { speed: 9600 } // Should be "baudRate"
|
|
268
|
+
|
|
269
|
+
// ✅ Correct
|
|
270
|
+
export const DEFAULT_CONFIG = { baudRate: 9600 }
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
2. **ValidationError - Invalid SUPPORTED_CONFIG:**
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
// ❌ Wrong
|
|
277
|
+
export const SUPPORTED_CONFIG = { baudRates: [9600] } // Should be "validBaudRates"
|
|
278
|
+
|
|
279
|
+
// ✅ Correct
|
|
280
|
+
export const SUPPORTED_CONFIG = { validBaudRates: [9600, 19200] }
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
3. **ValidationError - Missing createDriver:**
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
// ❌ Wrong
|
|
287
|
+
export function makeDriver() {
|
|
288
|
+
...
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ✅ Correct
|
|
292
|
+
export function createDriver() {
|
|
293
|
+
...
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
4. **PackageJsonError - Not a driver package:**
|
|
298
|
+
|
|
299
|
+
Add the `ya-modbus-driver` keyword to your package.json:
|
|
300
|
+
|
|
301
|
+
```json
|
|
302
|
+
{
|
|
303
|
+
"name": "ya-modbus-driver-mydevice",
|
|
304
|
+
"keywords": ["ya-modbus-driver"]
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
5. **Configuration inconsistency warnings:**
|
|
309
|
+
|
|
310
|
+
Ensure DEFAULT_CONFIG values are within SUPPORTED_CONFIG constraints:
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// ❌ Inconsistent
|
|
314
|
+
export const DEFAULT_CONFIG = { baudRate: 115200 }
|
|
315
|
+
export const SUPPORTED_CONFIG = { validBaudRates: [9600, 19200] }
|
|
316
|
+
|
|
317
|
+
// ✅ Consistent
|
|
318
|
+
export const DEFAULT_CONFIG = { baudRate: 9600 }
|
|
319
|
+
export const SUPPORTED_CONFIG = { validBaudRates: [9600, 19200] }
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Getting More Help
|
|
323
|
+
|
|
324
|
+
For additional debugging:
|
|
325
|
+
|
|
326
|
+
1. **Enable verbose logging:**
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
const logger = {
|
|
330
|
+
warn: (msg: string) => console.warn('[DRIVER]', msg),
|
|
331
|
+
debug: (msg: string) => console.debug('[DRIVER]', msg),
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const driver = await loadDriver({ logger })
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
2. **Check cache statistics:**
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
import { getDriverCacheStats } from '@ya-modbus/driver-loader'
|
|
341
|
+
|
|
342
|
+
console.log(getDriverCacheStats())
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
3. **Clear the cache:**
|
|
346
|
+
```typescript
|
|
347
|
+
import { clearDriverCache } from '@ya-modbus/driver-loader'
|
|
348
|
+
clearDriverCache()
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## License
|
|
352
|
+
|
|
353
|
+
GPL-3.0-or-later
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime validation for driver configuration exports
|
|
3
|
+
*
|
|
4
|
+
* Validates DEFAULT_CONFIG, SUPPORTED_CONFIG, and DEVICES from third-party drivers
|
|
5
|
+
* to ensure type safety at runtime.
|
|
6
|
+
*/
|
|
7
|
+
import type { DefaultConfig, DeviceRegistry, SupportedConfig } from '@ya-modbus/driver-types';
|
|
8
|
+
import type { Logger } from './loader.js';
|
|
9
|
+
/**
|
|
10
|
+
* Output configuration warnings to logger
|
|
11
|
+
*
|
|
12
|
+
* @param context - Context description (e.g., "Driver DEFAULT_CONFIG")
|
|
13
|
+
* @param warnings - Array of warning messages
|
|
14
|
+
* @param logger - Logger to output warnings to
|
|
15
|
+
*/
|
|
16
|
+
export declare function outputConfigWarnings(context: string, warnings: string[], logger?: Logger): void;
|
|
17
|
+
/**
|
|
18
|
+
* Validate DEFAULT_CONFIG export from a driver module
|
|
19
|
+
*
|
|
20
|
+
* @param config - The DEFAULT_CONFIG value to validate
|
|
21
|
+
* @returns Validated config
|
|
22
|
+
* @throws Error with helpful message if validation fails
|
|
23
|
+
*/
|
|
24
|
+
export declare function validateDefaultConfig(config: unknown): DefaultConfig;
|
|
25
|
+
/**
|
|
26
|
+
* Validate SUPPORTED_CONFIG export from a driver module
|
|
27
|
+
*
|
|
28
|
+
* @param config - The SUPPORTED_CONFIG value to validate
|
|
29
|
+
* @returns Validated config
|
|
30
|
+
* @throws Error with helpful message if validation fails
|
|
31
|
+
*/
|
|
32
|
+
export declare function validateSupportedConfig(config: unknown): SupportedConfig;
|
|
33
|
+
/**
|
|
34
|
+
* Validate DEVICES export from a driver module
|
|
35
|
+
*
|
|
36
|
+
* @param devices - The DEVICES value to validate
|
|
37
|
+
* @param logger - Optional logger for warnings (defaults to console)
|
|
38
|
+
* @returns Validated devices registry
|
|
39
|
+
* @throws Error with helpful message if validation fails
|
|
40
|
+
*/
|
|
41
|
+
export declare function validateDevices(devices: unknown, logger?: Logger): DeviceRegistry;
|
|
42
|
+
/**
|
|
43
|
+
* Cross-validate DEFAULT_CONFIG against SUPPORTED_CONFIG constraints
|
|
44
|
+
*
|
|
45
|
+
* Checks that all DEFAULT_CONFIG values are within SUPPORTED_CONFIG constraints.
|
|
46
|
+
* This helps catch driver authoring errors where defaults don't match declared support.
|
|
47
|
+
*
|
|
48
|
+
* @param defaultConfig - The validated DEFAULT_CONFIG
|
|
49
|
+
* @param supportedConfig - The validated SUPPORTED_CONFIG
|
|
50
|
+
* @returns Array of warning messages for any inconsistencies found (empty if all valid)
|
|
51
|
+
*/
|
|
52
|
+
export declare function crossValidateConfigs(defaultConfig: DefaultConfig, supportedConfig: SupportedConfig): string[];
|
|
53
|
+
//# sourceMappingURL=config-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-validator.d.ts","sourceRoot":"","sources":["../src/config-validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAG7F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAAE,EAClB,MAAM,GAAE,MAAgB,GACvB,IAAI,CAON;AA6BD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,aAAa,CAyBpE;AAoED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,eAAe,CAuExE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,GAAE,MAAgB,GAAG,cAAc,CAsG1F;AAiBD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,GAC/B,MAAM,EAAE,CA2GV"}
|