Skip to main content

kittycad_modeling_cmds/
exec_kcl.rs

1use bon::Builder;
2#[cfg(feature = "websocket")]
3use kcl_api::ArtifactGraph;
4use kcl_error::{CompilationIssue, KclError};
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7
8use crate::shared::safe_filepath::SafeFilepath;
9
10/// A KCL project that can be executed.
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default, Builder)]
12#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
13#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
14#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
15#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
16pub struct KclProject {
17    /// All files in the project.
18    pub files: Vec<KclFile>,
19    /// Which file is the entrypoint?
20    /// This is the first KCL file to be executed,
21    /// the root of the KCL module tree.
22    pub entrypoint: SafeFilepath,
23}
24
25impl KclProject {
26    /// Create a new KCL project.
27    pub fn new(files: Vec<KclFile>, entrypoint: SafeFilepath) -> Self {
28        Self { files, entrypoint }
29    }
30}
31
32/// Region-creation algorithm version.
33#[derive(Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default, Builder)]
34#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
35#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
36#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
37#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
38pub struct KclFile {
39    /// Where is the file, relative to the project directory?
40    pub path: SafeFilepath,
41    /// Contents of the file, as UTF-8 encoded bytes.
42    #[serde(
43        serialize_with = "serde_bytes::serialize",
44        deserialize_with = "serde_bytes::deserialize"
45    )]
46    pub contents: Vec<u8>,
47}
48
49impl std::fmt::Debug for KclFile {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        f.debug_struct("KclFile")
52            .field("path", &self.path)
53            .field("contents.len()", &self.contents.len())
54            .finish()
55    }
56}
57
58impl KclFile {
59    /// Create a KCL file.
60    pub fn new(path: SafeFilepath, contents: Vec<u8>) -> Self {
61        Self { path, contents }
62    }
63}
64
65#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
66#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
67#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
68#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
69/// Successful KCL project execution response.
70pub struct ExecKclProjectOk {
71    /// The artifact graph produced by the KCL execution.
72    #[cfg(feature = "websocket")]
73    pub artifact_graph: ArtifactGraph,
74}
75
76#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
77#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
78#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
79#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
80/// Failed KCL project execution response.
81pub struct ExecKclProjectErr {
82    /// Fatal KCL errors that prevented your geometry from being created.
83    pub error: Option<KclError>,
84    /// Nonfatal KCL errors that need to be fixed.
85    pub non_fatal: Vec<CompilationIssue>,
86    // TODO: Add fields to this as we make KCL data serializable.
87    // Should be a usable subset of `KclErrorWithOutputs`.
88}
89
90impl ExecKclProjectErr {
91    /// Used when the project execution had a fatal error.
92    pub fn fatal_error(error: KclError) -> Self {
93        Self {
94            error: Some(error),
95            non_fatal: Default::default(),
96        }
97    }
98}
99
100#[cfg(feature = "arbitrary")]
101impl<'a> arbitrary::Arbitrary<'a> for ExecKclProjectOk {
102    fn arbitrary(_u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
103        Ok(Self {
104            #[cfg(feature = "websocket")]
105            artifact_graph: ArtifactGraph::default(),
106        })
107    }
108}
109
110#[cfg(feature = "arbitrary")]
111impl<'a> arbitrary::Arbitrary<'a> for ExecKclProjectErr {
112    fn arbitrary(_u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
113        Ok(Self {
114            error: Default::default(),
115            non_fatal: Default::default(),
116        })
117    }
118}