@cldmv/slothlet 3.2.3 → 3.3.2

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.
Files changed (138) hide show
  1. package/README.md +22 -9
  2. package/REFERENCE.md +23 -0
  3. package/dist/lib/builders/api-assignment.mjs +1 -589
  4. package/dist/lib/builders/api_builder.mjs +1 -1155
  5. package/dist/lib/builders/builder.mjs +1 -78
  6. package/dist/lib/builders/modes-processor.mjs +1 -1800
  7. package/dist/lib/errors.mjs +9 -211
  8. package/dist/lib/factories/component-base.mjs +1 -80
  9. package/dist/lib/factories/context.mjs +1 -22
  10. package/dist/lib/handlers/api-cache-manager.mjs +1 -200
  11. package/dist/lib/handlers/api-manager.mjs +1 -2513
  12. package/dist/lib/handlers/context-async.mjs +1 -168
  13. package/dist/lib/handlers/context-live.mjs +1 -168
  14. package/dist/lib/handlers/hook-manager.mjs +1 -773
  15. package/dist/lib/handlers/lifecycle-token.mjs +1 -28
  16. package/dist/lib/handlers/lifecycle.mjs +1 -115
  17. package/dist/lib/handlers/materialize-manager.mjs +1 -48
  18. package/dist/lib/handlers/metadata.mjs +1 -501
  19. package/dist/lib/handlers/ownership.mjs +1 -322
  20. package/dist/lib/handlers/permission-manager.mjs +17 -0
  21. package/dist/lib/handlers/unified-wrapper.mjs +1 -3042
  22. package/dist/lib/handlers/version-manager.mjs +1 -885
  23. package/dist/lib/helpers/class-instance-wrapper.mjs +1 -109
  24. package/dist/lib/helpers/config.mjs +1 -355
  25. package/dist/lib/helpers/eventemitter-context.mjs +1 -349
  26. package/dist/lib/helpers/hint-detector.mjs +1 -47
  27. package/dist/lib/helpers/modes-utils.mjs +1 -37
  28. package/dist/lib/helpers/pattern-matcher.mjs +17 -0
  29. package/dist/lib/helpers/resolve-from-caller.mjs +1 -169
  30. package/dist/lib/helpers/sanitize.mjs +1 -340
  31. package/dist/lib/helpers/utilities.mjs +1 -70
  32. package/dist/lib/i18n/languages/de-de.json +21 -1
  33. package/dist/lib/i18n/languages/en-gb.json +21 -1
  34. package/dist/lib/i18n/languages/en-us.json +21 -1
  35. package/dist/lib/i18n/languages/es-mx.json +21 -1
  36. package/dist/lib/i18n/languages/fr-fr.json +21 -1
  37. package/dist/lib/i18n/languages/hi-in.json +21 -1
  38. package/dist/lib/i18n/languages/ja-jp.json +21 -1
  39. package/dist/lib/i18n/languages/ko-kr.json +21 -1
  40. package/dist/lib/i18n/languages/pt-br.json +21 -1
  41. package/dist/lib/i18n/languages/ru-ru.json +21 -1
  42. package/dist/lib/i18n/languages/zh-cn.json +21 -1
  43. package/dist/lib/i18n/translations.mjs +1 -126
  44. package/dist/lib/modes/eager.mjs +1 -59
  45. package/dist/lib/modes/lazy.mjs +1 -81
  46. package/dist/lib/processors/flatten.mjs +1 -437
  47. package/dist/lib/processors/loader.mjs +1 -339
  48. package/dist/lib/processors/type-generator.mjs +1 -275
  49. package/dist/lib/processors/typescript.mjs +1 -172
  50. package/dist/lib/runtime/runtime-asynclocalstorage.mjs +1 -113
  51. package/dist/lib/runtime/runtime-livebindings.mjs +1 -78
  52. package/dist/lib/runtime/runtime.mjs +1 -102
  53. package/dist/slothlet.mjs +1 -808
  54. package/package.json +37 -31
  55. package/types/dist/lib/builders/api-assignment.d.mts +3 -92
  56. package/types/dist/lib/builders/api-assignment.d.mts.map +1 -1
  57. package/types/dist/lib/builders/api_builder.d.mts +102 -91
  58. package/types/dist/lib/builders/api_builder.d.mts.map +1 -1
  59. package/types/dist/lib/builders/builder.d.mts +1 -55
  60. package/types/dist/lib/builders/builder.d.mts.map +1 -1
  61. package/types/dist/lib/builders/modes-processor.d.mts +3 -27
  62. package/types/dist/lib/builders/modes-processor.d.mts.map +1 -1
  63. package/types/dist/lib/errors.d.mts +19 -109
  64. package/types/dist/lib/errors.d.mts.map +1 -1
  65. package/types/dist/lib/factories/component-base.d.mts +7 -177
  66. package/types/dist/lib/factories/component-base.d.mts.map +1 -1
  67. package/types/dist/lib/factories/context.d.mts +4 -22
  68. package/types/dist/lib/factories/context.d.mts.map +1 -1
  69. package/types/dist/lib/handlers/api-cache-manager.d.mts +20 -203
  70. package/types/dist/lib/handlers/api-cache-manager.d.mts.map +1 -1
  71. package/types/dist/lib/handlers/api-manager.d.mts +33 -408
  72. package/types/dist/lib/handlers/api-manager.d.mts.map +1 -1
  73. package/types/dist/lib/handlers/context-async.d.mts +23 -61
  74. package/types/dist/lib/handlers/context-async.d.mts.map +1 -1
  75. package/types/dist/lib/handlers/context-live.d.mts +22 -59
  76. package/types/dist/lib/handlers/context-live.d.mts.map +1 -1
  77. package/types/dist/lib/handlers/hook-manager.d.mts +46 -185
  78. package/types/dist/lib/handlers/hook-manager.d.mts.map +1 -1
  79. package/types/dist/lib/handlers/lifecycle-token.d.mts +3 -48
  80. package/types/dist/lib/handlers/lifecycle-token.d.mts.map +1 -1
  81. package/types/dist/lib/handlers/lifecycle.d.mts +5 -82
  82. package/types/dist/lib/handlers/lifecycle.d.mts.map +1 -1
  83. package/types/dist/lib/handlers/materialize-manager.d.mts +8 -70
  84. package/types/dist/lib/handlers/materialize-manager.d.mts.map +1 -1
  85. package/types/dist/lib/handlers/metadata.d.mts +17 -221
  86. package/types/dist/lib/handlers/metadata.d.mts.map +1 -1
  87. package/types/dist/lib/handlers/ownership.d.mts +44 -160
  88. package/types/dist/lib/handlers/ownership.d.mts.map +1 -1
  89. package/types/dist/lib/handlers/permission-manager.d.mts +47 -0
  90. package/types/dist/lib/handlers/permission-manager.d.mts.map +1 -0
  91. package/types/dist/lib/handlers/unified-wrapper.d.mts +26 -239
  92. package/types/dist/lib/handlers/unified-wrapper.d.mts.map +1 -1
  93. package/types/dist/lib/handlers/version-manager.d.mts +28 -225
  94. package/types/dist/lib/handlers/version-manager.d.mts.map +1 -1
  95. package/types/dist/lib/helpers/class-instance-wrapper.d.mts +2 -52
  96. package/types/dist/lib/helpers/class-instance-wrapper.d.mts.map +1 -1
  97. package/types/dist/lib/helpers/config.d.mts +125 -123
  98. package/types/dist/lib/helpers/config.d.mts.map +1 -1
  99. package/types/dist/lib/helpers/eventemitter-context.d.mts +3 -29
  100. package/types/dist/lib/helpers/eventemitter-context.d.mts.map +1 -1
  101. package/types/dist/lib/helpers/hint-detector.d.mts +2 -15
  102. package/types/dist/lib/helpers/hint-detector.d.mts.map +1 -1
  103. package/types/dist/lib/helpers/modes-utils.d.mts +3 -30
  104. package/types/dist/lib/helpers/modes-utils.d.mts.map +1 -1
  105. package/types/dist/lib/helpers/pattern-matcher.d.mts +4 -0
  106. package/types/dist/lib/helpers/pattern-matcher.d.mts.map +1 -0
  107. package/types/dist/lib/helpers/resolve-from-caller.d.mts +3 -27
  108. package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -1
  109. package/types/dist/lib/helpers/sanitize.d.mts +4 -92
  110. package/types/dist/lib/helpers/sanitize.d.mts.map +1 -1
  111. package/types/dist/lib/helpers/utilities.d.mts +4 -52
  112. package/types/dist/lib/helpers/utilities.d.mts.map +1 -1
  113. package/types/dist/lib/i18n/translations.d.mts +4 -37
  114. package/types/dist/lib/i18n/translations.d.mts.map +1 -1
  115. package/types/dist/lib/modes/eager.d.mts +8 -30
  116. package/types/dist/lib/modes/eager.d.mts.map +1 -1
  117. package/types/dist/lib/modes/lazy.d.mts +10 -43
  118. package/types/dist/lib/modes/lazy.d.mts.map +1 -1
  119. package/types/dist/lib/processors/flatten.d.mts +56 -107
  120. package/types/dist/lib/processors/flatten.d.mts.map +1 -1
  121. package/types/dist/lib/processors/loader.d.mts +6 -41
  122. package/types/dist/lib/processors/loader.d.mts.map +1 -1
  123. package/types/dist/lib/processors/type-generator.d.mts +2 -16
  124. package/types/dist/lib/processors/type-generator.d.mts.map +1 -1
  125. package/types/dist/lib/processors/typescript.d.mts +6 -53
  126. package/types/dist/lib/processors/typescript.d.mts.map +1 -1
  127. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +3 -71
  128. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
  129. package/types/dist/lib/runtime/runtime-livebindings.d.mts +2 -37
  130. package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
  131. package/types/dist/lib/runtime/runtime.d.mts +3 -39
  132. package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
  133. package/types/dist/slothlet.d.mts +3 -249
  134. package/types/dist/slothlet.d.mts.map +1 -1
  135. package/types/index.d.mts +36 -16
  136. package/types/index.d.mts.map +1 -0
  137. package/AGENT-USAGE.md +0 -736
  138. package/docs/API-RULES.md +0 -712
