parallelized modules from kcl (#6206)
* wip * sketch a bit more; going to pull this out of tests next * wip * lock start things * this was a bad idea * Revert "this was a bad idea" This reverts commita2092e7ed6. * prepare prelude before spawning * error * poop * yike * :( * ok * Reapply "this was a bad idea" This reverts commitfafdf41093. * chip away more * man this is bad * fix rebase add feature flag Signed-off-by: Jess Frazelle <github@jessfraz.com> * get rid of execution kind Signed-off-by: Jess Frazelle <github@jessfraz.com> * clippy Signed-off-by: Jess Frazelle <github@jessfraz.com> * logs Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * no extra executes Signed-off-by: Jess Frazelle <github@jessfraz.com> * race w batch Signed-off-by: Jess Frazelle <github@jessfraz.com> * cluppy Signed-off-by: Jess Frazelle <github@jessfraz.com> * no printlns Signed-off-by: Jess Frazelle <github@jessfraz.com> * no printlns Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix source ranges Signed-off-by: Jess Frazelle <github@jessfraz.com> * batch shit Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix some bugs Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix error Signed-off-by: Jess Frazelle <github@jessfraz.com> * cut 1 * preserve mem * re-ad deep_clone the helper we were calling was pushing a new call, which was hanging out. we can skip the middleman since we already have something properly prepared, just without a stdlib in some cases. * skip non-kcl * clean up source range bug * error message changed the uuids also changed because the error is hit before execute even starts. * typo * rensnapshot a few * order things * MAYBE REVERT LATER: attempt at an ordering * snapsnap * Revert "snapsnap" This reverts commit7350b32c7d. * Revert "MAYBE REVERT LATER:" This reverts commitab49f3e85f. * ugh * poop * poop2 * lint * tranche 1 * more * more snaps * snap * more * update * MAYBE REVERT THIS * cache multi-file Signed-off-by: Jess Frazelle <github@jessfraz.com> * addd tests Signed-off-by: Jess Frazelle <github@jessfraz.com> * set to false Signed-off-by: Jess Frazelle <github@jessfraz.com> * add test outputs Signed-off-by: Jess Frazelle <github@jessfraz.com> * clippy Signed-off-by: Jess Frazelle <github@jessfraz.com> * kcl-py-bindings uses carwheel Signed-off-by: Jess Frazelle <github@jessfraz.com> * update snapshots Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: Paul R. Tagliamonte <paul@zoo.dev> Co-authored-by: Paul Tagliamonte <paultag@gmail.com>
This commit is contained in:
		
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -67,6 +67,7 @@
 | 
			
		||||
        PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH = "${pkgs.playwright-driver.browsers}/chromium-1091/chrome-linux/chrome";
 | 
			
		||||
        PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}";
 | 
			
		||||
        NODE_ENV = "development";
 | 
			
		||||
        RUSTFMT = "${pkgs.rust-bin.stable.latest.rustfmt}/bin/rustfmt";
 | 
			
		||||
      };
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								rust/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										20
									
								
								rust/Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -1907,6 +1907,7 @@ dependencies = [
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "sha2",
 | 
			
		||||
 "tabled",
 | 
			
		||||
 "tempdir",
 | 
			
		||||
 "thiserror 2.0.12",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tokio-tungstenite",
 | 
			
		||||
@ -3084,6 +3085,15 @@ version = "0.8.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "remove_dir_all"
 | 
			
		||||
version = "0.5.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "winapi",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "reqwest"
 | 
			
		||||
version = "0.12.15"
 | 
			
		||||
@ -3779,6 +3789,16 @@ version = "0.13.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tempdir"
 | 
			
		||||
version = "0.3.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "rand 0.4.6",
 | 
			
		||||
 "remove_dir_all",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tempfile"
 | 
			
		||||
version = "3.19.0"
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,6 @@ debug = 0
 | 
			
		||||
 | 
			
		||||
[profile.dev.package]
 | 
			
		||||
insta = { opt-level = 3 }
 | 
			
		||||
similar = { opt-level = 3 }
 | 
			
		||||
 | 
			
		||||
[profile.test]
 | 
			
		||||
debug = "line-tables-only"
 | 
			
		||||
 | 
			
		||||
@ -69,6 +69,7 @@ serde = { workspace = true }
 | 
			
		||||
serde_json = { workspace = true }
 | 
			
		||||
sha2 = "0.10.8"
 | 
			
		||||
tabled = { version = "0.18.0", optional = true }
 | 
			
		||||
tempdir = "0.3.7"
 | 
			
		||||
thiserror = "2.0.0"
 | 
			
		||||
toml = "0.8.19"
 | 
			
		||||
ts-rs = { version = "10.1.0", features = [
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ use kittycad_modeling_cmds as kcmc;
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct Variation<'a> {
 | 
			
		||||
    code: &'a str,
 | 
			
		||||
    other_files: Vec<(std::path::PathBuf, std::string::String)>,
 | 
			
		||||
    settings: &'a kcl_lib::ExecutorSettings,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -31,7 +32,31 @@ async fn cache_test(
 | 
			
		||||
        // set the new settings.
 | 
			
		||||
        ctx.settings = variation.settings.clone();
 | 
			
		||||
 | 
			
		||||
        let outcome = ctx.run_with_caching(program).await.unwrap();
 | 
			
		||||
        if !variation.other_files.is_empty() {
 | 
			
		||||
            let tmp_dir = std::env::temp_dir();
 | 
			
		||||
            let tmp_dir = tmp_dir
 | 
			
		||||
                .join(format!("kcl_test_{}", test_name))
 | 
			
		||||
                .join(uuid::Uuid::new_v4().to_string());
 | 
			
		||||
 | 
			
		||||
            // Create a temporary file for each of the other files.
 | 
			
		||||
            for (variant_path, variant_code) in &variation.other_files {
 | 
			
		||||
                let tmp_file = tmp_dir.join(variant_path);
 | 
			
		||||
                std::fs::create_dir_all(tmp_file.parent().unwrap()).unwrap();
 | 
			
		||||
                std::fs::write(tmp_file, variant_code).unwrap();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ctx.settings.project_directory = Some(tmp_dir.clone());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let outcome = match ctx.run_with_caching(program).await {
 | 
			
		||||
            Ok(outcome) => outcome,
 | 
			
		||||
            Err(error) => {
 | 
			
		||||
                let report = error.clone().into_miette_report_with_outputs(variation.code).unwrap();
 | 
			
		||||
                let report = miette::Report::new(report);
 | 
			
		||||
                panic!("{:?}", report);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let snapshot_png_bytes = ctx.prepare_snapshot().await.unwrap().contents.0;
 | 
			
		||||
 | 
			
		||||
        // Decode the snapshot, return it.
 | 
			
		||||
@ -68,6 +93,7 @@ async fn kcl_test_cache_change_grid_visualizes_grid_off_to_on() {
 | 
			
		||||
        vec![
 | 
			
		||||
            Variation {
 | 
			
		||||
                code,
 | 
			
		||||
                other_files: vec![],
 | 
			
		||||
                settings: &kcl_lib::ExecutorSettings {
 | 
			
		||||
                    show_grid: false,
 | 
			
		||||
                    ..Default::default()
 | 
			
		||||
@ -75,6 +101,7 @@ async fn kcl_test_cache_change_grid_visualizes_grid_off_to_on() {
 | 
			
		||||
            },
 | 
			
		||||
            Variation {
 | 
			
		||||
                code,
 | 
			
		||||
                other_files: vec![],
 | 
			
		||||
                settings: &kcl_lib::ExecutorSettings {
 | 
			
		||||
                    show_grid: true,
 | 
			
		||||
                    ..Default::default()
 | 
			
		||||
@ -107,6 +134,7 @@ async fn kcl_test_cache_change_grid_visualizes_grid_on_to_off() {
 | 
			
		||||
        vec![
 | 
			
		||||
            Variation {
 | 
			
		||||
                code,
 | 
			
		||||
                other_files: vec![],
 | 
			
		||||
                settings: &kcl_lib::ExecutorSettings {
 | 
			
		||||
                    show_grid: true,
 | 
			
		||||
                    ..Default::default()
 | 
			
		||||
@ -114,6 +142,7 @@ async fn kcl_test_cache_change_grid_visualizes_grid_on_to_off() {
 | 
			
		||||
            },
 | 
			
		||||
            Variation {
 | 
			
		||||
                code,
 | 
			
		||||
                other_files: vec![],
 | 
			
		||||
                settings: &kcl_lib::ExecutorSettings {
 | 
			
		||||
                    show_grid: false,
 | 
			
		||||
                    ..Default::default()
 | 
			
		||||
@ -146,6 +175,7 @@ async fn kcl_test_cache_change_highlight_edges_changes_visual() {
 | 
			
		||||
        vec![
 | 
			
		||||
            Variation {
 | 
			
		||||
                code,
 | 
			
		||||
                other_files: vec![],
 | 
			
		||||
                settings: &kcl_lib::ExecutorSettings {
 | 
			
		||||
                    highlight_edges: true,
 | 
			
		||||
                    ..Default::default()
 | 
			
		||||
@ -153,6 +183,7 @@ async fn kcl_test_cache_change_highlight_edges_changes_visual() {
 | 
			
		||||
            },
 | 
			
		||||
            Variation {
 | 
			
		||||
                code,
 | 
			
		||||
                other_files: vec![],
 | 
			
		||||
                settings: &kcl_lib::ExecutorSettings {
 | 
			
		||||
                    highlight_edges: false,
 | 
			
		||||
                    ..Default::default()
 | 
			
		||||
@ -168,6 +199,58 @@ async fn kcl_test_cache_change_highlight_edges_changes_visual() {
 | 
			
		||||
    assert!(first.1 != second.1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
async fn kcl_test_cache_multi_file_same_code_dont_reexecute() {
 | 
			
		||||
    let code = r#"import "toBeImported.kcl" as importedCube
 | 
			
		||||
 | 
			
		||||
importedCube
 | 
			
		||||
 | 
			
		||||
sketch001 = startSketchOn(XZ)
 | 
			
		||||
profile001 = startProfileAt([-134.53, -56.17], sketch001)
 | 
			
		||||
  |> angledLine(angle = 0, length = 79.05, tag = $rectangleSegmentA001)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 76.28)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $seg01)
 | 
			
		||||
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
 | 
			
		||||
  |> close()
 | 
			
		||||
extrude001 = extrude(profile001, length = 100)
 | 
			
		||||
sketch003 = startSketchOn(extrude001, face = seg02)
 | 
			
		||||
sketch002 = startSketchOn(extrude001, face = seg01)
 | 
			
		||||
"#;
 | 
			
		||||
 | 
			
		||||
    let other_file = (
 | 
			
		||||
        std::path::PathBuf::from("toBeImported.kcl"),
 | 
			
		||||
        r#"sketch001 = startSketchOn(XZ)
 | 
			
		||||
profile001 = startProfileAt([281.54, 305.81], sketch001)
 | 
			
		||||
  |> angledLine(angle = 0, length = 123.43, tag = $rectangleSegmentA001)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 85.99)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
 | 
			
		||||
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
 | 
			
		||||
  |> close()
 | 
			
		||||
extrude(profile001, length = 100)"#
 | 
			
		||||
            .to_string(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    let result = cache_test(
 | 
			
		||||
        "multi_file_same_code_dont_reexecute",
 | 
			
		||||
        vec![
 | 
			
		||||
            Variation {
 | 
			
		||||
                code,
 | 
			
		||||
                other_files: vec![other_file.clone()],
 | 
			
		||||
                settings: &Default::default(),
 | 
			
		||||
            },
 | 
			
		||||
            Variation {
 | 
			
		||||
                code,
 | 
			
		||||
                other_files: vec![other_file],
 | 
			
		||||
                settings: &Default::default(),
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
    )
 | 
			
		||||
    .await;
 | 
			
		||||
 | 
			
		||||
    result.first().unwrap();
 | 
			
		||||
    result.last().unwrap();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
async fn kcl_test_cache_add_line_preserves_artifact_commands() {
 | 
			
		||||
    let code = r#"sketch001 = startSketchOn('XY')
 | 
			
		||||
@ -190,10 +273,12 @@ extrude(sketch001, length = 4)
 | 
			
		||||
        vec![
 | 
			
		||||
            Variation {
 | 
			
		||||
                code,
 | 
			
		||||
                other_files: vec![],
 | 
			
		||||
                settings: &Default::default(),
 | 
			
		||||
            },
 | 
			
		||||
            Variation {
 | 
			
		||||
                code: code_with_extrude.as_str(),
 | 
			
		||||
                other_files: vec![],
 | 
			
		||||
                settings: &Default::default(),
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
@ -282,3 +367,109 @@ async fn kcl_test_cache_empty_file_pop_cache_empty_file_planes_work() {
 | 
			
		||||
 | 
			
		||||
    ctx.close().await;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
async fn kcl_test_cache_multi_file_after_empty_with_export() {
 | 
			
		||||
    let code = r#"import importedCube from "toBeImported.kcl"
 | 
			
		||||
 | 
			
		||||
importedCube
 | 
			
		||||
 | 
			
		||||
sketch001 = startSketchOn(XZ)
 | 
			
		||||
profile001 = startProfileAt([-134.53, -56.17], sketch001)
 | 
			
		||||
  |> angledLine(angle = 0, length = 79.05, tag = $rectangleSegmentA001)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 76.28)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $seg01)
 | 
			
		||||
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
 | 
			
		||||
  |> close()
 | 
			
		||||
extrude001 = extrude(profile001, length = 100)
 | 
			
		||||
sketch003 = startSketchOn(extrude001, face = seg02)
 | 
			
		||||
sketch002 = startSketchOn(extrude001, face = seg01)
 | 
			
		||||
"#;
 | 
			
		||||
 | 
			
		||||
    let other_file = (
 | 
			
		||||
        std::path::PathBuf::from("toBeImported.kcl"),
 | 
			
		||||
        r#"sketch001 = startSketchOn(XZ)
 | 
			
		||||
profile001 = startProfileAt([281.54, 305.81], sketch001)
 | 
			
		||||
  |> angledLine(angle = 0, length = 123.43, tag = $rectangleSegmentA001)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 85.99)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
 | 
			
		||||
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
 | 
			
		||||
  |> close()
 | 
			
		||||
export importedCube = extrude(profile001, length = 100)
 | 
			
		||||
"#
 | 
			
		||||
        .to_string(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    let result = cache_test(
 | 
			
		||||
        "multi_file_after_empty",
 | 
			
		||||
        vec![
 | 
			
		||||
            Variation {
 | 
			
		||||
                code: "",
 | 
			
		||||
                other_files: vec![],
 | 
			
		||||
                settings: &Default::default(),
 | 
			
		||||
            },
 | 
			
		||||
            Variation {
 | 
			
		||||
                code,
 | 
			
		||||
                other_files: vec![other_file],
 | 
			
		||||
                settings: &Default::default(),
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
    )
 | 
			
		||||
    .await;
 | 
			
		||||
 | 
			
		||||
    result.first().unwrap();
 | 
			
		||||
    result.last().unwrap();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
async fn kcl_test_cache_multi_file_after_empty_with_woo() {
 | 
			
		||||
    let code = r#"import "toBeImported.kcl" as importedCube
 | 
			
		||||
 | 
			
		||||
importedCube
 | 
			
		||||
 | 
			
		||||
sketch001 = startSketchOn(XZ)
 | 
			
		||||
profile001 = startProfileAt([-134.53, -56.17], sketch001)
 | 
			
		||||
  |> angledLine(angle = 0, length = 79.05, tag = $rectangleSegmentA001)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 76.28)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $seg01)
 | 
			
		||||
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
 | 
			
		||||
  |> close()
 | 
			
		||||
extrude001 = extrude(profile001, length = 100)
 | 
			
		||||
sketch003 = startSketchOn(extrude001, face = seg02)
 | 
			
		||||
sketch002 = startSketchOn(extrude001, face = seg01)
 | 
			
		||||
"#;
 | 
			
		||||
 | 
			
		||||
    let other_file = (
 | 
			
		||||
        std::path::PathBuf::from("toBeImported.kcl"),
 | 
			
		||||
        r#"sketch001 = startSketchOn(XZ)
 | 
			
		||||
profile001 = startProfileAt([281.54, 305.81], sketch001)
 | 
			
		||||
  |> angledLine(angle = 0, length = 123.43, tag = $rectangleSegmentA001)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 85.99)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
 | 
			
		||||
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
 | 
			
		||||
  |> close()
 | 
			
		||||
extrude(profile001, length = 100)
 | 
			
		||||
"#
 | 
			
		||||
        .to_string(),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    let result = cache_test(
 | 
			
		||||
        "multi_file_after_empty",
 | 
			
		||||
        vec![
 | 
			
		||||
            Variation {
 | 
			
		||||
                code: "",
 | 
			
		||||
                other_files: vec![],
 | 
			
		||||
                settings: &Default::default(),
 | 
			
		||||
            },
 | 
			
		||||
            Variation {
 | 
			
		||||
                code,
 | 
			
		||||
                other_files: vec![other_file],
 | 
			
		||||
                settings: &Default::default(),
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
    )
 | 
			
		||||
    .await;
 | 
			
		||||
 | 
			
		||||
    result.first().unwrap();
 | 
			
		||||
    result.last().unwrap();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 19 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 35 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 35 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 35 KiB  | 
@ -18,7 +18,7 @@ use tokio::sync::{mpsc, oneshot, RwLock};
 | 
			
		||||
use tokio_tungstenite::tungstenite::Message as WsMsg;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
use super::{EngineStats, ExecutionKind};
 | 
			
		||||
use super::EngineStats;
 | 
			
		||||
use crate::{
 | 
			
		||||
    engine::EngineManager,
 | 
			
		||||
    errors::{KclError, KclErrorDetails},
 | 
			
		||||
@ -51,7 +51,6 @@ pub struct EngineConnection {
 | 
			
		||||
    /// If the server sends session data, it'll be copied to here.
 | 
			
		||||
    session_data: Arc<RwLock<Option<ModelingSessionData>>>,
 | 
			
		||||
 | 
			
		||||
    execution_kind: Arc<RwLock<ExecutionKind>>,
 | 
			
		||||
    stats: EngineStats,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -344,7 +343,6 @@ impl EngineConnection {
 | 
			
		||||
            artifact_commands: Arc::new(RwLock::new(Vec::new())),
 | 
			
		||||
            default_planes: Default::default(),
 | 
			
		||||
            session_data,
 | 
			
		||||
            execution_kind: Default::default(),
 | 
			
		||||
            stats: Default::default(),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
@ -368,18 +366,6 @@ impl EngineManager for EngineConnection {
 | 
			
		||||
        self.artifact_commands.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn execution_kind(&self) -> ExecutionKind {
 | 
			
		||||
        let guard = self.execution_kind.read().await;
 | 
			
		||||
        *guard
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind {
 | 
			
		||||
        let mut guard = self.execution_kind.write().await;
 | 
			
		||||
        let original = *guard;
 | 
			
		||||
        *guard = execution_kind;
 | 
			
		||||
        original
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn stats(&self) -> &EngineStats {
 | 
			
		||||
        &self.stats
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ use kittycad_modeling_cmds::{self as kcmc};
 | 
			
		||||
use tokio::sync::RwLock;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
use super::{EngineStats, ExecutionKind};
 | 
			
		||||
use super::EngineStats;
 | 
			
		||||
use crate::{
 | 
			
		||||
    errors::KclError,
 | 
			
		||||
    exec::DefaultPlanes,
 | 
			
		||||
@ -29,7 +29,6 @@ pub struct EngineConnection {
 | 
			
		||||
    batch: Arc<RwLock<Vec<(WebSocketRequest, SourceRange)>>>,
 | 
			
		||||
    batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
 | 
			
		||||
    artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>,
 | 
			
		||||
    execution_kind: Arc<RwLock<ExecutionKind>>,
 | 
			
		||||
    /// The default planes for the scene.
 | 
			
		||||
    default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
 | 
			
		||||
    stats: EngineStats,
 | 
			
		||||
@ -41,7 +40,6 @@ impl EngineConnection {
 | 
			
		||||
            batch: Arc::new(RwLock::new(Vec::new())),
 | 
			
		||||
            batch_end: Arc::new(RwLock::new(IndexMap::new())),
 | 
			
		||||
            artifact_commands: Arc::new(RwLock::new(Vec::new())),
 | 
			
		||||
            execution_kind: Default::default(),
 | 
			
		||||
            default_planes: Default::default(),
 | 
			
		||||
            stats: Default::default(),
 | 
			
		||||
        })
 | 
			
		||||
@ -70,18 +68,6 @@ impl crate::engine::EngineManager for EngineConnection {
 | 
			
		||||
        self.artifact_commands.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn execution_kind(&self) -> ExecutionKind {
 | 
			
		||||
        let guard = self.execution_kind.read().await;
 | 
			
		||||
        *guard
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind {
 | 
			
		||||
        let mut guard = self.execution_kind.write().await;
 | 
			
		||||
        let original = *guard;
 | 
			
		||||
        *guard = execution_kind;
 | 
			
		||||
        original
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
 | 
			
		||||
        self.default_planes.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ use uuid::Uuid;
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    engine::{EngineStats, ExecutionKind},
 | 
			
		||||
    engine::EngineStats,
 | 
			
		||||
    errors::{KclError, KclErrorDetails},
 | 
			
		||||
    execution::{ArtifactCommand, DefaultPlanes, IdGenerator},
 | 
			
		||||
    SourceRange,
 | 
			
		||||
@ -42,7 +42,6 @@ pub struct EngineConnection {
 | 
			
		||||
    batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
 | 
			
		||||
    responses: Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>>,
 | 
			
		||||
    artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>,
 | 
			
		||||
    execution_kind: Arc<RwLock<ExecutionKind>>,
 | 
			
		||||
    /// The default planes for the scene.
 | 
			
		||||
    default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
 | 
			
		||||
    stats: EngineStats,
 | 
			
		||||
@ -61,7 +60,6 @@ impl EngineConnection {
 | 
			
		||||
            batch_end: Arc::new(RwLock::new(IndexMap::new())),
 | 
			
		||||
            responses: Arc::new(RwLock::new(IndexMap::new())),
 | 
			
		||||
            artifact_commands: Arc::new(RwLock::new(Vec::new())),
 | 
			
		||||
            execution_kind: Default::default(),
 | 
			
		||||
            default_planes: Default::default(),
 | 
			
		||||
            stats: Default::default(),
 | 
			
		||||
        })
 | 
			
		||||
@ -164,18 +162,6 @@ impl crate::engine::EngineManager for EngineConnection {
 | 
			
		||||
        self.artifact_commands.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn execution_kind(&self) -> ExecutionKind {
 | 
			
		||||
        let guard = self.execution_kind.read().await;
 | 
			
		||||
        *guard
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind {
 | 
			
		||||
        let mut guard = self.execution_kind.write().await;
 | 
			
		||||
        let original = *guard;
 | 
			
		||||
        *guard = execution_kind;
 | 
			
		||||
        original
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
 | 
			
		||||
        self.default_planes.clone()
 | 
			
		||||
    }
 | 
			
		||||
@ -218,11 +204,6 @@ impl crate::engine::EngineManager for EngineConnection {
 | 
			
		||||
            .do_send_modeling_cmd(id, source_range, cmd, id_to_source_range)
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        // In isolated mode, we don't save the response.
 | 
			
		||||
        if self.execution_kind().await.is_isolated() {
 | 
			
		||||
            return Ok(ws_result);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut responses = self.responses.write().await;
 | 
			
		||||
        responses.insert(id, ws_result.clone());
 | 
			
		||||
        drop(responses);
 | 
			
		||||
 | 
			
		||||
@ -47,23 +47,6 @@ lazy_static::lazy_static! {
 | 
			
		||||
    pub static ref GRID_SCALE_TEXT_OBJECT_ID: uuid::Uuid = uuid::Uuid::parse_str("10782f33-f588-4668-8bcd-040502d26590").unwrap();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The mode of execution.  When isolated, like during an import, attempting to
 | 
			
		||||
/// send a command results in an error.
 | 
			
		||||
#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS, JsonSchema)]
 | 
			
		||||
#[ts(export)]
 | 
			
		||||
#[serde(rename_all = "camelCase")]
 | 
			
		||||
pub enum ExecutionKind {
 | 
			
		||||
    #[default]
 | 
			
		||||
    Normal,
 | 
			
		||||
    Isolated,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ExecutionKind {
 | 
			
		||||
    pub fn is_isolated(&self) -> bool {
 | 
			
		||||
        matches!(self, ExecutionKind::Isolated)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Default, Debug)]
 | 
			
		||||
pub struct EngineStats {
 | 
			
		||||
    pub commands_batched: AtomicUsize,
 | 
			
		||||
@ -118,13 +101,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
        std::mem::take(&mut *self.responses().write().await)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the current execution kind.
 | 
			
		||||
    async fn execution_kind(&self) -> ExecutionKind;
 | 
			
		||||
 | 
			
		||||
    /// Replace the current execution kind with a new value and return the
 | 
			
		||||
    /// existing value.
 | 
			
		||||
    async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind;
 | 
			
		||||
 | 
			
		||||
    /// Get the default planes.
 | 
			
		||||
    fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>>;
 | 
			
		||||
 | 
			
		||||
@ -289,11 +265,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
        cmd: &ModelingCmd,
 | 
			
		||||
    ) -> Result<(), crate::errors::KclError> {
 | 
			
		||||
        // In isolated mode, we don't send the command to the engine.
 | 
			
		||||
        if self.execution_kind().await.is_isolated() {
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let req = WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
 | 
			
		||||
            cmd: cmd.clone(),
 | 
			
		||||
            cmd_id: id.into(),
 | 
			
		||||
@ -315,11 +286,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
        cmds: &[ModelingCmdReq],
 | 
			
		||||
    ) -> Result<(), crate::errors::KclError> {
 | 
			
		||||
        // In isolated mode, we don't send the command to the engine.
 | 
			
		||||
        if self.execution_kind().await.is_isolated() {
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Add cmds to the batch.
 | 
			
		||||
        let mut extended_cmds = Vec::with_capacity(cmds.len());
 | 
			
		||||
        for cmd in cmds {
 | 
			
		||||
@ -342,11 +308,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
        cmd: &ModelingCmd,
 | 
			
		||||
    ) -> Result<(), crate::errors::KclError> {
 | 
			
		||||
        // In isolated mode, we don't send the command to the engine.
 | 
			
		||||
        if self.execution_kind().await.is_isolated() {
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let req = WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
 | 
			
		||||
            cmd: cmd.clone(),
 | 
			
		||||
            cmd_id: id.into(),
 | 
			
		||||
@ -365,36 +326,36 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
        cmd: &ModelingCmd,
 | 
			
		||||
    ) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
 | 
			
		||||
        self.batch_modeling_cmd(id, source_range, cmd).await?;
 | 
			
		||||
        let mut requests = self.take_batch().await.clone();
 | 
			
		||||
 | 
			
		||||
        // Add the command to the batch.
 | 
			
		||||
        requests.push((
 | 
			
		||||
            WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
 | 
			
		||||
                cmd: cmd.clone(),
 | 
			
		||||
                cmd_id: id.into(),
 | 
			
		||||
            }),
 | 
			
		||||
            source_range,
 | 
			
		||||
        ));
 | 
			
		||||
        self.stats().commands_batched.fetch_add(1, Ordering::Relaxed);
 | 
			
		||||
 | 
			
		||||
        // Flush the batch queue.
 | 
			
		||||
        self.flush_batch(false, source_range).await
 | 
			
		||||
        self.run_batch(requests, source_range).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Force flush the batch queue.
 | 
			
		||||
    async fn flush_batch(
 | 
			
		||||
    /// Run the batch for the specific commands.
 | 
			
		||||
    async fn run_batch(
 | 
			
		||||
        &self,
 | 
			
		||||
        // Whether or not to flush the end commands as well.
 | 
			
		||||
        // We only do this at the very end of the file.
 | 
			
		||||
        batch_end: bool,
 | 
			
		||||
        orig_requests: Vec<(WebSocketRequest, SourceRange)>,
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
    ) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
 | 
			
		||||
        let all_requests = if batch_end {
 | 
			
		||||
            let mut requests = self.take_batch().await.clone();
 | 
			
		||||
            requests.extend(self.take_batch_end().await.values().cloned());
 | 
			
		||||
            requests
 | 
			
		||||
        } else {
 | 
			
		||||
            self.take_batch().await.clone()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Return early if we have no commands to send.
 | 
			
		||||
        if all_requests.is_empty() {
 | 
			
		||||
        if orig_requests.is_empty() {
 | 
			
		||||
            return Ok(OkWebSocketResponseData::Modeling {
 | 
			
		||||
                modeling_response: OkModelingCmdResponse::Empty {},
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let requests: Vec<ModelingCmdReq> = all_requests
 | 
			
		||||
        let requests: Vec<ModelingCmdReq> = orig_requests
 | 
			
		||||
            .iter()
 | 
			
		||||
            .filter_map(|(val, _)| match val {
 | 
			
		||||
                WebSocketRequest::ModelingCmdReq(ModelingCmdReq { cmd, cmd_id }) => Some(ModelingCmdReq {
 | 
			
		||||
@ -411,9 +372,9 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
            responses: true,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let final_req = if all_requests.len() == 1 {
 | 
			
		||||
        let final_req = if orig_requests.len() == 1 {
 | 
			
		||||
            // We can unwrap here because we know the batch has only one element.
 | 
			
		||||
            all_requests.first().unwrap().0.clone()
 | 
			
		||||
            orig_requests.first().unwrap().0.clone()
 | 
			
		||||
        } else {
 | 
			
		||||
            batched_requests
 | 
			
		||||
        };
 | 
			
		||||
@ -421,7 +382,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
        // Create the map of original command IDs to source range.
 | 
			
		||||
        // This is for the wasm side, kurt needs it for selections.
 | 
			
		||||
        let mut id_to_source_range = HashMap::new();
 | 
			
		||||
        for (req, range) in all_requests.iter() {
 | 
			
		||||
        for (req, range) in orig_requests.iter() {
 | 
			
		||||
            match req {
 | 
			
		||||
                WebSocketRequest::ModelingCmdReq(ModelingCmdReq { cmd: _, cmd_id }) => {
 | 
			
		||||
                    id_to_source_range.insert(Uuid::from(*cmd_id), *range);
 | 
			
		||||
@ -436,7 +397,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Do the artifact commands.
 | 
			
		||||
        for (req, _) in all_requests.iter() {
 | 
			
		||||
        for (req, _) in orig_requests.iter() {
 | 
			
		||||
            match &req {
 | 
			
		||||
                WebSocketRequest::ModelingCmdBatchReq(ModelingBatch { requests, .. }) => {
 | 
			
		||||
                    for request in requests {
 | 
			
		||||
@ -506,6 +467,25 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Force flush the batch queue.
 | 
			
		||||
    async fn flush_batch(
 | 
			
		||||
        &self,
 | 
			
		||||
        // Whether or not to flush the end commands as well.
 | 
			
		||||
        // We only do this at the very end of the file.
 | 
			
		||||
        batch_end: bool,
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
    ) -> Result<OkWebSocketResponseData, crate::errors::KclError> {
 | 
			
		||||
        let all_requests = if batch_end {
 | 
			
		||||
            let mut requests = self.take_batch().await.clone();
 | 
			
		||||
            requests.extend(self.take_batch_end().await.values().cloned());
 | 
			
		||||
            requests
 | 
			
		||||
        } else {
 | 
			
		||||
            self.take_batch().await.clone()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        self.run_batch(all_requests, source_range).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn make_default_plane(
 | 
			
		||||
        &self,
 | 
			
		||||
        plane_id: uuid::Uuid,
 | 
			
		||||
 | 
			
		||||
@ -217,10 +217,13 @@ impl IntoDiagnostic for KclErrorWithOutputs {
 | 
			
		||||
    fn to_lsp_diagnostics(&self, code: &str) -> Vec<Diagnostic> {
 | 
			
		||||
        let message = self.error.get_message();
 | 
			
		||||
        let source_ranges = self.error.source_ranges();
 | 
			
		||||
        println!("self: {:?}", self);
 | 
			
		||||
 | 
			
		||||
        source_ranges
 | 
			
		||||
            .into_iter()
 | 
			
		||||
            .map(|source_range| {
 | 
			
		||||
                println!("source_range: {:?}", source_range);
 | 
			
		||||
                println!("filenames: {:?}", self.filenames);
 | 
			
		||||
                let source = self
 | 
			
		||||
                    .source_files
 | 
			
		||||
                    .get(&source_range.module_id())
 | 
			
		||||
 | 
			
		||||
@ -243,7 +243,7 @@ fn generate_changed_program(old_ast: Node<Program>, mut new_ast: Node<Program>,
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::execution::{parse_execute, ExecTestResults};
 | 
			
		||||
    use crate::execution::{parse_execute, parse_execute_with_project_dir, ExecTestResults};
 | 
			
		||||
 | 
			
		||||
    #[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
    async fn test_get_changed_program_same_code() {
 | 
			
		||||
@ -600,4 +600,64 @@ startSketchOn('XY')
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
    async fn test_multi_file_no_changes_does_not_reexecute() {
 | 
			
		||||
        let code = r#"import "toBeImported.kcl" as importedCube
 | 
			
		||||
 | 
			
		||||
importedCube
 | 
			
		||||
 | 
			
		||||
sketch001 = startSketchOn(XZ)
 | 
			
		||||
profile001 = startProfileAt([-134.53, -56.17], sketch001)
 | 
			
		||||
  |> angledLine(angle = 0, length = 79.05, tag = $rectangleSegmentA001)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 76.28)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $seg01)
 | 
			
		||||
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
 | 
			
		||||
  |> close()
 | 
			
		||||
extrude001 = extrude(profile001, length = 100)
 | 
			
		||||
sketch003 = startSketchOn(extrude001, face = seg02)
 | 
			
		||||
sketch002 = startSketchOn(extrude001, face = seg01)
 | 
			
		||||
"#;
 | 
			
		||||
 | 
			
		||||
        let other_file = (
 | 
			
		||||
            std::path::PathBuf::from("toBeImported.kcl"),
 | 
			
		||||
            r#"sketch001 = startSketchOn(XZ)
 | 
			
		||||
profile001 = startProfileAt([281.54, 305.81], sketch001)
 | 
			
		||||
  |> angledLine(angle = 0, length = 123.43, tag = $rectangleSegmentA001)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 85.99)
 | 
			
		||||
  |> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001))
 | 
			
		||||
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
 | 
			
		||||
  |> close()
 | 
			
		||||
extrude(profile001, length = 100)"#
 | 
			
		||||
                .to_string(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let tmp_dir = std::env::temp_dir();
 | 
			
		||||
        let tmp_dir = tmp_dir.join(uuid::Uuid::new_v4().to_string());
 | 
			
		||||
 | 
			
		||||
        // Create a temporary file for each of the other files.
 | 
			
		||||
        let tmp_file = tmp_dir.join(other_file.0);
 | 
			
		||||
        std::fs::create_dir_all(tmp_file.parent().unwrap()).unwrap();
 | 
			
		||||
        std::fs::write(tmp_file, other_file.1).unwrap();
 | 
			
		||||
 | 
			
		||||
        let ExecTestResults { program, exec_ctxt, .. } =
 | 
			
		||||
            parse_execute_with_project_dir(code, Some(tmp_dir)).await.unwrap();
 | 
			
		||||
 | 
			
		||||
        let mut new_program = crate::Program::parse_no_errs(code).unwrap();
 | 
			
		||||
        new_program.compute_digest();
 | 
			
		||||
 | 
			
		||||
        let result = get_changed_program(
 | 
			
		||||
            CacheInformation {
 | 
			
		||||
                ast: &program.ast,
 | 
			
		||||
                settings: &exec_ctxt.settings,
 | 
			
		||||
            },
 | 
			
		||||
            CacheInformation {
 | 
			
		||||
                ast: &new_program.ast,
 | 
			
		||||
                settings: &exec_ctxt.settings,
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
        .await;
 | 
			
		||||
 | 
			
		||||
        assert_eq!(result, CacheResult::NoAction(false));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,6 @@ use super::{
 | 
			
		||||
    types::{PrimitiveType, CHECK_NUMERIC_TYPES},
 | 
			
		||||
};
 | 
			
		||||
use crate::{
 | 
			
		||||
    engine::ExecutionKind,
 | 
			
		||||
    errors::{KclError, KclErrorDetails},
 | 
			
		||||
    execution::{
 | 
			
		||||
        annotations,
 | 
			
		||||
@ -66,15 +65,13 @@ impl ExecutorContext {
 | 
			
		||||
                        exec_state.mod_local.explicit_length_units = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    let new_units = exec_state.length_unit();
 | 
			
		||||
                    if !self.engine.execution_kind().await.is_isolated() {
 | 
			
		||||
                        self.engine
 | 
			
		||||
                            .set_units(
 | 
			
		||||
                                new_units.into(),
 | 
			
		||||
                                annotation.as_source_range(),
 | 
			
		||||
                                exec_state.id_generator(),
 | 
			
		||||
                            )
 | 
			
		||||
                            .await?;
 | 
			
		||||
                    }
 | 
			
		||||
                    self.engine
 | 
			
		||||
                        .set_units(
 | 
			
		||||
                            new_units.into(),
 | 
			
		||||
                            annotation.as_source_range(),
 | 
			
		||||
                            exec_state.id_generator(),
 | 
			
		||||
                        )
 | 
			
		||||
                        .await?;
 | 
			
		||||
                } else {
 | 
			
		||||
                    exec_state.err(CompilationError::err(
 | 
			
		||||
                        annotation.as_source_range(),
 | 
			
		||||
@ -104,15 +101,11 @@ impl ExecutorContext {
 | 
			
		||||
        &self,
 | 
			
		||||
        program: &Node<Program>,
 | 
			
		||||
        exec_state: &mut ExecState,
 | 
			
		||||
        exec_kind: ExecutionKind,
 | 
			
		||||
        preserve_mem: bool,
 | 
			
		||||
        module_id: ModuleId,
 | 
			
		||||
        path: &ModulePath,
 | 
			
		||||
    ) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
 | 
			
		||||
        crate::log::log(format!("enter module {path} {} {exec_kind:?}", exec_state.stack()));
 | 
			
		||||
 | 
			
		||||
        let old_units = exec_state.length_unit();
 | 
			
		||||
        let original_execution = self.engine.replace_execution_kind(exec_kind).await;
 | 
			
		||||
        crate::log::log(format!("enter module {path} {}", exec_state.stack()));
 | 
			
		||||
 | 
			
		||||
        let mut local_state = ModuleState::new(path.std_path(), exec_state.stack().memory.clone(), Some(module_id));
 | 
			
		||||
        if !preserve_mem {
 | 
			
		||||
@ -131,7 +124,6 @@ impl ExecutorContext {
 | 
			
		||||
            .exec_block(program, exec_state, crate::execution::BodyType::Root)
 | 
			
		||||
            .await;
 | 
			
		||||
 | 
			
		||||
        let new_units = exec_state.length_unit();
 | 
			
		||||
        let env_ref = if preserve_mem {
 | 
			
		||||
            exec_state.mut_stack().pop_and_preserve_env()
 | 
			
		||||
        } else {
 | 
			
		||||
@ -141,17 +133,6 @@ impl ExecutorContext {
 | 
			
		||||
            std::mem::swap(&mut exec_state.mod_local, &mut local_state);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // We only need to reset the units if we are not on the Main path.
 | 
			
		||||
        // If we reset at the end of the main path, then we just add on an extra
 | 
			
		||||
        // command and we'd need to flush the batch again.
 | 
			
		||||
        // This avoids that.
 | 
			
		||||
        if !exec_kind.is_isolated() && new_units != old_units && *path != ModulePath::Main {
 | 
			
		||||
            self.engine
 | 
			
		||||
                .set_units(old_units.into(), Default::default(), exec_state.id_generator())
 | 
			
		||||
                .await?;
 | 
			
		||||
        }
 | 
			
		||||
        self.engine.replace_execution_kind(original_execution).await;
 | 
			
		||||
 | 
			
		||||
        crate::log::log(format!("leave {path}"));
 | 
			
		||||
 | 
			
		||||
        result.map(|result| (result, env_ref, local_state.module_exports))
 | 
			
		||||
@ -161,7 +142,7 @@ impl ExecutorContext {
 | 
			
		||||
    #[async_recursion]
 | 
			
		||||
    pub(super) async fn exec_block<'a>(
 | 
			
		||||
        &'a self,
 | 
			
		||||
        program: NodeRef<'a, crate::parsing::ast::types::Program>,
 | 
			
		||||
        program: NodeRef<'a, Program>,
 | 
			
		||||
        exec_state: &mut ExecState,
 | 
			
		||||
        body_type: BodyType,
 | 
			
		||||
    ) -> Result<Option<KclValue>, KclError> {
 | 
			
		||||
@ -185,9 +166,8 @@ impl ExecutorContext {
 | 
			
		||||
 | 
			
		||||
                    match &import_stmt.selector {
 | 
			
		||||
                        ImportSelector::List { items } => {
 | 
			
		||||
                            let (env_ref, module_exports) = self
 | 
			
		||||
                                .exec_module_for_items(module_id, exec_state, ExecutionKind::Isolated, source_range)
 | 
			
		||||
                                .await?;
 | 
			
		||||
                            let (env_ref, module_exports) =
 | 
			
		||||
                                self.exec_module_for_items(module_id, exec_state, source_range).await?;
 | 
			
		||||
                            for import_item in items {
 | 
			
		||||
                                // Extract the item from the module.
 | 
			
		||||
                                let item = exec_state
 | 
			
		||||
@ -228,9 +208,8 @@ impl ExecutorContext {
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        ImportSelector::Glob(_) => {
 | 
			
		||||
                            let (env_ref, module_exports) = self
 | 
			
		||||
                                .exec_module_for_items(module_id, exec_state, ExecutionKind::Isolated, source_range)
 | 
			
		||||
                                .await?;
 | 
			
		||||
                            let (env_ref, module_exports) =
 | 
			
		||||
                                self.exec_module_for_items(module_id, exec_state, source_range).await?;
 | 
			
		||||
                            for name in module_exports.iter() {
 | 
			
		||||
                                let item = exec_state
 | 
			
		||||
                                    .stack()
 | 
			
		||||
@ -421,7 +400,7 @@ impl ExecutorContext {
 | 
			
		||||
        Ok(last_expr)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(super) async fn open_module(
 | 
			
		||||
    pub async fn open_module(
 | 
			
		||||
        &self,
 | 
			
		||||
        path: &ImportPath,
 | 
			
		||||
        attrs: &[Node<Annotation>],
 | 
			
		||||
@ -429,6 +408,7 @@ impl ExecutorContext {
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
    ) -> Result<ModuleId, KclError> {
 | 
			
		||||
        let resolved_path = ModulePath::from_import_path(path, &self.settings.project_directory);
 | 
			
		||||
 | 
			
		||||
        match path {
 | 
			
		||||
            ImportPath::Kcl { .. } => {
 | 
			
		||||
                exec_state.global.mod_loader.cycle_check(&resolved_path, source_range)?;
 | 
			
		||||
@ -485,7 +465,6 @@ impl ExecutorContext {
 | 
			
		||||
        &self,
 | 
			
		||||
        module_id: ModuleId,
 | 
			
		||||
        exec_state: &mut ExecState,
 | 
			
		||||
        exec_kind: ExecutionKind,
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
    ) -> Result<(EnvironmentRef, Vec<String>), KclError> {
 | 
			
		||||
        let path = exec_state.global.module_infos[&module_id].path.clone();
 | 
			
		||||
@ -494,12 +473,12 @@ impl ExecutorContext {
 | 
			
		||||
 | 
			
		||||
        let result = match &mut repr {
 | 
			
		||||
            ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
 | 
			
		||||
            ModuleRepr::Kcl(_, Some((env_ref, items))) => Ok((*env_ref, items.clone())),
 | 
			
		||||
            ModuleRepr::Kcl(_, Some((_, env_ref, items))) => Ok((*env_ref, items.clone())),
 | 
			
		||||
            ModuleRepr::Kcl(program, cache) => self
 | 
			
		||||
                .exec_module_from_ast(program, module_id, &path, exec_state, exec_kind, source_range)
 | 
			
		||||
                .exec_module_from_ast(program, module_id, &path, exec_state, source_range, false)
 | 
			
		||||
                .await
 | 
			
		||||
                .map(|(_, er, items)| {
 | 
			
		||||
                    *cache = Some((er, items.clone()));
 | 
			
		||||
                .map(|(val, er, items)| {
 | 
			
		||||
                    *cache = Some((val, er, items.clone()));
 | 
			
		||||
                    (er, items)
 | 
			
		||||
                }),
 | 
			
		||||
            ModuleRepr::Foreign(geom) => Err(KclError::Semantic(KclErrorDetails {
 | 
			
		||||
@ -518,7 +497,6 @@ impl ExecutorContext {
 | 
			
		||||
        module_id: ModuleId,
 | 
			
		||||
        module_name: &BoxNode<Name>,
 | 
			
		||||
        exec_state: &mut ExecState,
 | 
			
		||||
        exec_kind: ExecutionKind,
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
    ) -> Result<Option<KclValue>, KclError> {
 | 
			
		||||
        exec_state.global.operations.push(Operation::GroupBegin {
 | 
			
		||||
@ -535,13 +513,14 @@ impl ExecutorContext {
 | 
			
		||||
 | 
			
		||||
        let result = match &mut repr {
 | 
			
		||||
            ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
 | 
			
		||||
            ModuleRepr::Kcl(_, Some((val, _, _))) => Ok(val.clone()),
 | 
			
		||||
            ModuleRepr::Kcl(program, cached_items) => {
 | 
			
		||||
                let result = self
 | 
			
		||||
                    .exec_module_from_ast(program, module_id, &path, exec_state, exec_kind, source_range)
 | 
			
		||||
                    .exec_module_from_ast(program, module_id, &path, exec_state, source_range, false)
 | 
			
		||||
                    .await;
 | 
			
		||||
                match result {
 | 
			
		||||
                    Ok((val, env, items)) => {
 | 
			
		||||
                        *cached_items = Some((env, items));
 | 
			
		||||
                        *cached_items = Some((val.clone(), env, items));
 | 
			
		||||
                        Ok(val)
 | 
			
		||||
                    }
 | 
			
		||||
                    Err(e) => Err(e),
 | 
			
		||||
@ -560,18 +539,18 @@ impl ExecutorContext {
 | 
			
		||||
        result
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn exec_module_from_ast(
 | 
			
		||||
    pub async fn exec_module_from_ast(
 | 
			
		||||
        &self,
 | 
			
		||||
        program: &Node<Program>,
 | 
			
		||||
        module_id: ModuleId,
 | 
			
		||||
        path: &ModulePath,
 | 
			
		||||
        exec_state: &mut ExecState,
 | 
			
		||||
        exec_kind: ExecutionKind,
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
        preserve_mem: bool,
 | 
			
		||||
    ) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
 | 
			
		||||
        exec_state.global.mod_loader.enter_module(path);
 | 
			
		||||
        let result = self
 | 
			
		||||
            .exec_module_body(program, exec_state, exec_kind, false, module_id, path)
 | 
			
		||||
            .exec_module_body(program, exec_state, preserve_mem, module_id, path)
 | 
			
		||||
            .await;
 | 
			
		||||
        exec_state.global.mod_loader.leave_module(path);
 | 
			
		||||
 | 
			
		||||
@ -608,7 +587,7 @@ impl ExecutorContext {
 | 
			
		||||
            Expr::Name(name) => {
 | 
			
		||||
                let value = name.get_result(exec_state, self).await?.clone();
 | 
			
		||||
                if let KclValue::Module { value: module_id, meta } = value {
 | 
			
		||||
                    self.exec_module_for_result(module_id, name, exec_state, ExecutionKind::Normal, metadata.source_range)
 | 
			
		||||
                    self.exec_module_for_result(module_id, name, exec_state,  metadata.source_range)
 | 
			
		||||
                        .await?
 | 
			
		||||
                        .unwrap_or_else(|| {
 | 
			
		||||
                            exec_state.warn(CompilationError::err(
 | 
			
		||||
@ -808,7 +787,7 @@ impl Node<Name> {
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            mem_spec = Some(
 | 
			
		||||
                ctx.exec_module_for_items(*module_id, exec_state, ExecutionKind::Normal, p.as_source_range())
 | 
			
		||||
                ctx.exec_module_for_items(*module_id, exec_state, p.as_source_range())
 | 
			
		||||
                    .await?,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
@ -1320,7 +1299,7 @@ impl Node<CallExpressionKw> {
 | 
			
		||||
                    ));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let op = if func.feature_tree_operation() && !ctx.is_isolated_execution().await {
 | 
			
		||||
                let op = if func.feature_tree_operation() {
 | 
			
		||||
                    let op_labeled_args = args
 | 
			
		||||
                        .kw_args
 | 
			
		||||
                        .labeled
 | 
			
		||||
@ -1406,7 +1385,7 @@ impl Node<CallExpressionKw> {
 | 
			
		||||
                        e.add_source_ranges(vec![callsite])
 | 
			
		||||
                    })?;
 | 
			
		||||
 | 
			
		||||
                if matches!(fn_src, FunctionSource::User { .. }) && !ctx.is_isolated_execution().await {
 | 
			
		||||
                if matches!(fn_src, FunctionSource::User { .. }) {
 | 
			
		||||
                    // Track return operation.
 | 
			
		||||
                    exec_state.global.operations.push(Operation::GroupEnd);
 | 
			
		||||
                }
 | 
			
		||||
@ -1458,7 +1437,7 @@ impl Node<CallExpression> {
 | 
			
		||||
                    ));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let op = if func.feature_tree_operation() && !ctx.is_isolated_execution().await {
 | 
			
		||||
                let op = if func.feature_tree_operation() {
 | 
			
		||||
                    let op_labeled_args = func
 | 
			
		||||
                        .args(false)
 | 
			
		||||
                        .iter()
 | 
			
		||||
@ -1516,19 +1495,17 @@ impl Node<CallExpression> {
 | 
			
		||||
                // exec_state.
 | 
			
		||||
                let func = fn_name.get_result(exec_state, ctx).await?.clone();
 | 
			
		||||
 | 
			
		||||
                if !ctx.is_isolated_execution().await {
 | 
			
		||||
                    // Track call operation.
 | 
			
		||||
                    exec_state.global.operations.push(Operation::GroupBegin {
 | 
			
		||||
                        group: Group::FunctionCall {
 | 
			
		||||
                            name: Some(fn_name.to_string()),
 | 
			
		||||
                            function_source_range: func.function_def_source_range().unwrap_or_default(),
 | 
			
		||||
                            unlabeled_arg: None,
 | 
			
		||||
                            // TODO: Add the arguments for legacy positional parameters.
 | 
			
		||||
                            labeled_args: Default::default(),
 | 
			
		||||
                        },
 | 
			
		||||
                        source_range: callsite,
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
                // Track call operation.
 | 
			
		||||
                exec_state.global.operations.push(Operation::GroupBegin {
 | 
			
		||||
                    group: Group::FunctionCall {
 | 
			
		||||
                        name: Some(fn_name.to_string()),
 | 
			
		||||
                        function_source_range: func.function_def_source_range().unwrap_or_default(),
 | 
			
		||||
                        unlabeled_arg: None,
 | 
			
		||||
                        // TODO: Add the arguments for legacy positional parameters.
 | 
			
		||||
                        labeled_args: Default::default(),
 | 
			
		||||
                    },
 | 
			
		||||
                    source_range: callsite,
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                let Some(fn_src) = func.as_fn() else {
 | 
			
		||||
                    return Err(KclError::Semantic(KclErrorDetails {
 | 
			
		||||
@ -1557,10 +1534,8 @@ impl Node<CallExpression> {
 | 
			
		||||
                    })
 | 
			
		||||
                })?;
 | 
			
		||||
 | 
			
		||||
                if !ctx.is_isolated_execution().await {
 | 
			
		||||
                    // Track return operation.
 | 
			
		||||
                    exec_state.global.operations.push(Operation::GroupEnd);
 | 
			
		||||
                }
 | 
			
		||||
                // Track return operation.
 | 
			
		||||
                exec_state.global.operations.push(Operation::GroupEnd);
 | 
			
		||||
 | 
			
		||||
                Ok(result)
 | 
			
		||||
            }
 | 
			
		||||
@ -2313,7 +2288,7 @@ impl FunctionSource {
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let op = if props.include_in_feature_tree && !ctx.is_isolated_execution().await {
 | 
			
		||||
                let op = if props.include_in_feature_tree {
 | 
			
		||||
                    let op_labeled_args = args
 | 
			
		||||
                        .kw_args
 | 
			
		||||
                        .labeled
 | 
			
		||||
@ -2357,28 +2332,26 @@ impl FunctionSource {
 | 
			
		||||
                Ok(Some(result))
 | 
			
		||||
            }
 | 
			
		||||
            FunctionSource::User { ast, memory, .. } => {
 | 
			
		||||
                if !ctx.is_isolated_execution().await {
 | 
			
		||||
                    // Track call operation.
 | 
			
		||||
                    let op_labeled_args = args
 | 
			
		||||
                        .kw_args
 | 
			
		||||
                        .labeled
 | 
			
		||||
                        .iter()
 | 
			
		||||
                        .map(|(k, arg)| (k.clone(), OpArg::new(OpKclValue::from(&arg.value), arg.source_range)))
 | 
			
		||||
                        .collect();
 | 
			
		||||
                    exec_state.global.operations.push(Operation::GroupBegin {
 | 
			
		||||
                        group: Group::FunctionCall {
 | 
			
		||||
                            name: fn_name.clone(),
 | 
			
		||||
                            function_source_range: ast.as_source_range(),
 | 
			
		||||
                            unlabeled_arg: args
 | 
			
		||||
                                .kw_args
 | 
			
		||||
                                .unlabeled
 | 
			
		||||
                                .as_ref()
 | 
			
		||||
                                .map(|arg| OpArg::new(OpKclValue::from(&arg.value), arg.source_range)),
 | 
			
		||||
                            labeled_args: op_labeled_args,
 | 
			
		||||
                        },
 | 
			
		||||
                        source_range: callsite,
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
                // Track call operation.
 | 
			
		||||
                let op_labeled_args = args
 | 
			
		||||
                    .kw_args
 | 
			
		||||
                    .labeled
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|(k, arg)| (k.clone(), OpArg::new(OpKclValue::from(&arg.value), arg.source_range)))
 | 
			
		||||
                    .collect();
 | 
			
		||||
                exec_state.global.operations.push(Operation::GroupBegin {
 | 
			
		||||
                    group: Group::FunctionCall {
 | 
			
		||||
                        name: fn_name.clone(),
 | 
			
		||||
                        function_source_range: ast.as_source_range(),
 | 
			
		||||
                        unlabeled_arg: args
 | 
			
		||||
                            .kw_args
 | 
			
		||||
                            .unlabeled
 | 
			
		||||
                            .as_ref()
 | 
			
		||||
                            .map(|arg| OpArg::new(OpKclValue::from(&arg.value), arg.source_range)),
 | 
			
		||||
                        labeled_args: op_labeled_args,
 | 
			
		||||
                    },
 | 
			
		||||
                    source_range: callsite,
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                call_user_defined_function_kw(fn_name.as_deref(), args.kw_args, *memory, ast, exec_state, ctx).await
 | 
			
		||||
            }
 | 
			
		||||
@ -2391,10 +2364,13 @@ impl FunctionSource {
 | 
			
		||||
mod test {
 | 
			
		||||
    use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
    use tokio::io::AsyncWriteExt;
 | 
			
		||||
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::{
 | 
			
		||||
        execution::{memory::Stack, parse_execute, ContextType},
 | 
			
		||||
        parsing::ast::types::{DefaultParamVal, Identifier, Parameter},
 | 
			
		||||
        ExecutorSettings,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    #[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
@ -2504,7 +2480,7 @@ mod test {
 | 
			
		||||
            // Run each test.
 | 
			
		||||
            let func_expr = &Node::no_src(FunctionExpression {
 | 
			
		||||
                params,
 | 
			
		||||
                body: crate::parsing::ast::types::Program::empty(),
 | 
			
		||||
                body: Program::empty(),
 | 
			
		||||
                return_type: None,
 | 
			
		||||
                digest: None,
 | 
			
		||||
            });
 | 
			
		||||
@ -2607,6 +2583,102 @@ a = foo()
 | 
			
		||||
        assert!(result.unwrap_err().to_string().contains("return"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
    async fn load_all_modules() {
 | 
			
		||||
        // program a.kcl
 | 
			
		||||
        let programa_kcl = r#"
 | 
			
		||||
export a = 1
 | 
			
		||||
"#;
 | 
			
		||||
        // program b.kcl
 | 
			
		||||
        let programb_kcl = r#"
 | 
			
		||||
import a from 'a.kcl'
 | 
			
		||||
 | 
			
		||||
export b = a + 1
 | 
			
		||||
"#;
 | 
			
		||||
        // program c.kcl
 | 
			
		||||
        let programc_kcl = r#"
 | 
			
		||||
import a from 'a.kcl'
 | 
			
		||||
 | 
			
		||||
export c = a + 2
 | 
			
		||||
"#;
 | 
			
		||||
 | 
			
		||||
        // program main.kcl
 | 
			
		||||
        let main_kcl = r#"
 | 
			
		||||
import b from 'b.kcl'
 | 
			
		||||
import c from 'c.kcl'
 | 
			
		||||
 | 
			
		||||
d = b + c
 | 
			
		||||
"#;
 | 
			
		||||
 | 
			
		||||
        let main = crate::parsing::parse_str(main_kcl, ModuleId::default())
 | 
			
		||||
            .parse_errs_as_err()
 | 
			
		||||
            .unwrap();
 | 
			
		||||
 | 
			
		||||
        let tmpdir = tempdir::TempDir::new("zma_kcl_load_all_modules").unwrap();
 | 
			
		||||
 | 
			
		||||
        tokio::fs::File::create(tmpdir.path().join("main.kcl"))
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .write_all(main_kcl.as_bytes())
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap();
 | 
			
		||||
 | 
			
		||||
        tokio::fs::File::create(tmpdir.path().join("a.kcl"))
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .write_all(programa_kcl.as_bytes())
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap();
 | 
			
		||||
 | 
			
		||||
        tokio::fs::File::create(tmpdir.path().join("b.kcl"))
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .write_all(programb_kcl.as_bytes())
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap();
 | 
			
		||||
 | 
			
		||||
        tokio::fs::File::create(tmpdir.path().join("c.kcl"))
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .write_all(programc_kcl.as_bytes())
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap();
 | 
			
		||||
 | 
			
		||||
        let exec_ctxt = ExecutorContext {
 | 
			
		||||
            engine: Arc::new(Box::new(
 | 
			
		||||
                crate::engine::conn_mock::EngineConnection::new()
 | 
			
		||||
                    .await
 | 
			
		||||
                    .map_err(|err| {
 | 
			
		||||
                        KclError::Internal(crate::errors::KclErrorDetails {
 | 
			
		||||
                            message: format!("Failed to create mock engine connection: {}", err),
 | 
			
		||||
                            source_ranges: vec![SourceRange::default()],
 | 
			
		||||
                        })
 | 
			
		||||
                    })
 | 
			
		||||
                    .unwrap(),
 | 
			
		||||
            )),
 | 
			
		||||
            fs: Arc::new(crate::fs::FileManager::new()),
 | 
			
		||||
            settings: ExecutorSettings {
 | 
			
		||||
                project_directory: Some(tmpdir.path().into()),
 | 
			
		||||
                ..Default::default()
 | 
			
		||||
            },
 | 
			
		||||
            stdlib: Arc::new(crate::std::StdLib::new()),
 | 
			
		||||
            context_type: ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        let mut exec_state = ExecState::new(&exec_ctxt);
 | 
			
		||||
 | 
			
		||||
        exec_ctxt
 | 
			
		||||
            .run_concurrent(
 | 
			
		||||
                &crate::Program {
 | 
			
		||||
                    ast: main.clone(),
 | 
			
		||||
                    original_file_contents: "".to_owned(),
 | 
			
		||||
                },
 | 
			
		||||
                &mut exec_state,
 | 
			
		||||
                false,
 | 
			
		||||
            )
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
    async fn user_coercion() {
 | 
			
		||||
        let program = r#"fn foo(x: Axis2d) {
 | 
			
		||||
 | 
			
		||||
@ -4,13 +4,13 @@ use anyhow::Result;
 | 
			
		||||
use schemars::JsonSchema;
 | 
			
		||||
use serde::Serialize;
 | 
			
		||||
 | 
			
		||||
use super::{types::UnitLen, EnvironmentRef, ExecState, MetaSettings};
 | 
			
		||||
use crate::{
 | 
			
		||||
    errors::KclErrorDetails,
 | 
			
		||||
    execution::{
 | 
			
		||||
        annotations::{SETTINGS, SETTINGS_UNIT_LENGTH},
 | 
			
		||||
        types::{NumericType, PrimitiveType, RuntimeType},
 | 
			
		||||
        Face, Helix, ImportedGeometry, Metadata, Plane, Sketch, Solid, TagIdentifier,
 | 
			
		||||
        types::{NumericType, PrimitiveType, RuntimeType, UnitLen},
 | 
			
		||||
        EnvironmentRef, ExecState, Face, Helix, ImportedGeometry, MetaSettings, Metadata, Plane, Sketch, Solid,
 | 
			
		||||
        TagIdentifier,
 | 
			
		||||
    },
 | 
			
		||||
    parsing::ast::types::{
 | 
			
		||||
        DefaultParamVal, FunctionExpression, KclNone, Literal, LiteralValue, Node, TagDeclarator, TagNode,
 | 
			
		||||
 | 
			
		||||
@ -28,18 +28,18 @@ pub use state::{ExecState, MetaSettings};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    engine::EngineManager,
 | 
			
		||||
    errors::KclError,
 | 
			
		||||
    errors::{KclError, KclErrorDetails},
 | 
			
		||||
    execution::{
 | 
			
		||||
        artifact::build_artifact_graph,
 | 
			
		||||
        cache::{CacheInformation, CacheResult},
 | 
			
		||||
        types::{UnitAngle, UnitLen},
 | 
			
		||||
    },
 | 
			
		||||
    fs::FileManager,
 | 
			
		||||
    modules::{ModuleId, ModulePath},
 | 
			
		||||
    modules::{ModuleId, ModulePath, ModuleRepr},
 | 
			
		||||
    parsing::ast::types::{Expr, ImportPath, NodeRef},
 | 
			
		||||
    source_range::SourceRange,
 | 
			
		||||
    std::StdLib,
 | 
			
		||||
    CompilationError, ExecError, ExecutionKind, KclErrorWithOutputs,
 | 
			
		||||
    CompilationError, ExecError, KclErrorWithOutputs,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub(crate) mod annotations;
 | 
			
		||||
@ -495,13 +495,9 @@ impl ExecutorContext {
 | 
			
		||||
        self.context_type == ContextType::Mock || self.context_type == ContextType::MockCustomForwarded
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn is_isolated_execution(&self) -> bool {
 | 
			
		||||
        self.engine.execution_kind().await.is_isolated()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns true if we should not send engine commands for any reason.
 | 
			
		||||
    pub async fn no_engine_commands(&self) -> bool {
 | 
			
		||||
        self.is_mock() || self.is_isolated_execution().await
 | 
			
		||||
        self.is_mock()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn send_clear_scene(
 | 
			
		||||
@ -672,7 +668,7 @@ impl ExecutorContext {
 | 
			
		||||
            (program, exec_state, false)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let result = self.inner_run(&program, &mut exec_state, preserve_mem).await;
 | 
			
		||||
        let result = self.run_concurrent(&program, &mut exec_state, preserve_mem).await;
 | 
			
		||||
 | 
			
		||||
        if result.is_err() {
 | 
			
		||||
            cache::bust_cache().await;
 | 
			
		||||
@ -705,9 +701,210 @@ impl ExecutorContext {
 | 
			
		||||
        program: &crate::Program,
 | 
			
		||||
        exec_state: &mut ExecState,
 | 
			
		||||
    ) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
 | 
			
		||||
        self.run_concurrent(program, exec_state, false).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Perform the execution of a program.
 | 
			
		||||
    ///
 | 
			
		||||
    /// You can optionally pass in some initialization memory for partial
 | 
			
		||||
    /// execution.
 | 
			
		||||
    ///
 | 
			
		||||
    /// To access non-fatal errors and warnings, extract them from the `ExecState`.
 | 
			
		||||
    pub async fn run_single_threaded(
 | 
			
		||||
        &self,
 | 
			
		||||
        program: &crate::Program,
 | 
			
		||||
        exec_state: &mut ExecState,
 | 
			
		||||
    ) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
 | 
			
		||||
        exec_state.add_root_module_contents(program);
 | 
			
		||||
        self.eval_prelude(exec_state, SourceRange::synthetic())
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(KclErrorWithOutputs::no_outputs)?;
 | 
			
		||||
 | 
			
		||||
        self.inner_run(program, exec_state, false).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Perform the execution of a program using an (experimental!) concurrent
 | 
			
		||||
    /// execution model. This has the same signature as [Self::run].
 | 
			
		||||
    ///
 | 
			
		||||
    /// For now -- do not use this unless you're willing to accept some
 | 
			
		||||
    /// breakage.
 | 
			
		||||
    ///
 | 
			
		||||
    /// You can optionally pass in some initialization memory for partial
 | 
			
		||||
    /// execution.
 | 
			
		||||
    ///
 | 
			
		||||
    /// To access non-fatal errors and warnings, extract them from the `ExecState`.
 | 
			
		||||
    pub async fn run_concurrent(
 | 
			
		||||
        &self,
 | 
			
		||||
        program: &crate::Program,
 | 
			
		||||
        exec_state: &mut ExecState,
 | 
			
		||||
        preserve_mem: bool,
 | 
			
		||||
    ) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
 | 
			
		||||
        exec_state.add_root_module_contents(program);
 | 
			
		||||
        self.eval_prelude(exec_state, SourceRange::synthetic())
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(KclErrorWithOutputs::no_outputs)?;
 | 
			
		||||
 | 
			
		||||
        let mut universe = std::collections::HashMap::new();
 | 
			
		||||
 | 
			
		||||
        let default_planes = self.engine.get_default_planes().read().await.clone();
 | 
			
		||||
        crate::walk::import_universe(self, &program.ast, &mut universe, exec_state)
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(|err| {
 | 
			
		||||
                let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
 | 
			
		||||
                    .global
 | 
			
		||||
                    .path_to_source_id
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|(k, v)| ((*v), k.clone()))
 | 
			
		||||
                    .collect();
 | 
			
		||||
 | 
			
		||||
                KclErrorWithOutputs::new(
 | 
			
		||||
                    err,
 | 
			
		||||
                    exec_state.global.operations.clone(),
 | 
			
		||||
                    exec_state.global.artifact_commands.clone(),
 | 
			
		||||
                    exec_state.global.artifact_graph.clone(),
 | 
			
		||||
                    module_id_to_module_path,
 | 
			
		||||
                    exec_state.global.id_to_source.clone(),
 | 
			
		||||
                    default_planes.clone(),
 | 
			
		||||
                )
 | 
			
		||||
            })?;
 | 
			
		||||
 | 
			
		||||
        for modules in crate::walk::import_graph(&universe, self)
 | 
			
		||||
            .map_err(|err| {
 | 
			
		||||
                let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
 | 
			
		||||
                    .global
 | 
			
		||||
                    .path_to_source_id
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|(k, v)| ((*v), k.clone()))
 | 
			
		||||
                    .collect();
 | 
			
		||||
 | 
			
		||||
                KclErrorWithOutputs::new(
 | 
			
		||||
                    err,
 | 
			
		||||
                    exec_state.global.operations.clone(),
 | 
			
		||||
                    exec_state.global.artifact_commands.clone(),
 | 
			
		||||
                    exec_state.global.artifact_graph.clone(),
 | 
			
		||||
                    module_id_to_module_path,
 | 
			
		||||
                    exec_state.global.id_to_source.clone(),
 | 
			
		||||
                    default_planes.clone(),
 | 
			
		||||
                )
 | 
			
		||||
            })?
 | 
			
		||||
            .into_iter()
 | 
			
		||||
        {
 | 
			
		||||
            #[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
            let mut set = tokio::task::JoinSet::new();
 | 
			
		||||
 | 
			
		||||
            #[allow(clippy::type_complexity)]
 | 
			
		||||
            let (results_tx, mut results_rx): (
 | 
			
		||||
                tokio::sync::mpsc::Sender<(
 | 
			
		||||
                    ModuleId,
 | 
			
		||||
                    ModulePath,
 | 
			
		||||
                    Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError>,
 | 
			
		||||
                )>,
 | 
			
		||||
                tokio::sync::mpsc::Receiver<_>,
 | 
			
		||||
            ) = tokio::sync::mpsc::channel(1);
 | 
			
		||||
 | 
			
		||||
            for module in modules {
 | 
			
		||||
                let Some((import_stmt, module_id, module_path, program)) = universe.get(&module) else {
 | 
			
		||||
                    return Err(KclErrorWithOutputs::no_outputs(KclError::Internal(KclErrorDetails {
 | 
			
		||||
                        message: format!("Module {module} not found in universe"),
 | 
			
		||||
                        source_ranges: Default::default(),
 | 
			
		||||
                    })));
 | 
			
		||||
                };
 | 
			
		||||
                let module_id = *module_id;
 | 
			
		||||
                let module_path = module_path.clone();
 | 
			
		||||
                let program = program.clone();
 | 
			
		||||
                let exec_state = exec_state.clone();
 | 
			
		||||
                let exec_ctxt = self.clone();
 | 
			
		||||
                let results_tx = results_tx.clone();
 | 
			
		||||
                let source_range = SourceRange::from(import_stmt);
 | 
			
		||||
 | 
			
		||||
                #[cfg(target_arch = "wasm32")]
 | 
			
		||||
                {
 | 
			
		||||
                    wasm_bindgen_futures::spawn_local(async move {
 | 
			
		||||
                        //set.spawn(async move {
 | 
			
		||||
                        let mut exec_state = exec_state;
 | 
			
		||||
                        let exec_ctxt = exec_ctxt;
 | 
			
		||||
 | 
			
		||||
                        let result = exec_ctxt
 | 
			
		||||
                            .exec_module_from_ast(
 | 
			
		||||
                                &program,
 | 
			
		||||
                                module_id,
 | 
			
		||||
                                &module_path,
 | 
			
		||||
                                &mut exec_state,
 | 
			
		||||
                                source_range,
 | 
			
		||||
                                false,
 | 
			
		||||
                            )
 | 
			
		||||
                            .await;
 | 
			
		||||
 | 
			
		||||
                        results_tx
 | 
			
		||||
                            .send((module_id, module_path, result))
 | 
			
		||||
                            .await
 | 
			
		||||
                            .unwrap_or_default();
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
                #[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
                {
 | 
			
		||||
                    set.spawn(async move {
 | 
			
		||||
                        let mut exec_state = exec_state;
 | 
			
		||||
                        let exec_ctxt = exec_ctxt;
 | 
			
		||||
 | 
			
		||||
                        let result = exec_ctxt
 | 
			
		||||
                            .exec_module_from_ast(
 | 
			
		||||
                                &program,
 | 
			
		||||
                                module_id,
 | 
			
		||||
                                &module_path,
 | 
			
		||||
                                &mut exec_state,
 | 
			
		||||
                                source_range,
 | 
			
		||||
                                false,
 | 
			
		||||
                            )
 | 
			
		||||
                            .await;
 | 
			
		||||
 | 
			
		||||
                        results_tx
 | 
			
		||||
                            .send((module_id, module_path, result))
 | 
			
		||||
                            .await
 | 
			
		||||
                            .unwrap_or_default();
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            drop(results_tx);
 | 
			
		||||
 | 
			
		||||
            while let Some((module_id, _, result)) = results_rx.recv().await {
 | 
			
		||||
                match result {
 | 
			
		||||
                    Ok((val, session_data, variables)) => {
 | 
			
		||||
                        let mut repr = exec_state.global.module_infos[&module_id].take_repr();
 | 
			
		||||
 | 
			
		||||
                        let ModuleRepr::Kcl(_, cache) = &mut repr else {
 | 
			
		||||
                            continue;
 | 
			
		||||
                        };
 | 
			
		||||
                        *cache = Some((val, session_data, variables));
 | 
			
		||||
 | 
			
		||||
                        exec_state.global.module_infos[&module_id].restore_repr(repr);
 | 
			
		||||
                    }
 | 
			
		||||
                    Err(e) => {
 | 
			
		||||
                        let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
 | 
			
		||||
                            .global
 | 
			
		||||
                            .path_to_source_id
 | 
			
		||||
                            .iter()
 | 
			
		||||
                            .map(|(k, v)| ((*v), k.clone()))
 | 
			
		||||
                            .collect();
 | 
			
		||||
 | 
			
		||||
                        return Err(KclErrorWithOutputs::new(
 | 
			
		||||
                            e,
 | 
			
		||||
                            exec_state.global.operations.clone(),
 | 
			
		||||
                            exec_state.global.artifact_commands.clone(),
 | 
			
		||||
                            exec_state.global.artifact_graph.clone(),
 | 
			
		||||
                            module_id_to_module_path,
 | 
			
		||||
                            exec_state.global.id_to_source.clone(),
 | 
			
		||||
                            default_planes,
 | 
			
		||||
                        ));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.inner_run(program, exec_state, preserve_mem).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Perform the execution of a program.  Accept all possible parameters and
 | 
			
		||||
    /// output everything.
 | 
			
		||||
    async fn inner_run(
 | 
			
		||||
@ -716,8 +913,6 @@ impl ExecutorContext {
 | 
			
		||||
        exec_state: &mut ExecState,
 | 
			
		||||
        preserve_mem: bool,
 | 
			
		||||
    ) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
 | 
			
		||||
        exec_state.add_root_module_contents(program);
 | 
			
		||||
 | 
			
		||||
        let _stats = crate::log::LogPerfStats::new("Interpretation");
 | 
			
		||||
 | 
			
		||||
        // Re-apply the settings, in case the cache was busted.
 | 
			
		||||
@ -783,7 +978,6 @@ impl ExecutorContext {
 | 
			
		||||
            .exec_module_body(
 | 
			
		||||
                program,
 | 
			
		||||
                exec_state,
 | 
			
		||||
                ExecutionKind::Normal,
 | 
			
		||||
                preserve_mem,
 | 
			
		||||
                ModuleId::default(),
 | 
			
		||||
                &ModulePath::Main,
 | 
			
		||||
@ -837,9 +1031,7 @@ impl ExecutorContext {
 | 
			
		||||
                    source_range,
 | 
			
		||||
                )
 | 
			
		||||
                .await?;
 | 
			
		||||
            let (module_memory, _) = self
 | 
			
		||||
                .exec_module_for_items(id, exec_state, ExecutionKind::Isolated, source_range)
 | 
			
		||||
                .await?;
 | 
			
		||||
            let (module_memory, _) = self.exec_module_for_items(id, exec_state, source_range).await?;
 | 
			
		||||
 | 
			
		||||
            exec_state.mut_stack().memory.set_std(module_memory);
 | 
			
		||||
        }
 | 
			
		||||
@ -947,6 +1139,14 @@ impl ExecutorContext {
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
pub(crate) async fn parse_execute(code: &str) -> Result<ExecTestResults, KclError> {
 | 
			
		||||
    parse_execute_with_project_dir(code, None).await
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
pub(crate) async fn parse_execute_with_project_dir(
 | 
			
		||||
    code: &str,
 | 
			
		||||
    project_directory: Option<std::path::PathBuf>,
 | 
			
		||||
) -> Result<ExecTestResults, KclError> {
 | 
			
		||||
    let program = crate::Program::parse_no_errs(code)?;
 | 
			
		||||
 | 
			
		||||
    let exec_ctxt = ExecutorContext {
 | 
			
		||||
@ -960,7 +1160,10 @@ pub(crate) async fn parse_execute(code: &str) -> Result<ExecTestResults, KclErro
 | 
			
		||||
        )),
 | 
			
		||||
        fs: Arc::new(crate::fs::FileManager::new()),
 | 
			
		||||
        stdlib: Arc::new(crate::std::StdLib::new()),
 | 
			
		||||
        settings: Default::default(),
 | 
			
		||||
        settings: ExecutorSettings {
 | 
			
		||||
            project_directory,
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        },
 | 
			
		||||
        context_type: ContextType::Mock,
 | 
			
		||||
    };
 | 
			
		||||
    let mut exec_state = ExecState::new(&exec_ctxt);
 | 
			
		||||
 | 
			
		||||
@ -229,6 +229,10 @@ impl ExecState {
 | 
			
		||||
        self.global.module_infos.insert(id, module_info);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_module(&mut self, id: ModuleId) -> Option<&ModuleInfo> {
 | 
			
		||||
        self.global.module_infos.get(&id)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn current_default_units(&self) -> NumericType {
 | 
			
		||||
        NumericType::Default {
 | 
			
		||||
            len: self.length_unit(),
 | 
			
		||||
 | 
			
		||||
@ -76,12 +76,12 @@ pub mod std;
 | 
			
		||||
pub mod test_server;
 | 
			
		||||
mod thread;
 | 
			
		||||
mod unparser;
 | 
			
		||||
mod walk;
 | 
			
		||||
pub mod walk;
 | 
			
		||||
#[cfg(target_arch = "wasm32")]
 | 
			
		||||
mod wasm;
 | 
			
		||||
 | 
			
		||||
pub use coredump::CoreDump;
 | 
			
		||||
pub use engine::{EngineManager, EngineStats, ExecutionKind};
 | 
			
		||||
pub use engine::{EngineManager, EngineStats};
 | 
			
		||||
pub use errors::{
 | 
			
		||||
    CompilationError, ConnectionError, ExecError, KclError, KclErrorWithOutputs, Report, ReportWithOutputs,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    errors::{KclError, KclErrorDetails},
 | 
			
		||||
    exec::KclValue,
 | 
			
		||||
    execution::{EnvironmentRef, PreImportedGeometry},
 | 
			
		||||
    fs::{FileManager, FileSystem},
 | 
			
		||||
    parsing::ast::types::{ImportPath, Node, Program},
 | 
			
		||||
@ -94,7 +95,7 @@ pub(crate) fn read_std(mod_name: &str) -> Option<&'static str> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Info about a module.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Serialize)]
 | 
			
		||||
pub struct ModuleInfo {
 | 
			
		||||
    /// The ID of the module.
 | 
			
		||||
    pub(crate) id: ModuleId,
 | 
			
		||||
@ -117,11 +118,11 @@ impl ModuleInfo {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(clippy::large_enum_variant)]
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Serialize)]
 | 
			
		||||
pub enum ModuleRepr {
 | 
			
		||||
    Root,
 | 
			
		||||
    // AST, memory, exported names
 | 
			
		||||
    Kcl(Node<Program>, Option<(EnvironmentRef, Vec<String>)>),
 | 
			
		||||
    Kcl(Node<Program>, Option<(Option<KclValue>, EnvironmentRef, Vec<String>)>),
 | 
			
		||||
    Foreign(PreImportedGeometry),
 | 
			
		||||
    Dummy,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
use std::{
 | 
			
		||||
    collections::HashMap,
 | 
			
		||||
    panic::{catch_unwind, AssertUnwindSafe},
 | 
			
		||||
    path::{Path, PathBuf},
 | 
			
		||||
};
 | 
			
		||||
@ -251,6 +252,38 @@ fn assert_common_snapshots(
 | 
			
		||||
    artifact_commands: Vec<ArtifactCommand>,
 | 
			
		||||
    artifact_graph: ArtifactGraph,
 | 
			
		||||
) {
 | 
			
		||||
    let artifact_commands = {
 | 
			
		||||
        // Due to our newfound concurrency, we're going to mess with the
 | 
			
		||||
        // artifact_commands a bit -- we're going to maintain the order,
 | 
			
		||||
        // but only for a given module ID. This means the artifact_commands
 | 
			
		||||
        // is no longer meaningful, but it is deterministic and will hopefully
 | 
			
		||||
        // catch meaningful changes in behavior.
 | 
			
		||||
 | 
			
		||||
        let mut artifact_commands_map = artifact_commands
 | 
			
		||||
            .into_iter()
 | 
			
		||||
            .map(|v| (v.range.module_id().as_usize(), v))
 | 
			
		||||
            .fold(
 | 
			
		||||
                HashMap::<usize, Vec<ArtifactCommand>>::new(),
 | 
			
		||||
                |mut map, (module_id, el)| {
 | 
			
		||||
                    let mut v = map.remove(&module_id).unwrap_or_default();
 | 
			
		||||
                    v.push(el);
 | 
			
		||||
                    map.insert(module_id, v);
 | 
			
		||||
                    map
 | 
			
		||||
                },
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
        let mut artifact_commands_keys = artifact_commands_map.keys().cloned().collect::<Vec<_>>();
 | 
			
		||||
        artifact_commands_keys.sort();
 | 
			
		||||
 | 
			
		||||
        let artifact_commands: Vec<ArtifactCommand> = artifact_commands_keys
 | 
			
		||||
            .iter()
 | 
			
		||||
            .flat_map(|idx| artifact_commands_map.remove(idx).unwrap())
 | 
			
		||||
            .collect();
 | 
			
		||||
 | 
			
		||||
        assert_eq!(0, artifact_commands_map.len());
 | 
			
		||||
        artifact_commands
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let result1 = catch_unwind(AssertUnwindSafe(|| {
 | 
			
		||||
        assert_snapshot(test, "Operations executed", || {
 | 
			
		||||
            insta::assert_json_snapshot!("ops", operations, {
 | 
			
		||||
 | 
			
		||||
@ -86,7 +86,7 @@ async fn do_execute_and_snapshot(
 | 
			
		||||
) -> Result<(ExecState, EnvironmentRef, image::DynamicImage), ExecErrorWithState> {
 | 
			
		||||
    let mut exec_state = ExecState::new(ctx);
 | 
			
		||||
    let result = ctx
 | 
			
		||||
        .run(&program, &mut exec_state)
 | 
			
		||||
        .run_single_threaded(&program, &mut exec_state)
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(|err| ExecErrorWithState::new(err.into(), exec_state.clone()))?;
 | 
			
		||||
    for e in exec_state.errors() {
 | 
			
		||||
 | 
			
		||||
@ -6,31 +6,37 @@ use std::{
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    parsing::ast::types::{ImportPath, NodeRef, Program},
 | 
			
		||||
    errors::KclErrorDetails,
 | 
			
		||||
    modules::{ModulePath, ModuleRepr},
 | 
			
		||||
    parsing::ast::types::{ImportPath, ImportStatement, Node as AstNode, NodeRef, Program},
 | 
			
		||||
    walk::{Node, Visitable},
 | 
			
		||||
    ExecState, ExecutorContext, KclError, ModuleId, SourceRange,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Specific dependency between two modules. The 0th element of this tuple
 | 
			
		||||
/// Specific dependency between two modules. The 0th element of this info
 | 
			
		||||
/// is the "importing" module, the 1st is the "imported" module. The 0th
 | 
			
		||||
/// module *depends on* the 1st module.
 | 
			
		||||
type Dependency = (String, String);
 | 
			
		||||
 | 
			
		||||
type Graph = Vec<Dependency>;
 | 
			
		||||
 | 
			
		||||
type DependencyInfo = (AstNode<ImportStatement>, ModuleId, ModulePath, AstNode<Program>);
 | 
			
		||||
type Universe = HashMap<String, DependencyInfo>;
 | 
			
		||||
 | 
			
		||||
/// Process a number of programs, returning the graph of dependencies.
 | 
			
		||||
///
 | 
			
		||||
/// This will (currently) return a list of lists of IDs that can be safely
 | 
			
		||||
/// run concurrently. Each "stage" is blocking in this model, which will
 | 
			
		||||
/// change in the future. Don't use this function widely, yet.
 | 
			
		||||
#[allow(clippy::iter_over_hash_type)]
 | 
			
		||||
pub fn import_graph(progs: HashMap<String, NodeRef<'_, Program>>) -> Result<Vec<Vec<String>>> {
 | 
			
		||||
pub fn import_graph(progs: &Universe, ctx: &ExecutorContext) -> Result<Vec<Vec<String>>, KclError> {
 | 
			
		||||
    let mut graph = Graph::new();
 | 
			
		||||
 | 
			
		||||
    for (name, program) in progs.iter() {
 | 
			
		||||
    for (name, (_, _, _, program)) in progs.iter() {
 | 
			
		||||
        graph.extend(
 | 
			
		||||
            import_dependencies(program)?
 | 
			
		||||
            import_dependencies(program, ctx)?
 | 
			
		||||
                .into_iter()
 | 
			
		||||
                .map(|dependency| (name.clone(), dependency))
 | 
			
		||||
                .map(|(dependency, _, _)| (name.clone(), dependency))
 | 
			
		||||
                .collect::<Vec<_>>(),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
@ -40,7 +46,10 @@ pub fn import_graph(progs: HashMap<String, NodeRef<'_, Program>>) -> Result<Vec<
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(clippy::iter_over_hash_type)]
 | 
			
		||||
fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>> {
 | 
			
		||||
fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>, KclError> {
 | 
			
		||||
    if all_modules.is_empty() {
 | 
			
		||||
        return Ok(vec![]);
 | 
			
		||||
    }
 | 
			
		||||
    let mut dep_map = HashMap::<String, Vec<String>>::new();
 | 
			
		||||
 | 
			
		||||
    for (dependent, dependency) in graph.iter() {
 | 
			
		||||
@ -83,7 +92,13 @@ fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>> {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if stage_modules.is_empty() {
 | 
			
		||||
            anyhow::bail!("imports are acyclic");
 | 
			
		||||
            waiting_modules.sort();
 | 
			
		||||
 | 
			
		||||
            return Err(KclError::ImportCycle(KclErrorDetails {
 | 
			
		||||
                message: format!("circular import of modules not allowed: {}", waiting_modules.join(", ")),
 | 
			
		||||
                // TODO: we can get the right import lines from the AST, but we don't
 | 
			
		||||
                source_ranges: vec![SourceRange::default()],
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // not strictly needed here, but perhaps helpful to avoid thinking
 | 
			
		||||
@ -101,33 +116,97 @@ fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>> {
 | 
			
		||||
    Ok(order)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn import_dependencies(prog: NodeRef<'_, Program>) -> Result<Vec<String>> {
 | 
			
		||||
type ImportDependencies = Vec<(String, AstNode<ImportStatement>, ModulePath)>;
 | 
			
		||||
 | 
			
		||||
pub(crate) fn import_dependencies(
 | 
			
		||||
    prog: NodeRef<Program>,
 | 
			
		||||
    ctx: &ExecutorContext,
 | 
			
		||||
) -> Result<ImportDependencies, KclError> {
 | 
			
		||||
    let ret = Arc::new(Mutex::new(vec![]));
 | 
			
		||||
 | 
			
		||||
    fn walk(ret: Arc<Mutex<Vec<String>>>, node: Node<'_>) {
 | 
			
		||||
    fn walk(ret: Arc<Mutex<ImportDependencies>>, node: Node<'_>, ctx: &ExecutorContext) -> Result<(), KclError> {
 | 
			
		||||
        if let Node::ImportStatement(is) = node {
 | 
			
		||||
            let dependency = match &is.path {
 | 
			
		||||
                ImportPath::Kcl { filename } => filename.to_string(),
 | 
			
		||||
                ImportPath::Foreign { path } => path.to_string(),
 | 
			
		||||
                ImportPath::Std { path } => path.join("::"),
 | 
			
		||||
            };
 | 
			
		||||
            // We only care about Kcl imports for now.
 | 
			
		||||
            if let ImportPath::Kcl { filename } = &is.path {
 | 
			
		||||
                let resolved_path = ModulePath::from_import_path(&is.path, &ctx.settings.project_directory);
 | 
			
		||||
 | 
			
		||||
            ret.lock().unwrap().push(dependency);
 | 
			
		||||
                // We need to lock the mutex to push the dependency.
 | 
			
		||||
                // This is a bit of a hack, but it works for now.
 | 
			
		||||
                ret.lock()
 | 
			
		||||
                    .map_err(|err| {
 | 
			
		||||
                        KclError::Internal(KclErrorDetails {
 | 
			
		||||
                            message: format!("Failed to lock mutex: {}", err),
 | 
			
		||||
                            source_ranges: Default::default(),
 | 
			
		||||
                        })
 | 
			
		||||
                    })?
 | 
			
		||||
                    .push((filename.to_string(), is.clone(), resolved_path));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for child in node.children().iter() {
 | 
			
		||||
            walk(ret.clone(), *child)
 | 
			
		||||
            walk(ret.clone(), *child, ctx)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    walk(ret.clone(), prog.into());
 | 
			
		||||
    walk(ret.clone(), prog.into(), ctx)?;
 | 
			
		||||
 | 
			
		||||
    let ret = ret.lock().unwrap().clone();
 | 
			
		||||
    Ok(ret)
 | 
			
		||||
    let ret = ret.lock().map_err(|err| {
 | 
			
		||||
        KclError::Internal(KclErrorDetails {
 | 
			
		||||
            message: format!("Failed to lock mutex: {}", err),
 | 
			
		||||
            source_ranges: Default::default(),
 | 
			
		||||
        })
 | 
			
		||||
    })?;
 | 
			
		||||
 | 
			
		||||
    Ok(ret.clone())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) async fn import_universe(
 | 
			
		||||
    ctx: &ExecutorContext,
 | 
			
		||||
    prog: NodeRef<'_, Program>,
 | 
			
		||||
    out: &mut Universe,
 | 
			
		||||
    exec_state: &mut ExecState,
 | 
			
		||||
) -> Result<(), KclError> {
 | 
			
		||||
    let modules = import_dependencies(prog, ctx)?;
 | 
			
		||||
    for (filename, import_stmt, module_path) in modules {
 | 
			
		||||
        if out.contains_key(&filename) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let module_id = ctx
 | 
			
		||||
            .open_module(&import_stmt.path, &[], exec_state, Default::default())
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        let program = {
 | 
			
		||||
            let Some(module_info) = exec_state.get_module(module_id) else {
 | 
			
		||||
                return Err(KclError::Internal(KclErrorDetails {
 | 
			
		||||
                    message: format!("Module {} not found", module_id),
 | 
			
		||||
                    source_ranges: vec![import_stmt.into()],
 | 
			
		||||
                }));
 | 
			
		||||
            };
 | 
			
		||||
            let ModuleRepr::Kcl(program, _) = &module_info.repr else {
 | 
			
		||||
                // if it's not a KCL module we can skip it since it has no
 | 
			
		||||
                // dependencies.
 | 
			
		||||
                continue;
 | 
			
		||||
            };
 | 
			
		||||
            program.clone()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        out.insert(
 | 
			
		||||
            filename.clone(),
 | 
			
		||||
            (import_stmt.clone(), module_id, module_path.clone(), program.clone()),
 | 
			
		||||
        );
 | 
			
		||||
        Box::pin(import_universe(ctx, &program, out, exec_state)).await?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::parsing::ast::types::ImportSelector;
 | 
			
		||||
 | 
			
		||||
    macro_rules! kcl {
 | 
			
		||||
        ( $kcl:expr ) => {{
 | 
			
		||||
@ -135,26 +214,41 @@ mod tests {
 | 
			
		||||
        }};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn order_imports() {
 | 
			
		||||
    fn into_module_info(program: AstNode<Program>) -> DependencyInfo {
 | 
			
		||||
        (
 | 
			
		||||
            AstNode::no_src(ImportStatement {
 | 
			
		||||
                selector: ImportSelector::None { alias: None },
 | 
			
		||||
                path: ImportPath::Kcl { filename: "".into() },
 | 
			
		||||
                visibility: Default::default(),
 | 
			
		||||
                digest: None,
 | 
			
		||||
            }),
 | 
			
		||||
            ModuleId::default(),
 | 
			
		||||
            ModulePath::Local { value: "".into() },
 | 
			
		||||
            program,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[tokio::test]
 | 
			
		||||
    async fn order_imports() {
 | 
			
		||||
        let mut modules = HashMap::new();
 | 
			
		||||
 | 
			
		||||
        let a = kcl!("");
 | 
			
		||||
        modules.insert("a.kcl".to_owned(), &a);
 | 
			
		||||
        modules.insert("a.kcl".to_owned(), into_module_info(a));
 | 
			
		||||
 | 
			
		||||
        let b = kcl!(
 | 
			
		||||
            "
 | 
			
		||||
import \"a.kcl\"
 | 
			
		||||
"
 | 
			
		||||
        );
 | 
			
		||||
        modules.insert("b.kcl".to_owned(), &b);
 | 
			
		||||
        modules.insert("b.kcl".to_owned(), into_module_info(b));
 | 
			
		||||
 | 
			
		||||
        let order = import_graph(modules).unwrap();
 | 
			
		||||
        let ctx = ExecutorContext::new_mock().await;
 | 
			
		||||
        let order = import_graph(&modules, &ctx).unwrap();
 | 
			
		||||
        assert_eq!(vec![vec!["a.kcl".to_owned()], vec!["b.kcl".to_owned()]], order);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn order_imports_none() {
 | 
			
		||||
    #[tokio::test]
 | 
			
		||||
    async fn order_imports_none() {
 | 
			
		||||
        let mut modules = HashMap::new();
 | 
			
		||||
 | 
			
		||||
        let a = kcl!(
 | 
			
		||||
@ -162,49 +256,51 @@ import \"a.kcl\"
 | 
			
		||||
y = 2
 | 
			
		||||
"
 | 
			
		||||
        );
 | 
			
		||||
        modules.insert("a.kcl".to_owned(), &a);
 | 
			
		||||
        modules.insert("a.kcl".to_owned(), into_module_info(a));
 | 
			
		||||
 | 
			
		||||
        let b = kcl!(
 | 
			
		||||
            "
 | 
			
		||||
x = 1
 | 
			
		||||
"
 | 
			
		||||
        );
 | 
			
		||||
        modules.insert("b.kcl".to_owned(), &b);
 | 
			
		||||
        modules.insert("b.kcl".to_owned(), into_module_info(b));
 | 
			
		||||
 | 
			
		||||
        let order = import_graph(modules).unwrap();
 | 
			
		||||
        let ctx = ExecutorContext::new_mock().await;
 | 
			
		||||
        let order = import_graph(&modules, &ctx).unwrap();
 | 
			
		||||
        assert_eq!(vec![vec!["a.kcl".to_owned(), "b.kcl".to_owned()]], order);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn order_imports_2() {
 | 
			
		||||
    #[tokio::test]
 | 
			
		||||
    async fn order_imports_2() {
 | 
			
		||||
        let mut modules = HashMap::new();
 | 
			
		||||
 | 
			
		||||
        let a = kcl!("");
 | 
			
		||||
        modules.insert("a.kcl".to_owned(), &a);
 | 
			
		||||
        modules.insert("a.kcl".to_owned(), into_module_info(a));
 | 
			
		||||
 | 
			
		||||
        let b = kcl!(
 | 
			
		||||
            "
 | 
			
		||||
import \"a.kcl\"
 | 
			
		||||
"
 | 
			
		||||
        );
 | 
			
		||||
        modules.insert("b.kcl".to_owned(), &b);
 | 
			
		||||
        modules.insert("b.kcl".to_owned(), into_module_info(b));
 | 
			
		||||
 | 
			
		||||
        let c = kcl!(
 | 
			
		||||
            "
 | 
			
		||||
import \"a.kcl\"
 | 
			
		||||
"
 | 
			
		||||
        );
 | 
			
		||||
        modules.insert("c.kcl".to_owned(), &c);
 | 
			
		||||
        modules.insert("c.kcl".to_owned(), into_module_info(c));
 | 
			
		||||
 | 
			
		||||
        let order = import_graph(modules).unwrap();
 | 
			
		||||
        let ctx = ExecutorContext::new_mock().await;
 | 
			
		||||
        let order = import_graph(&modules, &ctx).unwrap();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            vec![vec!["a.kcl".to_owned()], vec!["b.kcl".to_owned(), "c.kcl".to_owned()]],
 | 
			
		||||
            order
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn order_imports_cycle() {
 | 
			
		||||
    #[tokio::test]
 | 
			
		||||
    async fn order_imports_cycle() {
 | 
			
		||||
        let mut modules = HashMap::new();
 | 
			
		||||
 | 
			
		||||
        let a = kcl!(
 | 
			
		||||
@ -212,15 +308,16 @@ import \"a.kcl\"
 | 
			
		||||
import \"b.kcl\"
 | 
			
		||||
"
 | 
			
		||||
        );
 | 
			
		||||
        modules.insert("a.kcl".to_owned(), &a);
 | 
			
		||||
        modules.insert("a.kcl".to_owned(), into_module_info(a));
 | 
			
		||||
 | 
			
		||||
        let b = kcl!(
 | 
			
		||||
            "
 | 
			
		||||
import \"a.kcl\"
 | 
			
		||||
"
 | 
			
		||||
        );
 | 
			
		||||
        modules.insert("b.kcl".to_owned(), &b);
 | 
			
		||||
        modules.insert("b.kcl".to_owned(), into_module_info(b));
 | 
			
		||||
 | 
			
		||||
        import_graph(modules).unwrap_err();
 | 
			
		||||
        let ctx = ExecutorContext::new_mock().await;
 | 
			
		||||
        import_graph(&modules, &ctx).unwrap_err();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8,3 +8,5 @@ mod import_graph;
 | 
			
		||||
pub use ast_node::Node;
 | 
			
		||||
pub use ast_visitor::Visitable;
 | 
			
		||||
pub use ast_walk::walk;
 | 
			
		||||
pub use import_graph::import_graph;
 | 
			
		||||
pub(crate) use import_graph::import_universe;
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands add_lots.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -360,5 +360,29 @@ description: Artifact commands angled_line.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands argument_error.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Error from executing argument_error.kcl
 | 
			
		||||
---
 | 
			
		||||
KCL Type error
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands array_elem_pop.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands array_elem_pop_empty_fail.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands array_elem_pop_fail.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands array_elem_push.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands array_elem_push_fail.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands array_index_oob.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands array_range_expr.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands array_range_negative_expr.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -520,5 +520,29 @@ description: Artifact commands artifact_graph_example_code1.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -291,5 +291,29 @@ description: Artifact commands artifact_graph_example_code_no_3d.kcl
 | 
			
		||||
        "angle_snap_increment": null
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -214,5 +214,29 @@ description: Artifact commands artifact_graph_example_code_offset_planes.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -881,5 +881,29 @@ description: Artifact commands artifact_graph_sketch_on_face_etc.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,30 @@ description: Artifact commands assembly_mixed_units_cubes.kcl
 | 
			
		||||
      "unit": "in"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
@ -602,13 +626,5 @@ description: Artifact commands assembly_mixed_units_cubes.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "in"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,30 @@ description: Artifact commands assembly_non_default_units.kcl
 | 
			
		||||
      "unit": "in"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
@ -254,5 +278,13 @@ description: Artifact commands assembly_non_default_units.kcl
 | 
			
		||||
      "type": "close_path",
 | 
			
		||||
      "path_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "in"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands bad_units_in_annotation.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -320,5 +320,29 @@ description: Artifact commands basic_fillet_cube_close_opposite.kcl
 | 
			
		||||
      "tolerance": 0.0000001,
 | 
			
		||||
      "cut_type": "fillet"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -320,5 +320,29 @@ description: Artifact commands basic_fillet_cube_end.kcl
 | 
			
		||||
      "tolerance": 0.0000001,
 | 
			
		||||
      "cut_type": "fillet"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -308,5 +308,29 @@ description: Artifact commands basic_fillet_cube_next_adjacent.kcl
 | 
			
		||||
      "tolerance": 0.0000001,
 | 
			
		||||
      "cut_type": "fillet"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -308,5 +308,29 @@ description: Artifact commands basic_fillet_cube_previous_adjacent.kcl
 | 
			
		||||
      "tolerance": 0.0000001,
 | 
			
		||||
      "cut_type": "fillet"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -310,5 +310,29 @@ description: Artifact commands basic_fillet_cube_start.kcl
 | 
			
		||||
      "tolerance": 0.0000001,
 | 
			
		||||
      "cut_type": "fillet"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -249,5 +249,29 @@ description: Artifact commands big_number_angle_to_match_length_x.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -249,5 +249,29 @@ description: Artifact commands big_number_angle_to_match_length_y.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands boolean_logical_and.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands boolean_logical_multiple.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands boolean_logical_or.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -200,5 +200,29 @@ description: Artifact commands circle_three_point.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -618,5 +618,29 @@ description: Artifact commands circular_pattern3d_a_pattern.kcl
 | 
			
		||||
      "arc_degrees": 360.0,
 | 
			
		||||
      "rotate_duplicates": false
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands comparisons.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands comparisons_multiple.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands computed_var.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -1655,5 +1655,29 @@ description: Artifact commands crazy_multi_profile.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -303,5 +303,29 @@ description: Artifact commands cube.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -223,5 +223,29 @@ description: Artifact commands cube_with_error.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands double_map_fn.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -1830,5 +1830,29 @@ description: Artifact commands fillet-and-shell.kcl
 | 
			
		||||
      "shell_thickness": 1.0,
 | 
			
		||||
      "hollow": false
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -322,5 +322,29 @@ description: Artifact commands flush_batch_on_end.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -286,5 +286,29 @@ description: Artifact commands function_sketch.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -286,5 +286,29 @@ description: Artifact commands function_sketch_with_position.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -215,5 +215,29 @@ description: Artifact commands helix_ccw.kcl
 | 
			
		||||
      "is_clockwise": false,
 | 
			
		||||
      "length": 10.0
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -129,5 +129,29 @@ description: Artifact commands helix_simple.kcl
 | 
			
		||||
      "is_clockwise": false,
 | 
			
		||||
      "edge_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -1433,5 +1433,29 @@ description: Artifact commands i_shape.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands if_else.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands import_constant.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands import_cycle1.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands import_export.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands import_file_not_exist_error.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands import_file_parse_error.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -3021,5 +3021,29 @@ description: Artifact commands import_foreign.kcl
 | 
			
		||||
        "type": "gltf"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -36,5 +36,434 @@ description: Artifact commands import_function_not_sketch.kcl
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "in"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "make_plane",
 | 
			
		||||
      "origin": {
 | 
			
		||||
        "x": 0.0,
 | 
			
		||||
        "y": 0.0,
 | 
			
		||||
        "z": 0.0
 | 
			
		||||
      },
 | 
			
		||||
      "x_axis": {
 | 
			
		||||
        "x": 1.0,
 | 
			
		||||
        "y": 0.0,
 | 
			
		||||
        "z": 0.0
 | 
			
		||||
      },
 | 
			
		||||
      "y_axis": {
 | 
			
		||||
        "x": 0.0,
 | 
			
		||||
        "y": 1.0,
 | 
			
		||||
        "z": 0.0
 | 
			
		||||
      },
 | 
			
		||||
      "size": 60.0,
 | 
			
		||||
      "clobber": false,
 | 
			
		||||
      "hide": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "enable_sketch_mode",
 | 
			
		||||
      "entity_id": "[uuid]",
 | 
			
		||||
      "ortho": false,
 | 
			
		||||
      "animated": false,
 | 
			
		||||
      "adjust_camera": false,
 | 
			
		||||
      "planar_normal": {
 | 
			
		||||
        "x": 0.0,
 | 
			
		||||
        "y": 0.0,
 | 
			
		||||
        "z": 1.0
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "start_path"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "move_path_pen",
 | 
			
		||||
      "path": "[uuid]",
 | 
			
		||||
      "to": {
 | 
			
		||||
        "x": 4.0,
 | 
			
		||||
        "y": 12.0,
 | 
			
		||||
        "z": 0.0
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "sketch_mode_disable"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "extend_path",
 | 
			
		||||
      "path": "[uuid]",
 | 
			
		||||
      "segment": {
 | 
			
		||||
        "type": "line",
 | 
			
		||||
        "end": {
 | 
			
		||||
          "x": 2.0,
 | 
			
		||||
          "y": 0.0,
 | 
			
		||||
          "z": 0.0
 | 
			
		||||
        },
 | 
			
		||||
        "relative": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "extend_path",
 | 
			
		||||
      "path": "[uuid]",
 | 
			
		||||
      "segment": {
 | 
			
		||||
        "type": "line",
 | 
			
		||||
        "end": {
 | 
			
		||||
          "x": 0.0,
 | 
			
		||||
          "y": -6.0,
 | 
			
		||||
          "z": 0.0
 | 
			
		||||
        },
 | 
			
		||||
        "relative": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "extend_path",
 | 
			
		||||
      "path": "[uuid]",
 | 
			
		||||
      "segment": {
 | 
			
		||||
        "type": "line",
 | 
			
		||||
        "end": {
 | 
			
		||||
          "x": 4.0,
 | 
			
		||||
          "y": -6.0,
 | 
			
		||||
          "z": 0.0
 | 
			
		||||
        },
 | 
			
		||||
        "relative": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "extend_path",
 | 
			
		||||
      "path": "[uuid]",
 | 
			
		||||
      "segment": {
 | 
			
		||||
        "type": "line",
 | 
			
		||||
        "end": {
 | 
			
		||||
          "x": 0.0,
 | 
			
		||||
          "y": -6.0,
 | 
			
		||||
          "z": 0.0
 | 
			
		||||
        },
 | 
			
		||||
        "relative": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "extend_path",
 | 
			
		||||
      "path": "[uuid]",
 | 
			
		||||
      "segment": {
 | 
			
		||||
        "type": "line",
 | 
			
		||||
        "end": {
 | 
			
		||||
          "x": -3.75,
 | 
			
		||||
          "y": -4.5,
 | 
			
		||||
          "z": 0.0
 | 
			
		||||
        },
 | 
			
		||||
        "relative": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "extend_path",
 | 
			
		||||
      "path": "[uuid]",
 | 
			
		||||
      "segment": {
 | 
			
		||||
        "type": "line",
 | 
			
		||||
        "end": {
 | 
			
		||||
          "x": 0.0,
 | 
			
		||||
          "y": -5.5,
 | 
			
		||||
          "z": 0.0
 | 
			
		||||
        },
 | 
			
		||||
        "relative": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "extend_path",
 | 
			
		||||
      "path": "[uuid]",
 | 
			
		||||
      "segment": {
 | 
			
		||||
        "type": "line",
 | 
			
		||||
        "end": {
 | 
			
		||||
          "x": -2.0,
 | 
			
		||||
          "y": 0.0,
 | 
			
		||||
          "z": 0.0
 | 
			
		||||
        },
 | 
			
		||||
        "relative": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "close_path",
 | 
			
		||||
      "path_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "revolve",
 | 
			
		||||
      "target": "[uuid]",
 | 
			
		||||
      "origin": {
 | 
			
		||||
        "x": 0.0,
 | 
			
		||||
        "y": 0.0,
 | 
			
		||||
        "z": 0.0
 | 
			
		||||
      },
 | 
			
		||||
      "axis": {
 | 
			
		||||
        "x": 0.0,
 | 
			
		||||
        "y": 1.0,
 | 
			
		||||
        "z": 0.0
 | 
			
		||||
      },
 | 
			
		||||
      "axis_is_2d": true,
 | 
			
		||||
      "angle": {
 | 
			
		||||
        "unit": "degrees",
 | 
			
		||||
        "value": 360.0
 | 
			
		||||
      },
 | 
			
		||||
      "tolerance": 0.0000001,
 | 
			
		||||
      "opposite": "None"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "object_bring_to_front",
 | 
			
		||||
      "object_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_extrusion_face_info",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_opposite_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_next_adjacent_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_opposite_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_next_adjacent_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_opposite_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_next_adjacent_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_opposite_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_next_adjacent_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_opposite_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_next_adjacent_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_opposite_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_next_adjacent_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_opposite_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_next_adjacent_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_opposite_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_get_next_adjacent_edge",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
assertion_line: 189
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart import_function_not_sketch.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,82 @@
 | 
			
		||||
```mermaid
 | 
			
		||||
flowchart LR
 | 
			
		||||
  subgraph path2 [Path]
 | 
			
		||||
    2["Path<br>[75, 101, 5]"]
 | 
			
		||||
    3["Segment<br>[107, 125, 5]"]
 | 
			
		||||
    4["Segment<br>[131, 150, 5]"]
 | 
			
		||||
    5["Segment<br>[156, 175, 5]"]
 | 
			
		||||
    6["Segment<br>[181, 200, 5]"]
 | 
			
		||||
    7["Segment<br>[206, 231, 5]"]
 | 
			
		||||
    8["Segment<br>[237, 258, 5]"]
 | 
			
		||||
    9["Segment<br>[264, 283, 5]"]
 | 
			
		||||
    10["Segment<br>[289, 296, 5]"]
 | 
			
		||||
    11[Solid2d]
 | 
			
		||||
  end
 | 
			
		||||
  1["Plane<br>[52, 69, 5]"]
 | 
			
		||||
  12["Sweep Revolve<br>[302, 319, 5]"]
 | 
			
		||||
  13[Wall]
 | 
			
		||||
  14[Wall]
 | 
			
		||||
  15[Wall]
 | 
			
		||||
  16[Wall]
 | 
			
		||||
  17[Wall]
 | 
			
		||||
  18[Wall]
 | 
			
		||||
  19[Wall]
 | 
			
		||||
  20[Wall]
 | 
			
		||||
  21["SweepEdge Adjacent"]
 | 
			
		||||
  22["SweepEdge Adjacent"]
 | 
			
		||||
  23["SweepEdge Adjacent"]
 | 
			
		||||
  24["SweepEdge Adjacent"]
 | 
			
		||||
  25["SweepEdge Adjacent"]
 | 
			
		||||
  26["SweepEdge Adjacent"]
 | 
			
		||||
  27["SweepEdge Adjacent"]
 | 
			
		||||
  1 --- 2
 | 
			
		||||
  2 --- 3
 | 
			
		||||
  2 --- 4
 | 
			
		||||
  2 --- 5
 | 
			
		||||
  2 --- 6
 | 
			
		||||
  2 --- 7
 | 
			
		||||
  2 --- 8
 | 
			
		||||
  2 --- 9
 | 
			
		||||
  2 --- 10
 | 
			
		||||
  2 ---- 12
 | 
			
		||||
  2 --- 11
 | 
			
		||||
  3 --- 13
 | 
			
		||||
  3 x--> 21
 | 
			
		||||
  4 --- 14
 | 
			
		||||
  4 --- 21
 | 
			
		||||
  5 --- 15
 | 
			
		||||
  5 --- 22
 | 
			
		||||
  6 --- 16
 | 
			
		||||
  6 --- 23
 | 
			
		||||
  7 --- 17
 | 
			
		||||
  7 --- 24
 | 
			
		||||
  8 --- 18
 | 
			
		||||
  8 --- 25
 | 
			
		||||
  9 --- 19
 | 
			
		||||
  9 --- 26
 | 
			
		||||
  10 --- 20
 | 
			
		||||
  10 --- 27
 | 
			
		||||
  12 --- 13
 | 
			
		||||
  12 --- 14
 | 
			
		||||
  12 --- 15
 | 
			
		||||
  12 --- 16
 | 
			
		||||
  12 --- 17
 | 
			
		||||
  12 --- 18
 | 
			
		||||
  12 --- 19
 | 
			
		||||
  12 --- 20
 | 
			
		||||
  12 <--x 3
 | 
			
		||||
  12 --- 21
 | 
			
		||||
  12 <--x 4
 | 
			
		||||
  12 <--x 5
 | 
			
		||||
  12 --- 22
 | 
			
		||||
  12 <--x 6
 | 
			
		||||
  12 --- 23
 | 
			
		||||
  12 <--x 7
 | 
			
		||||
  12 --- 24
 | 
			
		||||
  12 <--x 8
 | 
			
		||||
  12 --- 25
 | 
			
		||||
  12 <--x 9
 | 
			
		||||
  12 --- 26
 | 
			
		||||
  12 <--x 10
 | 
			
		||||
  12 --- 27
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -2,4 +2,106 @@
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Operations executed import_function_not_sketch.kcl
 | 
			
		||||
---
 | 
			
		||||
[]
 | 
			
		||||
[
 | 
			
		||||
  {
 | 
			
		||||
    "labeledArgs": {
 | 
			
		||||
      "planeOrSolid": {
 | 
			
		||||
        "value": {
 | 
			
		||||
          "type": "Plane",
 | 
			
		||||
          "artifact_id": "[uuid]"
 | 
			
		||||
        },
 | 
			
		||||
        "sourceRange": []
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "name": "startSketchOn",
 | 
			
		||||
    "sourceRange": [],
 | 
			
		||||
    "type": "StdLibCall",
 | 
			
		||||
    "unlabeledArg": null
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "type": "KclStdLibCall",
 | 
			
		||||
    "name": "revolve",
 | 
			
		||||
    "unlabeledArg": {
 | 
			
		||||
      "value": {
 | 
			
		||||
        "type": "Sketch",
 | 
			
		||||
        "value": {
 | 
			
		||||
          "artifactId": "[uuid]"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "sourceRange": []
 | 
			
		||||
    },
 | 
			
		||||
    "labeledArgs": {
 | 
			
		||||
      "axis": {
 | 
			
		||||
        "value": {
 | 
			
		||||
          "type": "Object",
 | 
			
		||||
          "value": {
 | 
			
		||||
            "direction": {
 | 
			
		||||
              "type": "Array",
 | 
			
		||||
              "value": [
 | 
			
		||||
                {
 | 
			
		||||
                  "type": "Number",
 | 
			
		||||
                  "value": 0.0,
 | 
			
		||||
                  "ty": {
 | 
			
		||||
                    "type": "Default",
 | 
			
		||||
                    "len": {
 | 
			
		||||
                      "type": "Mm"
 | 
			
		||||
                    },
 | 
			
		||||
                    "angle": {
 | 
			
		||||
                      "type": "Degrees"
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  "type": "Number",
 | 
			
		||||
                  "value": 1.0,
 | 
			
		||||
                  "ty": {
 | 
			
		||||
                    "type": "Default",
 | 
			
		||||
                    "len": {
 | 
			
		||||
                      "type": "Mm"
 | 
			
		||||
                    },
 | 
			
		||||
                    "angle": {
 | 
			
		||||
                      "type": "Degrees"
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              ]
 | 
			
		||||
            },
 | 
			
		||||
            "origin": {
 | 
			
		||||
              "type": "Array",
 | 
			
		||||
              "value": [
 | 
			
		||||
                {
 | 
			
		||||
                  "type": "Number",
 | 
			
		||||
                  "value": 0.0,
 | 
			
		||||
                  "ty": {
 | 
			
		||||
                    "type": "Default",
 | 
			
		||||
                    "len": {
 | 
			
		||||
                      "type": "Mm"
 | 
			
		||||
                    },
 | 
			
		||||
                    "angle": {
 | 
			
		||||
                      "type": "Degrees"
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  "type": "Number",
 | 
			
		||||
                  "value": 0.0,
 | 
			
		||||
                  "ty": {
 | 
			
		||||
                    "type": "Default",
 | 
			
		||||
                    "len": {
 | 
			
		||||
                      "type": "Mm"
 | 
			
		||||
                    },
 | 
			
		||||
                    "angle": {
 | 
			
		||||
                      "type": "Degrees"
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              ]
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "sourceRange": []
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "sourceRange": []
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 99 KiB  | 
@ -28,5 +28,29 @@ description: Artifact commands import_glob.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,130 @@ description: Artifact commands import_side_effect.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "make_plane",
 | 
			
		||||
      "origin": {
 | 
			
		||||
        "x": 0.0,
 | 
			
		||||
        "y": 0.0,
 | 
			
		||||
        "z": 0.0
 | 
			
		||||
      },
 | 
			
		||||
      "x_axis": {
 | 
			
		||||
        "x": 1.0,
 | 
			
		||||
        "y": 0.0,
 | 
			
		||||
        "z": 0.0
 | 
			
		||||
      },
 | 
			
		||||
      "y_axis": {
 | 
			
		||||
        "x": 0.0,
 | 
			
		||||
        "y": 1.0,
 | 
			
		||||
        "z": 0.0
 | 
			
		||||
      },
 | 
			
		||||
      "size": 60.0,
 | 
			
		||||
      "clobber": false,
 | 
			
		||||
      "hide": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "enable_sketch_mode",
 | 
			
		||||
      "entity_id": "[uuid]",
 | 
			
		||||
      "ortho": false,
 | 
			
		||||
      "animated": false,
 | 
			
		||||
      "adjust_camera": false,
 | 
			
		||||
      "planar_normal": {
 | 
			
		||||
        "x": 0.0,
 | 
			
		||||
        "y": 0.0,
 | 
			
		||||
        "z": 1.0
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "start_path"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "move_path_pen",
 | 
			
		||||
      "path": "[uuid]",
 | 
			
		||||
      "to": {
 | 
			
		||||
        "x": 10.0,
 | 
			
		||||
        "y": 0.0,
 | 
			
		||||
        "z": 0.0
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "sketch_mode_disable"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "extend_path",
 | 
			
		||||
      "path": "[uuid]",
 | 
			
		||||
      "segment": {
 | 
			
		||||
        "type": "arc",
 | 
			
		||||
        "center": {
 | 
			
		||||
          "x": 0.0,
 | 
			
		||||
          "y": 0.0
 | 
			
		||||
        },
 | 
			
		||||
        "radius": 10.0,
 | 
			
		||||
        "start": {
 | 
			
		||||
          "unit": "degrees",
 | 
			
		||||
          "value": 0.0
 | 
			
		||||
        },
 | 
			
		||||
        "end": {
 | 
			
		||||
          "unit": "degrees",
 | 
			
		||||
          "value": 360.0
 | 
			
		||||
        },
 | 
			
		||||
        "relative": false
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "close_path",
 | 
			
		||||
      "path_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
assertion_line: 189
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart import_side_effect.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,12 @@
 | 
			
		||||
```mermaid
 | 
			
		||||
flowchart LR
 | 
			
		||||
  subgraph path2 [Path]
 | 
			
		||||
    2["Path<br>[102, 138, 5]"]
 | 
			
		||||
    3["Segment<br>[102, 138, 5]"]
 | 
			
		||||
    4[Solid2d]
 | 
			
		||||
  end
 | 
			
		||||
  1["Plane<br>[77, 96, 5]"]
 | 
			
		||||
  1 --- 2
 | 
			
		||||
  2 --- 3
 | 
			
		||||
  2 --- 4
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -2,4 +2,20 @@
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Operations executed import_side_effect.kcl
 | 
			
		||||
---
 | 
			
		||||
[]
 | 
			
		||||
[
 | 
			
		||||
  {
 | 
			
		||||
    "labeledArgs": {
 | 
			
		||||
      "planeOrSolid": {
 | 
			
		||||
        "value": {
 | 
			
		||||
          "type": "String",
 | 
			
		||||
          "value": "XY"
 | 
			
		||||
        },
 | 
			
		||||
        "sourceRange": []
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "name": "startSketchOn",
 | 
			
		||||
    "sourceRange": [],
 | 
			
		||||
    "type": "StdLibCall",
 | 
			
		||||
    "unlabeledArg": null
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -5571162,5 +5571162,29 @@ description: Artifact commands import_transform.kcl
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,54 @@ description: Artifact commands import_whole.kcl
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_object_transform",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "transforms": [
 | 
			
		||||
        {
 | 
			
		||||
          "translate": {
 | 
			
		||||
            "property": {
 | 
			
		||||
              "x": 0.0,
 | 
			
		||||
              "y": 0.0,
 | 
			
		||||
              "z": 1.0
 | 
			
		||||
            },
 | 
			
		||||
            "set": false,
 | 
			
		||||
            "is_local": true
 | 
			
		||||
          },
 | 
			
		||||
          "rotate_rpy": null,
 | 
			
		||||
          "rotate_angle_axis": null,
 | 
			
		||||
          "scale": null
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
@ -216,26 +264,5 @@ description: Artifact commands import_whole.kcl
 | 
			
		||||
      "edge_id": "[uuid]",
 | 
			
		||||
      "face_id": "[uuid]"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "solid3d_shell_face",
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "face_ids": [
 | 
			
		||||
        "[uuid]"
 | 
			
		||||
      ],
 | 
			
		||||
      "shell_thickness": 42.0,
 | 
			
		||||
      "hollow": false
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -63,61 +63,21 @@ description: Result of parsing import_whole.kcl
 | 
			
		||||
                    "label": {
 | 
			
		||||
                      "commentStart": 0,
 | 
			
		||||
                      "end": 0,
 | 
			
		||||
                      "name": "faces",
 | 
			
		||||
                      "name": "z",
 | 
			
		||||
                      "start": 0,
 | 
			
		||||
                      "type": "Identifier"
 | 
			
		||||
                    },
 | 
			
		||||
                    "arg": {
 | 
			
		||||
                      "commentStart": 0,
 | 
			
		||||
                      "elements": [
 | 
			
		||||
                        {
 | 
			
		||||
                          "commentStart": 0,
 | 
			
		||||
                          "end": 0,
 | 
			
		||||
                          "raw": "'end'",
 | 
			
		||||
                          "start": 0,
 | 
			
		||||
                          "type": "Literal",
 | 
			
		||||
                          "type": "Literal",
 | 
			
		||||
                          "value": "end"
 | 
			
		||||
                        }
 | 
			
		||||
                      ],
 | 
			
		||||
                      "end": 0,
 | 
			
		||||
                      "raw": "1",
 | 
			
		||||
                      "start": 0,
 | 
			
		||||
                      "type": "ArrayExpression",
 | 
			
		||||
                      "type": "ArrayExpression"
 | 
			
		||||
                    }
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    "type": "LabeledArg",
 | 
			
		||||
                    "label": {
 | 
			
		||||
                      "commentStart": 0,
 | 
			
		||||
                      "end": 0,
 | 
			
		||||
                      "name": "thickness",
 | 
			
		||||
                      "start": 0,
 | 
			
		||||
                      "type": "Identifier"
 | 
			
		||||
                    },
 | 
			
		||||
                    "arg": {
 | 
			
		||||
                      "abs_path": false,
 | 
			
		||||
                      "commentStart": 0,
 | 
			
		||||
                      "end": 0,
 | 
			
		||||
                      "name": {
 | 
			
		||||
                        "commentStart": 0,
 | 
			
		||||
                        "end": 0,
 | 
			
		||||
                        "name": "thickness",
 | 
			
		||||
                        "start": 0,
 | 
			
		||||
                        "type": "Identifier"
 | 
			
		||||
                      },
 | 
			
		||||
                      "path": [
 | 
			
		||||
                        {
 | 
			
		||||
                          "commentStart": 0,
 | 
			
		||||
                          "end": 0,
 | 
			
		||||
                          "name": "foo",
 | 
			
		||||
                          "start": 0,
 | 
			
		||||
                          "type": "Identifier"
 | 
			
		||||
                        }
 | 
			
		||||
                      ],
 | 
			
		||||
                      "start": 0,
 | 
			
		||||
                      "type": "Name",
 | 
			
		||||
                      "type": "Name"
 | 
			
		||||
                      "type": "Literal",
 | 
			
		||||
                      "type": "Literal",
 | 
			
		||||
                      "value": {
 | 
			
		||||
                        "value": 1.0,
 | 
			
		||||
                        "suffix": "None"
 | 
			
		||||
                      }
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                ],
 | 
			
		||||
@ -128,7 +88,7 @@ description: Result of parsing import_whole.kcl
 | 
			
		||||
                  "name": {
 | 
			
		||||
                    "commentStart": 0,
 | 
			
		||||
                    "end": 0,
 | 
			
		||||
                    "name": "shell",
 | 
			
		||||
                    "name": "translate",
 | 
			
		||||
                    "start": 0,
 | 
			
		||||
                    "type": "Identifier"
 | 
			
		||||
                  },
 | 
			
		||||
 | 
			
		||||
@ -3,4 +3,4 @@
 | 
			
		||||
import "exported_mod.kcl" as foo
 | 
			
		||||
 | 
			
		||||
bar = foo
 | 
			
		||||
  |> shell(faces = ['end'], thickness = foo::thickness)
 | 
			
		||||
    |> translate(z=1)
 | 
			
		||||
 | 
			
		||||
@ -61,49 +61,5 @@ description: Operations executed import_whole.kcl
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "type": "GroupEnd"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "labeledArgs": {
 | 
			
		||||
      "faces": {
 | 
			
		||||
        "value": {
 | 
			
		||||
          "type": "Array",
 | 
			
		||||
          "value": [
 | 
			
		||||
            {
 | 
			
		||||
              "type": "String",
 | 
			
		||||
              "value": "end"
 | 
			
		||||
            }
 | 
			
		||||
          ]
 | 
			
		||||
        },
 | 
			
		||||
        "sourceRange": []
 | 
			
		||||
      },
 | 
			
		||||
      "thickness": {
 | 
			
		||||
        "value": {
 | 
			
		||||
          "type": "Number",
 | 
			
		||||
          "value": 42.0,
 | 
			
		||||
          "ty": {
 | 
			
		||||
            "type": "Default",
 | 
			
		||||
            "len": {
 | 
			
		||||
              "type": "Inches"
 | 
			
		||||
            },
 | 
			
		||||
            "angle": {
 | 
			
		||||
              "type": "Degrees"
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "sourceRange": []
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "name": "shell",
 | 
			
		||||
    "sourceRange": [],
 | 
			
		||||
    "type": "StdLibCall",
 | 
			
		||||
    "unlabeledArg": {
 | 
			
		||||
      "value": {
 | 
			
		||||
        "type": "Solid",
 | 
			
		||||
        "value": {
 | 
			
		||||
          "artifactId": "[uuid]"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "sourceRange": []
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -7,4 +7,4 @@ description: Result of unparsing import_whole.kcl
 | 
			
		||||
import "exported_mod.kcl" as foo
 | 
			
		||||
 | 
			
		||||
bar = foo
 | 
			
		||||
  |> shell(faces = [END], thickness = foo::thickness)
 | 
			
		||||
  |> translate(z = 1)
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands index_of_array.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -580,5 +580,29 @@ description: Artifact commands intersect_cubes.kcl
 | 
			
		||||
      ],
 | 
			
		||||
      "tolerance": 0.0000001
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands invalid_index_fractional.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands invalid_index_negative.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands invalid_index_str.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,29 @@ description: Artifact commands invalid_member_object.kcl
 | 
			
		||||
      "object_id": "[uuid]",
 | 
			
		||||
      "hidden": true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "cmdId": "[uuid]",
 | 
			
		||||
    "range": [],
 | 
			
		||||
    "command": {
 | 
			
		||||
      "type": "set_scene_units",
 | 
			
		||||
      "unit": "mm"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user