@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
130 lines • 4.19 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ImportValidator = void 0;
const paths_1 = require("../constants/paths");
/**
* Validates imports for aggregate boundary violations
*
* Checks if imports cross aggregate boundaries inappropriately
* and ensures proper encapsulation in DDD architecture.
*/
class ImportValidator {
folderRegistry;
pathAnalyzer;
constructor(folderRegistry, pathAnalyzer) {
this.folderRegistry = folderRegistry;
this.pathAnalyzer = pathAnalyzer;
}
/**
* Checks if an import violates aggregate boundaries
*/
isViolation(importPath, currentAggregate) {
const normalizedPath = this.normalizeImportPath(importPath);
if (!this.isValidImportPath(normalizedPath)) {
return false;
}
if (this.isInternalBoundedContextImport(normalizedPath)) {
return false;
}
const targetAggregate = this.pathAnalyzer.extractAggregateFromImport(normalizedPath);
if (!targetAggregate || targetAggregate === currentAggregate) {
return false;
}
if (this.isAllowedImport(normalizedPath)) {
return false;
}
return this.seemsLikeEntityImport(normalizedPath);
}
/**
* Extracts all import paths from a line of code
*/
extractImports(line) {
const imports = [];
this.extractEsImports(line, imports);
this.extractRequireImports(line, imports);
return imports;
}
/**
* Normalizes an import path for consistent processing
*/
normalizeImportPath(importPath) {
return importPath.replace(paths_1.IMPORT_PATTERNS.QUOTE, "").toLowerCase();
}
/**
* Checks if import path is valid for analysis
*/
isValidImportPath(normalizedPath) {
if (!normalizedPath.includes("/")) {
return false;
}
if (!normalizedPath.startsWith(".") && !normalizedPath.startsWith("/")) {
return false;
}
return true;
}
/**
* Checks if import is internal to the same bounded context
*/
isInternalBoundedContextImport(normalizedPath) {
const parts = normalizedPath.split("/");
const dotDotCount = parts.filter((p) => p === "..").length;
if (dotDotCount === 1) {
const nonDotParts = parts.filter((p) => p !== ".." && p !== ".");
if (nonDotParts.length >= 1) {
const firstFolder = nonDotParts[0];
if (this.folderRegistry.isEntityFolder(firstFolder)) {
return true;
}
}
}
return false;
}
/**
* Checks if import is from an allowed folder
*/
isAllowedImport(normalizedPath) {
for (const folderName of this.folderRegistry.allowedFolders) {
if (normalizedPath.includes(`/${folderName}/`)) {
return true;
}
}
return false;
}
/**
* Checks if import seems to be an entity
*/
seemsLikeEntityImport(normalizedPath) {
const pathParts = normalizedPath.split("/");
const lastPart = pathParts[pathParts.length - 1];
if (!lastPart) {
return false;
}
const filename = lastPart.replace(/\.(ts|js)$/, "");
if (filename.length > 0 && /^[a-z][a-z]/.exec(filename)) {
return true;
}
return false;
}
/**
* Extracts ES6 imports from a line
*/
extractEsImports(line, imports) {
let match = paths_1.IMPORT_PATTERNS.ES_IMPORT.exec(line);
while (match) {
imports.push(match[1]);
match = paths_1.IMPORT_PATTERNS.ES_IMPORT.exec(line);
}
}
/**
* Extracts CommonJS requires from a line
*/
extractRequireImports(line, imports) {
let match = paths_1.IMPORT_PATTERNS.REQUIRE.exec(line);
while (match) {
imports.push(match[1]);
match = paths_1.IMPORT_PATTERNS.REQUIRE.exec(line);
}
}
}
exports.ImportValidator = ImportValidator;
//# sourceMappingURL=ImportValidator.js.map