ima-claude 2.9.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/LICENSE +21 -0
- package/README.md +463 -0
- package/dist/cli.js +1064 -0
- package/package.json +49 -0
- package/platforms/claude/adapter.ts +115 -0
- package/platforms/junie/adapter.ts +254 -0
- package/platforms/junie/agents-template.md +113 -0
- package/platforms/junie/hook-translations.md +84 -0
- package/platforms/shared/detector.ts +27 -0
- package/platforms/shared/installer.ts +202 -0
- package/platforms/shared/types.ts +78 -0
- package/plugins/ima-claude/.claude-plugin/plugin.json +25 -0
- package/plugins/ima-claude/agents/explorer.md +30 -0
- package/plugins/ima-claude/agents/implementer.md +30 -0
- package/plugins/ima-claude/agents/memory.md +42 -0
- package/plugins/ima-claude/agents/reviewer.md +53 -0
- package/plugins/ima-claude/agents/tester.md +33 -0
- package/plugins/ima-claude/agents/wp-developer.md +46 -0
- package/plugins/ima-claude/hooks/README.md +145 -0
- package/plugins/ima-claude/hooks/atlassian_prereqs.py +112 -0
- package/plugins/ima-claude/hooks/block_sed_edits.py +59 -0
- package/plugins/ima-claude/hooks/bootstrap.sh +90 -0
- package/plugins/ima-claude/hooks/bootstrap_utility_check.py +94 -0
- package/plugins/ima-claude/hooks/composer_autoload_check.py +70 -0
- package/plugins/ima-claude/hooks/docs_organization.py +104 -0
- package/plugins/ima-claude/hooks/enforce_rg_over_grep.py +56 -0
- package/plugins/ima-claude/hooks/fp_utility_check.py +90 -0
- package/plugins/ima-claude/hooks/hook_logger.py +69 -0
- package/plugins/ima-claude/hooks/hooks.json +239 -0
- package/plugins/ima-claude/hooks/jira_issue_fetch.py +79 -0
- package/plugins/ima-claude/hooks/jquery_in_wordpress.py +92 -0
- package/plugins/ima-claude/hooks/memory_bootstrap.py +79 -0
- package/plugins/ima-claude/hooks/memory_store_reminder.py +75 -0
- package/plugins/ima-claude/hooks/prompt_coach.py +125 -0
- package/plugins/ima-claude/hooks/prompt_coach_digest.md +48 -0
- package/plugins/ima-claude/hooks/prompt_coach_system.md +30 -0
- package/plugins/ima-claude/hooks/sequential_thinking_check.py +81 -0
- package/plugins/ima-claude/hooks/serena_over_grep.py +96 -0
- package/plugins/ima-claude/hooks/serena_over_read.py +66 -0
- package/plugins/ima-claude/hooks/serena_project_check.py +133 -0
- package/plugins/ima-claude/hooks/sql_injection_check.py +73 -0
- package/plugins/ima-claude/hooks/task_master_after_plan.py +31 -0
- package/plugins/ima-claude/hooks/task_master_before_impl.py +93 -0
- package/plugins/ima-claude/hooks/tavily_extract_advanced.py +48 -0
- package/plugins/ima-claude/hooks/vestige_before_external.py +86 -0
- package/plugins/ima-claude/hooks/webfetch_to_tavily.py +42 -0
- package/plugins/ima-claude/hooks/websearch_to_tavily.py +41 -0
- package/plugins/ima-claude/hooks/wp_security_check.py +150 -0
- package/plugins/ima-claude/personalities/README.md +45 -0
- package/plugins/ima-claude/personalities/enable-40k.md +69 -0
- package/plugins/ima-claude/personalities/enable-templars.md +69 -0
- package/plugins/ima-claude/skills/.research-summary.md +340 -0
- package/plugins/ima-claude/skills/architect/SKILL.md +304 -0
- package/plugins/ima-claude/skills/compound-bridge/SKILL.md +200 -0
- package/plugins/ima-claude/skills/discourse/SKILL.md +440 -0
- package/plugins/ima-claude/skills/discourse-admin/SKILL.md +192 -0
- package/plugins/ima-claude/skills/discourse-admin/references/api-endpoints.md +441 -0
- package/plugins/ima-claude/skills/discourse-admin/references/gotchas.md +107 -0
- package/plugins/ima-claude/skills/discourse-admin/references/staging-defaults.md +98 -0
- package/plugins/ima-claude/skills/discourse-admin/scripts/discourse-admin.py +319 -0
- package/plugins/ima-claude/skills/docs-organize/SKILL.md +254 -0
- package/plugins/ima-claude/skills/docs-organize/templates/active-README.md +50 -0
- package/plugins/ima-claude/skills/docs-organize/templates/archive-README.md +57 -0
- package/plugins/ima-claude/skills/docs-organize/templates/docs-README.md +43 -0
- package/plugins/ima-claude/skills/docs-organize/templates/phase-archive-README.md +83 -0
- package/plugins/ima-claude/skills/docs-organize/templates/section-README.md +48 -0
- package/plugins/ima-claude/skills/docs-organize/templates/transient-README.md +79 -0
- package/plugins/ima-claude/skills/docs-organize/templates/transient-gitignore +9 -0
- package/plugins/ima-claude/skills/ember-discourse/SKILL.md +496 -0
- package/plugins/ima-claude/skills/functional-programmer/SKILL.md +258 -0
- package/plugins/ima-claude/skills/ima-bootstrap/SKILL.md +278 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/bootstrap-patterns.md +356 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/ima-brand.md +273 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/theme-integration.md +212 -0
- package/plugins/ima-claude/skills/ima-brand/SKILL.md +108 -0
- package/plugins/ima-claude/skills/ima-brand/references/brand-identity.md +140 -0
- package/plugins/ima-claude/skills/ima-brand/references/digital-standards.md +180 -0
- package/plugins/ima-claude/skills/ima-brand/references/visual-system.md +173 -0
- package/plugins/ima-claude/skills/ima-forms-expert/SKILL.md +175 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/container-components.md +154 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/examples.md +328 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/field-components.md +298 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/form-factory.md +193 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/quick-reference.md +153 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/validation-engine.md +336 -0
- package/plugins/ima-claude/skills/jira-checkpoint/SKILL.md +178 -0
- package/plugins/ima-claude/skills/jquery/SKILL.md +413 -0
- package/plugins/ima-claude/skills/js-fp/SKILL.md +463 -0
- package/plugins/ima-claude/skills/js-fp/core-principles.md +487 -0
- package/plugins/ima-claude/skills/js-fp/examples/pure-functions.js +260 -0
- package/plugins/ima-claude/skills/js-fp/examples/tests/pure-functions.test.js +262 -0
- package/plugins/ima-claude/skills/js-fp/references/anti-patterns.md +120 -0
- package/plugins/ima-claude/skills/js-fp/references/performance-patterns.md +116 -0
- package/plugins/ima-claude/skills/js-fp/references/testing-patterns.md +134 -0
- package/plugins/ima-claude/skills/js-fp-api/SKILL.md +280 -0
- package/plugins/ima-claude/skills/js-fp-api/examples/crud-endpoint.js +258 -0
- package/plugins/ima-claude/skills/js-fp-api/references/middleware-patterns.md +134 -0
- package/plugins/ima-claude/skills/js-fp-api/references/security-sql.md +110 -0
- package/plugins/ima-claude/skills/js-fp-api/references/validation-patterns.md +165 -0
- package/plugins/ima-claude/skills/js-fp-react/SKILL.md +447 -0
- package/plugins/ima-claude/skills/js-fp-react/examples/ProductCard.tsx +65 -0
- package/plugins/ima-claude/skills/js-fp-react/references/hooks-advanced.md +136 -0
- package/plugins/ima-claude/skills/js-fp-react/references/performance-patterns.md +175 -0
- package/plugins/ima-claude/skills/js-fp-vue/SKILL.md +322 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/complete-examples.md +397 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/composables-advanced.md +282 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/reactivity-patterns.md +348 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/testing.md +314 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/SKILL.md +301 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/ajax-patterns.md +192 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/event-patterns.md +136 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/wp-integration.md +248 -0
- package/plugins/ima-claude/skills/livecanvas/SKILL.md +209 -0
- package/plugins/ima-claude/skills/livecanvas/references/livecanvas-features.md +311 -0
- package/plugins/ima-claude/skills/livecanvas/references/loops-and-logic.md +730 -0
- package/plugins/ima-claude/skills/livecanvas/references/picostrap.md +227 -0
- package/plugins/ima-claude/skills/mcp-atlassian/SKILL.md +339 -0
- package/plugins/ima-claude/skills/mcp-context7/SKILL.md +109 -0
- package/plugins/ima-claude/skills/mcp-memory/SKILL.md +182 -0
- package/plugins/ima-claude/skills/mcp-qdrant/SKILL.md +233 -0
- package/plugins/ima-claude/skills/mcp-sequential/SKILL.md +149 -0
- package/plugins/ima-claude/skills/mcp-serena/SKILL.md +174 -0
- package/plugins/ima-claude/skills/mcp-tavily/SKILL.md +118 -0
- package/plugins/ima-claude/skills/mcp-vestige/SKILL.md +259 -0
- package/plugins/ima-claude/skills/php-authnet/SKILL.md +275 -0
- package/plugins/ima-claude/skills/php-authnet/references/api-reference.md +624 -0
- package/plugins/ima-claude/skills/php-authnet/references/sandbox-testing.md +424 -0
- package/plugins/ima-claude/skills/php-fp/SKILL.md +333 -0
- package/plugins/ima-claude/skills/php-fp/examples/pure-functions.php +403 -0
- package/plugins/ima-claude/skills/php-fp/examples/tests/PureFunctionsTest.php +515 -0
- package/plugins/ima-claude/skills/php-fp/references/core-principles.md +277 -0
- package/plugins/ima-claude/skills/php-fp/references/testing-patterns.md +374 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/SKILL.md +216 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/fp-patterns.md +275 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/plugin-architecture.md +295 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/security-examples.md +203 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/testing-strategy.md +259 -0
- package/plugins/ima-claude/skills/phpunit-wp/SKILL.md +716 -0
- package/plugins/ima-claude/skills/playwright/SKILL.md +434 -0
- package/plugins/ima-claude/skills/playwright/references/accessibility-testing.md +153 -0
- package/plugins/ima-claude/skills/playwright/references/ci-cd.md +268 -0
- package/plugins/ima-claude/skills/playwright/references/network-mocking.md +270 -0
- package/plugins/ima-claude/skills/playwright/references/visual-regression.md +215 -0
- package/plugins/ima-claude/skills/py-fp/SKILL.md +663 -0
- package/plugins/ima-claude/skills/py-fp/examples/pure-functions.py +185 -0
- package/plugins/ima-claude/skills/py-fp/examples/tests/test_pure_functions.py +244 -0
- package/plugins/ima-claude/skills/py-fp/references/core-principles.md +381 -0
- package/plugins/ima-claude/skills/py-fp/references/testing-patterns.md +283 -0
- package/plugins/ima-claude/skills/quasar-fp/SKILL.md +327 -0
- package/plugins/ima-claude/skills/quasar-fp/metadata.json +85 -0
- package/plugins/ima-claude/skills/quasar-fp/references/component-patterns.md +257 -0
- package/plugins/ima-claude/skills/quasar-fp/references/theme-integration.md +233 -0
- package/plugins/ima-claude/skills/quasar-fp/references/utility-classes.md +237 -0
- package/plugins/ima-claude/skills/quickstart/SKILL.md +129 -0
- package/plugins/ima-claude/skills/rails/SKILL.md +359 -0
- package/plugins/ima-claude/skills/resume-session/SKILL.md +68 -0
- package/plugins/ima-claude/skills/rg/SKILL.md +205 -0
- package/plugins/ima-claude/skills/ruby-fp/SKILL.md +336 -0
- package/plugins/ima-claude/skills/save-session/SKILL.md +81 -0
- package/plugins/ima-claude/skills/scorecard/SKILL.md +96 -0
- package/plugins/ima-claude/skills/skill-analyzer/SKILL.md +127 -0
- package/plugins/ima-claude/skills/skill-analyzer/references/advanced-checklist.md +44 -0
- package/plugins/ima-claude/skills/skill-analyzer/references/core-checklist.md +60 -0
- package/plugins/ima-claude/skills/skill-analyzer/scripts/analyze_skill.py +418 -0
- package/plugins/ima-claude/skills/skill-creator/LICENSE.txt +202 -0
- package/plugins/ima-claude/skills/skill-creator/SKILL.md +343 -0
- package/plugins/ima-claude/skills/skill-creator/references/output-patterns.md +82 -0
- package/plugins/ima-claude/skills/skill-creator/references/workflows.md +28 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/plugins/ima-claude/skills/task-master/SKILL.md +51 -0
- package/plugins/ima-claude/skills/task-planner/SKILL.md +228 -0
- package/plugins/ima-claude/skills/task-runner/SKILL.md +192 -0
- package/plugins/ima-claude/skills/unit-testing/SKILL.md +198 -0
- package/plugins/ima-claude/skills/unit-testing/references/mock-patterns.md +181 -0
- package/plugins/ima-claude/skills/unit-testing/references/tdd-workflow.md +177 -0
- package/plugins/ima-claude/skills/unit-testing/references/test-strategy.md +126 -0
- package/plugins/ima-claude/skills/wp-local/SKILL.md +246 -0
- package/plugins/ima-claude/skills/wp-local/references/configuration.md +198 -0
- package/plugins/ima-claude/skills/wp-local/references/wp-cli-reference.md +406 -0
- package/plugins/ima-claude/skills/wp-local/scripts/wp-local.sh +61 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
# Core FP Principles - Deep Dive
|
|
2
|
+
|
|
3
|
+
Complete functional programming philosophy with detailed pattern explanations and cross-pattern comparisons.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Philosophy and Mindset](#philosophy-and-mindset)
|
|
8
|
+
2. [Purity Deep Dive](#purity-deep-dive)
|
|
9
|
+
3. [Composition Strategies](#composition-strategies)
|
|
10
|
+
4. [Dependency Injection Patterns](#dependency-injection-patterns)
|
|
11
|
+
5. [Immutability Strategies](#immutability-strategies)
|
|
12
|
+
6. [Error Handling Patterns](#error-handling-patterns)
|
|
13
|
+
7. [State Management](#state-management)
|
|
14
|
+
8. [Cross-Pattern Comparisons](#cross-pattern-comparisons)
|
|
15
|
+
|
|
16
|
+
## Philosophy and Mindset
|
|
17
|
+
|
|
18
|
+
### The FP Mental Model
|
|
19
|
+
|
|
20
|
+
Functional programming is about:
|
|
21
|
+
- **Functions as building blocks**: Small, composable, testable units
|
|
22
|
+
- **Data transformation**: Input → Processing → Output (no hidden state)
|
|
23
|
+
- **Explicit over implicit**: Dependencies and effects are visible
|
|
24
|
+
- **Simplicity over cleverness**: Native patterns over utilities
|
|
25
|
+
|
|
26
|
+
### Why FP in JavaScript?
|
|
27
|
+
|
|
28
|
+
**JavaScript's FP strengths**:
|
|
29
|
+
- First-class functions (functions as values)
|
|
30
|
+
- Closures (lexical scoping for data encapsulation)
|
|
31
|
+
- Array methods (map, filter, reduce are FP primitives)
|
|
32
|
+
- Async/await (functional async composition)
|
|
33
|
+
|
|
34
|
+
**NOT about**:
|
|
35
|
+
- Creating Haskell in JavaScript
|
|
36
|
+
- Complex category theory
|
|
37
|
+
- Academic purity for its own sake
|
|
38
|
+
- FP utility libraries
|
|
39
|
+
|
|
40
|
+
## Purity Deep Dive
|
|
41
|
+
|
|
42
|
+
### What Makes a Function Pure?
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
// Pure: Same inputs → Same outputs, no side effects
|
|
46
|
+
const add = (a, b) => a + b
|
|
47
|
+
const multiply = (x) => (y) => x * y
|
|
48
|
+
|
|
49
|
+
// Impure: Depends on external state
|
|
50
|
+
let discount = 0.1
|
|
51
|
+
const calculatePrice = (price) => price * (1 - discount) // ❌
|
|
52
|
+
|
|
53
|
+
// Pure version: Explicit dependency
|
|
54
|
+
const calculatePrice = (price, discount) => price * (1 - discount) // ✅
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Benefits of Purity
|
|
58
|
+
|
|
59
|
+
**1. Testability**: 100% of logic is testable
|
|
60
|
+
```javascript
|
|
61
|
+
// Pure function - test every data type easily
|
|
62
|
+
const safeDivide = (a, b) => b === 0 ? 0 : a / b
|
|
63
|
+
|
|
64
|
+
describe('safeDivide', () => {
|
|
65
|
+
const testCases = [
|
|
66
|
+
[10, 2, 5],
|
|
67
|
+
[10, 0, 0],
|
|
68
|
+
[0, 5, 0],
|
|
69
|
+
[-10, 2, -5]
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
testCases.forEach(([a, b, expected]) => {
|
|
73
|
+
it(`${a} / ${b} = ${expected}`, () => {
|
|
74
|
+
expect(safeDivide(a, b)).toBe(expected)
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**2. Predictability**: No surprises from hidden state
|
|
81
|
+
```javascript
|
|
82
|
+
// Impure: Can fail randomly based on network
|
|
83
|
+
const getUser = (id) => fetch(`/users/${id}`).then(r => r.json()) // ❌
|
|
84
|
+
|
|
85
|
+
// Pure: Explicit dependency injection
|
|
86
|
+
const getUser = (id, fetcher) => fetcher.get(`/users/${id}`) // ✅
|
|
87
|
+
|
|
88
|
+
// Test with mock
|
|
89
|
+
const mockFetcher = { get: jest.fn().mockResolvedValue({ id: 1, name: 'Test' }) }
|
|
90
|
+
await getUser(1, mockFetcher) // Fully controllable
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**3. Memoization**: Pure functions can be cached safely
|
|
94
|
+
```javascript
|
|
95
|
+
const memoize = (fn) => {
|
|
96
|
+
const cache = new Map()
|
|
97
|
+
return (...args) => {
|
|
98
|
+
const key = JSON.stringify(args)
|
|
99
|
+
if (cache.has(key)) return cache.get(key)
|
|
100
|
+
const result = fn(...args)
|
|
101
|
+
cache.set(key, result)
|
|
102
|
+
return result
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Only works with pure functions
|
|
107
|
+
const expensiveCalculation = memoize((n) => {
|
|
108
|
+
// Complex computation
|
|
109
|
+
return n * n * n
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Side Effect Isolation
|
|
114
|
+
|
|
115
|
+
**Pattern**: Push effects to the edges
|
|
116
|
+
```javascript
|
|
117
|
+
// ❌ Mixed concerns
|
|
118
|
+
const processAndSaveUser = async (userData) => {
|
|
119
|
+
const validated = validateUser(userData) // Pure
|
|
120
|
+
console.log('Validated:', validated) // Side effect
|
|
121
|
+
const enhanced = enhanceUser(validated) // Pure
|
|
122
|
+
await database.save(enhanced) // Side effect
|
|
123
|
+
console.log('Saved:', enhanced.id) // Side effect
|
|
124
|
+
return enhanced
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ✅ Separated concerns
|
|
128
|
+
// Pure business logic
|
|
129
|
+
const processUser = (userData) => {
|
|
130
|
+
const validated = validateUser(userData)
|
|
131
|
+
if (!validated.valid) return validated
|
|
132
|
+
return { valid: true, data: enhanceUser(validated.data) }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Side effects at the edge
|
|
136
|
+
const saveUser = async (userData, logger, database) => {
|
|
137
|
+
const result = processUser(userData) // Pure
|
|
138
|
+
|
|
139
|
+
if (!result.valid) {
|
|
140
|
+
logger.error('Validation failed', result.errors)
|
|
141
|
+
return result
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
logger.info('Validated', result.data)
|
|
145
|
+
const saved = await database.save(result.data)
|
|
146
|
+
logger.info('Saved', saved.id)
|
|
147
|
+
return { valid: true, data: saved }
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Composition Strategies
|
|
152
|
+
|
|
153
|
+
### Why Composition Over Inheritance?
|
|
154
|
+
|
|
155
|
+
**Problems with inheritance**:
|
|
156
|
+
- Tight coupling between parent and child
|
|
157
|
+
- Fragile base class problem
|
|
158
|
+
- Deep hierarchies are hard to understand
|
|
159
|
+
- Can't mix behaviors from multiple parents easily
|
|
160
|
+
|
|
161
|
+
**Composition benefits**:
|
|
162
|
+
- Loosely coupled functions
|
|
163
|
+
- Easy to understand each piece
|
|
164
|
+
- Mix and match behaviors freely
|
|
165
|
+
- Easy to test each function
|
|
166
|
+
|
|
167
|
+
### Composition Patterns
|
|
168
|
+
|
|
169
|
+
**1. Sequential Composition (early returns)**
|
|
170
|
+
```javascript
|
|
171
|
+
// Each step can short-circuit
|
|
172
|
+
const processOrder = (order) => {
|
|
173
|
+
const validated = validateOrder(order)
|
|
174
|
+
if (!validated.valid) return validated
|
|
175
|
+
|
|
176
|
+
const priced = calculatePrice(validated.data)
|
|
177
|
+
if (!priced.valid) return priced
|
|
178
|
+
|
|
179
|
+
const inventoryCheck = checkInventory(priced.data)
|
|
180
|
+
if (!inventoryCheck.valid) return inventoryCheck
|
|
181
|
+
|
|
182
|
+
return { valid: true, data: prepareShipment(inventoryCheck.data) }
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**2. Array Methods Composition**
|
|
187
|
+
```javascript
|
|
188
|
+
// Native JavaScript composition
|
|
189
|
+
const processUsers = (users) =>
|
|
190
|
+
users
|
|
191
|
+
.filter(user => user.active)
|
|
192
|
+
.map(user => ({ ...user, displayName: `${user.firstName} ${user.lastName}` }))
|
|
193
|
+
.sort((a, b) => a.lastName.localeCompare(b.lastName))
|
|
194
|
+
.slice(0, 10)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**3. Function Factories**
|
|
198
|
+
```javascript
|
|
199
|
+
// Create specialized functions
|
|
200
|
+
const createTransformer = (config) => {
|
|
201
|
+
// Pre-compile configuration
|
|
202
|
+
const rules = compileRules(config.rules)
|
|
203
|
+
const filters = compileFilters(config.filters)
|
|
204
|
+
|
|
205
|
+
return (data) => {
|
|
206
|
+
const filtered = filters.reduce((d, filter) => filter(d), data)
|
|
207
|
+
return rules.reduce((d, rule) => rule(d), filtered)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Use specialized function
|
|
212
|
+
const userTransformer = createTransformer(userConfig)
|
|
213
|
+
const results = users.map(userTransformer)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Dependency Injection Patterns
|
|
217
|
+
|
|
218
|
+
### Why DI in FP?
|
|
219
|
+
|
|
220
|
+
- Makes dependencies explicit
|
|
221
|
+
- Enables complete testing
|
|
222
|
+
- Reduces coupling
|
|
223
|
+
- Makes side effects visible
|
|
224
|
+
|
|
225
|
+
### DI Pattern Levels
|
|
226
|
+
|
|
227
|
+
**Level 1: Direct Parameter Injection**
|
|
228
|
+
```javascript
|
|
229
|
+
const saveUser = (user, hasher, database) => {
|
|
230
|
+
const hashed = hasher.hash(user.password)
|
|
231
|
+
return database.save({ ...user, password: hashed })
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Test with mocks
|
|
235
|
+
const mockHasher = { hash: (p) => `hashed_${p}` }
|
|
236
|
+
const mockDb = { save: jest.fn() }
|
|
237
|
+
saveUser(testUser, mockHasher, mockDb)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Level 2: Function Factory**
|
|
241
|
+
```javascript
|
|
242
|
+
const createUserService = (hasher, database) => ({
|
|
243
|
+
save: (user) => saveUser(user, hasher, database),
|
|
244
|
+
find: (id) => database.findById(id),
|
|
245
|
+
update: (id, updates) => updateUser(id, updates, hasher, database)
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
// Create once with real deps
|
|
249
|
+
const userService = createUserService(bcrypt, postgresDb)
|
|
250
|
+
|
|
251
|
+
// Use without passing deps every time
|
|
252
|
+
await userService.save(userData)
|
|
253
|
+
|
|
254
|
+
// Test with mock deps
|
|
255
|
+
const testService = createUserService(mockHasher, mockDb)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Level 3: Higher-Order Functions**
|
|
259
|
+
```javascript
|
|
260
|
+
const withLogging = (fn, logger) => async (...args) => {
|
|
261
|
+
logger.info('Starting', { fn: fn.name, args })
|
|
262
|
+
try {
|
|
263
|
+
const result = await fn(...args)
|
|
264
|
+
logger.info('Success', { fn: fn.name, result })
|
|
265
|
+
return result
|
|
266
|
+
} catch (error) {
|
|
267
|
+
logger.error('Failed', { fn: fn.name, error })
|
|
268
|
+
throw error
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Wrap any function with logging
|
|
273
|
+
const saveUserWithLogging = withLogging(saveUser, console)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Immutability Strategies
|
|
277
|
+
|
|
278
|
+
### Why Immutability?
|
|
279
|
+
|
|
280
|
+
- Prevents unexpected mutations
|
|
281
|
+
- Makes state changes explicit
|
|
282
|
+
- Enables time-travel debugging
|
|
283
|
+
- Safer concurrent operations
|
|
284
|
+
|
|
285
|
+
### Immutable Operations
|
|
286
|
+
|
|
287
|
+
**Objects**:
|
|
288
|
+
```javascript
|
|
289
|
+
// Add property
|
|
290
|
+
const addProp = (obj, key, value) => ({ ...obj, [key]: value })
|
|
291
|
+
|
|
292
|
+
// Remove property
|
|
293
|
+
const removeProp = (obj, key) => {
|
|
294
|
+
const { [key]: removed, ...rest } = obj
|
|
295
|
+
return rest
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Update nested property
|
|
299
|
+
const updateNested = (obj, path, value) => {
|
|
300
|
+
const [key, ...rest] = path
|
|
301
|
+
if (rest.length === 0) return { ...obj, [key]: value }
|
|
302
|
+
return { ...obj, [key]: updateNested(obj[key], rest, value) }
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Arrays**:
|
|
307
|
+
```javascript
|
|
308
|
+
// Add
|
|
309
|
+
const add = (arr, item) => [...arr, item]
|
|
310
|
+
const addAt = (arr, index, item) => [...arr.slice(0, index), item, ...arr.slice(index)]
|
|
311
|
+
|
|
312
|
+
// Remove
|
|
313
|
+
const remove = (arr, index) => [...arr.slice(0, index), ...arr.slice(index + 1)]
|
|
314
|
+
const removeBy = (arr, predicate) => arr.filter(item => !predicate(item))
|
|
315
|
+
|
|
316
|
+
// Update
|
|
317
|
+
const update = (arr, index, updater) =>
|
|
318
|
+
arr.map((item, i) => i === index ? updater(item) : item)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Error Handling Patterns
|
|
322
|
+
|
|
323
|
+
### Result Type Pattern
|
|
324
|
+
|
|
325
|
+
```javascript
|
|
326
|
+
// Standard result shape
|
|
327
|
+
const createResult = (data, error = null) =>
|
|
328
|
+
error ? { success: false, error } : { success: true, data }
|
|
329
|
+
|
|
330
|
+
// Use in functions
|
|
331
|
+
const divide = (a, b) =>
|
|
332
|
+
b === 0
|
|
333
|
+
? createResult(null, 'Division by zero')
|
|
334
|
+
: createResult(a / b)
|
|
335
|
+
|
|
336
|
+
// Chain results
|
|
337
|
+
const calculate = (a, b, c) => {
|
|
338
|
+
const result1 = divide(a, b)
|
|
339
|
+
if (!result1.success) return result1
|
|
340
|
+
|
|
341
|
+
const result2 = divide(result1.data, c)
|
|
342
|
+
return result2
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Try-Catch Wrapper
|
|
347
|
+
|
|
348
|
+
```javascript
|
|
349
|
+
const tryCatch = (fn) => async (...args) => {
|
|
350
|
+
try {
|
|
351
|
+
const data = await fn(...args)
|
|
352
|
+
return { success: true, data }
|
|
353
|
+
} catch (error) {
|
|
354
|
+
return { success: false, error: error.message }
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Wrap async functions
|
|
359
|
+
const safeFetchUser = tryCatch(fetchUser)
|
|
360
|
+
const result = await safeFetchUser(userId)
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## State Management
|
|
364
|
+
|
|
365
|
+
### Local State with Closures
|
|
366
|
+
|
|
367
|
+
```javascript
|
|
368
|
+
const createCounter = (initial = 0) => {
|
|
369
|
+
let count = initial
|
|
370
|
+
|
|
371
|
+
return {
|
|
372
|
+
get: () => count,
|
|
373
|
+
increment: () => ++count,
|
|
374
|
+
decrement: () => --count,
|
|
375
|
+
reset: () => count = initial
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const counter = createCounter(10)
|
|
380
|
+
counter.increment() // 11
|
|
381
|
+
counter.get() // 11
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Immutable State Updates
|
|
385
|
+
|
|
386
|
+
```javascript
|
|
387
|
+
const createStore = (initialState) => {
|
|
388
|
+
let state = initialState
|
|
389
|
+
const listeners = []
|
|
390
|
+
|
|
391
|
+
return {
|
|
392
|
+
getState: () => state,
|
|
393
|
+
setState: (updater) => {
|
|
394
|
+
state = updater(state)
|
|
395
|
+
listeners.forEach(listener => listener(state))
|
|
396
|
+
},
|
|
397
|
+
subscribe: (listener) => {
|
|
398
|
+
listeners.push(listener)
|
|
399
|
+
return () => {
|
|
400
|
+
const index = listeners.indexOf(listener)
|
|
401
|
+
if (index > -1) listeners.splice(index, 1)
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## Cross-Pattern Comparisons
|
|
409
|
+
|
|
410
|
+
### OOP vs FP Comparison
|
|
411
|
+
|
|
412
|
+
**OOP Approach**:
|
|
413
|
+
```javascript
|
|
414
|
+
class UserService {
|
|
415
|
+
constructor(database, hasher) {
|
|
416
|
+
this.database = database
|
|
417
|
+
this.hasher = hasher
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
async saveUser(userData) {
|
|
421
|
+
const hashed = await this.hasher.hash(userData.password)
|
|
422
|
+
return this.database.save({ ...userData, password: hashed })
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**FP Approach**:
|
|
428
|
+
```javascript
|
|
429
|
+
const createUserService = (database, hasher) => ({
|
|
430
|
+
saveUser: async (userData) => {
|
|
431
|
+
const hashed = await hasher.hash(userData.password)
|
|
432
|
+
return database.save({ ...userData, password: hashed })
|
|
433
|
+
}
|
|
434
|
+
})
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**Trade-offs**:
|
|
438
|
+
- FP: Simpler, more explicit, easier to test
|
|
439
|
+
- OOP: More familiar to some developers, encapsulation through privacy
|
|
440
|
+
|
|
441
|
+
### Procedural vs FP
|
|
442
|
+
|
|
443
|
+
**Procedural**:
|
|
444
|
+
```javascript
|
|
445
|
+
function processUsers(users) {
|
|
446
|
+
const result = []
|
|
447
|
+
for (let i = 0; i < users.length; i++) {
|
|
448
|
+
if (users[i].active) {
|
|
449
|
+
result.push({
|
|
450
|
+
...users[i],
|
|
451
|
+
displayName: users[i].firstName + ' ' + users[i].lastName
|
|
452
|
+
})
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return result
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**FP**:
|
|
460
|
+
```javascript
|
|
461
|
+
const processUsers = (users) =>
|
|
462
|
+
users
|
|
463
|
+
.filter(user => user.active)
|
|
464
|
+
.map(user => ({
|
|
465
|
+
...user,
|
|
466
|
+
displayName: `${user.firstName} ${user.lastName}`
|
|
467
|
+
}))
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
**Trade-offs**:
|
|
471
|
+
- FP: More declarative, easier to understand intent
|
|
472
|
+
- Procedural: More control, potentially more performant for very large datasets
|
|
473
|
+
|
|
474
|
+
## When to Break the Rules
|
|
475
|
+
|
|
476
|
+
FP is a tool, not a religion. Break rules when:
|
|
477
|
+
|
|
478
|
+
1. **Performance**: Mutation is faster for large datasets (measure first!)
|
|
479
|
+
2. **Simplicity**: Sometimes procedural code is clearer
|
|
480
|
+
3. **Library Integration**: Some libraries require mutation
|
|
481
|
+
4. **Team Familiarity**: Don't force FP on a team that hates it
|
|
482
|
+
|
|
483
|
+
Always prioritize:
|
|
484
|
+
1. Correctness
|
|
485
|
+
2. Simplicity
|
|
486
|
+
3. Maintainability
|
|
487
|
+
4. Performance (when needed with evidence)
|