@cldmv/slothlet 2.4.2 → 2.4.3

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.
@@ -53,9 +53,18 @@ export async function create(dir, rootLevel = true, maxDepth = Infinity, current
53
53
  }
54
54
 
55
55
  if (mod && "default" in mod) {
56
- defaultExportFiles.push({ entry, fileName, mod });
57
- if (this.config.debug) {
58
- console.log(`[DEBUG] Added ${fileName} to defaultExportFiles`);
56
+
57
+ const isSelfReferential = Object.entries(mod).some(([key, value]) => key !== "default" && value === mod.default);
58
+
59
+ if (!isSelfReferential) {
60
+ defaultExportFiles.push({ entry, fileName, mod });
61
+ if (this.config.debug) {
62
+ console.log(`[DEBUG] Added ${fileName} to defaultExportFiles (non-self-referential)`);
63
+ }
64
+ } else {
65
+ if (this.config.debug) {
66
+ console.log(`[DEBUG] Skipped ${fileName} - self-referential default export`);
67
+ }
59
68
  }
60
69
  }
61
70
  }
@@ -78,8 +87,12 @@ export async function create(dir, rootLevel = true, maxDepth = Infinity, current
78
87
  const apiKey = this._toApiKey(fileName);
79
88
  const mod = await this._loadSingleModule(path.join(dir, entry.name), true);
80
89
 
90
+
91
+ const isSelfReferential =
92
+ mod && "default" in mod && Object.entries(mod).some(([key, value]) => key !== "default" && value === mod.default);
93
+
81
94
  if (mod && typeof mod.default === "function") {
82
- if (hasMultipleDefaultExports) {
95
+ if (hasMultipleDefaultExports && !isSelfReferential) {
83
96
 
84
97
  api[apiKey] = mod.default;
85
98
 
@@ -95,13 +108,12 @@ export async function create(dir, rootLevel = true, maxDepth = Infinity, current
95
108
  }
96
109
  } else {
97
110
 
98
-
99
111
  if (this.config.debug) {
100
112
  console.log(
101
- `[DEBUG] Processing traditional default: hasMultipleDefaultExports=${hasMultipleDefaultExports}, rootDefaultFunction=${!!rootDefaultFunction}`
113
+ `[DEBUG] Processing traditional default: hasMultipleDefaultExports=${hasMultipleDefaultExports}, isSelfReferential=${isSelfReferential}, rootDefaultFunction=${!!rootDefaultFunction}`
102
114
  );
103
115
  }
104
- if (!hasMultipleDefaultExports && !rootDefaultFunction) {
116
+ if ((!hasMultipleDefaultExports || isSelfReferential) && !rootDefaultFunction) {
105
117
  rootDefaultFunction = mod.default;
106
118
  if (this.config.debug) {
107
119
  console.log(`[DEBUG] Set rootDefaultFunction to:`, mod.default.name);
@@ -117,19 +129,39 @@ export async function create(dir, rootLevel = true, maxDepth = Infinity, current
117
129
  }
118
130
  } else {
119
131
 
120
-
121
132
  if (this.config.debug) {
122
- console.log(`[DEBUG] Processing non-default exports for ${fileName}`);
133
+ console.log(`[DEBUG] Processing non-function or named-only exports for ${fileName}`);
123
134
  }
124
135
 
125
- if (hasMultipleDefaultExports) {
136
+ if (isSelfReferential) {
137
+
138
+ if (this.config.debug) {
139
+ console.log(`[DEBUG] Self-referential ${fileName}: preserving as namespace`);
140
+ }
141
+ api[apiKey] = mod.default;
142
+ } else if (hasMultipleDefaultExports) {
126
143
 
127
144
  if (this.config.debug) {
128
145
  console.log(`[DEBUG] Multi-default context: flattening ${fileName} exports to root`);
129
146
  }
130
- for (const [key, value] of Object.entries(mod)) {
131
- api[key] = value;
132
- rootNamedExports[key] = value;
147
+
148
+ const eager_addNamedExportsToApi = (exports, api, rootNamedExports) => {
149
+ for (const [key, value] of Object.entries(exports)) {
150
+ if (key !== "default") {
151
+ api[key] = value;
152
+ rootNamedExports[key] = value;
153
+ }
154
+ }
155
+ };
156
+
157
+ if (mod && "default" in mod) {
158
+
159
+ api[apiKey] = mod.default;
160
+
161
+ eager_addNamedExportsToApi(mod, api, rootNamedExports);
162
+ } else {
163
+
164
+ eager_addNamedExportsToApi(mod, api, rootNamedExports);
133
165
  }
134
166
  } else {
135
167
 
@@ -35,27 +35,80 @@ export async function create(dir, rootLevel = true, maxDepth = Infinity, current
35
35
  const defaultExportFiles = [];
36
36
 
37
37
 
38
+ const selfReferentialFiles = new Set();
39
+ const rawModuleCache = new Map();
40
+
38
41
  for (const entry of moduleFiles) {
39
42
  const ext = path.extname(entry.name);
40
43
  const fileName = path.basename(entry.name, ext);
41
- const mod = await instance._loadSingleModule(path.join(dir, entry.name), true);
42
44
 
43
- if (mod && "default" in mod) {
44
- defaultExportFiles.push({ entry, fileName, mod });
45
+ if (instance.config.debug) {
46
+ console.log(`[DEBUG] First pass processing: ${fileName}`);
47
+ }
48
+
49
+
50
+ const modulePath = path.resolve(dir, entry.name);
51
+ const rawMod = await import(`file://${modulePath.replace(/\\/g, "/")}`);
52
+ rawModuleCache.set(entry.name, rawMod);
53
+
54
+ if (instance.config.debug && fileName === "config") {
55
+ console.log(`[DEBUG] First pass - raw config keys:`, Object.keys(rawMod || {}));
56
+ console.log(`[DEBUG] First pass - raw config has default:`, rawMod && "default" in rawMod);
57
+ }
58
+
59
+ if (rawMod && "default" in rawMod) {
60
+
61
+ const isSelfReferential = Object.entries(rawMod).some(([key, value]) => key !== "default" && value === rawMod.default);
62
+
63
+
64
+ if (instance.config.debug && fileName === "config") {
65
+ console.log(`[DEBUG] First pass - ${fileName} self-referential check:`);
66
+ console.log(`[DEBUG] - rawMod.default === rawMod.config: ${rawMod.default === rawMod.config}`);
67
+ console.log(`[DEBUG] - isSelfReferential result: ${isSelfReferential}`);
68
+ }
69
+
70
+ if (!isSelfReferential) {
71
+
72
+ const mod = await instance._loadSingleModule(path.join(dir, entry.name), true);
73
+ defaultExportFiles.push({ entry, fileName, mod });
74
+ if (instance.config.debug) {
75
+ console.log(`[DEBUG] Added ${fileName} to defaultExportFiles (non-self-referential)`);
76
+ }
77
+ } else {
78
+ selfReferentialFiles.add(fileName);
79
+ if (instance.config.debug) {
80
+ console.log(`[DEBUG] Skipped ${fileName} - self-referential default export`);
81
+ }
82
+ }
45
83
  }
46
84
  }
47
85
 
48
86
  const hasMultipleDefaultExports = defaultExportFiles.length > 1;
49
87
 
50
88
 
89
+ const processedModuleCache = new Map();
90
+
51
91
  for (const entry of moduleFiles) {
52
92
  const ext = path.extname(entry.name);
53
93
  const fileName = path.basename(entry.name, ext);
54
94
  const apiKey = instance._toApiKey(fileName);
55
- const mod = await instance._loadSingleModule(path.join(dir, entry.name), true);
95
+
96
+
97
+ let mod = null;
98
+ const existingDefault = defaultExportFiles.find((def) => def.fileName === fileName);
99
+ if (existingDefault) {
100
+ mod = existingDefault.mod;
101
+ } else {
102
+
103
+ mod = await instance._loadSingleModule(path.join(dir, entry.name), true);
104
+ processedModuleCache.set(entry.name, mod);
105
+ }
106
+
107
+
108
+ const isSelfReferential = selfReferentialFiles.has(fileName);
56
109
 
57
110
  if (mod && typeof mod.default === "function") {
58
- if (hasMultipleDefaultExports) {
111
+ if (hasMultipleDefaultExports && !isSelfReferential) {
59
112
 
60
113
  api[apiKey] = mod.default;
61
114
 
@@ -69,6 +122,12 @@ export async function create(dir, rootLevel = true, maxDepth = Infinity, current
69
122
  if (instance.config.debug) {
70
123
  console.log(`[DEBUG] Multi-default in lazy mode: using filename '${apiKey}' for default export`);
71
124
  }
125
+ } else if (isSelfReferential) {
126
+
127
+ if (instance.config.debug) {
128
+ console.log(`[DEBUG] Self-referential default export: preserving ${fileName} as namespace`);
129
+ }
130
+ api[apiKey] = mod;
72
131
  } else {
73
132
 
74
133
 
@@ -86,13 +145,22 @@ export async function create(dir, rootLevel = true, maxDepth = Infinity, current
86
145
  console.log(`[DEBUG] Processing non-default exports for ${fileName}`);
87
146
  }
88
147
 
89
- if (hasMultipleDefaultExports) {
148
+ if (isSelfReferential) {
149
+
150
+ if (instance.config.debug) {
151
+ console.log(`[DEBUG] Self-referential: preserving ${fileName} as namespace`);
152
+ }
153
+
154
+ api[apiKey] = mod[apiKey] || mod;
155
+ } else if (hasMultipleDefaultExports) {
90
156
 
91
157
  if (instance.config.debug) {
92
158
  console.log(`[DEBUG] Multi-default context: flattening ${fileName} exports to root`);
93
159
  }
94
160
  for (const [k, v] of Object.entries(mod)) {
95
- api[k] = v;
161
+ if (k !== "default") {
162
+ api[k] = v;
163
+ }
96
164
  }
97
165
  } else {
98
166
 
package/dist/slothlet.mjs CHANGED
@@ -423,33 +423,78 @@ const slothletObject = {
423
423
 
424
424
 
425
425
  const defaultExportFiles = [];
426
+ const selfReferentialFiles = new Set();
427
+ const rawModuleCache = new Map();
428
+
429
+
426
430
  for (const file of moduleFiles) {
427
431
  const moduleExt = path.extname(file.name);
428
432
  const moduleName = this._toApiKey(path.basename(file.name, moduleExt));
429
- const tempMod = await this._loadSingleModule(path.join(categoryPath, file.name));
433
+ const moduleFilePath = path.resolve(categoryPath, file.name);
430
434
 
431
435
 
436
+ const rawMod = await import(`file://${moduleFilePath.replace(/\\/g, "/")}`);
437
+ rawModuleCache.set(file.name, rawMod);
438
+
432
439
 
433
- if (tempMod && tempMod.__slothletDefault === true) {
434
- defaultExportFiles.push({ file, moduleName, mod: tempMod });
440
+ if (rawMod && "default" in rawMod) {
441
+
442
+ const isSelfReferential = Object.entries(rawMod).some(([key, value]) => key !== "default" && value === rawMod.default);
443
+
435
444
  if (this.config.debug) {
436
- console.log(`[DEBUG] Found default export in ${file.name}`);
445
+ console.log(`[DEBUG] _buildCategory: Checking ${file.name} in ${categoryPath}`);
446
+ console.log(`[DEBUG] - moduleName: ${moduleName}`);
447
+ console.log(`[DEBUG] - has default: ${rawMod && "default" in rawMod}`);
448
+ console.log(`[DEBUG] - isSelfReferential: ${isSelfReferential}`);
449
+ }
450
+
451
+ if (!isSelfReferential) {
452
+
453
+ const processedMod = await this._loadSingleModule(path.join(categoryPath, file.name));
454
+ defaultExportFiles.push({ file, moduleName, mod: processedMod });
455
+ if (this.config.debug) {
456
+ console.log(`[DEBUG] Found default export in ${file.name} (non-self-referential)`);
457
+ }
458
+ } else {
459
+ selfReferentialFiles.add(moduleName);
460
+ if (this.config.debug) {
461
+ console.log(`[DEBUG] Skipped ${file.name} - self-referential default export`);
462
+ }
437
463
  }
438
464
  }
439
465
  }
440
466
 
441
467
  const hasMultipleDefaultExports = defaultExportFiles.length > 1;
442
468
 
469
+ if (this.config.debug) {
470
+ console.log(`[DEBUG] selfReferentialFiles Set:`, Array.from(selfReferentialFiles));
471
+ console.log(`[DEBUG] hasMultipleDefaultExports:`, hasMultipleDefaultExports);
472
+ }
473
+
443
474
  for (const file of moduleFiles) {
444
475
  const moduleExt = path.extname(file.name);
445
476
  const moduleName = this._toApiKey(path.basename(file.name, moduleExt));
446
477
 
447
478
 
479
+ if (this.config.debug && moduleName === "config") {
480
+ console.log("[DEBUG] Processing config file:", file.name, "moduleName:", moduleName);
481
+ console.log("[DEBUG] selfReferentialFiles has config?", selfReferentialFiles.has(moduleName));
482
+ }
483
+
448
484
 
449
-
450
-
485
+ let mod = null;
486
+ const existingDefault = defaultExportFiles.find(def => def.moduleName === moduleName);
487
+ if (existingDefault) {
488
+ mod = existingDefault.mod;
489
+ } else {
490
+
491
+ mod = await this._loadSingleModule(path.join(categoryPath, file.name));
492
+ }
451
493
 
452
- const mod = await this._loadSingleModule(path.join(categoryPath, file.name));
494
+ if (this.config.debug && moduleName === "config") {
495
+ console.log("[DEBUG] Config mod type:", typeof mod);
496
+ console.log("[DEBUG] Config mod keys:", Object.keys(mod));
497
+ }
453
498
  if (moduleName === categoryName && mod && typeof mod === "object") {
454
499
  if (
455
500
  Object.prototype.hasOwnProperty.call(mod, categoryName) &&
@@ -465,8 +510,11 @@ const slothletObject = {
465
510
  }
466
511
  } else if (typeof mod === "function") {
467
512
 
513
+ const isSelfReferential = selfReferentialFiles.has(moduleName);
514
+
515
+
468
516
  let apiKey;
469
- if (hasMultipleDefaultExports && mod.__slothletDefault === true) {
517
+ if (hasMultipleDefaultExports && mod.__slothletDefault === true && !isSelfReferential) {
470
518
 
471
519
  apiKey = moduleName;
472
520
  try {
@@ -477,6 +525,14 @@ const slothletObject = {
477
525
  if (this.config.debug) {
478
526
  console.log(`[DEBUG] Multi-default detected: using filename '${moduleName}' for default export`);
479
527
  }
528
+ } else if (selfReferentialFiles.has(moduleName)) {
529
+
530
+ if (this.config.debug) {
531
+ console.log(`[DEBUG] Self-referential default export: treating ${moduleName} as namespace`);
532
+ }
533
+
534
+ categoryModules[moduleName] = mod[moduleName] || mod;
535
+ continue;
480
536
  } else {
481
537
 
482
538
  const fnName = mod.name && mod.name !== "default" ? mod.name : moduleName;
@@ -553,6 +609,12 @@ const slothletObject = {
553
609
  if (hasPreferredName) {
554
610
  Object.assign(categoryModules, modWithPreferredNames);
555
611
 
612
+ } else if (selfReferentialFiles.has(moduleName)) {
613
+
614
+ if (this.config.debug) {
615
+ console.log(`[DEBUG] Self-referential object: treating ${moduleName} as namespace`);
616
+ }
617
+ categoryModules[moduleName] = mod[moduleName] || mod;
556
618
  } else {
557
619
  categoryModules[this._toApiKey(moduleName)] = mod;
558
620
 
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@cldmv/slothlet",
3
- "version": "2.4.2",
3
+ "version": "2.4.3",
4
4
  "moduleVersions": {
5
- "lazy": "1.2.0",
6
- "eager": "1.2.0"
5
+ "lazy": "1.3.0",
6
+ "eager": "1.3.0"
7
7
  },
8
8
  "description": "Slothlet: Modular API Loader for Node.js. Lazy mode dynamically loads API modules and submodules only when accessed, supporting both lazy and eager loading.",
9
9
  "main": "./index.cjs",
@@ -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,CAqK3B"}
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 +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,CAiIpC"}
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 +1 @@
1
- {"version":3,"file":"slothlet.d.mts","sourceRoot":"","sources":["../../dist/slothlet.mjs"],"names":[],"mappings":"AA86CA;;;;;;;;;GASG;AACH,kDARW,WAAS,MAAM,UACf,WAAS,MAAM,QAwCzB;AAz0CD;;;;;;;GAOG;AACH,mBAJU,MAAM,CAIO;AAEvB;;;;;GAKG;AACH,sBAJU,MAAM,CAIU;AAE1B;;;;;GAKG;AACH,wBAJU,MAAM,CAIY;;;;;;;;;UA4zCd,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;;AAp2CD;;;;;;;;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":"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"}