use crate::{Completeness, FileEdit, PlanError, PlanEvidence, PlanFingerprint, TextEdit};
use blazingly_json::Value;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
pub const REFACTOR_PLAN_SCHEMA: &str = "weavatrix.refactor-plan.v1";
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RefactorPlan {
pub schema_version: String,
pub operation: String,
pub operations: Vec<RefactorOperation>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub completeness: Option<Completeness>,
#[serde(flatten)]
pub evidence: PlanEvidence,
}
impl RefactorPlan {
#[must_use]
pub fn new(operation: impl Into<String>, operations: Vec<RefactorOperation>) -> Self {
Self {
schema_version: REFACTOR_PLAN_SCHEMA.to_owned(),
operation: operation.into(),
operations,
completeness: None,
evidence: PlanEvidence::default(),
}
}
pub fn validate(&self) -> Result<crate::ValidatedConsumerPlan<'_>, PlanError> {
crate::validate_consumer_plan(self, crate::RefactorPlanLimits::default())
}
pub fn validate_with(
&self,
limits: crate::RefactorPlanLimits,
) -> Result<crate::ValidatedConsumerPlan<'_>, PlanError> {
crate::validate_consumer_plan(self, limits)
}
pub fn fingerprint(&self) -> Result<PlanFingerprint, PlanError> {
crate::fingerprint_plan(self)
}
pub fn from_text_edit_plan(plan: crate::EditPlan) -> Result<Self, PlanError> {
crate::conversion::from_text_edit_plan(plan)
}
pub fn try_into_text_edit_plan(self) -> Result<crate::EditPlan, PlanError> {
crate::conversion::into_text_edit_plan(self)
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", content = "value", rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
pub enum RefactorOperation {
Modify(FileEdit),
Create(CreateFile),
Delete(DeleteFile),
Rename(RenameFile),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateFile {
pub path: String,
pub contents: String,
#[serde(default, skip_serializing_if = "CreatePermissions::is_default")]
pub permissions: CreatePermissions,
#[serde(flatten, default, skip_serializing_if = "BTreeMap::is_empty")]
pub extensions: BTreeMap<String, Value>,
}
impl CreateFile {
#[must_use]
pub fn new(path: impl Into<String>, contents: impl Into<String>) -> Self {
Self {
path: path.into(),
contents: contents.into(),
permissions: CreatePermissions::default(),
extensions: BTreeMap::new(),
}
}
#[must_use]
pub const fn with_executable(mut self, executable: bool) -> Self {
self.permissions.executable = executable;
self
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct CreatePermissions {
pub executable: bool,
}
impl CreatePermissions {
#[must_use]
pub const fn is_default(&self) -> bool {
!self.executable
}
#[must_use]
pub const fn readonly(self) -> bool {
false
}
#[must_use]
pub const fn unix_mode(self) -> u32 {
if self.executable { 0o755 } else { 0o644 }
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DeleteFile {
pub path: String,
pub expected_sha256: String,
#[serde(flatten, default, skip_serializing_if = "BTreeMap::is_empty")]
pub extensions: BTreeMap<String, Value>,
}
impl DeleteFile {
#[must_use]
pub fn new(path: impl Into<String>, expected_sha256: impl Into<String>) -> Self {
Self {
path: path.into(),
expected_sha256: expected_sha256.into(),
extensions: BTreeMap::new(),
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RenameFile {
pub from: String,
pub to: String,
pub expected_source_sha256: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub edits: Vec<TextEdit>,
#[serde(flatten, default, skip_serializing_if = "BTreeMap::is_empty")]
pub extensions: BTreeMap<String, Value>,
}
impl RenameFile {
#[must_use]
pub fn new(
from: impl Into<String>,
to: impl Into<String>,
expected_source_sha256: impl Into<String>,
) -> Self {
Self {
from: from.into(),
to: to.into(),
expected_source_sha256: expected_source_sha256.into(),
edits: Vec::new(),
extensions: BTreeMap::new(),
}
}
#[must_use]
pub fn with_edits(mut self, edits: Vec<TextEdit>) -> Self {
self.edits = edits;
self
}
}