qtools-library-dot-d 1.0.12 → 1.1.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/LICENSE +21 -0
- package/README.md +89 -0
- package/package.json +9 -3
- package/qtools-library-dot-d.js +553 -2
- package/libDotD_Working_Example/README.md +0 -234
- package/libDotD_Working_Example/demoModules_DotD/demo1.js +0 -46
- package/libDotD_Working_Example/demoModules_DotD/demo2.js +0 -48
- package/libDotD_Working_Example/index.js +0 -133
- package/libDotD_Working_Example/node_modules/.package-lock.json +0 -29
- package/libDotD_Working_Example/node_modules/qtools-asynchronous-pipe-plus/README.md +0 -213
- package/libDotD_Working_Example/node_modules/qtools-asynchronous-pipe-plus/package.json +0 -20
- package/libDotD_Working_Example/node_modules/qtools-asynchronous-pipe-plus/qtools-asynchronous-pipe-plus.js +0 -278
- package/libDotD_Working_Example/node_modules/qtools-asynchronous-pipe-plus/test.js +0 -79
- package/libDotD_Working_Example/node_modules/qtools-functional-library/README.md +0 -110
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-clone/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-clone/qtools-clone.js +0 -103
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-clone/test.js +0 -78
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-get-by-property/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-get-by-property/qtools-get-by-property.js +0 -73
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-get-by-property/test.js +0 -129
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-includes-regex/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-includes-regex/qtools-includes-regex.js +0 -54
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-includes-regex/test.js +0 -76
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-log-output/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-log-output/qtools-log-output.js +0 -114
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-log-output/test.js +0 -130
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-map-properties/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-map-properties/qtools-map-properties.js +0 -99
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-map-properties/test.js +0 -118
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-merge/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-merge/qtools-merge.js +0 -147
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-merge/test.js +0 -214
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-new-method-template/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-new-method-template/qtools-new-method-template.js +0 -70
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-new-method-template/test.js +0 -66
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-number-iterator/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-number-iterator/qtools-number-iterator.js +0 -137
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-number-iterator/test.js +0 -68
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-number-keys-to-array/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-number-keys-to-array/qtools-number-keys-to-array.js +0 -131
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-number-keys-to-array/test.js +0 -181
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-object-sure-path/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-object-sure-path/qtools-object-sure-path.js +0 -204
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-object-sure-path/test.js +0 -345
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-pass-through/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-pass-through/qtools-pass-through.js +0 -58
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-pass-through/test.js +0 -66
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-pop/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-pop/qtools-pop.js +0 -175
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-pop/test.js +0 -118
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-print-debug/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-print-debug/qtools-print-debug.js +0 -352
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-print-debug/test.js +0 -77
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-select-properties/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-select-properties/qtools-select-properties.js +0 -132
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-select-properties/test.js +0 -156
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-template-replace/README.md +0 -3
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-template-replace/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-template-replace/qtools-template-replace.js +0 -106
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-template-replace/test.js +0 -168
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-to-key-value-array/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-to-key-value-array/qtools-to-key-value-array.js +0 -83
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-to-key-value-array/test.js +0 -68
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-to-string/package.json +0 -11
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-to-string/qtools-to-string.js +0 -84
- package/libDotD_Working_Example/node_modules/qtools-functional-library/lib/qtools-to-string/test.js +0 -63
- package/libDotD_Working_Example/node_modules/qtools-functional-library/package.json +0 -37
- package/libDotD_Working_Example/node_modules/qtools-functional-library/qtFunctionalDemo.js +0 -297
- package/libDotD_Working_Example/node_modules/qtools-functional-library/qtools-functional-library.js +0 -271
- package/libDotD_Working_Example/node_modules/qtools-functional-library/test.js +0 -47
- package/libDotD_Working_Example/node_modules/qtools-library-dot-d/README.md +0 -208
- package/libDotD_Working_Example/node_modules/qtools-library-dot-d/package.json +0 -15
- package/libDotD_Working_Example/node_modules/qtools-library-dot-d/qtools-library-dot-d.js +0 -239
- package/libDotD_Working_Example/package-lock.json +0 -37
- package/libDotD_Working_Example/package.json +0 -23
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 TQ White II
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -227,8 +227,97 @@ The dotD pattern works particularly well in:
|
|
|
227
227
|
|
|
228
228
|
This pattern is used extensively in the qtools ecosystem for building scalable, maintainable Node.js applications.
|
|
229
229
|
|
|
230
|
+
## Loading from several directories
|
|
231
|
+
|
|
232
|
+
*New in 1.1.0. Opt-in: nothing changes for a library that uses `setLibraryPath`.*
|
|
233
|
+
|
|
234
|
+
A library can load from an ordered list of roots, so that one installation (an *instance*) can add its own modules beside the shared *framework* ones, and replace a framework module only by saying so.
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
const screenersDotD = qtLibDotD({ libraryName: 'corpusScreeners' });
|
|
238
|
+
|
|
239
|
+
screenersDotD.setInterface({ // optional; checks every element
|
|
240
|
+
describeFunctionName: 'describeCorpusScreener',
|
|
241
|
+
requiredFunctionList: ['screenCorpus'],
|
|
242
|
+
nameFieldName: 'corpusScreenerName',
|
|
243
|
+
versionFieldName: 'corpusScreenerVersion',
|
|
244
|
+
contractVersion: 1,
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
screenersDotD.setForbiddenRequireCheck({ // optional; static scan of instance source
|
|
248
|
+
provenanceList: ['instance'],
|
|
249
|
+
allowedModuleList: require('module').builtinModules,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
screenersDotD.setLibraryPathList([
|
|
253
|
+
{ dirPath: instanceScreenersPath, provenance: 'instance', mayBeAbsent: true },
|
|
254
|
+
{ dirPath: frameworkScreenersPath, provenance: 'framework' },
|
|
255
|
+
]);
|
|
256
|
+
|
|
257
|
+
screenersDotD.loadModules({ passThroughParameters }, (err) => {
|
|
258
|
+
// err names every refusal, one per line; '' when all loaded
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### The rules
|
|
263
|
+
|
|
264
|
+
- **Entries.** `{ dirPath, provenance: 'instance' | 'framework', mayBeAbsent }`. A plain string is a framework root that must exist. `mayBeAbsent` is optional and false when omitted.
|
|
265
|
+
- **Order.** Framework roots load first, then instance roots, whatever order the list gives them in.
|
|
266
|
+
- **Missing roots.** Refused as `PLUGIN_ROOT_NOT_FOUND` unless `mayBeAbsent` is true, in which case the log says `ROOT_ABSENT_ALLOWED`.
|
|
267
|
+
- **What is a module.** A `.js`/`.cjs`/`.mjs` file or a directory (`require()` must resolve it: `package.json` `main` or `index.js`). Dotfiles and other files are skipped and logged as `SKIPPED_NON_MODULE`; in single-path mode they would be "ignoring invalid file" lines.
|
|
268
|
+
- **One name, one element.** A name added a second time is refused as `PLUGIN_NAME_COLLISION`, naming both files, unless an instance element replaces a framework element **and declares it**:
|
|
269
|
+
|
|
270
|
+
```javascript
|
|
271
|
+
overridesFramework: { replacesVersion: '1', reason: 'why this instance needs its own' }
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
The declaration lives in the element's describe output when an interface is set, otherwise on the element itself (an object or function property). It needs both fields, or it is refused as `PLUGIN_OVERRIDE_DECLARATION_INVALID`. Two framework elements, or two instance elements, of one name always collide.
|
|
275
|
+
- **Stale overrides warn.** When `replacesVersion` is not strictly equal to the framework element's declared version (`versionFieldName`), the override is accepted and the log says `OVERRIDE_TARGET_CHANGED`. Without an interface there is no framework version to compare, and the log says `OVERRIDE_TARGET_UNVERSIONED`. A declaration with nothing to replace logs `OVERRIDE_TARGET_ABSENT`.
|
|
276
|
+
- **Interface check.** With `setInterface`, all five fields are required (`INTERFACE_SPEC_INCOMPLETE`). Each element must carry the describe function and every required function (`PLUGIN_INTERFACE_INCOMPLETE`), describe itself by the name it was added under (`PLUGIN_NAME_MISMATCH`), and declare the library's `contractVersion` (`PLUGIN_CONTRACT_MISMATCH`).
|
|
277
|
+
- **Load errors are refusals.** A module whose `require()` throws is refused as `PLUGIN_LOAD_FAILED`, naming the file. `loadModules({ passThroughParameters, tolerateLoadErrors: true })` lists it in the exception list instead, still as `PLUGIN_LOAD_FAILED`.
|
|
278
|
+
- **Forbidden requires.** With `setForbiddenRequireCheck`, the source of every module from a listed provenance is scanned before it runs. A refused module is never executed (`PLUGIN_FORBIDDEN_REQUIRE`).
|
|
279
|
+
- **What is allowed:**
|
|
280
|
+
- names in `allowedModuleList` (a `node:` prefix is ignored);
|
|
281
|
+
- relative or absolute paths whose resolved file, judged by its real path after symlinks, stays inside the plugin's own directory. For a single-file module, that is its root.
|
|
282
|
+
- **What is refused:**
|
|
283
|
+
- a path that resolves to a non-module file, such as `require('./payload.txt')`, which CommonJS would run as JavaScript;
|
|
284
|
+
- a path that does not resolve at all;
|
|
285
|
+
- a module whose own real path, or `package.json` `main`, lies outside its directory.
|
|
286
|
+
- **What the scan cannot see.** The scan reads every `.js`/`.cjs`/`.mjs` file in a directory module, recursively (this needs Node 20 or later). It is a regular expression over string-literal `require('…')` and static template calls. It does **not** catch:
|
|
287
|
+
- a require whose name is built at run time: a variable, string concatenation, or a `${}` template;
|
|
288
|
+
- `import()`;
|
|
289
|
+
- `module.createRequire` (`module` is a built-in, so allowed).
|
|
290
|
+
|
|
291
|
+
It also refuses a `require('…')` that appears only in a comment. That is a false refusal, not a missed one.
|
|
292
|
+
- **Why the check exists.** It serves portability (spec R6), not security: it is not a sandbox.
|
|
293
|
+
- **Reserved names.** An element may not take a library API name such as `toString` or `getProvenance`, nor a name `Object.prototype` carries (`constructor`, `hasOwnProperty`, `__proto__`, and the `qt…` methods qtools-functional-library installs there). Elements are properties of the library object itself, so such a name would shadow a method the library relies on: `qtSelectProperties` would break `seal()`. Refused as `PLUGIN_NAME_RESERVED`.
|
|
294
|
+
- **Adding late.** `library.add()` after loading has finished throws `PLUGIN_ADD_OUTSIDE_LOAD`: there is no file to attribute it to and no callback left to report it. A module must register synchronously, while it is being required. A registration from a timer or a promise throws there, uncaught, and stops the process.
|
|
295
|
+
- **Load once.** A second `loadModules` on a path-list library is refused (`LOAD_MODULES_REPEATED`); single-path libraries still simply re-add.
|
|
296
|
+
- **Directory modules need an entry point.** `require(<dir>)` resolves `package.json` `main` or `index.js`. A layout like `screeners.d/<name>/<name>.js` without one of them is `PLUGIN_LOAD_FAILED`.
|
|
297
|
+
- **A loadModules error is fatal.** Refusals are collected, and `loadModules` calls back with all of them. Elements that passed stay loaded, so after an error the library is partly populated. Treat the error as fatal and do not use the library.
|
|
298
|
+
- **Silent modules.** A module that loads but adds nothing is logged as `MODULE_ADDED_NOTHING`.
|
|
299
|
+
- **Not mixable.** One library uses either `setLibraryPath` or `setLibraryPathList` (`LIBRARY_PATH_MODE_CONFLICT`). `setInterface` and `setForbiddenRequireCheck` need a path list (`REQUIRES_PATH_LIST`), and so does the default add: `setCustomAddFunction` with a path list is refused (`CUSTOM_ADD_REQUIRES_SINGLE_PATH`).
|
|
300
|
+
- **Without a callback,** `setLibraryPathList` and `loadModules` throw the refusal string, as `setLibraryPath` throws a bad path.
|
|
301
|
+
- **Sealing.** `seal()` removes the setters, `library` and `logList`, as it always has. For a path-list library it also removes `setLibraryPathList`, `setInterface` and `setForbiddenRequireCheck`. The getters remain.
|
|
302
|
+
|
|
303
|
+
### Provenance
|
|
304
|
+
|
|
305
|
+
Every element records `{ provenance, filePath, overrides? }`:
|
|
306
|
+
|
|
307
|
+
```javascript
|
|
308
|
+
screenersDotD.getProvenance('transcriptDetector');
|
|
309
|
+
// { provenance: 'instance', filePath: '…/corpusScreeners.d/transcriptDetector',
|
|
310
|
+
// overrides: { provenance: 'framework', filePath: '…', version: '1', reason: '…' } }
|
|
311
|
+
screenersDotD.getProvenanceList(); // [{ elementName, provenance, filePath, overrides? }, …]
|
|
312
|
+
screenersDotD.getRefusalList(); // [{ refusalCode, elementName, filePath, message }, …]
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
`toString()` adds the same on each element line, e.g. `transcriptDetector: object [instance: …; overrides framework v1 (…) because …]`. `getProvenance` throws `PROVENANCE_NOT_RECORDED` for a single-path library and `PROVENANCE_UNKNOWN_NAME` for a name it does not have. Warnings (`OVERRIDE_TARGET_…`, `ROOT_ABSENT_ALLOWED`, `SKIPPED_NON_MODULE`, `MODULE_ADDED_NOTHING`) are in `qtdProcessLog()`.
|
|
316
|
+
|
|
230
317
|
## HISTORY
|
|
231
318
|
|
|
319
|
+
v1.1.0 - setLibraryPathList: framework and instance roots, declared overrides, opt-in interface and forbidden-require checks, provenance, named refusals; Object.prototype names reserved in path-list mode. setLibraryPath unchanged. Tests added (npm test); test/ not shipped in the package.
|
|
320
|
+
v1.13 - License changed to MIT (was ISC). No code changes.
|
|
232
321
|
v1.12 - clarified error message "Ignoring invalid file".
|
|
233
322
|
v1.10 - there was a reason I did not return the exception list. Undone.
|
|
234
323
|
v1.09 - fixed broken error handling when library file path is bad; added demonstration application
|
package/package.json
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qtools-library-dot-d",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
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
|
+
"files": [
|
|
7
|
+
"qtools-library-dot-d.js",
|
|
8
|
+
"README.md",
|
|
9
|
+
"README2.md",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
6
12
|
"scripts": {
|
|
7
|
-
"test": "
|
|
13
|
+
"test": "node --test test/*.test.js"
|
|
8
14
|
},
|
|
9
15
|
"author": "TQ White II",
|
|
10
|
-
"license": "
|
|
16
|
+
"license": "MIT",
|
|
11
17
|
"dependencies": {
|
|
12
18
|
"qtools-asynchronous-pipe-plus": "^1.0.2",
|
|
13
19
|
"qtools-functional-library": "^2.0.4"
|