qtools-library-dot-d 1.0.5 → 1.0.6
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/README.md +184 -151
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,208 +1,241 @@
|
|
|
1
|
-
|
|
1
|
+
## NAME
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
qtools-library-dot-d is system for creating dynamic, modular libraries in Node.js. The dotD (dot-D) pattern provides a powerful way to build extensible applications through automatic module discovery and loading.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## What is qtools-library-dot-d?
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**qtools-library-dot-d** is a Node.js library that enables dynamic module loading from directories. It automatically discovers JavaScript files in specified directories and makes them available as methods on a library object, creating a plugin-like architecture without the complexity of traditional plugin systems.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## The dotD Pattern
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The "dotD" naming convention (short for "dot-D") refers to directories that contain dynamically loadable modules:
|
|
12
12
|
|
|
13
|
+
- `modules.d/` - Directory containing module files
|
|
14
|
+
- `endpoints.d/` - Directory containing API endpoint modules
|
|
15
|
+
- `accessPoints.d/` - Directory containing data access modules
|
|
16
|
+
- `mappers.d/` - Directory containing data mapping modules
|
|
13
17
|
|
|
18
|
+
Each `.js` file in a dotD directory becomes a method on the library object, with the filename determining the method name.
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
## Why Use Dynamic dotD Libraries?
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
### 1. **Automatic Module Discovery**
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
No need to manually import or register modules. Simply add a `.js` file to the dotD directory and it's automatically available.
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
```javascript
|
|
27
|
+
// Traditional approach - manual imports
|
|
28
|
+
const module1 = require('./modules/module1');
|
|
29
|
+
const module2 = require('./modules/module2');
|
|
30
|
+
const module3 = require('./modules/module3');
|
|
22
31
|
|
|
23
|
-
|
|
32
|
+
// dotD approach - automatic discovery
|
|
33
|
+
const library = qtLibDotD({ libraryName: 'myLibrary' });
|
|
34
|
+
library.setLibraryPath('./modules.d');
|
|
35
|
+
library.loadModules();
|
|
36
|
+
// All modules in modules.d/ are now available as library.moduleName()
|
|
37
|
+
```
|
|
24
38
|
|
|
39
|
+
### 2. **Plugin Architecture**
|
|
25
40
|
|
|
41
|
+
Create extensible applications where new functionality can be added by simply dropping files into directories.
|
|
26
42
|
|
|
27
|
-
|
|
43
|
+
```javascript
|
|
44
|
+
// Add new functionality by creating a new file
|
|
45
|
+
// modules.d/newFeature.js -> library.newFeature()
|
|
46
|
+
```
|
|
28
47
|
|
|
29
|
-
|
|
48
|
+
### 3. **Shared Resources**
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
libraryName: 'promptObjects',
|
|
33
|
-
}, callback);
|
|
34
|
-
promptObjects.setLibraryPath(path.join(__dirname, 'prompts.d'), callback);
|
|
50
|
+
Pass common resources (configuration, database connections, utilities) to all modules through `passThroughParameters`.
|
|
35
51
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
52
|
+
```javascript
|
|
53
|
+
const passThroughParameters = {
|
|
54
|
+
config: getConfig(),
|
|
55
|
+
database: dbConnection,
|
|
56
|
+
logger: xLog,
|
|
57
|
+
utilities: commonUtils
|
|
58
|
+
};
|
|
59
|
+
library.loadModules({ passThroughParameters });
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 4. **Clean Separation of Concerns**
|
|
63
|
+
|
|
64
|
+
Each module is self-contained and focused on a single responsibility, making code easier to maintain and test.
|
|
39
65
|
|
|
66
|
+
### 5. **Runtime Flexibility**
|
|
40
67
|
|
|
68
|
+
Modules can be loaded synchronously or asynchronously, and the library can be sealed to prevent modifications after loading.
|
|
41
69
|
|
|
42
|
-
|
|
70
|
+
## Real-World Use Cases
|
|
43
71
|
|
|
44
|
-
|
|
45
|
-
libraryName: 'promptObjects',
|
|
46
|
-
});
|
|
47
|
-
promptObjects.setLibraryPath(path.join(__dirname, 'prompts.d'));
|
|
72
|
+
### API Endpoint Management
|
|
48
73
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
74
|
+
```javascript
|
|
75
|
+
// endpoints.d/userEndpoints.js
|
|
76
|
+
// endpoints.d/productEndpoints.js
|
|
77
|
+
// endpoints.d/orderEndpoints.js
|
|
78
|
+
// Each file defines related API endpoints
|
|
79
|
+
```
|
|
52
80
|
|
|
81
|
+
### Data Access Layer
|
|
53
82
|
|
|
54
|
-
|
|
83
|
+
```javascript
|
|
84
|
+
// accessPoints.d/getUserData.js
|
|
85
|
+
// accessPoints.d/saveUserData.js
|
|
86
|
+
// accessPoints.d/deleteUserData.js
|
|
87
|
+
// Each file handles specific data operations
|
|
88
|
+
```
|
|
55
89
|
|
|
56
|
-
|
|
57
|
-
// index.js for demonstration
|
|
90
|
+
### Business Logic Modules
|
|
58
91
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
//
|
|
62
|
-
|
|
92
|
+
```javascript
|
|
93
|
+
// processors.d/validateOrder.js
|
|
94
|
+
// processors.d/calculateTax.js
|
|
95
|
+
// processors.d/sendNotification.js
|
|
96
|
+
// Each file contains specific business logic
|
|
97
|
+
```
|
|
63
98
|
|
|
64
|
-
|
|
99
|
+
### CLI Command Tools
|
|
65
100
|
|
|
66
|
-
|
|
101
|
+
```javascript
|
|
102
|
+
// commands.d/deploy.js
|
|
103
|
+
// commands.d/backup.js
|
|
104
|
+
// commands.d/migrate.js
|
|
105
|
+
// Each file implements a CLI command
|
|
106
|
+
```
|
|
67
107
|
|
|
68
|
-
|
|
69
|
-
const path = require('path');
|
|
70
|
-
const fs = require('fs');
|
|
108
|
+
## How It Works
|
|
71
109
|
|
|
110
|
+
### 1. **Library Creation**
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
72
113
|
const qtLibDotD = require('qtools-library-dot-d');
|
|
114
|
+
const library = qtLibDotD({ libraryName: 'myLibrary' });
|
|
115
|
+
```
|
|
73
116
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// ========================================================================
|
|
80
|
-
// SYNCHRONOUS DEMO
|
|
81
|
-
|
|
82
|
-
const synchronousDemo = () => {
|
|
83
|
-
const demoDotD = qtLibDotD({
|
|
84
|
-
libraryName: 'demoDotD',
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
const libraryModulesPath = path.join(__dirname, 'demoModules_DotD');
|
|
88
|
-
|
|
89
|
-
const passThroughParameters = {
|
|
90
|
-
message: 'Hello from a dotDlib module',
|
|
91
|
-
add: (a, b) => a + b,
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
demoDotD.setLibraryPath(libraryModulesPath);
|
|
95
|
-
demoDotD.loadModules({ passThroughParameters });
|
|
96
|
-
demoDotD.seal();
|
|
97
|
-
|
|
98
|
-
// console.log(demoDotD.qtdProcessLog());
|
|
99
|
-
console.log(demoDotD.toString());
|
|
100
|
-
|
|
101
|
-
demoDotD.demo1();
|
|
102
|
-
demoDotD.demo2(10, 7);
|
|
103
|
-
};
|
|
104
|
-
console.log(`SYNCHRONOUS DEMO =====================================`);
|
|
105
|
-
synchronousDemo();
|
|
106
|
-
|
|
107
|
-
// ========================================================================
|
|
108
|
-
// ASYNCHRONOUS DEMO
|
|
109
|
-
|
|
110
|
-
const asynchronousDemo = (callback) => {
|
|
111
|
-
const localCallback = (err) => {
|
|
112
|
-
demoDotD.seal();
|
|
113
|
-
callback(err, demoDotD);
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const demoDotD = qtLibDotD({
|
|
117
|
-
libraryName: 'demoDotD',
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
const libraryModulesPath = path.join(__dirname, 'demoModules_DotD');
|
|
121
|
-
|
|
122
|
-
const passThroughParameters = {
|
|
123
|
-
message: 'Hello from a dotDlib module',
|
|
124
|
-
add: (a, b) => a + b,
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
demoDotD.setLibraryPath(libraryModulesPath);
|
|
128
|
-
demoDotD.loadModules({ passThroughParameters }, localCallback);
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
console.log(`\n\nASYNCHRONOUS DEMO =====================================`);
|
|
132
|
-
|
|
133
|
-
const callback = (err, demoDotD) => {
|
|
134
|
-
console.log(demoDotD.toString());
|
|
135
|
-
demoDotD.demo1();
|
|
136
|
-
demoDotD.demo2(10, 7);
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
asynchronousDemo(callback);
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
// ================================================================================
|
|
144
|
-
// demo1.js
|
|
145
|
-
|
|
146
|
-
#!/usr/bin/env node
|
|
147
|
-
'use strict';
|
|
148
|
-
// Suppress punycode deprecation warning
|
|
149
|
-
process.noDeprecation = true;
|
|
150
|
-
|
|
151
|
-
const moduleName = __filename.replace(__dirname + '/', '').replace(/.js$/, ''); //this just seems to come in handy a lot
|
|
152
|
-
|
|
153
|
-
//START OF moduleFunction() ============================================================
|
|
154
|
-
const moduleFunction = ({ moduleName } = {}) => ({ dotD, passThroughParameters } = {}) => {
|
|
117
|
+
### 2. **Module Directory Setup**
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
library.setLibraryPath('./modules.d');
|
|
121
|
+
```
|
|
155
122
|
|
|
156
|
-
|
|
157
|
-
console.log(`${passThroughParameters.message} [${moduleName}]`);
|
|
158
|
-
return 'hello';
|
|
159
|
-
};
|
|
160
|
-
|
|
123
|
+
### 3. **Shared Resource Definition**
|
|
161
124
|
|
|
162
|
-
|
|
125
|
+
```javascript
|
|
126
|
+
const passThroughParameters = {
|
|
127
|
+
config: appConfig,
|
|
128
|
+
database: dbConnection,
|
|
129
|
+
logger: logger
|
|
163
130
|
};
|
|
131
|
+
```
|
|
164
132
|
|
|
165
|
-
|
|
133
|
+
### 4. **Module Loading**
|
|
166
134
|
|
|
167
|
-
|
|
168
|
-
//
|
|
135
|
+
```javascript
|
|
136
|
+
// Synchronous
|
|
137
|
+
library.loadModules({ passThroughParameters });
|
|
169
138
|
|
|
170
|
-
|
|
139
|
+
// Asynchronous
|
|
140
|
+
library.loadModules({ passThroughParameters }, callback);
|
|
141
|
+
```
|
|
171
142
|
|
|
143
|
+
### 5. **Library Sealing**
|
|
172
144
|
|
|
173
|
-
|
|
174
|
-
//
|
|
145
|
+
```javascript
|
|
146
|
+
library.seal(); // Prevents further modifications
|
|
147
|
+
```
|
|
175
148
|
|
|
176
|
-
|
|
177
|
-
'use strict';
|
|
178
|
-
// Suppress punycode deprecation warning
|
|
179
|
-
process.noDeprecation = true;
|
|
149
|
+
### 6. **Module Usage**
|
|
180
150
|
|
|
181
|
-
|
|
151
|
+
```javascript
|
|
152
|
+
// If you have modules.d/processOrder.js
|
|
153
|
+
library.processOrder(orderData);
|
|
154
|
+
|
|
155
|
+
// If you have modules.d/sendEmail.js
|
|
156
|
+
library.sendEmail(recipient, message);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Module Structure
|
|
160
|
+
|
|
161
|
+
Every dotD module follows this pattern:
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
const moduleName = __filename.replace(__dirname + '/', '').replace(/.js$/, '');
|
|
182
165
|
|
|
183
|
-
//START OF moduleFunction() ============================================================
|
|
184
166
|
const moduleFunction = ({ moduleName } = {}) => ({ dotD, passThroughParameters } = {}) => {
|
|
185
167
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
168
|
+
const workingFunction = (/* your parameters */) => {
|
|
169
|
+
// Access shared resources
|
|
170
|
+
const config = passThroughParameters.config;
|
|
171
|
+
const logger = passThroughParameters.logger;
|
|
172
|
+
|
|
173
|
+
// Your module logic here
|
|
174
|
+
|
|
175
|
+
return result;
|
|
176
|
+
};
|
|
191
177
|
|
|
192
|
-
|
|
178
|
+
// Register the function
|
|
179
|
+
dotD.library.add(moduleName, workingFunction);
|
|
193
180
|
};
|
|
194
181
|
|
|
195
|
-
|
|
182
|
+
module.exports = moduleFunction({ moduleName });
|
|
183
|
+
```
|
|
196
184
|
|
|
197
|
-
|
|
185
|
+
## Benefits Over Traditional Approaches
|
|
198
186
|
|
|
187
|
+
| Traditional | dotD Libraries |
|
|
188
|
+
| --------------------- | --------------------------- |
|
|
189
|
+
| Manual imports | Automatic discovery |
|
|
190
|
+
| Tight coupling | Loose coupling |
|
|
191
|
+
| Hard to extend | Easy to extend |
|
|
192
|
+
| Configuration in code | Configuration through files |
|
|
193
|
+
| Monolithic | Modular |
|
|
194
|
+
| Static structure | Dynamic structure |
|
|
199
195
|
|
|
200
|
-
|
|
196
|
+
## Getting Started
|
|
201
197
|
|
|
202
|
-
|
|
203
|
-
|
|
198
|
+
1. **Install the dependency:**
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
npm install qtools-library-dot-d
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
2. **Run the example:**
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
npm start
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
3. **Create your own modules:**
|
|
211
|
+
|
|
212
|
+
- Add `.js` files to `demoModules_DotD/`
|
|
213
|
+
- Follow the module pattern shown in the examples
|
|
214
|
+
- Access shared resources via `passThroughParameters`
|
|
215
|
+
|
|
216
|
+
## Advanced Features
|
|
217
|
+
|
|
218
|
+
- **Async module loading** for modules that need initialization
|
|
219
|
+
- **Error handling** during module loading
|
|
220
|
+
- **Library introspection** with `toString()` and `qtdProcessLog()`
|
|
221
|
+
- **Multiple libraries** in the same application
|
|
222
|
+
- **Nested module structures** for complex applications
|
|
204
223
|
|
|
224
|
+
## Integration with Larger Systems
|
|
205
225
|
|
|
206
|
-
|
|
226
|
+
The dotD pattern works particularly well in:
|
|
207
227
|
|
|
228
|
+
- **Web frameworks** (Express, Koa) for route organization
|
|
229
|
+
- **API systems** for endpoint management
|
|
230
|
+
- **CLI tools** for command organization
|
|
231
|
+
- **Microservices** for feature modularity
|
|
232
|
+
- **Plugin systems** for extensible applications
|
|
233
|
+
|
|
234
|
+
This pattern is used extensively in the qtools ecosystem for building scalable, maintainable Node.js applications.
|
|
235
|
+
|
|
236
|
+
## HISTORY
|
|
237
|
+
|
|
238
|
+
v1.06 - updated README
|
|
239
|
+
v1.05 - cleaned up toString() report, returns exception list (or err if callback) if needed, added qtools-functional-library
|
|
208
240
|
v1.04 - Now tolerates (and reports) directories and files that are not modules.
|
|
241
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qtools-library-dot-d",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Scan a directory for JS modules that can execute and addMe() that attaches it to some form of name/value list, eg, a Map() with functions as values or an xPressJS route/endpoint list.",
|
|
5
5
|
"main": "qtools-library-dot-d.js",
|
|
6
6
|
"scripts": {
|