claude-code-ultimate-guide/examples/skills/design-patterns/signatures/detection-rules.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

769 lines
20 KiB
YAML

version: "1.0.0"
description: Detection rules and heuristics for identifying design patterns in TypeScript/JavaScript code
# Detection Strategy:
# 1. Glob Phase: Find candidate files by naming convention
# 2. Grep Phase: Search for primary and secondary signals
# 3. Read Phase: Validate structure and relationships
# 4. Confidence Scoring: Aggregate signal strengths
# Creational Patterns
creational:
singleton:
naming_conventions:
- "*Singleton*.ts"
- "*Manager.ts"
- "*Service.ts"
- "*Client.ts"
- "*Config.ts"
- "*Instance.ts"
primary_signals:
- pattern: "private\\s+constructor"
weight: 0.4
description: "Private constructor prevents direct instantiation"
- pattern: "static\\s+getInstance\\s*\\("
weight: 0.35
description: "Static getInstance method is canonical singleton signature"
- pattern: "private\\s+static\\s+\\w+:\\s*\\w+"
weight: 0.25
description: "Private static instance field"
secondary_signals:
- pattern: "if\\s*\\(!\\w+\\.instance\\)"
weight: 0.15
description: "Lazy initialization check"
- pattern: "return\\s+\\w+\\.instance"
weight: 0.10
description: "Returns singleton instance"
typescript_specific:
- pattern: "private\\s+static\\s+instance\\?:\\s*\\w+"
description: "TypeScript optional instance field"
- pattern: "public\\s+static\\s+getInstance\\(\\):\\s*\\w+"
description: "Explicit return type annotation"
anti_patterns:
- pattern: "new\\s+\\w+\\(\\).*getInstance"
description: "Creating new instance inside getInstance (wrong)"
confidence_threshold: 0.70
minimum_signals: 2
factory-method:
naming_conventions:
- "*Factory.ts"
- "*Creator.ts"
- "*Provider.ts"
- "*Builder.ts"
primary_signals:
- pattern: "create\\w+\\s*\\([^)]*\\):\\s*\\w+"
weight: 0.35
description: "create* method returning interface/type"
- pattern: "abstract\\s+create\\w+"
weight: 0.30
description: "Abstract factory method"
- pattern: "interface\\s+\\w+Factory"
weight: 0.20
description: "Factory interface definition"
secondary_signals:
- pattern: "class\\s+\\w+\\s+extends\\s+\\w+Factory"
weight: 0.15
description: "Concrete factory inheriting from abstract"
- pattern: "return\\s+new\\s+\\w+\\("
weight: 0.10
description: "Factory returns new instance"
- pattern: "switch\\s*\\([^)]*type[^)]*\\)"
weight: 0.15
description: "Type-based creation logic"
typescript_specific:
- pattern: "create\\w+<T[^>]*>"
description: "Generic factory method"
confidence_threshold: 0.65
minimum_signals: 2
abstract-factory:
naming_conventions:
- "*AbstractFactory.ts"
- "*Factory.ts"
- "*FactoryInterface.ts"
primary_signals:
- pattern: "abstract\\s+class\\s+\\w+Factory"
weight: 0.30
description: "Abstract factory class"
- pattern: "interface\\s+\\w+Factory\\s*\\{[^}]*create\\w+[^}]*create\\w+"
weight: 0.35
description: "Factory interface with multiple create methods"
- pattern: "create\\w+\\s*\\([^)]*\\):\\s*\\w+.*create\\w+\\s*\\([^)]*\\):\\s*\\w+"
weight: 0.25
description: "Multiple factory methods"
secondary_signals:
- pattern: "class\\s+\\w+\\s+implements\\s+\\w+Factory"
weight: 0.15
description: "Concrete factory implementing interface"
- pattern: "family|related|product"
weight: 0.10
description: "Domain language suggesting related objects"
confidence_threshold: 0.70
minimum_signals: 2
builder:
naming_conventions:
- "*Builder.ts"
- "*ConfigBuilder.ts"
- "*QueryBuilder.ts"
primary_signals:
- pattern: "\\w+\\s*\\([^)]*\\):\\s*(this|\\w+Builder)"
weight: 0.30
description: "Fluent interface returning this or builder type"
- pattern: "build\\s*\\(\\):\\s*\\w+"
weight: 0.35
description: "Build method returning final product"
- pattern: "with\\w+\\s*\\([^)]*\\):\\s*this"
weight: 0.25
description: "with* methods for setting properties"
secondary_signals:
- pattern: "set\\w+\\s*\\([^)]*\\):\\s*this"
weight: 0.15
description: "set* methods returning this"
- pattern: "private\\s+\\w+\\?:\\s*\\w+"
weight: 0.10
description: "Optional private fields being built up"
typescript_specific:
- pattern: "class\\s+\\w+Builder<T"
description: "Generic builder"
- pattern: "\\): this \\{"
description: "Explicit 'this' return type"
confidence_threshold: 0.70
minimum_signals: 2
prototype:
naming_conventions:
- "*Prototype.ts"
- "*Cloneable.ts"
primary_signals:
- pattern: "clone\\s*\\(\\):\\s*\\w+"
weight: 0.45
description: "Clone method signature"
- pattern: "Object\\.create\\("
weight: 0.25
description: "Using Object.create for prototypal inheritance"
- pattern: "JSON\\.parse\\(JSON\\.stringify\\("
weight: 0.20
description: "Deep clone via JSON (simple approach)"
secondary_signals:
- pattern: "\\.\\.\\."
weight: 0.10
description: "Spread operator for shallow copy"
- pattern: "structuredClone\\("
weight: 0.15
description: "Modern structuredClone API"
confidence_threshold: 0.60
minimum_signals: 1
# Structural Patterns
structural:
adapter:
naming_conventions:
- "*Adapter.ts"
- "*Wrapper.ts"
primary_signals:
- pattern: "class\\s+\\w+Adapter\\s+implements\\s+\\w+"
weight: 0.35
description: "Adapter implementing target interface"
- pattern: "private\\s+\\w+:\\s*\\w+;"
weight: 0.25
description: "Holds reference to adaptee"
- pattern: "constructor\\([^)]*adaptee[^)]*\\)"
weight: 0.30
description: "Adaptee injected in constructor"
secondary_signals:
- pattern: "this\\.\\w+\\.\\w+\\("
weight: 0.15
description: "Delegates to adaptee"
- pattern: "convert|transform|map"
weight: 0.10
description: "Conversion language in methods"
confidence_threshold: 0.65
minimum_signals: 2
bridge:
naming_conventions:
- "*Bridge.ts"
- "*Abstraction.ts"
- "*Implementation.ts"
primary_signals:
- pattern: "protected\\s+impl:\\s*\\w+Implementation"
weight: 0.35
description: "Abstraction holds implementation reference"
- pattern: "interface\\s+\\w+Implementation"
weight: 0.30
description: "Implementation interface"
- pattern: "constructor\\([^)]*implementation[^)]*\\)"
weight: 0.25
description: "Implementation injected"
secondary_signals:
- pattern: "this\\.impl\\."
weight: 0.15
description: "Delegates to implementation"
confidence_threshold: 0.60
minimum_signals: 2
composite:
naming_conventions:
- "*Composite.ts"
- "*Component.ts"
- "*Container.ts"
- "*Group.ts"
primary_signals:
- pattern: "private\\s+children:\\s*\\w+\\[\\]"
weight: 0.35
description: "Collection of child components"
- pattern: "add\\s*\\([^)]*\\):|remove\\s*\\([^)]*\\):"
weight: 0.30
description: "Methods to manage children"
- pattern: "abstract\\s+class\\s+\\w+Component"
weight: 0.25
description: "Abstract component class"
secondary_signals:
- pattern: "children\\.forEach\\(|children\\.map\\("
weight: 0.15
description: "Iterates over children"
- pattern: "getChild\\(|getChildren\\("
weight: 0.10
description: "Access to children"
typescript_specific:
- pattern: "children:\\s*Array<\\w+>"
description: "Typed array of components"
confidence_threshold: 0.70
minimum_signals: 2
decorator:
naming_conventions:
- "*Decorator.ts"
- "*Wrapper.ts"
primary_signals:
- pattern: "class\\s+\\w+Decorator\\s+implements\\s+\\w+"
weight: 0.30
description: "Decorator implements same interface"
- pattern: "protected\\s+wrapped:\\s*\\w+"
weight: 0.30
description: "Holds reference to wrapped object"
- pattern: "constructor\\([^)]*wrapped[^)]*\\)"
weight: 0.25
description: "Wrapped object injected"
secondary_signals:
- pattern: "this\\.wrapped\\.\\w+\\("
weight: 0.20
description: "Delegates to wrapped object"
- pattern: "super\\(wrapped\\)"
weight: 0.15
description: "Passes wrapped to base decorator"
typescript_specific:
- pattern: "@\\w+"
description: "TypeScript decorator syntax (different usage)"
confidence_threshold: 0.65
minimum_signals: 2
facade:
naming_conventions:
- "*Facade.ts"
- "*API.ts"
- "*Interface.ts"
- "*Service.ts"
primary_signals:
- pattern: "private\\s+\\w+Service:\\s*\\w+;[^}]*private\\s+\\w+Service:\\s*\\w+"
weight: 0.35
description: "Multiple subsystem dependencies"
- pattern: "constructor\\([^)]*,\\s*[^)]*,\\s*[^)]*\\)"
weight: 0.25
description: "Multiple injected dependencies"
secondary_signals:
- pattern: "this\\.\\w+Service\\.\\w+\\([^)]*\\);[^}]*this\\.\\w+Service\\.\\w+\\("
weight: 0.20
description: "Coordinates multiple subsystems"
- pattern: "public\\s+async\\s+\\w+\\([^)]*\\)"
weight: 0.10
description: "Simplified public interface"
confidence_threshold: 0.60
minimum_signals: 2
flyweight:
naming_conventions:
- "*Flyweight.ts"
- "*Pool.ts"
- "*Cache.ts"
primary_signals:
- pattern: "private\\s+static\\s+pool:\\s*Map"
weight: 0.35
description: "Shared pool of flyweights"
- pattern: "getFlyweight\\s*\\([^)]*\\):\\s*\\w+"
weight: 0.30
description: "Factory method for shared objects"
- pattern: "if\\s*\\(!pool\\.has\\([^)]*\\)\\)"
weight: 0.25
description: "Check if flyweight exists before creating"
secondary_signals:
- pattern: "intrinsic|extrinsic"
weight: 0.15
description: "Domain language for shared/unique state"
confidence_threshold: 0.65
minimum_signals: 2
proxy:
naming_conventions:
- "*Proxy.ts"
primary_signals:
- pattern: "class\\s+\\w+Proxy\\s+implements\\s+\\w+"
weight: 0.30
description: "Proxy implements same interface as real subject"
- pattern: "private\\s+realSubject:\\s*\\w+"
weight: 0.30
description: "Holds reference to real subject"
- pattern: "lazy|cache|access|log"
weight: 0.20
description: "Proxy purpose keywords"
secondary_signals:
- pattern: "if\\s*\\(!this\\.realSubject\\)"
weight: 0.15
description: "Lazy initialization"
- pattern: "this\\.realSubject\\.\\w+\\("
weight: 0.15
description: "Delegates to real subject"
typescript_specific:
- pattern: "new\\s+Proxy\\("
description: "JavaScript Proxy object"
confidence_threshold: 0.65
minimum_signals: 2
# Behavioral Patterns
behavioral:
chain-of-responsibility:
naming_conventions:
- "*Handler.ts"
- "*Middleware.ts"
- "*Chain.ts"
primary_signals:
- pattern: "protected\\s+next:\\s*\\w+Handler"
weight: 0.35
description: "Reference to next handler"
- pattern: "setNext\\s*\\([^)]*\\):\\s*\\w+Handler"
weight: 0.30
description: "Method to set next handler"
- pattern: "handle\\s*\\([^)]*\\):"
weight: 0.25
description: "Handle method"
secondary_signals:
- pattern: "if\\s*\\(this\\.next\\)"
weight: 0.15
description: "Checks if next handler exists"
- pattern: "this\\.next\\.handle\\("
weight: 0.15
description: "Passes request to next"
confidence_threshold: 0.70
minimum_signals: 2
command:
naming_conventions:
- "*Command.ts"
- "*Action.ts"
primary_signals:
- pattern: "interface\\s+\\w+Command\\s*\\{[^}]*execute"
weight: 0.35
description: "Command interface with execute"
- pattern: "execute\\s*\\(\\):"
weight: 0.30
description: "Execute method"
- pattern: "undo\\s*\\(\\):"
weight: 0.25
description: "Undo method for reversibility"
secondary_signals:
- pattern: "private\\s+receiver:\\s*\\w+"
weight: 0.15
description: "Holds receiver reference"
- pattern: "history|stack"
weight: 0.10
description: "Command history tracking"
confidence_threshold: 0.65
minimum_signals: 2
iterator:
naming_conventions:
- "*Iterator.ts"
primary_signals:
- pattern: "\\[Symbol\\.iterator\\]\\(\\)"
weight: 0.40
description: "JavaScript iterator protocol"
- pattern: "next\\s*\\(\\):\\s*\\{\\s*value[^}]*done"
weight: 0.35
description: "Iterator next method"
- pattern: "function\\*|\\*\\w+\\s*\\("
weight: 0.25
description: "Generator function"
secondary_signals:
- pattern: "yield"
weight: 0.15
description: "Generator yield"
- pattern: "implements\\s+Iterator<"
weight: 0.15
description: "Implements Iterator interface"
confidence_threshold: 0.65
minimum_signals: 1
mediator:
naming_conventions:
- "*Mediator.ts"
- "*Controller.ts"
- "*Coordinator.ts"
primary_signals:
- pattern: "class\\s+\\w+Mediator"
weight: 0.30
description: "Mediator class"
- pattern: "private\\s+colleagues:\\s*\\w+\\[\\]"
weight: 0.30
description: "Collection of colleagues"
- pattern: "notify\\s*\\([^)]*sender[^)]*\\)"
weight: 0.30
description: "Notify method with sender"
secondary_signals:
- pattern: "register\\w+\\(|add\\w+\\("
weight: 0.15
description: "Register colleagues"
confidence_threshold: 0.65
minimum_signals: 2
memento:
naming_conventions:
- "*Memento.ts"
- "*Snapshot.ts"
- "*Caretaker.ts"
primary_signals:
- pattern: "save\\s*\\(\\):\\s*\\w+Memento"
weight: 0.35
description: "Save state to memento"
- pattern: "restore\\s*\\([^)]*memento[^)]*\\)"
weight: 0.35
description: "Restore from memento"
- pattern: "class\\s+\\w+Memento"
weight: 0.20
description: "Memento class"
secondary_signals:
- pattern: "private\\s+state:"
weight: 0.15
description: "Encapsulated state"
- pattern: "history:\\s*\\w+\\[\\]"
weight: 0.10
description: "History of mementos"
confidence_threshold: 0.70
minimum_signals: 2
observer:
naming_conventions:
- "*Observer.ts"
- "*Subject.ts"
- "*Publisher.ts"
- "*Subscriber.ts"
- "*Event*.ts"
primary_signals:
- pattern: "subscribe\\s*\\([^)]*\\):|attach\\s*\\([^)]*\\):"
weight: 0.30
description: "Subscribe method"
- pattern: "unsubscribe\\s*\\([^)]*\\):|detach\\s*\\([^)]*\\):"
weight: 0.25
description: "Unsubscribe method"
- pattern: "notify\\s*\\(\\):|emit\\s*\\("
weight: 0.30
description: "Notify/emit method"
secondary_signals:
- pattern: "private\\s+observers:\\s*\\w+\\[\\]"
weight: 0.20
description: "Collection of observers"
- pattern: "observers\\.forEach\\("
weight: 0.15
description: "Iterates over observers to notify"
typescript_specific:
- pattern: "Subject<"
description: "RxJS Subject (common in Angular/React)"
confidence_threshold: 0.70
minimum_signals: 2
state:
naming_conventions:
- "*State.ts"
- "*Context.ts"
primary_signals:
- pattern: "interface\\s+\\w+State"
weight: 0.30
description: "State interface"
- pattern: "private\\s+state:\\s*\\w+State"
weight: 0.30
description: "Context holds current state"
- pattern: "setState\\s*\\([^)]*\\):|changeState\\s*\\([^)]*\\):"
weight: 0.30
description: "Method to change state"
secondary_signals:
- pattern: "this\\.state\\.handle\\("
weight: 0.15
description: "Delegates to state"
- pattern: "class\\s+\\w+State\\s+implements\\s+\\w+State"
weight: 0.15
description: "Concrete state classes"
confidence_threshold: 0.70
minimum_signals: 2
strategy:
naming_conventions:
- "*Strategy.ts"
- "*Policy.ts"
- "*Algorithm.ts"
primary_signals:
- pattern: "interface\\s+\\w+Strategy"
weight: 0.35
description: "Strategy interface"
- pattern: "private\\s+strategy:\\s*\\w+Strategy"
weight: 0.30
description: "Context holds strategy"
- pattern: "setStrategy\\s*\\([^)]*\\):"
weight: 0.25
description: "Method to set strategy"
secondary_signals:
- pattern: "this\\.strategy\\.execute\\("
weight: 0.15
description: "Delegates to strategy"
- pattern: "class\\s+\\w+Strategy\\s+implements\\s+\\w+Strategy"
weight: 0.15
description: "Concrete strategies"
confidence_threshold: 0.70
minimum_signals: 2
template-method:
naming_conventions:
- "*Template.ts"
- "*Abstract*.ts"
primary_signals:
- pattern: "abstract\\s+class"
weight: 0.30
description: "Abstract class with template"
- pattern: "abstract\\s+\\w+\\s*\\(\\):"
weight: 0.30
description: "Abstract primitive operations"
- pattern: "protected\\s+\\w+\\s*\\(\\):"
weight: 0.20
description: "Hook methods"
secondary_signals:
- pattern: "this\\.\\w+\\(\\);[^}]*this\\.\\w+\\(\\);"
weight: 0.15
description: "Template calls primitive operations"
- pattern: "final\\s+|\\btemplate\\b"
weight: 0.10
description: "Template method should be final (not overridden)"
confidence_threshold: 0.65
minimum_signals: 2
visitor:
naming_conventions:
- "*Visitor.ts"
primary_signals:
- pattern: "interface\\s+\\w+Visitor\\s*\\{[^}]*visit\\w+"
weight: 0.35
description: "Visitor interface with visit methods"
- pattern: "visit\\w+\\s*\\([^)]*:\\s*\\w+\\)"
weight: 0.30
description: "Visit methods for each element type"
- pattern: "accept\\s*\\([^)]*visitor[^)]*\\)"
weight: 0.30
description: "Elements accept visitor"
secondary_signals:
- pattern: "visitor\\.visit\\w+\\(this\\)"
weight: 0.15
description: "Double dispatch pattern"
confidence_threshold: 0.70
minimum_signals: 2
interpreter:
naming_conventions:
- "*Interpreter.ts"
- "*Expression.ts"
- "*Parser.ts"
primary_signals:
- pattern: "interface\\s+\\w+Expression"
weight: 0.30
description: "Expression interface"
- pattern: "interpret\\s*\\([^)]*context[^)]*\\)"
weight: 0.35
description: "Interpret method with context"
- pattern: "abstract\\s+class\\s+\\w+Expression"
weight: 0.25
description: "Abstract expression"
secondary_signals:
- pattern: "class\\s+Terminal\\w+|class\\s+NonTerminal\\w+"
weight: 0.15
description: "Terminal and non-terminal expressions"
- pattern: "parse\\s*\\("
weight: 0.10
description: "Parser for grammar"
confidence_threshold: 0.60
minimum_signals: 2
# Confidence Calculation
confidence_calculation:
formula: "sum(matched_signal_weights) / sum(all_possible_weights)"
adjustments:
- "If pattern name matches naming convention: +0.15"
- "If stack has native equivalent and not used: -0.20"
- "If anti-pattern detected: -0.30"
- "If typescript-specific signals present: +0.10"
# Output Format for Detection Results
detection_output:
file: "path/to/file.ts"
pattern: "singleton"
lines: "5-28"
confidence: 0.85
matched_signals:
- signal: "private constructor"
weight: 0.4
- signal: "static getInstance"
weight: 0.35
stack_context:
native_alternative: "Context API"
recommendation: "Consider using React Context for better testability"