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

130 lines 4.19 kB
"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