@cldmv/slothlet 2.11.0 → 3.0.1

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 (189) hide show
  1. package/AGENT-USAGE.md +355 -325
  2. package/README.md +554 -238
  3. package/dist/lib/builders/api-assignment.mjs +605 -0
  4. package/dist/lib/builders/api_builder.mjs +1073 -0
  5. package/dist/lib/builders/builder.mjs +94 -0
  6. package/dist/lib/builders/modes-processor.mjs +1816 -0
  7. package/dist/lib/errors.mjs +227 -0
  8. package/dist/lib/factories/component-base.mjs +96 -0
  9. package/dist/lib/factories/context.mjs +38 -0
  10. package/dist/lib/handlers/api-cache-manager.mjs +216 -0
  11. package/dist/lib/handlers/api-manager.mjs +2364 -0
  12. package/dist/lib/handlers/context-async.mjs +184 -0
  13. package/dist/lib/handlers/context-live.mjs +184 -0
  14. package/dist/lib/handlers/hook-manager.mjs +789 -0
  15. package/dist/lib/handlers/lifecycle-token.mjs +44 -0
  16. package/dist/lib/handlers/lifecycle.mjs +131 -0
  17. package/dist/lib/handlers/materialize-manager.mjs +64 -0
  18. package/dist/lib/handlers/metadata.mjs +500 -0
  19. package/dist/lib/handlers/ownership.mjs +338 -0
  20. package/dist/lib/handlers/unified-wrapper.mjs +3031 -0
  21. package/dist/lib/helpers/class-instance-wrapper.mjs +125 -0
  22. package/dist/lib/helpers/config.mjs +343 -0
  23. package/dist/lib/helpers/eventemitter-context.mjs +365 -0
  24. package/dist/lib/helpers/hint-detector.mjs +63 -0
  25. package/dist/lib/helpers/modes-utils.mjs +53 -0
  26. package/dist/lib/helpers/resolve-from-caller.mjs +123 -117
  27. package/dist/lib/helpers/sanitize.mjs +247 -168
  28. package/dist/lib/helpers/utilities.mjs +46 -81
  29. package/dist/lib/i18n/languages/de-de.json +377 -0
  30. package/dist/lib/i18n/languages/en-gb.json +377 -0
  31. package/dist/lib/i18n/languages/en-us.json +377 -0
  32. package/dist/lib/i18n/languages/es-mx.json +377 -0
  33. package/dist/lib/i18n/languages/fr-fr.json +377 -0
  34. package/dist/lib/i18n/languages/hi-in.json +377 -0
  35. package/dist/lib/i18n/languages/ja-jp.json +377 -0
  36. package/dist/lib/i18n/languages/ko-kr.json +377 -0
  37. package/dist/lib/i18n/languages/pt-br.json +377 -0
  38. package/dist/lib/i18n/languages/ru-ru.json +377 -0
  39. package/dist/lib/i18n/languages/zh-cn.json +377 -0
  40. package/dist/lib/i18n/translations.mjs +140 -0
  41. package/dist/lib/modes/eager.mjs +75 -0
  42. package/dist/lib/modes/lazy.mjs +97 -0
  43. package/dist/lib/processors/flatten.mjs +453 -0
  44. package/dist/lib/processors/loader.mjs +355 -0
  45. package/dist/lib/processors/type-generator.mjs +291 -0
  46. package/dist/lib/processors/typescript.mjs +188 -0
  47. package/dist/lib/runtime/runtime-asynclocalstorage.mjs +80 -522
  48. package/dist/lib/runtime/runtime-livebindings.mjs +45 -390
  49. package/dist/lib/runtime/runtime.mjs +39 -159
  50. package/dist/slothlet.mjs +525 -744
  51. package/docs/API-RULES.md +338 -486
  52. package/index.cjs +4 -4
  53. package/index.mjs +82 -45
  54. package/package.json +143 -30
  55. package/types/dist/lib/builders/api-assignment.d.mts +97 -0
  56. package/types/dist/lib/builders/api-assignment.d.mts.map +1 -0
  57. package/types/dist/lib/builders/api_builder.d.mts +96 -0
  58. package/types/dist/lib/builders/api_builder.d.mts.map +1 -0
  59. package/types/dist/lib/builders/builder.d.mts +60 -0
  60. package/types/dist/lib/builders/builder.d.mts.map +1 -0
  61. package/types/dist/lib/builders/modes-processor.d.mts +32 -0
  62. package/types/dist/lib/builders/modes-processor.d.mts.map +1 -0
  63. package/types/dist/lib/errors.d.mts +118 -0
  64. package/types/dist/lib/errors.d.mts.map +1 -0
  65. package/types/dist/lib/factories/component-base.d.mts +182 -0
  66. package/types/dist/lib/factories/component-base.d.mts.map +1 -0
  67. package/types/dist/lib/factories/context.d.mts +26 -0
  68. package/types/dist/lib/factories/context.d.mts.map +1 -0
  69. package/types/dist/lib/handlers/api-cache-manager.d.mts +208 -0
  70. package/types/dist/lib/handlers/api-cache-manager.d.mts.map +1 -0
  71. package/types/dist/lib/handlers/api-manager.d.mts +392 -0
  72. package/types/dist/lib/handlers/api-manager.d.mts.map +1 -0
  73. package/types/dist/lib/handlers/context-async.d.mts +66 -0
  74. package/types/dist/lib/handlers/context-async.d.mts.map +1 -0
  75. package/types/dist/lib/handlers/context-live.d.mts +65 -0
  76. package/types/dist/lib/handlers/context-live.d.mts.map +1 -0
  77. package/types/dist/lib/handlers/hook-manager.d.mts +199 -0
  78. package/types/dist/lib/handlers/hook-manager.d.mts.map +1 -0
  79. package/types/dist/lib/handlers/lifecycle-token.d.mts +49 -0
  80. package/types/dist/lib/handlers/lifecycle-token.d.mts.map +1 -0
  81. package/types/dist/lib/handlers/lifecycle.d.mts +90 -0
  82. package/types/dist/lib/handlers/lifecycle.d.mts.map +1 -0
  83. package/types/dist/lib/handlers/materialize-manager.d.mts +75 -0
  84. package/types/dist/lib/handlers/materialize-manager.d.mts.map +1 -0
  85. package/types/dist/lib/handlers/metadata.d.mts +215 -0
  86. package/types/dist/lib/handlers/metadata.d.mts.map +1 -0
  87. package/types/dist/lib/handlers/ownership.d.mts +170 -0
  88. package/types/dist/lib/handlers/ownership.d.mts.map +1 -0
  89. package/types/dist/lib/handlers/unified-wrapper.d.mts +250 -0
  90. package/types/dist/lib/handlers/unified-wrapper.d.mts.map +1 -0
  91. package/types/dist/lib/helpers/class-instance-wrapper.d.mts +54 -0
  92. package/types/dist/lib/helpers/class-instance-wrapper.d.mts.map +1 -0
  93. package/types/dist/lib/helpers/config.d.mts +96 -0
  94. package/types/dist/lib/helpers/config.d.mts.map +1 -0
  95. package/types/dist/lib/helpers/eventemitter-context.d.mts +31 -0
  96. package/types/dist/lib/helpers/eventemitter-context.d.mts.map +1 -0
  97. package/types/dist/lib/helpers/hint-detector.d.mts +20 -0
  98. package/types/dist/lib/helpers/hint-detector.d.mts.map +1 -0
  99. package/types/dist/lib/helpers/modes-utils.d.mts +35 -0
  100. package/types/dist/lib/helpers/modes-utils.d.mts.map +1 -0
  101. package/types/dist/lib/helpers/resolve-from-caller.d.mts +29 -145
  102. package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -1
  103. package/types/dist/lib/helpers/sanitize.d.mts +95 -94
  104. package/types/dist/lib/helpers/sanitize.d.mts.map +1 -1
  105. package/types/dist/lib/helpers/utilities.d.mts +53 -116
  106. package/types/dist/lib/helpers/utilities.d.mts.map +1 -1
  107. package/types/dist/lib/i18n/translations.d.mts +39 -0
  108. package/types/dist/lib/i18n/translations.d.mts.map +1 -0
  109. package/types/dist/lib/modes/eager.d.mts +36 -0
  110. package/types/dist/lib/modes/eager.d.mts.map +1 -0
  111. package/types/dist/lib/modes/lazy.d.mts +49 -0
  112. package/types/dist/lib/modes/lazy.d.mts.map +1 -0
  113. package/types/dist/lib/processors/flatten.d.mts +114 -0
  114. package/types/dist/lib/processors/flatten.d.mts.map +1 -0
  115. package/types/dist/lib/processors/loader.d.mts +47 -0
  116. package/types/dist/lib/processors/loader.d.mts.map +1 -0
  117. package/types/dist/lib/processors/type-generator.d.mts +19 -0
  118. package/types/dist/lib/processors/type-generator.d.mts.map +1 -0
  119. package/types/dist/lib/processors/typescript.d.mts +55 -0
  120. package/types/dist/lib/processors/typescript.d.mts.map +1 -0
  121. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +47 -42
  122. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
  123. package/types/dist/lib/runtime/runtime-livebindings.d.mts +34 -65
  124. package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
  125. package/types/dist/lib/runtime/runtime.d.mts +39 -9
  126. package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
  127. package/types/dist/slothlet.d.mts +184 -111
  128. package/types/dist/slothlet.d.mts.map +1 -1
  129. package/types/index.d.mts +1 -3
  130. package/dist/lib/engine/README.md +0 -21
  131. package/dist/lib/engine/slothlet_child.mjs +0 -59
  132. package/dist/lib/engine/slothlet_engine.mjs +0 -372
  133. package/dist/lib/engine/slothlet_esm.mjs +0 -230
  134. package/dist/lib/engine/slothlet_helpers.mjs +0 -455
  135. package/dist/lib/engine/slothlet_worker.mjs +0 -149
  136. package/dist/lib/helpers/als-eventemitter.mjs +0 -256
  137. package/dist/lib/helpers/api_builder/add_api.mjs +0 -553
  138. package/dist/lib/helpers/api_builder/analysis.mjs +0 -532
  139. package/dist/lib/helpers/api_builder/construction.mjs +0 -495
  140. package/dist/lib/helpers/api_builder/decisions.mjs +0 -748
  141. package/dist/lib/helpers/api_builder/metadata.mjs +0 -248
  142. package/dist/lib/helpers/api_builder.mjs +0 -41
  143. package/dist/lib/helpers/auto-wrap.mjs +0 -62
  144. package/dist/lib/helpers/hooks.mjs +0 -389
  145. package/dist/lib/helpers/instance-manager.mjs +0 -111
  146. package/dist/lib/helpers/metadata-api.mjs +0 -201
  147. package/dist/lib/helpers/multidefault.mjs +0 -216
  148. package/dist/lib/modes/slothlet_eager.mjs +0 -154
  149. package/dist/lib/modes/slothlet_lazy.mjs +0 -594
  150. package/docs/API-RULES-CONDITIONS.md +0 -712
  151. package/types/dist/lib/engine/slothlet_child.d.mts +0 -2
  152. package/types/dist/lib/engine/slothlet_child.d.mts.map +0 -1
  153. package/types/dist/lib/engine/slothlet_engine.d.mts +0 -31
  154. package/types/dist/lib/engine/slothlet_engine.d.mts.map +0 -1
  155. package/types/dist/lib/engine/slothlet_esm.d.mts +0 -19
  156. package/types/dist/lib/engine/slothlet_esm.d.mts.map +0 -1
  157. package/types/dist/lib/engine/slothlet_helpers.d.mts +0 -25
  158. package/types/dist/lib/engine/slothlet_helpers.d.mts.map +0 -1
  159. package/types/dist/lib/engine/slothlet_worker.d.mts +0 -2
  160. package/types/dist/lib/engine/slothlet_worker.d.mts.map +0 -1
  161. package/types/dist/lib/helpers/als-eventemitter.d.mts +0 -56
  162. package/types/dist/lib/helpers/als-eventemitter.d.mts.map +0 -1
  163. package/types/dist/lib/helpers/api_builder/add_api.d.mts +0 -102
  164. package/types/dist/lib/helpers/api_builder/add_api.d.mts.map +0 -1
  165. package/types/dist/lib/helpers/api_builder/analysis.d.mts +0 -189
  166. package/types/dist/lib/helpers/api_builder/analysis.d.mts.map +0 -1
  167. package/types/dist/lib/helpers/api_builder/construction.d.mts +0 -107
  168. package/types/dist/lib/helpers/api_builder/construction.d.mts.map +0 -1
  169. package/types/dist/lib/helpers/api_builder/decisions.d.mts +0 -213
  170. package/types/dist/lib/helpers/api_builder/decisions.d.mts.map +0 -1
  171. package/types/dist/lib/helpers/api_builder/metadata.d.mts +0 -99
  172. package/types/dist/lib/helpers/api_builder/metadata.d.mts.map +0 -1
  173. package/types/dist/lib/helpers/api_builder.d.mts +0 -6
  174. package/types/dist/lib/helpers/api_builder.d.mts.map +0 -1
  175. package/types/dist/lib/helpers/auto-wrap.d.mts +0 -49
  176. package/types/dist/lib/helpers/auto-wrap.d.mts.map +0 -1
  177. package/types/dist/lib/helpers/hooks.d.mts +0 -342
  178. package/types/dist/lib/helpers/hooks.d.mts.map +0 -1
  179. package/types/dist/lib/helpers/instance-manager.d.mts +0 -41
  180. package/types/dist/lib/helpers/instance-manager.d.mts.map +0 -1
  181. package/types/dist/lib/helpers/metadata-api.d.mts +0 -132
  182. package/types/dist/lib/helpers/metadata-api.d.mts.map +0 -1
  183. package/types/dist/lib/helpers/multidefault.d.mts +0 -90
  184. package/types/dist/lib/helpers/multidefault.d.mts.map +0 -1
  185. package/types/dist/lib/modes/slothlet_eager.d.mts +0 -65
  186. package/types/dist/lib/modes/slothlet_eager.d.mts.map +0 -1
  187. package/types/dist/lib/modes/slothlet_lazy.d.mts +0 -31
  188. package/types/dist/lib/modes/slothlet_lazy.d.mts.map +0 -1
  189. package/types/index.d.mts.map +0 -1
@@ -0,0 +1,1816 @@
1
+ /*
2
+ Copyright 2026 CLDMV/Shinrai
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+
18
+
19
+
20
+ 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
+ }