diff --git a/src/clientSideScene/sceneEntities.ts b/src/clientSideScene/sceneEntities.ts index bf29bae2b5..c9f1f35192 100644 --- a/src/clientSideScene/sceneEntities.ts +++ b/src/clientSideScene/sceneEntities.ts @@ -92,7 +92,7 @@ import { updateRectangleSketch, } from 'lib/rectangleTool' import { getThemeColorForThreeJs, Themes } from 'lib/theme' -import { err, reportRejection, trap } from 'lib/trap' +import { err, Reason, reportRejection, trap } from 'lib/trap' import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer' import { Point3d } from 'wasm-lib/kcl/bindings/Point3d' import { SegmentInputs } from 'lang/std/stdTypes' @@ -1517,7 +1517,7 @@ export class SceneEntities { maybeSketch, variableDeclarationName ) - if (typeof sk !== 'string') { + if (!(sk instanceof Reason)) { sketch = sk } else if ((maybeSketch as Solid).sketch) { sketch = (maybeSketch as Solid).sketch diff --git a/src/components/ModelingSidebar/ModelingPanes/MemoryPane.tsx b/src/components/ModelingSidebar/ModelingPanes/MemoryPane.tsx index d3597b20c5..9e7ba83a83 100644 --- a/src/components/ModelingSidebar/ModelingPanes/MemoryPane.tsx +++ b/src/components/ModelingSidebar/ModelingPanes/MemoryPane.tsx @@ -10,7 +10,7 @@ import { import { useKclContext } from 'lang/KclProvider' import { useResolvedTheme } from 'hooks/useResolvedTheme' import { ActionButton } from 'components/ActionButton' -import { trap } from 'lib/trap' +import { Reason, trap } from 'lib/trap' import Tooltip from 'components/Tooltip' import { useModelingContext } from 'hooks/useModelingContext' @@ -98,7 +98,7 @@ export const processMemory = (programMemory: ProgramMemory) => { processedMemory[key] = val.value.map(({ ...rest }: ExtrudeSurface) => { return rest }) - } else if (typeof sk !== 'string') { + } else if (!(sk instanceof Reason)) { processedMemory[key] = sk.paths.map(({ __geoMeta, ...rest }: Path) => { return rest }) diff --git a/src/lang/queryAst.ts b/src/lang/queryAst.ts index ca797a4e77..61f8f892cb 100644 --- a/src/lang/queryAst.ts +++ b/src/lang/queryAst.ts @@ -28,7 +28,7 @@ import { getConstraintLevelFromSourceRange, getConstraintType, } from './std/sketchcombos' -import { err } from 'lib/trap' +import { err, Reason } from 'lib/trap' import { ImportStatement } from 'wasm-lib/kcl/bindings/ImportStatement' import { Node } from 'wasm-lib/kcl/bindings/Node' @@ -792,7 +792,7 @@ export function hasExtrudeSketch({ const varValue = programMemory?.get(varName) return ( varValue?.type === 'Solid' || - typeof sketchFromKclValueOptional(varValue, varName) !== 'string' + !(sketchFromKclValueOptional(varValue, varName) instanceof Reason) ) } diff --git a/src/lang/wasm.ts b/src/lang/wasm.ts index 28ab05107a..5c78a76106 100644 --- a/src/lang/wasm.ts +++ b/src/lang/wasm.ts @@ -32,7 +32,7 @@ import { CoreDumpManager } from 'lib/coredump' import openWindow from 'lib/openWindow' import { DefaultPlanes } from 'wasm-lib/kcl/bindings/DefaultPlanes' import { TEST } from 'env' -import { err } from 'lib/trap' +import { err, Reason } from 'lib/trap' import { Configuration } from 'wasm-lib/kcl/bindings/Configuration' import { DeepPartial } from 'lib/types' import { ProjectConfiguration } from 'wasm-lib/kcl/bindings/ProjectConfiguration' @@ -360,7 +360,7 @@ export class ProgramMemory { export function sketchFromKclValueOptional( obj: any, varName: string | null -): Sketch | string { +): Sketch | Reason { if (obj?.value?.type === 'Sketch') return obj.value if (obj?.value?.type === 'Solid') return obj.value.sketch if (obj?.type === 'Solid') return obj.sketch @@ -369,9 +369,11 @@ export function sketchFromKclValueOptional( } const actualType = obj?.value?.type ?? obj?.type if (actualType) { - return `Expected ${varName} to be a sketch or solid, but it was ${actualType} instead.` + return new Reason( + `Expected ${varName} to be a sketch or solid, but it was ${actualType} instead.` + ) } else { - return `Expected ${varName} to be a sketch, but it wasn't.` + return new Reason(`Expected ${varName} to be a sketch, but it wasn't.`) } } @@ -381,8 +383,8 @@ export function sketchFromKclValue( varName: string | null ): Sketch | Error { const result = sketchFromKclValueOptional(obj, varName) - if (typeof result === 'string') { - return new Error(result) + if (result instanceof Reason) { + return result.toError() } return result } diff --git a/src/lib/trap.ts b/src/lib/trap.ts index 686571d79b..ab4551a42a 100644 --- a/src/lib/trap.ts +++ b/src/lib/trap.ts @@ -2,6 +2,23 @@ import toast from 'react-hot-toast' type ExcludeErr = Exclude +/** + * Similar to Error, but more lightweight, without the stack trace. It can also + * be used to represent a reason for not being able to provide an alternative, + * which isn't necessarily an error. + */ +export class Reason { + message: string + + constructor(message: string) { + this.message = message + } + + toError() { + return new Error(this.message) + } +} + /** * This is intentionally *not* exported due to misuse. We'd like to add a lint. */