@cldmv/slothlet 2.5.5 → 2.6.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/README.md +59 -5
- package/dist/lib/helpers/als-eventemitter.mjs +5 -4
- package/dist/lib/helpers/api_builder.mjs +27 -13
- package/dist/lib/helpers/auto-wrap.mjs +4 -2
- package/dist/lib/helpers/instance-manager.mjs +111 -0
- package/dist/lib/helpers/multidefault.mjs +12 -2
- package/dist/lib/modes/slothlet_eager.mjs +1 -1
- package/dist/lib/modes/slothlet_lazy.mjs +48 -5
- package/dist/lib/runtime/runtime-asynclocalstorage.mjs +435 -0
- package/dist/lib/runtime/runtime-livebindings.mjs +298 -0
- package/dist/lib/runtime/runtime.mjs +152 -349
- package/dist/slothlet.mjs +97 -11
- package/index.cjs +30 -39
- package/index.mjs +45 -15
- package/package.json +17 -1
- package/types/dist/lib/helpers/als-eventemitter.d.mts +3 -3
- package/types/dist/lib/helpers/als-eventemitter.d.mts.map +1 -1
- package/types/dist/lib/helpers/api_builder.d.mts.map +1 -1
- package/types/dist/lib/helpers/auto-wrap.d.mts.map +1 -1
- package/types/dist/lib/helpers/instance-manager.d.mts +41 -0
- package/types/dist/lib/helpers/instance-manager.d.mts.map +1 -0
- package/types/dist/lib/helpers/multidefault.d.mts +8 -3
- package/types/dist/lib/helpers/multidefault.d.mts.map +1 -1
- package/types/dist/lib/modes/slothlet_lazy.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +58 -0
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -0
- package/types/dist/lib/runtime/runtime-livebindings.d.mts +58 -0
- package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -0
- package/types/dist/lib/runtime/runtime.d.mts +8 -57
- package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
- package/types/dist/slothlet.d.mts +17 -9
- package/types/dist/slothlet.d.mts.map +1 -1
package/README.md
CHANGED
|
@@ -104,6 +104,12 @@ v2.0 represents a ground-up rewrite with enterprise-grade features:
|
|
|
104
104
|
> [!TIP]
|
|
105
105
|
> **📁 For comprehensive examples of API flattening, naming conventions, and function preservation patterns, see the test modules in [api_tests/](https://github.com/CLDMV/slothlet/blob/HEAD/api_tests) and their documentation in [docs/api_tests/](https://github.com/CLDMV/slothlet/blob/HEAD/docs/api_tests)**
|
|
106
106
|
|
|
107
|
+
> [!NOTE]
|
|
108
|
+
> **🔍 For detailed technical documentation on API transformation rules:**
|
|
109
|
+
>
|
|
110
|
+
> - **[API-RULES.md](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES.md)** - Verified API transformation rules with examples and test cases
|
|
111
|
+
> - **[API-RULES-CONDITIONS.md](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES-CONDITIONS.md)** - Complete technical reference of all conditional logic that controls API generation
|
|
112
|
+
|
|
107
113
|
### 🔗 **Advanced Binding System**
|
|
108
114
|
|
|
109
115
|
- **Live Bindings**: Dynamic context and reference binding for runtime API mutation
|
|
@@ -193,9 +199,16 @@ const mixedResult = await api.interop.processData({ data: "test" }); // CJS+ESM
|
|
|
193
199
|
```javascript
|
|
194
200
|
import slothlet from "@cldmv/slothlet";
|
|
195
201
|
|
|
196
|
-
// Lazy mode with copy-left materialization
|
|
202
|
+
// Lazy mode with copy-left materialization
|
|
197
203
|
const api = await slothlet({
|
|
198
|
-
|
|
204
|
+
mode: "lazy", // New preferred syntax
|
|
205
|
+
dir: "./api",
|
|
206
|
+
apiDepth: 3
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Or use legacy syntax (still supported)
|
|
210
|
+
const apiLegacy = await slothlet({
|
|
211
|
+
lazy: true, // Legacy syntax
|
|
199
212
|
dir: "./api",
|
|
200
213
|
apiDepth: 3
|
|
201
214
|
});
|
|
@@ -214,7 +227,8 @@ import slothlet from "@cldmv/slothlet";
|
|
|
214
227
|
|
|
215
228
|
const api = await slothlet({
|
|
216
229
|
dir: "./api",
|
|
217
|
-
|
|
230
|
+
mode: "eager", // New: Loading strategy (lazy/eager)
|
|
231
|
+
engine: "singleton", // New: Execution environment
|
|
218
232
|
api_mode: "auto", // API structure behavior
|
|
219
233
|
apiDepth: Infinity, // Directory traversal depth
|
|
220
234
|
debug: false, // Enable verbose logging
|
|
@@ -334,15 +348,50 @@ Creates and loads an API instance with the specified configuration.
|
|
|
334
348
|
| Option | Type | Default | Description |
|
|
335
349
|
| ----------- | --------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
336
350
|
| `dir` | `string` | `"api"` | Directory to load API modules from. Can be absolute or relative path. If relative, resolved from process.cwd(). |
|
|
337
|
-
| `lazy` | `boolean` | `false` |
|
|
351
|
+
| `lazy` | `boolean` | `false` | **Legacy** loading strategy - `true` for lazy loading (on-demand), `false` for eager loading (immediate). Use `mode` option instead. |
|
|
352
|
+
| `mode` | `string` | - | **New** loading mode - `"lazy"` for on-demand loading, `"eager"` for immediate loading. Takes precedence over `lazy` option. Also supports execution modes for backward compatibility. |
|
|
353
|
+
| `engine` | `string` | `"singleton"` | **New** execution environment mode - `"singleton"`, `"vm"`, `"worker"`, or `"fork"` |
|
|
338
354
|
| `apiDepth` | `number` | `Infinity` | Directory traversal depth control - `0` for root only, `Infinity` for all levels |
|
|
339
355
|
| `debug` | `boolean` | `false` | Enable verbose logging. Can also be set via `--slothletdebug` command line flag or `SLOTHLET_DEBUG=true` environment variable |
|
|
340
|
-
| `mode` | `string` | `"singleton"` | Execution environment mode - `"singleton"`, `"vm"`, `"worker"`, or `"fork"` |
|
|
341
356
|
| `api_mode` | `string` | `"auto"` | API structure behavior when root-level default functions exist:<br/>• `"auto"`: Automatically detects if root has default function export and creates callable API<br/>• `"function"`: Forces API to be callable (use when you have root-level default function exports)<br/>• `"object"`: Forces API to be object-only (use when you want object interface regardless of exports) |
|
|
342
357
|
| `context` | `object` | `{}` | Context data object injected into live-binding `context` reference. Available to all loaded modules via `import { context } from "@cldmv/slothlet/runtime"` |
|
|
343
358
|
| `reference` | `object` | `{}` | Reference object merged into the API root level. Properties not conflicting with loaded modules are added directly to the API |
|
|
344
359
|
| `sanitize` | `object` | `{}` | **🔧 NEW**: Control how filenames become API property names. Supports exact matches, glob patterns (`*json*`), and boundary patterns (`**url**`). Configure `lowerFirst` and `rules` for `leave`, `leaveInsensitive`, `upper`, and `lower` transformations |
|
|
345
360
|
|
|
361
|
+
#### ✨ New Option Format (v2.6.0+)
|
|
362
|
+
|
|
363
|
+
The option structure has been improved for better clarity:
|
|
364
|
+
|
|
365
|
+
```javascript
|
|
366
|
+
// ✅ New recommended syntax
|
|
367
|
+
const api = await slothlet({
|
|
368
|
+
mode: "lazy", // Loading strategy: "lazy" | "eager"
|
|
369
|
+
engine: "singleton", // Execution environment: "singleton" | "vm" | "worker" | "fork"
|
|
370
|
+
dir: "./api"
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// ✅ Legacy syntax (still fully supported)
|
|
374
|
+
const api = await slothlet({
|
|
375
|
+
lazy: true, // Boolean loading strategy
|
|
376
|
+
mode: "singleton", // Execution environment (legacy placement)
|
|
377
|
+
dir: "./api"
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
// ✅ Mixed usage (mode takes precedence)
|
|
381
|
+
const api = await slothlet({
|
|
382
|
+
lazy: false, // Will be overridden
|
|
383
|
+
mode: "lazy", // Takes precedence - results in lazy loading
|
|
384
|
+
engine: "singleton"
|
|
385
|
+
});
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
**Benefits of the new syntax:**
|
|
389
|
+
|
|
390
|
+
- **Clearer separation**: `mode` for loading strategy, `engine` for execution environment
|
|
391
|
+
- **Better discoverability**: String values are more self-documenting than boolean flags
|
|
392
|
+
- **Future-proof**: Easier to extend with additional loading strategies
|
|
393
|
+
- **Backward compatible**: All existing code continues to work unchanged
|
|
394
|
+
|
|
346
395
|
#### `slothlet.getApi()` ⇒ `object`
|
|
347
396
|
|
|
348
397
|
Returns the raw API object (Proxy or plain object).
|
|
@@ -1157,6 +1206,11 @@ Key highlights:
|
|
|
1157
1206
|
- **[Security Policy](https://github.com/CLDMV/slothlet/blob/HEAD/SECURITY.md)** - Security guidelines and reporting
|
|
1158
1207
|
- **[Test Documentation](https://github.com/CLDMV/slothlet/blob/HEAD/api_tests)** - Comprehensive test module examples
|
|
1159
1208
|
|
|
1209
|
+
### 🔧 Technical Documentation
|
|
1210
|
+
|
|
1211
|
+
- **[API Rules](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES.md)** - Systematically verified API transformation rules with real examples and test cases
|
|
1212
|
+
- **[API Rules Conditions](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES-CONDITIONS.md)** - Complete technical reference of all 26 conditional statements that control API generation
|
|
1213
|
+
|
|
1160
1214
|
---
|
|
1161
1215
|
|
|
1162
1216
|
## 🔗 Links
|
|
@@ -20,10 +20,13 @@
|
|
|
20
20
|
|
|
21
21
|
import { AsyncResource } from "node:async_hooks";
|
|
22
22
|
import { EventEmitter } from "node:events";
|
|
23
|
-
import {
|
|
23
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
const defaultALS = new AsyncLocalStorage();
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
export function enableAlsForEventEmitters(als = defaultALS) {
|
|
27
30
|
|
|
28
31
|
const kPatched = Symbol.for("slothlet.als.patched");
|
|
29
32
|
|
|
@@ -115,5 +118,3 @@ export function enableAlsForEventEmitters(als = sharedALS) {
|
|
|
115
118
|
return res;
|
|
116
119
|
};
|
|
117
120
|
}
|
|
118
|
-
|
|
119
|
-
|
|
@@ -22,6 +22,8 @@ import fs from "node:fs/promises";
|
|
|
22
22
|
import path from "node:path";
|
|
23
23
|
import { types as utilTypes } from "node:util";
|
|
24
24
|
import { pathToFileURL } from "node:url";
|
|
25
|
+
import { multidefault_analyzeModules } from "@cldmv/slothlet/helpers/multidefault";
|
|
26
|
+
import { setActiveInstance } from "@cldmv/slothlet/helpers/instance-manager";
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
|
|
@@ -48,10 +50,29 @@ function isLikelySerializable(val) {
|
|
|
48
50
|
|
|
49
51
|
|
|
50
52
|
export async function analyzeModule(modulePath, options = {}) {
|
|
51
|
-
const { debug = false } = options;
|
|
53
|
+
const { debug = false, instance = null } = options;
|
|
52
54
|
|
|
53
55
|
const moduleUrl = pathToFileURL(modulePath).href;
|
|
54
|
-
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
let importUrl = moduleUrl;
|
|
59
|
+
if (instance && instance.instanceId) {
|
|
60
|
+
const runtimeType = instance.config?.runtime || "async";
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
if (runtimeType === "live") {
|
|
64
|
+
const separator = moduleUrl.includes("?") ? "&" : "?";
|
|
65
|
+
importUrl = `${moduleUrl}${separator}slothlet_instance=${instance.instanceId}`;
|
|
66
|
+
importUrl = `${importUrl}&slothlet_runtime=${runtimeType}`;
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
setActiveInstance(instance.instanceId);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const rawModule = await import(importUrl);
|
|
55
76
|
|
|
56
77
|
|
|
57
78
|
let processedModule = rawModule;
|
|
@@ -361,8 +382,7 @@ export async function analyzeDirectoryStructure(categoryPath, options = {}) {
|
|
|
361
382
|
|
|
362
383
|
let multiDefaultAnalysis = null;
|
|
363
384
|
if (processingStrategy === "multi-file") {
|
|
364
|
-
|
|
365
|
-
multiDefaultAnalysis = await multidefault_analyzeModules(moduleFiles, categoryPath, debug);
|
|
385
|
+
multiDefaultAnalysis = await multidefault_analyzeModules(moduleFiles, categoryPath, { debug, instance });
|
|
366
386
|
}
|
|
367
387
|
|
|
368
388
|
|
|
@@ -949,8 +969,7 @@ export async function buildCategoryStructure(categoryPath, options = {}) {
|
|
|
949
969
|
const categoryModules = {};
|
|
950
970
|
|
|
951
971
|
|
|
952
|
-
const
|
|
953
|
-
const analysis = await multidefault_analyzeModules(moduleFiles, categoryPath, debug);
|
|
972
|
+
const analysis = await multidefault_analyzeModules(moduleFiles, categoryPath, { debug, instance });
|
|
954
973
|
const { totalDefaultExports, hasMultipleDefaultExports, selfReferentialFiles, defaultExportFiles: analysisDefaults } = analysis;
|
|
955
974
|
|
|
956
975
|
|
|
@@ -1090,8 +1109,7 @@ export async function buildRootAPI(dir, options = {}) {
|
|
|
1090
1109
|
|
|
1091
1110
|
if (moduleFiles.length > 0) {
|
|
1092
1111
|
|
|
1093
|
-
const
|
|
1094
|
-
const analysis = await multidefault_analyzeModules(moduleFiles, dir, debug);
|
|
1112
|
+
const analysis = await multidefault_analyzeModules(moduleFiles, dir, { debug, instance });
|
|
1095
1113
|
const { hasMultipleDefaultExports, selfReferentialFiles } = analysis;
|
|
1096
1114
|
|
|
1097
1115
|
|
|
@@ -1193,9 +1211,6 @@ export async function buildCategoryDecisions(categoryPath, options = {}) {
|
|
|
1193
1211
|
console.log(`[DEBUG] buildCategoryDecisions called with path: ${categoryPath}, mode: ${mode}`);
|
|
1194
1212
|
}
|
|
1195
1213
|
|
|
1196
|
-
const fs = await import("fs/promises");
|
|
1197
|
-
const path = await import("path");
|
|
1198
|
-
|
|
1199
1214
|
const files = await fs.readdir(categoryPath, { withFileTypes: true });
|
|
1200
1215
|
const moduleFiles = files.filter((f) => instance._shouldIncludeFile(f));
|
|
1201
1216
|
const categoryName = instance._toapiPathKey(path.basename(categoryPath));
|
|
@@ -1390,8 +1405,7 @@ export async function buildCategoryDecisions(categoryPath, options = {}) {
|
|
|
1390
1405
|
}
|
|
1391
1406
|
|
|
1392
1407
|
|
|
1393
|
-
const
|
|
1394
|
-
const analysis = await multidefault_analyzeModules(moduleFiles, categoryPath, debug);
|
|
1408
|
+
const analysis = await multidefault_analyzeModules(moduleFiles, categoryPath, { debug, instance });
|
|
1395
1409
|
|
|
1396
1410
|
decisions.multifileAnalysis = analysis;
|
|
1397
1411
|
|
|
@@ -22,13 +22,15 @@
|
|
|
22
22
|
export async function autoWrapEventEmitters(nodeModule) {
|
|
23
23
|
|
|
24
24
|
try {
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
const { self } = await import("@cldmv/slothlet/runtime/async");
|
|
26
28
|
if (!self?.__ctx) {
|
|
27
29
|
|
|
28
30
|
return nodeModule;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
const { makeWrapper } = await import("
|
|
33
|
+
const { makeWrapper } = await import("@cldmv/slothlet/runtime/async");
|
|
32
34
|
const wrapper = makeWrapper(self.__ctx);
|
|
33
35
|
|
|
34
36
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 CLDMV/Shinrai
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
const instanceRegistry = new Map();
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
let currentActiveInstanceId = null;
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export function getInstanceData(instanceId) {
|
|
27
|
+
return instanceRegistry.get(instanceId) || null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
export function updateInstanceData(instanceId, key, value) {
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
let instanceData = instanceRegistry.get(instanceId);
|
|
39
|
+
if (!instanceData) {
|
|
40
|
+
instanceData = {
|
|
41
|
+
self: null,
|
|
42
|
+
context: {},
|
|
43
|
+
reference: {}
|
|
44
|
+
};
|
|
45
|
+
instanceRegistry.set(instanceId, instanceData);
|
|
46
|
+
}
|
|
47
|
+
instanceData[key] = value;
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
export async function cleanupInstance(instanceId) {
|
|
54
|
+
|
|
55
|
+
instanceRegistry.delete(instanceId);
|
|
56
|
+
|
|
57
|
+
if (currentActiveInstanceId === instanceId) {
|
|
58
|
+
currentActiveInstanceId = null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
export function setActiveInstance(instanceId) {
|
|
64
|
+
currentActiveInstanceId = instanceId;
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
export function getCurrentActiveInstanceId() {
|
|
70
|
+
return currentActiveInstanceId;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
export function detectCurrentInstanceId() {
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
if (currentActiveInstanceId && instanceRegistry.has(currentActiveInstanceId)) {
|
|
84
|
+
return currentActiveInstanceId;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
const stack = new Error().stack;
|
|
89
|
+
if (stack) {
|
|
90
|
+
|
|
91
|
+
const matches = stack.match(/slothlet_instance=([^&\s):]+)/g);
|
|
92
|
+
|
|
93
|
+
if (matches && matches.length > 0) {
|
|
94
|
+
|
|
95
|
+
const instanceParam = matches[0];
|
|
96
|
+
const instanceId = instanceParam.replace(/slothlet_instance=([^&\s):]+).*/, "$1");
|
|
97
|
+
|
|
98
|
+
if (instanceRegistry.has(instanceId)) {
|
|
99
|
+
return instanceId;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
export function getAllInstanceIds() {
|
|
110
|
+
return Array.from(instanceRegistry.keys());
|
|
111
|
+
}
|
|
@@ -16,10 +16,13 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
|
|
20
|
+
|
|
19
21
|
import path from "path";
|
|
20
22
|
|
|
21
23
|
|
|
22
|
-
async function multidefault_analyzeModules(moduleFiles, baseDir,
|
|
24
|
+
async function multidefault_analyzeModules(moduleFiles, baseDir, options = {}) {
|
|
25
|
+
const { debug = false, instance = null } = options;
|
|
23
26
|
const selfReferentialFiles = new Set();
|
|
24
27
|
const rawModuleCache = new Map();
|
|
25
28
|
const defaultExportFiles = [];
|
|
@@ -36,7 +39,14 @@ async function multidefault_analyzeModules(moduleFiles, baseDir, debug = false)
|
|
|
36
39
|
const moduleFilePath = path.resolve(baseDir, file.name);
|
|
37
40
|
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
let importUrl = `file://${moduleFilePath.replace(/\\/g, "/")}`;
|
|
43
|
+
if (instance && instance.instanceId) {
|
|
44
|
+
const separator = importUrl.includes("?") ? "&" : "?";
|
|
45
|
+
importUrl = `${importUrl}${separator}slothlet_instance=${instance.instanceId}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
const rawImport = await import(importUrl);
|
|
40
50
|
|
|
41
51
|
|
|
42
52
|
const isCjsFile = moduleExt === ".cjs";
|
|
@@ -38,7 +38,7 @@ export async function create(dir, maxDepth = Infinity, currentDepth = 0) {
|
|
|
38
38
|
const moduleFiles = entries.filter((e) => this._shouldIncludeFile(e));
|
|
39
39
|
const defaultExportFiles = [];
|
|
40
40
|
|
|
41
|
-
const analysis = await multidefault_analyzeModules(moduleFiles, dir, this.config.debug);
|
|
41
|
+
const analysis = await multidefault_analyzeModules(moduleFiles, dir, { debug: this.config.debug, instance: this });
|
|
42
42
|
|
|
43
43
|
const { totalDefaultExports, hasMultipleDefaultExports, selfReferentialFiles, defaultExportFiles: analysisDefaults } = analysis;
|
|
44
44
|
|
|
@@ -21,13 +21,17 @@ import fs from "node:fs/promises";
|
|
|
21
21
|
import { readdirSync } from "node:fs";
|
|
22
22
|
import path from "node:path";
|
|
23
23
|
import { types as utilTypes } from "node:util";
|
|
24
|
-
import { runWithCtx } from "@cldmv/slothlet/runtime";
|
|
25
24
|
import { processModuleForAPI } from "@cldmv/slothlet/helpers/api_builder";
|
|
26
25
|
import { multidefault_analyzeModules } from "@cldmv/slothlet/helpers/multidefault";
|
|
27
26
|
|
|
28
27
|
|
|
29
28
|
export async function create(dir, maxDepth = Infinity, currentDepth = 0) {
|
|
30
29
|
const instance = this;
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
const runtimePath = instance.config.runtime === "live" ? "@cldmv/slothlet/runtime/live" : "@cldmv/slothlet/runtime/async";
|
|
33
|
+
const { runWithCtx } = await import(runtimePath);
|
|
34
|
+
|
|
31
35
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
32
36
|
let api = {};
|
|
33
37
|
let rootDefaultFn = null;
|
|
@@ -38,7 +42,7 @@ export async function create(dir, maxDepth = Infinity, currentDepth = 0) {
|
|
|
38
42
|
const defaultExportFiles = [];
|
|
39
43
|
|
|
40
44
|
|
|
41
|
-
const analysis = await multidefault_analyzeModules(moduleFiles, dir, instance.config.debug);
|
|
45
|
+
const analysis = await multidefault_analyzeModules(moduleFiles, dir, { debug: instance.config.debug, instance });
|
|
42
46
|
|
|
43
47
|
const { totalDefaultExports, hasMultipleDefaultExports, selfReferentialFiles, defaultExportFiles: analysisDefaults } = analysis;
|
|
44
48
|
|
|
@@ -156,7 +160,8 @@ export async function create(dir, maxDepth = Infinity, currentDepth = 0) {
|
|
|
156
160
|
instance,
|
|
157
161
|
depth,
|
|
158
162
|
maxDepth,
|
|
159
|
-
pathParts: [key]
|
|
163
|
+
pathParts: [key],
|
|
164
|
+
runWithCtx
|
|
160
165
|
});
|
|
161
166
|
parent[key] = proxy;
|
|
162
167
|
}
|
|
@@ -223,7 +228,7 @@ function replacePlaceholder(parent, key, placeholder, value, instance, depth) {
|
|
|
223
228
|
}
|
|
224
229
|
|
|
225
230
|
|
|
226
|
-
function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth, pathParts }) {
|
|
231
|
+
function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth, pathParts, runWithCtx }) {
|
|
227
232
|
let materialized = null;
|
|
228
233
|
let inFlight = null;
|
|
229
234
|
|
|
@@ -246,7 +251,8 @@ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth,
|
|
|
246
251
|
instance,
|
|
247
252
|
depth: cd + 1,
|
|
248
253
|
maxDepth: md,
|
|
249
|
-
pathParts: [...pathParts, nestedKey]
|
|
254
|
+
pathParts: [...pathParts, nestedKey],
|
|
255
|
+
runWithCtx
|
|
250
256
|
})
|
|
251
257
|
});
|
|
252
258
|
materialized = value;
|
|
@@ -374,6 +380,43 @@ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth,
|
|
|
374
380
|
return new Proxy(
|
|
375
381
|
function lazy_deepPropertyAccessor() {},
|
|
376
382
|
{
|
|
383
|
+
get(target, nextProp) {
|
|
384
|
+
if (nextProp === "name") return `lazy_${prop}_${subProp}`;
|
|
385
|
+
if (nextProp === "length") return 0;
|
|
386
|
+
|
|
387
|
+
return new Proxy(function lazy_deeperPropertyAccessor() {}, {
|
|
388
|
+
apply(target, thisArg, args) {
|
|
389
|
+
if (materialized) {
|
|
390
|
+
const value = materialized[prop];
|
|
391
|
+
const subValue = value ? value[subProp] : undefined;
|
|
392
|
+
if (subValue && typeof subValue[nextProp] === "function") {
|
|
393
|
+
const ctx = instance.boundapi?.__ctx;
|
|
394
|
+
if (ctx) {
|
|
395
|
+
return runWithCtx(ctx, subValue[nextProp], thisArg, args);
|
|
396
|
+
} else {
|
|
397
|
+
return subValue[nextProp].apply(thisArg, args);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return subValue ? subValue[nextProp] : undefined;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (!inFlight) inFlight = _materialize();
|
|
404
|
+
return inFlight.then(function lazy_handleDeeperResolvedValue(resolved) {
|
|
405
|
+
const value = resolved ? resolved[prop] : undefined;
|
|
406
|
+
const subValue = value ? value[subProp] : undefined;
|
|
407
|
+
if (subValue && typeof subValue[nextProp] === "function") {
|
|
408
|
+
const ctx = instance.boundapi?.__ctx;
|
|
409
|
+
if (ctx) {
|
|
410
|
+
return runWithCtx(ctx, subValue[nextProp], thisArg, args);
|
|
411
|
+
} else {
|
|
412
|
+
return subValue[nextProp].apply(thisArg, args);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return subValue ? subValue[nextProp] : undefined;
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
},
|
|
377
420
|
apply(target, thisArg, args) {
|
|
378
421
|
|
|
379
422
|
if (materialized) {
|