Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions modeling-cmds/openapi/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -2577,7 +2577,7 @@
]
},
"KclFile": {
"description": "Region-creation algorithm version.",
"description": "A file in a KCL project.",
"type": "object",
"properties": {
"contents": {
Expand All @@ -2604,7 +2604,7 @@
]
},
"KclProject": {
"description": "A KCL project that can be executed.",
"description": "A KCL project.",
"type": "object",
"properties": {
"entrypoint": {
Expand Down Expand Up @@ -4134,6 +4134,15 @@
}
]
},
"kcl_source": {
"nullable": true,
"description": "KCL source to embed in formats that support source metadata.",
"allOf": [
{
"$ref": "#/components/schemas/KclProject"
}
]
},
"type": {
"type": "string",
"enum": [
Expand Down Expand Up @@ -4167,6 +4176,15 @@
}
]
},
"kcl_source": {
"nullable": true,
"description": "KCL source to embed in formats that support source metadata.",
"allOf": [
{
"$ref": "#/components/schemas/KclProject"
}
]
},
"type": {
"type": "string",
"enum": [
Expand Down
7 changes: 7 additions & 0 deletions modeling-cmds/src/def_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ define_modeling_cmd_enum! {
format::{OutputFormat2d, OutputFormat3d},
id::ModelingCmdId,
length_unit::LengthUnit,
kcl_project::KclProject,
shared::{
Angle,
RegionVersion,
Expand Down Expand Up @@ -692,6 +693,9 @@ define_modeling_cmd_enum! {
pub entity_ids: Vec<Uuid>,
/// The file format to export to.
pub format: OutputFormat3d,
/// KCL source to embed in formats that support source metadata.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub kcl_source: Option<KclProject>,
}

/// Export the scene to a file.
Expand All @@ -708,6 +712,9 @@ define_modeling_cmd_enum! {
pub entity_ids: Vec<Uuid>,
/// The file format to export to.
pub format: OutputFormat3d,
/// KCL source to embed in formats that support source metadata.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub kcl_source: Option<KclProject>,
}

/// What is this entity's parent?
Expand Down
57 changes: 1 addition & 56 deletions modeling-cmds/src/exec_kcl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,62 +7,7 @@ use kcl_error::{CompilationIssue, KclError};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::shared::safe_filepath::SafeFilepath;

/// A KCL project that can be executed.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default, Builder)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
Comment thread
adamchalmers marked this conversation as resolved.
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
pub struct KclProject {
/// All files in the project.
pub files: Vec<KclFile>,
/// Which file is the entrypoint?
/// This is the first KCL file to be executed,
/// the root of the KCL module tree.
pub entrypoint: SafeFilepath,
}

impl KclProject {
/// Create a new KCL project.
pub fn new(files: Vec<KclFile>, entrypoint: SafeFilepath) -> Self {
Self { files, entrypoint }
}
}

/// Region-creation algorithm version.
#[derive(Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default, Builder)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
pub struct KclFile {
/// Where is the file, relative to the project directory?
pub path: SafeFilepath,
/// Contents of the file, as UTF-8 encoded bytes.
#[serde(
serialize_with = "serde_bytes::serialize",
deserialize_with = "serde_bytes::deserialize"
)]
pub contents: Vec<u8>,
}

impl std::fmt::Debug for KclFile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("KclFile")
.field("path", &self.path)
.field("contents.len()", &self.contents.len())
.finish()
}
}

impl KclFile {
/// Create a KCL file.
pub fn new(path: SafeFilepath, contents: Vec<u8>) -> Self {
Self { path, contents }
}
}
pub use crate::kcl_project::{KclFile, KclFileBuilder, KclProject, KclProjectBuilder};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
Expand Down
59 changes: 59 additions & 0 deletions modeling-cmds/src/kcl_project.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::shared::safe_filepath::SafeFilepath;
use bon::Builder;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

/// A KCL project.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default, Builder)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
pub struct KclProject {
/// All files in the project.
pub files: Vec<KclFile>,
/// Which file is the entrypoint?
/// This is the first KCL file to be executed,
/// the root of the KCL module tree.
pub entrypoint: SafeFilepath,
}

impl KclProject {
/// Create a new KCL project.
pub fn new(files: Vec<KclFile>, entrypoint: SafeFilepath) -> Self {
Self { files, entrypoint }
}
}

/// A file in a KCL project.
#[derive(Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default, Builder)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
#[cfg_attr(not(feature = "unstable_exhaustive"), non_exhaustive)]
pub struct KclFile {
/// Where is the file, relative to the project directory?
pub path: SafeFilepath,
/// Contents of the file, as UTF-8 encoded bytes.
#[serde(
serialize_with = "serde_bytes::serialize",
deserialize_with = "serde_bytes::deserialize"
)]
pub contents: Vec<u8>,
}

impl std::fmt::Debug for KclFile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("KclFile")
.field("path", &self.path)
.field("contents.len()", &self.contents.len())
.finish()
}
}

impl KclFile {
/// Create a KCL file.
pub fn new(path: SafeFilepath, contents: Vec<u8>) -> Self {
Self { path, contents }
}
}
3 changes: 3 additions & 0 deletions modeling-cmds/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ pub mod shared;
#[cfg(feature = "exec-kcl")]
pub mod exec_kcl;

/// Structure of KCL projects (one or more KCL files).
pub mod kcl_project;

#[cfg(all(test, feature = "derive-jsonschema-on-enums"))]
mod tests;

Expand Down
2 changes: 2 additions & 0 deletions modeling-cmds/src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use crate::{

pub mod safe_filepath;

pub use crate::kcl_project::{KclFile, KclFileBuilder, KclProject, KclProjectBuilder};

/// Default tolerance values for modeling operations.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Builder)]
#[serde(rename_all = "snake_case")]
Expand Down
44 changes: 44 additions & 0 deletions modeling-cmds/tests/kcl_project_compat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! Checks that moving KCL project types preserves consumers' existing import paths.

use kittycad_modeling_cmds::{kcl_project, shared};

#[test]
fn shared_project_types_and_builders_remain_compatible() {
let file_builder: shared::KclFileBuilder = kcl_project::KclFile::builder();
let file: shared::KclFile = file_builder
.path("main.kcl".parse().unwrap())
.contents(b"// KCL source".to_vec())
.build();
let file: kcl_project::KclFile = file;

let project_builder: shared::KclProjectBuilder = kcl_project::KclProject::builder();
let project: shared::KclProject = project_builder
.files(vec![file])
.entrypoint("main.kcl".parse().unwrap())
.build();
let project: kcl_project::KclProject = project;

assert_eq!(project.entrypoint, project.files[0].path);
}

#[cfg(feature = "exec-kcl")]
#[test]
fn exec_kcl_project_types_and_builders_remain_compatible() {
use kittycad_modeling_cmds::exec_kcl;

let file_builder: exec_kcl::KclFileBuilder = kcl_project::KclFile::builder();
let file: exec_kcl::KclFile = file_builder
.path("main.kcl".parse().unwrap())
.contents(b"// KCL source".to_vec())
.build();
let file: kcl_project::KclFile = file;

let project_builder: exec_kcl::KclProjectBuilder = kcl_project::KclProject::builder();
let project: exec_kcl::KclProject = project_builder
.files(vec![file])
.entrypoint("main.kcl".parse().unwrap())
.build();
let project: kcl_project::KclProject = project;

assert_eq!(project.entrypoint, project.files[0].path);
}
Loading