mirror of
https://github.com/samiyev/puaros.git
synced 2025-12-27 23:06:54 +05:00
fix: improve repository method name suggestions and patterns
- Add smart context-aware suggestions for repository method names - queryUsers() → search, findBy[Property] - selectById() → findBy[Property], get[Entity] - insertUser() → create, add[Entity], store[Entity] - And more intelligent pattern matching - Expand domain method patterns support - find*() methods (findNodes, findNodeById, findSimilar) - saveAll() batch operations - deleteBy*() methods (deleteByPath, deleteById) - deleteAll() clear operations - add*() methods (addRelationship, addItem) - initializeCollection() initialization - Remove findAll from ORM blacklist (valid domain method) - Reduce complexity in suggestDomainMethodName (22 → 9) Version 0.6.4
This commit is contained in:
@@ -5,6 +5,51 @@ All notable changes to @samiyev/guardian will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.6.4] - 2025-11-24
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
**🎯 Smart Context-Aware Suggestions for Repository Method Names**
|
||||||
|
|
||||||
|
Guardian now provides intelligent, context-specific suggestions when it detects non-domain method names in repositories.
|
||||||
|
|
||||||
|
- ✅ **Intelligent method name analysis:**
|
||||||
|
- `queryUsers()` → Suggests: `search`, `findBy[Property]`
|
||||||
|
- `selectById()` → Suggests: `findBy[Property]`, `get[Entity]`
|
||||||
|
- `insertUser()` → Suggests: `create`, `add[Entity]`, `store[Entity]`
|
||||||
|
- `updateRecord()` → Suggests: `update`, `modify[Entity]`
|
||||||
|
- `upsertUser()` → Suggests: `save`, `store[Entity]`
|
||||||
|
- `removeUser()` → Suggests: `delete`, `removeBy[Property]`
|
||||||
|
- `fetchUserData()` → Suggests: `findBy[Property]`, `get[Entity]`
|
||||||
|
- And more technical patterns detected automatically!
|
||||||
|
|
||||||
|
- 🎯 **Impact:**
|
||||||
|
- Developers get actionable, relevant suggestions instead of generic examples
|
||||||
|
- Faster refactoring with specific naming alternatives
|
||||||
|
- Better learning experience for developers new to DDD
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- ✅ **Expanded domain method patterns support:**
|
||||||
|
- `find*()` methods - e.g., `findNodes()`, `findNodeById()`, `findSimilar()`
|
||||||
|
- `saveAll()` - batch save operations
|
||||||
|
- `deleteBy*()` methods - e.g., `deleteByPath()`, `deleteById()`
|
||||||
|
- `deleteAll()` - clear all entities
|
||||||
|
- `add*()` methods - e.g., `addRelationship()`, `addItem()`
|
||||||
|
- `initializeCollection()` - collection initialization
|
||||||
|
|
||||||
|
- 🐛 **Removed `findAll` from technical methods blacklist:**
|
||||||
|
- `findAll()` is now correctly recognized as a standard domain method
|
||||||
|
- Reduced false positives for repositories using this common pattern
|
||||||
|
|
||||||
|
### Technical
|
||||||
|
|
||||||
|
- Added `suggestDomainMethodName()` method in `RepositoryPatternDetector.ts` with keyword-based suggestion mapping
|
||||||
|
- Updated `getNonDomainMethodSuggestion()` in `RepositoryViolation.ts` to extract and use smart suggestions
|
||||||
|
- Refactored suggestion logic to reduce cyclomatic complexity (22 → 9)
|
||||||
|
- Enhanced `domainMethodPatterns` with 9 additional patterns
|
||||||
|
- All 333 tests passing
|
||||||
|
|
||||||
## [0.6.3] - 2025-11-24
|
## [0.6.3] - 2025-11-24
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@samiyev/guardian",
|
"name": "@samiyev/guardian",
|
||||||
"version": "0.6.3",
|
"version": "0.6.4",
|
||||||
"description": "Research-backed code quality guardian for AI-assisted development. Detects hardcodes, circular deps, framework leaks, entity exposure, and 8 architecture violations. Enforces Clean Architecture/DDD principles. Works with GitHub Copilot, Cursor, Windsurf, Claude, ChatGPT, Cline, and any AI coding tool.",
|
"description": "Research-backed code quality guardian for AI-assisted development. Detects hardcodes, circular deps, framework leaks, entity exposure, and 8 architecture violations. Enforces Clean Architecture/DDD principles. Works with GitHub Copilot, Cursor, Windsurf, Claude, ChatGPT, Cline, and any AI coding tool.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"puaros",
|
"puaros",
|
||||||
|
|||||||
@@ -177,6 +177,9 @@ export class RepositoryViolation extends ValueObject<RepositoryViolationProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getNonDomainMethodSuggestion(): string {
|
private getNonDomainMethodSuggestion(): string {
|
||||||
|
const detailsMatch = /Consider: (.+)$/.exec(this.props.details)
|
||||||
|
const smartSuggestion = detailsMatch ? detailsMatch[1] : null
|
||||||
|
|
||||||
const technicalToDomain = {
|
const technicalToDomain = {
|
||||||
findOne: REPOSITORY_PATTERN_MESSAGES.SUGGESTION_FINDONE,
|
findOne: REPOSITORY_PATTERN_MESSAGES.SUGGESTION_FINDONE,
|
||||||
findMany: REPOSITORY_PATTERN_MESSAGES.SUGGESTION_FINDMANY,
|
findMany: REPOSITORY_PATTERN_MESSAGES.SUGGESTION_FINDMANY,
|
||||||
@@ -186,8 +189,10 @@ export class RepositoryViolation extends ValueObject<RepositoryViolationProps> {
|
|||||||
query: REPOSITORY_PATTERN_MESSAGES.SUGGESTION_QUERY,
|
query: REPOSITORY_PATTERN_MESSAGES.SUGGESTION_QUERY,
|
||||||
}
|
}
|
||||||
|
|
||||||
const suggestion =
|
const fallbackSuggestion =
|
||||||
technicalToDomain[this.props.methodName as keyof typeof technicalToDomain]
|
technicalToDomain[this.props.methodName as keyof typeof technicalToDomain]
|
||||||
|
const finalSuggestion =
|
||||||
|
smartSuggestion || fallbackSuggestion || "findById() or findByEmail()"
|
||||||
|
|
||||||
return [
|
return [
|
||||||
REPOSITORY_PATTERN_MESSAGES.STEP_RENAME_METHOD,
|
REPOSITORY_PATTERN_MESSAGES.STEP_RENAME_METHOD,
|
||||||
@@ -196,7 +201,7 @@ export class RepositoryViolation extends ValueObject<RepositoryViolationProps> {
|
|||||||
"",
|
"",
|
||||||
REPOSITORY_PATTERN_MESSAGES.EXAMPLE_PREFIX,
|
REPOSITORY_PATTERN_MESSAGES.EXAMPLE_PREFIX,
|
||||||
`❌ Bad: ${this.props.methodName || "findOne"}()`,
|
`❌ Bad: ${this.props.methodName || "findOne"}()`,
|
||||||
`✅ Good: ${suggestion || "findById() or findByEmail()"}`,
|
`✅ Good: ${finalSuggestion}`,
|
||||||
].join("\n")
|
].join("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,13 +69,21 @@ export class RepositoryPatternDetector implements IRepositoryPatternDetector {
|
|||||||
private readonly domainMethodPatterns = [
|
private readonly domainMethodPatterns = [
|
||||||
/^findBy[A-Z]/,
|
/^findBy[A-Z]/,
|
||||||
/^findAll/,
|
/^findAll/,
|
||||||
|
/^find[A-Z]/,
|
||||||
/^save$/,
|
/^save$/,
|
||||||
|
/^saveAll$/,
|
||||||
/^create$/,
|
/^create$/,
|
||||||
/^update$/,
|
/^update$/,
|
||||||
/^delete$/,
|
/^delete$/,
|
||||||
|
/^deleteBy[A-Z]/,
|
||||||
|
/^deleteAll$/,
|
||||||
/^remove$/,
|
/^remove$/,
|
||||||
|
/^removeBy[A-Z]/,
|
||||||
|
/^removeAll$/,
|
||||||
/^add$/,
|
/^add$/,
|
||||||
|
/^add[A-Z]/,
|
||||||
/^get[A-Z]/,
|
/^get[A-Z]/,
|
||||||
|
/^getAll/,
|
||||||
/^search/,
|
/^search/,
|
||||||
/^list/,
|
/^list/,
|
||||||
/^has[A-Z]/,
|
/^has[A-Z]/,
|
||||||
@@ -86,6 +94,7 @@ export class RepositoryPatternDetector implements IRepositoryPatternDetector {
|
|||||||
/^clearAll$/,
|
/^clearAll$/,
|
||||||
/^store[A-Z]/,
|
/^store[A-Z]/,
|
||||||
/^initialize$/,
|
/^initialize$/,
|
||||||
|
/^initializeCollection$/,
|
||||||
/^close$/,
|
/^close$/,
|
||||||
/^connect$/,
|
/^connect$/,
|
||||||
/^disconnect$/,
|
/^disconnect$/,
|
||||||
@@ -237,6 +246,42 @@ export class RepositoryPatternDetector implements IRepositoryPatternDetector {
|
|||||||
return violations
|
return violations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suggests better domain method names based on the original method name
|
||||||
|
*/
|
||||||
|
private suggestDomainMethodName(methodName: string): string {
|
||||||
|
const lowerName = methodName.toLowerCase()
|
||||||
|
const suggestions: string[] = []
|
||||||
|
|
||||||
|
const suggestionMap: Record<string, string[]> = {
|
||||||
|
query: ["search", "findBy[Property]"],
|
||||||
|
select: ["findBy[Property]", "get[Entity]"],
|
||||||
|
insert: ["create", "add[Entity]", "store[Entity]"],
|
||||||
|
update: ["update", "modify[Entity]"],
|
||||||
|
upsert: ["save", "store[Entity]"],
|
||||||
|
remove: ["delete", "removeBy[Property]"],
|
||||||
|
fetch: ["findBy[Property]", "get[Entity]"],
|
||||||
|
retrieve: ["findBy[Property]", "get[Entity]"],
|
||||||
|
load: ["findBy[Property]", "get[Entity]"],
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [keyword, keywords] of Object.entries(suggestionMap)) {
|
||||||
|
if (lowerName.includes(keyword)) {
|
||||||
|
suggestions.push(...keywords)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowerName.includes("get") && lowerName.includes("all")) {
|
||||||
|
suggestions.push("findAll", "listAll")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suggestions.length === 0) {
|
||||||
|
return "Use domain-specific names like: findBy[Property], save, create, delete, update, add[Entity]"
|
||||||
|
}
|
||||||
|
|
||||||
|
return `Consider: ${suggestions.slice(0, 3).join(", ")}`
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detects non-domain method names in repository interfaces
|
* Detects non-domain method names in repository interfaces
|
||||||
*/
|
*/
|
||||||
@@ -258,13 +303,14 @@ export class RepositoryPatternDetector implements IRepositoryPatternDetector {
|
|||||||
const methodName = methodMatch[1]
|
const methodName = methodMatch[1]
|
||||||
|
|
||||||
if (!this.isDomainMethodName(methodName) && !line.trim().startsWith("//")) {
|
if (!this.isDomainMethodName(methodName) && !line.trim().startsWith("//")) {
|
||||||
|
const suggestion = this.suggestDomainMethodName(methodName)
|
||||||
violations.push(
|
violations.push(
|
||||||
RepositoryViolation.create(
|
RepositoryViolation.create(
|
||||||
REPOSITORY_VIOLATION_TYPES.NON_DOMAIN_METHOD_NAME,
|
REPOSITORY_VIOLATION_TYPES.NON_DOMAIN_METHOD_NAME,
|
||||||
filePath,
|
filePath,
|
||||||
layer || LAYERS.DOMAIN,
|
layer || LAYERS.DOMAIN,
|
||||||
lineNumber,
|
lineNumber,
|
||||||
`Method '${methodName}' uses technical name instead of domain language`,
|
`Method '${methodName}' uses technical name instead of domain language. ${suggestion}`,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
methodName,
|
methodName,
|
||||||
|
|||||||
Reference in New Issue
Block a user