Stronger types and better error handling in executeMock (#7370)
This brings the `execute_mock` function into line with the `execute` function, which I tweaked in https://github.com/KittyCAD/modeling-app/pull/7351. Now mock execution, like real execution, will always return a properly-formatted KCL error, instead of any possible JS value. Also, incidentally, I noticed that send_response always succeeds, so I changed it from Result<()> to void.
This commit is contained in:
@ -80,12 +80,12 @@ impl ResponseContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a response to the context.
|
// Add a response to the context.
|
||||||
pub async fn send_response(&self, data: js_sys::Uint8Array) -> Result<(), JsValue> {
|
pub async fn send_response(&self, data: js_sys::Uint8Array) {
|
||||||
let ws_result: WebSocketResponse = match bson::from_slice(&data.to_vec()) {
|
let ws_result: WebSocketResponse = match bson::from_slice(&data.to_vec()) {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// We don't care about the error if we can't parse it.
|
// We don't care about the error if we can't parse it.
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -96,13 +96,11 @@ impl ResponseContext {
|
|||||||
|
|
||||||
let Some(id) = id else {
|
let Some(id) = id else {
|
||||||
// We only care if we have an id.
|
// We only care if we have an id.
|
||||||
return Ok(());
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add this response to our responses.
|
// Add this response to our responses.
|
||||||
self.add(id, ws_result.clone()).await;
|
self.add(id, ws_result.clone()).await;
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,6 +220,7 @@ impl schemars::JsonSchema for TypedPath {
|
|||||||
///
|
///
|
||||||
/// * Does **not** touch `..` or symlinks – call `canonicalize()` if you need that.
|
/// * Does **not** touch `..` or symlinks – call `canonicalize()` if you need that.
|
||||||
/// * Returns an owned `PathBuf` only when normalisation was required.
|
/// * Returns an owned `PathBuf` only when normalisation was required.
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
fn normalise_import<S: AsRef<str>>(raw: S) -> std::path::PathBuf {
|
fn normalise_import<S: AsRef<str>>(raw: S) -> std::path::PathBuf {
|
||||||
let s = raw.as_ref();
|
let s = raw.as_ref();
|
||||||
// On Unix we need to swap `\` → `/`. On Windows we leave it alone.
|
// On Unix we need to swap `\` → `/`. On Windows we leave it alone.
|
||||||
|
@ -6,6 +6,8 @@ use gloo_utils::format::JsValueSerdeExt;
|
|||||||
use kcl_lib::{wasm_engine::FileManager, EngineManager, ExecOutcome, KclError, KclErrorWithOutputs, Program};
|
use kcl_lib::{wasm_engine::FileManager, EngineManager, ExecOutcome, KclError, KclErrorWithOutputs, Program};
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
const TRUE_BUG: &str = "This is a bug in KCL and not in your code, please report this to Zoo.";
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
engine: Arc<Box<dyn EngineManager>>,
|
engine: Arc<Box<dyn EngineManager>>,
|
||||||
@ -79,12 +81,15 @@ impl Context {
|
|||||||
|
|
||||||
self.execute_typed(program_ast_json, path, settings)
|
self.execute_typed(program_ast_json, path, settings)
|
||||||
.await
|
.await
|
||||||
.and_then(|outcome| JsValue::from_serde(&outcome).map_err(|e| {
|
.and_then(|outcome| {
|
||||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues.
|
JsValue::from_serde(&outcome).map_err(|e| {
|
||||||
// DO NOT USE serde_wasm_bindgen::to_value it will break the frontend.
|
// The serde-wasm-bindgen does not work here because of weird HashMap issues.
|
||||||
KclErrorWithOutputs::no_outputs(KclError::internal(
|
// DO NOT USE serde_wasm_bindgen::to_value it will break the frontend.
|
||||||
format!("Could not serialize successful KCL result. This is a bug in KCL and not in your code, please report this to Zoo. Details: {e}"),
|
KclErrorWithOutputs::no_outputs(KclError::internal(format!(
|
||||||
))}))
|
"Could not serialize successful KCL result. {TRUE_BUG} Details: {e}"
|
||||||
|
)))
|
||||||
|
})
|
||||||
|
})
|
||||||
.map_err(|e: KclErrorWithOutputs| JsValue::from_serde(&e).unwrap())
|
.map_err(|e: KclErrorWithOutputs| JsValue::from_serde(&e).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,16 +100,14 @@ impl Context {
|
|||||||
settings: &str,
|
settings: &str,
|
||||||
) -> Result<ExecOutcome, KclErrorWithOutputs> {
|
) -> Result<ExecOutcome, KclErrorWithOutputs> {
|
||||||
let program: Program = serde_json::from_str(program_ast_json).map_err(|e| {
|
let program: Program = serde_json::from_str(program_ast_json).map_err(|e| {
|
||||||
let err = KclError::internal(
|
let err = KclError::internal(format!("Could not deserialize KCL AST. {TRUE_BUG} Details: {e}"));
|
||||||
format!("Could not deserialize KCL AST. This is a bug in KCL and not in your code, please report this to Zoo. Details: {e}"),
|
KclErrorWithOutputs::no_outputs(err)
|
||||||
);
|
})?;
|
||||||
KclErrorWithOutputs::no_outputs(err)
|
let ctx = self.create_executor_ctx(settings, path, false).map_err(|e| {
|
||||||
})?;
|
KclErrorWithOutputs::no_outputs(KclError::internal(format!(
|
||||||
let ctx = self
|
"Could not create KCL executor context. {TRUE_BUG} Details: {e}"
|
||||||
.create_executor_ctx(settings, path, false)
|
)))
|
||||||
.map_err(|e| KclErrorWithOutputs::no_outputs(KclError::internal(
|
})?;
|
||||||
format!("Could not create KCL executor context. This is a bug in KCL and not in your code, please report this to Zoo. Details: {e}"),
|
|
||||||
)))?;
|
|
||||||
ctx.run_with_caching(program).await
|
ctx.run_with_caching(program).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +128,7 @@ impl Context {
|
|||||||
|
|
||||||
/// Send a response to kcl lib's engine.
|
/// Send a response to kcl lib's engine.
|
||||||
#[wasm_bindgen(js_name = sendResponse)]
|
#[wasm_bindgen(js_name = sendResponse)]
|
||||||
pub async fn send_response(&self, data: js_sys::Uint8Array) -> Result<(), JsValue> {
|
pub async fn send_response(&self, data: js_sys::Uint8Array) {
|
||||||
self.response_context.send_response(data).await
|
self.response_context.send_response(data).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,18 +140,40 @@ impl Context {
|
|||||||
path: Option<String>,
|
path: Option<String>,
|
||||||
settings: &str,
|
settings: &str,
|
||||||
use_prev_memory: bool,
|
use_prev_memory: bool,
|
||||||
) -> Result<JsValue, String> {
|
) -> Result<JsValue, JsValue> {
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
let program: Program = serde_json::from_str(program_ast_json).map_err(|e| e.to_string())?;
|
self.execute_mock_typed(program_ast_json, path, settings, use_prev_memory)
|
||||||
|
.await
|
||||||
|
.and_then(|outcome| {
|
||||||
|
JsValue::from_serde(&outcome).map_err(|e| {
|
||||||
|
// The serde-wasm-bindgen does not work here because of weird HashMap issues.
|
||||||
|
// DO NOT USE serde_wasm_bindgen::to_value it will break the frontend.
|
||||||
|
KclErrorWithOutputs::no_outputs(KclError::internal(format!(
|
||||||
|
"Could not serialize successful KCL result. {TRUE_BUG} Details: {e}"
|
||||||
|
)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map_err(|e: KclErrorWithOutputs| JsValue::from_serde(&e).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
let ctx = self.create_executor_ctx(settings, path, true)?;
|
async fn execute_mock_typed(
|
||||||
match ctx.run_mock(program, use_prev_memory).await {
|
&self,
|
||||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues.
|
program_ast_json: &str,
|
||||||
// DO NOT USE serde_wasm_bindgen::to_value it will break the frontend.
|
path: Option<String>,
|
||||||
Ok(outcome) => JsValue::from_serde(&outcome).map_err(|e| e.to_string()),
|
settings: &str,
|
||||||
Err(err) => Err(serde_json::to_string(&err).map_err(|serde_err| serde_err.to_string())?),
|
use_prev_memory: bool,
|
||||||
}
|
) -> Result<ExecOutcome, KclErrorWithOutputs> {
|
||||||
|
let program: Program = serde_json::from_str(program_ast_json).map_err(|e| {
|
||||||
|
let err = KclError::internal(format!("Could not deserialize KCL AST. {TRUE_BUG} Details: {e}"));
|
||||||
|
KclErrorWithOutputs::no_outputs(err)
|
||||||
|
})?;
|
||||||
|
let ctx = self.create_executor_ctx(settings, path, true).map_err(|e| {
|
||||||
|
KclErrorWithOutputs::no_outputs(KclError::internal(format!(
|
||||||
|
"Could not create KCL executor context. {TRUE_BUG} Details: {e}"
|
||||||
|
)))
|
||||||
|
})?;
|
||||||
|
ctx.run_mock(program, use_prev_memory).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Export a scene to a file.
|
/// Export a scene to a file.
|
||||||
|
Reference in New Issue
Block a user