@su-record/vibe 2.4.56 โ 2.4.57
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/CLAUDE.md +7 -18
- package/agents/compounder.md +1 -1
- package/agents/implementer.md +2 -1
- package/agents/simplifier.md +2 -1
- package/commands/vibe.run.md +4 -1
- package/commands/vibe.spec.md +56 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +0 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/postinstall.js +32 -1
- package/dist/cli/postinstall.js.map +1 -1
- package/dist/cli/setup.d.ts +18 -4
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +87 -27
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/types.d.ts +6 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/languages/csharp-unity.md +516 -0
- package/languages/gdscript-godot.md +470 -0
- package/languages/ruby-rails.md +489 -0
- package/languages/typescript-angular.md +433 -0
- package/languages/typescript-astro.md +416 -0
- package/languages/typescript-electron.md +407 -0
- package/languages/typescript-nestjs.md +524 -0
- package/languages/typescript-svelte.md +407 -0
- package/languages/typescript-tauri.md +366 -0
- package/package.json +1 -1
- package/skills/vibe-capabilities.md +1 -1
- package/vibe/constitution.md +130 -97
- package/vibe/rules/core/communication-guide.md +50 -56
- package/vibe/rules/core/development-philosophy.md +35 -36
- package/vibe/rules/core/quick-start.md +66 -85
- package/vibe/rules/quality/bdd-contract-testing.md +94 -89
- package/vibe/rules/quality/checklist.md +132 -132
- package/vibe/rules/quality/testing-strategy.md +132 -129
- package/vibe/rules/standards/anti-patterns.md +74 -74
- package/vibe/rules/standards/code-structure.md +44 -44
- package/vibe/rules/standards/complexity-metrics.md +63 -62
- package/vibe/rules/standards/naming-conventions.md +72 -72
- package/vibe/templates/constitution-template.md +153 -95
- package/vibe/templates/contract-backend-template.md +41 -32
- package/vibe/templates/contract-frontend-template.md +35 -30
- package/vibe/templates/feature-template.md +33 -33
- package/vibe/templates/spec-template.md +118 -96
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Automatic Anti-Pattern Avoidance
|
|
2
2
|
|
|
3
|
-
## TypeScript
|
|
3
|
+
## TypeScript Anti-Patterns
|
|
4
4
|
|
|
5
|
-
### 1. any
|
|
5
|
+
### 1. Using any Type
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
|
-
// โ any
|
|
8
|
+
// โ Using any
|
|
9
9
|
function processData(data: any) {
|
|
10
|
-
return data.value; //
|
|
10
|
+
return data.value; // Loss of type safety
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// โ
unknown + type guard
|
|
14
14
|
function processData(data: unknown) {
|
|
15
15
|
if (isValidData(data)) {
|
|
16
|
-
return data.value; //
|
|
16
|
+
return data.value; // Type safe
|
|
17
17
|
}
|
|
18
18
|
throw new Error('Invalid data');
|
|
19
19
|
}
|
|
@@ -23,31 +23,31 @@ function isValidData(data: unknown): data is { value: string } {
|
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
### 2.
|
|
26
|
+
### 2. Forced Type Casting with as any
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
|
-
// โ as any
|
|
29
|
+
// โ Bypassing types with as any
|
|
30
30
|
const user = response as any;
|
|
31
|
-
user.name; //
|
|
31
|
+
user.name; // Runtime error risk
|
|
32
32
|
|
|
33
|
-
// โ
|
|
33
|
+
// โ
Proper type definition
|
|
34
34
|
interface User {
|
|
35
35
|
name: string;
|
|
36
36
|
email: string;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
const user = response as User;
|
|
40
|
-
user.name; //
|
|
40
|
+
user.name; // Type safe
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
### 3. @ts-ignore
|
|
43
|
+
### 3. Overusing @ts-ignore
|
|
44
44
|
|
|
45
45
|
```typescript
|
|
46
|
-
// โ @ts-ignore
|
|
46
|
+
// โ Ignoring errors with @ts-ignore
|
|
47
47
|
// @ts-ignore
|
|
48
48
|
const result = problematicCode();
|
|
49
49
|
|
|
50
|
-
// โ
|
|
50
|
+
// โ
Fix the type issue at its root
|
|
51
51
|
interface Expected {
|
|
52
52
|
id: string;
|
|
53
53
|
}
|
|
@@ -57,17 +57,17 @@ const result: Expected = {
|
|
|
57
57
|
};
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
## React
|
|
60
|
+
## React Anti-Patterns
|
|
61
61
|
|
|
62
|
-
### 1. dangerouslySetInnerHTML
|
|
62
|
+
### 1. Using dangerouslySetInnerHTML
|
|
63
63
|
|
|
64
64
|
```typescript
|
|
65
|
-
// โ XSS
|
|
65
|
+
// โ XSS vulnerability
|
|
66
66
|
function Component({ html }: { html: string }) {
|
|
67
67
|
return <div dangerouslySetInnerHTML={{ __html: html }} />;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
// โ
|
|
70
|
+
// โ
Safe rendering
|
|
71
71
|
import DOMPurify from 'dompurify';
|
|
72
72
|
|
|
73
73
|
function Component({ html }: { html: string }) {
|
|
@@ -75,7 +75,7 @@ function Component({ html }: { html: string }) {
|
|
|
75
75
|
return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
// โ
|
|
78
|
+
// โ
Better approach: Use markdown library
|
|
79
79
|
import ReactMarkdown from 'react-markdown';
|
|
80
80
|
|
|
81
81
|
function Component({ markdown }: { markdown: string }) {
|
|
@@ -83,7 +83,7 @@ function Component({ markdown }: { markdown: string }) {
|
|
|
83
83
|
}
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
### 2. Props Drilling (3
|
|
86
|
+
### 2. Props Drilling (More than 3 levels)
|
|
87
87
|
|
|
88
88
|
```typescript
|
|
89
89
|
// โ Props drilling
|
|
@@ -104,7 +104,7 @@ function GrandChild({ user }: { user: User }) {
|
|
|
104
104
|
return <div>{user.name}</div>;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
// โ
Context API
|
|
107
|
+
// โ
Use Context API
|
|
108
108
|
const UserContext = createContext<User | undefined>(undefined);
|
|
109
109
|
|
|
110
110
|
function App() {
|
|
@@ -122,73 +122,73 @@ function GrandChild() {
|
|
|
122
122
|
}
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
### 3. useEffect
|
|
125
|
+
### 3. Missing useEffect Dependency Array
|
|
126
126
|
|
|
127
127
|
```typescript
|
|
128
|
-
// โ
|
|
128
|
+
// โ Missing dependency
|
|
129
129
|
function Component({ userId }: { userId: string }) {
|
|
130
130
|
const [user, setUser] = useState<User>();
|
|
131
131
|
|
|
132
132
|
useEffect(() => {
|
|
133
133
|
fetchUser(userId).then(setUser);
|
|
134
|
-
}, []); // userId
|
|
134
|
+
}, []); // Missing userId dependency!
|
|
135
135
|
|
|
136
136
|
return <div>{user?.name}</div>;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
// โ
|
|
139
|
+
// โ
Specify all dependencies
|
|
140
140
|
function Component({ userId }: { userId: string }) {
|
|
141
141
|
const [user, setUser] = useState<User>();
|
|
142
142
|
|
|
143
143
|
useEffect(() => {
|
|
144
144
|
fetchUser(userId).then(setUser);
|
|
145
|
-
}, [userId]); //
|
|
145
|
+
}, [userId]); // Dependency specified
|
|
146
146
|
|
|
147
147
|
return <div>{user?.name}</div>;
|
|
148
148
|
}
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
-
## JavaScript
|
|
151
|
+
## JavaScript Anti-Patterns
|
|
152
152
|
|
|
153
|
-
### 1. var
|
|
153
|
+
### 1. Using var
|
|
154
154
|
|
|
155
155
|
```typescript
|
|
156
|
-
// โ var
|
|
156
|
+
// โ Using var
|
|
157
157
|
var count = 0;
|
|
158
158
|
if (true) {
|
|
159
|
-
var count = 1; //
|
|
159
|
+
var count = 1; // Same variable!
|
|
160
160
|
}
|
|
161
161
|
console.log(count); // 1
|
|
162
162
|
|
|
163
|
-
// โ
const/let
|
|
163
|
+
// โ
Use const/let
|
|
164
164
|
let count = 0;
|
|
165
165
|
if (true) {
|
|
166
|
-
let count = 1; //
|
|
166
|
+
let count = 1; // Block scope
|
|
167
167
|
}
|
|
168
168
|
console.log(count); // 0
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
### 2. ==
|
|
171
|
+
### 2. Using == (Loose Comparison)
|
|
172
172
|
|
|
173
173
|
```typescript
|
|
174
|
-
// โ ==
|
|
175
|
-
if (value == null) { } // undefined
|
|
176
|
-
if ('5' == 5) { } // true (
|
|
174
|
+
// โ Using ==
|
|
175
|
+
if (value == null) { } // Also matches undefined
|
|
176
|
+
if ('5' == 5) { } // true (type coercion)
|
|
177
177
|
|
|
178
|
-
// โ
===
|
|
178
|
+
// โ
Use ===
|
|
179
179
|
if (value === null) { }
|
|
180
180
|
if (value === undefined) { }
|
|
181
181
|
if ('5' === 5) { } // false
|
|
182
182
|
```
|
|
183
183
|
|
|
184
|
-
### 3. eval()
|
|
184
|
+
### 3. Using eval()
|
|
185
185
|
|
|
186
186
|
```typescript
|
|
187
|
-
// โ eval()
|
|
187
|
+
// โ Using eval() (security risk)
|
|
188
188
|
const code = userInput;
|
|
189
|
-
eval(code); //
|
|
189
|
+
eval(code); // Can execute arbitrary code
|
|
190
190
|
|
|
191
|
-
// โ
|
|
191
|
+
// โ
Alternative implementation
|
|
192
192
|
const allowedOperations = {
|
|
193
193
|
add: (a: number, b: number) => a + b,
|
|
194
194
|
subtract: (a: number, b: number) => a - b,
|
|
@@ -200,28 +200,28 @@ if (operation) {
|
|
|
200
200
|
}
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
-
## CSS
|
|
203
|
+
## CSS Anti-Patterns
|
|
204
204
|
|
|
205
|
-
### 1. !important
|
|
205
|
+
### 1. Overusing !important
|
|
206
206
|
|
|
207
207
|
```css
|
|
208
|
-
/* โ !important
|
|
208
|
+
/* โ Overusing !important */
|
|
209
209
|
.button {
|
|
210
210
|
color: blue !important;
|
|
211
211
|
background: red !important;
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
/* โ
|
|
214
|
+
/* โ
Use specific selectors */
|
|
215
215
|
.navigation .button.primary {
|
|
216
216
|
color: blue;
|
|
217
217
|
background: red;
|
|
218
218
|
}
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
-
### 2.
|
|
221
|
+
### 2. Overusing Inline Styles
|
|
222
222
|
|
|
223
223
|
```typescript
|
|
224
|
-
// โ
|
|
224
|
+
// โ Inline styles
|
|
225
225
|
function Button() {
|
|
226
226
|
return (
|
|
227
227
|
<button
|
|
@@ -237,7 +237,7 @@ function Button() {
|
|
|
237
237
|
);
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
// โ
CSS
|
|
240
|
+
// โ
Use CSS classes
|
|
241
241
|
function Button() {
|
|
242
242
|
return <button className="btn-primary">Click me</button>;
|
|
243
243
|
}
|
|
@@ -251,18 +251,18 @@ function Button() {
|
|
|
251
251
|
}
|
|
252
252
|
```
|
|
253
253
|
|
|
254
|
-
##
|
|
254
|
+
## Performance Anti-Patterns
|
|
255
255
|
|
|
256
|
-
### 1.
|
|
256
|
+
### 1. Unnecessary Re-renders
|
|
257
257
|
|
|
258
258
|
```typescript
|
|
259
|
-
// โ
|
|
259
|
+
// โ Creating new objects/functions every render
|
|
260
260
|
function Parent() {
|
|
261
261
|
return <Child config={{ theme: 'dark' }} onClick={() => {}} />;
|
|
262
|
-
//
|
|
262
|
+
// New object/function created every render โ Child re-renders
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
-
// โ
useMemo/useCallback
|
|
265
|
+
// โ
Use useMemo/useCallback
|
|
266
266
|
function Parent() {
|
|
267
267
|
const config = useMemo(() => ({ theme: 'dark' }), []);
|
|
268
268
|
const handleClick = useCallback(() => {}, []);
|
|
@@ -271,10 +271,10 @@ function Parent() {
|
|
|
271
271
|
}
|
|
272
272
|
```
|
|
273
273
|
|
|
274
|
-
### 2.
|
|
274
|
+
### 2. Synchronous Heavy Computations
|
|
275
275
|
|
|
276
276
|
```typescript
|
|
277
|
-
// โ
|
|
277
|
+
// โ Blocking main thread
|
|
278
278
|
function Component({ data }: { data: number[] }) {
|
|
279
279
|
const result = data
|
|
280
280
|
.map(heavyComputation)
|
|
@@ -284,7 +284,7 @@ function Component({ data }: { data: number[] }) {
|
|
|
284
284
|
return <div>{result}</div>;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
-
// โ
useMemo
|
|
287
|
+
// โ
Memoization with useMemo
|
|
288
288
|
function Component({ data }: { data: number[] }) {
|
|
289
289
|
const result = useMemo(
|
|
290
290
|
() =>
|
|
@@ -299,42 +299,42 @@ function Component({ data }: { data: number[] }) {
|
|
|
299
299
|
}
|
|
300
300
|
```
|
|
301
301
|
|
|
302
|
-
##
|
|
302
|
+
## Security Anti-Patterns
|
|
303
303
|
|
|
304
|
-
### 1.
|
|
304
|
+
### 1. Hardcoding Sensitive Information
|
|
305
305
|
|
|
306
306
|
```typescript
|
|
307
|
-
// โ API
|
|
307
|
+
// โ Hardcoded API key
|
|
308
308
|
const API_KEY = 'sk-1234567890abcdef';
|
|
309
309
|
|
|
310
|
-
// โ
|
|
310
|
+
// โ
Use environment variables
|
|
311
311
|
const API_KEY = process.env.NEXT_PUBLIC_API_KEY;
|
|
312
312
|
```
|
|
313
313
|
|
|
314
|
-
### 2. SQL Injection
|
|
314
|
+
### 2. SQL Injection Vulnerability
|
|
315
315
|
|
|
316
316
|
```typescript
|
|
317
|
-
// โ
|
|
317
|
+
// โ Direct string concatenation
|
|
318
318
|
const query = `SELECT * FROM users WHERE id = ${userId}`;
|
|
319
319
|
|
|
320
|
-
// โ
|
|
320
|
+
// โ
Parameterized query
|
|
321
321
|
const query = 'SELECT * FROM users WHERE id = ?';
|
|
322
322
|
db.execute(query, [userId]);
|
|
323
323
|
```
|
|
324
324
|
|
|
325
|
-
##
|
|
325
|
+
## Error Handling Anti-Patterns
|
|
326
326
|
|
|
327
|
-
### 1.
|
|
327
|
+
### 1. Empty catch Block
|
|
328
328
|
|
|
329
329
|
```typescript
|
|
330
|
-
// โ
|
|
330
|
+
// โ Ignoring errors
|
|
331
331
|
try {
|
|
332
332
|
riskyOperation();
|
|
333
333
|
} catch (e) {
|
|
334
|
-
//
|
|
334
|
+
// Does nothing
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
-
// โ
|
|
337
|
+
// โ
Proper error handling
|
|
338
338
|
try {
|
|
339
339
|
riskyOperation();
|
|
340
340
|
} catch (error) {
|
|
@@ -344,26 +344,26 @@ try {
|
|
|
344
344
|
}
|
|
345
345
|
```
|
|
346
346
|
|
|
347
|
-
### 2.
|
|
347
|
+
### 2. Handling Without Error Type Check
|
|
348
348
|
|
|
349
349
|
```typescript
|
|
350
|
-
// โ
|
|
350
|
+
// โ Treating all errors the same
|
|
351
351
|
try {
|
|
352
352
|
await fetchData();
|
|
353
353
|
} catch (error) {
|
|
354
|
-
showError('Failed'); //
|
|
354
|
+
showError('Failed'); // Not specific
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
-
// โ
|
|
357
|
+
// โ
Handle by error type
|
|
358
358
|
try {
|
|
359
359
|
await fetchData();
|
|
360
360
|
} catch (error) {
|
|
361
361
|
if (error instanceof NetworkError) {
|
|
362
|
-
showError('
|
|
362
|
+
showError('Please check your network connection');
|
|
363
363
|
} else if (error instanceof AuthError) {
|
|
364
364
|
redirectToLogin();
|
|
365
365
|
} else {
|
|
366
|
-
showError('
|
|
366
|
+
showError('An unknown error occurred');
|
|
367
367
|
}
|
|
368
368
|
}
|
|
369
369
|
```
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Code Structure Automation Rules
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Component Structure (Strict Order)
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
|
-
// 1. Import
|
|
6
|
+
// 1. Import statements
|
|
7
7
|
import React, { useState, useEffect } from 'react';
|
|
8
8
|
|
|
9
|
-
// 2.
|
|
9
|
+
// 2. Type/Interface definitions
|
|
10
10
|
interface Props {
|
|
11
11
|
userId: string;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
// 3.
|
|
14
|
+
// 3. Component definition
|
|
15
15
|
function UserProfile({ userId }: Props) {
|
|
16
16
|
// 4. State & Refs
|
|
17
17
|
const [user, setUser] = useState<User | null>(null);
|
|
@@ -45,17 +45,17 @@ function UserProfile({ userId }: Props) {
|
|
|
45
45
|
}
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
##
|
|
48
|
+
## Function Separation Criteria
|
|
49
49
|
|
|
50
|
-
### 1.
|
|
50
|
+
### 1. Function Length Criteria
|
|
51
51
|
|
|
52
52
|
```typescript
|
|
53
|
-
// โ 20
|
|
53
|
+
// โ Over 20 lines - needs separation
|
|
54
54
|
function processUserData(user: User) {
|
|
55
|
-
// 30
|
|
55
|
+
// 30 lines of complex logic
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
// โ
|
|
58
|
+
// โ
Separate by single responsibility
|
|
59
59
|
function processUserData(user: User) {
|
|
60
60
|
const validated = validateUser(user);
|
|
61
61
|
const transformed = transformUserData(validated);
|
|
@@ -67,19 +67,19 @@ function transformUserData(user: User) { /* ... */ }
|
|
|
67
67
|
function saveUserData(user: User) { /* ... */ }
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
### 2.
|
|
70
|
+
### 2. Component JSX Length Criteria
|
|
71
71
|
|
|
72
72
|
```typescript
|
|
73
|
-
// โ JSX 50
|
|
73
|
+
// โ JSX over 50 lines - needs separation
|
|
74
74
|
function Dashboard() {
|
|
75
75
|
return (
|
|
76
76
|
<div>
|
|
77
|
-
{/* 60
|
|
77
|
+
{/* 60 lines of complex JSX */}
|
|
78
78
|
</div>
|
|
79
79
|
);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
// โ
|
|
82
|
+
// โ
Extract sub-components
|
|
83
83
|
function Dashboard() {
|
|
84
84
|
return (
|
|
85
85
|
<div>
|
|
@@ -95,37 +95,37 @@ function DashboardContent() { /* ... */ }
|
|
|
95
95
|
function DashboardFooter() { /* ... */ }
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
### 3.
|
|
98
|
+
### 3. Nesting Depth Criteria
|
|
99
99
|
|
|
100
100
|
```typescript
|
|
101
|
-
// โ
|
|
101
|
+
// โ Nesting over 3 levels
|
|
102
102
|
function processData(data: Data) {
|
|
103
103
|
if (data) {
|
|
104
104
|
if (data.isValid) {
|
|
105
105
|
if (data.user) {
|
|
106
106
|
if (data.user.isActive) {
|
|
107
|
-
//
|
|
107
|
+
// Too deep nesting
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
// โ
|
|
114
|
+
// โ
Flatten with early returns
|
|
115
115
|
function processData(data: Data) {
|
|
116
116
|
if (!data) return null;
|
|
117
117
|
if (!data.isValid) return null;
|
|
118
118
|
if (!data.user) return null;
|
|
119
119
|
if (!data.user.isActive) return null;
|
|
120
120
|
|
|
121
|
-
//
|
|
121
|
+
// Execute logic
|
|
122
122
|
}
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
### 4. Cyclomatic Complexity > 10
|
|
126
126
|
|
|
127
127
|
```typescript
|
|
128
|
-
// โ
|
|
128
|
+
// โ High complexity (15)
|
|
129
129
|
function calculatePrice(item: Item) {
|
|
130
130
|
let price = item.basePrice;
|
|
131
131
|
if (item.discount) price *= 0.9;
|
|
@@ -133,11 +133,11 @@ function calculatePrice(item: Item) {
|
|
|
133
133
|
if (item.seasonal) price *= 0.95;
|
|
134
134
|
if (item.member) price *= 0.85;
|
|
135
135
|
if (item.firstTime) price *= 0.9;
|
|
136
|
-
// ...
|
|
136
|
+
// ... more conditions
|
|
137
137
|
return price;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
// โ
|
|
140
|
+
// โ
Reduced complexity (3)
|
|
141
141
|
function calculatePrice(item: Item) {
|
|
142
142
|
const basePrice = item.basePrice;
|
|
143
143
|
const discounts = getApplicableDiscounts(item);
|
|
@@ -148,20 +148,20 @@ function calculatePrice(item: Item) {
|
|
|
148
148
|
### 5. Cognitive Complexity > 15
|
|
149
149
|
|
|
150
150
|
```typescript
|
|
151
|
-
// โ
|
|
151
|
+
// โ High cognitive complexity
|
|
152
152
|
function processOrder(order: Order) {
|
|
153
153
|
if (order.isPremium) {
|
|
154
154
|
for (let item of order.items) {
|
|
155
155
|
if (item.category === 'electronics') {
|
|
156
156
|
if (item.price > 1000) {
|
|
157
|
-
//
|
|
157
|
+
// Nested complex logic
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
// โ
|
|
164
|
+
// โ
Reduced cognitive complexity
|
|
165
165
|
function processOrder(order: Order) {
|
|
166
166
|
if (!order.isPremium) return;
|
|
167
167
|
|
|
@@ -172,7 +172,7 @@ function processOrder(order: Order) {
|
|
|
172
172
|
}
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
-
##
|
|
175
|
+
## File Structure Standard
|
|
176
176
|
|
|
177
177
|
```typescript
|
|
178
178
|
// ๐ user-profile.component.tsx
|
|
@@ -189,23 +189,23 @@ type UserRole = 'admin' | 'user';
|
|
|
189
189
|
const MAX_BIO_LENGTH = 500;
|
|
190
190
|
const DEFAULT_AVATAR = '/avatar.png';
|
|
191
191
|
|
|
192
|
-
// 4. Helper Functions (
|
|
192
|
+
// 4. Helper Functions (internal only)
|
|
193
193
|
function formatUserName(name: string) { }
|
|
194
194
|
|
|
195
195
|
// 5. Main Component
|
|
196
196
|
export function UserProfile() { }
|
|
197
197
|
|
|
198
|
-
// 6. Sub Components (
|
|
198
|
+
// 6. Sub Components (not exported)
|
|
199
199
|
function ProfileHeader() { }
|
|
200
200
|
function ProfileContent() { }
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
-
##
|
|
203
|
+
## Module Organization Principles
|
|
204
204
|
|
|
205
|
-
### 1.
|
|
205
|
+
### 1. Cohesion
|
|
206
206
|
|
|
207
207
|
```typescript
|
|
208
|
-
// โ
|
|
208
|
+
// โ
High cohesion - only related functions
|
|
209
209
|
// ๐ user.service.ts
|
|
210
210
|
export class UserService {
|
|
211
211
|
getUser(id: string) { }
|
|
@@ -213,8 +213,8 @@ export class UserService {
|
|
|
213
213
|
deleteUser(id: string) { }
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
// โ
|
|
217
|
-
// ๐ utils.ts (
|
|
216
|
+
// โ Low cohesion - unrelated functions mixed
|
|
217
|
+
// ๐ utils.ts (anti-pattern)
|
|
218
218
|
export class Utils {
|
|
219
219
|
validateEmail(email: string) { }
|
|
220
220
|
formatCurrency(amount: number) { }
|
|
@@ -222,10 +222,10 @@ export class Utils {
|
|
|
222
222
|
}
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
### 2.
|
|
225
|
+
### 2. Coupling
|
|
226
226
|
|
|
227
227
|
```typescript
|
|
228
|
-
// โ
|
|
228
|
+
// โ
Loose coupling - depends on interface
|
|
229
229
|
interface Storage {
|
|
230
230
|
save(key: string, value: unknown): void;
|
|
231
231
|
load(key: string): unknown;
|
|
@@ -235,16 +235,16 @@ class UserService {
|
|
|
235
235
|
constructor(private storage: Storage) { }
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
// โ
|
|
238
|
+
// โ Tight coupling - depends on implementation directly
|
|
239
239
|
class UserService {
|
|
240
|
-
private storage = new LocalStorage(); //
|
|
240
|
+
private storage = new LocalStorage(); // Direct dependency
|
|
241
241
|
}
|
|
242
242
|
```
|
|
243
243
|
|
|
244
|
-
##
|
|
244
|
+
## Function Parameter Limit
|
|
245
245
|
|
|
246
246
|
```typescript
|
|
247
|
-
// โ
|
|
247
|
+
// โ Over 5 parameters
|
|
248
248
|
function createUser(
|
|
249
249
|
name: string,
|
|
250
250
|
email: string,
|
|
@@ -254,7 +254,7 @@ function createUser(
|
|
|
254
254
|
role: string
|
|
255
255
|
) { }
|
|
256
256
|
|
|
257
|
-
// โ
|
|
257
|
+
// โ
Group into object
|
|
258
258
|
interface CreateUserParams {
|
|
259
259
|
name: string;
|
|
260
260
|
email: string;
|
|
@@ -267,19 +267,19 @@ interface CreateUserParams {
|
|
|
267
267
|
function createUser(params: CreateUserParams) { }
|
|
268
268
|
```
|
|
269
269
|
|
|
270
|
-
##
|
|
270
|
+
## Preventing Circular Dependencies
|
|
271
271
|
|
|
272
272
|
```typescript
|
|
273
|
-
// โ
|
|
273
|
+
// โ Circular dependency
|
|
274
274
|
// fileA.ts
|
|
275
275
|
import { funcB } from './fileB';
|
|
276
276
|
export function funcA() { funcB(); }
|
|
277
277
|
|
|
278
278
|
// fileB.ts
|
|
279
|
-
import { funcA } from './fileA'; //
|
|
279
|
+
import { funcA } from './fileA'; // Circular!
|
|
280
280
|
export function funcB() { funcA(); }
|
|
281
281
|
|
|
282
|
-
// โ
|
|
282
|
+
// โ
Separate common module
|
|
283
283
|
// shared.ts
|
|
284
284
|
export function sharedFunc() { }
|
|
285
285
|
|