UNPKG

@samiyev/guardian

Version:

Research-backed code quality guardian for AI-assisted development. Detects hardcodes, secrets, circular deps, framework leaks, entity exposure, and 9 architecture violations. Enforces Clean Architecture/DDD principles. Works with GitHub Copilot, Cursor, W

133 lines (127 loc) 4.73 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DependencyViolation = void 0; const ValueObject_1 = require("./ValueObject"); const layers_1 = require("../../shared/constants/layers"); const Messages_1 = require("../constants/Messages"); /** * Represents a dependency direction violation in the codebase * * Dependency direction violations occur when a layer imports from a layer * that it should not depend on according to Clean Architecture principles: * - Domain → should not import from Application or Infrastructure * - Application → should not import from Infrastructure * - Infrastructure → can import from Application and Domain (allowed) * - Shared → can be imported by all layers (allowed) * * @example * ```typescript * // Bad: Domain importing from Application * const violation = DependencyViolation.create( * 'domain', * 'application', * '../../application/dtos/UserDto', * 'src/domain/entities/User.ts', * 5 * ) * * console.log(violation.getMessage()) * // "Domain layer should not import from Application layer" * ``` */ class DependencyViolation extends ValueObject_1.ValueObject { constructor(props) { super(props); } static create(fromLayer, toLayer, importPath, filePath, line) { return new DependencyViolation({ fromLayer, toLayer, importPath, filePath, line, }); } get fromLayer() { return this.props.fromLayer; } get toLayer() { return this.props.toLayer; } get importPath() { return this.props.importPath; } get filePath() { return this.props.filePath; } get line() { return this.props.line; } getMessage() { return `${this.capitalizeFirst(this.props.fromLayer)} layer should not import from ${this.capitalizeFirst(this.props.toLayer)} layer`; } getSuggestion() { const suggestions = []; if (this.props.fromLayer === layers_1.LAYER_DOMAIN) { suggestions.push(Messages_1.DEPENDENCY_VIOLATION_MESSAGES.DOMAIN_INDEPENDENCE, Messages_1.DEPENDENCY_VIOLATION_MESSAGES.DOMAIN_MOVE_TO_DOMAIN, Messages_1.DEPENDENCY_VIOLATION_MESSAGES.DOMAIN_USE_DI); } else if (this.props.fromLayer === layers_1.LAYER_APPLICATION) { suggestions.push(Messages_1.DEPENDENCY_VIOLATION_MESSAGES.APPLICATION_NO_INFRA, Messages_1.DEPENDENCY_VIOLATION_MESSAGES.APPLICATION_DEFINE_PORT, Messages_1.DEPENDENCY_VIOLATION_MESSAGES.APPLICATION_IMPLEMENT_ADAPTER, Messages_1.DEPENDENCY_VIOLATION_MESSAGES.APPLICATION_USE_DI); } return suggestions.join("\n"); } getExampleFix() { if (this.props.fromLayer === layers_1.LAYER_DOMAIN && this.props.toLayer === layers_1.LAYER_INFRASTRUCTURE) { return ` // ❌ Bad: Domain depends on Infrastructure (PrismaClient) // domain/services/UserService.ts class UserService { constructor(private prisma: PrismaClient) {} } // ✅ Good: Domain defines interface, Infrastructure implements // domain/repositories/IUserRepository.ts interface IUserRepository { findById(id: UserId): Promise<User | null> save(user: User): Promise<void> } // domain/services/UserService.ts class UserService { constructor(private userRepo: IUserRepository) {} } // infrastructure/repositories/PrismaUserRepository.ts class PrismaUserRepository implements IUserRepository { constructor(private prisma: PrismaClient) {} async findById(id: UserId): Promise<User | null> { } async save(user: User): Promise<void> { } }`; } if (this.props.fromLayer === layers_1.LAYER_APPLICATION && this.props.toLayer === layers_1.LAYER_INFRASTRUCTURE) { return ` // ❌ Bad: Application depends on Infrastructure (SmtpEmailService) // application/use-cases/SendEmail.ts class SendWelcomeEmail { constructor(private emailService: SmtpEmailService) {} } // ✅ Good: Application defines Port, Infrastructure implements Adapter // application/ports/IEmailService.ts interface IEmailService { send(to: string, subject: string, body: string): Promise<void> } // application/use-cases/SendEmail.ts class SendWelcomeEmail { constructor(private emailService: IEmailService) {} } // infrastructure/adapters/SmtpEmailService.ts class SmtpEmailService implements IEmailService { async send(to: string, subject: string, body: string): Promise<void> { } }`; } return ""; } capitalizeFirst(str) { return str.charAt(0).toUpperCase() + str.slice(1); } } exports.DependencyViolation = DependencyViolation; //# sourceMappingURL=DependencyViolation.js.map