"use strict";
/**
 * Canonical graph loader. Per CLAUDE.md Rule 12, every consumer of
 * `.dxkit/reports/graph.json` reads via `loadGraph(cwd)` — never
 * `JSON.parse` directly. Arch-check enforces; this is the only file
 * that may parse the artifact.
 *
 * Throws typed errors so callers can react precisely:
 *   - GraphNotFoundError      → file doesn't exist (suggest --refresh)
 *   - GraphSchemaVersionError → wire-format newer than the loader knows
 *   - GraphCorruptError       → missing/malformed required field
 */
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.GraphCorruptError = exports.GraphSchemaVersionError = exports.GraphNotFoundError = exports.GRAPH_REPORT_PATH = void 0;
exports.loadGraph = loadGraph;
exports.tryLoadGraph = tryLoadGraph;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const types_1 = require("./types");
Object.defineProperty(exports, "GRAPH_REPORT_PATH", { enumerable: true, get: function () { return types_1.GRAPH_REPORT_PATH; } });
class GraphNotFoundError extends Error {
    absPath;
    constructor(absPath) {
        super(`No graph.json at ${absPath}. Run \`vyuh-dxkit health\` or pass \`--refresh\` to regenerate.`);
        this.absPath = absPath;
        this.name = 'GraphNotFoundError';
    }
}
exports.GraphNotFoundError = GraphNotFoundError;
class GraphSchemaVersionError extends Error {
    absPath;
    found;
    expected;
    constructor(absPath, found, expected) {
        super(`graph.json at ${absPath} declares schemaVersion=${String(found)}; this dxkit reads schemaVersion=${expected}. Upgrade dxkit (\`npm install -g @vyuhlabs/dxkit@latest\`) to read newer artifacts.`);
        this.absPath = absPath;
        this.found = found;
        this.expected = expected;
        this.name = 'GraphSchemaVersionError';
    }
}
exports.GraphSchemaVersionError = GraphSchemaVersionError;
class GraphCorruptError extends Error {
    absPath;
    detail;
    constructor(absPath, detail) {
        super(`graph.json at ${absPath} is malformed: ${detail}. Regenerate with \`--refresh\`.`);
        this.absPath = absPath;
        this.detail = detail;
        this.name = 'GraphCorruptError';
    }
}
exports.GraphCorruptError = GraphCorruptError;
/**
 * Read + validate + index the graph artifact. The returned `Graph`
 * carries convenience indices (`nodeById`, `edgesFromNode`, ...)
 * built once at load time; queries in `./queries.ts` read from these
 * maps for O(1) traversal rather than repeatedly scanning the arrays.
 *
 * Validation is intentionally lightweight — top-level shape + required
 * fields per node/edge. Deep schema validation (every optional field's
 * types, referential integrity of every edge endpoint) would catch
 * more but cost more on every load; instead we trust the producer and
 * surface unexpected shapes as runtime errors at the query layer.
 */
function loadGraph(cwd) {
    const absPath = path.join(cwd, types_1.GRAPH_REPORT_PATH);
    if (!fs.existsSync(absPath)) {
        throw new GraphNotFoundError(absPath);
    }
    let raw;
    try {
        raw = JSON.parse(fs.readFileSync(absPath, 'utf-8'));
    }
    catch (err) {
        throw new GraphCorruptError(absPath, err instanceof Error ? err.message : 'JSON parse failed');
    }
    const json = validateAndUpgrade(absPath, raw);
    return indexGraph(json);
}
/**
 * Fail-open variant of {@link loadGraph}: returns undefined on ANY
 * error (missing file, parse failure, schema mismatch) instead of
 * throwing. For additive, never-block consumers — the PreToolUse
 * context hook and the finding-enrichment pass — where a missing or
 * stale graph must degrade to "no context", never an error.
 */
function tryLoadGraph(cwd) {
    try {
        return loadGraph(cwd);
    }
    catch {
        return undefined;
    }
}
function validateAndUpgrade(absPath, raw) {
    if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
        throw new GraphCorruptError(absPath, 'top-level value is not an object');
    }
    const obj = raw;
    const v = obj.schemaVersion;
    if (typeof v !== 'number') {
        throw new GraphCorruptError(absPath, 'schemaVersion is missing or not a number');
    }
    if (v > types_1.GRAPH_SCHEMA_VERSION) {
        throw new GraphSchemaVersionError(absPath, v, types_1.GRAPH_SCHEMA_VERSION);
    }
    // Future migrations: switch on v here when v2+ lands. Today v === 1
    // is the only supported version; no migration needed.
    for (const key of ['meta', 'nodes', 'edges', 'communities', 'symbolIndex']) {
        if (!(key in obj)) {
            throw new GraphCorruptError(absPath, `missing required top-level field "${key}"`);
        }
    }
    if (!Array.isArray(obj.nodes)) {
        throw new GraphCorruptError(absPath, '"nodes" is not an array');
    }
    if (!Array.isArray(obj.edges)) {
        throw new GraphCorruptError(absPath, '"edges" is not an array');
    }
    if (!Array.isArray(obj.communities)) {
        throw new GraphCorruptError(absPath, '"communities" is not an array');
    }
    // Trust the rest; runtime errors in queries surface deeper issues.
    return raw;
}
function indexGraph(json) {
    const nodeById = new Map();
    for (const n of json.nodes)
        nodeById.set(n.id, n);
    const edgesFromNode = new Map();
    const edgesToNode = new Map();
    for (const e of json.edges) {
        const fromList = edgesFromNode.get(e.from) ?? [];
        fromList.push(e);
        edgesFromNode.set(e.from, fromList);
        const toList = edgesToNode.get(e.to) ?? [];
        toList.push(e);
        edgesToNode.set(e.to, toList);
    }
    const nodesByFile = new Map();
    for (const n of json.nodes) {
        const list = nodesByFile.get(n.sourceFile) ?? [];
        list.push(n);
        nodesByFile.set(n.sourceFile, list);
    }
    const communityById = new Map();
    const communityByNode = new Map();
    for (const c of json.communities) {
        communityById.set(c.id, c);
        for (const nid of c.nodeIds)
            communityByNode.set(nid, c);
    }
    return {
        ...json,
        nodeById,
        edgesFromNode,
        edgesToNode,
        nodesByFile,
        communityById,
        communityByNode,
    };
}
//# sourceMappingURL=load.js.map