@codyswann/lisa 1.55.3 → 1.56.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/all/deletions.json +0 -1
- package/cdk/copy-overwrite/tsconfig.json +3 -0
- package/expo/copy-overwrite/tsconfig.json +7 -0
- package/expo/deletions.json +1 -0
- package/nestjs/copy-overwrite/tsconfig.json +6 -0
- package/package.json +6 -3
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/skills/reduce-complexity/SKILL.md +251 -0
- package/plugins/lisa-expo/skills/reduce-complexity/references/extraction-strategies.md +456 -0
- package/plugins/lisa-expo/skills/reduce-complexity/references/refactoring-patterns.md +557 -0
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/src/expo/skills/reduce-complexity/SKILL.md +251 -0
- package/plugins/src/expo/skills/reduce-complexity/references/extraction-strategies.md +456 -0
- package/plugins/src/expo/skills/reduce-complexity/references/refactoring-patterns.md +557 -0
- package/tsconfig/base.json +1 -2
- package/tsconfig/expo.json +0 -5
- package/tsconfig/nestjs.json +1 -5
- package/typescript/copy-overwrite/tsconfig.json +3 -0
- package/scripts/strip-workspaces-for-pack.sh +0 -20
package/all/deletions.json
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": ["@codyswann/lisa/tsconfig/expo", "./tsconfig.local.json"],
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": "./",
|
|
5
|
+
"paths": {
|
|
6
|
+
"@/graphql/*": ["./generated/*"],
|
|
7
|
+
"@/*": ["./*"]
|
|
8
|
+
}
|
|
9
|
+
},
|
|
3
10
|
"include": ["**/*.ts", "**/*.tsx", "nativewind-env.d.ts"],
|
|
4
11
|
"exclude": ["node_modules", "dist", "web-build", "components/ui"]
|
|
5
12
|
}
|
package/expo/deletions.json
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": ["@codyswann/lisa/tsconfig/nestjs", "./tsconfig.local.json"],
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": "./",
|
|
5
|
+
"paths": {
|
|
6
|
+
"@/*": ["./src/*"]
|
|
7
|
+
}
|
|
8
|
+
},
|
|
3
9
|
"include": ["src/**/*"],
|
|
4
10
|
"exclude": ["node_modules", ".build", "dist", "**/*.test.ts", "**/*.spec.ts"]
|
|
5
11
|
}
|
package/package.json
CHANGED
|
@@ -27,8 +27,6 @@
|
|
|
27
27
|
"setup:deploy-key": "bash scripts/setup-deploy-key.sh",
|
|
28
28
|
"lisa:update:local": "bash scripts/lisa-update-local.sh",
|
|
29
29
|
"lisa:commit-and-pr:local": "bash scripts/lisa-commit-and-pr-local.sh",
|
|
30
|
-
"prepack": "bash scripts/strip-workspaces-for-pack.sh",
|
|
31
|
-
"postpack": "[ -f package.json.bak ] && mv package.json.bak package.json || true",
|
|
32
30
|
"prepublishOnly": "$npm_execpath run build",
|
|
33
31
|
"postinstall": "bash ./scripts/install-claude-plugins.sh || true; [ -d dist/configs ] || tsc || true"
|
|
34
32
|
},
|
|
@@ -39,6 +37,11 @@
|
|
|
39
37
|
"bun": "1.3.8",
|
|
40
38
|
"node": "22.21.1"
|
|
41
39
|
},
|
|
40
|
+
"workspaces": [
|
|
41
|
+
"eslint-plugin-code-organization",
|
|
42
|
+
"eslint-plugin-component-structure",
|
|
43
|
+
"eslint-plugin-ui-standards"
|
|
44
|
+
],
|
|
42
45
|
"files": [
|
|
43
46
|
"dist",
|
|
44
47
|
"all",
|
|
@@ -69,7 +72,7 @@
|
|
|
69
72
|
"axios": ">=1.13.5"
|
|
70
73
|
},
|
|
71
74
|
"name": "@codyswann/lisa",
|
|
72
|
-
"version": "1.
|
|
75
|
+
"version": "1.56.0",
|
|
73
76
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
74
77
|
"main": "dist/index.js",
|
|
75
78
|
"exports": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-cdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.56.0",
|
|
4
4
|
"description": "Claude Code governance plugin for AWS CDK projects — includes all universal skills, agents, hooks, and rules from Lisa plus TypeScript tooling",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-expo",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.56.0",
|
|
4
4
|
"description": "Claude Code governance plugin for Expo/React Native projects — includes all universal skills, agents, hooks, and rules from Lisa plus Expo-specific tooling",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reduce-complexity
|
|
3
|
+
description: This skill provides strategies and patterns for reducing cognitive complexity in React components. It should be used when ESLint reports sonarjs/cognitive-complexity violations, when refactoring complex View components, or when planning how to break down large components. The skill enforces this project's Container/View pattern requirements when extracting components.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Reduce Complexity
|
|
7
|
+
|
|
8
|
+
This skill provides systematic approaches for reducing cognitive complexity in React components while adhering to this project's Container/View pattern requirements.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
- ESLint reports `sonarjs/cognitive-complexity` violations (threshold: 28)
|
|
13
|
+
- A View component exceeds 200 lines
|
|
14
|
+
- A component has deeply nested conditionals or repeated patterns
|
|
15
|
+
- Planning refactoring of a complex component
|
|
16
|
+
- Deciding between extracting helper functions vs full components
|
|
17
|
+
|
|
18
|
+
## Complexity Sources in React Components
|
|
19
|
+
|
|
20
|
+
Cognitive complexity increases with:
|
|
21
|
+
|
|
22
|
+
| Source | Complexity Impact | Common in View Components |
|
|
23
|
+
| ---------------------- | ----------------- | ------------------------- |
|
|
24
|
+
| Nested conditionals | +1 per nesting | Yes |
|
|
25
|
+
| Ternary expressions | +1 each | Yes |
|
|
26
|
+
| Logical operators (&&) | +1 each | Yes |
|
|
27
|
+
| Loops (map, filter) | +1 each | Yes |
|
|
28
|
+
| Switch/case statements | +1 per case | Rare |
|
|
29
|
+
| Catch blocks | +1 each | No (Container only) |
|
|
30
|
+
| Nested functions | +1 per nesting | Yes |
|
|
31
|
+
|
|
32
|
+
## Decision Framework: Helper Function vs Full Component
|
|
33
|
+
|
|
34
|
+
Before extracting code, determine the appropriate strategy:
|
|
35
|
+
|
|
36
|
+
### Extract as Helper Function When:
|
|
37
|
+
|
|
38
|
+
- The JSX renders a static or simple section with no logic of its own
|
|
39
|
+
- The section does not need its own state, hooks, or callbacks
|
|
40
|
+
- The pattern appears only in this file
|
|
41
|
+
- The complexity comes from rendering, not behavior
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
// Helper function - no logic, just rendering
|
|
45
|
+
function renderSectionHeader(props: {
|
|
46
|
+
readonly title: string;
|
|
47
|
+
readonly count: number;
|
|
48
|
+
}) {
|
|
49
|
+
return (
|
|
50
|
+
<HStack className="justify-between">
|
|
51
|
+
<Text className="font-bold">{props.title}</Text>
|
|
52
|
+
<Text className="text-sm">({props.count})</Text>
|
|
53
|
+
</HStack>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Extract as Full Component (Container/View) When:
|
|
59
|
+
|
|
60
|
+
- The section has reusable logic or could be used elsewhere
|
|
61
|
+
- The section would benefit from its own state management
|
|
62
|
+
- The pattern repeats across multiple files
|
|
63
|
+
- The section has 3+ props that could be simplified with a Container
|
|
64
|
+
- Extracting would create a meaningful, named abstraction
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
FilterChipList/
|
|
68
|
+
├── FilterChipListContainer.tsx # Handles selection logic
|
|
69
|
+
├── FilterChipListView.tsx # Renders chip list
|
|
70
|
+
└── index.tsx # Exports Container
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Refactoring Process
|
|
74
|
+
|
|
75
|
+
### Step 1: Analyze Complexity Sources
|
|
76
|
+
|
|
77
|
+
Run ESLint to identify the violation:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
bun run lint 2>&1 | grep "cognitive-complexity"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
> **Note:** Replace `bun` with your project's package manager (`npm`, `yarn`, `pnpm`) as needed.
|
|
84
|
+
|
|
85
|
+
Read the file and identify:
|
|
86
|
+
|
|
87
|
+
1. Which function has the violation (line number from ESLint)
|
|
88
|
+
2. What patterns repeat (copy-pasted JSX with slight variations)
|
|
89
|
+
3. What conditionals nest deeply (ternaries inside ternaries)
|
|
90
|
+
4. What could be pre-computed in Container
|
|
91
|
+
|
|
92
|
+
### Step 2: Choose Extraction Strategy
|
|
93
|
+
|
|
94
|
+
Use the decision framework above. For View components:
|
|
95
|
+
|
|
96
|
+
| Situation | Strategy |
|
|
97
|
+
| -------------------------- | --------------------------------- |
|
|
98
|
+
| Repeated JSX, no logic | Helper function |
|
|
99
|
+
| Repeated JSX, needs props | Helper function with props object |
|
|
100
|
+
| Repeated pattern, 3+ files | Full Container/View component |
|
|
101
|
+
| Complex section, own state | Full Container/View component |
|
|
102
|
+
| Deeply nested ternaries | Pre-compute flags in Container |
|
|
103
|
+
|
|
104
|
+
### Step 3: Write Tests First (TDD)
|
|
105
|
+
|
|
106
|
+
Before refactoring, ensure test coverage exists:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Check existing coverage
|
|
110
|
+
bun run test:unit --coverage --collectCoverageFrom='<file-path>'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If no tests exist, write tests that verify current behavior before refactoring.
|
|
114
|
+
|
|
115
|
+
### Step 4: Implement Extraction
|
|
116
|
+
|
|
117
|
+
For helper functions, see `references/extraction-strategies.md`.
|
|
118
|
+
For full components, use the Container/View pattern skill.
|
|
119
|
+
|
|
120
|
+
### Step 5: Verify Complexity Resolved
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
bun run lint 2>&1 | grep "cognitive-complexity"
|
|
124
|
+
bun run test:unit
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Quick Fixes for Common Patterns
|
|
128
|
+
|
|
129
|
+
### Repeated Conditional Styling
|
|
130
|
+
|
|
131
|
+
**Before (high complexity):**
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
<Pressable
|
|
135
|
+
style={{
|
|
136
|
+
backgroundColor: selected.includes(item) ? colors.primary : colors.bg,
|
|
137
|
+
borderColor: selected.includes(item) ? colors.primary : colors.border,
|
|
138
|
+
}}
|
|
139
|
+
>
|
|
140
|
+
<Text style={{ color: selected.includes(item) ? "#FFF" : colors.text }}>
|
|
141
|
+
{item}
|
|
142
|
+
</Text>
|
|
143
|
+
</Pressable>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**After (reduced complexity):**
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
// In Container - pre-compute selection state
|
|
150
|
+
const itemStates = useMemo(
|
|
151
|
+
() =>
|
|
152
|
+
items.map(item => ({
|
|
153
|
+
item,
|
|
154
|
+
isSelected: selected.includes(item),
|
|
155
|
+
})),
|
|
156
|
+
[items, selected]
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// In View - simple conditional
|
|
160
|
+
<Pressable style={isSelected ? styles.selected : styles.default}>
|
|
161
|
+
<Text style={isSelected ? styles.selectedText : styles.defaultText}>
|
|
162
|
+
{item}
|
|
163
|
+
</Text>
|
|
164
|
+
</Pressable>;
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Repeated Section Patterns
|
|
168
|
+
|
|
169
|
+
**Before (4x repeated pattern = high complexity):**
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
{positions.length > 0 && (
|
|
173
|
+
<VStack>
|
|
174
|
+
<Text>Positions</Text>
|
|
175
|
+
<HStack>{positions.map(p => <Chip key={p} ... />)}</HStack>
|
|
176
|
+
</VStack>
|
|
177
|
+
)}
|
|
178
|
+
{tags.length > 0 && (
|
|
179
|
+
<VStack>
|
|
180
|
+
<Text>Tags</Text>
|
|
181
|
+
<HStack>{tags.map(t => <Chip key={t.id} ... />)}</HStack>
|
|
182
|
+
</VStack>
|
|
183
|
+
)}
|
|
184
|
+
// ... repeated 2 more times
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**After (extract FilterChipList component):**
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
<FilterChipList
|
|
191
|
+
title="Positions"
|
|
192
|
+
items={positions}
|
|
193
|
+
selectedItems={filters.positions}
|
|
194
|
+
onToggle={onPositionToggle}
|
|
195
|
+
/>
|
|
196
|
+
<FilterChipList
|
|
197
|
+
title="Tags"
|
|
198
|
+
items={tags}
|
|
199
|
+
selectedItems={filters.tags}
|
|
200
|
+
onToggle={onTagToggle}
|
|
201
|
+
/>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Nested Ternaries
|
|
205
|
+
|
|
206
|
+
**Before:**
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
{
|
|
210
|
+
isLoading ? (
|
|
211
|
+
<Spinner />
|
|
212
|
+
) : hasError ? (
|
|
213
|
+
<Error />
|
|
214
|
+
) : isEmpty ? (
|
|
215
|
+
<Empty />
|
|
216
|
+
) : (
|
|
217
|
+
<Content />
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**After (pre-compute state in Container):**
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
// Container
|
|
226
|
+
const viewState = useMemo(() => {
|
|
227
|
+
if (isLoading) return "loading";
|
|
228
|
+
if (hasError) return "error";
|
|
229
|
+
if (isEmpty) return "empty";
|
|
230
|
+
return "content";
|
|
231
|
+
}, [isLoading, hasError, isEmpty]);
|
|
232
|
+
|
|
233
|
+
// View - map directly
|
|
234
|
+
const VIEW_STATES = {
|
|
235
|
+
loading: <Spinner />,
|
|
236
|
+
error: <Error />,
|
|
237
|
+
empty: <Empty />,
|
|
238
|
+
content: <Content />,
|
|
239
|
+
} as const;
|
|
240
|
+
|
|
241
|
+
{
|
|
242
|
+
VIEW_STATES[viewState];
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Reference Documentation
|
|
247
|
+
|
|
248
|
+
For detailed patterns and complete examples:
|
|
249
|
+
|
|
250
|
+
- `references/extraction-strategies.md` - Helper function patterns and when to use each
|
|
251
|
+
- `references/refactoring-patterns.md` - Step-by-step refactoring examples with before/after code
|