@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
JavaScript
"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