arela
Version:
AI-powered CTO with multi-agent orchestration, code summarization, visual testing (web + mobile) for blazing fast development.
161 lines • 4.97 kB
JavaScript
/**
* Directory pattern detection for horizontal vs vertical architecture
*/
// Patterns that indicate horizontal (layered) architecture
const HORIZONTAL_PATTERNS = [
/^components?$/i,
/^containers?$/i,
/^pages?$/i,
/^services?$/i,
/^controllers?$/i,
/^models?$/i,
/^views?$/i,
/^routes?$/i,
/^middleware?$/i,
/^utils?$/i,
/^helpers?$/i,
/^hooks?$/i,
/^store$/i,
/^reducers?$/i,
/^actions?$/i,
/^types?$/i,
/^interfaces?$/i,
/^schemas?$/i,
/^constants?$/i,
/^config$/i,
/^lib$/i,
];
// Patterns that indicate vertical (feature/slice) architecture
const VERTICAL_PATTERNS = [
/^features?$/i,
/^modules?$/i,
/^slices?$/i,
/^domains?$/i,
/^sections?$/i,
/^products?$/i,
];
/**
* Analyze directory structure and classify as layer or feature directory
*/
export function analyzeDirectoryStructure(files) {
const dirStats = new Map();
// Scan all files and extract directory information
for (const file of files) {
const parts = file.path.split("/").filter(p => p && p !== ".");
// Analyze each directory level
for (let i = 1; i <= parts.length; i++) {
const dirPath = parts.slice(0, i).join("/");
if (!dirStats.has(dirPath)) {
const fileName = parts[i - 1];
const isLayerDir = HORIZONTAL_PATTERNS.some(p => p.test(fileName));
const isFeatureDir = VERTICAL_PATTERNS.some(p => p.test(fileName));
dirStats.set(dirPath, {
path: dirPath,
depth: i,
fileName,
isLayerDir,
isFeatureDir,
fileCount: 0,
});
}
const stat = dirStats.get(dirPath);
stat.fileCount++;
}
}
const result = new Map();
for (const [dirPath, stat] of dirStats) {
// Only include top-level directories (depth <= 2 for meaningful analysis)
if (stat.depth > 2)
continue;
let type = "other";
if (stat.isLayerDir) {
type = "layer";
}
else if (stat.isFeatureDir) {
type = "feature";
}
else if (dirPath.includes("/")) {
// If it's a subdirectory of a feature, it's a module
const parent = dirPath.split("/")[0];
const parentIsFeature = VERTICAL_PATTERNS.some(p => p.test(parent));
if (parentIsFeature) {
type = "module";
}
}
result.set(dirPath, {
path: dirPath,
type,
fileCount: stat.fileCount,
internalImports: 0, // Will be calculated during coupling analysis
externalImports: 0,
importedBy: 0,
});
}
return result;
}
/**
* Determine if architecture is primarily horizontal or vertical
*/
export function classifyArchitecture(directories) {
let layerDirs = 0;
let featureDirs = 0;
let moduleDirs = 0;
for (const dir of directories.values()) {
if (dir.type === "layer")
layerDirs++;
else if (dir.type === "feature")
featureDirs++;
else if (dir.type === "module")
moduleDirs++;
}
const total = layerDirs + featureDirs + moduleDirs;
if (total === 0) {
return { type: "hybrid", score: 50 };
}
const layerPercentage = (layerDirs / total) * 100;
const featurePercentage = (featureDirs / total) * 100;
// Determine architecture type
if (layerPercentage > 60) {
return { type: "horizontal", score: Math.round(layerPercentage) };
}
else if (featurePercentage > 60) {
return { type: "vertical", score: Math.round(featurePercentage) };
}
else {
return { type: "hybrid", score: 50 };
}
}
/**
* Extract top-level directories from file paths
*/
export function getTopLevelDirs(filePaths) {
const dirs = new Set();
for (const filePath of filePaths) {
// Find first directory after any common prefixes
const normalizedPath = filePath.replace(/\\/g, "/");
const parts = normalizedPath.split("/").filter(p => p && !p.startsWith("."));
if (parts.length > 0) {
// Skip common root directories
if (parts[0] !== "src" && parts[0] !== "lib" && parts[0] !== "app") {
dirs.add(parts[0]);
}
else if (parts.length > 1) {
dirs.add(parts[1]);
}
}
}
return dirs;
}
/**
* Detect if a directory follows a layer pattern
*/
export function isLayerDirectory(dirName) {
return HORIZONTAL_PATTERNS.some(p => p.test(dirName));
}
/**
* Detect if a directory follows a feature pattern
*/
export function isFeatureDirectory(dirName) {
return VERTICAL_PATTERNS.some(p => p.test(dirName));
}
//# sourceMappingURL=patterns.js.map