"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateArchitectureMap = generateArchitectureMap;
const path = __importStar(require("node:path"));
const node_fs_1 = require("node:fs");
const architectureInit_1 = require("./architectureInit");
const dependencyValidation_1 = require("./dependencyValidation");
const moduleDiscovery_1 = require("./moduleDiscovery");
const moduleScope_1 = require("./moduleScope");
const moduleDetection_1 = require("./smartInit/moduleDetection");
function normalizePath(value) {
    return value.replace(/\\/g, '/');
}
async function pathExists(targetPath) {
    try {
        await node_fs_1.promises.access(targetPath);
        return true;
    }
    catch {
        return false;
    }
}
async function readTextFileIfExists(filePath) {
    try {
        return await node_fs_1.promises.readFile(filePath, { encoding: 'utf8' });
    }
    catch {
        return undefined;
    }
}
const sourceFileExtensions = new Set([
    '.ts',
    '.tsx',
    '.js',
    '.jsx',
    '.mjs',
    '.cjs',
    '.mts',
    '.cts',
    '.py',
    '.go',
    '.java',
    '.kt',
    '.kts',
    '.cs',
    '.php',
    '.rb',
    '.vue',
    '.svelte',
]);
const configuredRootIgnoredModuleNames = new Set([
    'components',
    'hooks',
    'utils',
    'util',
    'lib',
    'common',
    'shared',
    'shared-ui',
    'types',
    'constants',
    'config',
    'test',
    'tests',
    '__tests__',
    'fixtures',
    'mocks',
    '__mocks__',
    'generated',
    'dist',
    'build',
    'out',
    'node_modules',
]);
function sortUnique(values) {
    return [...new Set(values)].sort((left, right) => left.localeCompare(right));
}
function toSafeContractModuleFileStem(moduleName) {
    return normalizePath(moduleName)
        .split('/')
        .map((segment) => segment.trim())
        .filter((segment) => segment.length > 0)
        .join('.');
}
function getModuleRegistry(contract) {
    const modules = contract?.modules;
    if (!modules || typeof modules !== 'object' || Array.isArray(modules)) {
        return {};
    }
    return modules;
}
async function readArchitectureConfigRecord(workspaceRoot) {
    const content = await readTextFileIfExists(path.join(workspaceRoot, '.archpilot', 'architecture.json'));
    if (!content) {
        return undefined;
    }
    try {
        const parsed = JSON.parse(content);
        return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
            ? parsed
            : undefined;
    }
    catch {
        return undefined;
    }
}
function hasExplicitModuleRootConfig(config) {
    if (!config) {
        return false;
    }
    if (typeof config.modulesRootRelativePath === 'string' ||
        typeof config.modulesRoot === 'string') {
        return true;
    }
    const structure = config.structure && typeof config.structure === 'object' && !Array.isArray(config.structure)
        ? config.structure
        : undefined;
    return Boolean(typeof structure?.modulesRootRelativePath === 'string' ||
        typeof structure?.modulesRoot === 'string');
}
function hasConfiguredModuleRegistryEntries(config) {
    if (!config || !config.modules || typeof config.modules !== 'object' || Array.isArray(config.modules)) {
        return false;
    }
    return Object.keys(config.modules).length > 0;
}
function hasExplicitModuleRegistry(config) {
    return Boolean(config &&
        Object.prototype.hasOwnProperty.call(config, 'modules') &&
        config.modules &&
        typeof config.modules === 'object' &&
        !Array.isArray(config.modules));
}
function normalizePublicEntrypointList(entries) {
    return sortUnique(entries.map((entry) => normalizePath(entry.trim())).filter((entry) => entry.length > 0));
}
function hasConfiguredPublicEntrypoint(registryEntry) {
    return (Array.isArray(registryEntry?.publicEntrypoints) &&
        registryEntry.publicEntrypoints.some((entry) => typeof entry === 'string' && entry.trim().length > 0));
}
async function readPackageJsonIfExists(moduleDirectoryPath) {
    const content = await readTextFileIfExists(path.join(moduleDirectoryPath, 'package.json'));
    if (!content) {
        return undefined;
    }
    try {
        const parsed = JSON.parse(content);
        return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
            ? parsed
            : undefined;
    }
    catch {
        return undefined;
    }
}
async function collectModuleSourceEvidence(directoryPath) {
    let entries;
    try {
        entries = await node_fs_1.promises.readdir(directoryPath, { withFileTypes: true });
    }
    catch {
        return { sourceFileCount: 0, hasReadme: false, hasEntrypointFile: false };
    }
    let sourceFileCount = 0;
    let hasReadme = false;
    let hasEntrypointFile = false;
    for (const entry of entries) {
        const fullPath = path.join(directoryPath, entry.name);
        if (entry.isDirectory()) {
            if (['node_modules', 'dist', 'out', 'build', 'coverage', '.git'].includes(entry.name)) {
                continue;
            }
            const nested = await collectModuleSourceEvidence(fullPath);
            sourceFileCount += nested.sourceFileCount;
            hasReadme ||= nested.hasReadme;
            hasEntrypointFile ||= nested.hasEntrypointFile;
            continue;
        }
        if (!entry.isFile()) {
            continue;
        }
        const lowerName = entry.name.toLowerCase();
        if (lowerName === 'readme.md' || lowerName === 'readme.mdx') {
            hasReadme = true;
        }
        if (/^(index|main|app|extension|cli)\.[cm]?[jt]sx?$/iu.test(entry.name)) {
            hasEntrypointFile = true;
        }
        if (sourceFileExtensions.has(path.extname(entry.name).toLowerCase())) {
            sourceFileCount += 1;
        }
    }
    return { sourceFileCount, hasReadme, hasEntrypointFile };
}
function hasKnownBoundaryRole(moduleName) {
    const normalized = moduleName.toLowerCase();
    const compact = normalized.replace(/[-_/]/gu, '');
    const segments = normalized.split(/[/-]/u);
    return ['adr', 'ci', 'compliance', 'config', 'governance', 'policy', 'validation', 'smartinit'].some((role) => compact.includes(role) || segments.includes(role));
}
async function hasPackageEntrypoint(moduleDirectoryPath) {
    const packageJson = await readPackageJsonIfExists(moduleDirectoryPath);
    if (!packageJson) {
        return false;
    }
    return ['main', 'module', 'browser', 'types', 'bin', 'exports'].some((field) => packageJson[field] !== undefined);
}
async function hasIntentionalIndependentEvidence(args) {
    const moduleDirectoryPath = path.join(args.workspaceRoot, ...args.moduleEntry.sourcePath.split('/'));
    const evidence = await collectModuleSourceEvidence(moduleDirectoryPath);
    return (args.moduleEntry.contractExists ||
        args.moduleEntry.hasPublicEntrypoint === true ||
        evidence.hasReadme ||
        evidence.hasEntrypointFile ||
        (await hasPackageEntrypoint(moduleDirectoryPath)) ||
        args.hasChildren ||
        (args.isLeafChild && evidence.sourceFileCount > 0) ||
        hasKnownBoundaryRole(args.moduleEntry.moduleName) ||
        evidence.sourceFileCount >= 2);
}
async function loadModuleContractPublicEntrypoints(workspaceRoot, contractPath) {
    const fullContractPath = path.join(workspaceRoot, ...contractPath.split('/'));
    const content = await readTextFileIfExists(fullContractPath);
    if (!content) {
        return undefined;
    }
    try {
        const parsed = JSON.parse(content);
        if (!Array.isArray(parsed.publicEntrypoints)) {
            return undefined;
        }
        const validEntries = parsed.publicEntrypoints.filter((entry) => typeof entry === 'string');
        if (validEntries.length !== parsed.publicEntrypoints.length) {
            return undefined;
        }
        return normalizePublicEntrypointList(validEntries);
    }
    catch {
        return undefined;
    }
}
function parseCycleString(cycle) {
    const nodes = cycle.split('->').filter((entry) => entry.length > 0);
    if (nodes.length >= 2 && nodes[0] === nodes[nodes.length - 1]) {
        return nodes.slice(0, -1);
    }
    return nodes;
}
async function discoverModulesFromArchitectureContract(workspaceRoot, contract, modulesRoot) {
    const moduleRegistry = getModuleRegistry(contract);
    const normalizedModulesRoot = normalizePath(modulesRoot);
    const contractsRoot = normalizePath(contract.structure.contractsRoot ?? '.archpilot/contracts');
    const discovered = [];
    const toContractPath = (moduleName, registryEntry) => normalizePath(typeof registryEntry?.contract === 'string'
        ? registryEntry.contract
        : `${contractsRoot}/${toSafeContractModuleFileStem(moduleName)}.contract.json`);
    const resolveMissingPublicEntrypointAlignment = async (registryEntry, contractPath) => {
        if (!Array.isArray(registryEntry?.publicEntrypoints)) {
            return undefined;
        }
        const registryPublicEntrypoints = normalizePublicEntrypointList(registryEntry.publicEntrypoints.filter((entry) => typeof entry === 'string'));
        const contractPublicEntrypoints = await loadModuleContractPublicEntrypoints(workspaceRoot, contractPath);
        if (!contractPublicEntrypoints) {
            return true;
        }
        return (registryPublicEntrypoints.length !== contractPublicEntrypoints.length ||
            registryPublicEntrypoints.some((entry, index) => entry !== contractPublicEntrypoints[index]));
    };
    const registryEntries = Object.entries(moduleRegistry).sort(([left], [right]) => left.localeCompare(right));
    for (const [moduleName, registryEntry] of registryEntries) {
        if (!registryEntry.path || typeof registryEntry.path !== 'string') {
            continue;
        }
        const normalizedSourcePath = normalizePath(registryEntry.path);
        const absoluteSourcePath = path.join(workspaceRoot, ...normalizedSourcePath.split('/'));
        let sourcePathExists = false;
        let sourceIsDirectory = false;
        let sourceIsFile = false;
        try {
            const sourceStats = await node_fs_1.promises.stat(absoluteSourcePath);
            sourcePathExists = true;
            sourceIsDirectory = sourceStats.isDirectory();
            sourceIsFile = sourceStats.isFile();
        }
        catch {
            sourcePathExists = false;
        }
        if (!sourceIsDirectory && !sourceIsFile) {
            continue;
        }
        const contractPath = normalizePath(typeof registryEntry.contract === 'string'
            ? registryEntry.contract
            : `${contractsRoot}/${toSafeContractModuleFileStem(moduleName)}.contract.json`);
        const contractExists = await pathExists(path.join(workspaceRoot, ...contractPath.split('/')));
        const missingPublicEntrypointAlignment = await resolveMissingPublicEntrypointAlignment(registryEntry, contractPath);
        discovered.push({
            moduleName,
            sourcePath: normalizedSourcePath,
            discoverySource: 'architecture.json',
            sourcePathExists,
            ...(resolveModuleScopeForPath(workspaceRoot, normalizedSourcePath, contract)
                ? { scope: resolveModuleScopeForPath(workspaceRoot, normalizedSourcePath, contract) }
                : {}),
            contractPath,
            contractExists,
            hasPublicEntrypoint: hasConfiguredPublicEntrypoint(registryEntry),
            ...(missingPublicEntrypointAlignment !== undefined
                ? { missingPublicEntrypointAlignment }
                : {}),
        });
    }
    return discovered.sort((left, right) => left.moduleName.localeCompare(right.moduleName));
}
async function discoverModulesFromFallbackScan(workspaceRoot, modulesRoot = 'src/modules', contractsRoot = '.archpilot/contracts', options) {
    const topLevelWorkspaceModules = async () => {
        const modules = [];
        for (const container of ['packages', 'apps', 'services']) {
            for (const moduleName of await (0, moduleDiscovery_1.listModuleDirectoryNames)(workspaceRoot, container)) {
                if (configuredRootIgnoredModuleNames.has(moduleName.toLowerCase())) {
                    continue;
                }
                modules.push({ moduleId: moduleName, sourcePath: `${container}/${moduleName}` });
            }
        }
        return modules.sort((left, right) => left.moduleId.localeCompare(right.moduleId));
    };
    const hierarchicalModules = options?.topLevelWorkspaceOnly
        ? await topLevelWorkspaceModules()
        : options?.configuredRootOnly
            ? (0, moduleDetection_1.detectModuleCandidatesForRoot)(workspaceRoot, modulesRoot)
                .filter((candidate) => candidate.classification === 'architecture-module' &&
                !configuredRootIgnoredModuleNames.has(candidate.name.toLowerCase()))
                .map((candidate) => ({
                moduleId: candidate.name,
                sourcePath: candidate.path,
            }))
            : await (0, moduleDiscovery_1.discoverHierarchicalModuleRoots)(workspaceRoot, modulesRoot);
    const moduleNames = hierarchicalModules.length > 0 ? [] : await (0, moduleDiscovery_1.listModuleDirectoryNames)(workspaceRoot, modulesRoot);
    const discovered = [];
    for (const moduleRoot of hierarchicalModules) {
        const contractPath = `${contractsRoot}/${toSafeContractModuleFileStem(moduleRoot.moduleId)}.contract.json`;
        discovered.push({
            moduleName: moduleRoot.moduleId,
            sourcePath: moduleRoot.sourcePath,
            discoverySource: 'inferred-scan',
            sourcePathExists: true,
            ...(resolveModuleScopeForPath(workspaceRoot, moduleRoot.sourcePath)
                ? { scope: resolveModuleScopeForPath(workspaceRoot, moduleRoot.sourcePath) }
                : {}),
            contractPath,
            contractExists: await pathExists(path.join(workspaceRoot, ...contractPath.split('/'))),
        });
    }
    for (const moduleName of moduleNames) {
        const sourcePath = `${modulesRoot}/${moduleName}`;
        const contractPath = `${contractsRoot}/${toSafeContractModuleFileStem(moduleName)}.contract.json`;
        discovered.push({
            moduleName,
            sourcePath,
            discoverySource: 'inferred-scan',
            sourcePathExists: true,
            ...(resolveModuleScopeForPath(workspaceRoot, sourcePath)
                ? { scope: resolveModuleScopeForPath(workspaceRoot, sourcePath) }
                : {}),
            contractPath,
            contractExists: await pathExists(path.join(workspaceRoot, ...contractPath.split('/'))),
        });
    }
    return discovered;
}
function getComponentEntries(contract) {
    const components = contract?.components;
    if (!components) {
        return [];
    }
    const rawEntries = Array.isArray(components)
        ? components.map((entry) => {
            const typed = entry;
            return [typed.id, entry];
        })
        : Object.entries(components);
    const entries = [];
    for (const [key, value] of rawEntries) {
        if (!value || typeof value !== 'object' || Array.isArray(value)) {
            continue;
        }
        const typed = value;
        const componentId = typeof typed.id === 'string' && typed.id.trim().length > 0
            ? typed.id.trim()
            : typeof key === 'string' && key.trim().length > 0
                ? key.trim()
                : undefined;
        const sourcePath = typeof typed.path === 'string' && typed.path.trim().length > 0
            ? normalizePath(typed.path.trim())
            : undefined;
        if (!componentId || !sourcePath || sourcePath === '.') {
            continue;
        }
        entries.push({ componentId, sourcePath });
    }
    return entries.sort((left, right) => left.componentId.localeCompare(right.componentId));
}
async function discoverModulesFromComponents(workspaceRoot, contract, contractsRoot = '.archpilot/contracts') {
    const discovered = [];
    for (const component of getComponentEntries(contract)) {
        const absoluteSourcePath = path.join(workspaceRoot, ...component.sourcePath.split('/'));
        let sourcePathExists = false;
        let sourceIsDirectory = false;
        try {
            const sourceStats = await node_fs_1.promises.stat(absoluteSourcePath);
            sourcePathExists = true;
            sourceIsDirectory = sourceStats.isDirectory();
        }
        catch {
            sourcePathExists = false;
        }
        if (!sourceIsDirectory) {
            continue;
        }
        const contractPath = `${contractsRoot}/${toSafeContractModuleFileStem(component.componentId)}.contract.json`;
        discovered.push({
            moduleName: component.componentId,
            sourcePath: component.sourcePath,
            discoverySource: 'inferred-scan',
            sourcePathExists,
            ...(resolveModuleScopeForPath(workspaceRoot, component.sourcePath, contract)
                ? { scope: resolveModuleScopeForPath(workspaceRoot, component.sourcePath, contract) }
                : {}),
            contractPath,
            contractExists: await pathExists(path.join(workspaceRoot, ...contractPath.split('/'))),
        });
    }
    return discovered;
}
function toArchitectureMapEdge(edge) {
    return {
        source: edge.sourceModule,
        target: edge.targetModule,
        importCount: edge.importCount,
        publicImportCount: edge.publicImportCount,
        nonPublicImportCount: edge.nonPublicImportCount,
    };
}
function buildIncomingMap(modules, edges) {
    const incoming = new Map();
    for (const moduleEntry of modules) {
        incoming.set(moduleEntry.moduleName, new Set());
    }
    for (const edge of edges) {
        incoming.get(edge.target)?.add(edge.source);
    }
    return new Map([...incoming.entries()]
        .sort(([left], [right]) => left.localeCompare(right))
        .map(([moduleName, sources]) => [
        moduleName,
        [...sources].sort((left, right) => left.localeCompare(right)),
    ]));
}
function buildOutgoingMap(modules, edges) {
    const outgoing = new Map();
    for (const moduleEntry of modules) {
        outgoing.set(moduleEntry.moduleName, new Set());
    }
    for (const edge of edges) {
        outgoing.get(edge.source)?.add(edge.target);
    }
    return new Map([...outgoing.entries()]
        .sort(([left], [right]) => left.localeCompare(right))
        .map(([moduleName, targets]) => [
        moduleName,
        [...targets].sort((left, right) => left.localeCompare(right)),
    ]));
}
function sortRankedCounts(values) {
    return [...values].sort((left, right) => {
        const countCompare = right.count - left.count;
        if (countCompare !== 0) {
            return countCompare;
        }
        return left.moduleName.localeCompare(right.moduleName);
    });
}
function resolveProjectName(workspaceRoot, contract) {
    const fromContract = contract?.projectName?.trim();
    if (fromContract) {
        return fromContract;
    }
    return path.basename(workspaceRoot);
}
function resolveModuleScopeForPath(workspaceRoot, modulePath, contract) {
    return (0, moduleScope_1.classifyModuleScope)({
        modulePath,
        workspaceRoot,
        projectKinds: contract?.projectKinds,
        stacks: contract?.stacks,
    });
}
async function generateArchitectureMap(workspaceRoot, options) {
    const measure = async (phase, run) => {
        const started = Date.now();
        try {
            return await run();
        }
        finally {
            options?.onTiming?.({ phase, durationMs: Date.now() - started });
        }
    };
    const contract = await measure('architecture-map.contract-load', () => (0, architectureInit_1.loadArchitectureContract)(workspaceRoot));
    const rawArchitectureConfig = await measure('architecture-map.config-read', () => readArchitectureConfigRecord(workspaceRoot));
    const moduleRegistry = getModuleRegistry(contract);
    const hasArchitectureJson = Boolean(contract);
    const contractHasConfiguredModules = Object.keys(moduleRegistry).length > 0 ||
        hasConfiguredModuleRegistryEntries(rawArchitectureConfig);
    const hasComponentEntries = getComponentEntries(contract).length > 0;
    const hasExplicitEmptyModuleRegistry = hasArchitectureJson &&
        !contractHasConfiguredModules &&
        hasExplicitModuleRegistry(rawArchitectureConfig) &&
        !hasComponentEntries;
    const shouldUseConfiguredRootInference = hasArchitectureJson &&
        !contractHasConfiguredModules &&
        !hasExplicitEmptyModuleRegistry &&
        hasExplicitModuleRootConfig(rawArchitectureConfig);
    const shouldUseTopLevelWorkspaceInference = hasArchitectureJson &&
        !contractHasConfiguredModules &&
        !hasExplicitEmptyModuleRegistry &&
        !shouldUseConfiguredRootInference;
    const discoveryMode = hasArchitectureJson
        ? 'architecture-json'
        : 'inferred-src-modules';
    const modulesRoot = normalizePath(await (0, moduleDiscovery_1.resolveConfiguredModulesRoot)(workspaceRoot, (0, moduleDiscovery_1.resolveModulesRootFromContract)(contract)));
    const modules = await measure('architecture-map.discovery', () => {
        if (hasExplicitEmptyModuleRegistry) {
            return Promise.resolve([]);
        }
        if (hasArchitectureJson &&
            !shouldUseConfiguredRootInference &&
            !shouldUseTopLevelWorkspaceInference) {
            return discoverModulesFromArchitectureContract(workspaceRoot, contract, modulesRoot);
        }
        if (hasArchitectureJson && hasComponentEntries) {
            return discoverModulesFromComponents(workspaceRoot, contract, (0, moduleDiscovery_1.resolveContractsRootFromContract)(contract));
        }
        return discoverModulesFromFallbackScan(workspaceRoot, modulesRoot, (0, moduleDiscovery_1.resolveContractsRootFromContract)(contract), shouldUseConfiguredRootInference
            ? { configuredRootOnly: true }
            : shouldUseTopLevelWorkspaceInference
                ? { topLevelWorkspaceOnly: true }
                : undefined);
    });
    const moduleIds = modules.map((moduleEntry) => moduleEntry.moduleName);
    const dependencySnapshot = await measure('architecture-map.dependency-graph', () => (0, dependencyValidation_1.buildModuleDependencyGraphSnapshot)(workspaceRoot, {
        modulesRootRelativePath: modulesRoot,
        moduleFilter: moduleIds,
    }));
    const edges = dependencySnapshot.edges.map((edge) => toArchitectureMapEdge(edge));
    const hierarchyEdges = dependencySnapshot.hierarchyEdges;
    const parsedCycles = dependencySnapshot.cycles
        .map((cycle) => parseCycleString(cycle))
        .filter((cycle) => cycle.length > 1)
        .sort((left, right) => left.join('->').localeCompare(right.join('->')));
    const incomingMap = buildIncomingMap(modules, edges);
    const outgoingMap = buildOutgoingMap(modules, edges);
    const cycleMembership = new Set(parsedCycles.flatMap((cycle) => cycle));
    const hierarchyParentByChild = new Map(hierarchyEdges.map((edge) => [edge.childModule, edge.parentModule]));
    const childModulesByParent = new Map();
    for (const edge of hierarchyEdges) {
        const children = childModulesByParent.get(edge.parentModule) ?? [];
        children.push(edge.childModule);
        childModulesByParent.set(edge.parentModule, children);
    }
    const independentModuleNames = [];
    const potentialOrphanModuleNames = [];
    const hotspotSummary = await measure('architecture-map.hotspots', () => Promise.all(modules.map(async (moduleEntry) => {
        const incomingDependencyCount = incomingMap.get(moduleEntry.moduleName)?.length ?? 0;
        const outgoingDependencyCount = outgoingMap.get(moduleEntry.moduleName)?.length ?? 0;
        const hasNoPeerUsage = incomingDependencyCount === 0 && outgoingDependencyCount === 0;
        const hasIntentionalEvidence = hasNoPeerUsage
            ? await hasIntentionalIndependentEvidence({
                workspaceRoot,
                moduleEntry,
                hasChildren: (childModulesByParent.get(moduleEntry.moduleName)?.length ?? 0) > 0,
                isLeafChild: hierarchyParentByChild.has(moduleEntry.moduleName) &&
                    (childModulesByParent.get(moduleEntry.moduleName)?.length ?? 0) === 0,
            })
            : false;
        const orphan = hasNoPeerUsage && !hasIntentionalEvidence;
        if (hasNoPeerUsage && hasIntentionalEvidence) {
            independentModuleNames.push(moduleEntry.moduleName);
        }
        if (orphan) {
            potentialOrphanModuleNames.push(moduleEntry.moduleName);
        }
        return {
            moduleName: moduleEntry.moduleName,
            incomingDependencyCount,
            outgoingDependencyCount,
            participatesInCycle: cycleMembership.has(moduleEntry.moduleName),
            orphan,
            missingContract: !moduleEntry.contractExists,
            ...(moduleEntry.missingPublicEntrypointAlignment !== undefined
                ? {
                    missingPublicEntrypointAlignment: moduleEntry.missingPublicEntrypointAlignment,
                }
                : {}),
        };
    })));
    const mostDependedOnModules = sortRankedCounts(hotspotSummary
        .filter((entry) => entry.incomingDependencyCount > 0)
        .map((entry) => ({
        moduleName: entry.moduleName,
        count: entry.incomingDependencyCount,
    })));
    const highestOutgoingFanOutModules = sortRankedCounts(hotspotSummary
        .filter((entry) => entry.outgoingDependencyCount > 0)
        .map((entry) => ({
        moduleName: entry.moduleName,
        count: entry.outgoingDependencyCount,
    })));
    const modulesInCircularDependencies = sortUnique(hotspotSummary
        .filter((entry) => entry.participatesInCycle)
        .map((entry) => entry.moduleName));
    const independentModules = sortUnique(independentModuleNames);
    const potentialOrphanModules = sortUnique(potentialOrphanModuleNames);
    const orphanModules = potentialOrphanModules;
    const missingContracts = sortUnique(hotspotSummary
        .filter((entry) => entry.missingContract)
        .map((entry) => entry.moduleName));
    const missingPublicEntrypointAlignment = sortUnique(hotspotSummary
        .filter((entry) => entry.missingPublicEntrypointAlignment === true)
        .map((entry) => entry.moduleName));
    const connectivityThreshold = contract?.governance.validation?.highInboundDependencyWarningThreshold ?? 3;
    const highlyConnectedModules = sortRankedCounts(hotspotSummary
        .map((entry) => ({
        moduleName: entry.moduleName,
        count: entry.incomingDependencyCount + entry.outgoingDependencyCount,
    }))
        .filter((entry) => entry.count >= connectivityThreshold));
    return {
        ...(options?.metadata ? { xArchPilot: options.metadata } : {}),
        reportVersion: 1,
        projectName: resolveProjectName(workspaceRoot, contract),
        generatedAtUtc: options?.generatedAtUtc ?? new Date().toISOString(),
        discoveryMode,
        modulesRoot,
        modules,
        moduleHotspotSummary: hotspotSummary,
        edges,
        hierarchyEdges,
        cycles: parsedCycles,
        hotspots: {
            mostDependedOnModules,
            highestOutgoingFanOutModules,
            modulesInCircularDependencies,
            independentModules,
            potentialOrphanModules,
            orphanModules,
            missingContracts,
            highlyConnectedModules,
            missingPublicEntrypointAlignment,
        },
        summaryCounts: {
            moduleCount: modules.length,
            edgeCount: edges.length,
            cycleCount: parsedCycles.length,
            independentCount: independentModules.length,
            potentialOrphanCount: potentialOrphanModules.length,
            orphanCount: orphanModules.length,
            highlyConnectedCount: highlyConnectedModules.length,
            missingContractCount: missingContracts.length,
        },
        graph: {
            nodes: modules.map((moduleEntry) => ({
                id: moduleEntry.moduleName,
                label: moduleEntry.moduleName,
            })),
            edges: edges.map((edge) => ({
                source: edge.source,
                target: edge.target,
                importCount: edge.importCount,
                publicImportCount: edge.publicImportCount,
                nonPublicImportCount: edge.nonPublicImportCount,
            })),
            hierarchyEdges: hierarchyEdges.map((edge) => ({
                source: edge.parentModule,
                target: edge.childModule,
                relationship: 'contains',
            })),
        },
        notes: {
            usedArchitectureJson: discoveryMode === 'architecture-json',
            usedFallbackInference: discoveryMode !== 'architecture-json',
        },
    };
}
//# sourceMappingURL=architectureMap.js.map