From 6ce270c0d032f5a2e0fe25fcc837ac501421056a Mon Sep 17 00:00:00 2001 From: Jonathan Tran Date: Tue, 4 Feb 2025 20:34:56 -0500 Subject: [PATCH] Fix artifact graph to survive when there's an execution error (#5246) This also changes artifact graph errors to point to the KCL that the command originated from. --- src/lang/wasm.ts | 14 +++-- src/wasm-lib/kcl/src/execution/artifact.rs | 62 ++++++++++++++-------- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src/lang/wasm.ts b/src/lang/wasm.ts index 52e0dc55d..5586121cb 100644 --- a/src/lang/wasm.ts +++ b/src/lang/wasm.ts @@ -158,6 +158,12 @@ export function isTopLevelModule(range: SourceRange): boolean { return range[2] === 0 } +function firstSourceRange(error: RustKclError): SourceRange { + return error.sourceRanges.length > 0 + ? sourceRangeFromRust(error.sourceRanges[0]) + : defaultSourceRange() +} + export const wasmUrl = () => { // For when we're in electron (file based) or web server (network based) // For some reason relative paths don't work as expected. Otherwise we would @@ -255,7 +261,7 @@ export const parse = (code: string | Error): ParseResult | Error => { return new KCLError( parsed.kind, parsed.msg, - sourceRangeFromRust(parsed.sourceRanges[0]), + firstSourceRange(parsed), [], [], defaultArtifactGraph() @@ -622,7 +628,7 @@ export const executor = async ( const kclError = new KCLError( parsed.error.kind, parsed.error.msg, - sourceRangeFromRust(parsed.error.sourceRanges[0]), + firstSourceRange(parsed.error), parsed.operations, parsed.artifactCommands, rustArtifactGraphToMap(parsed.artifactGraph) @@ -691,7 +697,7 @@ export const modifyAstForSketch = async ( const kclError = new KCLError( parsed.kind, parsed.msg, - sourceRangeFromRust(parsed.sourceRanges[0]), + firstSourceRange(parsed), [], [], defaultArtifactGraph() @@ -762,7 +768,7 @@ export function programMemoryInit(): ProgramMemory | Error { return new KCLError( parsed.kind, parsed.msg, - sourceRangeFromRust(parsed.sourceRanges[0]), + firstSourceRange(parsed), [], [], defaultArtifactGraph() diff --git a/src/wasm-lib/kcl/src/execution/artifact.rs b/src/wasm-lib/kcl/src/execution/artifact.rs index 3dfb2a3ba..69481fd53 100644 --- a/src/wasm-lib/kcl/src/execution/artifact.rs +++ b/src/wasm-lib/kcl/src/execution/artifact.rs @@ -12,6 +12,7 @@ use serde::{ser::SerializeSeq, Deserialize, Serialize}; use uuid::Uuid; use crate::{ + errors::KclErrorDetails, parsing::ast::types::{Node, Program}, KclError, SourceRange, }; @@ -595,9 +596,12 @@ fn artifacts_to_update( } ModelingCmd::EnableSketchMode(_) => { let current_plane_id = current_plane_id.ok_or_else(|| { - KclError::internal(format!( - "Expected a current plane ID when processing EnableSketchMode command, but we have none: {id:?}" - )) + KclError::Internal(KclErrorDetails { + message: format!( + "Expected a current plane ID when processing EnableSketchMode command, but we have none: {id:?}" + ), + source_ranges: vec![range], + }) })?; let existing_plane = artifacts.get(&ArtifactId::new(current_plane_id)); match existing_plane { @@ -626,9 +630,12 @@ fn artifacts_to_update( ModelingCmd::StartPath(_) => { let mut return_arr = Vec::new(); let current_plane_id = current_plane_id.ok_or_else(|| { - KclError::internal(format!( - "Expected a current plane ID when processing StartPath command, but we have none: {id:?}" - )) + KclError::Internal(KclErrorDetails { + message: format!( + "Expected a current plane ID when processing StartPath command, but we have none: {id:?}" + ), + source_ranges: vec![range], + }) })?; return_arr.push(Artifact::Path(Path { id, @@ -730,9 +737,10 @@ fn artifacts_to_update( // TODO: Using the first one. Make sure to revisit this // choice, don't think it matters for now. path_id: ArtifactId::new(*loft_cmd.section_ids.first().ok_or_else(|| { - KclError::internal(format!( - "Expected at least one section ID in Loft command: {id:?}; cmd={cmd:?}" - )) + KclError::Internal(KclErrorDetails { + message: format!("Expected at least one section ID in Loft command: {id:?}; cmd={cmd:?}"), + source_ranges: vec![range], + }) })?), surface_ids: Vec::new(), edge_ids: Vec::new(), @@ -772,9 +780,12 @@ fn artifacts_to_update( }; last_path = Some(path); let path_sweep_id = path.sweep_id.ok_or_else(|| { - KclError::internal(format!( - "Expected a sweep ID on the path when processing Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}" - )) + KclError::Internal(KclErrorDetails { + message:format!( + "Expected a sweep ID on the path when processing Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}" + ), + source_ranges: vec![range], + }) })?; return_arr.push(Artifact::Wall(Wall { id: face_id, @@ -803,9 +814,12 @@ fn artifacts_to_update( continue; }; let path_sweep_id = path.sweep_id.ok_or_else(|| { - KclError::internal(format!( - "Expected a sweep ID on the path when processing Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}" - )) + KclError::Internal(KclErrorDetails { + message:format!( + "Expected a sweep ID on the path when processing Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}" + ), + source_ranges: vec![range], + }) })?; return_arr.push(Artifact::Cap(Cap { id: face_id, @@ -848,17 +862,23 @@ fn artifacts_to_update( let response_edge_id = match response { OkModelingCmdResponse::Solid3dGetNextAdjacentEdge(r) => { let Some(edge_id) = r.edge else { - return Err(KclError::internal(format!( - "Expected Solid3dGetNextAdjacentEdge response to have an edge ID, but found none: id={id:?}, {response:?}" - ))); + return Err(KclError::Internal(KclErrorDetails { + message:format!( + "Expected Solid3dGetNextAdjacentEdge response to have an edge ID, but found none: id={id:?}, {response:?}" + ), + source_ranges: vec![range], + })); }; edge_id.into() } OkModelingCmdResponse::Solid3dGetOppositeEdge(r) => r.edge.into(), _ => { - return Err(KclError::internal(format!( - "Expected Solid3dGetNextAdjacentEdge or Solid3dGetOppositeEdge response, but got: id={id:?}, {response:?}" - ))); + return Err(KclError::Internal(KclErrorDetails { + message:format!( + "Expected Solid3dGetNextAdjacentEdge or Solid3dGetOppositeEdge response, but got: id={id:?}, {response:?}" + ), + source_ranges: vec![range], + })); } };