qtools-library-dot-d 1.0.4 → 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 +214 -29
- package/package.json +3 -2
- package/qtools-library-dot-d.js +15 -5
package/README.md
CHANGED
|
@@ -1,56 +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
|
+
```
|
|
39
61
|
|
|
62
|
+
### 4. **Clean Separation of Concerns**
|
|
40
63
|
|
|
64
|
+
Each module is self-contained and focused on a single responsibility, making code easier to maintain and test.
|
|
41
65
|
|
|
42
|
-
|
|
66
|
+
### 5. **Runtime Flexibility**
|
|
43
67
|
|
|
44
|
-
|
|
45
|
-
libraryName: 'promptObjects',
|
|
46
|
-
});
|
|
47
|
-
promptObjects.setLibraryPath(path.join(__dirname, 'prompts.d'));
|
|
68
|
+
Modules can be loaded synchronously or asynchronously, and the library can be sealed to prevent modifications after loading.
|
|
48
69
|
|
|
49
|
-
|
|
50
|
-
promptObjects.loadModules({ passThroughParameters });
|
|
51
|
-
promptObjects.seal(); //make the library immutable
|
|
70
|
+
## Real-World Use Cases
|
|
52
71
|
|
|
72
|
+
### API Endpoint Management
|
|
53
73
|
|
|
54
|
-
|
|
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
|
+
```
|
|
55
80
|
|
|
81
|
+
### Data Access Layer
|
|
82
|
+
|
|
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
|
+
```
|
|
89
|
+
|
|
90
|
+
### Business Logic Modules
|
|
91
|
+
|
|
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
|
+
```
|
|
98
|
+
|
|
99
|
+
### CLI Command Tools
|
|
100
|
+
|
|
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
|
+
```
|
|
107
|
+
|
|
108
|
+
## How It Works
|
|
109
|
+
|
|
110
|
+
### 1. **Library Creation**
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
const qtLibDotD = require('qtools-library-dot-d');
|
|
114
|
+
const library = qtLibDotD({ libraryName: 'myLibrary' });
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 2. **Module Directory Setup**
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
library.setLibraryPath('./modules.d');
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 3. **Shared Resource Definition**
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
const passThroughParameters = {
|
|
127
|
+
config: appConfig,
|
|
128
|
+
database: dbConnection,
|
|
129
|
+
logger: logger
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 4. **Module Loading**
|
|
134
|
+
|
|
135
|
+
```javascript
|
|
136
|
+
// Synchronous
|
|
137
|
+
library.loadModules({ passThroughParameters });
|
|
138
|
+
|
|
139
|
+
// Asynchronous
|
|
140
|
+
library.loadModules({ passThroughParameters }, callback);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 5. **Library Sealing**
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
library.seal(); // Prevents further modifications
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 6. **Module Usage**
|
|
150
|
+
|
|
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$/, '');
|
|
165
|
+
|
|
166
|
+
const moduleFunction = ({ moduleName } = {}) => ({ dotD, passThroughParameters } = {}) => {
|
|
167
|
+
|
|
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
|
+
};
|
|
177
|
+
|
|
178
|
+
// Register the function
|
|
179
|
+
dotD.library.add(moduleName, workingFunction);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
module.exports = moduleFunction({ moduleName });
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Benefits Over Traditional Approaches
|
|
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 |
|
|
195
|
+
|
|
196
|
+
## Getting Started
|
|
197
|
+
|
|
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
|
|
223
|
+
|
|
224
|
+
## Integration with Larger Systems
|
|
225
|
+
|
|
226
|
+
The dotD pattern works particularly well in:
|
|
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
|
|
56
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": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"author": "TQ White II",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"qtools-asynchronous-pipe-plus": "^1.0.2"
|
|
12
|
+
"qtools-asynchronous-pipe-plus": "^1.0.2",
|
|
13
|
+
"qtools-functional-library": "^2.0.4"
|
|
13
14
|
}
|
|
14
15
|
}
|
package/qtools-library-dot-d.js
CHANGED
|
@@ -9,6 +9,8 @@ const os = require('os');
|
|
|
9
9
|
const path = require('path');
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
|
|
12
|
+
const qt = require('qtools-functional-library');
|
|
13
|
+
|
|
12
14
|
//START OF moduleFunction() ============================================================
|
|
13
15
|
const moduleFunction =
|
|
14
16
|
({ moduleName } = {}) =>
|
|
@@ -98,7 +100,8 @@ const moduleFunction =
|
|
|
98
100
|
let outString = typeof item;
|
|
99
101
|
if (typeof item == 'function') {
|
|
100
102
|
const result = item.toString().match(/\((?<args>.*?\))/);
|
|
101
|
-
|
|
103
|
+
const args = result.qtGetSurePath('groups.args', 'function');
|
|
104
|
+
outString = `(${args == ')' ? args + ' # function takes no arguments' : args}`;
|
|
102
105
|
}
|
|
103
106
|
return outString;
|
|
104
107
|
};
|
|
@@ -111,7 +114,7 @@ const moduleFunction =
|
|
|
111
114
|
? libraryObject[name]
|
|
112
115
|
: formatProperty(libraryObject[name])
|
|
113
116
|
}\n\t`,
|
|
114
|
-
`\n${libraryName} Library\n\t`,
|
|
117
|
+
`\n${libraryName} Library Elements\n\t`,
|
|
115
118
|
)
|
|
116
119
|
.replace(/\n\t$/, '');
|
|
117
120
|
|
|
@@ -204,10 +207,17 @@ const moduleFunction =
|
|
|
204
207
|
// INIT AND EXECUTE THE PIPELINE
|
|
205
208
|
|
|
206
209
|
if (typeof callback == 'function') {
|
|
207
|
-
|
|
210
|
+
if (exceptionList.length) {
|
|
211
|
+
callback(exceptionList);
|
|
212
|
+
} else {
|
|
213
|
+
callback();
|
|
214
|
+
}
|
|
208
215
|
} else {
|
|
209
|
-
|
|
210
|
-
|
|
216
|
+
if (exceptionList.length) {
|
|
217
|
+
return exceptionList;
|
|
218
|
+
} else {
|
|
219
|
+
return;
|
|
220
|
+
}}
|
|
211
221
|
};
|
|
212
222
|
|
|
213
223
|
const externalElements = {
|