@cldmv/slothlet 2.10.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 +27 -20
- package/dist/lib/helpers/api_builder/add_api.mjs +264 -3
- package/dist/lib/helpers/api_builder/construction.mjs +40 -2
- package/dist/lib/helpers/api_builder/decisions.mjs +15 -4
- package/dist/lib/helpers/resolve-from-caller.mjs +47 -10
- package/dist/lib/modes/slothlet_eager.mjs +29 -1
- package/dist/lib/modes/slothlet_lazy.mjs +85 -4
- package/dist/slothlet.mjs +53 -5
- 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 +55 -29
- package/types/dist/lib/helpers/api_builder/add_api.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/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/slothlet.d.mts +8 -0
- package/types/dist/slothlet.d.mts.map +1 -1
- package/types/index.d.mts.map +1 -0
|
@@ -1,508 +1,712 @@
|
|
|
1
|
-
# Slothlet Source Code Conditions Reference
|
|
1
|
+
# Slothlet Source Code Conditions Reference (v2)
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Complete Traceability Document for All API Generation Conditional Logic**
|
|
4
4
|
|
|
5
|
-
- **
|
|
6
|
-
- **Date**:
|
|
7
|
-
- **Purpose**:
|
|
8
|
-
- **Status**:
|
|
5
|
+
- **Version**: 2.0
|
|
6
|
+
- **Date**: January 3, 2026
|
|
7
|
+
- **Purpose**: Foundation documentation mapping every conditional statement in slothlet API generation to exact source code locations
|
|
8
|
+
- **Status**: ✅ **VERIFIED AND CURRENT** - All conditions verified against actual source code
|
|
9
|
+
- **Cross-Reference Support**: Provides technical foundation for [API-RULES-v2.md](API-RULES-v2.md) and [API-FLATTENING-v2.md](API-FLATTENING-v2.md)
|
|
9
10
|
|
|
10
11
|
---
|
|
11
12
|
|
|
12
|
-
##
|
|
13
|
+
## Document Hierarchy
|
|
13
14
|
|
|
14
|
-
This
|
|
15
|
+
This is the **foundation level** of slothlet's three-tier documentation system:
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
```text
|
|
18
|
+
📋 API-FLATTENING-v2.md (F##) ← User Guide: "How flattening works"
|
|
19
|
+
↓ references
|
|
20
|
+
📊 API-RULES-v2.md (1-12) ← Maintainer Guide: "All API behaviors"
|
|
21
|
+
↓ references
|
|
22
|
+
🔧 API-RULES-CONDITIONS-v2.md ← Developer/Debug Guide: "Exact code locations"
|
|
23
|
+
```
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
- [`processModuleForAPI()`](#processmoduleforapi-conditions) - 9 conditions for module processing
|
|
20
|
-
- [`buildCategoryDecisions()`](#buildcategorydecisions-conditions) - 11 decisions for directory structure
|
|
21
|
-
- [`buildCategoryStructure()`](#buildcategorystructure-conditions) - 6 structural assembly conditions
|
|
22
|
-
- [`multidefault_getFlatteningDecision()`](#multidefault_getflatteningdecision-conditions) - 4 multi-default rules
|
|
25
|
+
**Numbering System**: This document uses **C##** (C01, C02, etc.) for all conditions to avoid confusion with the other files' numbering systems.
|
|
23
26
|
|
|
24
27
|
---
|
|
25
28
|
|
|
26
|
-
##
|
|
29
|
+
## Overview
|
|
30
|
+
|
|
31
|
+
This document catalogs every conditional statement in slothlet's API generation system. Each condition provides:
|
|
32
|
+
|
|
33
|
+
- **Exact line numbers** and source file locations
|
|
34
|
+
- **Direct GitHub-style links** for precise code navigation
|
|
35
|
+
- **Input parameters** and **result values** for debugging
|
|
36
|
+
- **Cross-references** to higher-level rules that use these conditions
|
|
37
|
+
- **Examples** showing the condition in action
|
|
27
38
|
|
|
28
|
-
|
|
29
|
-
2. [processModuleForAPI() Conditions](#processmoduleforapi-conditions) (9 conditions)
|
|
30
|
-
3. [buildCategoryDecisions() Conditions](#buildcategorydecisions-conditions) (11 decisions)
|
|
31
|
-
4. [buildCategoryStructure() Conditions](#buildcategorystructure-conditions) (6 structural)
|
|
32
|
-
5. [multidefault_getFlatteningDecision() Conditions](#multidefault_getflatteningdecision-conditions) (4 rules)
|
|
39
|
+
**Architecture Pattern**: The API generation system uses 3 core functions with 18 conditional statements that determine how file structures become API surfaces.
|
|
33
40
|
|
|
34
41
|
---
|
|
35
42
|
|
|
36
|
-
##
|
|
43
|
+
## Core Decision Functions Summary
|
|
37
44
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
| Function | File | Conditions | Purpose |
|
|
46
|
+
| -------------------------- | ------------------------------------------------------------- | ---------- | ------------------------------ |
|
|
47
|
+
| `getFlatteningDecision()` | [decisions.mjs](../src/lib/helpers/api_builder/decisions.mjs) | C01-C07 | Basic flattening rules |
|
|
48
|
+
| `processModuleForAPI()` | [decisions.mjs](../src/lib/helpers/api_builder/decisions.mjs) | C08-C09b | Module-level processing |
|
|
49
|
+
| `buildCategoryDecisions()` | [decisions.mjs](../src/lib/helpers/api_builder/decisions.mjs) | C10-C18 | Single-file directory handling |
|
|
41
50
|
|
|
42
|
-
|
|
51
|
+
---
|
|
43
52
|
|
|
44
|
-
|
|
53
|
+
## Table of Contents
|
|
45
54
|
|
|
46
|
-
|
|
55
|
+
1. [C01: Self-Referential Check](#c01-self-referential-check)
|
|
56
|
+
2. [C02: Multi-Default Context With Default Export](#c02-multi-default-context-with-default-export)
|
|
57
|
+
3. [C03: Multi-Default Context Without Default Export](#c03-multi-default-context-without-default-export)
|
|
58
|
+
4. [C04: Auto-Flatten Single Named Export Matching Filename](#c04-auto-flatten-single-named-export-matching-filename)
|
|
59
|
+
5. [C05: Filename Matches Container (Category-Level Flatten)](#c05-filename-matches-container-category-level-flatten)
|
|
60
|
+
6. [C06: Single File Context (COMMENTED OUT)](#c06-single-file-context-commented-out)
|
|
61
|
+
7. [C07: Default Fallback - Preserve as Namespace](#c07-default-fallback---preserve-as-namespace)
|
|
62
|
+
8. [C08: Auto-Flattening](#c08-auto-flattening)
|
|
63
|
+
9. [C09: Flatten To Root/Category](#c09-flatten-to-rootcategory)
|
|
64
|
+
10. [C09a: Self-Referential Non-Function](#c09a-self-referential-non-function)
|
|
65
|
+
11. [C09b: Traditional Namespace Preservation](#c09b-traditional-namespace-preservation)
|
|
66
|
+
12. [C10: Single-File Function Folder Match](#c10-single-file-function-folder-match)
|
|
67
|
+
13. [C11: Default Export Flattening](#c11-default-export-flattening)
|
|
68
|
+
14. [C12: Object Auto-Flatten](#c12-object-auto-flatten)
|
|
69
|
+
15. [C13: Filename-Folder Exact Match Flattening](#c13-filename-folder-exact-match-flattening)
|
|
70
|
+
16. [C14: Parent-Level Flattening (Generic Filenames)](#c14-parent-level-flattening-generic-filenames)
|
|
71
|
+
17. [C15: Function Name Matches Folder](#c15-function-name-matches-folder)
|
|
72
|
+
18. [C16: Function Name Preference](#c16-function-name-preference)
|
|
73
|
+
19. [C17: Default Function Export Flattening](#c17-default-function-export-flattening)
|
|
74
|
+
20. [C18: Object Auto-Flatten (Final Check)](#c18-object-auto-flatten-final-check)
|
|
75
|
+
21. [Cross-Reference Index](#cross-reference-index)
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## C01: Self-Referential Check
|
|
80
|
+
|
|
81
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L87-L189)
|
|
82
|
+
**Function**: `getFlatteningDecision(options)`
|
|
83
|
+
**Line**: [100](../src/lib/helpers/api_builder/decisions.mjs#L100)
|
|
47
84
|
**Condition**: `if (isSelfReferential)`
|
|
48
85
|
**Purpose**: Self-referential exports (where filename matches an exported property) never flatten to avoid infinite nesting
|
|
49
|
-
**
|
|
50
|
-
**
|
|
86
|
+
**Input**: `isSelfReferential` (boolean)
|
|
87
|
+
**Result**: `{ shouldFlatten: false, preserveAsNamespace: true, reason: "self-referential export" }`
|
|
88
|
+
**Used By**: [API-RULES Rule 6](API-RULES-v2.md#rule-6-self-referential-export-protection)
|
|
89
|
+
|
|
90
|
+
**Example**:
|
|
51
91
|
|
|
52
|
-
|
|
92
|
+
```javascript
|
|
93
|
+
// math.mjs exports { math: { add, subtract } }
|
|
94
|
+
// → preserves as api.math.math.add() to avoid circular structure
|
|
95
|
+
```
|
|
53
96
|
|
|
54
97
|
---
|
|
55
98
|
|
|
56
|
-
|
|
99
|
+
## C02: Multi-Default Context With Default Export
|
|
57
100
|
|
|
58
|
-
**
|
|
59
|
-
**
|
|
101
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L87-L189)
|
|
102
|
+
**Function**: `getFlatteningDecision(options)`
|
|
103
|
+
**Line**: [113](../src/lib/helpers/api_builder/decisions.mjs#L113) → [114](../src/lib/helpers/api_builder/decisions.mjs#L114)
|
|
104
|
+
**Condition**: `if (hasMultipleDefaultExports) → if (moduleHasDefault)`
|
|
60
105
|
**Purpose**: In multi-default context, modules WITH default exports are preserved as namespaces to avoid conflicts
|
|
61
|
-
**
|
|
62
|
-
**
|
|
106
|
+
**Input**: `hasMultipleDefaultExports` (boolean), `moduleHasDefault` (boolean)
|
|
107
|
+
**Result**: `{ shouldFlatten: false, preserveAsNamespace: true, reason: "multi-default context with default export" }`
|
|
108
|
+
**Used By**: [API-RULES Rule 5](API-RULES-v2.md#rule-5-multi-default-export-mixed-pattern)
|
|
63
109
|
|
|
64
|
-
**Example**:
|
|
110
|
+
**Example**:
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
// Folder has 3 files with default exports
|
|
114
|
+
// → each keeps namespace to prevent collision
|
|
115
|
+
```
|
|
65
116
|
|
|
66
117
|
---
|
|
67
118
|
|
|
68
|
-
|
|
119
|
+
## C03: Multi-Default Context Without Default Export
|
|
69
120
|
|
|
70
|
-
**
|
|
71
|
-
**
|
|
121
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L87-L189)
|
|
122
|
+
**Function**: `getFlatteningDecision(options)`
|
|
123
|
+
**Line**: [113](../src/lib/helpers/api_builder/decisions.mjs#L113) → [125](../src/lib/helpers/api_builder/decisions.mjs#L125)
|
|
124
|
+
**Condition**: `if (hasMultipleDefaultExports) → else (!moduleHasDefault)`
|
|
72
125
|
**Purpose**: In multi-default context, modules WITHOUT default exports flatten to avoid empty namespaces
|
|
73
|
-
**
|
|
74
|
-
**
|
|
126
|
+
**Input**: `hasMultipleDefaultExports` (boolean), `moduleHasDefault` (boolean)
|
|
127
|
+
**Result**: `{ shouldFlatten: true, flattenToRoot: true, flattenToCategory: true, reason: "multi-default context without default export" }`
|
|
128
|
+
**Used By**: [API-RULES Rule 5](API-RULES-v2.md#rule-5-multi-default-export-mixed-pattern)
|
|
129
|
+
|
|
130
|
+
**Example**:
|
|
75
131
|
|
|
76
|
-
|
|
132
|
+
```javascript
|
|
133
|
+
// Folder has mix of default/named exports
|
|
134
|
+
// → named-only files flatten to category level
|
|
135
|
+
```
|
|
77
136
|
|
|
78
137
|
---
|
|
79
138
|
|
|
80
|
-
|
|
139
|
+
## C04: Auto-Flatten Single Named Export Matching Filename
|
|
81
140
|
|
|
82
|
-
**
|
|
141
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L87-L189)
|
|
142
|
+
**Function**: `getFlatteningDecision(options)`
|
|
143
|
+
**Line**: [138](../src/lib/helpers/api_builder/decisions.mjs#L138)
|
|
83
144
|
**Condition**: `if (moduleKeys.length === 1 && moduleKeys[0] === apiPathKey)`
|
|
84
145
|
**Purpose**: When module exports single named export matching filename, use the export directly
|
|
85
|
-
**
|
|
86
|
-
**
|
|
146
|
+
**Input**: `moduleKeys` (array), `apiPathKey` (string)
|
|
147
|
+
**Result**: `{ shouldFlatten: true, useAutoFlattening: true, reason: "auto-flatten single named export matching filename" }`
|
|
148
|
+
**Used By**: [API-RULES Rule 7](API-RULES-v2.md#rule-7-auto-flattening-single-named-export) | [FLATTENING F03](API-FLATTENING-v2.md#f03)
|
|
149
|
+
|
|
150
|
+
**Example**:
|
|
87
151
|
|
|
88
|
-
|
|
152
|
+
```javascript
|
|
153
|
+
// math.mjs exports { math: { add } }
|
|
154
|
+
// → becomes api.math.add() not api.math.math.add()
|
|
155
|
+
```
|
|
89
156
|
|
|
90
157
|
---
|
|
91
158
|
|
|
92
|
-
|
|
159
|
+
## C05: Filename Matches Container (Category-Level Flatten)
|
|
93
160
|
|
|
94
|
-
**
|
|
161
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L87-L189)
|
|
162
|
+
**Function**: `getFlatteningDecision(options)`
|
|
163
|
+
**Line**: [150](../src/lib/helpers/api_builder/decisions.mjs#L150)
|
|
95
164
|
**Condition**: `if (categoryName && fileName === categoryName && !moduleHasDefault && moduleKeys.length > 0)`
|
|
96
165
|
**Purpose**: When filename matches folder name and has named exports but no default, flatten to category level
|
|
97
|
-
**
|
|
98
|
-
**
|
|
99
|
-
|
|
100
|
-
**Example**: `math/math.mjs` with named exports → flattens to `api.math.add()` not `api.math.math.add()`
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
### C06: Single File Context (COMMENTED OUT)
|
|
105
|
-
|
|
106
|
-
**Lines**: [169-182](../src/lib/helpers/api_builder/decisions.mjs#L169-L182)
|
|
107
|
-
**Status**: ?? **DISABLED** - Commented out in current code
|
|
108
|
-
**Original Purpose**: Flatten single-file folders with named exports only
|
|
109
|
-
**Comment**: "This rule reduces API path flexibility. If users want flattening, they can use other rules like naming the file to match the folder."
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
### C07: Default Fallback - Preserve as Namespace
|
|
114
|
-
|
|
115
|
-
**Line**: [184](../src/lib/helpers/api_builder/decisions.mjs#L184)
|
|
116
|
-
**Condition**: Default case (no conditions matched)
|
|
117
|
-
**Purpose**: Traditional namespace preservation when no flattening rules apply
|
|
118
|
-
**Result**: `shouldFlatten: false, preserveAsNamespace: true`
|
|
119
|
-
**Reason**: `"traditional namespace preservation"`
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
|
-
## processModuleForAPI() Conditions
|
|
124
|
-
|
|
125
|
-
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L315-L466)
|
|
126
|
-
**Function**: `processModuleForAPI(options)`
|
|
127
|
-
**Lines**: [315-466](../src/lib/helpers/api_builder/decisions.mjs#L315-L466)
|
|
128
|
-
|
|
129
|
-
This function processes individual modules and determines how they integrate into the API structure.
|
|
166
|
+
**Input**: `categoryName` (string), `fileName` (string), `moduleHasDefault` (boolean), `moduleKeys` (array)
|
|
167
|
+
**Result**: `{ shouldFlatten: true, flattenToCategory: true, reason: "filename matches container, flatten to category" }`
|
|
168
|
+
**Used By**: [API-RULES Rule 1](API-RULES-v2.md#rule-1-filename-matches-container-flattening) | [FLATTENING F01](API-FLATTENING-v2.md#f01)
|
|
130
169
|
|
|
131
|
-
|
|
170
|
+
**Example**:
|
|
132
171
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
172
|
+
```javascript
|
|
173
|
+
// math/math.mjs with named exports
|
|
174
|
+
// → becomes api.math.add() not api.math.math.add()
|
|
175
|
+
```
|
|
137
176
|
|
|
138
177
|
---
|
|
139
178
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
**Line**: [351](../src/lib/helpers/api_builder/decisions.mjs#L351)
|
|
143
|
-
**Condition**: `if (hasMultipleDefaultExports && !isSelfReferential)`
|
|
144
|
-
**Purpose**: In multi-default context, function defaults use filename as API key to avoid conflicts
|
|
145
|
-
**Result**: `apiAssignments[apiPathKey] = mod, namespaced = true`
|
|
146
|
-
|
|
147
|
-
**Example**: Multiple files with function defaults → each uses filename as namespace key
|
|
148
|
-
|
|
149
|
-
---
|
|
179
|
+
## C06: Single File Context (COMMENTED OUT)
|
|
150
180
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
**Line**: [
|
|
154
|
-
**Condition**:
|
|
155
|
-
**Purpose**:
|
|
156
|
-
**
|
|
157
|
-
|
|
158
|
-
**Example**: `logger.mjs` exports function with `logger` property → preserves namespace structure
|
|
181
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L87-L189)
|
|
182
|
+
**Function**: `getFlatteningDecision(options)`
|
|
183
|
+
**Line**: [162-170](../src/lib/helpers/api_builder/decisions.mjs#L162-L170) _(commented out)_
|
|
184
|
+
**Condition**: `// if (totalModules === 1 && !moduleHasDefault && moduleKeys.length > 0)`
|
|
185
|
+
**Purpose**: **INTENTIONALLY DISABLED** - Would flatten single files, but removed for API path flexibility
|
|
186
|
+
**Status**: **DEPRECATED** - Architectural decision documented in source comments
|
|
187
|
+
**Reason**: "This rule reduces API path flexibility. If users want flattening, they can use other rules like naming the file to match the folder."
|
|
159
188
|
|
|
160
189
|
---
|
|
161
190
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
**Line**: [378](../src/lib/helpers/api_builder/decisions.mjs#L378)
|
|
165
|
-
**Condition**: `if (mode === "root" && getRootDefault && setRootDefault && !hasMultipleDefaultExports && !getRootDefault())`
|
|
166
|
-
**Purpose**: In root context with no existing root function, set as the callable root API
|
|
167
|
-
**Result**: `setRootDefault(defaultFunction), rootDefaultSet = true`
|
|
191
|
+
## C07: Default Fallback - Preserve as Namespace
|
|
168
192
|
|
|
169
|
-
**
|
|
170
|
-
|
|
171
|
-
|
|
193
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L87-L189)
|
|
194
|
+
**Function**: `getFlatteningDecision(options)`
|
|
195
|
+
**Line**: [174](../src/lib/helpers/api_builder/decisions.mjs#L174)
|
|
196
|
+
**Condition**: `else` (default case when no other conditions match)
|
|
197
|
+
**Purpose**: When no flattening rules apply, preserve module as namespace
|
|
198
|
+
**Input**: All other conditions failed
|
|
199
|
+
**Result**: `{ shouldFlatten: false, preserveAsNamespace: true, reason: "traditional namespace preservation" }`
|
|
200
|
+
**Used By**: Default behavior for all rules
|
|
172
201
|
|
|
173
|
-
|
|
202
|
+
**Example**:
|
|
174
203
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
204
|
+
```javascript
|
|
205
|
+
// Complex module structures that don't match flattening patterns
|
|
206
|
+
// → preserved with full namespace hierarchy
|
|
207
|
+
```
|
|
179
208
|
|
|
180
209
|
---
|
|
181
210
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
**Line**: [398](../src/lib/helpers/api_builder/decisions.mjs#L398)
|
|
185
|
-
**Condition**: `else` (when !hasDefaultFunction)
|
|
186
|
-
**Purpose**: Handles object exports, named-only exports, and non-function defaults
|
|
187
|
-
**Branches**: 4 sub-conditions based on flattening decision
|
|
211
|
+
## C08: Auto-Flattening
|
|
188
212
|
|
|
189
|
-
|
|
213
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L315-L480)
|
|
214
|
+
**Function**: `processModuleForAPI(options)`
|
|
215
|
+
**Line**: [424](../src/lib/helpers/api_builder/decisions.mjs#L424)
|
|
216
|
+
**Condition**: `if (decision.useAutoFlattening)`
|
|
217
|
+
**Purpose**: Apply auto-flattening when single named export matches filename
|
|
218
|
+
**Input**: `decision.useAutoFlattening` (boolean from getFlatteningDecision)
|
|
219
|
+
**Result**: `apiAssignments[apiPathKey] = mod[moduleKeys[0]], flattened = true`
|
|
220
|
+
**Used By**: [API-RULES Rule 7](API-RULES-v2.md#rule-7-auto-flattening-single-named-export)
|
|
190
221
|
|
|
191
|
-
|
|
222
|
+
**Example**:
|
|
192
223
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
224
|
+
```javascript
|
|
225
|
+
// math.mjs exports { math: { add } }
|
|
226
|
+
// → auto-flattened to api.math.add()
|
|
227
|
+
```
|
|
197
228
|
|
|
198
229
|
---
|
|
199
230
|
|
|
200
|
-
|
|
231
|
+
## C09: Flatten To Root/Category
|
|
201
232
|
|
|
202
|
-
**
|
|
233
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L315-L480)
|
|
234
|
+
**Function**: `processModuleForAPI(options)`
|
|
235
|
+
**Line**: [430](../src/lib/helpers/api_builder/decisions.mjs#L430)
|
|
203
236
|
**Condition**: `else if (decision.flattenToRoot || decision.flattenToCategory)`
|
|
204
237
|
**Purpose**: Merge all named exports into target based on flattening decision
|
|
205
|
-
**
|
|
238
|
+
**Input**: `decision.flattenToRoot` or `decision.flattenToCategory` (boolean)
|
|
239
|
+
**Processing**: Loop assigns `apiAssignments[key] = mod[key], flattened = true`
|
|
240
|
+
**Used By**: [API-RULES Rule 1, 5](API-RULES-v2.md#rule-1-filename-matches-container-flattening)
|
|
241
|
+
|
|
242
|
+
**Example**:
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
// logger.mjs exports function with properties
|
|
246
|
+
// → preserved as api.logger() with api.logger.info
|
|
247
|
+
```
|
|
206
248
|
|
|
207
249
|
---
|
|
208
250
|
|
|
209
|
-
|
|
251
|
+
## C09a: Self-Referential Non-Function
|
|
210
252
|
|
|
253
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L315-L480)
|
|
254
|
+
**Function**: `processModuleForAPI(options)`
|
|
211
255
|
**Line**: [440](../src/lib/helpers/api_builder/decisions.mjs#L440)
|
|
212
256
|
**Condition**: `else if (isSelfReferential)`
|
|
213
257
|
**Purpose**: Self-referential non-function exports use direct property access
|
|
214
|
-
**
|
|
258
|
+
**Input**: `isSelfReferential` (boolean)
|
|
259
|
+
**Result**: `apiAssignments[apiPathKey] = mod[apiPathKey] || mod, namespaced = true`
|
|
260
|
+
**Used By**: [API-RULES Rule 6](API-RULES-v2.md#rule-6-self-referential-export-protection)
|
|
215
261
|
|
|
216
262
|
---
|
|
217
263
|
|
|
218
|
-
|
|
264
|
+
## C09b: Traditional Namespace Preservation
|
|
219
265
|
|
|
266
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L315-L480)
|
|
267
|
+
**Function**: `processModuleForAPI(options)`
|
|
220
268
|
**Line**: [444](../src/lib/helpers/api_builder/decisions.mjs#L444)
|
|
221
|
-
**Condition**: `else`
|
|
269
|
+
**Condition**: `else` (default behavior)
|
|
222
270
|
**Purpose**: Default behavior preserves module as namespace
|
|
223
|
-
**
|
|
224
|
-
|
|
225
|
-
|
|
271
|
+
**Input**: All other conditions failed
|
|
272
|
+
**Result**: `apiAssignments[apiPathKey] = mod, namespaced = true`
|
|
273
|
+
**Used By**: Default behavior for complex modules
|
|
226
274
|
|
|
227
|
-
|
|
275
|
+
**Example**:
|
|
228
276
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
277
|
+
```javascript
|
|
278
|
+
// math/math.mjs named exports flatten to category level
|
|
279
|
+
// → api.math.add(), api.math.subtract()
|
|
280
|
+
```
|
|
232
281
|
|
|
233
|
-
|
|
282
|
+
---
|
|
234
283
|
|
|
235
|
-
|
|
284
|
+
## C10: Single-File Function Folder Match
|
|
236
285
|
|
|
237
|
-
**
|
|
286
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L516-L715)
|
|
287
|
+
**Function**: `buildCategoryDecisions(categoryPath, options)`
|
|
288
|
+
**Line**: [580](../src/lib/helpers/api_builder/decisions.mjs#L580)
|
|
238
289
|
**Condition**: `if (moduleName === categoryName && typeof mod === "function" && currentDepth > 0)`
|
|
239
290
|
**Purpose**: Flatten when filename matches folder name and exports function (not at root level)
|
|
240
|
-
**
|
|
241
|
-
|
|
242
|
-
**
|
|
291
|
+
**Input**: `moduleName` (string), `categoryName` (string), `typeof mod` ("function"), `currentDepth > 0`
|
|
292
|
+
**Result**: `shouldFlatten: true, flattenType: "function-folder-match"`
|
|
293
|
+
**Used By**: [API-RULES Rule 2](API-RULES-v2.md#rule-2-filename-folder-match-flattening)
|
|
243
294
|
|
|
244
295
|
---
|
|
245
296
|
|
|
246
|
-
|
|
297
|
+
## C11: Default Export Flattening
|
|
247
298
|
|
|
248
|
-
**
|
|
299
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L516-L715)
|
|
300
|
+
**Function**: `buildCategoryDecisions(categoryPath, options)`
|
|
301
|
+
**Line**: [588](../src/lib/helpers/api_builder/decisions.mjs#L588)
|
|
249
302
|
**Condition**: `if (analysis.hasDefault && analysis.defaultExportType === "object" && moduleName === categoryName && currentDepth > 0)`
|
|
250
303
|
**Purpose**: Flatten default object exports when filename matches folder (handles both CJS and ESM uniformly)
|
|
251
|
-
**
|
|
304
|
+
**Input**: `analysis.hasDefault`, `analysis.defaultExportType === "object"`, filename/folder match, not root level
|
|
305
|
+
**Result**: `shouldFlatten: true, flattenType: "default-export-flatten"`
|
|
306
|
+
**Used By**: [API-RULES Rule 4](API-RULES-v2.md#rule-4-default-export-object-flattening)
|
|
252
307
|
|
|
253
308
|
---
|
|
254
309
|
|
|
255
|
-
|
|
310
|
+
## C12: Object Auto-Flatten
|
|
256
311
|
|
|
257
|
-
**
|
|
312
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L516-L715)
|
|
313
|
+
**Function**: `buildCategoryDecisions(categoryPath, options)`
|
|
314
|
+
**Line**: [596](../src/lib/helpers/api_builder/decisions.mjs#L596)
|
|
258
315
|
**Condition**: `if (moduleName === categoryName && mod && typeof mod === "object" && !Array.isArray(mod) && currentDepth > 0)`
|
|
259
|
-
**Sub-condition**: [
|
|
316
|
+
**Sub-condition**: [601](../src/lib/helpers/api_builder/decisions.mjs#L601): `if (moduleKeys.length === 1 && moduleKeys[0] === moduleName)`
|
|
260
317
|
**Purpose**: When single named export matches filename, flatten the object contents
|
|
261
|
-
**
|
|
318
|
+
**Input**: Filename/category match, object type, single named export matching filename
|
|
319
|
+
**Result**: `shouldFlatten: true, flattenType: "object-auto-flatten"`
|
|
320
|
+
**Used By**: [API-RULES Rule 7](API-RULES-v2.md#rule-7-auto-flattening-single-named-export)
|
|
262
321
|
|
|
263
322
|
---
|
|
264
323
|
|
|
265
|
-
|
|
324
|
+
## C13: Filename-Folder Exact Match Flattening
|
|
266
325
|
|
|
267
|
-
**
|
|
326
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L516-L715)
|
|
327
|
+
**Function**: `buildCategoryDecisions(categoryPath, options)`
|
|
328
|
+
**Line**: [611](../src/lib/helpers/api_builder/decisions.mjs#L611)
|
|
268
329
|
**Condition**: `if (fileBaseName === categoryName && moduleKeys.length > 0)`
|
|
269
330
|
**Purpose**: Avoid double nesting when file basename matches folder (e.g., nest/nest.mjs)
|
|
270
|
-
**
|
|
331
|
+
**Input**: `fileBaseName === categoryName` and has named exports
|
|
332
|
+
**Result**: `shouldFlatten: true, flattenType: "filename-folder-match-flatten"`
|
|
333
|
+
**Used By**: [API-RULES Rule 1, 2](API-RULES-v2.md#rule-1-filename-matches-container-flattening)
|
|
271
334
|
|
|
272
335
|
---
|
|
273
336
|
|
|
274
|
-
|
|
337
|
+
## C14: Parent-Level Flattening (Generic Filenames)
|
|
275
338
|
|
|
276
|
-
**
|
|
339
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L516-L715)
|
|
340
|
+
**Function**: `buildCategoryDecisions(categoryPath, options)`
|
|
341
|
+
**Line**: [653](../src/lib/helpers/api_builder/decisions.mjs#L653)
|
|
277
342
|
**Condition**: `if (moduleFiles.length === 1 && currentDepth > 0 && mod && typeof mod === "object" && !Array.isArray(mod))`
|
|
278
|
-
**Sub-condition**: [
|
|
343
|
+
**Sub-condition**: [661](../src/lib/helpers/api_builder/decisions.mjs#L661): `if (moduleKeys.length === 1 && isGenericFilename)`
|
|
279
344
|
**Purpose**: Eliminate intermediate namespace for generic filenames (singlefile, index, main, default)
|
|
280
|
-
**
|
|
281
|
-
|
|
282
|
-
**
|
|
345
|
+
**Input**: Single file, object export, generic filename pattern: `["singlefile", "index", "main", "default"]`
|
|
346
|
+
**Result**: `shouldFlatten: true, flattenType: "parent-level-flatten"`
|
|
347
|
+
**Used By**: [API-RULES Rule 8](API-RULES-v2.md#rule-8-generic-filename-parent-flattening)
|
|
283
348
|
|
|
284
349
|
---
|
|
285
350
|
|
|
286
|
-
|
|
351
|
+
## C15: Function Name Matches Folder
|
|
287
352
|
|
|
288
|
-
**
|
|
353
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L516-L715)
|
|
354
|
+
**Function**: `buildCategoryDecisions(categoryPath, options)`
|
|
355
|
+
**Line**: [670](../src/lib/helpers/api_builder/decisions.mjs#L670)
|
|
289
356
|
**Condition**: `if (functionNameMatchesFolder && currentDepth > 0)`
|
|
290
357
|
**Purpose**: Flatten when function name matches folder name (case-insensitive), prefer function name
|
|
291
|
-
**
|
|
358
|
+
**Input**: Function name matches folder name (case-insensitive check), not at root level
|
|
359
|
+
**Result**: `shouldFlatten: true, flattenType: "function-folder-match", preferredName: mod.name`
|
|
360
|
+
**Used By**: [API-RULES Rule 9](API-RULES-v2.md#rule-9-function-name-preservation)
|
|
292
361
|
|
|
293
362
|
---
|
|
294
363
|
|
|
295
|
-
|
|
364
|
+
## C16: Function Name Preference
|
|
296
365
|
|
|
297
|
-
**
|
|
366
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L516-L715)
|
|
367
|
+
**Function**: `buildCategoryDecisions(categoryPath, options)`
|
|
368
|
+
**Line**: [678](../src/lib/helpers/api_builder/decisions.mjs#L678)
|
|
298
369
|
**Condition**: `if (functionNameMatchesFilename)`
|
|
299
370
|
**Purpose**: Use original function name instead of sanitized filename when they match semantically
|
|
300
|
-
**
|
|
301
|
-
|
|
302
|
-
**
|
|
371
|
+
**Input**: Function name matches filename semantically (case-insensitive, ignores sanitization differences)
|
|
372
|
+
**Result**: `shouldFlatten: false, preferredName: mod.name`
|
|
373
|
+
**Used By**: [API-RULES Rule 9](API-RULES-v2.md#rule-9-function-name-preservation)
|
|
303
374
|
|
|
304
375
|
---
|
|
305
376
|
|
|
306
|
-
|
|
377
|
+
## C17: Default Function Export Flattening
|
|
307
378
|
|
|
308
|
-
**
|
|
379
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L516-L715)
|
|
380
|
+
**Function**: `buildCategoryDecisions(categoryPath, options)`
|
|
381
|
+
**Line**: [687](../src/lib/helpers/api_builder/decisions.mjs#L687)
|
|
309
382
|
**Condition**: `if (typeof mod === "function" && (!mod.name || mod.name === "default" || mod.__slothletDefault === true) && currentDepth > 0)`
|
|
310
383
|
**Purpose**: Flatten functions marked as default exports (not at root level)
|
|
311
|
-
**
|
|
384
|
+
**Input**: Function with no name, "default" name, or marked as default export
|
|
385
|
+
**Result**: `shouldFlatten: true, flattenType: "default-function", preferredName: categoryName`
|
|
386
|
+
**Used By**: [API-RULES Rule 4](API-RULES-v2.md#rule-4-default-export-object-flattening)
|
|
312
387
|
|
|
313
388
|
---
|
|
314
389
|
|
|
315
|
-
|
|
390
|
+
## C18: Object Auto-Flatten (Final Check)
|
|
316
391
|
|
|
317
|
-
**
|
|
392
|
+
**File**: [`src/lib/helpers/api_builder/decisions.mjs`](../src/lib/helpers/api_builder/decisions.mjs#L516-L715)
|
|
393
|
+
**Function**: `buildCategoryDecisions(categoryPath, options)`
|
|
394
|
+
**Line**: [704](../src/lib/helpers/api_builder/decisions.mjs#L704)
|
|
318
395
|
**Condition**: `if (moduleKeys.length === 1 && moduleKeys[0] === moduleName)`
|
|
319
|
-
**Purpose**: Auto-flatten when module
|
|
320
|
-
**
|
|
396
|
+
**Purpose**: Auto-flatten when module has single named export matching filename (final check for single-file case)
|
|
397
|
+
**Input**: Single named export with name matching module name
|
|
398
|
+
**Result**: `shouldFlatten: true, flattenType: "object-auto-flatten", preferredName: moduleName`
|
|
399
|
+
**Used By**: [API-RULES Rule 7](API-RULES-v2.md#rule-7-auto-flattening-single-named-export)
|
|
321
400
|
|
|
322
401
|
---
|
|
323
402
|
|
|
324
|
-
|
|
403
|
+
## Cross-Reference Index
|
|
404
|
+
|
|
405
|
+
**By Rule Number**:
|
|
406
|
+
|
|
407
|
+
**By Rule Number**:
|
|
325
408
|
|
|
326
|
-
**
|
|
327
|
-
**
|
|
328
|
-
**
|
|
329
|
-
**
|
|
409
|
+
- **Rule 1**: [C05](#c05-filename-matches-container-category-level-flatten), [C09](#c09-flatten-to-rootcategory), [C13](#c13-filename-folder-exact-match-flattening)
|
|
410
|
+
- **Rule 2**: [C10](#c10-single-file-function-folder-match), [C13](#c13-filename-folder-exact-match-flattening)
|
|
411
|
+
- **Rule 4**: [C11](#c11-default-export-flattening), [C17](#c17-default-function-export-flattening)
|
|
412
|
+
- **Rule 5**: [C02](#c02-multi-default-context-with-default-export), [C03](#c03-multi-default-context-without-default-export)
|
|
413
|
+
- **Rule 6**: [C01](#c01-self-referential-check), [C09a](#c09a-self-referential-non-function)
|
|
414
|
+
- **Rule 7**: [C04](#c04-auto-flatten-single-named-export-matching-filename), [C08](#c08-auto-flattening), [C12](#c12-object-auto-flatten), [C18](#c18-object-auto-flatten-final-check)
|
|
415
|
+
- **Rule 8**: [C14](#c14-parent-level-flattening-generic-filenames)
|
|
416
|
+
- **Rule 9**: [C15](#c15-function-name-matches-folder), [C16](#c16-function-name-preference)
|
|
417
|
+
|
|
418
|
+
**By Flattening Feature**:
|
|
419
|
+
|
|
420
|
+
- **F01 (Basic Rules)**: [C01](#c01-self-referential-check), [C05](#c05-filename-matches-container-category-level-flatten), [C07](#c07-default-fallback---preserve-as-namespace)
|
|
421
|
+
- **F02 (Function Folder Match)**: [C10](#c10-single-file-function-folder-match), [C15](#c15-function-name-matches-folder)
|
|
422
|
+
- **F03 (Auto-Flatten)**: [C04](#c04-auto-flatten-single-named-export-matching-filename), [C08](#c08-auto-flattening)
|
|
423
|
+
- **F04 (Object Flatten)**: [C11](#c11-default-export-flattening), [C12](#c12-object-auto-flatten)
|
|
424
|
+
- **F05 (Processing)**: [C08](#c08-auto-flattening), [C09](#c09-flatten-to-rootcategory), [C09b](#c09b-traditional-namespace-preservation)
|
|
425
|
+
- **F06 (Mixed Patterns)**: [C02](#c02-multi-default-context-with-default-export), [C03](#c03-multi-default-context-without-default-export)
|
|
330
426
|
|
|
331
427
|
---
|
|
332
428
|
|
|
333
|
-
|
|
429
|
+
## Summary
|
|
430
|
+
|
|
431
|
+
**Total Active Conditions**: 18 documented conditions from actual source code
|
|
432
|
+
**Primary Functions**: 3 main functions containing API generation logic
|
|
433
|
+
**File Locations**: 1 primary source file - decisions.mjs
|
|
334
434
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
**
|
|
435
|
+
### Condition Categories
|
|
436
|
+
|
|
437
|
+
- **Basic Flattening** (C01-C07): Core flattening decision logic from `getFlatteningDecision()`
|
|
438
|
+
- **Module Processing** (C08-C09b): Module handling from `processModuleForAPI()`
|
|
439
|
+
- **Single-File Decisions** (C10-C18): Directory-level logic from `buildCategoryDecisions()`
|
|
440
|
+
|
|
441
|
+
### Key Architectural Patterns
|
|
442
|
+
|
|
443
|
+
1. **Self-Referential Protection**: Conditions C01, C09a prevent circular structures
|
|
444
|
+
2. **Multi-Default Coordination**: Conditions C02, C03 handle mixed export patterns
|
|
445
|
+
3. **Smart Flattening**: Auto-detection conditions C04, C08 reduce unnecessary nesting
|
|
446
|
+
4. **Filename Matching**: Conditions C10-C13 handle folder/file name matching
|
|
447
|
+
5. **Function Name Preference**: Conditions C15-C16 preserve semantic naming
|
|
448
|
+
|
|
449
|
+
### Implementation Notes
|
|
450
|
+
|
|
451
|
+
- **Line Numbers**: All verified against commit `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
|
|
452
|
+
- **GitHub Links**: Use `#Lxxx-Lyyy` format for precise source navigation
|
|
453
|
+
- **Test Verification**: Each condition has corresponding test cases in `/tests/` directory
|
|
454
|
+
- **Debug Support**: Most conditions log decisions when `config.debug` is enabled
|
|
339
455
|
|
|
340
456
|
---
|
|
341
457
|
|
|
342
|
-
|
|
458
|
+
## Document Maintenance
|
|
343
459
|
|
|
344
|
-
**
|
|
345
|
-
**
|
|
346
|
-
**
|
|
460
|
+
**Version**: 2.0
|
|
461
|
+
**Last Full Audit**: January 3, 2026
|
|
462
|
+
**Status**: ✅ **COMPLETE** - All conditions documented with technical details
|
|
463
|
+
**Cross-References**: Complete integration with API-RULES-v2.md and API-FLATTENING-v2.md
|
|
464
|
+
**Next Review**: When source code conditions change or new features are added
|
|
347
465
|
|
|
348
|
-
|
|
466
|
+
**Verification Commands**:
|
|
349
467
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
468
|
+
```bash
|
|
469
|
+
# Test all condition behaviors
|
|
470
|
+
npm run debug # Runs comprehensive API validation
|
|
471
|
+
npm run test:node # Core functionality tests
|
|
353
472
|
|
|
354
|
-
|
|
473
|
+
# Verify specific conditions
|
|
474
|
+
node tests/debug-slothlet.mjs --slothletdebug # Detailed decision tracing
|
|
475
|
+
```
|
|
355
476
|
|
|
356
|
-
|
|
357
|
-
**Condition**: `else if (hasMultipleDefaultExports && !mod.default && moduleKeys.length > 0)`
|
|
358
|
-
**Result**: `shouldFlatten: true, flattenType: "multi-default-no-default"`
|
|
477
|
+
This section maps conditions to the higher-level documentation they support.
|
|
359
478
|
|
|
360
|
-
|
|
479
|
+
## Summary
|
|
361
480
|
|
|
362
|
-
**
|
|
363
|
-
**
|
|
364
|
-
**
|
|
481
|
+
**Total Active Conditions**: 33 documented conditions (2 commented out: C06, C31)
|
|
482
|
+
**Primary Functions**: 6 key functions containing API generation logic
|
|
483
|
+
**File Locations**: 3 source files across api_builder/ modules
|
|
365
484
|
|
|
366
|
-
|
|
485
|
+
### Condition Categories
|
|
486
|
+
|
|
487
|
+
- **Basic Flattening** (C01-C07): Core flattening decision logic
|
|
488
|
+
- **Module Processing** (C08-C09d): Individual module handling
|
|
489
|
+
- **Category Decisions** (C10-C21d): Directory-level coordination
|
|
490
|
+
- **Structural Assembly** (C22-C26): Final API structure building
|
|
491
|
+
- **Multi-Default Logic** (C27-C32): Specialized multi-default handling
|
|
492
|
+
- **AddApi Special Cases** (C33): Always-flatten AddApi behavior
|
|
493
|
+
|
|
494
|
+
### Key Architectural Patterns
|
|
367
495
|
|
|
368
|
-
**
|
|
369
|
-
**
|
|
370
|
-
**
|
|
496
|
+
1. **Self-Referential Protection**: Multiple conditions (C01, C08b, C09c, C20, C27) prevent circular structures
|
|
497
|
+
2. **Multi-Default Coordination**: Specialized handling (C02, C03, C08a, C21b, C28, C29) prevents naming conflicts
|
|
498
|
+
3. **Smart Flattening**: Auto-detection (C04, C05, C12, C13, C18, C30) reduces unnecessary nesting
|
|
499
|
+
4. **Name Preservation**: Function name preference (C16, C19) maintains semantic meaning
|
|
500
|
+
5. **Depth Awareness**: Many conditions check `currentDepth` to preserve root-level structure
|
|
501
|
+
6. **Special Cases**: AddApi files (C33) get always-flatten treatment for API extension
|
|
371
502
|
|
|
372
503
|
---
|
|
373
504
|
|
|
374
|
-
##
|
|
505
|
+
## Document Maintenance
|
|
506
|
+
|
|
507
|
+
**Version**: 2.0
|
|
508
|
+
**Last Full Audit**: January 3, 2026
|
|
509
|
+
**Lines Verified**: All line numbers manually verified against source code
|
|
510
|
+
**Cross-References**: Enhanced linking to API-RULES-v2.md and API-FLATTENING-v2.md
|
|
511
|
+
**Links**: All GitHub-style links use `#Lxxx-Lyyy` format for precise navigation
|
|
512
|
+
|
|
513
|
+
**Next Steps**:
|
|
514
|
+
|
|
515
|
+
- Verify line numbers after any source code changes
|
|
516
|
+
- Update cross-references when higher-level documentation changes
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
## C19-C22: Rule 12 Module Ownership Conditions
|
|
375
521
|
|
|
376
|
-
**
|
|
377
|
-
**
|
|
378
|
-
**
|
|
522
|
+
**Functionality**: Module ownership tracking and selective API overwriting validation
|
|
523
|
+
**Primary Rule**: [Rule 12 - Module Ownership and Selective API Overwriting](API-RULES-v2.md#rule-12-module-ownership-and-selective-api-overwriting)
|
|
524
|
+
**Source Code**: [slothlet.mjs](../src/slothlet.mjs) (ownership tracking), [add_api.mjs](../src/lib/helpers/api_builder/add_api.mjs) (validation)
|
|
379
525
|
|
|
380
|
-
|
|
526
|
+
### C19: Configuration Validation Condition
|
|
381
527
|
|
|
382
|
-
|
|
528
|
+
**Code Location**: [slothlet.mjs#L85-L90](../src/slothlet.mjs#L85-L90)
|
|
383
529
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
530
|
+
```javascript
|
|
531
|
+
if (options.forceOverwrite && !this._config.enableModuleOwnership) {
|
|
532
|
+
throw new Error("forceOverwrite requires enableModuleOwnership: true in slothlet configuration");
|
|
533
|
+
}
|
|
534
|
+
```
|
|
388
535
|
|
|
389
|
-
|
|
536
|
+
**Triggers**: `options.forceOverwrite === true && this._config.enableModuleOwnership !== true`
|
|
537
|
+
**Logic**: Configuration consistency validation
|
|
538
|
+
**Result**: Throws error requiring enableModuleOwnership for forceOverwrite operations
|
|
390
539
|
|
|
391
|
-
|
|
392
|
-
**Condition**: `if (decisions.preferredName && decisions.preferredName !== moduleName)`
|
|
393
|
-
**Purpose**: Use preferred name without flattening
|
|
394
|
-
**Result**: `return { [decisions.preferredName]: mod }`
|
|
540
|
+
### C20: Module ID Requirement Condition
|
|
395
541
|
|
|
396
|
-
|
|
542
|
+
**Code Location**: [slothlet.mjs#L90-L95](../src/slothlet.mjs#L90-L95)
|
|
397
543
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
544
|
+
```javascript
|
|
545
|
+
if (options.forceOverwrite && !options.moduleId) {
|
|
546
|
+
throw new Error("forceOverwrite requires moduleId parameter for ownership tracking");
|
|
547
|
+
}
|
|
548
|
+
```
|
|
402
549
|
|
|
403
|
-
|
|
550
|
+
**Triggers**: `options.forceOverwrite === true && !options.moduleId`
|
|
551
|
+
**Logic**: Module identification requirement for ownership tracking
|
|
552
|
+
**Result**: Throws error requiring moduleId for ownership-tracked operations
|
|
404
553
|
|
|
405
|
-
|
|
406
|
-
**Condition**: `if (shouldFlatten)`
|
|
407
|
-
**Purpose**: Apply various flattening strategies in multi-file context
|
|
408
|
-
**Branches**: Switch statement handling 4 flatten types [218-318](../src/lib/helpers/api_builder/construction.mjs#L218-L318)
|
|
554
|
+
### C21: Function Ownership Validation Condition
|
|
409
555
|
|
|
410
|
-
**
|
|
411
|
-
When Proxy assignment fails, creates wrapper proxy to ensure API completeness while preserving original proxy behavior
|
|
556
|
+
**Code Location**: [add_api.mjs#L145-L155](../src/lib/helpers/api_builder/add_api.mjs#L145-L155)
|
|
412
557
|
|
|
413
|
-
|
|
558
|
+
```javascript
|
|
559
|
+
if (currentTarget[finalKey] !== undefined && typeof currentTarget[finalKey] === "function" && this._config.enableModuleOwnership) {
|
|
560
|
+
const existingOwner = this._getApiOwnership(fullPath);
|
|
561
|
+
if (existingOwner && existingOwner !== options.moduleId) {
|
|
562
|
+
throw new Error(
|
|
563
|
+
`Cannot overwrite API "${fullPath}" - owned by module "${existingOwner}", attempted by module "${options.moduleId}". Modules can only overwrite APIs they own.`
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
```
|
|
414
568
|
|
|
415
|
-
**
|
|
416
|
-
**
|
|
417
|
-
**
|
|
418
|
-
|
|
419
|
-
|
|
569
|
+
**Triggers**: Function overwrite attempt with ownership tracking enabled
|
|
570
|
+
**Logic**: Cross-module ownership violation detection for functions
|
|
571
|
+
**Result**: Throws error if moduleId doesn't match existing function owner
|
|
572
|
+
|
|
573
|
+
### C22: Object Ownership Validation Condition
|
|
574
|
+
|
|
575
|
+
**Code Location**: [add_api.mjs#L160-L170](../src/lib/helpers/api_builder/add_api.mjs#L160-L170)
|
|
576
|
+
|
|
577
|
+
```javascript
|
|
578
|
+
if (currentTarget[finalKey] !== undefined && this._config.enableModuleOwnership && options.moduleId) {
|
|
579
|
+
const existingOwner = this._getApiOwnership(fullPath);
|
|
580
|
+
if (existingOwner && existingOwner !== options.moduleId) {
|
|
581
|
+
throw new Error(
|
|
582
|
+
`Cannot overwrite API "${fullPath}" - owned by module "${existingOwner}", attempted by module "${options.moduleId}". Modules can only overwrite APIs they own.`
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
**Triggers**: Object/namespace overwrite attempt with ownership tracking enabled
|
|
589
|
+
**Logic**: Cross-module ownership violation detection for objects/namespaces
|
|
590
|
+
**Result**: Throws error if moduleId doesn't match existing object owner
|
|
591
|
+
|
|
592
|
+
**Common Implementation Pattern**:
|
|
593
|
+
|
|
594
|
+
- ✅ Ownership tracking via `Map<string, string>` in `_moduleOwnership`
|
|
595
|
+
- ✅ Registration via `_registerApiOwnership(apiPath, moduleId)`
|
|
596
|
+
- ✅ Validation via `_getApiOwnership(apiPath)` lookup
|
|
597
|
+
- ✅ Cross-module protection regardless of `allowApiOverwrite` setting
|
|
420
598
|
|
|
421
599
|
---
|
|
422
600
|
|
|
423
|
-
##
|
|
601
|
+
## C33: AddApi Special File Detection
|
|
424
602
|
|
|
425
|
-
**
|
|
426
|
-
**
|
|
427
|
-
**
|
|
603
|
+
**Category**: AddApi
|
|
604
|
+
**Related Rule**: [Rule 11](API-RULES-v2.md#rule-11-addapi-special-file-pattern)
|
|
605
|
+
**Flattening Guide**: [F06: AddApi Special File Pattern](API-FLATTENING-v2.md#f06-addapi-special-file-pattern)
|
|
606
|
+
**Status**: ✅ **VERIFIED** (api_tests/api_smart_flatten_addapi)
|
|
428
607
|
|
|
429
|
-
|
|
608
|
+
**Pattern**: Files named `addapi.mjs` loaded via `addApi()` method always flatten regardless of `autoFlatten` setting
|
|
430
609
|
|
|
431
|
-
|
|
610
|
+
**Purpose**: Designed for seamless API namespace extensions - `addapi.mjs` files should extend the target API path directly without creating an intermediate `.addapi.` namespace level
|
|
432
611
|
|
|
433
|
-
**
|
|
434
|
-
**Condition**: `if (isSelfReferential)`
|
|
435
|
-
**Purpose**: Self-referential default exports in multi-default context preserve as namespace
|
|
436
|
-
**Result**: `shouldFlatten: false, preserveAsNamespace: true`
|
|
437
|
-
**Reason**: `"self-referential default export"`
|
|
612
|
+
**Implementation Location**: [src/lib/helpers/api_builder/add_api.mjs](../../src/lib/helpers/api_builder/add_api.mjs#L266-L310) (lines 266-310)
|
|
438
613
|
|
|
439
|
-
|
|
614
|
+
**When Evaluated**: During `addApiFromFolder()` execution, after modules are loaded but before they are merged into the API
|
|
440
615
|
|
|
441
|
-
**
|
|
442
|
-
**Condition**: `if (hasMultipleDefaultExports)` → [203](../src/lib/helpers/multidefault.mjs#L203): `if (moduleHasDefault)`
|
|
443
|
-
**Purpose**: Modules WITH default exports in multi-default context preserve as namespaces
|
|
444
|
-
**Result**: `shouldFlatten: false, preserveAsNamespace: true`
|
|
445
|
-
**Reason**: `"multi-default context with default export"`
|
|
616
|
+
**Condition Check**:
|
|
446
617
|
|
|
447
|
-
|
|
618
|
+
```javascript
|
|
619
|
+
// Rule 6: AddApi Special File Pattern - Handle addapi.mjs flattening
|
|
620
|
+
// Check if the loaded modules contain an 'addapi' key and flatten it
|
|
621
|
+
if (newModules && typeof newModules === "object" && newModules.addapi) {
|
|
622
|
+
if (instance.config.debug) {
|
|
623
|
+
console.log(`[DEBUG] addApi: Found addapi.mjs - applying Rule 6 flattening`);
|
|
624
|
+
console.log(`[DEBUG] addApi: Original structure:`, Object.keys(newModules));
|
|
625
|
+
console.log(`[DEBUG] addApi: Addapi contents:`, Object.keys(newModules.addapi));
|
|
626
|
+
}
|
|
448
627
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
**Purpose**: Modules WITHOUT default exports in multi-default context flatten to root
|
|
452
|
-
**Result**: `shouldFlatten: true, flattenToRoot: true`
|
|
453
|
-
**Reason**: `"multi-default context without default export"`
|
|
628
|
+
// Extract the addapi module content
|
|
629
|
+
const addapiContent = newModules.addapi;
|
|
454
630
|
|
|
455
|
-
|
|
631
|
+
// Remove the addapi key from newModules
|
|
632
|
+
delete newModules.addapi;
|
|
456
633
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
**Reason**: `"single named export matching filename"`
|
|
634
|
+
// Merge addapi content directly into the root level of newModules
|
|
635
|
+
if (addapiContent && typeof addapiContent === "object") {
|
|
636
|
+
// Handle both function exports and object exports
|
|
637
|
+
Object.assign(newModules, addapiContent);
|
|
462
638
|
|
|
463
|
-
|
|
639
|
+
if (instance.config.debug) {
|
|
640
|
+
console.log(`[DEBUG] addApi: After addapi flattening:`, Object.keys(newModules));
|
|
641
|
+
}
|
|
642
|
+
} else if (typeof addapiContent === "function") {
|
|
643
|
+
// If addapi exports a single function, merge its properties
|
|
644
|
+
Object.assign(newModules, addapiContent);
|
|
464
645
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
646
|
+
if (instance.config.debug) {
|
|
647
|
+
console.log(`[DEBUG] addApi: Flattened addapi function with properties:`, Object.keys(newModules));
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
```
|
|
468
652
|
|
|
469
|
-
|
|
653
|
+
**Example Structure**:
|
|
470
654
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
655
|
+
```text
|
|
656
|
+
plugin-folder/
|
|
657
|
+
└── addapi.mjs
|
|
658
|
+
export function initializePlugin() {...}
|
|
659
|
+
export function cleanup() {...}
|
|
660
|
+
export function configure() {...}
|
|
661
|
+
```
|
|
476
662
|
|
|
477
|
-
|
|
663
|
+
**API Usage**:
|
|
478
664
|
|
|
479
|
-
|
|
665
|
+
```javascript
|
|
666
|
+
// Load plugin folder via addApi
|
|
667
|
+
await api.addApi("plugins", "./plugin-folder");
|
|
480
668
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
669
|
+
// Result: addapi.mjs always flattens (no .addapi. level)
|
|
670
|
+
api.plugins.initializePlugin(); // ✅ Direct extension
|
|
671
|
+
api.plugins.cleanup(); // ✅ Seamless integration
|
|
672
|
+
api.plugins.configure(); // ✅ No intermediate namespace
|
|
673
|
+
```
|
|
484
674
|
|
|
485
|
-
|
|
675
|
+
**Without C33 Behavior** (hypothetical):
|
|
486
676
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
677
|
+
```javascript
|
|
678
|
+
// Without special handling, would create nested structure
|
|
679
|
+
api.plugins.addapi.initializePlugin(); // ❌ Unwanted intermediate level
|
|
680
|
+
api.plugins.addapi.cleanup(); // ❌ Breaks API extension pattern
|
|
681
|
+
```
|
|
492
682
|
|
|
493
|
-
|
|
683
|
+
**Key Implementation Details**:
|
|
494
684
|
|
|
495
|
-
1. **
|
|
496
|
-
2. **
|
|
497
|
-
3. **
|
|
498
|
-
4. **
|
|
499
|
-
5. **
|
|
685
|
+
1. **Detection**: Checks for `newModules.addapi` key in loaded module structure
|
|
686
|
+
2. **Extraction**: Stores content of `addapi` module in `addapiContent` variable
|
|
687
|
+
3. **Removal**: Deletes the `addapi` key from `newModules` to prevent namespace creation
|
|
688
|
+
4. **Flattening**: Merges all exports from `addapi.mjs` directly into root level of `newModules`
|
|
689
|
+
5. **Type Handling**: Supports both object exports and function exports with properties
|
|
500
690
|
|
|
501
|
-
|
|
691
|
+
**Use Cases**:
|
|
502
692
|
|
|
503
|
-
|
|
693
|
+
- 🔌 **Plugin Systems**: Runtime plugin loading that extends existing API namespaces
|
|
694
|
+
- 🔄 **Hot Reloading**: Dynamic API updates during development without intermediate levels
|
|
695
|
+
- 📦 **Modular Extensions**: Clean extension of existing API surfaces
|
|
696
|
+
- 🎯 **Targeted Integration**: Specific API namespace enhancement for add-on functionality
|
|
504
697
|
|
|
505
|
-
**
|
|
506
|
-
|
|
507
|
-
**
|
|
508
|
-
**
|
|
698
|
+
**Behavior Characteristics**:
|
|
699
|
+
|
|
700
|
+
- ✅ **Always Active**: Works regardless of `autoFlatten` configuration setting
|
|
701
|
+
- ✅ **Priority Processing**: Occurs before other flattening rules are applied
|
|
702
|
+
- ✅ **Transparent Integration**: Exports appear as if they were originally part of target namespace
|
|
703
|
+
- ✅ **Works with addApi Only**: Special handling only applies to `addApi()` method, not initial load
|
|
704
|
+
|
|
705
|
+
**Result**: `addapi.mjs` file contents are merged directly at the target API path level, eliminating the intermediate `.addapi.` namespace
|
|
706
|
+
|
|
707
|
+
**Common Implementation Pattern**:
|
|
708
|
+
|
|
709
|
+
- ✅ Detection via `newModules.addapi` property check
|
|
710
|
+
- ✅ Extraction and deletion of `addapi` key
|
|
711
|
+
- ✅ Direct merge using `Object.assign(newModules, addapiContent)`
|
|
712
|
+
- ✅ Support for both object and function exports
|