anchi-kit 1.2.0 → 1.2.1
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/.antigravity/skills/article-extractor/SKILL.md +52 -0
- package/.antigravity/skills/artifacts-builder/SKILL.md +63 -0
- package/.antigravity/skills/aws-deployment/SKILL.md +85 -0
- package/.antigravity/skills/brainstorming/SKILL.md +73 -0
- package/.antigravity/skills/canvas-design/SKILL.md +62 -0
- package/.antigravity/skills/changelog-generator/SKILL.md +149 -0
- package/.antigravity/skills/changelog-generator/assets/changelog-template.md +60 -0
- package/.antigravity/skills/changelog-generator/scripts/generate-changelog.js +181 -0
- package/.antigravity/skills/claude-code/references/advanced-features.md +399 -0
- package/.antigravity/skills/claude-code/references/agent-skills.md +399 -0
- package/.antigravity/skills/claude-code/references/api-reference.md +498 -0
- package/.antigravity/skills/claude-code/references/best-practices.md +447 -0
- package/.antigravity/skills/claude-code/references/cicd-integration.md +428 -0
- package/.antigravity/skills/claude-code/references/common-workflows.md +119 -0
- package/.antigravity/skills/claude-code/references/configuration.md +480 -0
- package/.antigravity/skills/claude-code/references/enterprise-features.md +472 -0
- package/.antigravity/skills/claude-code/references/getting-started.md +252 -0
- package/.antigravity/skills/claude-code/references/hooks-and-plugins.md +444 -0
- package/.antigravity/skills/claude-code/references/hooks-comprehensive.md +622 -0
- package/.antigravity/skills/claude-code/references/ide-integration.md +316 -0
- package/.antigravity/skills/claude-code/references/mcp-integration.md +386 -0
- package/.antigravity/skills/claude-code/references/slash-commands.md +489 -0
- package/.antigravity/skills/claude-code/references/troubleshooting.md +456 -0
- package/.antigravity/skills/claude-code/skill.md +60 -0
- package/.antigravity/skills/code-quality/SKILL.md +273 -0
- package/.antigravity/skills/comprehensive-review/complexity.md +11 -0
- package/.antigravity/skills/comprehensive-review/index.yaml +19 -0
- package/.antigravity/skills/comprehensive-review/maintainability.md +12 -0
- package/.antigravity/skills/comprehensive-review/readability.md +12 -0
- package/.antigravity/skills/content-research-writer/SKILL.md +65 -0
- package/.antigravity/skills/csv-data-analyzer/SKILL.md +91 -0
- package/.antigravity/skills/d3-visualization/SKILL.md +65 -0
- package/.antigravity/skills/debugging/references/root-cause-analysis-methods.md +140 -0
- package/.antigravity/skills/engineering-discipline/incremental-change.md +15 -0
- package/.antigravity/skills/engineering-discipline/index.yaml +30 -0
- package/.antigravity/skills/engineering-discipline/planning-first.md +18 -0
- package/.antigravity/skills/engineering-discipline/reasoning-clarity.md +19 -0
- package/.antigravity/skills/engineering-discipline/verify-before-commit.md +17 -0
- package/.antigravity/skills/file-organizer/SKILL.md +64 -0
- package/.antigravity/skills/git-automation/SKILL.md +68 -0
- package/.antigravity/skills/git-automation/references/branch-finishing.md +64 -0
- package/.antigravity/skills/impact-scoring/SKILL.md +219 -0
- package/.antigravity/skills/kaizen/SKILL.md +94 -0
- package/.antigravity/skills/performance-patterns/SKILL.md +209 -0
- package/.antigravity/skills/playwright-testing/SKILL.md +115 -0
- package/.antigravity/skills/playwright-testing/references/playwright-patterns.md +122 -0
- package/.antigravity/skills/prompt-engineering/SKILL.md +126 -0
- package/.antigravity/skills/prompt-engineering/references/anthropic-best-practices.md +160 -0
- package/.antigravity/skills/pypict-testing/SKILL.md +79 -0
- package/.antigravity/skills/review-implementing/SKILL.md +287 -0
- package/.antigravity/skills/security-audit/SKILL.md +263 -0
- package/.antigravity/skills/software-architecture/SKILL.md +91 -0
- package/.antigravity/skills/software-architecture/references/solid-principles.md +293 -0
- package/.antigravity/skills/subagent-driven-development/SKILL.md +237 -0
- package/.antigravity/skills/test-driven-development/SKILL.md +130 -0
- package/.antigravity/skills/test-driven-development/references/tdd-patterns.md +124 -0
- package/.antigravity/skills/test-driven-development/references/testing-strategies.md +131 -0
- package/.antigravity/skills/test-fixing/SKILL.md +256 -0
- package/.antigravity/skills/theme-factory/SKILL.md +63 -0
- package/.antigravity/workflows/clean.md +333 -0
- package/.antigravity/workflows/health.md +228 -0
- package/.cursor/skills/_packs/common/pack-architecture.md +40 -0
- package/.cursor/skills/_packs/common/pack-devops.md +43 -0
- package/.cursor/skills/_packs/common/pack-productivity.md +37 -0
- package/.cursor/skills/_packs/common/pack-quality.md +41 -0
- package/.cursor/skills/_packs/data/pack-ai.md +41 -0
- package/.cursor/skills/_packs/data/pack-data-science.md +36 -0
- package/.cursor/skills/_packs/mobile/pack-mobile.md +40 -0
- package/.cursor/skills/_packs/web/pack-backend.md +61 -0
- package/.cursor/skills/_packs/web/pack-frontend.md +66 -0
- package/.cursor/skills/_packs/web3/pack-blockchain.md +37 -0
- package/.cursor/skills/advanced-coding/references/getting-started.md +93 -0
- package/.cursor/skills/advanced-coding/skill.md +34 -0
- package/.cursor/skills/template-skill/SKILL.md +6 -0
- package/README.md +1 -1
- package/docs/reference/SECURITY.md +1 -1
- package/package.json +2 -2
- package/src/cli.js +5 -5
- package/src/commands/dashboard.js +3 -3
- package/src/commands/init.js +15 -3
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# Security Audit Skill
|
|
2
|
+
|
|
3
|
+
> Domain knowledge for writing secure code and preventing vulnerabilities.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🔐 OWASP Top 10 Prevention
|
|
8
|
+
|
|
9
|
+
### 1. Injection (SQL, NoSQL, Command)
|
|
10
|
+
|
|
11
|
+
**❌ Vulnerable:**
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// SQL Injection
|
|
15
|
+
const user = await db.query(`SELECT * FROM users WHERE id = ${id}`);
|
|
16
|
+
|
|
17
|
+
// Command Injection
|
|
18
|
+
exec(`ls ${userInput}`);
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**✅ Secure:**
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// Parameterized queries
|
|
25
|
+
const user = await prisma.user.findUnique({ where: { id } });
|
|
26
|
+
|
|
27
|
+
// Avoid shell commands, use libraries
|
|
28
|
+
import { readdir } from "fs/promises";
|
|
29
|
+
const files = await readdir(safeDirectory);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
### 2. Broken Authentication
|
|
35
|
+
|
|
36
|
+
**Checklist:**
|
|
37
|
+
|
|
38
|
+
- [ ] Passwords hashed with bcrypt/argon2 (cost ≥ 10)
|
|
39
|
+
- [ ] Session tokens are random and long (≥ 32 bytes)
|
|
40
|
+
- [ ] Sessions expire (max 24h for sensitive, 30d for remember-me)
|
|
41
|
+
- [ ] Rate limiting on login (5 attempts/minute)
|
|
42
|
+
- [ ] Account lockout after repeated failures
|
|
43
|
+
- [ ] MFA available for sensitive accounts
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// Password hashing
|
|
47
|
+
import bcrypt from "bcrypt";
|
|
48
|
+
const hash = await bcrypt.hash(password, 12);
|
|
49
|
+
const valid = await bcrypt.compare(password, hash);
|
|
50
|
+
|
|
51
|
+
// Secure session
|
|
52
|
+
import { randomBytes } from "crypto";
|
|
53
|
+
const sessionToken = randomBytes(32).toString("hex");
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
### 3. Sensitive Data Exposure
|
|
59
|
+
|
|
60
|
+
**Checklist:**
|
|
61
|
+
|
|
62
|
+
- [ ] HTTPS everywhere (no HTTP)
|
|
63
|
+
- [ ] Sensitive data encrypted at rest
|
|
64
|
+
- [ ] API keys in environment variables, never in code
|
|
65
|
+
- [ ] Passwords never logged
|
|
66
|
+
- [ ] PII masked in logs
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// Never log sensitive data
|
|
70
|
+
console.log(`User login: ${email}`); // ❌
|
|
71
|
+
console.log(`User login: ${maskEmail(email)}`); // ✅
|
|
72
|
+
|
|
73
|
+
// Environment variables
|
|
74
|
+
const apiKey = process.env.STRIPE_SECRET_KEY; // ✅
|
|
75
|
+
const apiKey = "sk_live_abc123"; // ❌ NEVER
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### 4. Cross-Site Scripting (XSS)
|
|
81
|
+
|
|
82
|
+
**❌ Vulnerable:**
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// React dangerouslySetInnerHTML
|
|
86
|
+
<div dangerouslySetInnerHTML={{ __html: userContent }} />;
|
|
87
|
+
|
|
88
|
+
// Direct DOM manipulation
|
|
89
|
+
document.getElementById("output").innerHTML = userInput;
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**✅ Secure:**
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// React auto-escapes
|
|
96
|
+
<div>{userContent}</div>;
|
|
97
|
+
|
|
98
|
+
// Sanitize HTML if needed
|
|
99
|
+
import DOMPurify from "dompurify";
|
|
100
|
+
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userContent) }} />;
|
|
101
|
+
|
|
102
|
+
// CSP Headers
|
|
103
|
+
res.setHeader("Content-Security-Policy", "default-src 'self'");
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
### 5. Cross-Site Request Forgery (CSRF)
|
|
109
|
+
|
|
110
|
+
**Protection:**
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// 1. CSRF Token (forms)
|
|
114
|
+
<input type="hidden" name="_csrf" value={csrfToken} />;
|
|
115
|
+
|
|
116
|
+
// 2. SameSite cookies
|
|
117
|
+
res.cookie("session", token, {
|
|
118
|
+
httpOnly: true,
|
|
119
|
+
secure: true,
|
|
120
|
+
sameSite: "lax", // or 'strict' for sensitive
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// 3. Verify origin header
|
|
124
|
+
const origin = req.headers.origin;
|
|
125
|
+
if (!allowedOrigins.includes(origin)) {
|
|
126
|
+
return res.status(403).json({ error: "Forbidden" });
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### 6. Security Misconfiguration
|
|
133
|
+
|
|
134
|
+
**Checklist:**
|
|
135
|
+
|
|
136
|
+
- [ ] Debug mode OFF in production
|
|
137
|
+
- [ ] Default credentials changed
|
|
138
|
+
- [ ] Unnecessary features disabled
|
|
139
|
+
- [ ] Error messages don't leak stack traces
|
|
140
|
+
- [ ] Security headers configured
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// Security headers (Helmet.js)
|
|
144
|
+
import helmet from "helmet";
|
|
145
|
+
app.use(helmet());
|
|
146
|
+
|
|
147
|
+
// Custom error handler
|
|
148
|
+
app.use((err, req, res, next) => {
|
|
149
|
+
console.error(err); // Log full error
|
|
150
|
+
res.status(500).json({
|
|
151
|
+
error: "Internal Server Error", // Generic message to user
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 🛡️ API Security
|
|
159
|
+
|
|
160
|
+
### Rate Limiting
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import rateLimit from "express-rate-limit";
|
|
164
|
+
|
|
165
|
+
const limiter = rateLimit({
|
|
166
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
167
|
+
max: 100, // 100 requests per window
|
|
168
|
+
message: "Too many requests",
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
app.use("/api/", limiter);
|
|
172
|
+
|
|
173
|
+
// Stricter for auth endpoints
|
|
174
|
+
const authLimiter = rateLimit({
|
|
175
|
+
windowMs: 60 * 1000,
|
|
176
|
+
max: 5,
|
|
177
|
+
});
|
|
178
|
+
app.use("/api/auth/", authLimiter);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### Input Validation
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
import { z } from "zod";
|
|
187
|
+
|
|
188
|
+
const UserSchema = z.object({
|
|
189
|
+
email: z.string().email(),
|
|
190
|
+
password: z.string().min(8).max(128),
|
|
191
|
+
age: z.number().int().min(13).max(120).optional(),
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Validate
|
|
195
|
+
const result = UserSchema.safeParse(req.body);
|
|
196
|
+
if (!result.success) {
|
|
197
|
+
return res.status(400).json({ errors: result.error.issues });
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### Authorization
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// Role-based access
|
|
207
|
+
const requireRole = (roles: string[]) => {
|
|
208
|
+
return (req, res, next) => {
|
|
209
|
+
if (!roles.includes(req.user.role)) {
|
|
210
|
+
return res.status(403).json({ error: "Forbidden" });
|
|
211
|
+
}
|
|
212
|
+
next();
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
app.delete("/api/users/:id", requireRole(["admin"]), deleteUser);
|
|
217
|
+
|
|
218
|
+
// Resource ownership
|
|
219
|
+
app.put("/api/posts/:id", async (req, res) => {
|
|
220
|
+
const post = await prisma.post.findUnique({ where: { id: req.params.id } });
|
|
221
|
+
if (post.authorId !== req.user.id && req.user.role !== "admin") {
|
|
222
|
+
return res.status(403).json({ error: "Forbidden" });
|
|
223
|
+
}
|
|
224
|
+
// proceed with update
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## 🔑 Secrets Management
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// ✅ Environment variables
|
|
234
|
+
DATABASE_URL=postgresql://...
|
|
235
|
+
STRIPE_SECRET_KEY=sk_live_...
|
|
236
|
+
|
|
237
|
+
// ✅ .env files (gitignored)
|
|
238
|
+
// .env.local, .env.production
|
|
239
|
+
|
|
240
|
+
// ✅ Secret managers (production)
|
|
241
|
+
// AWS Secrets Manager, HashiCorp Vault, Doppler
|
|
242
|
+
|
|
243
|
+
// ❌ NEVER commit secrets
|
|
244
|
+
// ❌ NEVER log secrets
|
|
245
|
+
// ❌ NEVER hardcode in source
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## 📋 Quick Security Checklist
|
|
251
|
+
|
|
252
|
+
Before any implementation:
|
|
253
|
+
|
|
254
|
+
- [ ] All inputs validated and sanitized
|
|
255
|
+
- [ ] Authentication on protected routes
|
|
256
|
+
- [ ] Authorization checks (ownership, roles)
|
|
257
|
+
- [ ] No SQL/command injection
|
|
258
|
+
- [ ] XSS prevention (escape output)
|
|
259
|
+
- [ ] CSRF tokens for forms
|
|
260
|
+
- [ ] Rate limiting on sensitive endpoints
|
|
261
|
+
- [ ] Secrets in env vars, not code
|
|
262
|
+
- [ ] HTTPS enforced
|
|
263
|
+
- [ ] Security headers configured
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: software-architecture
|
|
3
|
+
description: Clean Architecture, SOLID principles, and design patterns for building maintainable software. Use when designing system architecture, refactoring codebases, conducting code reviews, or implementing complex features that require architectural decisions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Software Architecture
|
|
7
|
+
|
|
8
|
+
Comprehensive guide to software architecture principles, patterns, and best practices.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
- Designing system architecture
|
|
13
|
+
- Refactoring existing codebase
|
|
14
|
+
- Code reviews focusing on architecture
|
|
15
|
+
- Implementing complex features
|
|
16
|
+
- Making architectural decisions
|
|
17
|
+
- Solving scalability challenges
|
|
18
|
+
|
|
19
|
+
## Core Principles
|
|
20
|
+
|
|
21
|
+
### SOLID Principles
|
|
22
|
+
|
|
23
|
+
See [references/solid-principles.md](references/solid-principles.md) for detailed explanations and examples.
|
|
24
|
+
|
|
25
|
+
**Quick Reference:**
|
|
26
|
+
|
|
27
|
+
- **S**ingle Responsibility - One class, one reason to change
|
|
28
|
+
- **O**pen/Closed - Open for extension, closed for modification
|
|
29
|
+
- **L**iskov Substitution - Subclasses should be substitutable
|
|
30
|
+
- **I**nterface Segregation - Many specific interfaces over one general
|
|
31
|
+
- **D**ependency Inversion - Depend on abstractions, not concretions
|
|
32
|
+
|
|
33
|
+
### Clean Architecture
|
|
34
|
+
|
|
35
|
+
See [references/clean-architecture.md](references/clean-architecture.md) for layer-by-layer guide.
|
|
36
|
+
|
|
37
|
+
**Layers (outer to inner):**
|
|
38
|
+
|
|
39
|
+
1. Frameworks & Drivers (UI, DB, External APIs)
|
|
40
|
+
2. Interface Adapters (Controllers, Presenters, Gateways)
|
|
41
|
+
3. Application Business Rules (Use Cases)
|
|
42
|
+
4. Enterprise Business Rules (Entities)
|
|
43
|
+
|
|
44
|
+
**Rule:** Dependencies point inward only
|
|
45
|
+
|
|
46
|
+
## Common Design Patterns
|
|
47
|
+
|
|
48
|
+
See [references/design-patterns.md](references/design-patterns.md) for full catalog.
|
|
49
|
+
|
|
50
|
+
### Creational Patterns
|
|
51
|
+
|
|
52
|
+
- Factory Pattern - Object creation
|
|
53
|
+
- Builder Pattern - Complex object construction
|
|
54
|
+
- Singleton Pattern - Single instance
|
|
55
|
+
|
|
56
|
+
### Structural Patterns
|
|
57
|
+
|
|
58
|
+
- Adapter Pattern - Interface compatibility
|
|
59
|
+
- Decorator Pattern - Add behavior dynamically
|
|
60
|
+
- Repository Pattern - Data access abstraction
|
|
61
|
+
|
|
62
|
+
### Behavioral Patterns
|
|
63
|
+
|
|
64
|
+
- Strategy Pattern - Interchangeable algorithms
|
|
65
|
+
- Observer Pattern - Event notification
|
|
66
|
+
- Command Pattern - Encapsulate requests
|
|
67
|
+
|
|
68
|
+
## Architecture Best Practices
|
|
69
|
+
|
|
70
|
+
1. **Separation of Concerns** - Each module has distinct responsibility
|
|
71
|
+
2. **Dependency Injection** - Inject dependencies, don't create them
|
|
72
|
+
3. **Interface Programming** - Code to interfaces, not implementations
|
|
73
|
+
4. **Single Source of Truth** - One canonical source for each data type
|
|
74
|
+
5. **Test-Driven Design** - Design for testability from the start
|
|
75
|
+
6. **Incremental Refactoring** - Improve architecture continuously
|
|
76
|
+
|
|
77
|
+
## Code Organization
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
src/
|
|
81
|
+
├── domain/ # Business logic (entities, use cases)
|
|
82
|
+
├── infrastructure/ # External concerns (DB, API clients)
|
|
83
|
+
├── application/ # Application services
|
|
84
|
+
└── presentation/ # UI, controllers, views
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## References
|
|
88
|
+
|
|
89
|
+
- [SOLID Principles](references/solid-principles.md) - Detailed examples
|
|
90
|
+
- [Clean Architecture](references/clean-architecture.md) - Layer guide
|
|
91
|
+
- [Design Patterns](references/design-patterns.md) - Pattern catalog
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# SOLID Principles
|
|
2
|
+
|
|
3
|
+
## S - Single Responsibility Principle (SRP)
|
|
4
|
+
|
|
5
|
+
**A class should have only one reason to change.**
|
|
6
|
+
|
|
7
|
+
### ❌ Violation
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
class User {
|
|
11
|
+
constructor(name, email) {
|
|
12
|
+
this.name = name;
|
|
13
|
+
this.email = email;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Database logic - reason #1 to change
|
|
17
|
+
save() {
|
|
18
|
+
database.insert("users", this);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Email logic - reason #2 to change
|
|
22
|
+
sendWelcomeEmail() {
|
|
23
|
+
emailService.send(this.email, "Welcome!");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Validation - reason #3 to change
|
|
27
|
+
validate() {
|
|
28
|
+
return this.email.includes("@");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### ✅ Solution
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
class User {
|
|
37
|
+
constructor(name, email) {
|
|
38
|
+
this.name = name;
|
|
39
|
+
this.email = email;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class UserRepository {
|
|
44
|
+
save(user) {
|
|
45
|
+
database.insert("users", user);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class UserNotification {
|
|
50
|
+
sendWelcome(user) {
|
|
51
|
+
emailService.send(user.email, "Welcome!");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class UserValidator {
|
|
56
|
+
validate(user) {
|
|
57
|
+
return user.email.includes("@");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## O - Open/Closed Principle (OCP)
|
|
63
|
+
|
|
64
|
+
**Open for extension, closed for modification.**
|
|
65
|
+
|
|
66
|
+
### ❌ Violation
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
class PaymentProcessor {
|
|
70
|
+
process(payment) {
|
|
71
|
+
if (payment.type === "credit-card") {
|
|
72
|
+
// Process credit card
|
|
73
|
+
} else if (payment.type === "paypal") {
|
|
74
|
+
// Process PayPal
|
|
75
|
+
}
|
|
76
|
+
// Adding new payment type requires modifying this class
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### ✅ Solution
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
class PaymentProcessor {
|
|
85
|
+
constructor(strategy) {
|
|
86
|
+
this.strategy = strategy;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
process(payment) {
|
|
90
|
+
return this.strategy.process(payment);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
class CreditCardStrategy {
|
|
95
|
+
process(payment) {
|
|
96
|
+
// Process credit card
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
class PayPalStrategy {
|
|
101
|
+
process(payment) {
|
|
102
|
+
// Process PayPal
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Usage - extend without modification
|
|
107
|
+
const processor = new PaymentProcessor(new CreditCardStrategy());
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## L - Liskov Substitution Principle (LSP)
|
|
111
|
+
|
|
112
|
+
**Subclasses should be substitutable for their base classes.**
|
|
113
|
+
|
|
114
|
+
### ❌ Violation
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
class Rectangle {
|
|
118
|
+
setWidth(width) {
|
|
119
|
+
this.width = width;
|
|
120
|
+
}
|
|
121
|
+
setHeight(height) {
|
|
122
|
+
this.height = height;
|
|
123
|
+
}
|
|
124
|
+
getArea() {
|
|
125
|
+
return this.width * this.height;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
class Square extends Rectangle {
|
|
130
|
+
setWidth(width) {
|
|
131
|
+
this.width = width;
|
|
132
|
+
this.height = width; // Breaks expectation
|
|
133
|
+
}
|
|
134
|
+
setHeight(height) {
|
|
135
|
+
this.width = height;
|
|
136
|
+
this.height = height;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### ✅ Solution
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
class Shape {
|
|
145
|
+
getArea() {
|
|
146
|
+
throw new Error("Must implement getArea");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
class Rectangle extends Shape {
|
|
151
|
+
constructor(width, height) {
|
|
152
|
+
super();
|
|
153
|
+
this.width = width;
|
|
154
|
+
this.height = height;
|
|
155
|
+
}
|
|
156
|
+
getArea() {
|
|
157
|
+
return this.width * this.height;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
class Square extends Shape {
|
|
162
|
+
constructor(side) {
|
|
163
|
+
super();
|
|
164
|
+
this.side = side;
|
|
165
|
+
}
|
|
166
|
+
getArea() {
|
|
167
|
+
return this.side * this.side;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## I - Interface Segregation Principle (ISP)
|
|
173
|
+
|
|
174
|
+
**Many specific interfaces are better than one general interface.**
|
|
175
|
+
|
|
176
|
+
### ❌ Violation
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
class Worker {
|
|
180
|
+
work() {}
|
|
181
|
+
eat() {}
|
|
182
|
+
sleep() {}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
class Robot extends Worker {
|
|
186
|
+
work() {
|
|
187
|
+
/* OK */
|
|
188
|
+
}
|
|
189
|
+
eat() {
|
|
190
|
+
throw new Error("Robots don't eat");
|
|
191
|
+
}
|
|
192
|
+
sleep() {
|
|
193
|
+
throw new Error("Robots don't sleep");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### ✅ Solution
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
class Workable {
|
|
202
|
+
work() {}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
class Eatable {
|
|
206
|
+
eat() {}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
class Sleepable {
|
|
210
|
+
sleep() {}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
class Human extends Workable {
|
|
214
|
+
work() {
|
|
215
|
+
/* ... */
|
|
216
|
+
}
|
|
217
|
+
eat() {
|
|
218
|
+
/* via Eatable */
|
|
219
|
+
}
|
|
220
|
+
sleep() {
|
|
221
|
+
/* via Sleepable */
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
class Robot extends Workable {
|
|
226
|
+
work() {
|
|
227
|
+
/* ... */
|
|
228
|
+
}
|
|
229
|
+
// Doesn't implement eat/sleep
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## D - Dependency Inversion Principle (DIP)
|
|
234
|
+
|
|
235
|
+
**Depend on abstractions, not concretions.**
|
|
236
|
+
|
|
237
|
+
### ❌ Violation
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
class EmailService {
|
|
241
|
+
send(to, message) {
|
|
242
|
+
/* Send email */
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
class UserService {
|
|
247
|
+
constructor() {
|
|
248
|
+
this.emailService = new EmailService(); // Tight coupling
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
register(user) {
|
|
252
|
+
this.emailService.send(user.email, "Welcome");
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### ✅ Solution
|
|
258
|
+
|
|
259
|
+
```javascript
|
|
260
|
+
// Abstraction
|
|
261
|
+
class NotificationService {
|
|
262
|
+
send(to, message) {
|
|
263
|
+
throw new Error("Must implement");
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Implementations
|
|
268
|
+
class EmailService extends NotificationService {
|
|
269
|
+
send(to, message) {
|
|
270
|
+
/* Send email */
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
class SMSService extends NotificationService {
|
|
275
|
+
send(to, message) {
|
|
276
|
+
/* Send SMS */
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Depend on abstraction
|
|
281
|
+
class UserService {
|
|
282
|
+
constructor(notificationService) {
|
|
283
|
+
this.notificationService = notificationService;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
register(user) {
|
|
287
|
+
this.notificationService.send(user.email, "Welcome");
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Usage - easily swap implementations
|
|
292
|
+
const userService = new UserService(new EmailService());
|
|
293
|
+
```
|