Skip to main content

strixonomy_refactor/
model.rs

1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
5#[serde(rename_all = "snake_case")]
6pub enum UsageKind {
7    EntityDeclaration,
8    AxiomSubject,
9    AxiomObject,
10    AxiomPredicate,
11    AnnotationSubject,
12    AnnotationObject,
13    AnnotationPredicate,
14    Import,
15    TextReference,
16    SwrlReference,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct Usage {
21    pub iri: String,
22    pub referenced_iri: String,
23    pub file: PathBuf,
24    pub line: Option<u64>,
25    pub column: Option<u64>,
26    pub start_byte: Option<u64>,
27    pub end_byte: Option<u64>,
28    pub kind: UsageKind,
29    pub context: String,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct Hunk {
34    pub start_byte: u64,
35    pub end_byte: u64,
36    pub old_text: String,
37    pub new_text: String,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct FileChange {
42    pub path: PathBuf,
43    pub preview_text: String,
44    pub original_text: String,
45    #[serde(default, skip_serializing_if = "Vec::is_empty")]
46    pub hunks: Vec<Hunk>,
47}
48
49#[derive(Debug, Clone, Default, Serialize, Deserialize)]
50pub struct RefactorPlan {
51    pub changes: Vec<FileChange>,
52    #[serde(default, skip_serializing_if = "Vec::is_empty")]
53    pub warnings: Vec<String>,
54    /// Distinct entity IRIs touched by this plan (best-effort).
55    #[serde(default)]
56    pub affected_entity_count: usize,
57    /// Approximate axiom/hunk impact (sum of hunks, or 1 per changed file when hunks empty).
58    #[serde(default)]
59    pub affected_axiom_count: usize,
60}
61
62impl RefactorPlan {
63    /// Populate impact metrics from file changes and explicitly named entity IRIs.
64    pub fn with_metrics(mut self, entity_iris: impl IntoIterator<Item = impl AsRef<str>>) -> Self {
65        let mut entities: std::collections::BTreeSet<String> =
66            entity_iris.into_iter().map(|s| s.as_ref().to_string()).collect();
67        entities.retain(|iri| !iri.is_empty());
68        self.affected_entity_count = entities.len();
69        self.affected_axiom_count =
70            self.changes.iter().map(|c| if c.hunks.is_empty() { 1 } else { c.hunks.len() }).sum();
71        self
72    }
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
76#[serde(tag = "kind", rename_all = "snake_case")]
77pub enum RefactorRequest {
78    RenameIri {
79        from_iri: String,
80        to_iri: String,
81    },
82    MergeEntities {
83        keep_iri: String,
84        merge_iri: String,
85    },
86    ReplaceEntity {
87        from_iri: String,
88        to_iri: String,
89    },
90    MigrateNamespace {
91        from_base: String,
92        to_base: String,
93    },
94    MoveEntity {
95        entity_iri: String,
96        target_file: PathBuf,
97    },
98    ExtractModule {
99        entity_iris: Vec<String>,
100        output_file: PathBuf,
101        #[serde(default)]
102        leave_stub: bool,
103        /// When true, expand `entity_iris` under the bottom-locality heuristic before extract.
104        #[serde(default)]
105        locality: bool,
106    },
107    /// Move selected Turtle subject statements for an entity to another file.
108    /// `statement_indexes` are 0-based indexes into `all_entity_statement_ranges`
109    /// (excluding the primary type declaration when `exclude_primary` is true).
110    MoveAxioms {
111        entity_iri: String,
112        target_file: PathBuf,
113        #[serde(default)]
114        statement_indexes: Vec<usize>,
115        #[serde(default = "default_true")]
116        exclude_primary: bool,
117    },
118    /// Merge one or more source ontology Turtle files into a target file.
119    MergeOntologies {
120        source_paths: Vec<PathBuf>,
121        target_file: PathBuf,
122    },
123    /// Inline imported Turtle axioms into a root ontology and remove `owl:imports`.
124    FlattenImports {
125        ontology_file: PathBuf,
126    },
127    /// Remove unused `owl:imports` lines (heuristic: no imported entities referenced).
128    CleanupImports {
129        ontology_file: PathBuf,
130    },
131}
132
133fn default_true() -> bool {
134    true
135}