Skip to main content

code_ranker_graph/
snapshot.rs

1//! The serializable analysis artifact ([`Snapshot`]) and its header types
2//! ([`GitInfo`], [`StageTime`]).
3//!
4//! Shape (schema version `"2"`): the snapshot keeps the historical header
5//! (workspace/target/plugin/roots/versions/git/timings) and carries a `graphs`
6//! map `level_name -> LevelGraph`. The per-level payload lives in
7//! [`crate::level_graph`]; canonical serialization in [`crate::serialize`]; id
8//! relativization in [`crate::relativize`].
9
10use crate::level_graph::LevelGraph;
11use chrono::{DateTime, Utc};
12use code_ranker_plugin_api::Preset;
13use serde::{Deserialize, Serialize};
14use std::collections::BTreeMap;
15
16/// The snapshot schema version this build produces and can read back. A
17/// `--baseline` (or snapshot input) with a different version is rejected with a
18/// structured error rather than silently mis-parsed.
19pub const SCHEMA_VERSION: &str = "3";
20
21/// Per-stage timing in milliseconds, in execution order.
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct StageTime {
24    pub stage: String,
25    pub ms: u64,
26    #[serde(default, skip_serializing_if = "String::is_empty")]
27    pub detail: String,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct Snapshot {
32    pub schema_version: String,
33    pub generated_at: DateTime<Utc>,
34    pub command: String,
35    /// Directory from which `code-ranker` was invoked.
36    pub workspace: String,
37    /// The analyzed project directory (absolute path, stored once here).
38    pub target: String,
39    pub plugin: String,
40    /// Config file used for this analysis, if any was found.
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub config_file: Option<String>,
43    pub versions: BTreeMap<String, String>,
44    /// Named system roots used to shorten node paths (e.g. `{registry}`).
45    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
46    pub roots: BTreeMap<String, String>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub git: Option<GitInfo>,
49    #[serde(default, skip_serializing_if = "Vec::is_empty")]
50    pub timings: Vec<StageTime>,
51    /// Analysis levels, keyed by level name. Today only `"files"` is produced.
52    pub graphs: BTreeMap<String, LevelGraph>,
53    /// Prompt-Generator presets (refactoring principles), language-adapted.
54    #[serde(default, skip_serializing_if = "Vec::is_empty")]
55    pub presets: Vec<Preset>,
56    /// Prompt-Generator scaffolding prose (language-neutral framing), so the CLI
57    /// `prompt` format and the HTML viewer render the same text from one source.
58    #[serde(default)]
59    pub prompt: code_ranker_plugin_api::PromptTemplate,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct GitInfo {
64    pub branch: String,
65    pub commit: String,
66    pub dirty_files: u32,
67    /// Remote `origin` URL (raw). Used by the HTML report for source links.
68    #[serde(default, skip_serializing_if = "Option::is_none")]
69    pub origin: Option<String>,
70}
71
72impl Snapshot {
73    #[allow(clippy::too_many_arguments)]
74    pub fn new(
75        command: String,
76        workspace: String,
77        target: String,
78        plugin: String,
79        config_file: Option<String>,
80        versions: BTreeMap<String, String>,
81        roots: BTreeMap<String, String>,
82        git: Option<GitInfo>,
83        timings: Vec<StageTime>,
84        graphs: BTreeMap<String, LevelGraph>,
85        presets: Vec<Preset>,
86        prompt: code_ranker_plugin_api::PromptTemplate,
87    ) -> Self {
88        Self {
89            schema_version: SCHEMA_VERSION.to_string(),
90            generated_at: Utc::now(),
91            command,
92            workspace,
93            target,
94            plugin,
95            config_file,
96            versions,
97            roots,
98            git,
99            timings,
100            graphs,
101            presets,
102            prompt,
103        }
104    }
105}