claude-code-ultimate-guide/examples/skills/design-patterns/signatures/stack-patterns.yaml
Florian BRUNIAUX fcc6f2dba3 feat(skills): add design-patterns analyzer skill
Comprehensive GoF design patterns analyzer with stack-aware suggestions.

**Features**:
- Detects 23 GoF patterns (Creational, Structural, Behavioral)
- Stack detection (React, Angular, NestJS, Vue, Express, RxJS, Redux, ORMs)
- Code smell detection with pattern suggestions
- Quality evaluation (5 criteria scoring)
- Prefers stack-native alternatives (e.g., React Context over Singleton)

**Structure**:
- 9 files: SKILL.md + reference docs + detection rules + evaluation checklists
- 3 operating modes: Detection, Suggestion, Evaluation
- Pattern-specific documentation for all 23 GoF patterns

**Documentation**:
- Added comprehensive example in guide section 5.4
- Updated examples/README.md with skill entry
- Updated template count: 65 → 66

**Use cases**:
- Analyze existing patterns in codebase
- Suggest refactoring with stack-native patterns
- Evaluate pattern implementation quality

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-21 13:46:20 +01:00

582 lines
18 KiB
YAML

version: "1.0.0"
description: Stack detection rules and pattern adaptations for framework-native idioms
# Stack Detection Rules
stack_detection:
sources:
- file: "package.json"
check: "dependencies + devDependencies"
priority: 1
- file: "tsconfig.json"
check: "compilerOptions, paths, lib"
priority: 2
- files: ["angular.json", "next.config.*", "nest-cli.json", "vite.config.*", "nuxt.config.*"]
check: "presence"
priority: 1
- pattern: "*.jsx, *.tsx, *.vue, *.svelte"
check: "file extensions"
priority: 3
confidence_scoring:
high: "Primary framework found in package.json + config file present"
medium: "Framework in package.json OR config file present"
low: "Only file extensions or indirect evidence"
# Supported Stacks
stacks:
react:
detection:
package_json:
required: ["react"]
optional: ["react-dom", "next", "@types/react"]
files:
optional: ["next.config.js", "next.config.ts", "vite.config.ts"]
extensions: [".jsx", ".tsx"]
version_detection:
hooks_era: ">=16.8.0" # useState, useEffect introduced
concurrent: ">=18.0.0" # Concurrent features
native_patterns:
singleton:
replacement: "Context API + Provider"
example: |
// Instead of Singleton
const MyContext = createContext<ContextValue>(defaultValue);
export const MyProvider = ({ children }) => (
<MyContext.Provider value={value}>{children}</MyContext.Provider>
);
rationale: "Context provides dependency injection without global state"
confidence: 0.95
observer:
replacement: "useState + useEffect"
example: |
const [value, setValue] = useState(initial);
useEffect(() => {
// React auto-notifies subscribers
}, [value]);
rationale: "React's reactivity system is built-in observer pattern"
confidence: 0.98
strategy:
replacement: "Custom hooks"
example: |
const usePaymentStrategy = (type: PaymentType) => {
const strategies = {
credit: useCreditPayment(),
paypal: usePaypalPayment(),
};
return strategies[type];
};
rationale: "Hooks encapsulate behavior and are composable"
confidence: 0.90
decorator:
replacement: "Higher-Order Components (HOC)"
example: |
const withAuth = <P extends object>(Component: React.ComponentType<P>) => {
return (props: P) => {
const { user } = useAuth();
if (!user) return <Redirect to="/login" />;
return <Component {...props} />;
};
};
rationale: "HOCs wrap components to add behavior"
confidence: 0.85
mediator:
replacement: "Context API"
example: |
// Centralized state management
const AppContext = createContext<AppState>(initialState);
// Components communicate through context
rationale: "Context mediates communication between components"
confidence: 0.80
recommendations:
- "Prefer hooks over class-based patterns"
- "Use Context for shared state, not Singleton"
- "Leverage built-in reactivity instead of manual observer"
- "Consider React Query/SWR for data fetching patterns"
angular:
detection:
package_json:
required: ["@angular/core"]
optional: ["@angular/common", "@angular/platform-browser"]
files:
required: ["angular.json"]
extensions: [".ts"]
version_detection:
standalone: ">=14.0.0" # Standalone components
signals: ">=16.0.0" # Signals API
native_patterns:
singleton:
replacement: "@Injectable() services"
example: |
@Injectable({ providedIn: 'root' })
export class ConfigService {
// Automatically singleton via DI
}
rationale: "Angular's DI container manages singleton lifecycle"
confidence: 0.98
observer:
replacement: "RxJS Observables"
example: |
import { BehaviorSubject } from 'rxjs';
private data$ = new BehaviorSubject<Data>(initial);
getData() { return this.data$.asObservable(); }
rationale: "RxJS is Angular's standard reactive programming library"
confidence: 0.98
decorator:
replacement: "Directives and Pipes"
example: |
@Directive({ selector: '[appHighlight]' })
export class HighlightDirective {
// Adds behavior to DOM elements
}
rationale: "Angular decorators are first-class pattern"
confidence: 0.95
facade:
replacement: "Service with injected dependencies"
example: |
@Injectable()
export class UserFacade {
constructor(
private userService: UserService,
private authService: AuthService,
private profileService: ProfileService
) {}
}
rationale: "Services naturally encapsulate subsystems"
confidence: 0.90
recommendations:
- "Use DI instead of manual singleton patterns"
- "Leverage RxJS for all reactive patterns"
- "Use Angular decorators (@Component, @Directive, @Pipe)"
- "Services should be injected, not manually instantiated"
nestjs:
detection:
package_json:
required: ["@nestjs/core"]
optional: ["@nestjs/common", "@nestjs/platform-express"]
files:
required: ["nest-cli.json"]
extensions: [".ts"]
native_patterns:
singleton:
replacement: "@Injectable() with default scope"
example: |
@Injectable() // Default scope is SINGLETON
export class AppService {}
rationale: "NestJS DI uses singleton scope by default"
confidence: 0.98
chain-of-responsibility:
replacement: "Guards, Interceptors, Pipes, Middleware"
example: |
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
// Guard chain
}
}
rationale: "NestJS request pipeline is built-in chain pattern"
confidence: 0.95
decorator:
replacement: "Interceptors"
example: |
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler) {
// Wraps request handling
}
}
rationale: "Interceptors add behavior to route handlers"
confidence: 0.95
facade:
replacement: "Modules"
example: |
@Module({
providers: [ServiceA, ServiceB],
exports: [FacadeService]
})
export class FeatureModule {}
rationale: "Modules encapsulate and export simplified interfaces"
confidence: 0.85
factory:
replacement: "useFactory provider"
example: |
{
provide: 'CONFIG',
useFactory: (env: EnvService) => createConfig(env),
inject: [EnvService]
}
rationale: "DI supports factory pattern natively"
confidence: 0.90
recommendations:
- "Use built-in DI, never manual singleton"
- "Leverage Guards/Interceptors/Pipes for cross-cutting concerns"
- "Modules should export facades to subsystems"
- "Use dynamic modules for configurable features"
vue:
detection:
package_json:
required: ["vue"]
version: ">=3.0.0"
files:
optional: ["vite.config.ts", "nuxt.config.ts"]
extensions: [".vue"]
version_detection:
composition_api: ">=3.0.0" # Composition API default
script_setup: ">=3.2.0" # <script setup> sugar
native_patterns:
singleton:
replacement: "Provide/Inject"
example: |
// Root component
provide('config', reactive({ theme: 'dark' }));
// Child component
const config = inject('config');
rationale: "Provide/Inject offers dependency injection"
confidence: 0.90
observer:
replacement: "ref() and reactive()"
example: |
const count = ref(0);
watch(count, (newVal) => {
// Automatically notified on change
});
rationale: "Vue 3's reactivity is built-in observer"
confidence: 0.98
strategy:
replacement: "Composables"
example: |
export function usePayment(type: PaymentType) {
const strategies = {
credit: useCreditPayment,
paypal: usePaypalPayment,
};
return strategies[type]();
}
rationale: "Composables encapsulate reusable logic"
confidence: 0.90
mediator:
replacement: "Pinia stores or global state"
example: |
export const useAppStore = defineStore('app', {
state: () => ({ /* ... */ }),
actions: { /* ... */ }
});
rationale: "Pinia centralizes state management"
confidence: 0.85
recommendations:
- "Use Composition API for all new code"
- "Leverage ref()/reactive() instead of manual observer"
- "Use composables for strategy-like patterns"
- "Pinia for global state, provide/inject for DI"
express:
detection:
package_json:
required: ["express"]
extensions: [".js", ".ts"]
native_patterns:
chain-of-responsibility:
replacement: "Middleware (app.use)"
example: |
app.use(authMiddleware);
app.use(loggingMiddleware);
app.use(errorMiddleware);
rationale: "Express middleware is chain of responsibility"
confidence: 0.98
facade:
replacement: "Router"
example: |
const userRouter = express.Router();
userRouter.get('/', getUsers);
userRouter.post('/', createUser);
app.use('/users', userRouter);
rationale: "Routers group related endpoints"
confidence: 0.85
template-method:
replacement: "Route handlers with middleware"
example: |
app.get('/users',
validateRequest, // Step 1
checkAuth, // Step 2
loadUser, // Step 3
(req, res) => {} // Final step
);
rationale: "Middleware chain defines template"
confidence: 0.75
recommendations:
- "Use middleware for cross-cutting concerns"
- "Routers should group related functionality"
- "Error handling middleware should be last"
- "Avoid manual chain implementations"
rxjs:
detection:
package_json:
required: ["rxjs"]
extensions: [".ts", ".js"]
native_patterns:
observer:
replacement: "Subject, BehaviorSubject, ReplaySubject"
example: |
const subject = new BehaviorSubject<number>(0);
subject.subscribe(value => console.log(value));
subject.next(1); // Notifies subscribers
rationale: "RxJS is the observer pattern library"
confidence: 1.0
strategy:
replacement: "RxJS operators"
example: |
observable.pipe(
map(x => x * 2),
filter(x => x > 10),
debounceTime(300)
);
rationale: "Operators are composable strategies"
confidence: 0.90
decorator:
replacement: "pipe() operator"
example: |
source$.pipe(
tap(x => console.log(x)), // Add logging
catchError(handleError) // Add error handling
);
rationale: "pipe() chains operators that decorate behavior"
confidence: 0.85
chain-of-responsibility:
replacement: "mergeMap, concatMap, switchMap"
example: |
requests$.pipe(
mergeMap(req => processRequest(req)),
catchError((err, caught) => caught) // Pass to next
);
rationale: "Operators chain processing steps"
confidence: 0.75
recommendations:
- "Use Subject variants, not custom observer classes"
- "Compose operators instead of manual logic"
- "shareReplay() for caching/memoization"
- "Avoid manual subscription management, use async pipe (Angular)"
redux:
detection:
package_json:
required_any: ["redux", "@reduxjs/toolkit", "zustand", "jotai", "recoil"]
extensions: [".ts", ".js", ".tsx", ".jsx"]
native_patterns:
singleton:
replacement: "Store"
example: |
// Redux
const store = createStore(rootReducer);
// Zustand
export const useStore = create((set) => ({ /* ... */ }));
rationale: "Store is managed singleton"
confidence: 0.98
command:
replacement: "Actions and Action Creators"
example: |
// Redux action
const incrementAction = { type: 'INCREMENT', payload: 1 };
// Redux Toolkit
const increment = createAction<number>('counter/increment');
rationale: "Actions encapsulate state changes"
confidence: 0.95
observer:
replacement: "Store subscriptions"
example: |
// Redux
store.subscribe(() => console.log(store.getState()));
// Zustand (React)
const count = useStore(state => state.count);
rationale: "Store notifies subscribers on state change"
confidence: 0.95
state:
replacement: "Reducers"
example: |
const reducer = (state, action) => {
switch (action.type) {
case 'INCREMENT': return { count: state.count + 1 };
// Different states handled by action type
}
};
rationale: "Reducers implement state-dependent behavior"
confidence: 0.85
memento:
replacement: "Time-travel debugging / Redux DevTools"
example: |
// Redux DevTools captures state snapshots
// Can jump to any previous state
rationale: "Store history enables memento pattern"
confidence: 0.80
recommendations:
- "Use Redux Toolkit for modern Redux (reduces boilerplate)"
- "Consider Zustand for simpler state management"
- "Actions should be serializable (for time-travel)"
- "Selectors should use reselect for memoization"
orm:
detection:
package_json:
required_any: ["prisma", "@prisma/client", "typeorm", "@mikro-orm/core", "sequelize"]
files:
optional: ["prisma/schema.prisma", "ormconfig.json"]
extensions: [".ts"]
native_patterns:
repository:
replacement: "Prisma Client / TypeORM Repository"
example: |
// Prisma
const users = await prisma.user.findMany();
// TypeORM
const userRepo = dataSource.getRepository(User);
const users = await userRepo.find();
rationale: "ORMs provide repository pattern out-of-box"
confidence: 0.95
facade:
replacement: "ORM Client"
example: |
// Prisma facades complex SQL
await prisma.user.create({
data: { name: 'Alice', posts: { create: [{ title: 'Hello' }] } }
});
rationale: "ORM simplifies database operations"
confidence: 0.90
builder:
replacement: "Query Builder"
example: |
// Prisma
prisma.user.findMany({ where: { age: { gte: 18 } }, orderBy: { name: 'asc' } });
// TypeORM Query Builder
userRepo.createQueryBuilder('user')
.where('user.age >= :age', { age: 18 })
.orderBy('user.name', 'ASC')
.getMany();
rationale: "Fluent interface for complex queries"
confidence: 0.90
unit-of-work:
replacement: "Transactions"
example: |
await prisma.$transaction([
prisma.user.create({ data: userData }),
prisma.post.create({ data: postData })
]);
rationale: "Transactions implement unit of work"
confidence: 0.85
lazy-loading:
replacement: "Include/relations"
example: |
const user = await prisma.user.findUnique({
where: { id: 1 },
include: { posts: true } // Explicit eager loading
});
rationale: "ORMs control loading strategy"
confidence: 0.80
recommendations:
- "Use ORM repositories, not custom implementations"
- "Leverage query builders for complex queries"
- "Understand N+1 problem, use includes wisely"
- "Transactions for multi-model operations"
# Adaptation Rules
adaptation_rules:
- condition: "pattern exists natively in stack"
action: "suggest_native"
priority: "high"
message: "Use stack-native implementation instead of custom pattern"
- condition: "custom implementation found AND native exists"
action: "refactor_to_native"
priority: "high"
message: "Refactor custom implementation to use stack-native idiom"
- condition: "pattern missing AND native exists"
action: "suggest_native_with_example"
priority: "medium"
message: "Implement using stack-native features"
- condition: "pattern missing AND no native equivalent"
action: "suggest_custom_implementation"
priority: "low"
message: "Implement custom TypeScript pattern following best practices"
- condition: "anti-pattern detected"
action: "warn_and_suggest_alternative"
priority: "critical"
message: "Current implementation has known issues, see alternative"
# Common Stack Combinations
stack_combinations:
react_full:
primary: "react"
common_secondary: ["redux", "react-query", "zustand"]
pattern_notes: "React Query/SWR replaces many manual patterns for data fetching"
angular_full:
primary: "angular"
common_secondary: ["rxjs", "ngrx"]
pattern_notes: "RxJS is integral, NgRx adds Redux-like state management"
nestjs_full:
primary: "nestjs"
common_secondary: ["typeorm", "prisma"]
pattern_notes: "NestJS provides most patterns, ORM adds repository layer"
vue_full:
primary: "vue"
common_secondary: ["pinia", "vueuse"]
pattern_notes: "Pinia for state, VueUse provides composable utilities"
# Priority for suggestions
suggestion_priority:
critical: "Anti-pattern or security issue"
high: "Native stack alternative available, significant improvement"
medium: "Pattern missing, would improve code quality"
low: "Optional improvement, minimal impact"