@cldmv/slothlet 2.4.3 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cldmv/slothlet",
3
- "version": "2.4.3",
3
+ "version": "2.5.0",
4
4
  "moduleVersions": {
5
5
  "lazy": "1.3.0",
6
6
  "eager": "1.3.0"
@@ -53,6 +53,7 @@
53
53
  },
54
54
  "types": "./types/index.d.mts",
55
55
  "scripts": {
56
+ "precommit": "node tools/precommit-validation.mjs",
56
57
  "publish:manual": "npm publish --access public",
57
58
  "test": "node tests/test-conditional.mjs",
58
59
  "test:pre-build": "node tests/test-conditional.mjs",
@@ -0,0 +1,446 @@
1
+ /**
2
+ * Analyzes a module and returns processing decisions that both eager and lazy modes can use.
3
+ * This centralizes the module loading logic from _loadSingleModule while allowing each mode
4
+ * to handle the results according to their strategy (immediate materialization vs proxy creation).
5
+ * @function analyzeModule
6
+ * @internal
7
+ * @package
8
+ * @param {string} modulePath - Absolute path to the module file
9
+ * @param {object} options - Analysis options
10
+ * @param {boolean} [options.debug=false] - Enable debug logging
11
+ * @param {object} [options.instance] - Slothlet instance for accessing config and methods
12
+ * @returns {Promise<{
13
+ * rawModule: object,
14
+ * processedModule: object,
15
+ * isFunction: boolean,
16
+ * hasDefault: boolean,
17
+ * isCjs: boolean,
18
+ * exports: Array<[string, any]>,
19
+ * defaultExportType: 'function'|'object'|null,
20
+ * shouldWrapAsCallable: boolean,
21
+ * namedExports: object,
22
+ * metadata: object
23
+ * }>} Module analysis results
24
+ * @example
25
+ * // Analyze a module file
26
+ * const analysis = await analyzeModule("./api/math.mjs", { instance });
27
+ * // Eager mode: use analysis.processedModule directly
28
+ * // Lazy mode: create proxy based on analysis.isFunction, analysis.exports, etc.
29
+ */
30
+ export function analyzeModule(modulePath: string, options?: {
31
+ debug?: boolean;
32
+ instance?: object;
33
+ }): Promise<{
34
+ rawModule: object;
35
+ processedModule: object;
36
+ isFunction: boolean;
37
+ hasDefault: boolean;
38
+ isCjs: boolean;
39
+ exports: Array<[string, any]>;
40
+ defaultExportType: "function" | "object" | null;
41
+ shouldWrapAsCallable: boolean;
42
+ namedExports: object;
43
+ metadata: object;
44
+ }>;
45
+ /**
46
+ * Processes module analysis results into a final module object using slothlet's established patterns.
47
+ * This centralizes the processing logic while allowing both modes to apply the results differently.
48
+ * @function processModuleFromAnalysis
49
+ * @internal
50
+ * @package
51
+ * @param {object} analysis - Results from analyzeModule
52
+ * @param {object} options - Processing options
53
+ * @param {object} [options.instance] - Slothlet instance for accessing _toapiPathKey method
54
+ * @param {boolean} [options.debug=false] - Enable debug logging
55
+ * @returns {object} Processed module ready for API integration
56
+ * @example
57
+ * // Process analyzed module
58
+ * const analysis = await analyzeModule(modulePath, { instance });
59
+ * const processed = processModuleFromAnalysis(analysis, { instance });
60
+ * // Both modes can use 'processed' but integrate it differently
61
+ */
62
+ export function processModuleFromAnalysis(analysis: object, options?: {
63
+ instance?: object;
64
+ debug?: boolean;
65
+ }): object;
66
+ /**
67
+ * Analyzes a directory and returns structural decisions that both eager and lazy modes can use.
68
+ * This provides the decision-making logic for directory handling without implementing the actual
69
+ * loading strategy (allowing lazy mode to create proxies while eager mode materializes).
70
+ * @function analyzeDirectoryStructure
71
+ * @internal
72
+ * @package
73
+ * @param {string} categoryPath - Absolute path to the directory
74
+ * @param {object} options - Analysis options
75
+ * @param {object} options.instance - Slothlet instance for accessing config and methods
76
+ * @param {number} [options.currentDepth=0] - Current traversal depth
77
+ * @param {number} [options.maxDepth=Infinity] - Maximum traversal depth
78
+ * @param {boolean} [options.debug=false] - Enable debug logging
79
+ * @returns {Promise<{
80
+ * isSingleFile: boolean,
81
+ * shouldAutoFlatten: boolean,
82
+ * categoryName: string,
83
+ * moduleFiles: Array<import('fs').Dirent>,
84
+ * subDirs: Array<import('fs').Dirent>,
85
+ * multiDefaultAnalysis: object,
86
+ * processingStrategy: 'single-file'|'multi-file'|'empty',
87
+ * flatteningHints: object
88
+ * }>} Directory structure analysis
89
+ * @example
90
+ * // Analyze directory structure
91
+ * const analysis = await analyzeDirectoryStructure(categoryPath, { instance });
92
+ * if (analysis.isSingleFile) {
93
+ * // Both modes: handle as single file (but differently)
94
+ * } else {
95
+ * // Both modes: handle as multi-file (but differently)
96
+ * }
97
+ */
98
+ export function analyzeDirectoryStructure(categoryPath: string, options?: {
99
+ instance: object;
100
+ currentDepth?: number;
101
+ maxDepth?: number;
102
+ debug?: boolean;
103
+ }): Promise<{
104
+ isSingleFile: boolean;
105
+ shouldAutoFlatten: boolean;
106
+ categoryName: string;
107
+ moduleFiles: Array<import("fs").Dirent>;
108
+ subDirs: Array<import("fs").Dirent>;
109
+ multiDefaultAnalysis: object;
110
+ processingStrategy: "single-file" | "multi-file" | "empty";
111
+ flatteningHints: object;
112
+ }>;
113
+ /**
114
+ * Returns category building decisions and processed modules that both eager and lazy modes can use.
115
+ * This provides all the structural information needed to build a category but lets each mode
116
+ * implement the actual building strategy (materialization vs proxy creation).
117
+ * @function getCategoryBuildingDecisions
118
+ * @internal
119
+ * @package
120
+ * @param {string} categoryPath - Absolute path to the directory
121
+ * @param {object} options - Building options
122
+ * @param {object} options.instance - Slothlet instance for accessing config and methods
123
+ * @param {number} [options.currentDepth=0] - Current traversal depth
124
+ * @param {number} [options.maxDepth=Infinity] - Maximum traversal depth
125
+ * @param {boolean} [options.debug=false] - Enable debug logging
126
+ * @returns {Promise<{
127
+ * processingStrategy: 'single-file'|'multi-file'|'empty',
128
+ * categoryName: string,
129
+ * shouldFlattenSingle: boolean,
130
+ * processedModules: Array<{file: import('fs').Dirent, moduleName: string, processedModule: any, flattening: object}>,
131
+ * subDirectories: Array<{dirEntry: import('fs').Dirent, apiPathKey: string}>,
132
+ * multiDefaultAnalysis: object,
133
+ * flatteningDecisions: object,
134
+ * upwardFlatteningCandidate: {shouldFlatten: boolean, apiPathKey: string}
135
+ * }>} Complete category building information
136
+ * @example
137
+ * // Get category building decisions
138
+ * const decisions = await getCategoryBuildingDecisions(categoryPath, { instance });
139
+ * if (decisions.processingStrategy === "single-file") {
140
+ * // Both modes: handle single file differently
141
+ * // Eager: return decisions.processedModules[0].processedModule
142
+ * // Lazy: create proxy based on decisions.processedModules[0].flattening
143
+ * }
144
+ */
145
+ export function getCategoryBuildingDecisions(categoryPath: string, options?: {
146
+ instance: object;
147
+ currentDepth?: number;
148
+ maxDepth?: number;
149
+ debug?: boolean;
150
+ }): Promise<{
151
+ processingStrategy: "single-file" | "multi-file" | "empty";
152
+ categoryName: string;
153
+ shouldFlattenSingle: boolean;
154
+ processedModules: Array<{
155
+ file: import("fs").Dirent;
156
+ moduleName: string;
157
+ processedModule: any;
158
+ flattening: object;
159
+ }>;
160
+ subDirectories: Array<{
161
+ dirEntry: import("fs").Dirent;
162
+ apiPathKey: string;
163
+ }>;
164
+ multiDefaultAnalysis: object;
165
+ flatteningDecisions: object;
166
+ upwardFlatteningCandidate: {
167
+ shouldFlatten: boolean;
168
+ apiPathKey: string;
169
+ };
170
+ }>;
171
+ /**
172
+ * Auto-flattening decision logic that determines whether a module should be flattened
173
+ * based on filename matching, export patterns, and context.
174
+ * @function getFlatteningDecision
175
+ * @internal
176
+ * @package
177
+ * @param {object} options - Flattening analysis options
178
+ * @param {object} options.mod - The loaded module object
179
+ * @param {string} options.fileName - Original filename (without extension)
180
+ * @param {string} options.apiPathKey - Sanitized API key for the module
181
+ * @param {boolean} options.hasMultipleDefaultExports - Whether multiple default exports exist in the container
182
+ * @param {boolean} options.isSelfReferential - Whether this is a self-referential export
183
+ * @param {boolean} [options.moduleHasDefault] - Whether this specific module has a default export
184
+ * @param {string} [options.categoryName] - Container/category name for context
185
+ * @param {number} [options.totalModules=1] - Total number of modules in container
186
+ * @param {boolean} [options.debug=false] - Enable debug logging
187
+ * @returns {{
188
+ * shouldFlatten: boolean,
189
+ * flattenToRoot: boolean,
190
+ * flattenToCategory: boolean,
191
+ * preserveAsNamespace: boolean,
192
+ * useAutoFlattening: boolean,
193
+ * reason: string
194
+ * }} Flattening decision result
195
+ *
196
+ * @description
197
+ * Determines flattening behavior based on slothlet's established rules:
198
+ *
199
+ * 1. Self-referential exports: Never flatten (preserve as namespace)
200
+ * 2. Multi-default context: Flatten modules WITHOUT defaults, preserve WITH defaults
201
+ * 3. Single named export matching filename: Auto-flatten to use export directly
202
+ * 4. Filename matches container: Flatten contents to container level
203
+ * 5. Traditional context: Preserve as namespace unless auto-flattening applies
204
+ *
205
+ * @example
206
+ * // Internal usage - single named export matching filename
207
+ * const decision = getFlatteningDecision({
208
+ * mod: { math: { add: fn, multiply: fn } },
209
+ * fileName: "math", apiPathKey: "math",
210
+ * hasMultipleDefaultExports: false, isSelfReferential: false
211
+ * });
212
+ * // Returns: { shouldFlatten: true, useAutoFlattening: true, reason: "auto-flatten single named export" }
213
+ */
214
+ export function getFlatteningDecision(options: {
215
+ mod: object;
216
+ fileName: string;
217
+ apiPathKey: string;
218
+ hasMultipleDefaultExports: boolean;
219
+ isSelfReferential: boolean;
220
+ moduleHasDefault?: boolean;
221
+ categoryName?: string;
222
+ totalModules?: number;
223
+ debug?: boolean;
224
+ }): {
225
+ shouldFlatten: boolean;
226
+ flattenToRoot: boolean;
227
+ flattenToCategory: boolean;
228
+ preserveAsNamespace: boolean;
229
+ useAutoFlattening: boolean;
230
+ reason: string;
231
+ };
232
+ /**
233
+ * Processes a single module and applies it to the target API object based on flattening decisions.
234
+ * @function processModuleForAPI
235
+ * @internal
236
+ * @package
237
+ * @param {object} options - Module processing options
238
+ * @param {object} options.mod - The loaded module object
239
+ * @param {string} options.fileName - Original filename (without extension)
240
+ * @param {string} options.apiPathKey - Sanitized API key for the module
241
+ * @param {boolean} options.hasMultipleDefaultExports - Whether multiple default exports exist
242
+ * @param {boolean} options.isSelfReferential - Whether this is a self-referential export
243
+ * @param {object} options.api - Target API object to modify (could be root api or categoryModules)
244
+ * @param {function} [options.getRootDefault] - Function to get current root default function
245
+ * @param {function} [options.setRootDefault] - Function to set the root default function
246
+ * @param {object} [options.context] - Processing context
247
+ * @param {boolean} [options.context.debug=false] - Enable debug logging
248
+ * @param {string} [options.context.mode="unknown"] - Processing mode (root, subfolder, eager, lazy)
249
+ * @param {string} [options.context.categoryName] - Container/category name
250
+ * @param {number} [options.context.totalModules=1] - Total modules in container
251
+ * @returns {{
252
+ * processed: boolean,
253
+ * rootDefaultSet: boolean,
254
+ * flattened: boolean,
255
+ * namespaced: boolean,
256
+ * apiAssignments: Record<string, any>
257
+ * }} Processing result
258
+ *
259
+ * @description
260
+ * Unified module processing logic that handles:
261
+ * 1. Function default exports (multi-default, self-referential, traditional root contributor)
262
+ * 2. Object/named exports with flattening decisions
263
+ * 3. Export merging and namespace assignments
264
+ * 4. Function name preference logic
265
+ * 5. Root default function management
266
+ *
267
+ * @example
268
+ * // Internal usage for root-level processing
269
+ * const result = processModuleForAPI({
270
+ * mod, fileName, apiPathKey, hasMultipleDefaultExports, isSelfReferential, api,
271
+ * getRootDefault: () => rootDefaultFunction,
272
+ * setRootDefault: (fn) => { rootDefaultFunction = fn; },
273
+ * context: { debug: true, mode: "root", totalModules: 3 }
274
+ * });
275
+ */
276
+ export function processModuleForAPI(options: {
277
+ mod: object;
278
+ fileName: string;
279
+ apiPathKey: string;
280
+ hasMultipleDefaultExports: boolean;
281
+ isSelfReferential: boolean;
282
+ api: object;
283
+ getRootDefault?: Function;
284
+ setRootDefault?: Function;
285
+ context?: {
286
+ debug?: boolean;
287
+ mode?: string;
288
+ categoryName?: string;
289
+ totalModules?: number;
290
+ };
291
+ }): {
292
+ processed: boolean;
293
+ rootDefaultSet: boolean;
294
+ flattened: boolean;
295
+ namespaced: boolean;
296
+ apiAssignments: Record<string, any>;
297
+ };
298
+ /**
299
+ * Handles function name preference logic for better API naming.
300
+ * @function applyFunctionNamePreference
301
+ * @internal
302
+ * @package
303
+ * @param {object} options - Name preference options
304
+ * @param {object} options.mod - The loaded module object
305
+ * @param {string} options.fileName - Original filename (without extension)
306
+ * @param {string} options.apiPathKey - Sanitized API key
307
+ * @param {object} options.categoryModules - Target category modules object
308
+ * @param {function} options.toapiPathKey - Function to sanitize names to API keys
309
+ * @param {boolean} [options.debug=false] - Enable debug logging
310
+ * @returns {{hasPreferredName: boolean, preferredKey: string}} Name preference result
311
+ *
312
+ * @description
313
+ * Implements slothlet's function name preference logic where the original function name
314
+ * is preferred over the sanitized filename when they represent the same semantic meaning
315
+ * but have different capitalization (e.g., autoIP vs autoIp, parseJSON vs parseJson).
316
+ *
317
+ * @example
318
+ * // Internal usage in _buildCategory
319
+ * const preference = applyFunctionNamePreference({
320
+ * mod: { autoIP: function autoIP() {} },
321
+ * fileName: "auto-ip", apiPathKey: "autoIp",
322
+ * categoryModules, toapiPathKey: this._toapiPathKey, debug: true
323
+ * });
324
+ * // Returns: { hasPreferredName: true, preferredKey: "autoIP" }
325
+ */
326
+ export function applyFunctionNamePreference(options: {
327
+ mod: object;
328
+ fileName: string;
329
+ apiPathKey: string;
330
+ categoryModules: object;
331
+ toapiPathKey: Function;
332
+ debug?: boolean;
333
+ }): {
334
+ hasPreferredName: boolean;
335
+ preferredKey: string;
336
+ };
337
+ /**
338
+ * Comprehensive category/directory building function that replaces _buildCategory.
339
+ * Handles complete directory structure processing with all flattening rules.
340
+ * @function buildCategoryStructure
341
+ * @internal
342
+ * @package
343
+ * @async
344
+ * @param {string} categoryPath - Absolute path to the category directory
345
+ * @param {object} options - Building options
346
+ * @param {number} [options.currentDepth=0] - Current recursion depth
347
+ * @param {number} [options.maxDepth=Infinity] - Maximum recursion depth
348
+ * @param {string} [options.mode="eager"] - Loading mode ("eager" or "lazy")
349
+ * @param {function} [options.subdirHandler] - Custom subdirectory handler for lazy mode
350
+ * @param {object} options.instance - Slothlet instance for access to helper methods
351
+ * @returns {Promise<object>} Complete category API structure
352
+ *
353
+ * @description
354
+ * Complete directory structure building pipeline that handles:
355
+ * - Single-file vs multi-file directory processing
356
+ * - Auto-flattening decisions for single files matching directory names
357
+ * - Multi-default export detection and processing
358
+ * - Self-referential export handling
359
+ * - Recursive subdirectory traversal with depth control
360
+ * - Function name preference over sanitized names
361
+ * - All established slothlet flattening rules and conventions
362
+ *
363
+ * @example
364
+ * // Internal usage - build complete category structure
365
+ * const categoryApi = await buildCategoryStructure("/path/to/category", {
366
+ * currentDepth: 0, maxDepth: 3, mode: "eager", instance: slothletInstance
367
+ * });
368
+ */
369
+ export function buildCategoryStructure(categoryPath: string, options?: {
370
+ currentDepth?: number;
371
+ maxDepth?: number;
372
+ mode?: string;
373
+ subdirHandler?: Function;
374
+ instance: object;
375
+ }): Promise<object>;
376
+ /**
377
+ * Comprehensive root API building function that replaces eager/lazy create methods.
378
+ * Handles complete root-level API construction with mode-specific optimizations.
379
+ * @function buildRootAPI
380
+ * @internal
381
+ * @package
382
+ * @async
383
+ * @param {string} dir - Root directory path to build API from
384
+ * @param {object} options - Building options
385
+ * @param {boolean} [options.lazy=false] - Whether to use lazy loading mode
386
+ * @param {number} [options.maxDepth=Infinity] - Maximum recursion depth
387
+ * @param {object} options.instance - Slothlet instance for access to helper methods
388
+ * @returns {Promise<object|function>} Complete root API (object or function with properties)
389
+ *
390
+ * @description
391
+ * Complete root API building pipeline that handles:
392
+ * - Root-level module processing with multi-default detection
393
+ * - Root contributor pattern (default function becomes callable API)
394
+ * - Named export merging and flattening decisions
395
+ * - Recursive directory structure building via buildCategoryStructure
396
+ * - Mode-specific optimizations (eager vs lazy)
397
+ * - All established slothlet API construction patterns
398
+ *
399
+ * @example
400
+ * // Internal usage - build complete root API
401
+ * const rootApi = await buildRootAPI("/path/to/api", {
402
+ * lazy: false, maxDepth: 3, instance: slothletInstance
403
+ * });
404
+ */
405
+ export function buildRootAPI(dir: string, options?: {
406
+ lazy?: boolean;
407
+ maxDepth?: number;
408
+ instance: object;
409
+ }): Promise<object | Function>;
410
+ /**
411
+ * Centralized category building decisions - contains ALL logic for directory/category processing.
412
+ * This function analyzes a directory and returns decisions about how to structure the API,
413
+ * but doesn't actually build the API (allowing eager/lazy modes to implement differently).
414
+ *
415
+ * @function buildCategoryDecisions
416
+ * @param {string} categoryPath - Path to the category directory
417
+ * @param {object} options - Configuration options
418
+ * @param {number} [options.currentDepth=0] - Current nesting depth
419
+ * @param {number} [options.maxDepth=Infinity] - Maximum nesting depth
420
+ * @param {string} [options.mode="eager"] - Loading mode ("eager" or "lazy")
421
+ * @param {Function} [options.subdirHandler] - Handler for subdirectories (lazy mode)
422
+ * @param {object} options.instance - Slothlet instance with _toapiPathKey, _shouldIncludeFile, config
423
+ * @returns {Promise<object>} Category building decisions and data
424
+ *
425
+ * @example // ESM usage
426
+ * import { buildCategoryDecisions } from "@cldmv/slothlet/helpers/api_builder";
427
+ * const decisions = await buildCategoryDecisions("/path/to/category", {
428
+ * currentDepth: 1,
429
+ * instance: slothletInstance
430
+ * });
431
+ *
432
+ * @example // CJS usage
433
+ * const { buildCategoryDecisions } = require("@cldmv/slothlet/helpers/api_builder");
434
+ * const decisions = await buildCategoryDecisions("/path/to/category", {
435
+ * currentDepth: 1,
436
+ * instance: slothletInstance
437
+ * });
438
+ */
439
+ export function buildCategoryDecisions(categoryPath: string, options?: {
440
+ currentDepth?: number;
441
+ maxDepth?: number;
442
+ mode?: string;
443
+ subdirHandler?: Function;
444
+ instance: object;
445
+ }): Promise<object>;
446
+ //# sourceMappingURL=api_builder.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api_builder.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/api_builder.mjs"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Analyzes module files to detect multi-default and self-referential patterns.
3
+ * @internal
4
+ * @private
5
+ * @param {Array<{name: string}>} moduleFiles - Array of module file objects with name property
6
+ * @param {string} baseDir - Base directory path containing the modules
7
+ * @param {boolean} [debug=false] - Enable debug logging
8
+ * @returns {Promise<{
9
+ * totalDefaultExports: number,
10
+ * hasMultipleDefaultExports: boolean,
11
+ * selfReferentialFiles: Set<string>,
12
+ * rawModuleCache: Map<string, object>,
13
+ * defaultExportFiles: Array<{fileName: string, rawModule: object}>
14
+ * }>} Analysis results
15
+ * @example // Internal usage in slothlet modes
16
+ * const analysis = await multidefault_analyzeModules(moduleFiles, categoryPath, config.debug);
17
+ * if (analysis.hasMultipleDefaultExports) {
18
+ * // Handle multi-default context
19
+ * }
20
+ */
21
+ export function multidefault_analyzeModules(moduleFiles: Array<{
22
+ name: string;
23
+ }>, baseDir: string, debug?: boolean): Promise<{
24
+ totalDefaultExports: number;
25
+ hasMultipleDefaultExports: boolean;
26
+ selfReferentialFiles: Set<string>;
27
+ rawModuleCache: Map<string, object>;
28
+ defaultExportFiles: Array<{
29
+ fileName: string;
30
+ rawModule: object;
31
+ }>;
32
+ }>;
33
+ /**
34
+ * Checks if a raw module's default export is self-referential (points to a named export).
35
+ * @internal
36
+ * @private
37
+ * @param {object} rawModule - Raw module object to check
38
+ * @returns {boolean} True if default export points to a named export
39
+ * @example // Internal usage
40
+ * const isSelfRef = multidefault_isSelfReferential(rawModule);
41
+ */
42
+ export function multidefault_isSelfReferential(rawModule: object): boolean;
43
+ /**
44
+ * Determines auto-flattening behavior based on multi-default context and module structure.
45
+ * @internal
46
+ * @private
47
+ * @param {object} options - Configuration options
48
+ * @param {boolean} options.hasMultipleDefaultExports - Whether multiple default exports exist
49
+ * @param {boolean} options.moduleHasDefault - Whether current module has default export
50
+ * @param {boolean} options.isSelfReferential - Whether current module is self-referential
51
+ * @param {Array<string>} options.moduleKeys - Named export keys from the module
52
+ * @param {string} options.apiPathKey - API key for the module
53
+ * @param {number} options.totalModuleCount - Total number of modules in directory
54
+ * @param {boolean} [options.debug=false] - Enable debug logging
55
+ * @returns {{
56
+ * shouldFlatten: boolean,
57
+ * flattenToRoot: boolean,
58
+ * preserveAsNamespace: boolean,
59
+ * reason: string
60
+ * }} Flattening decision and reasoning
61
+ * @example // Internal usage in processing logic
62
+ * const decision = multidefault_getFlatteningDecision({
63
+ * hasMultipleDefaultExports: true,
64
+ * moduleHasDefault: false,
65
+ * isSelfReferential: false,
66
+ * moduleKeys: ["add", "subtract"],
67
+ * apiPathKey: "math",
68
+ * totalModuleCount: 3
69
+ * });
70
+ */
71
+ export function multidefault_getFlatteningDecision(options: {
72
+ hasMultipleDefaultExports: boolean;
73
+ moduleHasDefault: boolean;
74
+ isSelfReferential: boolean;
75
+ moduleKeys: Array<string>;
76
+ apiPathKey: string;
77
+ totalModuleCount: number;
78
+ debug?: boolean;
79
+ }): {
80
+ shouldFlatten: boolean;
81
+ flattenToRoot: boolean;
82
+ preserveAsNamespace: boolean;
83
+ reason: string;
84
+ };
85
+ //# sourceMappingURL=multidefault.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multidefault.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/multidefault.mjs"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,yDAhBW,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAC,WACrB,MAAM,UACN,OAAO,GACL,OAAO,CAAC;IAChB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,yBAAyB,EAAE,OAAO,CAAC;IACnC,oBAAoB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,kBAAkB,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,CAAC,CAAA;CACjE,CAAC,CAsFJ;AAED;;;;;;;;GAQG;AACH,0DALW,MAAM,GACJ,OAAO,CAWnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,4DAvBG;IAAyB,yBAAyB,EAA1C,OAAO;IACU,gBAAgB,EAAjC,OAAO;IACU,iBAAiB,EAAlC,OAAO;IACgB,UAAU,EAAjC,KAAK,CAAC,MAAM,CAAC;IACG,UAAU,EAA1B,MAAM;IACU,gBAAgB,EAAhC,MAAM;IACY,KAAK,GAAvB,OAAO;CACf,GAAU;IACR,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAA;CACf,CA4FH"}
@@ -41,7 +41,6 @@
41
41
  * @alias module:@cldmv/slothlet.modes.eager.create
42
42
  * @memberof module:@cldmv/slothlet.modes.eager
43
43
  * @param {string} dir - Directory to load
44
- * @param {boolean} [rootLevel=true] - Is this the root level?
45
44
  * @param {number} [maxDepth=Infinity] - Maximum depth to traverse
46
45
  * @param {number} [currentDepth=0] - Current traversal depth
47
46
  * @returns {Promise<object>} Complete API object with all modules loaded
@@ -53,14 +52,14 @@
53
52
  *
54
53
  * @example
55
54
  * // Internal usage - called by slothlet core
56
- * const api = await create('./api_test', true, 3, 0);
55
+ * const api = await create('./api_test', 3, 0);
57
56
  * // Returns: { math: { add: [Function], multiply: [Function] }, ... }
58
57
  *
59
58
  * @example
60
59
  * // Root-level processing with function exports
61
- * const api = await create('./api_test', true);
60
+ * const api = await create('./api_test');
62
61
  * // If root has default function: api becomes that function with properties
63
62
  * // Otherwise: api is object with module properties
64
63
  */
65
- export function create(dir: string, rootLevel?: boolean, maxDepth?: number, currentDepth?: number): Promise<object>;
64
+ export function create(dir: string, maxDepth?: number, currentDepth?: number): Promise<object>;
66
65
  //# sourceMappingURL=slothlet_eager.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slothlet_eager.d.mts","sourceRoot":"","sources":["../../../../dist/lib/modes/slothlet_eager.mjs"],"names":[],"mappings":"AA2IA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAsDH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,4BAtBW,MAAM,cACN,OAAO,aACP,MAAM,iBACN,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,CAqM3B"}
1
+ {"version":3,"file":"slothlet_eager.d.mts","sourceRoot":"","sources":["../../../../dist/lib/modes/slothlet_eager.mjs"],"names":[],"mappings":"AA0IA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAsDH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,4BArBW,MAAM,aACN,MAAM,iBACN,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,CA8G3B"}
@@ -6,7 +6,6 @@
6
6
  * @alias module:@cldmv/slothlet.modes.lazy.create
7
7
  * @memberof module:@cldmv/slothlet.modes.lazy
8
8
  * @param {string} dir - Root directory
9
- * @param {boolean} [rootLevel=true] - Root level flag
10
9
  * @param {number} [maxDepth=Infinity] - Maximum depth to traverse
11
10
  * @param {number} [currentDepth=0] - Current depth (for internal recursion only)
12
11
  * @returns {Promise<function|object>} Root API object or function (if default export)
@@ -19,14 +18,14 @@
19
18
  *
20
19
  * @example
21
20
  * // Internal usage - called by slothlet core
22
- * const api = await create('./api_test', true, 3, 0);
21
+ * const api = await create('./api_test', 3, 0);
23
22
  * // Returns: { math: [Function: lazyFolder_math], ... } (lazy proxies)
24
23
  *
25
24
  * @example
26
25
  * // Root-level processing with function exports
27
- * const api = await create('./api_test', true);
26
+ * const api = await create('./api_test');
28
27
  * // If root has default function: api becomes that function with properties
29
28
  * // Otherwise: api is object with lazy proxy properties
30
29
  */
31
- export function create(dir: string, rootLevel?: boolean, maxDepth?: number, currentDepth?: number): Promise<Function | object>;
30
+ export function create(dir: string, maxDepth?: number, currentDepth?: number): Promise<Function | object>;
32
31
  //# sourceMappingURL=slothlet_lazy.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slothlet_lazy.d.mts","sourceRoot":"","sources":["../../../../dist/lib/modes/slothlet_lazy.mjs"],"names":[],"mappings":"AA6JA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,4BAvBW,MAAM,cACN,OAAO,aACP,MAAM,iBACN,MAAM,GACJ,OAAO,CAAC,WAAS,MAAM,CAAC,CAqMpC"}
1
+ {"version":3,"file":"slothlet_lazy.d.mts","sourceRoot":"","sources":["../../../../dist/lib/modes/slothlet_lazy.mjs"],"names":[],"mappings":"AA+JA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,4BAtBW,MAAM,aACN,MAAM,iBACN,MAAM,GACJ,OAAO,CAAC,WAAS,MAAM,CAAC,CAqJpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"slothlet.d.mts","sourceRoot":"","sources":["../../dist/slothlet.mjs"],"names":[],"mappings":"AA4+CA;;;;;;;;;GASG;AACH,kDARW,WAAS,MAAM,UACf,WAAS,MAAM,QAwCzB;AAv4CD;;;;;;;GAOG;AACH,mBAJU,MAAM,CAIO;AAEvB;;;;;GAKG;AACH,sBAJU,MAAM,CAIU;AAE1B;;;;;GAKG;AACH,wBAJU,MAAM,CAIY;;;;;;;;;UA03Cd,MAAM;;;;;;WAIN,OAAO;;;;;;;eAGP,MAAM;;;;;;;;YAIN,OAAO;;;;;;;;WAKP,MAAM;;;;;;;eAKN,MAAM;;;;;;cAIN,MAAM;;;;;;gBAGN,MAAM;;;;;;eAMjB;QAA8B,UAAU,GAA7B,OAAO;QACY,gBAAgB,GAAnC,OAAO;QACY,gBAAgB,GAAnC,OAAO;QACW,KAAK,GAClC;YAAqC,KAAK,GAA/B,MAAM,EAAE;YACkB,gBAAgB,GAA1C,MAAM,EAAE;YACkB,KAAK,GAA/B,MAAM,EAAE;YACkB,KAAK,GAA/B,MAAM,EAAE;SACrB;KAAA;;AAl6CD;;;;;;;;GAQG;AACH,mCAJW,eAAe,GACb,OAAO,CAAC,WAAS,MAAM,CAAC,CAiCpC"}
1
+ {"version":3,"file":"slothlet.d.mts","sourceRoot":"","sources":["../../dist/slothlet.mjs"],"names":[],"mappings":"AAyzCA;;;;;;;;;GASG;AACH,kDARW,WAAS,MAAM,UACf,WAAS,MAAM,QAwCzB;AA9sCD;;;;;;;GAOG;AACH,mBAJU,MAAM,CAIO;AAEvB;;;;;GAKG;AACH,sBAJU,MAAM,CAIU;AAE1B;;;;;GAKG;AACH,wBAJU,MAAM,CAIY;;;;;;;;;UAisCd,MAAM;;;;;;WAIN,OAAO;;;;;;;eAGP,MAAM;;;;;;;;YAIN,OAAO;;;;;;;;WAKP,MAAM;;;;;;;eAKN,MAAM;;;;;;cAIN,MAAM;;;;;;gBAGN,MAAM;;;;;;eAMjB;QAA8B,UAAU,GAA7B,OAAO;QACY,gBAAgB,GAAnC,OAAO;QACY,gBAAgB,GAAnC,OAAO;QACW,KAAK,GAClC;YAAqC,KAAK,GAA/B,MAAM,EAAE;YACkB,gBAAgB,GAA1C,MAAM,EAAE;YACkB,KAAK,GAA/B,MAAM,EAAE;YACkB,KAAK,GAA/B,MAAM,EAAE;SACrB;KAAA;;AAzuCD;;;;;;;;GAQG;AACH,mCAJW,eAAe,GACb,OAAO,CAAC,WAAS,MAAM,CAAC,CAiCpC"}