@@ -14,1803 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
-
18
-
19
-
20
- import { ComponentBase } from "@cldmv/slothlet/factories/component-base";
21
- import { t } from "@cldmv/slothlet/i18n";
22
- import { UnifiedWrapper, resolveWrapper } from "@cldmv/slothlet/handlers/unified-wrapper";
23
- import { getInstanceToken } from "@cldmv/slothlet/handlers/lifecycle-token";
24
-
25
- export class ModesProcessor extends ComponentBase {
26
- static slothletProperty = "modesProcessor";
27
-
28
- constructor(slothlet) {
29
- super(slothlet);
30
- }
31
- async processFiles(
32
- api,
33
- files,
34
- directory,
35
- currentDepth,
36
- mode,
37
- isRoot,
38
- recursive,
39
- populateDirectly = false,
40
- apiPathPrefix = "",
41
- collisionContext = "initial",
42
- moduleID = null,
43
- sourceFolder = null,
44
- cacheBust = null,
45
- collisionModeOverride = null
46
- ) {
47
-
48
- const buildApiPath = (path) => {
49
- if (!apiPathPrefix) return path;
50
-
51
-
52
-
53
- if (path.startsWith(`${apiPathPrefix}.`)) {
54
- return path;
55
- }
56
-
57
- return `${apiPathPrefix}.${path}`;
58
- };
59
- let rootDefaultFunction = null;
60
- const rootContributors = [];
61
- const categoryName = isRoot && !populateDirectly ? null : this.slothlet.helpers.sanitize.sanitizePropertyName(directory.name);
62
- let targetApi = isRoot && !populateDirectly ? api : populateDirectly ? api : (api[categoryName] = api[categoryName] || {});
63
-
64
-
65
-
66
- const isRootFile = currentDepth === 0 && !populateDirectly;
67
- const effectiveMode = mode === "lazy" && isRootFile ? "eager" : mode;
68
- const shouldWrap = !(effectiveMode === "lazy" && populateDirectly);
69
-
70
- if (!isRoot && shouldWrap && !populateDirectly) {
71
- const existingTarget = api[categoryName];
72
-
73
-
74
- if (existingTarget && resolveWrapper(existingTarget)) {
75
- if (this.slothlet.config.debug?.modes) {
76
- this.slothlet.debug("modes", {
77
- key: "DEBUG_MODE_CATEGORY_REUSE_EXISTING_WRAPPER",
78
- categoryName,
79
- apiPath: resolveWrapper(existingTarget)?.apiPath
80
- });
81
- }
82
- targetApi = existingTarget;
83
- } else if (existingTarget === undefined || (typeof existingTarget === "object" && existingTarget !== null)) {
84
-
85
-
86
-
87
-
88
- const initialImpl = resolveWrapper(existingTarget)
89
- ? {}
90
- :
91
-
92
- this.slothlet.helpers.modesUtils.cloneWrapperImpl(existingTarget || {}, mode);
93
- if (this.slothlet.config.debug?.modes) {
94
- this.slothlet.debug("modes", {
95
- key: "DEBUG_MODE_CATEGORY_WRAPPER_CREATED",
96
- categoryName,
97
- apiPath: buildApiPath(categoryName)
98
- });
99
- }
100
- const wrapper = new UnifiedWrapper(this.slothlet, {
101
- mode: effectiveMode,
102
- apiPath: buildApiPath(categoryName),
103
- initialImpl,
104
- filePath: directory.path,
105
-
106
-
107
- moduleID: moduleID || categoryName,
108
- sourceFolder
109
- });
110
- api[categoryName] = wrapper.createProxy();
111
-
112
-
113
-
114
-
115
- if (this.slothlet.handlers?.metadata) {
116
- this.slothlet.handlers.metadata.tagSystemMetadata(
117
- wrapper,
118
- {
119
- filePath: directory.path,
120
- apiPath: buildApiPath(categoryName),
121
-
122
-
123
- moduleID: moduleID || "base",
124
-
125
-
126
- sourceFolder: sourceFolder || directory.path
127
- },
128
- getInstanceToken(this.slothlet)
129
- );
130
- }
131
-
132
- if (this.slothlet.config.debug?.modes) {
133
- this.slothlet.debug("modes", {
134
- key: "DEBUG_MODE_CATEGORY_WRAPPER_ASSIGNED",
135
- categoryName
136
- });
137
- }
138
- targetApi = api[categoryName];
139
- if (this.slothlet.config.debug?.modes) {
140
- this.slothlet.debug("modes", {
141
- key: "DEBUG_MODE_CATEGORY_CREATED",
142
- categoryName,
143
- apiPath: wrapper.apiPath
144
- });
145
- this.slothlet.debug("modes", {
146
- key: "DEBUG_MODE_CATEGORY_TARGET_API_STATUS",
147
- isWrapper: !!resolveWrapper(targetApi),
148
- targetApiKeys: Object.keys(targetApi)
149
- });
150
- }
151
- }
152
- }
153
-
154
- if (!isRoot && this.slothlet.config.debug?.modes) {
155
- this.slothlet.debug("modes", {
156
- message: await t("DEBUG_MODE_PROCESSING_DIRECTORY", { mode, categoryName, currentDepth })
157
- });
158
- }
159
-
160
- const loadedModules = [];
161
- for (const file of files) {
162
- if (this.slothlet.config.debug?.modes && categoryName === "string") {
163
- this.slothlet.debug("modes", {
164
- key: "DEBUG_MODE_PROCESSING_FILE",
165
- categoryName,
166
- file: file.name,
167
- isRoot,
168
- populateDirectly,
169
- mode
170
- });
171
- }
172
- try {
173
- const mod = await this.slothlet.processors.loader.loadModule(file.path, this.slothlet.instanceID, moduleID, cacheBust);
174
- const exports = this.slothlet.processors.loader.extractExports(mod);
175
- const moduleName = this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);
176
- const moduleKeys = Object.keys(exports).filter((k) => k !== "default");
177
- const analysis = {
178
- hasDefault: exports.default !== undefined,
179
- hasNamed: moduleKeys.length > 0,
180
- defaultExportType: exports.default ? typeof exports.default : null
181
- };
182
- loadedModules.push({ file, mod: exports, moduleName, moduleKeys, analysis });
183
- } catch (error) {
184
-
185
-
186
- if (error.name === "SlothletError") throw error;
187
-
188
-
189
-
190
-
191
- throw new this.SlothletError("MODULE_LOAD_FAILED", { modulePath: file.path, moduleID: moduleID || file.moduleID }, error);
192
- }
193
- }
194
-
195
- const hasMultipleDefaults = loadedModules.filter((m) => m.analysis.hasDefault).length > 1;
196
-
197
- for (const { file, mod, moduleName, moduleKeys, analysis } of loadedModules) {
198
- if (this.slothlet.config.debug?.modes && categoryName === "logger") {
199
- this.slothlet.debug("modes", {
200
- key: "DEBUG_MODE_PROCESSING_MODULE",
201
- categoryName,
202
- moduleName,
203
- hasDefault: analysis.hasDefault,
204
- moduleKeys,
205
- targetApiType: typeof targetApi,
206
- targetApiCallable: typeof targetApi === "function"
207
- });
208
- }
209
-
210
-
211
-
212
-
213
- const isAddapiFile =
214
- moduleName === "addapi" ||
215
- file.name === "addapi" ||
216
- (file.fullName && ["addapi.mjs", "addapi.cjs", "addapi.js", "addapi.ts"].includes(file.fullName.toLowerCase()));
217
- const isAddapiObjectDefault = isAddapiFile && analysis.hasDefault && typeof mod.default !== "function";
218
- const isRootContributor = isRoot && analysis.hasDefault && typeof mod.default === "function" && !isAddapiObjectDefault;
219
- if (moduleName === "config" || moduleKeys.some((k) => k.includes("Config") || k.includes("config"))) {
220
- if (this.slothlet.config.debug?.modes) {
221
- this.slothlet.debug("modes", {
222
- key: "DEBUG_MODE_FILE_PROCESSING",
223
- module: moduleName,
224
- category: categoryName || "(none)",
225
- isRoot,
226
- hasDefault: analysis.hasDefault,
227
- moduleKeys
228
- });
229
- }
230
- }
231
- if (isRootContributor) {
232
-
233
- const defaultFunc = this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default, moduleName);
234
- for (const key of moduleKeys) {
235
- if (!this.slothlet.processors.flatten.shouldAttachNamedExport(key, mod[key], defaultFunc, mod.default)) {
236
- continue;
237
- }
238
- defaultFunc[key] = mod[key];
239
- }
240
-
241
- rootContributors.push({ moduleName, file, defaultFunc });
242
- continue;
243
- } else {
244
-
245
- const decision = await this.slothlet.processors.flatten.getFlatteningDecision({
246
- mod,
247
- moduleName,
248
- categoryName: categoryName || moduleName,
249
- analysis,
250
- hasMultipleDefaults,
251
- moduleKeys,
252
- t
253
- });
254
- if (this.slothlet.config.debug?.modes) {
255
- this.slothlet.debug("modes", {
256
- message: await t("DEBUG_MODE_MODULE_DECISION", { mode, moduleName, reason: decision.reason })
257
- });
258
- }
259
-
260
- const propertyName = decision.preferredName || moduleName;
261
-
262
-
263
-
264
- const effectiveCategoryName = categoryName || moduleName;
265
-
266
-
267
- let { moduleContent } = this.slothlet.processors.flatten.processModuleForAPI({
268
- mod,
269
- decision,
270
- moduleName,
271
- propertyName,
272
- moduleKeys,
273
- analysis,
274
- file,
275
- collisionContext,
276
- apiPathPrefix: apiPathPrefix || ""
277
- });
278
-
279
-
280
- if (!isRoot && !apiPathPrefix && moduleName === categoryName) {
281
-
282
-
283
- if (moduleKeys.length === 1 && moduleKeys[0] === moduleName && !analysis.hasDefault) {
284
-
285
-
286
- const exportedValue = mod[moduleName];
287
-
288
-
289
- if (typeof exportedValue === "object" && exportedValue !== null) {
290
- if (this.slothlet.config.debug?.modes && categoryName === "string") {
291
- this.slothlet.debug("modes", {
292
- key: "DEBUG_MODE_SINGLE_FILE_FOLDER_DETECTED",
293
- categoryName,
294
- populateDirectly,
295
- isRoot,
296
- mode,
297
- exportKeys: Object.keys(exportedValue)
298
- });
299
- }
300
-
301
-
302
-
303
- if (shouldWrap) {
304
- const wrapper = new UnifiedWrapper(this.slothlet, {
305
- mode: effectiveMode,
306
- apiPath: buildApiPath(categoryName),
307
- initialImpl: exportedValue,
308
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
309
- filePath: file.path,
310
-
311
-
312
- moduleID: moduleID || file.moduleID,
313
- sourceFolder
314
- });
315
-
316
- api[categoryName] = wrapper.createProxy();
317
- targetApi = api[categoryName];
318
- } else {
319
- this.slothlet.debug("modes", {
320
- key: "DEBUG_MODE_SINGLE_FILE_FOLDER_WRAPPED",
321
- categoryName,
322
- implKeys: Object.keys(exportedValue)
323
- });
324
- }
325
-
326
- for (const key of Object.keys(exportedValue)) {
327
-
328
-
329
- if (this.slothlet.handlers.ownership) {
330
- this.slothlet.handlers.ownership.register({
331
-
332
-
333
- moduleID: moduleID || file.moduleID,
334
- apiPath: `${categoryName}.${key}`,
335
- source: "core",
336
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
337
- filePath: file.path
338
- });
339
- }
340
- }
341
- continue;
342
- }
343
-
344
-
345
- } else if (analysis.hasDefault) {
346
-
347
-
348
-
349
-
350
-
351
-
352
-
353
-
354
- const namedKeys = moduleKeys.length > 0 ? moduleKeys : Object.keys(mod).filter((key) => key !== "default");
355
-
356
-
357
- const callableModule =
358
- typeof mod.default === "function"
359
- ? this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default, categoryName)
360
- : moduleContent;
361
-
362
-
363
- if (namedKeys.length > 0) {
364
- for (const key of namedKeys) {
365
-
366
-
367
-
368
- if (key in callableModule) {
369
- continue;
370
- }
371
-
372
-
373
- if (!this.slothlet.processors.flatten.shouldAttachNamedExport(key, mod[key], callableModule, mod.default)) {
374
- continue;
375
- }
376
-
377
-
378
-
379
-
380
-
381
-
382
- callableModule[key] = mod[key];
383
- }
384
- }
385
- moduleContent = callableModule;
386
-
387
-
388
- if (shouldWrap) {
389
- const wrapper = new UnifiedWrapper(this.slothlet, {
390
- mode: effectiveMode,
391
- apiPath: buildApiPath(categoryName),
392
- initialImpl: this.slothlet.helpers.modesUtils.cloneWrapperImpl(callableModule, mode),
393
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
394
- filePath: file.path,
395
-
396
-
397
- moduleID: moduleID || file.moduleID,
398
- sourceFolder
399
- });
400
-
401
- api[categoryName] = wrapper.createProxy();
402
-
403
- targetApi = api[categoryName];
404
- } else {
405
-
406
-
407
-
408
-
409
-
410
-
411
-
412
- api[categoryName] = moduleContent;
413
- targetApi = api[categoryName];
414
-
415
- }
416
-
417
-
418
- const needsSeparateNamedExports = typeof mod.default === "function";
419
- if (needsSeparateNamedExports && namedKeys.length > 0) {
420
- for (const key of namedKeys) {
421
-
422
-
423
- if (shouldWrap) {
424
- const namedWrapper = new UnifiedWrapper(this.slothlet, {
425
- mode: effectiveMode,
426
- apiPath: buildApiPath(`${categoryName}.${key}`),
427
- initialImpl: mod[key],
428
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
429
- filePath: file.path,
430
-
431
-
432
- moduleID: moduleID || file.moduleID,
433
- sourceFolder
434
- });
435
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, key, namedWrapper.createProxy(), {
436
- useCollisionDetection: true,
437
- config: this.slothlet.config,
438
- collisionContext
439
- });
440
- } else {
441
-
442
-
443
-
444
-
445
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, key, mod[key], {
446
- useCollisionDetection: true,
447
- config: this.slothlet.config,
448
- collisionContext
449
- });
450
-
451
- }
452
-
453
-
454
- if (this.slothlet.handlers.ownership) {
455
- this.slothlet.handlers.ownership.register({
456
-
457
-
458
- moduleID: moduleID || file.moduleID,
459
- apiPath: `${categoryName}.${key}`,
460
- source: "core",
461
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
462
- filePath: file.path
463
- });
464
- }
465
- }
466
- }
467
-
468
-
469
- if (this.slothlet.handlers.ownership) {
470
- this.slothlet.handlers.ownership.register({
471
-
472
-
473
- moduleID: moduleID || file.moduleID,
474
- apiPath: categoryName,
475
- source: "core",
476
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
477
- filePath: file.path
478
- });
479
- }
480
-
481
- continue;
482
-
483
-
484
- } else if (moduleKeys.length > 0) {
485
-
486
-
487
-
488
-
489
- const hasMatchingObject = moduleKeys.some(
490
- (key) => key === moduleName && typeof mod[key] === "object" && mod[key] !== null && !Array.isArray(mod[key])
491
- );
492
- if (hasMatchingObject) {
493
-
494
-
495
- const matchingObj = mod[moduleName];
496
-
497
- for (const [propKey, propValue] of Object.entries(matchingObj)) {
498
-
499
-
500
- if (shouldWrap) {
501
- const wrapper = new UnifiedWrapper(this.slothlet, {
502
- mode: effectiveMode,
503
- apiPath: buildApiPath(`${categoryName}.${propKey}`),
504
- initialImpl: this.slothlet.helpers.modesUtils.cloneWrapperImpl(propValue, mode),
505
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
506
- filePath: file.path,
507
-
508
-
509
- moduleID: moduleID || file.moduleID,
510
- sourceFolder
511
- });
512
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, propKey, wrapper.createProxy(), {
513
- useCollisionDetection: true,
514
- config: this.slothlet.config,
515
- collisionContext
516
- });
517
- } else {
518
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, propKey, propValue, {
519
- useCollisionDetection: true,
520
- config: this.slothlet.config,
521
- collisionContext
522
- });
523
- }
524
-
525
-
526
- if (this.slothlet.handlers.ownership) {
527
- this.slothlet.handlers.ownership.register({
528
-
529
-
530
- moduleID: moduleID || file.moduleID,
531
- apiPath: `${categoryName}.${propKey}`,
532
- source: "core",
533
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
534
- filePath: file.path
535
- });
536
- }
537
- }
538
-
539
- for (const key of moduleKeys) {
540
- if (key !== moduleName) {
541
-
542
-
543
- if (shouldWrap) {
544
- const wrapper = new UnifiedWrapper(this.slothlet, {
545
- mode: effectiveMode,
546
- apiPath: buildApiPath(`${categoryName}.${key}`),
547
- initialImpl: this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key], mode),
548
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
549
- filePath: file.path,
550
-
551
-
552
- moduleID: moduleID || file.moduleID,
553
- sourceFolder
554
- });
555
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, key, wrapper.createProxy(), {
556
- useCollisionDetection: true,
557
- config: this.slothlet.config,
558
- collisionContext
559
- });
560
- } else {
561
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, key, mod[key], {
562
- useCollisionDetection: true,
563
- config: this.slothlet.config,
564
- collisionContext
565
- });
566
- }
567
-
568
-
569
- if (this.slothlet.handlers.ownership) {
570
- this.slothlet.handlers.ownership.register({
571
-
572
-
573
- moduleID: moduleID || file.moduleID,
574
- apiPath: `${categoryName}.${key}`,
575
- source: "core",
576
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
577
- filePath: file.path
578
- });
579
- }
580
- }
581
- }
582
- } else {
583
-
584
- if (this.slothlet.config.debug?.modes) {
585
- this.slothlet.debug("modes", {
586
- key: "DEBUG_MODE_FLATTEN_MULTI_EXPORT_FILE",
587
- moduleName,
588
- categoryName,
589
- exportCount: moduleKeys.length
590
- });
591
- this.slothlet.debug("modes", {
592
- key: "DEBUG_MODE_FLATTEN_MULTI_EXPORT_TARGET_STATUS",
593
- isWrapper: !!resolveWrapper(targetApi),
594
- keysBefore: Object.keys(targetApi)
595
- });
596
- }
597
- for (const key of moduleKeys) {
598
- if (this.slothlet.config.debug?.modes) {
599
- this.slothlet.debug("modes", {
600
- key: "DEBUG_MODE_FLATTEN_MULTI_EXPORT_ASSIGNING",
601
- propKey: key
602
- });
603
- }
604
-
605
-
606
- if (shouldWrap) {
607
- const wrapper = new UnifiedWrapper(this.slothlet, {
608
- mode: effectiveMode,
609
- apiPath: buildApiPath(`${categoryName}.${key}`),
610
- initialImpl: this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key], mode),
611
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
612
- filePath: file.path,
613
-
614
-
615
- moduleID: moduleID || file.moduleID,
616
- sourceFolder
617
- });
618
- const assigned = this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, key, wrapper.createProxy(), {
619
- useCollisionDetection: true,
620
- config: this.slothlet.config,
621
- collisionContext
622
- });
623
- if (assigned) {
624
- this.slothlet.debug("modes", {
625
- key: "DEBUG_MODE_FLATTEN_MULTI_EXPORT_ASSIGNED",
626
- propKey: key,
627
- keysAfter: Object.keys(targetApi)
628
- });
629
- } else {
630
- this.slothlet.debug("modes", {
631
- key: "DEBUG_MODE_FLATTEN_MULTI_EXPORT_BLOCKED",
632
- propKey: key
633
- });
634
- }
635
- } else {
636
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, key, mod[key], {
637
- useCollisionDetection: true,
638
- config: this.slothlet.config,
639
- collisionContext
640
- });
641
- }
642
-
643
-
644
- if (this.slothlet.handlers.ownership) {
645
- this.slothlet.handlers.ownership.register({
646
-
647
-
648
- moduleID: moduleID || file.moduleID,
649
- apiPath: `${categoryName}.${key}`,
650
- source: "core",
651
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
652
- filePath: file.path
653
- });
654
- }
655
- }
656
- }
657
- continue;
658
- }
659
-
660
- }
661
-
662
-
663
-
664
-
665
-
666
- if (!analysis.hasDefault && moduleKeys.length === 1 && !isRoot) {
667
- const key = moduleKeys[0];
668
- const keyValue = mod[key];
669
- const isMatchingObject = key === moduleName && typeof keyValue === "object" && keyValue !== null && !Array.isArray(keyValue);
670
-
671
- if (!isMatchingObject) {
672
-
673
- const normalizedKey = key.toLowerCase().replace(/[-_]/g, "");
674
- const normalizedModuleName = moduleName.toLowerCase().replace(/[-_]/g, "");
675
- if (normalizedKey === normalizedModuleName) {
676
-
677
- const preferredName = key;
678
-
679
-
680
- if (shouldWrap) {
681
- const wrapper = new UnifiedWrapper(this.slothlet, {
682
- mode: effectiveMode,
683
- apiPath: buildApiPath(`${categoryName}.${preferredName}`),
684
- initialImpl: this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key], mode),
685
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
686
- filePath: file.path,
687
-
688
-
689
- moduleID: moduleID || file.moduleID,
690
- sourceFolder
691
- });
692
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, preferredName, wrapper.createProxy(), {
693
- useCollisionDetection: true,
694
- config: this.slothlet.config,
695
- collisionContext
696
- });
697
- } else {
698
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, preferredName, mod[key], {
699
- useCollisionDetection: true,
700
- config: this.slothlet.config,
701
- collisionContext
702
- });
703
- }
704
-
705
-
706
- if (this.slothlet.handlers.ownership) {
707
- this.slothlet.handlers.ownership.register({
708
-
709
-
710
- moduleID: moduleID || file.moduleID,
711
- apiPath: `${categoryName}.${preferredName}`,
712
- source: "core",
713
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
714
- filePath: file.path
715
- });
716
- }
717
- continue;
718
- }
719
- }
720
- }
721
-
722
-
723
-
724
- if (decision.flattenToCategory && moduleContent && effectiveCategoryName) {
725
-
726
- const isAddapiFile = decision.flattenType === "addapi-metadata-default" || decision.flattenType === "addapi-special-file";
727
-
728
- if (isAddapiFile && typeof moduleContent === "object" && !Array.isArray(moduleContent) && typeof moduleContent !== "function") {
729
-
730
-
731
- for (const key of Object.keys(moduleContent)) {
732
- const value = moduleContent[key];
733
-
734
-
735
- const keyPath = isRoot ? key : `${apiPathPrefix ? apiPathPrefix + "." : ""}${key}`;
736
-
737
- if (shouldWrap && typeof value === "function") {
738
- const wrapper = new UnifiedWrapper(this.slothlet, {
739
- mode: effectiveMode,
740
- apiPath: buildApiPath(keyPath),
741
- initialImpl: value,
742
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
743
- filePath: file.path,
744
-
745
-
746
- moduleID: moduleID || file.moduleID,
747
- sourceFolder
748
- });
749
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, key, wrapper.createProxy(), {
750
- useCollisionDetection: true,
751
- config: this.slothlet.config,
752
- collisionContext
753
- });
754
- } else {
755
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, key, value, {
756
- useCollisionDetection: true,
757
- config: this.slothlet.config,
758
- collisionContext
759
- });
760
- }
761
- }
762
-
763
-
764
-
765
-
766
- if (this.slothlet.handlers.ownership) {
767
- for (const key of Object.keys(moduleContent)) {
768
-
769
-
770
- const apiPath = isRoot ? key : apiPathPrefix ? `${apiPathPrefix}.${key}` : key;
771
- this.slothlet.handlers.ownership.register({
772
-
773
-
774
- moduleID: moduleID || file.moduleID,
775
- apiPath,
776
- source: "core",
777
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
778
- config: this.slothlet.config
779
- });
780
- }
781
- }
782
- } else {
783
-
784
-
785
-
786
- const localPath = isRoot ? effectiveCategoryName : `${apiPathPrefix ? apiPathPrefix + "." : ""}${effectiveCategoryName}`;
787
-
788
-
789
-
790
- if (shouldWrap) {
791
- const wrapper = new UnifiedWrapper(this.slothlet, {
792
- mode: effectiveMode,
793
- apiPath: buildApiPath(localPath),
794
- initialImpl: moduleContent,
795
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
796
- filePath: file.path,
797
-
798
-
799
- moduleID: moduleID || file.moduleID,
800
- sourceFolder,
801
- isCallable: typeof moduleContent === "function"
802
- });
803
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, effectiveCategoryName, wrapper.createProxy(), {
804
- useCollisionDetection: true,
805
- config: this.slothlet.config,
806
- collisionContext
807
- });
808
- } else {
809
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, effectiveCategoryName, moduleContent, {
810
- useCollisionDetection: true,
811
- config: this.slothlet.config,
812
- collisionContext
813
- });
814
- }
815
-
816
-
817
-
818
-
819
- if (this.slothlet.handlers.ownership) {
820
- const apiPath = isRoot
821
- ? effectiveCategoryName
822
- : apiPathPrefix
823
- ? `${apiPathPrefix}.${effectiveCategoryName}`
824
- : effectiveCategoryName;
825
- this.slothlet.handlers.ownership.register({
826
-
827
-
828
- moduleID: moduleID || file.moduleID,
829
- apiPath,
830
- source: "core",
831
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
832
- config: this.slothlet.config
833
- });
834
- }
835
- }
836
-
837
- continue;
838
- }
839
-
840
-
841
-
842
-
843
- if (shouldWrap) {
844
- const localPath = isRoot ? propertyName : `${categoryName}.${propertyName}`;
845
- const wrapper = new UnifiedWrapper(this.slothlet, {
846
- mode: effectiveMode,
847
- apiPath: buildApiPath(localPath),
848
- initialImpl: moduleContent,
849
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
850
- filePath: file.path,
851
-
852
-
853
- moduleID: moduleID || file.moduleID,
854
- sourceFolder
855
- });
856
- this.slothlet.debug("modes", {
857
- key: "DEBUG_MODE_FILE_WRAPPER_ASSIGNMENT",
858
- propertyName,
859
- apiPath: buildApiPath(localPath),
860
-
861
-
862
- overwriting: propertyName in targetApi ? (resolveWrapper(targetApi[propertyName]) ? "wrapper" : "value") : "nothing"
863
- });
864
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, propertyName, wrapper.createProxy(), {
865
- useCollisionDetection: true,
866
- config: this.slothlet.config,
867
- collisionContext
868
- });
869
- } else {
870
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, propertyName, moduleContent, {
871
- useCollisionDetection: true,
872
- config: this.slothlet.config,
873
- collisionContext
874
- });
875
- }
876
- if (this.slothlet.config.debug?.modes && categoryName === "logger") {
877
- this.slothlet.debug("modes", {
878
- key: "DEBUG_MODE_AFTER_ASSIGNMENT_STATUS",
879
- targetApiType: typeof targetApi,
880
- propertyName,
881
- hasProperty: propertyName in targetApi,
882
- implType: typeof resolveWrapper(targetApi)?.____slothletInternal.impl,
883
- implHasProperty: !!resolveWrapper(targetApi)?.____slothletInternal.impl?.utils
884
- });
885
- }
886
-
887
-
888
- if (this.slothlet.handlers.ownership) {
889
- const apiPath = isRoot ? propertyName : `${categoryName}.${propertyName}`;
890
- this.slothlet.handlers.ownership.register({
891
-
892
-
893
- moduleID: moduleID || file.moduleID,
894
- apiPath,
895
- source: "core",
896
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
897
- config: this.slothlet.config
898
- });
899
- }
900
- }
901
- }
902
-
903
- if (this.slothlet.config.debug?.modes) {
904
- this.slothlet.debug("modes", {
905
- key: "DEBUG_MODE_SUBDIRECTORY_CHECK",
906
- isRoot,
907
- categoryName,
908
- hasDirectory: !!directory,
909
- hasChildren: !!directory?.children,
910
- directoryCount: directory?.children?.directories?.length || 0
911
- });
912
- }
913
- this.slothlet.debug("modes", {
914
- key: "DEBUG_MODE_DIRECTORY_CHECK",
915
- hasChildren: !!directory?.children,
916
- hasDirectories: !!directory?.children?.directories,
917
- length: directory?.children?.directories?.length || 0
918
- });
919
- if (directory?.children?.directories) {
920
- this.slothlet.debug("modes", {
921
- key: "DEBUG_MODE_DIRECTORY_CHECK_PASSED",
922
- recursive
923
- });
924
- if (this.slothlet.config.debug?.modes) {
925
- this.slothlet.debug("modes", {
926
- key: "DEBUG_MODE_SUBDIRECTORIES_FOUND",
927
- subdirectoryCount: directory.children.directories.length,
928
- recursive
929
- });
930
- }
931
- if (recursive) {
932
-
933
- this.slothlet.debug("modes", {
934
- key: "DEBUG_MODE_SUBDIRECTORY_LOOP_START",
935
- count: directory.children.directories.length
936
- });
937
- for (const subDir of directory.children.directories) {
938
- this.slothlet.debug("modes", {
939
- key: "DEBUG_MODE_PROCESSING_SUBDIRECTORY",
940
- name: subDir.name,
941
- fileCount: subDir.children.files.length,
942
- subdirCount: subDir.children.directories.length
943
- });
944
- const subDirName = this.slothlet.helpers.sanitize.sanitizePropertyName(subDir.name);
945
-
946
- if (subDir.children.files.length === 1 && subDir.children.directories.length === 0) {
947
- const file = subDir.children.files[0];
948
- const moduleName = this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);
949
- const genericFilenames = ["singlefile", "index", "main", "default"];
950
- const isGeneric = genericFilenames.includes(moduleName.toLowerCase());
951
- const filenameMatchesFolder = moduleName === subDirName;
952
-
953
-
954
-
955
-
956
- if (isGeneric || filenameMatchesFolder) {
957
- this.slothlet.debug("modes", {
958
- key: "DEBUG_MODE_FOLDER_LEVEL_FLATTEN_CHECK",
959
- subDir: subDirName,
960
- file: moduleName,
961
- isGeneric,
962
- filenameMatches: filenameMatchesFolder
963
- });
964
- const mod = await this.slothlet.processors.loader.loadModule(file.path, this.slothlet.instanceID, moduleID, cacheBust);
965
- const exports = this.slothlet.processors.loader.extractExports(mod);
966
- const moduleKeys = Object.keys(exports).filter((k) => k !== "default");
967
- const analysis = {
968
- hasDefault: exports.default !== undefined,
969
- hasNamed: moduleKeys.length > 0,
970
- defaultExportType: exports.default ? typeof exports.default : null
971
- };
972
- const modContent = exports.default !== undefined ? exports.default : exports;
973
- const categoryDecision = await this.slothlet.processors.flatten.buildCategoryDecisions({
974
- categoryName: subDirName,
975
- mod: modContent,
976
- moduleName,
977
- fileBaseName: file.name,
978
- analysis,
979
- moduleKeys,
980
- currentDepth: currentDepth + 1,
981
- moduleFiles: subDir.children.files,
982
- t
983
- });
984
-
985
-
986
-
987
- if (categoryDecision.shouldFlatten) {
988
- this.slothlet.debug("modes", {
989
- key: "DEBUG_MODE_FOLDER_LEVEL_FLATTEN_SKIP_RECURSION",
990
- subDir: subDirName
991
- });
992
-
993
-
994
- let implToWrap;
995
-
996
-
997
-
998
-
999
- if (categoryDecision.flattenType === "addapi-metadata-default") {
1000
-
1001
- implToWrap = {};
1002
- for (const key of moduleKeys) {
1003
-
1004
-
1005
- if (key !== "default") {
1006
- implToWrap[key] = exports[key];
1007
- }
1008
- }
1009
- } else if (moduleName === subDirName && moduleKeys.includes(subDirName)) {
1010
-
1011
- implToWrap = exports[subDirName];
1012
- } else if (exports.default !== undefined) {
1013
-
1014
- implToWrap = exports.default;
1015
- if (moduleKeys.length > 0) {
1016
-
1017
-
1018
-
1019
- if (typeof implToWrap === "function") {
1020
-
1021
-
1022
-
1023
- const collisionConfig = this.slothlet.config.api?.collision || this.slothlet.config.collision;
1024
-
1025
-
1026
- const collisionMode = (collisionContext === "initial" ? collisionConfig?.initial : collisionConfig?.api) || "merge";
1027
- for (const key of moduleKeys) {
1028
-
1029
-
1030
- if (key !== "default") {
1031
- const hasExisting = implToWrap[key] !== undefined;
1032
- if (hasExisting) {
1033
- if (collisionMode === "merge" || collisionMode === "skip") {
1034
-
1035
- continue;
1036
- } else if (collisionMode === "error") {
1037
- throw new this.slothlet.SlothletError(
1038
- "COLLISION_DEFAULT_EXPORT_ERROR",
1039
- {
1040
- key,
1041
- apiPath: `${apiPathPrefix}.${subDirName}`
1042
- },
1043
- null,
1044
- { validationError: true }
1045
- );
1046
- } else if (collisionMode === "warn") {
1047
- new this.slothlet.SlothletWarning("WARNING_COLLISION_DEFAULT_EXPORT_OVERWRITE", {
1048
- key,
1049
- apiPath: `${apiPathPrefix}.${subDirName}`
1050
- });
1051
- }
1052
-
1053
- }
1054
- implToWrap[key] = exports[key];
1055
- }
1056
- }
1057
- } else if (typeof implToWrap === "object" && implToWrap !== null) {
1058
-
1059
- for (const key of moduleKeys) {
1060
- if (key !== "default" && !(key in implToWrap)) {
1061
- implToWrap[key] = exports[key];
1062
- }
1063
- }
1064
- }
1065
-
1066
- }
1067
- } else {
1068
-
1069
- implToWrap = modContent;
1070
- }
1071
-
1072
-
1073
-
1074
-
1075
-
1076
-
1077
-
1078
-
1079
-
1080
-
1081
-
1082
-
1083
-
1084
-
1085
- const modes_eagerCollisionConfig = this.slothlet.config.api?.collision || this.slothlet.config.collision;
1086
-
1087
-
1088
- const modes_eagerCollisionMode =
1089
- (collisionContext === "initial" ? modes_eagerCollisionConfig?.initial : modes_eagerCollisionConfig?.api) || "merge";
1090
- const modes_existingAtKey = targetApi[subDirName];
1091
- if (modes_existingAtKey !== undefined && modes_eagerCollisionMode !== "replace" && modes_eagerCollisionMode !== "skip") {
1092
- const modes_existingWrapper = resolveWrapper(modes_existingAtKey);
1093
-
1094
-
1095
- if (modes_existingWrapper) {
1096
-
1097
-
1098
-
1099
-
1100
-
1101
- if (
1102
- modes_existingWrapper.____slothletInternal?.materializeFunc &&
1103
- !modes_existingWrapper.____slothletInternal?.state?.materialized
1104
- ) {
1105
- await modes_existingWrapper._materialize();
1106
- }
1107
-
1108
-
1109
-
1110
-
1111
- if (
1112
- modes_existingWrapper.____slothletInternal?.impl &&
1113
- !modes_existingWrapper.____slothletInternal?.state?.childrenAdopted
1114
- ) {
1115
- modes_existingWrapper.___adoptImplChildren();
1116
- }
1117
- const modes_existingImpl = modes_existingWrapper.__impl;
1118
-
1119
-
1120
- if (modes_existingImpl && typeof modes_existingImpl === "object" && !Array.isArray(modes_existingImpl)) {
1121
- if (typeof implToWrap === "object" && implToWrap !== null) {
1122
- for (const [k, v] of Object.entries(modes_existingImpl)) {
1123
-
1124
-
1125
-
1126
-
1127
- if (!(k in implToWrap)) {
1128
- implToWrap[k] = v;
1129
- }
1130
- }
1131
-
1132
-
1133
-
1134
-
1135
- } else if (typeof implToWrap === "function") {
1136
- for (const [k, v] of Object.entries(modes_existingImpl)) {
1137
- if (implToWrap[k] === undefined) {
1138
- implToWrap[k] = v;
1139
- }
1140
- }
1141
- }
1142
-
1143
- }
1144
-
1145
- const modes_existingChildKeys = Object.keys(modes_existingWrapper).filter(
1146
- (k) => !k.startsWith("_") && !k.startsWith("__")
1147
- );
1148
- for (const ck of modes_existingChildKeys) {
1149
- if (typeof implToWrap === "object" && implToWrap !== null && !(ck in implToWrap)) {
1150
- implToWrap[ck] = modes_existingWrapper[ck];
1151
- } else if (typeof implToWrap === "function" && implToWrap[ck] === undefined) {
1152
- implToWrap[ck] = modes_existingWrapper[ck];
1153
- }
1154
- }
1155
- this.slothlet.debug("modes", {
1156
- key: "DEBUG_MODE_FILE_FOLDER_COLLISION_MERGED",
1157
- subDir: subDirName,
1158
- mergedKeys: Object.keys(implToWrap)
1159
- });
1160
- }
1161
- }
1162
-
1163
-
1164
- const wrapper = new UnifiedWrapper(this.slothlet, {
1165
- mode: effectiveMode,
1166
-
1167
-
1168
- apiPath: buildApiPath(categoryName ? `${categoryName}.${subDirName}` : subDirName),
1169
- initialImpl: implToWrap,
1170
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
1171
- filePath: file.path,
1172
-
1173
-
1174
- moduleID: moduleID || file.moduleID,
1175
- sourceFolder
1176
- });
1177
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, subDirName, wrapper.createProxy(), {
1178
- useCollisionDetection: true,
1179
- config: this.slothlet.config,
1180
- collisionContext
1181
- });
1182
-
1183
-
1184
- if (this.slothlet.handlers.ownership) {
1185
-
1186
-
1187
- const apiPath = buildApiPath(categoryName ? `${categoryName}.${subDirName}` : subDirName);
1188
- this.slothlet.handlers.ownership.register({
1189
-
1190
-
1191
- moduleID: moduleID || file.moduleID,
1192
- apiPath,
1193
- source: "core",
1194
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
1195
- config: this.slothlet.config
1196
- });
1197
- }
1198
- continue;
1199
- }
1200
- }
1201
- }
1202
-
1203
-
1204
-
1205
-
1206
-
1207
-
1208
-
1209
-
1210
- const currentCategoryName = apiPathPrefix ? apiPathPrefix.split(".").pop() : categoryName;
1211
- if (subDirName === currentCategoryName && currentCategoryName !== null) {
1212
-
1213
- await this.processFiles(
1214
- targetApi,
1215
- subDir.children.files,
1216
- subDir,
1217
- currentDepth + 1,
1218
- mode,
1219
- false,
1220
- recursive,
1221
- true,
1222
- apiPathPrefix,
1223
- collisionContext,
1224
- moduleID,
1225
- sourceFolder,
1226
- cacheBust
1227
- );
1228
- continue;
1229
- }
1230
-
1231
-
1232
- await this.processFiles(
1233
- targetApi,
1234
- subDir.children.files,
1235
- { name: subDirName, path: subDir.path, children: subDir.children },
1236
- currentDepth + 1,
1237
- mode,
1238
- false,
1239
- recursive,
1240
- false,
1241
- apiPathPrefix,
1242
- collisionContext,
1243
- moduleID,
1244
- sourceFolder,
1245
- cacheBust
1246
- );
1247
- }
1248
- } else {
1249
-
1250
- for (const subDir of directory.children.directories) {
1251
- const subDirName = this.slothlet.helpers.sanitize.sanitizePropertyName(subDir.name);
1252
-
1253
-
1254
-
1255
-
1256
-
1257
-
1258
-
1259
-
1260
-
1261
-
1262
-
1263
- const lazy_currentCategoryName = apiPathPrefix ? apiPathPrefix.split(".").pop() : categoryName;
1264
- if (subDirName === lazy_currentCategoryName && lazy_currentCategoryName !== null && !populateDirectly) {
1265
- await this.processFiles(
1266
- targetApi,
1267
- subDir.children.files,
1268
- subDir,
1269
- currentDepth + 1,
1270
- "eager",
1271
- false,
1272
- true,
1273
- true,
1274
- apiPathPrefix,
1275
- collisionContext,
1276
- moduleID,
1277
- sourceFolder,
1278
- cacheBust
1279
- );
1280
- continue;
1281
- }
1282
-
1283
- const apiPath = categoryName ? `${categoryName}.${subDirName}` : apiPathPrefix ? `${apiPathPrefix}.${subDirName}` : subDirName;
1284
- if (this.slothlet.config.debug?.modes) {
1285
- this.slothlet.debug("modes", {
1286
- key: "DEBUG_MODE_CREATING_LAZY_SUBDIRECTORY",
1287
- apiPath,
1288
- fileCount: subDir.children.files.length
1289
- });
1290
- }
1291
-
1292
-
1293
-
1294
-
1295
-
1296
-
1297
-
1298
-
1299
- const collisionConfig = this.slothlet.config.api?.collision;
1300
-
1301
-
1302
- const modes_initialCollisionMode =
1303
- collisionModeOverride || (collisionContext === "initial" ? collisionConfig?.initial : collisionConfig?.api) || "replace";
1304
-
1305
- let modes_fileFolderImpl = null;
1306
- const modes_lazyExisting = targetApi[subDirName];
1307
- if (modes_initialCollisionMode !== "replace" && resolveWrapper(modes_lazyExisting)) {
1308
- const modes_lazyExistingW = resolveWrapper(modes_lazyExisting);
1309
-
1310
- const existImpl = modes_lazyExistingW.__impl;
1311
-
1312
-
1313
- if (existImpl && typeof existImpl === "object" && !Array.isArray(existImpl)) {
1314
- modes_fileFolderImpl = { ...existImpl };
1315
- }
1316
-
1317
- const existChildKeys = Object.keys(modes_lazyExistingW).filter((k) => !k.startsWith("_") && !k.startsWith("__"));
1318
- for (const ck of existChildKeys) {
1319
-
1320
-
1321
-
1322
-
1323
-
1324
-
1325
- if (!modes_fileFolderImpl) modes_fileFolderImpl = {};
1326
-
1327
-
1328
- if (!(ck in modes_fileFolderImpl)) {
1329
- modes_fileFolderImpl[ck] = modes_lazyExistingW[ck];
1330
- }
1331
- }
1332
- }
1333
-
1334
- this.slothlet.builders.apiAssignment.assignToApiPath(
1335
- targetApi,
1336
- subDirName,
1337
- this.createLazySubdirectoryWrapper(
1338
- subDir,
1339
- apiPath,
1340
- moduleID,
1341
- sourceFolder,
1342
- cacheBust,
1343
- modes_fileFolderImpl,
1344
- modes_initialCollisionMode
1345
- ),
1346
- {
1347
- useCollisionDetection: true,
1348
- config: this.slothlet.config,
1349
- collisionContext
1350
- }
1351
- );
1352
- }
1353
- }
1354
- }
1355
-
1356
- if (isRoot && rootContributors.length > 0) {
1357
- if (rootContributors.length === 1) {
1358
-
1359
- const { moduleName, file, defaultFunc } = rootContributors[0];
1360
- rootDefaultFunction = defaultFunc;
1361
- if (this.slothlet.config.debug?.modes) {
1362
- this.slothlet.debug("modes", {
1363
-
1364
-
1365
- message: await t("DEBUG_MODE_ROOT_CONTRIBUTOR", { mode, functionName: defaultFunc.name || "anonymous" })
1366
- });
1367
- }
1368
-
1369
-
1370
- if (this.slothlet.handlers.ownership) {
1371
- this.slothlet.handlers.ownership.register({
1372
-
1373
-
1374
- moduleID: moduleID || file.moduleID,
1375
- apiPath: moduleName,
1376
- source: "core",
1377
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
1378
- filePath: file.path
1379
- });
1380
- }
1381
- } else {
1382
-
1383
- new this.SlothletWarning("WARNING_MULTIPLE_ROOT_CONTRIBUTORS", {
1384
- rootContributors: rootContributors.map((rc) => rc.moduleName).join(", "),
1385
- firstContributor: rootContributors[0].moduleName
1386
- });
1387
- for (const { moduleName, file, defaultFunc } of rootContributors) {
1388
-
1389
-
1390
-
1391
- if (shouldWrap) {
1392
- const wrapper = new UnifiedWrapper(this.slothlet, {
1393
- mode: effectiveMode,
1394
- apiPath: buildApiPath(moduleName),
1395
- initialImpl: this.slothlet.helpers.modesUtils.cloneWrapperImpl(defaultFunc, mode),
1396
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
1397
- filePath: file.path,
1398
-
1399
-
1400
- moduleID: moduleID || file.moduleID,
1401
- sourceFolder
1402
- });
1403
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, moduleName, wrapper.createProxy(), {
1404
- useCollisionDetection: true,
1405
- config: this.slothlet.config,
1406
- collisionContext
1407
- });
1408
-
1409
-
1410
-
1411
-
1412
-
1413
- } else {
1414
- this.slothlet.builders.apiAssignment.assignToApiPath(targetApi, moduleName, defaultFunc, {
1415
- useCollisionDetection: true,
1416
- config: this.slothlet.config,
1417
- collisionContext
1418
- });
1419
- }
1420
-
1421
-
1422
-
1423
- if (this.slothlet.handlers.ownership) {
1424
- this.slothlet.handlers.ownership.register({
1425
-
1426
-
1427
- moduleID: moduleID || file.moduleID,
1428
- apiPath: moduleName,
1429
- source: "core",
1430
- collisionMode: this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config, collisionContext),
1431
- filePath: file.path
1432
- });
1433
- }
1434
- }
1435
- }
1436
- }
1437
- return rootDefaultFunction;
1438
- }
1439
-
1440
- createLazySubdirectoryWrapper(
1441
- dir,
1442
- apiPath,
1443
- moduleID = null,
1444
- sourceFolder = null,
1445
- cacheBust = null,
1446
- fileFolderCollisionImpl = null,
1447
- collisionMode = "merge"
1448
- ) {
1449
-
1450
-
1451
- const lazy_materializeFunc = this.slothlet.modes.lazy.createNamedMaterializeFunc(apiPath, async () => {
1452
- if (this.slothlet.config.debug?.modes) {
1453
- this.slothlet.debug("modes", {
1454
- key: "DEBUG_MODE_MATERIALIZE_FUNCTION_STARTING",
1455
- dir: dir.name,
1456
-
1457
-
1458
- fileCount: dir.children.files?.length || 0
1459
- });
1460
- }
1461
- const categoryName = this.slothlet.helpers.sanitize.sanitizePropertyName(dir.name);
1462
- const materialized = {};
1463
-
1464
-
1465
-
1466
-
1467
-
1468
-
1469
- const actualSourceFolder = sourceFolder
1470
- ? `${sourceFolder}/${dir.name}`.replace(/\\/g, "/")
1471
- : `${this.slothlet.config?.dir}/${dir.name}`.replace(/\\/g, "/");
1472
-
1473
-
1474
-
1475
-
1476
-
1477
-
1478
- const parentPrefix = apiPath.includes(".") ? apiPath.split(".").slice(0, -1).join(".") : "";
1479
-
1480
-
1481
- const subDirs = dir.children.directories || [];
1482
- if (dir.children.files.length === 1 && subDirs.length === 0) {
1483
- const file = dir.children.files[0];
1484
- const moduleName = this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);
1485
- const genericFilenames = ["singlefile", "index", "main", "default"];
1486
- const isGeneric = genericFilenames.includes(moduleName.toLowerCase());
1487
- const filenameMatchesFolder = moduleName === categoryName;
1488
- if (isGeneric || filenameMatchesFolder) {
1489
- const mod = await this.slothlet.processors.loader.loadModule(file.path, this.slothlet.instanceID, moduleID, cacheBust);
1490
- const exports = this.slothlet.processors.loader.extractExports(mod);
1491
- const moduleKeys = Object.keys(exports).filter((k) => k !== "default");
1492
- const analysis = {
1493
- hasDefault: exports.default !== undefined,
1494
- hasNamed: moduleKeys.length > 0,
1495
- defaultExportType: exports.default ? typeof exports.default : null
1496
- };
1497
- const modContent = exports.default !== undefined ? exports.default : exports;
1498
- const categoryDecision = await this.slothlet.processors.flatten.buildCategoryDecisions({
1499
- categoryName,
1500
- mod: modContent,
1501
- moduleName,
1502
- fileBaseName: file.name,
1503
- analysis,
1504
- moduleKeys,
1505
- currentDepth: apiPath.split(".").length,
1506
- moduleFiles: dir.children.files,
1507
- t
1508
- });
1509
- if (categoryDecision.shouldFlatten) {
1510
- let implToWrap;
1511
-
1512
-
1513
-
1514
-
1515
- if (categoryDecision.flattenType === "addapi-metadata-default") {
1516
-
1517
- implToWrap = exports.default;
1518
- for (const key of moduleKeys) {
1519
-
1520
-
1521
- if (key !== "default") {
1522
- implToWrap[key] = exports[key];
1523
- }
1524
- }
1525
- } else if (moduleName === categoryName && moduleKeys.includes(categoryName)) {
1526
- implToWrap = exports[categoryName];
1527
- } else if (exports.default !== undefined) {
1528
- implToWrap = exports.default;
1529
-
1530
-
1531
-
1532
-
1533
-
1534
- if (moduleKeys.length > 0 && (typeof implToWrap === "function" || (typeof implToWrap === "object" && implToWrap !== null))) {
1535
- const collisionMode = this.slothlet.config?.collision?.initial || "merge";
1536
- for (const key of moduleKeys) {
1537
-
1538
-
1539
-
1540
-
1541
-
1542
- if (!this.slothlet.processors.flatten.shouldAttachNamedExport(key, exports[key], implToWrap, exports.default)) {
1543
- continue;
1544
- }
1545
-
1546
- const hasExisting = Object.prototype.hasOwnProperty.call(implToWrap, key);
1547
- if (hasExisting) {
1548
- if (collisionMode === "merge" || collisionMode === "skip") {
1549
-
1550
- continue;
1551
- } else if (collisionMode === "error") {
1552
- throw new this.slothlet.SlothletError(
1553
- "COLLISION_DEFAULT_EXPORT_ERROR",
1554
- {
1555
- key,
1556
- apiPath
1557
- },
1558
- null,
1559
- { validationError: true }
1560
- );
1561
- } else if (collisionMode === "warn") {
1562
- new this.slothlet.SlothletWarning("WARNING_COLLISION_DEFAULT_EXPORT_OVERWRITE", {
1563
- key,
1564
- apiPath
1565
- });
1566
- }
1567
-
1568
- }
1569
- implToWrap[key] = exports[key];
1570
- }
1571
- }
1572
-
1573
- } else {
1574
- implToWrap = modContent;
1575
- }
1576
-
1577
-
1578
-
1579
-
1580
-
1581
-
1582
-
1583
-
1584
-
1585
- if (implToWrap && typeof implToWrap === "object" && this.slothlet.handlers?.lifecycle) {
1586
- for (const key of Object.keys(implToWrap)) {
1587
- const value = implToWrap[key];
1588
- if (typeof value === "function") {
1589
- this.slothlet.handlers.lifecycle.emit("impl:created", {
1590
- apiPath: `${apiPath}.${key}`,
1591
- impl: value,
1592
- source: "lazy-materialization",
1593
- moduleID: moduleID,
1594
- filePath: file.path,
1595
-
1596
-
1597
- sourceFolder: sourceFolder || this.slothlet.config?.dir
1598
- });
1599
- }
1600
- }
1601
- }
1602
-
1603
-
1604
-
1605
- if (implToWrap && typeof implToWrap === "object") {
1606
-
1607
- const childPaths = {};
1608
- for (const key of Object.keys(implToWrap)) {
1609
- if (typeof key !== "symbol" && key !== "__childFilePaths" && key !== "__filePath") {
1610
- childPaths[key] = file.path;
1611
- }
1612
- }
1613
-
1614
-
1615
-
1616
-
1617
-
1618
-
1619
-
1620
- implToWrap.__childFilePaths = childPaths;
1621
- }
1622
-
1623
-
1624
- if (fileFolderCollisionImpl && typeof implToWrap === "object" && implToWrap !== null) {
1625
- for (const [k, v] of Object.entries(fileFolderCollisionImpl)) {
1626
- if (!(k in implToWrap)) {
1627
- implToWrap[k] = v;
1628
- }
1629
- }
1630
- } else if (fileFolderCollisionImpl && typeof implToWrap === "function") {
1631
- for (const [k, v] of Object.entries(fileFolderCollisionImpl)) {
1632
-
1633
-
1634
- if (implToWrap[k] === undefined) {
1635
- implToWrap[k] = v;
1636
- }
1637
- }
1638
- }
1639
-
1640
- return implToWrap;
1641
- }
1642
- }
1643
- }
1644
-
1645
-
1646
-
1647
- await this.processFiles(
1648
- materialized,
1649
- dir.children.files,
1650
- { name: dir.name, children: dir.children },
1651
- 0,
1652
- "eager",
1653
- false,
1654
- false,
1655
- true,
1656
- parentPrefix,
1657
- "initial",
1658
- moduleID,
1659
- actualSourceFolder,
1660
- cacheBust,
1661
- collisionMode
1662
- );
1663
- if (this.slothlet.config.debug?.modes) {
1664
- this.slothlet.debug("modes", {
1665
- key: "DEBUG_MODE_MATERIALIZE_FUNCTION_RETURNING_IMPL",
1666
- dir: dir.name,
1667
- keys: Object.keys(materialized)
1668
- });
1669
- }
1670
-
1671
-
1672
-
1673
- if (fileFolderCollisionImpl) {
1674
- for (const [k, v] of Object.entries(fileFolderCollisionImpl)) {
1675
-
1676
-
1677
- if (!(k in materialized)) {
1678
- materialized[k] = v;
1679
- }
1680
- }
1681
- }
1682
-
1683
- const materializedKeys = Object.keys(materialized);
1684
-
1685
-
1686
-
1687
-
1688
-
1689
-
1690
- const _hasCategoryFile = dir.children.files.some((f) => this.slothlet.helpers.sanitize.sanitizePropertyName(f.name) === categoryName);
1691
- if (_hasCategoryFile && materializedKeys.includes(categoryName) && materializedKeys.length > 1) {
1692
- if (this.slothlet.config.debug?.modes) {
1693
- this.slothlet.debug("modes", {
1694
- key: "DEBUG_MODE_FOLDER_PATTERN_MATCH",
1695
- dir: dir.name,
1696
- categoryName,
1697
- keys: materializedKeys
1698
- });
1699
- }
1700
- const mainValue = materialized[categoryName];
1701
-
1702
- for (const key of materializedKeys) {
1703
- if (key !== categoryName) {
1704
- if (this.slothlet.config.debug?.modes) {
1705
- this.slothlet.debug("modes", {
1706
- key: "DEBUG_MODE_FOLDER_PATTERN_ATTACH_PROPERTY",
1707
- categoryName,
1708
- propKey: key,
1709
- valueType: typeof materialized[key]
1710
- });
1711
- }
1712
- mainValue[key] = materialized[key];
1713
- }
1714
- }
1715
- if (this.slothlet.config.debug?.modes) {
1716
- this.slothlet.debug("modes", {
1717
- key: "DEBUG_MODE_FOLDER_PATTERN_RETURN",
1718
- categoryName,
1719
- keys: Object.keys(mainValue).filter((k) => !k.startsWith("__"))
1720
- });
1721
- }
1722
- return mainValue;
1723
- }
1724
- if (materializedKeys.length === 1 && materializedKeys[0] === categoryName) {
1725
- const nestedValue = materialized[categoryName];
1726
-
1727
-
1728
-
1729
-
1730
-
1731
- if (nestedValue && resolveWrapper(nestedValue) !== null) {
1732
- const attachedKeys = Object.keys(nestedValue).filter((key) => key !== "____slothletInternal");
1733
-
1734
-
1735
- if (attachedKeys.length > 0) {
1736
- return nestedValue;
1737
- }
1738
-
1739
- return nestedValue.__impl ?? nestedValue;
1740
-
1741
-
1742
-
1743
- } else {
1744
- return nestedValue;
1745
- }
1746
-
1747
- }
1748
-
1749
- return materialized;
1750
- });
1751
-
1752
- const wrapper = new UnifiedWrapper(this.slothlet, {
1753
- mode: "lazy",
1754
- apiPath,
1755
- materializeFunc: lazy_materializeFunc,
1756
- materializeOnCreate: this.slothlet.config.backgroundMaterialize,
1757
- filePath: dir.path,
1758
- moduleID: moduleID,
1759
- sourceFolder
1760
- });
1761
-
1762
-
1763
-
1764
-
1765
-
1766
- if (collisionMode) {
1767
- wrapper.____slothletInternal.state.collisionMode = collisionMode;
1768
- }
1769
-
1770
-
1771
-
1772
-
1773
-
1774
-
1775
-
1776
-
1777
-
1778
-
1779
- const shouldPrePopulate = collisionMode === "merge" || collisionMode === "warn";
1780
- if (fileFolderCollisionImpl && shouldPrePopulate) {
1781
- for (const [k, v] of Object.entries(fileFolderCollisionImpl)) {
1782
-
1783
-
1784
- if (typeof k === "string" && !k.startsWith("_") && !k.startsWith("__")) {
1785
- Object.defineProperty(wrapper, k, {
1786
- value: v,
1787
- writable: false,
1788
- enumerable: true,
1789
- configurable: true
1790
- });
1791
- }
1792
- }
1793
- }
1794
-
1795
- return wrapper.createProxy();
1796
- }
1797
-
1798
- async applyRootContributor(api, rootFunction, mode) {
1799
- if (rootFunction) {
1800
-
1801
-
1802
-
1803
-
1804
-
1805
-
1806
- Object.assign(rootFunction, api);
1807
- if (this.slothlet.config.debug?.modes) {
1808
- this.slothlet.debug("modes", {
1809
- message: await t("DEBUG_MODE_ROOT_CONTRIBUTOR_APPLIED", { mode, properties: Object.keys(api).length })
1810
- });
1811
- }
1812
- return rootFunction;
1813
- }
1814
- return api;
1815
- }
1816
- }
17
+ import{ComponentBase}from"@cldmv/slothlet/factories/component-base";import{t}from"@cldmv/slothlet/i18n";import{UnifiedWrapper,resolveWrapper}from"@cldmv/slothlet/handlers/unified-wrapper";import{getInstanceToken}from"@cldmv/slothlet/handlers/lifecycle-token";class ModesProcessor extends ComponentBase{static slothletProperty="modesProcessor";constructor(slothlet){super(slothlet)}async processFiles(api,files,directory,currentDepth,mode,isRoot,recursive,populateDirectly=false,apiPathPrefix="",collisionContext="initial",moduleID=null,sourceFolder=null,cacheBust=null,collisionModeOverride=null){const buildApiPath=path=>{if(!apiPathPrefix)return path;if(path.startsWith(`${apiPathPrefix}.`)){return path}return`${apiPathPrefix}.${path}`};let rootDefaultFunction=null;const rootContributors=[];const categoryName=isRoot&&!populateDirectly?null:this.slothlet.helpers.sanitize.sanitizePropertyName(directory.name);let targetApi=isRoot&&!populateDirectly?api:populateDirectly?api:api[categoryName]=api[categoryName]||{};const isRootFile=currentDepth===0&&!populateDirectly;const effectiveMode=mode==="lazy"&&isRootFile?"eager":mode;const shouldWrap=!(effectiveMode==="lazy"&&populateDirectly);if(!isRoot&&shouldWrap&&!populateDirectly){const existingTarget=api[categoryName];if(existingTarget&&resolveWrapper(existingTarget)){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_REUSE_EXISTING_WRAPPER",categoryName,apiPath:resolveWrapper(existingTarget)?.apiPath})}targetApi=existingTarget}else if(existingTarget===void 0||typeof existingTarget==="object"&&existingTarget!==null){const initialImpl=resolveWrapper(existingTarget)?{}:this.slothlet.helpers.modesUtils.cloneWrapperImpl(existingTarget||{},mode);if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_WRAPPER_CREATED",categoryName,apiPath:buildApiPath(categoryName)})}const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName),initialImpl,filePath:directory.path,moduleID:moduleID||categoryName,sourceFolder});api[categoryName]=wrapper.createProxy();if(this.slothlet.handlers?.metadata){this.slothlet.handlers.metadata.tagSystemMetadata(wrapper,{filePath:directory.path,apiPath:buildApiPath(categoryName),moduleID:moduleID||"base",sourceFolder:sourceFolder||directory.path},getInstanceToken(this.slothlet))}if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_WRAPPER_ASSIGNED",categoryName})}targetApi=api[categoryName];if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_CREATED",categoryName,apiPath:wrapper.apiPath});this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_TARGET_API_STATUS",isWrapper:!!resolveWrapper(targetApi),targetApiKeys:Object.keys(targetApi)})}}}if(!isRoot&&this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_PROCESSING_DIRECTORY",{mode,categoryName,currentDepth})})}const loadedModules=[];for(const file of files){if(this.slothlet.config.debug?.modes&&categoryName==="string"){this.slothlet.debug("modes",{key:"DEBUG_MODE_PROCESSING_FILE",categoryName,file:file.name,isRoot,populateDirectly,mode})}try{const mod=await this.slothlet.processors.loader.loadModule(file.path,this.slothlet.instanceID,moduleID,cacheBust);const exports=this.slothlet.processors.loader.extractExports(mod);const moduleName=this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);const moduleKeys=Object.keys(exports).filter(k=>k!=="default");const analysis={hasDefault:exports.default!==void 0,hasNamed:moduleKeys.length>0,defaultExportType:exports.default?typeof exports.default:null};loadedModules.push({file,mod:exports,moduleName,moduleKeys,analysis})}catch(error){if(error.name==="SlothletError")throw error;throw new this.SlothletError("MODULE_LOAD_FAILED",{modulePath:file.path,moduleID:moduleID||file.moduleID},error)}}const hasMultipleDefaults=loadedModules.filter(m=>m.analysis.hasDefault).length>1;for(const{file,mod,moduleName,moduleKeys,analysis}of loadedModules){if(this.slothlet.config.debug?.modes&&categoryName==="logger"){this.slothlet.debug("modes",{key:"DEBUG_MODE_PROCESSING_MODULE",categoryName,moduleName,hasDefault:analysis.hasDefault,moduleKeys,targetApiType:typeof targetApi,targetApiCallable:typeof targetApi==="function"})}const isAddapiFile=moduleName==="addapi"||file.name==="addapi"||file.fullName&&["addapi.mjs","addapi.cjs","addapi.js","addapi.ts"].includes(file.fullName.toLowerCase());const isAddapiObjectDefault=isAddapiFile&&analysis.hasDefault&&typeof mod.default!=="function";const isRootContributor=isRoot&&analysis.hasDefault&&typeof mod.default==="function"&&!isAddapiObjectDefault;if(moduleName==="config"||moduleKeys.some(k=>k.includes("Config")||k.includes("config"))){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FILE_PROCESSING",module:moduleName,category:categoryName||"(none)",isRoot,hasDefault:analysis.hasDefault,moduleKeys})}}if(isRootContributor){const defaultFunc=this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default,moduleName);for(const key of moduleKeys){if(!this.slothlet.processors.flatten.shouldAttachNamedExport(key,mod[key],defaultFunc,mod.default)){continue}defaultFunc[key]=mod[key]}rootContributors.push({moduleName,file,defaultFunc});continue}else{const decision=await this.slothlet.processors.flatten.getFlatteningDecision({mod,moduleName,categoryName:categoryName||moduleName,analysis,hasMultipleDefaults,moduleKeys,t});if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_MODULE_DECISION",{mode,moduleName,reason:decision.reason})})}const propertyName=decision.preferredName||moduleName;const effectiveCategoryName=categoryName||moduleName;let{moduleContent}=this.slothlet.processors.flatten.processModuleForAPI({mod,decision,moduleName,propertyName,moduleKeys,analysis,file,collisionContext,apiPathPrefix:apiPathPrefix||""});if(!isRoot&&!apiPathPrefix&&moduleName===categoryName){if(moduleKeys.length===1&&moduleKeys[0]===moduleName&&!analysis.hasDefault){const exportedValue=mod[moduleName];if(typeof exportedValue==="object"&&exportedValue!==null){if(this.slothlet.config.debug?.modes&&categoryName==="string"){this.slothlet.debug("modes",{key:"DEBUG_MODE_SINGLE_FILE_FOLDER_DETECTED",categoryName,populateDirectly,isRoot,mode,exportKeys:Object.keys(exportedValue)})}if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName),initialImpl:exportedValue,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});api[categoryName]=wrapper.createProxy();targetApi=api[categoryName]}else{this.slothlet.debug("modes",{key:"DEBUG_MODE_SINGLE_FILE_FOLDER_WRAPPED",categoryName,implKeys:Object.keys(exportedValue)})}for(const key of Object.keys(exportedValue)){if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}continue}}else if(analysis.hasDefault){const namedKeys=moduleKeys.length>0?moduleKeys:Object.keys(mod).filter(key=>key!=="default");const callableModule=typeof mod.default==="function"?this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default,categoryName):moduleContent;if(namedKeys.length>0){for(const key of namedKeys){if(key in callableModule){continue}if(!this.slothlet.processors.flatten.shouldAttachNamedExport(key,mod[key],callableModule,mod.default)){continue}callableModule[key]=mod[key]}}moduleContent=callableModule;if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(callableModule,mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});api[categoryName]=wrapper.createProxy();targetApi=api[categoryName]}else{api[categoryName]=moduleContent;targetApi=api[categoryName]}const needsSeparateNamedExports=typeof mod.default==="function";if(needsSeparateNamedExports&&namedKeys.length>0){for(const key of namedKeys){if(shouldWrap){const namedWrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${key}`),initialImpl:mod[key],materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,namedWrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:categoryName,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}continue}else if(moduleKeys.length>0){const hasMatchingObject=moduleKeys.some(key=>key===moduleName&&typeof mod[key]==="object"&&mod[key]!==null&&!Array.isArray(mod[key]));if(hasMatchingObject){const matchingObj=mod[moduleName];for(const[propKey,propValue]of Object.entries(matchingObj)){if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${propKey}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(propValue,mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propKey,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propKey,propValue,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${propKey}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}for(const key of moduleKeys){if(key!==moduleName){if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${key}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key],mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}}else{if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_FILE",moduleName,categoryName,exportCount:moduleKeys.length});this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_TARGET_STATUS",isWrapper:!!resolveWrapper(targetApi),keysBefore:Object.keys(targetApi)})}for(const key of moduleKeys){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_ASSIGNING",propKey:key})}if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${key}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key],mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});const assigned=this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext});if(assigned){this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_ASSIGNED",propKey:key,keysAfter:Object.keys(targetApi)})}else{this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_BLOCKED",propKey:key})}}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}continue}}if(!analysis.hasDefault&&moduleKeys.length===1&&!isRoot){const key=moduleKeys[0];const keyValue=mod[key];const isMatchingObject=key===moduleName&&typeof keyValue==="object"&&keyValue!==null&&!Array.isArray(keyValue);if(!isMatchingObject){const normalizedKey=key.toLowerCase().replace(/[-_]/g,"");const normalizedModuleName=moduleName.toLowerCase().replace(/[-_]/g,"");if(normalizedKey===normalizedModuleName){const preferredName=key;if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${preferredName}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key],mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,preferredName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,preferredName,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${preferredName}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}continue}}}if(decision.flattenToCategory&&moduleContent&&effectiveCategoryName){const isAddapiFile2=decision.flattenType==="addapi-metadata-default"||decision.flattenType==="addapi-special-file";if(isAddapiFile2&&typeof moduleContent==="object"&&!Array.isArray(moduleContent)&&typeof moduleContent!=="function"){for(const key of Object.keys(moduleContent)){const value=moduleContent[key];const keyPath=isRoot?key:`${apiPathPrefix?apiPathPrefix+".":""}${key}`;if(shouldWrap&&typeof value==="function"){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(keyPath),initialImpl:value,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,value,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}}if(this.slothlet.handlers.ownership){for(const key of Object.keys(moduleContent)){const apiPath=isRoot?key:apiPathPrefix?`${apiPathPrefix}.${key}`:key;this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}}}else{const localPath=isRoot?effectiveCategoryName:`${apiPathPrefix?apiPathPrefix+".":""}${effectiveCategoryName}`;if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(localPath),initialImpl:moduleContent,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder,isCallable:typeof moduleContent==="function"});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,effectiveCategoryName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,effectiveCategoryName,moduleContent,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){const apiPath=isRoot?effectiveCategoryName:apiPathPrefix?`${apiPathPrefix}.${effectiveCategoryName}`:effectiveCategoryName;this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}}continue}if(shouldWrap){const localPath=isRoot?propertyName:`${categoryName}.${propertyName}`;const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(localPath),initialImpl:moduleContent,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.debug("modes",{key:"DEBUG_MODE_FILE_WRAPPER_ASSIGNMENT",propertyName,apiPath:buildApiPath(localPath),overwriting:propertyName in targetApi?resolveWrapper(targetApi[propertyName])?"wrapper":"value":"nothing"});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propertyName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propertyName,moduleContent,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.config.debug?.modes&&categoryName==="logger"){this.slothlet.debug("modes",{key:"DEBUG_MODE_AFTER_ASSIGNMENT_STATUS",targetApiType:typeof targetApi,propertyName,hasProperty:propertyName in targetApi,implType:typeof resolveWrapper(targetApi)?.____slothletInternal.impl,implHasProperty:!!resolveWrapper(targetApi)?.____slothletInternal.impl?.utils})}if(this.slothlet.handlers.ownership){const apiPath=isRoot?propertyName:`${categoryName}.${propertyName}`;this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}}}if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_SUBDIRECTORY_CHECK",isRoot,categoryName,hasDirectory:!!directory,hasChildren:!!directory?.children,directoryCount:directory?.children?.directories?.length||0})}this.slothlet.debug("modes",{key:"DEBUG_MODE_DIRECTORY_CHECK",hasChildren:!!directory?.children,hasDirectories:!!directory?.children?.directories,length:directory?.children?.directories?.length||0});if(directory?.children?.directories){this.slothlet.debug("modes",{key:"DEBUG_MODE_DIRECTORY_CHECK_PASSED",recursive});if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_SUBDIRECTORIES_FOUND",subdirectoryCount:directory.children.directories.length,recursive})}if(recursive){this.slothlet.debug("modes",{key:"DEBUG_MODE_SUBDIRECTORY_LOOP_START",count:directory.children.directories.length});for(const subDir of directory.children.directories){this.slothlet.debug("modes",{key:"DEBUG_MODE_PROCESSING_SUBDIRECTORY",name:subDir.name,fileCount:subDir.children.files.length,subdirCount:subDir.children.directories.length});const subDirName=this.slothlet.helpers.sanitize.sanitizePropertyName(subDir.name);if(subDir.children.files.length===1&&subDir.children.directories.length===0){const file=subDir.children.files[0];const moduleName=this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);const genericFilenames=["singlefile","index","main","default"];const isGeneric=genericFilenames.includes(moduleName.toLowerCase());const filenameMatchesFolder=moduleName===subDirName;if(isGeneric||filenameMatchesFolder){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_LEVEL_FLATTEN_CHECK",subDir:subDirName,file:moduleName,isGeneric,filenameMatches:filenameMatchesFolder});const mod=await this.slothlet.processors.loader.loadModule(file.path,this.slothlet.instanceID,moduleID,cacheBust);const exports=this.slothlet.processors.loader.extractExports(mod);const moduleKeys=Object.keys(exports).filter(k=>k!=="default");const analysis={hasDefault:exports.default!==void 0,hasNamed:moduleKeys.length>0,defaultExportType:exports.default?typeof exports.default:null};const modContent=exports.default!==void 0?exports.default:exports;const categoryDecision=await this.slothlet.processors.flatten.buildCategoryDecisions({categoryName:subDirName,mod:modContent,moduleName,fileBaseName:file.name,analysis,moduleKeys,currentDepth:currentDepth+1,moduleFiles:subDir.children.files,t});if(categoryDecision.shouldFlatten){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_LEVEL_FLATTEN_SKIP_RECURSION",subDir:subDirName});let implToWrap;if(categoryDecision.flattenType==="addapi-metadata-default"){implToWrap={};for(const key of moduleKeys){if(key!=="default"){implToWrap[key]=exports[key]}}}else if(moduleName===subDirName&&moduleKeys.includes(subDirName)){implToWrap=exports[subDirName]}else if(exports.default!==void 0){implToWrap=exports.default;if(moduleKeys.length>0){if(typeof implToWrap==="function"){const collisionConfig=this.slothlet.config.api?.collision||this.slothlet.config.collision;const collisionMode=(collisionContext==="initial"?collisionConfig?.initial:collisionConfig?.api)||"merge";for(const key of moduleKeys){if(key!=="default"){const hasExisting=implToWrap[key]!==void 0;if(hasExisting){if(collisionMode==="merge"||collisionMode==="skip"){continue}else if(collisionMode==="error"){throw new this.slothlet.SlothletError("COLLISION_DEFAULT_EXPORT_ERROR",{key,apiPath:`${apiPathPrefix}.${subDirName}`},null,{validationError:true})}else if(collisionMode==="warn"){new this.slothlet.SlothletWarning("WARNING_COLLISION_DEFAULT_EXPORT_OVERWRITE",{key,apiPath:`${apiPathPrefix}.${subDirName}`})}}implToWrap[key]=exports[key]}}}else if(typeof implToWrap==="object"&&implToWrap!==null){for(const key of moduleKeys){if(key!=="default"&&!(key in implToWrap)){implToWrap[key]=exports[key]}}}}}else{implToWrap=modContent}const modes_eagerCollisionConfig=this.slothlet.config.api?.collision||this.slothlet.config.collision;const modes_eagerCollisionMode=(collisionContext==="initial"?modes_eagerCollisionConfig?.initial:modes_eagerCollisionConfig?.api)||"merge";const modes_existingAtKey=targetApi[subDirName];if(modes_existingAtKey!==void 0&&modes_eagerCollisionMode!=="replace"&&modes_eagerCollisionMode!=="skip"){const modes_existingWrapper=resolveWrapper(modes_existingAtKey);if(modes_existingWrapper){if(modes_existingWrapper.____slothletInternal?.materializeFunc&&!modes_existingWrapper.____slothletInternal?.state?.materialized){await modes_existingWrapper._materialize()}if(modes_existingWrapper.____slothletInternal?.impl&&!modes_existingWrapper.____slothletInternal?.state?.childrenAdopted){modes_existingWrapper.___adoptImplChildren()}const modes_existingImpl=modes_existingWrapper.__impl;if(modes_existingImpl&&typeof modes_existingImpl==="object"&&!Array.isArray(modes_existingImpl)){if(typeof implToWrap==="object"&&implToWrap!==null){for(const[k,v]of Object.entries(modes_existingImpl)){if(!(k in implToWrap)){implToWrap[k]=v}}}else if(typeof implToWrap==="function"){for(const[k,v]of Object.entries(modes_existingImpl)){if(implToWrap[k]===void 0){implToWrap[k]=v}}}}const modes_existingChildKeys=Object.keys(modes_existingWrapper).filter(k=>!k.startsWith("_")&&!k.startsWith("__"));for(const ck of modes_existingChildKeys){if(typeof implToWrap==="object"&&implToWrap!==null&&!(ck in implToWrap)){implToWrap[ck]=modes_existingWrapper[ck]}else if(typeof implToWrap==="function"&&implToWrap[ck]===void 0){implToWrap[ck]=modes_existingWrapper[ck]}}this.slothlet.debug("modes",{key:"DEBUG_MODE_FILE_FOLDER_COLLISION_MERGED",subDir:subDirName,mergedKeys:Object.keys(implToWrap)})}}const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName?`${categoryName}.${subDirName}`:subDirName),initialImpl:implToWrap,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,subDirName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext});if(this.slothlet.handlers.ownership){const apiPath=buildApiPath(categoryName?`${categoryName}.${subDirName}`:subDirName);this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}continue}}}const currentCategoryName=apiPathPrefix?apiPathPrefix.split(".").pop():categoryName;if(subDirName===currentCategoryName&&currentCategoryName!==null){await this.processFiles(targetApi,subDir.children.files,subDir,currentDepth+1,mode,false,recursive,true,apiPathPrefix,collisionContext,moduleID,sourceFolder,cacheBust);continue}await this.processFiles(targetApi,subDir.children.files,{name:subDirName,path:subDir.path,children:subDir.children},currentDepth+1,mode,false,recursive,false,apiPathPrefix,collisionContext,moduleID,sourceFolder,cacheBust)}}else{for(const subDir of directory.children.directories){const subDirName=this.slothlet.helpers.sanitize.sanitizePropertyName(subDir.name);const lazy_currentCategoryName=apiPathPrefix?apiPathPrefix.split(".").pop():categoryName;if(subDirName===lazy_currentCategoryName&&lazy_currentCategoryName!==null&&!populateDirectly){await this.processFiles(targetApi,subDir.children.files,subDir,currentDepth+1,"eager",false,true,true,apiPathPrefix,collisionContext,moduleID,sourceFolder,cacheBust);continue}const apiPath=categoryName?`${categoryName}.${subDirName}`:apiPathPrefix?`${apiPathPrefix}.${subDirName}`:subDirName;if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CREATING_LAZY_SUBDIRECTORY",apiPath,fileCount:subDir.children.files.length})}const collisionConfig=this.slothlet.config.api?.collision;const modes_initialCollisionMode=collisionModeOverride||(collisionContext==="initial"?collisionConfig?.initial:collisionConfig?.api)||"replace";let modes_fileFolderImpl=null;const modes_lazyExisting=targetApi[subDirName];if(modes_initialCollisionMode!=="replace"&&resolveWrapper(modes_lazyExisting)){const modes_lazyExistingW=resolveWrapper(modes_lazyExisting);const existImpl=modes_lazyExistingW.__impl;if(existImpl&&typeof existImpl==="object"&&!Array.isArray(existImpl)){modes_fileFolderImpl={...existImpl}}const existChildKeys=Object.keys(modes_lazyExistingW).filter(k=>!k.startsWith("_")&&!k.startsWith("__"));for(const ck of existChildKeys){if(!modes_fileFolderImpl)modes_fileFolderImpl={};if(!(ck in modes_fileFolderImpl)){modes_fileFolderImpl[ck]=modes_lazyExistingW[ck]}}}this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,subDirName,this.createLazySubdirectoryWrapper(subDir,apiPath,moduleID,sourceFolder,cacheBust,modes_fileFolderImpl,modes_initialCollisionMode),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}}}if(isRoot&&rootContributors.length>0){if(rootContributors.length===1){const{moduleName,file,defaultFunc}=rootContributors[0];rootDefaultFunction=defaultFunc;if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_ROOT_CONTRIBUTOR",{mode,functionName:defaultFunc.name||"anonymous"})})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:moduleName,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}else{new this.SlothletWarning("WARNING_MULTIPLE_ROOT_CONTRIBUTORS",{rootContributors:rootContributors.map(rc=>rc.moduleName).join(", "),firstContributor:rootContributors[0].moduleName});for(const{moduleName,file,defaultFunc}of rootContributors){if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(moduleName),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(defaultFunc,mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,moduleName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,moduleName,defaultFunc,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:moduleName,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}}return rootDefaultFunction}createLazySubdirectoryWrapper(dir,apiPath,moduleID=null,sourceFolder=null,cacheBust=null,fileFolderCollisionImpl=null,collisionMode="merge"){const lazy_materializeFunc=this.slothlet.modes.lazy.createNamedMaterializeFunc(apiPath,async()=>{if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_MATERIALIZE_FUNCTION_STARTING",dir:dir.name,fileCount:dir.children.files?.length||0})}const categoryName=this.slothlet.helpers.sanitize.sanitizePropertyName(dir.name);const materialized={};const actualSourceFolder=sourceFolder?`${sourceFolder}/${dir.name}`.replace(/\\/g,"/"):`${this.slothlet.config?.dir}/${dir.name}`.replace(/\\/g,"/");const parentPrefix=apiPath.includes(".")?apiPath.split(".").slice(0,-1).join("."):"";const subDirs=dir.children.directories||[];if(dir.children.files.length===1&&subDirs.length===0){const file=dir.children.files[0];const moduleName=this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);const genericFilenames=["singlefile","index","main","default"];const isGeneric=genericFilenames.includes(moduleName.toLowerCase());const filenameMatchesFolder=moduleName===categoryName;if(isGeneric||filenameMatchesFolder){const mod=await this.slothlet.processors.loader.loadModule(file.path,this.slothlet.instanceID,moduleID,cacheBust);const exports=this.slothlet.processors.loader.extractExports(mod);const moduleKeys=Object.keys(exports).filter(k=>k!=="default");const analysis={hasDefault:exports.default!==void 0,hasNamed:moduleKeys.length>0,defaultExportType:exports.default?typeof exports.default:null};const modContent=exports.default!==void 0?exports.default:exports;const categoryDecision=await this.slothlet.processors.flatten.buildCategoryDecisions({categoryName,mod:modContent,moduleName,fileBaseName:file.name,analysis,moduleKeys,currentDepth:apiPath.split(".").length,moduleFiles:dir.children.files,t});if(categoryDecision.shouldFlatten){let implToWrap;if(categoryDecision.flattenType==="addapi-metadata-default"){implToWrap=exports.default;for(const key of moduleKeys){if(key!=="default"){implToWrap[key]=exports[key]}}}else if(moduleName===categoryName&&moduleKeys.includes(categoryName)){implToWrap=exports[categoryName]}else if(exports.default!==void 0){implToWrap=exports.default;if(moduleKeys.length>0&&(typeof implToWrap==="function"||typeof implToWrap==="object"&&implToWrap!==null)){const collisionMode2=this.slothlet.config?.collision?.initial||"merge";for(const key of moduleKeys){if(!this.slothlet.processors.flatten.shouldAttachNamedExport(key,exports[key],implToWrap,exports.default)){continue}const hasExisting=Object.prototype.hasOwnProperty.call(implToWrap,key);if(hasExisting){if(collisionMode2==="merge"||collisionMode2==="skip"){continue}else if(collisionMode2==="error"){throw new this.slothlet.SlothletError("COLLISION_DEFAULT_EXPORT_ERROR",{key,apiPath},null,{validationError:true})}else if(collisionMode2==="warn"){new this.slothlet.SlothletWarning("WARNING_COLLISION_DEFAULT_EXPORT_OVERWRITE",{key,apiPath})}}implToWrap[key]=exports[key]}}}else{implToWrap=modContent}if(implToWrap&&typeof implToWrap==="object"&&this.slothlet.handlers?.lifecycle){for(const key of Object.keys(implToWrap)){const value=implToWrap[key];if(typeof value==="function"){this.slothlet.handlers.lifecycle.emit("impl:created",{apiPath:`${apiPath}.${key}`,impl:value,source:"lazy-materialization",moduleID,filePath:file.path,sourceFolder:sourceFolder||this.slothlet.config?.dir})}}}if(implToWrap&&typeof implToWrap==="object"){const childPaths={};for(const key of Object.keys(implToWrap)){if(typeof key!=="symbol"&&key!=="__childFilePaths"&&key!=="__filePath"){childPaths[key]=file.path}}implToWrap.__childFilePaths=childPaths}if(fileFolderCollisionImpl&&typeof implToWrap==="object"&&implToWrap!==null){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(!(k in implToWrap)){implToWrap[k]=v}}}else if(fileFolderCollisionImpl&&typeof implToWrap==="function"){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(implToWrap[k]===void 0){implToWrap[k]=v}}}return implToWrap}}}await this.processFiles(materialized,dir.children.files,{name:dir.name,children:dir.children},0,"eager",false,false,true,parentPrefix,"initial",moduleID,actualSourceFolder,cacheBust,collisionMode);if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_MATERIALIZE_FUNCTION_RETURNING_IMPL",dir:dir.name,keys:Object.keys(materialized)})}if(fileFolderCollisionImpl){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(!(k in materialized)){materialized[k]=v}}}const materializedKeys=Object.keys(materialized);const _hasCategoryFile=dir.children.files.some(f=>this.slothlet.helpers.sanitize.sanitizePropertyName(f.name)===categoryName);if(_hasCategoryFile&&materializedKeys.includes(categoryName)&&materializedKeys.length>1){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_PATTERN_MATCH",dir:dir.name,categoryName,keys:materializedKeys})}const mainValue=materialized[categoryName];for(const key of materializedKeys){if(key!==categoryName){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_PATTERN_ATTACH_PROPERTY",categoryName,propKey:key,valueType:typeof materialized[key]})}mainValue[key]=materialized[key]}}if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_PATTERN_RETURN",categoryName,keys:Object.keys(mainValue).filter(k=>!k.startsWith("__"))})}return mainValue}if(materializedKeys.length===1&&materializedKeys[0]===categoryName){const nestedValue=materialized[categoryName];if(nestedValue&&resolveWrapper(nestedValue)!==null){const attachedKeys=Object.keys(nestedValue).filter(key=>key!=="____slothletInternal");if(attachedKeys.length>0){return nestedValue}return nestedValue.__impl??nestedValue}else{return nestedValue}}return materialized});const wrapper=new UnifiedWrapper(this.slothlet,{mode:"lazy",apiPath,materializeFunc:lazy_materializeFunc,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:dir.path,moduleID,sourceFolder});if(collisionMode){wrapper.____slothletInternal.state.collisionMode=collisionMode}const shouldPrePopulate=collisionMode==="merge"||collisionMode==="warn";if(fileFolderCollisionImpl&&shouldPrePopulate){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(typeof k==="string"&&!k.startsWith("_")&&!k.startsWith("__")){Object.defineProperty(wrapper,k,{value:v,writable:false,enumerable:true,configurable:true})}}}return wrapper.createProxy()}async applyRootContributor(api,rootFunction,mode){if(rootFunction){Object.assign(rootFunction,api);if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_ROOT_CONTRIBUTOR_APPLIED",{mode,properties:Object.keys(api).length})})}return rootFunction}return api}}export{ModesProcessor};