diff --git a/src/schema/v2/emit.ts b/src/schema/v2/emit.ts index 3f0098b..db70c9e 100644 --- a/src/schema/v2/emit.ts +++ b/src/schema/v2/emit.ts @@ -12,6 +12,7 @@ import * as path from "node:path"; import type { AnalysisOptions } from "../../options"; +import { ANALYZER_VERSION } from "../../utils/version"; import type { TSApplication, TSCallable, @@ -30,6 +31,7 @@ import type { V2Application, V2BodyNode, V2CallEdge, V2Callable, V2External, V2F const LANGUAGE = "typescript"; const SCHEMA_VERSION = "2.0.0"; +const ANALYZER_NAME = "codeanalyzer-typescript"; /** Highest analysis level this emitter populates today (L1 tree, L2 call graph, L3/L4 dataflow). */ const MAX_IMPLEMENTED = 4; @@ -371,6 +373,7 @@ export function toV2Detailed(app: TSApplication, opts: AnalysisOptions): ToV2Res language: LANGUAGE, max_level: Math.min(level, MAX_IMPLEMENTED), ...(k_limit !== undefined ? { k_limit } : {}), + analyzer: { name: ANALYZER_NAME, version: ANALYZER_VERSION }, application: root, }; return { application, idBySig, collisions, dangling }; diff --git a/src/schema/v2/model.ts b/src/schema/v2/model.ts index a2a19af..493fee6 100644 --- a/src/schema/v2/model.ts +++ b/src/schema/v2/model.ts @@ -25,9 +25,16 @@ export interface V2Application { language: string; // "typescript" max_level: number; // highest level populated; consumers read this, not key-sniffing k_limit?: number; // access-path depth bound for the L3/L4 dataflow (present at L3+) + analyzer: V2Analyzer; // which analyzer produced this artifact, and at what version application: V2Root; } +/** Analyzer identity — lets consumers correlate an `analysis.json` with the tool/version that emitted it. */ +export interface V2Analyzer { + name: string; // "codeanalyzer-typescript" + version: string; // ANALYZER_VERSION (src/utils/version.ts) +} + export interface V2Root { id: string; // can:/// kind: "application"; diff --git a/src/utils/version.ts b/src/utils/version.ts index d2cd3e6..c33aa41 100644 --- a/src/utils/version.ts +++ b/src/utils/version.ts @@ -3,4 +3,4 @@ * the analyzer invalidates stale per-file Modules (whose source is unchanged but whose extracted * shape may differ across analyzer versions). */ -export const ANALYZER_VERSION = "0.1.0"; +export const ANALYZER_VERSION = "0.5.0"; diff --git a/test/schema-v2.test.ts b/test/schema-v2.test.ts index a33584e..6e151e3 100644 --- a/test/schema-v2.test.ts +++ b/test/schema-v2.test.ts @@ -9,6 +9,7 @@ import { describe, expect, test } from "bun:test"; import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; +import pkg from "../package.json"; import { analyze } from "../src/core"; import type { AnalysisOptions } from "../src/options"; import type { GraphSelector, TSApplication } from "../src/schema"; @@ -103,6 +104,11 @@ describe("schema v2 — L1 envelope", () => { expect(key).not.toContain("\\"); } }); + + test("envelope carries analyzer{name,version}", () => { + expect(v2.analyzer?.name).toBe("codeanalyzer-typescript"); + expect(v2.analyzer?.version).toBe(pkg.version); + }); }); describe("schema v2 — L1 identity", () => {