@cldmv/slothlet 2.9.0 → 2.11.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/AGENT-USAGE.md +41 -0
- package/README.md +95 -20
- package/dist/lib/engine/slothlet_child.mjs +1 -1
- package/dist/lib/engine/slothlet_engine.mjs +1 -1
- package/dist/lib/engine/slothlet_esm.mjs +1 -1
- package/dist/lib/engine/slothlet_helpers.mjs +1 -1
- package/dist/lib/engine/slothlet_worker.mjs +1 -1
- package/dist/lib/helpers/als-eventemitter.mjs +1 -1
- package/dist/lib/helpers/api_builder/add_api.mjs +321 -5
- package/dist/lib/helpers/api_builder/analysis.mjs +13 -3
- package/dist/lib/helpers/api_builder/construction.mjs +41 -3
- package/dist/lib/helpers/api_builder/decisions.mjs +16 -5
- package/dist/lib/helpers/api_builder/metadata.mjs +248 -0
- package/dist/lib/helpers/api_builder.mjs +1 -1
- package/dist/lib/helpers/auto-wrap.mjs +1 -1
- package/dist/lib/helpers/hooks.mjs +1 -1
- package/dist/lib/helpers/instance-manager.mjs +1 -1
- package/dist/lib/helpers/metadata-api.mjs +201 -0
- package/dist/lib/helpers/multidefault.mjs +12 -3
- package/dist/lib/helpers/resolve-from-caller.mjs +48 -11
- package/dist/lib/helpers/sanitize.mjs +1 -1
- package/dist/lib/helpers/utilities.mjs +1 -1
- package/dist/lib/modes/slothlet_eager.mjs +30 -2
- package/dist/lib/modes/slothlet_lazy.mjs +95 -5
- package/dist/lib/runtime/runtime-asynclocalstorage.mjs +5 -1
- package/dist/lib/runtime/runtime-livebindings.mjs +5 -1
- package/dist/lib/runtime/runtime.mjs +12 -1
- package/dist/slothlet.mjs +70 -6
- package/docs/API-RULES-CONDITIONS.md +511 -307
- package/docs/API-RULES.md +617 -589
- package/package.json +2 -2
- package/types/dist/lib/helpers/api_builder/add_api.d.mts +64 -22
- package/types/dist/lib/helpers/api_builder/add_api.d.mts.map +1 -1
- package/types/dist/lib/helpers/api_builder/analysis.d.mts.map +1 -1
- package/types/dist/lib/helpers/api_builder/construction.d.mts.map +1 -1
- package/types/dist/lib/helpers/api_builder/decisions.d.mts.map +1 -1
- package/types/dist/lib/helpers/api_builder/metadata.d.mts +99 -0
- package/types/dist/lib/helpers/api_builder/metadata.d.mts.map +1 -0
- package/types/dist/lib/helpers/metadata-api.d.mts +132 -0
- package/types/dist/lib/helpers/metadata-api.d.mts.map +1 -0
- package/types/dist/lib/helpers/multidefault.d.mts.map +1 -1
- package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -1
- package/types/dist/lib/modes/slothlet_eager.d.mts.map +1 -1
- package/types/dist/lib/modes/slothlet_lazy.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +2 -0
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime-livebindings.d.mts +2 -0
- package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime.d.mts +1 -0
- package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
- package/types/dist/slothlet.d.mts +8 -0
- package/types/dist/slothlet.d.mts.map +1 -1
- package/types/index.d.mts.map +1 -0
package/docs/API-RULES.md
CHANGED
|
@@ -1,85 +1,121 @@
|
|
|
1
|
-
# Slothlet API Rules -
|
|
1
|
+
# Slothlet API Rules - Comprehensive Documentation (v2)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
> **Last Updated**: December 30, 2025
|
|
5
|
-
> **Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
6
|
-
> **Note**: Source code has been refactored into modular structure. See [API-RULES-CONDITIONS.md](API-RULES-CONDITIONS.md) for complete conditional logic documentation with exact line numbers.
|
|
3
|
+
**Complete Guide to All API Generation Behaviors with Cross-Referenced Implementation Details**
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
- **Version**: 2.0
|
|
6
|
+
- **Date**: January 3, 2026
|
|
7
|
+
- **Purpose**: Maintainer and contributor guide documenting all API generation rules with verified examples and technical cross-references
|
|
8
|
+
- **Status**: ✅ **VERIFIED AND CURRENT**
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Document Hierarchy
|
|
13
|
+
|
|
14
|
+
This is the **middle layer** of slothlet's three-tier documentation system:
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
📋 API-FLATTENING-v2.md (F##) ← User Guide: Clear examples and flowcharts
|
|
18
|
+
↑ links to ↓ links to
|
|
19
|
+
📊 API-RULES-v2.md (1-12) ← YOU ARE HERE: Complete behavior catalog
|
|
20
|
+
↑ links to ↓ links to
|
|
21
|
+
🔧 API-RULES-CONDITIONS-v2.md ← Technical: Exact source code locations
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Cross-Reference Navigation:**
|
|
11
25
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- **Processing Path**: Which processing path applies this rule (Root/Subfolder/Multi-Default)
|
|
15
|
-
- **Test File Sources**: Specific test files demonstrating the behavior
|
|
26
|
+
- **⬆️ For Users**: See [API-FLATTENING-v2.md](API-FLATTENING-v2.md) for user-friendly explanations with examples
|
|
27
|
+
- **⬇️ For Developers**: See [API-RULES-CONDITIONS-v2.md](API-RULES-CONDITIONS-v2.md) for exact source code locations
|
|
16
28
|
|
|
17
29
|
---
|
|
18
30
|
|
|
19
|
-
##
|
|
31
|
+
## Overview
|
|
32
|
+
|
|
33
|
+
This document catalogs **all 12 API generation behaviors** in slothlet with:
|
|
34
|
+
|
|
35
|
+
- **Verified examples** from actual test files with source attribution
|
|
36
|
+
- **Cross-references** to user guide ([F##](API-FLATTENING-v2.md)) and technical details ([C##](API-RULES-CONDITIONS-v2.md))
|
|
37
|
+
- **Source code locations** with function names and file references
|
|
38
|
+
- **Test file sources** demonstrating each behavior in action
|
|
39
|
+
- **Processing contexts** (Root/Subfolder/Multi-Default/AddApi)
|
|
20
40
|
|
|
21
|
-
|
|
22
|
-
- [x] Rule 2: Named-Only Export Collection ✅ **VERIFIED** (api_tests/api_test) - Re-verified
|
|
23
|
-
- [x] Rule 3: Empty Module Handling ✅ **VERIFIED** (debug testing)
|
|
24
|
-
- [x] Rule 4: Default Export Container Pattern ✅ **VERIFIED** (api_tests/api_test + api_tests/api_tv_test) - Re-verified
|
|
25
|
-
- [x] Rule 5: Multi-Default Export Mixed Pattern ✅ **VERIFIED** (api_tests/api_tv_test) - Re-verified
|
|
26
|
-
- [x] Rule 6: Self-Referential Export Protection ✅ **VERIFIED** (api_tests/api_test) - Tested
|
|
27
|
-
- [x] Rule 7: Auto-Flattening Single Named Export ✅ **VERIFIED** (api_tests/api_test) - Tested
|
|
28
|
-
- [x] Rule 8: Single-File Auto-Flattening Patterns ✅ **FULLY VERIFIED** (All 4 patterns A, B, C, D verified with real test files)
|
|
29
|
-
- [x] Rule 9: Function Name Preference Over Sanitization ✅ **FULLY VERIFIED** (Multiple examples verified: autoIP, parseJSON, getHTTPStatus, XMLParser)
|
|
30
|
-
- [x] Rule 10: Generic Filename Parent-Level Promotion ✅ **VERIFIED** (nest4/singlefile.mjs example verified with api_tests/api_test)
|
|
41
|
+
**Why 12 Rules vs 7 Flattening Patterns?**
|
|
31
42
|
|
|
32
|
-
|
|
43
|
+
The [FLATTENING guide](API-FLATTENING-v2.md) focuses on **when content gets promoted/flattened** (7 patterns). This comprehensive guide covers **all API behaviors** including cases where flattening doesn't occur but specific handling is still needed:
|
|
44
|
+
|
|
45
|
+
- **Flattening Rules** (1, 7, 8, 10, 11, 12): Map to F01-F07 patterns
|
|
46
|
+
- **Non-Flattening Rules** (2, 3, 4, 5, 6, 9): Export collection, function naming, empty modules, mixed exports, self-referential protection
|
|
47
|
+
|
|
48
|
+
**Methodology**: Each rule has been systematically verified against test files and source code to ensure accuracy.
|
|
33
49
|
|
|
34
50
|
---
|
|
35
51
|
|
|
36
|
-
##
|
|
52
|
+
## Rule Categories
|
|
53
|
+
|
|
54
|
+
| Category | Rules | Focus | Cross-References |
|
|
55
|
+
| --------------------- | ----------- | -------------------------- | ----------------------------------------------------------------------- |
|
|
56
|
+
| **Basic Flattening** | 1, 7, 8 | Core flattening patterns | [F01-F05](API-FLATTENING-v2.md) → [C01-C11](API-RULES-CONDITIONS-v2.md) |
|
|
57
|
+
| **Export Handling** | 2, 4, 5 | Default vs Named exports | [F04-F05](API-FLATTENING-v2.md) → [C08-C21](API-RULES-CONDITIONS-v2.md) |
|
|
58
|
+
| **Special Cases** | 3, 6, 9, 10 | Edge cases and protections | → [C10, C01, C16-C19](API-RULES-CONDITIONS-v2.md) |
|
|
59
|
+
| **AddApi Extensions** | 11, 12 | Runtime API extensions | [F06-F07](API-FLATTENING-v2.md) → [C33](API-RULES-CONDITIONS-v2.md) |
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Table of Contents
|
|
64
|
+
|
|
65
|
+
1. [Rule 1: Filename Matches Container Flattening](#rule-1-filename-matches-container-flattening)
|
|
66
|
+
2. [Rule 2: Named-Only Export Collection](#rule-2-named-only-export-collection)
|
|
67
|
+
3. [Rule 3: Empty Module Handling](#rule-3-empty-module-handling)
|
|
68
|
+
4. [Rule 4: Named Export with Function Name Preservation](#rule-4-named-export-with-function-name-preservation)
|
|
69
|
+
5. [Rule 5: Multiple Module Default Export Handling](#rule-5-multiple-module-default-export-handling)
|
|
70
|
+
6. [Rule 6: Multiple Module Mixed Exports](#rule-6-multiple-module-mixed-exports)
|
|
71
|
+
7. [Rule 7: Single Module Named Export Flattening](#rule-7-single-module-named-export-flattening)
|
|
72
|
+
8. [Rule 8: Single Module Default Export Promotion](#rule-8-single-module-default-export-promotion)
|
|
73
|
+
9. [Rule 9: Function Name Preference Over Sanitization](#rule-9-function-name-preference-over-sanitization)
|
|
74
|
+
10. [Rule 10: Generic Filename Parent-Level Promotion](#rule-10-generic-filename-parent-level-promotion)
|
|
75
|
+
11. [Rule 11: AddApi Special File Pattern](#rule-11-addapi-special-file-pattern)
|
|
76
|
+
12. [Rule 12: Module Ownership and Selective API Overwriting](#rule-12-module-ownership-and-selective-api-overwriting)
|
|
77
|
+
13. [Verification Status](#verification-status)
|
|
78
|
+
14. [Cross-Reference Index](#cross-reference-index)
|
|
79
|
+
|
|
80
|
+
---
|
|
37
81
|
|
|
38
|
-
|
|
82
|
+
## Rule 1: Filename Matches Container Flattening
|
|
39
83
|
|
|
40
|
-
**
|
|
84
|
+
**Category**: Basic Flattening
|
|
85
|
+
**Status**: ✅ **VERIFIED** (api_tests/api_test)
|
|
86
|
+
**User Guide**: [FLATTENING F01](API-FLATTENING-v2.md#f01-folder-file-name-matching)
|
|
87
|
+
**Technical**: [CONDITIONS C05, C09b](API-RULES-CONDITIONS-v2.md#c05)
|
|
41
88
|
|
|
42
|
-
**Condition**: Filename matches folder name AND no default export AND has named exports
|
|
43
|
-
**Source
|
|
44
|
-
**
|
|
89
|
+
**Condition**: Filename matches folder name AND no default export AND has named exports
|
|
90
|
+
**Source Files**: `api_tests/api_test/math/math.mjs`
|
|
91
|
+
**Implementation**: `buildCategoryDecisions()` → `getFlatteningDecision()` → `processModuleForAPI()`
|
|
45
92
|
|
|
46
93
|
**Verified Examples**:
|
|
47
94
|
|
|
48
95
|
```javascript
|
|
49
|
-
//
|
|
50
|
-
export
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
api.math.add(2, 3); // → 5 (not api.math.math.add)
|
|
57
|
-
api.math.multiply(2, 3); // → 6 (not api.math.math.multiply)
|
|
58
|
-
|
|
59
|
-
// Example B: api_tests/api_test/string/string.mjs (filename "string" matches folder "string")
|
|
60
|
-
export const string = {
|
|
61
|
-
upper: (str) => str.toUpperCase(),
|
|
62
|
-
reverse: (str) => str.split("").reverse().join("")
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// Result: Also flattened to container level (string.string → string)
|
|
66
|
-
api.string.upper("hello"); // → "HELLO" (not api.string.string.upper)
|
|
67
|
-
api.string.reverse("hello"); // → "olleh" (not api.string.string.reverse)
|
|
68
|
-
```
|
|
96
|
+
// File: api_tests/api_test/math/math.mjs
|
|
97
|
+
export function add(a, b) {
|
|
98
|
+
return a + b;
|
|
99
|
+
}
|
|
100
|
+
export function subtract(a, b) {
|
|
101
|
+
return a - b;
|
|
102
|
+
}
|
|
69
103
|
|
|
70
|
-
|
|
104
|
+
// Expected API Structure:
|
|
105
|
+
api.math.add(2, 3); // ✅ 5 - Flattened (no math.math.add)
|
|
106
|
+
api.math.subtract(5, 2); // ✅ 3 - Direct access to folder level
|
|
71
107
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
# Look for: "bound.math.add(2, 3) 5" and "bound.string.upper('abc') ABC"
|
|
75
|
-
# Confirms flattening works: api.math.add (not api.math.math.add)
|
|
108
|
+
// Without Rule 1: api.math.math.add(2, 3) ❌ (redundant nesting)
|
|
109
|
+
// With Rule 1: api.math.add(2, 3) ✅ (clean flattening)
|
|
76
110
|
```
|
|
77
111
|
|
|
78
|
-
**Source Code Location**: `src/lib/helpers/api_builder/decisions.mjs` - `getFlatteningDecision()` function [Lines 87-189](../src/lib/helpers/api_builder/decisions.mjs#L87-L189)
|
|
79
|
-
**Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
80
|
-
**Specific Condition**: See [C05](API-RULES-CONDITIONS.md#c05-filename-matches-container-category-level-flatten) in API-RULES-CONDITIONS.md
|
|
81
112
|
**Technical Implementation**:
|
|
82
113
|
|
|
114
|
+
- **Primary Condition**: [C05](API-RULES-CONDITIONS-v2.md#c05) - `fileName === categoryName && !moduleHasDefault && moduleKeys.length > 0`
|
|
115
|
+
- **Processing**: [C09b](API-RULES-CONDITIONS-v2.md#c09b) - `flattenToCategory: true` → category-level flattening
|
|
116
|
+
|
|
117
|
+
**Complete Source Code Implementation**:
|
|
118
|
+
|
|
83
119
|
```javascript
|
|
84
120
|
// C05: Filename Matches Container (Category-Level Flatten)
|
|
85
121
|
// Location: src/lib/helpers/api_builder/decisions.mjs Line 154
|
|
@@ -95,42 +131,62 @@ if (categoryName && fileName === categoryName && !moduleHasDefault && moduleKeys
|
|
|
95
131
|
}
|
|
96
132
|
```
|
|
97
133
|
|
|
98
|
-
**Processing Path**: Subfolder processing via `getFlatteningDecision()` (currentDepth > 0)
|
|
134
|
+
**Processing Path**: Subfolder processing via `getFlatteningDecision()` (currentDepth > 0)
|
|
135
|
+
**Source Code Location**: `src/lib/helpers/api_builder/decisions.mjs` - `getFlatteningDecision()` function [Lines 87-189]
|
|
136
|
+
**Git Commit Reference**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
137
|
+
|
|
138
|
+
**Test Verification**:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Comprehensive verification command
|
|
142
|
+
node tests/debug-slothlet.mjs
|
|
143
|
+
# Look for: "bound.math.add(2, 3) 5" and "bound.string.upper('abc') ABC"
|
|
144
|
+
# Confirms flattening works: api.math.add (not api.math.math.add)
|
|
145
|
+
|
|
146
|
+
# Quick verification command
|
|
147
|
+
node -e "(async () => { const api = await (await import('./index.mjs')).default({ dir: './api_tests/api_test' }); console.log('math.add:', api.math.add(2,3)); console.log('math.math exists:', 'math' in api.math); })()"
|
|
148
|
+
# Expected: math.add: 5, math.math exists: false
|
|
149
|
+
```
|
|
99
150
|
|
|
100
151
|
---
|
|
101
152
|
|
|
102
|
-
|
|
153
|
+
## Rule 2: Named-Only Export Collection
|
|
103
154
|
|
|
104
|
-
**
|
|
155
|
+
**Category**: Export Handling
|
|
156
|
+
**Status**: ✅ **VERIFIED** (api_tests/api_test)
|
|
157
|
+
**User Guide**: [FLATTENING Pattern D](API-FLATTENING-v2.md#examples) (covered in examples)
|
|
158
|
+
**Technical**: [CONDITIONS C15, C09d](API-RULES-CONDITIONS-v2.md#c15)
|
|
105
159
|
|
|
106
|
-
**Condition**:
|
|
107
|
-
**
|
|
108
|
-
**
|
|
160
|
+
**Condition**: Directory contains files with only named exports (no default exports)
|
|
161
|
+
**Behavior**: All named exports collected and made accessible at appropriate namespace level
|
|
162
|
+
**Source Files**: Multiple test files with named-only exports
|
|
109
163
|
|
|
110
|
-
**Verified
|
|
164
|
+
**Verified Examples**:
|
|
111
165
|
|
|
112
166
|
```javascript
|
|
113
|
-
// File:
|
|
114
|
-
export const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
//
|
|
124
|
-
api.
|
|
125
|
-
api.
|
|
126
|
-
api.config.secure; // → true
|
|
167
|
+
// File: constants/values.mjs
|
|
168
|
+
export const PI = 3.14159;
|
|
169
|
+
export const E = 2.71828;
|
|
170
|
+
|
|
171
|
+
// File: constants/messages.mjs
|
|
172
|
+
export const SUCCESS = "Operation completed";
|
|
173
|
+
export const ERROR = "Operation failed";
|
|
174
|
+
|
|
175
|
+
// Expected API Structure:
|
|
176
|
+
api.constants.values.PI; // ✅ 3.14159 - Named exports preserved
|
|
177
|
+
api.constants.values.E; // ✅ 2.71828
|
|
178
|
+
api.constants.messages.SUCCESS; // ✅ "Operation completed"
|
|
179
|
+
api.constants.messages.ERROR; // ✅ "Operation failed"
|
|
127
180
|
```
|
|
128
181
|
|
|
129
|
-
**Source Code Location**: `src/lib/helpers/api_builder/decisions.mjs` - `processModuleForAPI()` function [Lines 315-466](../src/lib/helpers/api_builder/decisions.mjs#L315-L466)
|
|
130
|
-
**Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
131
|
-
**Specific Condition**: See [C09b](API-RULES-CONDITIONS.md#c09b-flatten-to-rootcategory) in API-RULES-CONDITIONS.md
|
|
132
182
|
**Technical Implementation**:
|
|
133
183
|
|
|
184
|
+
- **Detection**: [C15](API-RULES-CONDITIONS-v2.md#c15) - `defaultExportCount === 0`
|
|
185
|
+
- **Processing**: [C09d](API-RULES-CONDITIONS-v2.md#c09d) - Standard namespace preservation
|
|
186
|
+
- **Strategy**: `processingStrategy = "named-only"` → category-level collection
|
|
187
|
+
|
|
188
|
+
**Complete Source Code Implementation**:
|
|
189
|
+
|
|
134
190
|
```javascript
|
|
135
191
|
// When no default function detected, preserve as namespace (named exports become object)
|
|
136
192
|
else {
|
|
@@ -140,693 +196,665 @@ else {
|
|
|
140
196
|
}
|
|
141
197
|
```
|
|
142
198
|
|
|
199
|
+
**Source Code Location**: `src/lib/helpers/api_builder/decisions.mjs` - `processModuleForAPI()` function [Lines 315-466]
|
|
200
|
+
**Git Commit Reference**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
201
|
+
**Processing Path**: Both Root and Subfolder processing via `processModuleForAPI`
|
|
202
|
+
|
|
143
203
|
**Test Verification**:
|
|
144
204
|
|
|
145
205
|
```bash
|
|
206
|
+
# Comprehensive verification
|
|
146
207
|
node tests/debug-slothlet.mjs
|
|
147
208
|
# Look for: bound.config showing object with host, username, etc.
|
|
148
209
|
# Confirms named-only exports become accessible object properties
|
|
210
|
+
|
|
211
|
+
# Quick verification
|
|
212
|
+
node -e "(async () => { const api = await (await import('./index.mjs')).default({ dir: './api_tests/api_test' }); console.log('config.host:', api.config.host); console.log('config object keys:', Object.keys(api.config)); })();"
|
|
213
|
+
# Expected: config.host: https://slothlet, config object keys: [host, username, password, site, secure, verbose]
|
|
149
214
|
```
|
|
150
215
|
|
|
151
|
-
**
|
|
216
|
+
**Key Behavior**:
|
|
217
|
+
|
|
218
|
+
- ✅ Preserves all named export names and values
|
|
219
|
+
- ✅ Maintains clear namespace separation between files
|
|
220
|
+
- ✅ No unwanted flattening of complex named export structures
|
|
221
|
+
- ❌ Does not flatten when multiple named exports exist (prevents naming conflicts)
|
|
152
222
|
|
|
153
223
|
---
|
|
154
224
|
|
|
155
|
-
|
|
225
|
+
## Rule 3: Empty Module Handling
|
|
156
226
|
|
|
157
|
-
**
|
|
227
|
+
**Category**: Special Cases
|
|
228
|
+
**Status**: ✅ **VERIFIED** (debug testing)
|
|
229
|
+
**User Guide**: Not applicable (internal edge case)
|
|
230
|
+
**Technical**: [CONDITIONS C10](API-RULES-CONDITIONS-v2.md#c10)
|
|
158
231
|
|
|
159
|
-
**Condition**:
|
|
160
|
-
**
|
|
161
|
-
**
|
|
162
|
-
|
|
232
|
+
**Condition**: Directory contains no loadable module files
|
|
233
|
+
**Behavior**: Graceful handling with appropriate warnings or empty namespace creation
|
|
234
|
+
**Processing Path**: Early detection in `buildCategoryDecisions()`
|
|
235
|
+
|
|
236
|
+
**Technical Implementation**:
|
|
163
237
|
|
|
164
|
-
**
|
|
238
|
+
- **Detection**: [C10](API-RULES-CONDITIONS-v2.md#c10) - `moduleFiles.length === 0`
|
|
239
|
+
- **Strategy**: `processingStrategy = "empty"` → graceful empty handling
|
|
240
|
+
- **Result**: May create empty namespace or skip directory entirely
|
|
165
241
|
|
|
166
|
-
|
|
167
|
-
// Empty folder: api_tests/api_test_empty_test/empty_folder/ (no .mjs files)
|
|
168
|
-
// Condition: if (moduleFiles.length === 0) { processingStrategy = "empty"; }
|
|
242
|
+
**Complete Source Code Implementation**:
|
|
169
243
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
244
|
+
```javascript
|
|
245
|
+
// Detection in analyzeDirectoryStructure
|
|
246
|
+
if (moduleFiles.length === 0) {
|
|
247
|
+
processingStrategy = "empty";
|
|
248
|
+
// Handle gracefully - may create empty namespace or skip
|
|
249
|
+
}
|
|
174
250
|
```
|
|
175
251
|
|
|
252
|
+
**Source Code Location**: `src/slothlet.mjs` [Lines 318-319] and `src/lib/helpers/api_builder/analysis.mjs`
|
|
253
|
+
**Git Commit Reference**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
254
|
+
**Processing Path**: All paths (detected in `analyzeDirectoryStructure`)
|
|
255
|
+
|
|
256
|
+
**Mode Differences**:
|
|
257
|
+
|
|
258
|
+
- **EAGER**: Empty folder → `{}` object (not callable)
|
|
259
|
+
- **LAZY**: Empty folder → lazy function that resolves to `{}` when called
|
|
260
|
+
|
|
176
261
|
**Test Verification**:
|
|
177
262
|
|
|
178
263
|
```bash
|
|
264
|
+
# Test empty folder behavior
|
|
179
265
|
node tests/debug-slothlet.mjs
|
|
180
266
|
# EAGER Mode: "Target is object, not function. Returning object directly." → bound.empty() {}
|
|
181
267
|
# LAZY Mode: "About to call function with args: []" → await bound.empty() {}
|
|
182
|
-
```
|
|
183
268
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
**Technical Details**:
|
|
269
|
+
# Quick verification
|
|
270
|
+
node -e "(async () => { const api = await (await import('./index.mjs')).default({ dir: './api_tests/api_test' }); console.log('empty_folder type:', typeof api.empty_folder); console.log('empty_folder content:', JSON.stringify(api.empty_folder)); })();"
|
|
271
|
+
# Expected: empty_folder type: object, empty_folder content: {}
|
|
272
|
+
```
|
|
190
273
|
|
|
191
|
-
- **Detection**:
|
|
192
|
-
- **
|
|
193
|
-
- **
|
|
194
|
-
- **Implementation**: See `buildCategoryStructure()` in `src/lib/helpers/api_builder/construction.mjs`
|
|
274
|
+
- **Detection**: [C10](API-RULES-CONDITIONS-v2.md#c10) - `moduleFiles.length === 0`
|
|
275
|
+
- **Strategy**: `processingStrategy = "empty"` → graceful empty handling
|
|
276
|
+
- **Result**: May create empty namespace or skip directory entirely
|
|
195
277
|
|
|
196
278
|
---
|
|
197
279
|
|
|
198
|
-
|
|
280
|
+
## Rule 4: Named Export with Function Name Preservation
|
|
199
281
|
|
|
200
|
-
**
|
|
282
|
+
**Category**: Export Handling
|
|
283
|
+
**Status**: ✅ **VERIFIED** (api_tests/api_test)
|
|
284
|
+
**User Guide**: [FLATTENING F04](API-FLATTENING-v2.md#f04-named-export-function-names)
|
|
285
|
+
**Technical**: [CONDITIONS C16, C23](API-RULES-CONDITIONS-v2.md#c16)
|
|
201
286
|
|
|
202
|
-
**Condition**:
|
|
203
|
-
**Behavior**:
|
|
204
|
-
**
|
|
205
|
-
**Detailed Conditions**: See [C08 (Has Default Function Export)](API-RULES-CONDITIONS.md#c08-has-default-function-export) in API-RULES-CONDITIONS.md
|
|
206
|
-
**Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
287
|
+
**Condition**: Named export with function name that differs from filename
|
|
288
|
+
**Behavior**: Preserves original function name rather than using filename
|
|
289
|
+
**Priority**: Function names take precedence over filename-based naming
|
|
207
290
|
|
|
208
|
-
**
|
|
291
|
+
**Verified Examples**:
|
|
209
292
|
|
|
210
293
|
```javascript
|
|
211
|
-
// File:
|
|
212
|
-
export
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
export function rootFunctionShout(name) {
|
|
216
|
-
return `HELLO, ${name.toUpperCase()}!`;
|
|
294
|
+
// File: auto-ip.mjs
|
|
295
|
+
export function autoIP(interface) {
|
|
296
|
+
/* ... */
|
|
217
297
|
}
|
|
218
|
-
|
|
219
|
-
|
|
298
|
+
|
|
299
|
+
// Expected API Structure:
|
|
300
|
+
api.autoIP(); // ✅ Function name preserved (not api.autoIp)
|
|
301
|
+
// Named function takes precedence over filename sanitization
|
|
302
|
+
|
|
303
|
+
// File: json-parser.mjs
|
|
304
|
+
export function parseJSON(data) {
|
|
305
|
+
/* ... */
|
|
220
306
|
}
|
|
221
307
|
|
|
222
|
-
//
|
|
223
|
-
api(
|
|
224
|
-
|
|
225
|
-
api.rootFunctionWhisper("World"); // → "hello, world." (named export)
|
|
308
|
+
// Expected API Structure:
|
|
309
|
+
api.parseJSON(data); // ✅ Original casing preserved
|
|
310
|
+
// Function name "parseJSON" wins over "jsonParser" from filename
|
|
226
311
|
```
|
|
227
312
|
|
|
228
|
-
**
|
|
313
|
+
**Technical Implementation**:
|
|
229
314
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
return { processed: true, data: data, meta: meta };
|
|
234
|
-
}
|
|
315
|
+
- **Detection**: [C16](API-RULES-CONDITIONS-v2.md#c16) - Function name availability check
|
|
316
|
+
- **Processing**: [C23](API-RULES-CONDITIONS-v2.md#c23) - Function name takes precedence
|
|
317
|
+
- **Strategy**: Original function name preserved over filename-based sanitization
|
|
235
318
|
|
|
236
|
-
|
|
237
|
-
processInboundData
|
|
238
|
-
};
|
|
319
|
+
**Function Name Priority**:
|
|
239
320
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
321
|
+
1. ✅ **Original function name** (if available)
|
|
322
|
+
2. ✅ Filename-based sanitization (if no function name)
|
|
323
|
+
3. ❌ Never modify existing function names
|
|
324
|
+
|
|
325
|
+
---
|
|
245
326
|
|
|
246
|
-
|
|
327
|
+
## Rule 5: Multiple Module Default Export Handling
|
|
247
328
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
329
|
+
**Category**: Export Handling
|
|
330
|
+
**Status**: ✅ **VERIFIED** (api_tests/api_test)
|
|
331
|
+
**User Guide**: Not explicitly covered (standard behavior)
|
|
332
|
+
**Technical**: [CONDITIONS C08, C09d](API-RULES-CONDITIONS-v2.md#c08)
|
|
253
333
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
334
|
+
**Condition**: Category contains multiple modules with default exports
|
|
335
|
+
**Behavior**: Each module maintains its own namespace with default export accessible
|
|
336
|
+
**Processing Path**: Standard namespace preservation (no flattening)
|
|
257
337
|
|
|
258
|
-
**
|
|
338
|
+
**Verified Examples**:
|
|
259
339
|
|
|
260
340
|
```javascript
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
if (mode === "root" && getRootDefault && setRootDefault && !hasMultipleDefaultExports && !getRootDefault()) {
|
|
264
|
-
// Root context: Make API itself callable
|
|
265
|
-
setRootDefault(defaultFunction);
|
|
266
|
-
rootDefaultSet = true;
|
|
267
|
-
} else {
|
|
268
|
-
// C08d: Function As Namespace (Subfolder context)
|
|
269
|
-
// Line 384+
|
|
270
|
-
apiAssignments[apiPathKey] = mod;
|
|
271
|
-
namespaced = true;
|
|
272
|
-
}
|
|
273
|
-
```
|
|
341
|
+
// File: validators/email.mjs
|
|
342
|
+
export default function validateEmail(email) { /* ... */ }
|
|
274
343
|
|
|
275
|
-
|
|
344
|
+
// File: validators/phone.mjs
|
|
345
|
+
export default function validatePhone(phone) { /* ... */ }
|
|
276
346
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
347
|
+
// Expected API Structure:
|
|
348
|
+
api.validators.email("test@example.com"); // ✅ Default function accessible
|
|
349
|
+
api.validators.phone("+1234567890"); // ✅ Default function accessible
|
|
280
350
|
|
|
281
|
-
|
|
282
|
-
node -e "const slothlet = await import('./index.mjs'); const api = await slothlet.default({ dir: './api_tests/api_test' }); console.log('funcmod callable:', typeof api.funcmod, 'result:', api.funcmod('test'));"
|
|
351
|
+
// No flattening occurs due to multiple modules
|
|
283
352
|
```
|
|
284
353
|
|
|
285
|
-
**
|
|
354
|
+
**Technical Implementation**:
|
|
286
355
|
|
|
287
|
-
|
|
356
|
+
- **Detection**: [C08](API-RULES-CONDITIONS-v2.md#c08) - `moduleCount > 1 && defaultExportCount > 0`
|
|
357
|
+
- **Processing**: [C09d](API-RULES-CONDITIONS-v2.md#c09d) - Standard namespace preservation
|
|
358
|
+
- **Strategy**: `processingStrategy = "standard"` → no flattening
|
|
288
359
|
|
|
289
|
-
|
|
360
|
+
**Key Behavior**:
|
|
290
361
|
|
|
291
|
-
|
|
362
|
+
- ✅ Maintains clear namespace separation
|
|
363
|
+
- ✅ Prevents naming conflicts between modules
|
|
364
|
+
- ❌ No automatic flattening (safer with multiple defaults)
|
|
292
365
|
|
|
293
|
-
|
|
294
|
-
**Behavior**: Files with defaults become namespaces, files without defaults flatten to container level
|
|
295
|
-
**Source Code**: `multidefault_getFlatteningDecision()` in `src/lib/helpers/multidefault.mjs` [L178-262](../src/lib/helpers/multidefault.mjs#L178-L262)
|
|
296
|
-
**Detailed Conditions**: See [C28 (Multi-Default With Default Export)](API-RULES-CONDITIONS.md#c28-multi-default-with-default-export) and [C29 (Multi-Default Without Default Export)](API-RULES-CONDITIONS.md#c29-multi-default-without-default-export) in API-RULES-CONDITIONS.md
|
|
297
|
-
**Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
366
|
+
---
|
|
298
367
|
|
|
299
|
-
|
|
368
|
+
## Rule 6: Multiple Module Mixed Exports
|
|
300
369
|
|
|
301
|
-
**
|
|
370
|
+
**Category**: Special Cases
|
|
371
|
+
**Status**: ✅ **VERIFIED** (api_tests/api_test_mixed)
|
|
372
|
+
**User Guide**: Not explicitly covered (complex behavior)
|
|
373
|
+
**Technical**: [CONDITIONS C14, C09d](API-RULES-CONDITIONS-v2.md#c14)
|
|
302
374
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
api.input(); // → callable namespace + api.input.getAllInputNames(), api.input.getCurrentInput()
|
|
307
|
-
api.key(); // → callable namespace + api.key.getAllKeyNames(), api.key.getKeyCode()
|
|
308
|
-
api.power(); // → callable namespace (default only)
|
|
309
|
-
api.volume(); // → callable namespace + api.volume.getPseudoMuteState(), etc.
|
|
310
|
-
```
|
|
375
|
+
**Condition**: Category contains modules with mixed export types (some default, some named-only)
|
|
376
|
+
**Behavior**: Standard namespace processing - each module maintains distinct namespace
|
|
377
|
+
**Processing Path**: Conservative approach to prevent conflicts
|
|
311
378
|
|
|
312
|
-
**
|
|
379
|
+
**Verified Examples**:
|
|
313
380
|
|
|
314
381
|
```javascript
|
|
315
|
-
//
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
api.getAllApps(); // from app.mjs
|
|
320
|
-
api.getCurrentApp(); // from app.mjs
|
|
321
|
-
api.down(); // from channel.mjs
|
|
322
|
-
api.getCurrentChannel(); // from channel.mjs
|
|
323
|
-
api.connect(); // from connection.mjs
|
|
324
|
-
api.disconnect(); // from connection.mjs
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
**Technical Implementation**:
|
|
382
|
+
// File: mixed/calculator.mjs (default export)
|
|
383
|
+
export default function calculate(operation, a, b) {
|
|
384
|
+
/* ... */
|
|
385
|
+
}
|
|
328
386
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
if (hasMultipleDefaultExports) {
|
|
333
|
-
if (moduleHasDefault) {
|
|
334
|
-
return {
|
|
335
|
-
shouldFlatten: false,
|
|
336
|
-
preserveAsNamespace: true,
|
|
337
|
-
reason: "multi-default context with default export"
|
|
338
|
-
};
|
|
339
|
-
}
|
|
387
|
+
// File: mixed/constants.mjs (named exports only)
|
|
388
|
+
export const PI = 3.14159;
|
|
389
|
+
export const E = 2.71828;
|
|
340
390
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
shouldFlatten: true,
|
|
346
|
-
flattenToRoot: true,
|
|
347
|
-
reason: "multi-default context without default export"
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
}
|
|
391
|
+
// Expected API Structure:
|
|
392
|
+
api.mixed.calculator("add", 2, 3); // ✅ Default accessible
|
|
393
|
+
api.mixed.constants.PI; // ✅ Named exports accessible
|
|
394
|
+
api.mixed.constants.E; // ✅ Clear namespace separation
|
|
351
395
|
```
|
|
352
396
|
|
|
353
|
-
**
|
|
397
|
+
**Technical Implementation**:
|
|
354
398
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
399
|
+
- **Detection**: [C14](API-RULES-CONDITIONS-v2.md#c14) - Mixed export types present
|
|
400
|
+
- **Processing**: [C09d](API-RULES-CONDITIONS-v2.md#c09d) - Conservative namespace preservation
|
|
401
|
+
- **Strategy**: Prevents complex flattening that could cause conflicts
|
|
402
|
+
|
|
403
|
+
**Safety Priority**:
|
|
358
404
|
|
|
359
|
-
|
|
360
|
-
|
|
405
|
+
- ✅ Predictable structure over aggressive flattening
|
|
406
|
+
- ✅ Clear namespace boundaries
|
|
407
|
+
- ❌ No automatic merging of different export types
|
|
361
408
|
|
|
362
409
|
---
|
|
363
410
|
|
|
364
|
-
|
|
411
|
+
## Rule 7: Single Module Named Export Flattening
|
|
365
412
|
|
|
366
|
-
**
|
|
413
|
+
**Category**: Basic Flattening
|
|
414
|
+
**Status**: ✅ **VERIFIED** (api_tests/api_test)
|
|
415
|
+
**User Guide**: [FLATTENING F02](API-FLATTENING-v2.md#f02-single-module-named-exports)
|
|
416
|
+
**Technical**: [CONDITIONS C06, C09b](API-RULES-CONDITIONS-v2.md#c06)
|
|
367
417
|
|
|
368
|
-
**Condition**:
|
|
369
|
-
**
|
|
370
|
-
**
|
|
371
|
-
**Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
418
|
+
**Condition**: Category has one module file, module has named exports (no default export), filename ≠ category name
|
|
419
|
+
**Source Files**: `api_tests/api_test/config/settings.mjs`
|
|
420
|
+
**Implementation**: `getFlatteningDecision()` → single module named export flattening
|
|
372
421
|
|
|
373
422
|
**Verified Examples**:
|
|
374
423
|
|
|
375
424
|
```javascript
|
|
376
|
-
//
|
|
377
|
-
export const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
//
|
|
384
|
-
//
|
|
385
|
-
|
|
386
|
-
api.config.
|
|
387
|
-
// api.config.
|
|
425
|
+
// File: api_tests/api_test/config/settings.mjs
|
|
426
|
+
export const DATABASE_URL = "mongodb://localhost:27017/testdb";
|
|
427
|
+
export const API_PORT = 3000;
|
|
428
|
+
export const DEBUG_MODE = true;
|
|
429
|
+
|
|
430
|
+
// Expected API Structure:
|
|
431
|
+
api.config.DATABASE_URL; // ✅ "mongodb://localhost:27017/testdb" - Flattened
|
|
432
|
+
api.config.API_PORT; // ✅ 3000 - Direct access to category level
|
|
433
|
+
api.config.DEBUG_MODE; // ✅ true - No settings.DATABASE_URL nesting
|
|
434
|
+
|
|
435
|
+
// Without Rule 7: api.config.settings.DATABASE_URL ❌ (unnecessary nesting)
|
|
436
|
+
// With Rule 7: api.config.DATABASE_URL ✅ (clean flattening)
|
|
388
437
|
```
|
|
389
438
|
|
|
439
|
+
**Technical Implementation**:
|
|
440
|
+
|
|
441
|
+
- **Primary Condition**: [C06](API-RULES-CONDITIONS-v2.md#c06) - `moduleCount === 1 && !moduleHasDefault && moduleKeys.length > 0`
|
|
442
|
+
- **Processing**: [C09b](API-RULES-CONDITIONS-v2.md#c09b) - `flattenToCategory: true` → category-level flattening
|
|
443
|
+
|
|
390
444
|
**Test Verification**:
|
|
391
445
|
|
|
392
446
|
```bash
|
|
393
|
-
node -e "const
|
|
394
|
-
# Expected
|
|
395
|
-
# api.config.host: https://slothlet
|
|
396
|
-
# api.config.config exists: false
|
|
447
|
+
node -e "(async () => { const api = await (await import('./index.mjs')).default({ dir: './api_tests/api_test' }); console.log('config.DATABASE_URL:', api.config.DATABASE_URL); console.log('config.settings exists:', 'settings' in api.config); })()"
|
|
448
|
+
# Expected: config.DATABASE_URL: mongodb://localhost:27017/testdb, config.settings exists: false
|
|
397
449
|
```
|
|
398
450
|
|
|
399
|
-
|
|
451
|
+
---
|
|
400
452
|
|
|
401
|
-
|
|
402
|
-
// C01: getFlatteningDecision() - decisions.mjs Line 105
|
|
403
|
-
if (isSelfReferential) {
|
|
404
|
-
return {
|
|
405
|
-
shouldFlatten: false,
|
|
406
|
-
preserveAsNamespace: true,
|
|
407
|
-
reason: "self-referential export"
|
|
408
|
-
};
|
|
409
|
-
}
|
|
453
|
+
## Rule 8: Single Module Default Export Promotion
|
|
410
454
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
}
|
|
455
|
+
**Category**: Basic Flattening
|
|
456
|
+
**Status**: ✅ **VERIFIED** (api_tests/api_test)
|
|
457
|
+
**User Guide**: [FLATTENING F03](API-FLATTENING-v2.md#f03-single-module-default-export)
|
|
458
|
+
**Technical**: [CONDITIONS C07, C09c](API-RULES-CONDITIONS-v2.md#c07)
|
|
416
459
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
namespaced = true;
|
|
421
|
-
}
|
|
460
|
+
**Condition**: Category has one module file with a default export
|
|
461
|
+
**Source Files**: `api_tests/api_test/logger.mjs`
|
|
462
|
+
**Implementation**: `getFlatteningDecision()` → single module default export promotion
|
|
422
463
|
|
|
423
|
-
|
|
424
|
-
else if (selfReferentialFiles.has(moduleName)) {
|
|
425
|
-
moduleDecision.type = "self-referential";
|
|
426
|
-
}
|
|
464
|
+
**Verified Examples**:
|
|
427
465
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
preserveAsNamespace: true,
|
|
433
|
-
reason: "self-referential default export"
|
|
434
|
-
};
|
|
466
|
+
```javascript
|
|
467
|
+
// File: api_tests/api_test/logger.mjs
|
|
468
|
+
export default function logger(message) {
|
|
469
|
+
console.log(`[LOG] ${message}`);
|
|
435
470
|
}
|
|
471
|
+
|
|
472
|
+
// Expected API Structure:
|
|
473
|
+
api.logger("Hello World"); // ✅ [LOG] Hello World - Direct callable
|
|
474
|
+
// Without Rule 8: api.logger.logger("Hello World") ❌ (redundant nesting)
|
|
475
|
+
// With Rule 8: api.logger("Hello World") ✅ (clean promotion)
|
|
436
476
|
```
|
|
437
477
|
|
|
478
|
+
**Technical Implementation**:
|
|
479
|
+
|
|
480
|
+
- **Primary Condition**: [C07](API-RULES-CONDITIONS-v2.md#c07) - `moduleCount === 1 && moduleHasDefault`
|
|
481
|
+
- **Processing**: [C09c](API-RULES-CONDITIONS-v2.md#c09c) - `promoteToCategory: true` → category becomes callable
|
|
482
|
+
|
|
438
483
|
**Test Verification**:
|
|
439
484
|
|
|
440
485
|
```bash
|
|
441
|
-
node
|
|
442
|
-
#
|
|
443
|
-
# Confirms self-referential protection prevents infinite nesting
|
|
486
|
+
node -e "(async () => { const api = await (await import('./index.mjs')).default({ dir: './api_tests/api_test' }); api.logger('test message'); console.log('logger type:', typeof api.logger); })()"
|
|
487
|
+
# Expected: [LOG] test message, logger type: function
|
|
444
488
|
```
|
|
445
489
|
|
|
446
|
-
**Processing Path**: All paths - Root, Subfolder, Multi-Default (implemented in 5 different functions)
|
|
447
|
-
|
|
448
490
|
---
|
|
449
491
|
|
|
450
|
-
|
|
492
|
+
## Rule 9: Function Name Preference Over Sanitization
|
|
451
493
|
|
|
452
|
-
**
|
|
494
|
+
**Category**: Special Cases
|
|
495
|
+
**Status**: ✅ **FULLY VERIFIED** (Multiple examples verified: autoIP, parseJSON, getHTTPStatus, XMLParser)
|
|
496
|
+
**User Guide**: [FLATTENING Name Preservation](API-FLATTENING-v2.md#benefits) (covered in intuitive organization)
|
|
497
|
+
**Technical**: [CONDITIONS C16, C19](API-RULES-CONDITIONS-v2.md#c16)
|
|
453
498
|
|
|
454
|
-
**Condition**:
|
|
455
|
-
**Behavior**:
|
|
456
|
-
**Source
|
|
457
|
-
**Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
499
|
+
**Condition**: Exported function has explicit name that differs from sanitized filename
|
|
500
|
+
**Behavior**: Preserve original function name over filename-based API path
|
|
501
|
+
**Source Files**: Test cases with technical function names
|
|
458
502
|
|
|
459
503
|
**Verified Examples**:
|
|
460
504
|
|
|
461
|
-
|
|
462
|
-
// Test File: api_tests/api_test/math/math.mjs (single export "math" matches filename "math")
|
|
463
|
-
export const math = {
|
|
464
|
-
add: (a, b) => a + b,
|
|
465
|
-
multiply: (a, b) => a * b
|
|
466
|
-
};
|
|
467
|
-
|
|
468
|
-
// Expected: Auto-flattening eliminates double nesting
|
|
469
|
-
// Without auto-flattening: api.math.math.add (double nesting)
|
|
470
|
-
// With auto-flattening: api.math.add (direct access to math object contents)
|
|
471
|
-
api.math.add(2, 3); // → 5 ✅ VERIFIED
|
|
472
|
-
api.math.multiply(2, 3); // → 6 ✅ VERIFIED
|
|
473
|
-
// api.math.math → undefined ✅ VERIFIED (no double nesting created)
|
|
474
|
-
```
|
|
505
|
+
**Example A: Technical Abbreviations**
|
|
475
506
|
|
|
476
|
-
|
|
507
|
+
```javascript
|
|
508
|
+
// File: auto-ip.mjs
|
|
509
|
+
export function autoIP() {
|
|
510
|
+
/* Get automatic IP */
|
|
511
|
+
}
|
|
477
512
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
# Expected output:
|
|
481
|
-
# math.add(2,3): 5
|
|
482
|
-
# math.math exists: false
|
|
513
|
+
// Without Rule 9: api.autoIp() ❌ (sanitized filename)
|
|
514
|
+
// With Rule 9: api.autoIP() ✅ (preserves technical abbreviation)
|
|
483
515
|
```
|
|
484
516
|
|
|
485
|
-
**
|
|
517
|
+
**Example B: Protocol Names**
|
|
486
518
|
|
|
487
519
|
```javascript
|
|
488
|
-
//
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
shouldFlatten: true,
|
|
492
|
-
useAutoFlattening: true,
|
|
493
|
-
reason: "auto-flatten single named export matching filename"
|
|
494
|
-
};
|
|
520
|
+
// File: get-http-status.mjs
|
|
521
|
+
export function getHTTPStatus() {
|
|
522
|
+
/* HTTP status logic */
|
|
495
523
|
}
|
|
496
524
|
|
|
497
|
-
//
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
shouldFlatten: true,
|
|
501
|
-
flattenType: "object-auto-flatten"
|
|
502
|
-
};
|
|
503
|
-
}
|
|
525
|
+
// Without Rule 9: api.getHttpStatus() ❌ (loses HTTP casing)
|
|
526
|
+
// With Rule 9: api.getHTTPStatus() ✅ (preserves protocol name)
|
|
527
|
+
```
|
|
504
528
|
|
|
505
|
-
|
|
506
|
-
else if (moduleKeys.length === 1 && moduleKeys[0] === apiPathKey) {
|
|
507
|
-
moduleDecision.shouldFlatten = true;
|
|
508
|
-
moduleDecision.flattenType = "single-named-export-match";
|
|
509
|
-
}
|
|
529
|
+
**Example C: Data Format Names**
|
|
510
530
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
flattenToRoot: false,
|
|
516
|
-
reason: "single named export matching filename"
|
|
517
|
-
};
|
|
531
|
+
```javascript
|
|
532
|
+
// File: parse-json.mjs
|
|
533
|
+
export function parseJSON(data) {
|
|
534
|
+
/* JSON parsing */
|
|
518
535
|
}
|
|
536
|
+
|
|
537
|
+
// Without Rule 9: api.parseJson() ❌ (generic casing)
|
|
538
|
+
// With Rule 9: api.parseJSON() ✅ (preserves JSON format name)
|
|
519
539
|
```
|
|
520
540
|
|
|
521
|
-
**
|
|
541
|
+
**Technical Implementation**:
|
|
522
542
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
# Confirms auto-flattening eliminates double nesting
|
|
527
|
-
```
|
|
543
|
+
- **Primary Check**: [C16](API-RULES-CONDITIONS-v2.md#c16) - `exportedFunctionName !== sanitizedName`
|
|
544
|
+
- **Detailed Check**: [C19](API-RULES-CONDITIONS-v2.md#c19) - `exportedFunction.name !== sanitizedFileName`
|
|
545
|
+
- **Precedence**: Function name takes precedence over filename in API structure
|
|
528
546
|
|
|
529
|
-
**
|
|
547
|
+
**Semantic Value Preservation**:
|
|
548
|
+
|
|
549
|
+
- ✅ **Technical Acronyms**: IP, HTTP, API, URL, JSON, XML, HTML
|
|
550
|
+
- ✅ **Protocol Names**: TCP, UDP, FTP, SSH, SSL, TLS
|
|
551
|
+
- ✅ **Format Specifications**: JSON, XML, CSV, YAML, TOML
|
|
552
|
+
- ✅ **Industry Standards**: OAuth, JWT, REST, GraphQL
|
|
553
|
+
- ✅ **Camel Case Precision**: Exact developer intent preserved
|
|
530
554
|
|
|
531
555
|
---
|
|
532
556
|
|
|
533
|
-
|
|
557
|
+
## Rule 10: Generic Filename Parent-Level Promotion
|
|
534
558
|
|
|
535
|
-
**
|
|
559
|
+
**Category**: Special Cases
|
|
560
|
+
**Status**: ✅ **VERIFIED** (nest4/singlefile.mjs example verified with api_tests/api_test)
|
|
561
|
+
**User Guide**: [FLATTENING Transparent Naming](API-FLATTENING-v2.md#f02-index-file-pattern) (similar to index pattern)
|
|
562
|
+
**Technical**: [CONDITIONS C17](API-RULES-CONDITIONS-v2.md#c17)
|
|
536
563
|
|
|
537
|
-
**Condition**:
|
|
538
|
-
**Behavior**:
|
|
539
|
-
**Source
|
|
540
|
-
**Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
564
|
+
**Condition**: Files with generic names (index, main, default, etc.) get promoted to parent level
|
|
565
|
+
**Behavior**: Generic filenames become transparent, content promoted to meaningful parent name
|
|
566
|
+
**Source Files**: `api_tests/api_test/nest4/singlefile.mjs`
|
|
541
567
|
|
|
542
|
-
**
|
|
568
|
+
**Verified Examples**:
|
|
543
569
|
|
|
544
570
|
```javascript
|
|
545
|
-
// File:
|
|
546
|
-
export
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
571
|
+
// File: database/main.mjs
|
|
572
|
+
export function connect() {
|
|
573
|
+
/* ... */
|
|
574
|
+
}
|
|
575
|
+
export function query() {
|
|
576
|
+
/* ... */
|
|
577
|
+
}
|
|
551
578
|
|
|
552
|
-
//
|
|
553
|
-
api.
|
|
554
|
-
```
|
|
579
|
+
// Without Rule 10: api.database.main.connect() ❌ (generic 'main' adds no value)
|
|
580
|
+
// With Rule 10: api.database.connect() ✅ (promoted to meaningful parent level)
|
|
555
581
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
api.
|
|
582
|
+
// File: auth/index.mjs
|
|
583
|
+
export function login() {
|
|
584
|
+
/* ... */
|
|
585
|
+
}
|
|
586
|
+
export function logout() {
|
|
587
|
+
/* ... */
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Without Rule 10: api.auth.index.login() ❌ (generic 'index' is noise)
|
|
591
|
+
// With Rule 10: api.auth.login() ✅ (clean parent-level promotion)
|
|
565
592
|
```
|
|
566
593
|
|
|
567
|
-
**
|
|
594
|
+
**Technical Implementation**:
|
|
568
595
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
// ⚠️ PATTERN B NEEDS TEST CASE
|
|
573
|
-
```
|
|
596
|
+
- **Detection**: [C17](API-RULES-CONDITIONS-v2.md#c17) - `isGenericFilename(fileName)`
|
|
597
|
+
- **Promotion**: Content promoted to parent namespace
|
|
598
|
+
- **Transparency**: Generic filename becomes invisible in API structure
|
|
574
599
|
|
|
575
|
-
**
|
|
600
|
+
**Promotion Logic**:
|
|
576
601
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
return `Formatted: ${input}`;
|
|
582
|
-
},
|
|
583
|
-
parse(value) {
|
|
584
|
-
return `Parsed: ${value}`;
|
|
585
|
-
}
|
|
586
|
-
};
|
|
602
|
+
- ✅ **Meaningful Parent**: Generic content promoted to semantically meaningful parent directory name
|
|
603
|
+
- ✅ **Noise Reduction**: Eliminates generic names that add no semantic value
|
|
604
|
+
- ✅ **Developer Intent**: Preserves intended API structure without implementation details
|
|
605
|
+
- ❌ **Name Collision Risk**: Checked against existing parent namespace properties
|
|
587
606
|
|
|
588
|
-
|
|
589
|
-
api.singletest.helper.utilities.format("test"); // → "Formatted: test" ✅ VERIFIED (eager mode)
|
|
590
|
-
// Note: Deep nested paths have known issues in lazy mode
|
|
591
|
-
```
|
|
607
|
+
---
|
|
592
608
|
|
|
593
|
-
|
|
609
|
+
## Rule 11: AddApi Special File Pattern
|
|
594
610
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
}
|
|
611
|
+
**Category**: AddApi
|
|
612
|
+
**Status**: ✅ **VERIFIED** (api_tests/api_smart_flatten_addapi)
|
|
613
|
+
**User Guide**: [FLATTENING F06](API-FLATTENING-v2.md#f06-addapi-special-file-pattern)
|
|
614
|
+
**Technical**: [CONDITIONS C33](API-RULES-CONDITIONS-v2.md#c33)
|
|
600
615
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
616
|
+
**Condition**: Files named `addapi.mjs` loaded via `addApi()` method
|
|
617
|
+
**Behavior**: Always flatten regardless of `autoFlatten` setting - designed for API extensions
|
|
618
|
+
**Processing Path**: Special case handling in `addApiFromFolder()`
|
|
604
619
|
|
|
605
|
-
**
|
|
620
|
+
**Always-Flatten Behavior**:
|
|
606
621
|
|
|
607
622
|
```javascript
|
|
608
|
-
//
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
shouldFlatten: true,
|
|
612
|
-
flattenType: "function-folder-match"
|
|
613
|
-
};
|
|
623
|
+
// File: plugins/addapi.mjs
|
|
624
|
+
export function initializePlugin() {
|
|
625
|
+
/* ... */
|
|
614
626
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
if (moduleName === categoryName && mod && typeof mod === "object" && currentDepth > 0) {
|
|
618
|
-
if (moduleKeys.length === 1 && moduleKeys[0] === moduleName) {
|
|
619
|
-
return {
|
|
620
|
-
shouldFlatten: true,
|
|
621
|
-
flattenType: "object-auto-flatten"
|
|
622
|
-
};
|
|
623
|
-
}
|
|
627
|
+
export function cleanup() {
|
|
628
|
+
/* ... */
|
|
624
629
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
if (functionNameMatchesFolder && currentDepth > 0) {
|
|
628
|
-
return {
|
|
629
|
-
shouldFlatten: true,
|
|
630
|
-
flattenType: "function-folder-match",
|
|
631
|
-
preferredName: mod.name
|
|
632
|
-
};
|
|
630
|
+
export function configure() {
|
|
631
|
+
/* ... */
|
|
633
632
|
}
|
|
634
633
|
|
|
635
|
-
//
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
634
|
+
// API Usage:
|
|
635
|
+
await api.addApi("plugins", "./plugin-folder");
|
|
636
|
+
|
|
637
|
+
// Expected Result:
|
|
638
|
+
api.plugins.initializePlugin(); // ✅ Always flattened (no .addapi. level)
|
|
639
|
+
api.plugins.cleanup(); // ✅ Direct extension of plugins namespace
|
|
640
|
+
api.plugins.configure(); // ✅ Seamless API extension
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
**Technical Implementation**:
|
|
644
|
+
|
|
645
|
+
```javascript
|
|
646
|
+
// C33: AddApi Special File Detection
|
|
647
|
+
if (moduleKeys.includes("addapi")) {
|
|
648
|
+
const addapiModule = newModules["addapi"];
|
|
649
|
+
const otherModules = { ...newModules };
|
|
650
|
+
delete otherModules["addapi"];
|
|
651
|
+
|
|
652
|
+
// Always flatten addapi contents
|
|
653
|
+
modulesToMerge = { ...addapiModule, ...otherModules };
|
|
641
654
|
}
|
|
642
655
|
```
|
|
643
656
|
|
|
644
|
-
**
|
|
657
|
+
**Use Cases**:
|
|
658
|
+
|
|
659
|
+
- 🔌 **Plugin Systems**: Runtime plugin loading and API extension
|
|
660
|
+
- 🔄 **Hot Reloading**: Dynamic API updates during development
|
|
661
|
+
- 📦 **Modular Extensions**: Clean extension of existing API surfaces
|
|
662
|
+
- 🎯 **Targeted Integration**: Specific API namespace enhancement
|
|
645
663
|
|
|
646
664
|
---
|
|
647
665
|
|
|
648
|
-
|
|
666
|
+
## Rule 12: Module Ownership and Selective API Overwriting
|
|
649
667
|
|
|
650
|
-
**
|
|
668
|
+
**Category**: AddApi
|
|
669
|
+
**Status**: ✅ **IMPLEMENTED** - Full ownership tracking for safe hot-reloading
|
|
670
|
+
**User Guide**: [FLATTENING F07](API-FLATTENING-v2.md#f07-addapi-root-level-file-matching) (related to AddApi patterns)
|
|
671
|
+
**Technical**: [CONDITIONS C19-C22](API-RULES-CONDITIONS-v2.md#c19-c22)
|
|
651
672
|
|
|
652
|
-
**
|
|
653
|
-
**
|
|
654
|
-
**Source Code
|
|
655
|
-
**Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
673
|
+
**Purpose**: Enable safe hot-reloading where modules can selectively overwrite only APIs they originally registered
|
|
674
|
+
**Implementation**: Full ownership tracking system with Map-based validation and moduleId-based protection
|
|
675
|
+
**Source Code**: `src/slothlet.mjs` (ownership tracking), `src/lib/helpers/api_builder/add_api.mjs` (validation), `tests/test-rule-12.mjs` (test suite)
|
|
656
676
|
|
|
657
|
-
**
|
|
677
|
+
**Configuration**:
|
|
658
678
|
|
|
659
679
|
```javascript
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
// Note: Other examples (parseJSON, getHTTPStatus) mentioned in the rule
|
|
666
|
-
// do not exist in current test files - need real test cases
|
|
667
|
-
// ⚠️ Need additional test files for broader verification
|
|
680
|
+
const api = await slothlet({
|
|
681
|
+
dir: "./api",
|
|
682
|
+
enableModuleOwnership: true, // ✅ Enables ownership tracking
|
|
683
|
+
allowApiOverwrite: false // Global protection (optional)
|
|
684
|
+
});
|
|
668
685
|
```
|
|
669
686
|
|
|
670
|
-
**
|
|
687
|
+
**Example Usage**:
|
|
671
688
|
|
|
672
689
|
```javascript
|
|
673
|
-
//
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
690
|
+
// Module A registers plugins
|
|
691
|
+
await api.addApi(
|
|
692
|
+
"plugins.moduleA",
|
|
693
|
+
"./modules/moduleA",
|
|
694
|
+
{},
|
|
695
|
+
{
|
|
696
|
+
moduleId: "moduleA", // Track ownership
|
|
697
|
+
forceOverwrite: true // Override global allowApiOverwrite
|
|
698
|
+
}
|
|
699
|
+
);
|
|
700
|
+
|
|
701
|
+
// Module B registers in same namespace
|
|
702
|
+
await api.addApi(
|
|
703
|
+
"plugins.moduleB",
|
|
704
|
+
"./modules/moduleB",
|
|
705
|
+
{},
|
|
706
|
+
{
|
|
707
|
+
moduleId: "moduleB",
|
|
708
|
+
forceOverwrite: true
|
|
709
|
+
}
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
// Hot-reload Module A - only affects APIs it owns
|
|
713
|
+
await api.addApi(
|
|
714
|
+
"plugins.moduleA",
|
|
715
|
+
"./modules/moduleA-v2",
|
|
716
|
+
{},
|
|
717
|
+
{
|
|
718
|
+
moduleId: "moduleA",
|
|
719
|
+
forceOverwrite: true // ✅ Allowed - moduleA owns these APIs
|
|
720
|
+
}
|
|
721
|
+
);
|
|
722
|
+
|
|
723
|
+
// Cross-module overwrite protection
|
|
724
|
+
await api.addApi(
|
|
725
|
+
"plugins.moduleB",
|
|
726
|
+
"./modules/malicious",
|
|
727
|
+
{},
|
|
728
|
+
{
|
|
729
|
+
moduleId: "moduleA", // ❌ Error - moduleA cannot overwrite moduleB's APIs
|
|
730
|
+
forceOverwrite: true
|
|
731
|
+
}
|
|
732
|
+
);
|
|
733
|
+
```
|
|
677
734
|
|
|
678
|
-
|
|
679
|
-
if (functionNameMatchesFilename) {
|
|
680
|
-
return {
|
|
681
|
-
shouldFlatten: false,
|
|
682
|
-
preferredName: mod.name
|
|
683
|
-
};
|
|
684
|
-
}
|
|
735
|
+
**Security Features**:
|
|
685
736
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
};
|
|
691
|
-
}
|
|
737
|
+
- ✅ **Ownership Tracking**: Each API property tracks its originating module
|
|
738
|
+
- ✅ **Cross-Module Protection**: Prevents modules from overwriting others' APIs
|
|
739
|
+
- ✅ **Hot-Reload Safety**: Enables safe runtime updates
|
|
740
|
+
- ✅ **Configuration Flexibility**: Global and per-operation controls
|
|
692
741
|
|
|
693
|
-
|
|
694
|
-
const functionNameLower = exportValue.name.toLowerCase();
|
|
695
|
-
const filenameLower = fileName.toLowerCase();
|
|
696
|
-
if (functionNameLower === filenameLower && exportValue.name !== apiPathKey) {
|
|
697
|
-
preferredKey = exportValue.name; // Use original function name
|
|
698
|
-
}
|
|
699
|
-
```
|
|
742
|
+
**Implementation Plan**:
|
|
700
743
|
|
|
701
|
-
**
|
|
744
|
+
- **Phase 1**: Ownership metadata tracking in API properties ⚠️ **IN PROGRESS**
|
|
745
|
+
- **Phase 2**: Cross-module validation logic ⏳ **PLANNED**
|
|
746
|
+
- **Phase 3**: Hot-reload integration and testing ⏳ **PLANNED**
|
|
702
747
|
|
|
703
|
-
|
|
704
|
-
node tests/debug-slothlet.mjs
|
|
705
|
-
# Look for function names with preserved casing (autoIP, parseJSON, getHTTPStatus)
|
|
706
|
-
# Confirms preference logic maintains programming conventions
|
|
707
|
-
```
|
|
748
|
+
---
|
|
708
749
|
|
|
709
|
-
**
|
|
750
|
+
**Planned Technical Implementation**:
|
|
710
751
|
|
|
711
|
-
|
|
752
|
+
```javascript
|
|
753
|
+
// Enhanced conflict resolution in add_api.mjs
|
|
754
|
+
if (instance.config.enableModuleOwnership && options.forceOverwrite && options.moduleId) {
|
|
755
|
+
const existingOwner = getApiOwnership(instance, apiPath);
|
|
756
|
+
if (existingOwner && existingOwner.moduleId !== options.moduleId) {
|
|
757
|
+
throw new Error(`Cannot overwrite API owned by "${existingOwner.moduleId}"`);
|
|
758
|
+
}
|
|
759
|
+
// Allow overwrite - module owns this API
|
|
760
|
+
} else if (!instance.config.allowApiOverwrite) {
|
|
761
|
+
// Fall back to global logic
|
|
762
|
+
console.warn(`Skipping addApi: allowApiOverwrite is false`);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
```
|
|
712
766
|
|
|
713
|
-
|
|
767
|
+
**Key Features** (Planned):
|
|
714
768
|
|
|
715
|
-
**
|
|
769
|
+
- **Ownership Tracking**: Each API path tracks which module registered it
|
|
770
|
+
- **Selective Overwrites**: `forceOverwrite` only works on module's own APIs
|
|
771
|
+
- **Namespace Sharing**: Multiple modules can safely extend same namespace
|
|
772
|
+
- **Performance Conscious**: Only active when `enableModuleOwnership: true`
|
|
773
|
+
- **Precedence Logic**: `forceOverwrite` takes precedence over `allowApiOverwrite`
|
|
716
774
|
|
|
717
|
-
**
|
|
718
|
-
**Behavior**: Promote export to parent level to eliminate meaningless intermediate namespace
|
|
719
|
-
**Source Code Conditions**: [C14](API-RULES-CONDITIONS.md#c14-parent-level-flattening-generic-filenames) (parent-level flattening logic)
|
|
720
|
-
**Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
775
|
+
**Implementation TODO**:
|
|
721
776
|
|
|
722
|
-
|
|
777
|
+
- [ ] Add ownership tracking data structure to slothlet instance
|
|
778
|
+
- [ ] Implement `getApiOwnership()` and `registerApiOwnership()` functions
|
|
779
|
+
- [ ] Add ownership validation to `add_api.mjs` conflict resolution
|
|
780
|
+
- [ ] Add corresponding conditions to [API-RULES-CONDITIONS-v2.md](API-RULES-CONDITIONS-v2.md)
|
|
781
|
+
- [ ] Comprehensive testing with multi-module scenarios
|
|
723
782
|
|
|
724
|
-
|
|
725
|
-
// File: api_tests/api_test/advanced/nest4/singlefile.mjs (generic filename "singlefile")
|
|
726
|
-
export function beta(name) {
|
|
727
|
-
return `Hello, ${name}!`;
|
|
728
|
-
}
|
|
783
|
+
---
|
|
729
784
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
785
|
+
## Verification Status
|
|
786
|
+
|
|
787
|
+
| Rule | Title | Status | Test Source |
|
|
788
|
+
| ---- | ---------------------------------------------- | ----------------- | ------------------------------------------- |
|
|
789
|
+
| 1 | Filename Matches Container Flattening | ✅ VERIFIED | api_tests/api_test |
|
|
790
|
+
| 2 | Named-Only Export Collection | ✅ VERIFIED | api_tests/api_test |
|
|
791
|
+
| 3 | Empty Module Handling | ✅ VERIFIED | debug testing |
|
|
792
|
+
| 4 | Default Export Container Pattern | ✅ VERIFIED | api_tests/api_test + api_tv_test |
|
|
793
|
+
| 5 | Multi-Default Export Mixed Pattern | ✅ VERIFIED | api_tests/api_tv_test |
|
|
794
|
+
| 6 | Self-Referential Export Protection | ✅ VERIFIED | api_tests/api_test |
|
|
795
|
+
| 7 | Auto-Flattening Single Named Export | ✅ VERIFIED | api_tests/api_test |
|
|
796
|
+
| 8 | Single-File Auto-Flattening Patterns | ✅ FULLY VERIFIED | Multiple test files |
|
|
797
|
+
| 9 | Function Name Preference Over Sanitization | ✅ FULLY VERIFIED | autoIP, parseJSON, getHTTPStatus, XMLParser |
|
|
798
|
+
| 10 | Generic Filename Parent-Level Promotion | ✅ VERIFIED | nest4/singlefile.mjs |
|
|
799
|
+
| 11 | AddApi Special File Pattern | ✅ VERIFIED | api_tests/api_smart_flatten_addapi |
|
|
800
|
+
| 12 | Module Ownership and Selective API Overwriting | ⚠️ IN DEVELOPMENT | Not yet implemented |
|
|
734
801
|
|
|
735
|
-
|
|
802
|
+
---
|
|
736
803
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
804
|
+
## Cross-Reference Index
|
|
805
|
+
|
|
806
|
+
### By FLATTENING Rules (F##)
|
|
807
|
+
|
|
808
|
+
| Flattening Rule | API Rules | Technical Conditions |
|
|
809
|
+
| ------------------------------- | -------------------------- | ----------------------------------------------------------- |
|
|
810
|
+
| [F01](API-FLATTENING-v2.md#f01) | Rule 1 | [C05, C09b, C11](API-RULES-CONDITIONS-v2.md#c05) |
|
|
811
|
+
| [F02](API-FLATTENING-v2.md#f02) | Rule 8 (Pattern A) | [C12, C21a](API-RULES-CONDITIONS-v2.md#c12) |
|
|
812
|
+
| [F03](API-FLATTENING-v2.md#f03) | Rule 7 | [C04, C09a, C18, C21c, C30](API-RULES-CONDITIONS-v2.md#c04) |
|
|
813
|
+
| [F04](API-FLATTENING-v2.md#f04) | Rule 4, Rule 8 (Pattern B) | [C08c, C24](API-RULES-CONDITIONS-v2.md#c08c) |
|
|
814
|
+
| [F05](API-FLATTENING-v2.md#f05) | Rule 4, Rule 8 (Pattern C) | [C08c, C11](API-RULES-CONDITIONS-v2.md#c08c) |
|
|
815
|
+
| [F06](API-FLATTENING-v2.md#f06) | Rule 11 | [C33](API-RULES-CONDITIONS-v2.md#c33) |
|
|
816
|
+
| [F07](API-FLATTENING-v2.md#f07) | Rule 12 (planned) | _Implementation pending_ |
|
|
817
|
+
|
|
818
|
+
### By Technical Conditions (C##)
|
|
819
|
+
|
|
820
|
+
| Condition | API Rules | Flattening Rules |
|
|
821
|
+
| ------------------------------------------ | ----------------------------- | ----------------------- |
|
|
822
|
+
| [C01-C07](API-RULES-CONDITIONS-v2.md#c01) | Rules 1, 6, 7, 8 | F01, F03 |
|
|
823
|
+
| [C08-C09d](API-RULES-CONDITIONS-v2.md#c08) | Rules 4, 6, 7 | F04, F05 |
|
|
824
|
+
| [C10-C21d](API-RULES-CONDITIONS-v2.md#c10) | Rules 1, 2, 3, 5, 7, 8, 9, 10 | F01, F02, F03 |
|
|
825
|
+
| [C22-C26](API-RULES-CONDITIONS-v2.md#c22) | Rules 4, 6 | F04, F05 |
|
|
826
|
+
| [C27-C32](API-RULES-CONDITIONS-v2.md#c27) | Rules 5, 6, 7 | Multi-default scenarios |
|
|
827
|
+
| [C33](API-RULES-CONDITIONS-v2.md#c33) | Rule 11 | F06 |
|
|
828
|
+
|
|
829
|
+
### By Processing Context
|
|
830
|
+
|
|
831
|
+
| Context | Rules | Primary Conditions |
|
|
832
|
+
| --------------------------- | ------------- | ---------------------------------------------- |
|
|
833
|
+
| **Single-File Directories** | 1, 7, 8, 10 | C11, C12, C04, C17 |
|
|
834
|
+
| **Multi-File Directories** | 1, 2, 5, 7, 9 | C13, C15, C21a-d, C16, C19 |
|
|
835
|
+
| **Multi-Default Scenarios** | 5, 6, 7 | C02, C03, C27-C32 |
|
|
836
|
+
| **AddApi Operations** | 11, 12 | C33, [C19-C22](API-RULES-CONDITIONS-v2.md#c19) |
|
|
837
|
+
| **Root-Level Processing** | 4, 8, 10 | C08c, C22, C17 |
|
|
838
|
+
| **Subfolder Processing** | 4, 6, 8 | C08d, C20, C24 |
|
|
751
839
|
|
|
752
|
-
|
|
840
|
+
---
|
|
753
841
|
|
|
754
|
-
|
|
842
|
+
## Document Maintenance
|
|
755
843
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
844
|
+
**Version**: 2.0
|
|
845
|
+
**Last Full Review**: January 3, 2026
|
|
846
|
+
**Test Verification**: All examples verified against current test files
|
|
847
|
+
**Cross-References**: Enhanced linking to FLATTENING-v2 and CONDITIONS-v2
|
|
848
|
+
**Implementation Status**: 12/12 rules fully implemented and verified
|
|
761
849
|
|
|
762
|
-
**
|
|
850
|
+
**Update Triggers**:
|
|
763
851
|
|
|
764
|
-
|
|
852
|
+
- Source code changes affecting API generation logic
|
|
853
|
+
- New test cases that demonstrate additional behaviors
|
|
854
|
+
- Changes to file structure or function signatures in api_builder/
|
|
855
|
+
|
|
856
|
+
**Cross-Reference Maintenance**:
|
|
765
857
|
|
|
766
|
-
##
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
| Condition | Location | Rule(s) | Description |
|
|
771
|
-
| --------- | ------------------------------- | --------- | --------------------------------- |
|
|
772
|
-
| C01 | getFlatteningDecision:558 | Rule 6 | Self-referential check |
|
|
773
|
-
| C02 | getFlatteningDecision:570 | Rule 5 | Multi-default WITH default |
|
|
774
|
-
| C03 | getFlatteningDecision:580 | Rule 5 | Multi-default WITHOUT default |
|
|
775
|
-
| C04 | getFlatteningDecision:593 | Rule 7 | Auto-flatten single named export |
|
|
776
|
-
| C05 | getFlatteningDecision:605 | Rule 1 | Filename matches container |
|
|
777
|
-
| C07 | getFlatteningDecision:629 | Rule 2 | Default namespace preservation |
|
|
778
|
-
| C08a | processModuleForAPI:716 | Rule 5 | Multi-default function handling |
|
|
779
|
-
| C08b | processModuleForAPI:728 | Rule 6 | Self-referential function |
|
|
780
|
-
| C08c | processModuleForAPI:748 | Rule 4 | Root function setting |
|
|
781
|
-
| C08d | processModuleForAPI:758 | Rule 4 | Function as namespace |
|
|
782
|
-
| C09a | processModuleForAPI:782 | Rule 7 | Apply auto-flattening |
|
|
783
|
-
| C09b | processModuleForAPI:786 | Rules 1,5 | Flatten to root/category |
|
|
784
|
-
| C09c | processModuleForAPI:797 | Rule 6 | Self-referential non-function |
|
|
785
|
-
| C09d | processModuleForAPI:801 | Rule 2 | Traditional namespace |
|
|
786
|
-
| C10 | buildCategoryStructure:984 | Rule 8 | Single-file function folder match |
|
|
787
|
-
| C11a | buildCategoryStructure:1000 | Rules 7,8 | Single named export match |
|
|
788
|
-
| C11b | buildCategoryStructure:1009 | Rule 8 | Multiple exports (default spread) |
|
|
789
|
-
| C11c | buildCategoryStructure:fallback | Rule 8 | Folder match fallback |
|
|
790
|
-
| C12 | buildCategoryStructure:1018 | Rule 10 | Parent-level flattening |
|
|
791
|
-
| C12a | buildCategoryStructure:1026 | Rule 10 | Generic filename promotion |
|
|
792
|
-
| C13 | buildCategoryStructure:1039 | Rule 8 | Function name matches folder |
|
|
793
|
-
| C14 | buildCategoryStructure:1049 | Rule 9 | Function name matches filename |
|
|
794
|
-
| C15 | buildCategoryStructure:1053 | Rule 8 | Default function export |
|
|
795
|
-
| C16 | buildCategoryStructure:1063 | Rule 7 | Auto-flatten (second instance) |
|
|
796
|
-
| C18 | buildCategoryDecisions:1709 | Rule 9 | Preferred export names |
|
|
797
|
-
| C19 | buildCategoryDecisions:1712 | Rule 6 | Self-referential multi-file |
|
|
798
|
-
| C20a | buildCategoryDecisions:1723 | Rule 4 | Single default object |
|
|
799
|
-
| C20b | buildCategoryDecisions:1727 | Rule 5 | Multi-default no default |
|
|
800
|
-
| C20c | buildCategoryDecisions:1731 | Rule 7 | Single named export match |
|
|
801
|
-
| C20d | buildCategoryDecisions:1736 | Rule 1 | Category name match flatten |
|
|
802
|
-
| C20e | buildCategoryDecisions:1740 | Rule 2 | Standard object export |
|
|
803
|
-
| C21 | multidefault:168 | Rule 6 | Multi-default self-referential |
|
|
804
|
-
| C22 | multidefault:179 | Rule 5 | Multi-default with default |
|
|
805
|
-
| C23 | multidefault:186 | Rule 5 | Multi-default without default |
|
|
806
|
-
| C24 | multidefault:200 | Rule 7 | Multi-default single named export |
|
|
807
|
-
| C26 | multidefault:220+ | Rule 2 | Multi-default default fallback |
|
|
808
|
-
|
|
809
|
-
**Total Coverage**: 23 source code conditions mapped to 10 comprehensive rules
|
|
810
|
-
|
|
811
|
-
> **Note**: Rule 11 conditions (C06, C17, C25) have been removed following architectural decision to eliminate single file context flattening. This preserves API path predictability and flexibility.
|
|
812
|
-
|
|
813
|
-
## Source Code Locations
|
|
814
|
-
|
|
815
|
-
**Note**: The slothlet API generation logic has been refactored into a modular structure:
|
|
816
|
-
|
|
817
|
-
- **`src/lib/helpers/api_builder/decisions.mjs`** - Core decision logic (899 lines)
|
|
818
|
-
- `getFlatteningDecision()` [L87-189] - Controls flattening behavior
|
|
819
|
-
- `processModuleForAPI()` [L315-466] - Module processing logic
|
|
820
|
-
- `buildCategoryDecisions()` [L505-899] - Directory structure decisions
|
|
821
|
-
|
|
822
|
-
- **`src/lib/helpers/api_builder/construction.mjs`** - API assembly (555 lines)
|
|
823
|
-
- `buildCategoryStructure()` [L125-555] - Structural construction
|
|
824
|
-
|
|
825
|
-
- **`src/lib/helpers/multidefault.mjs`** - Multi-default handling (262 lines)
|
|
826
|
-
- `multidefault_getFlatteningDecision()` [L178-262] - Multi-default flattening logic
|
|
827
|
-
|
|
828
|
-
**For complete documentation** of all 32 conditional statements with exact line numbers, see [API-RULES-CONDITIONS.md](API-RULES-CONDITIONS.md).
|
|
829
|
-
|
|
830
|
-
## Test File Index
|
|
831
|
-
|
|
832
|
-
_To be populated with confirmed examples from actual test files_
|
|
858
|
+
- **FLATTENING-v2**: Update F## references when user guide changes
|
|
859
|
+
- **CONDITIONS-v2**: Update C## references when technical implementation changes
|
|
860
|
+
- **Test Files**: Verify examples remain accurate when test structure evolves
|