Compare commits

...

26 Commits

Author SHA1 Message Date
7fd9eb3322 Remove node wrapper around NonCodeMeta
Trying to fix TS unit test errors deserializing JSON AST in Rust.
2024-10-28 17:46:02 -04:00
5aef2b72cb Rename field to avoid name collisions 2024-10-28 17:46:02 -04:00
8ccdf2286d Add minimal failing test 2024-10-28 16:52:07 -04:00
054e235362 Fix wasm TS types 2024-10-28 16:26:04 -04:00
3eebd36a41 Fix tsc errors 2024-10-26 12:31:36 -04:00
412417411b Fix ts_rs bindings 2024-10-26 10:56:06 -04:00
a1c9dd99cf Fix yarn build:wasm 2024-10-25 21:17:12 -04:00
3ed873b6e9 Fix formatting 2024-10-25 21:16:52 -04:00
a172e606b4 WIP
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-10-24 14:02:43 +13:00
c42967d0e7 Fix auto changelog in make-release.sh (#4197) 2024-10-18 11:57:21 -07:00
cb8fc33adb Change CUT_RELEASE_PR to BUILD_RELEASE for out-yml (#4214)
Change CUT_RELEASE_PR to BUILD_RELEASE
2024-10-18 12:46:12 -04:00
2dc8b429ff Cut release v0.26.0 (#4196) 2024-10-18 09:17:13 -07:00
19ffa220e8 Fix reading files from WebAssembly (#4183) 2024-10-18 14:43:01 +00:00
5332ddd88e Add more Machine API capabilities (#4203) 2024-10-18 10:25:54 -04:00
11d9a2ee00 Fix test settings to actually get used (#4191)
* Fix test settings to actually get used

Co-authored-by: Frank Noirot <frank@zoo.dev>

* Export file size changed out from under us again, relax this test to just be above a reasonable size

* Missed on updated export expectation

* Wrong check, should just be greater than

* Fix E2E test, remove console log

* fmt

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Sketchy rectangle commit fix

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Re-run CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit 2ace7a3b0e.

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Bump timeouts for snapshots

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Re-run CI

---------

Co-authored-by: Frank Noirot <frank@zoo.dev>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-18 08:31:00 +00:00
bfebc41a5c Franknoirot/adhoc/revert-dedupe-commits (#4213)
* Revert "KCL: Fix duplicate 'type' key"

This reverts commit f650281855.

* Revert "Remove duplicate "type" field in the snapshots (#4211)"

This reverts commit 824b4c823e.
2024-10-18 02:16:44 -04:00
824b4c823e Remove duplicate "type" field in the snapshots (#4211)
* Remove duplicate "type" field in the snapshots

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Confirm

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2024-10-18 01:32:03 -04:00
785002fa4e Live reload on file tree changes and project settings changes (#4142)
* Reload FileTree and File when changed externally

* Added tests

* Make file and project creation a bit more reliable
2024-10-17 23:42:24 -04:00
f650281855 KCL: Fix duplicate 'type' key 2024-10-17 20:37:05 -07:00
9f6999829a Fix broken digest code (#4206)
I broke the typescript bindings in https://github.com/KittyCAD/modeling-app/pull/4193 -- basically the `digest: Option<Digest>` fields previously allowed Typescript to not set a value for the `digest` key at all, but somehow my change made it required in the Typescript.

Fix is to apply `#[ts(optional)]`, see docs at https://docs.rs/ts-rs/latest/ts_rs/trait.TS.html#struct-field-attributes
2024-10-17 20:36:40 -07:00
a14bbaa237 Update machine-api spec (#4205)
* YOYO NEW API SPEC!

* New machine-api types

* empty

* Update .codespellrc

* Update .codespellrc

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2024-10-17 20:01:34 -07:00
0706624381 KCL: Refactor array-indexing code (#4173)
Neater code, and better error messages.
2024-10-17 16:29:27 -07:00
ef0ae5e06e Add syntax highlighting for comparison operators (#4182)
* Add syntax highlighting for comparison operators

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Confirm

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-17 23:29:13 +00:00
a010743abb KCL: Skip serializing default values for AST nodes (#4193)
This will make our snapshots and JSON representations easier to read (making our tests less verbose).
2024-10-17 16:22:40 -07:00
057ee479c3 Update machine-api spec (#4201)
* YOYO NEW API SPEC!

* New machine-api types

* empt

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
2024-10-17 16:03:55 -07:00
7218efc489 Fix weird machine api behavior/add status (#4186)
* YOYO NEW API SPEC!

* fies

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* add status

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* pass disabled

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* disabled

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* add nozzle diameter

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* ypdates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* update types

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* update types

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* update types

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Paul Tagliamonte <paul@zoo.dev>
2024-10-17 15:30:46 -07:00
208 changed files with 20992 additions and 16777 deletions

View File

@ -1,3 +1,3 @@
[codespell] [codespell]
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey,atleast,ue,afterall ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey,atleast,ue,afterall
skip: **/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md,.yarn.lock,**/yarn.lock skip: **/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md,.yarn.lock,**/yarn.lock,./openapi/*.json,./src/lib/machine-api.d.ts

View File

@ -211,7 +211,7 @@ jobs:
out/*-x86_64-linux.* out/*-x86_64-linux.*
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
if: ${{ env.CUT_RELEASE_PR == 'true' }} if: ${{ env.BUILD_RELEASE == 'true' }}
with: with:
name: out-yml name: out-yml
path: | path: |

View File

@ -9,7 +9,7 @@ Draw a line segment relative to the current origin using the polar
measure of some angle and distance. measure of some angle and distance.
```js ```js
angledLine(data: AngledLineData, sketch: Sketch, tag?: TagDeclarator) -> Sketch angledLine(data: AngledLineData, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ angledLine(data: AngledLineData, sketch: Sketch, tag?: TagDeclarator) -> Sketch
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`AngledLineData`](/docs/kcl/types/AngledLineData) | Data to draw an angled line. | Yes | | `data` | [`AngledLineData`](/docs/kcl/types/AngledLineData) | Data to draw an angled line. | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Create a line segment from the current 2-dimensional sketch origin
along some angle (in degrees) for some relative length in the 'x' dimension. along some angle (in degrees) for some relative length in the 'x' dimension.
```js ```js
angledLineOfXLength(data: AngledLineData, sketch: Sketch, tag?: TagDeclarator) -> Sketch angledLineOfXLength(data: AngledLineData, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ angledLineOfXLength(data: AngledLineData, sketch: Sketch, tag?: TagDeclarator) -
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`AngledLineData`](/docs/kcl/types/AngledLineData) | Data to draw an angled line. | Yes | | `data` | [`AngledLineData`](/docs/kcl/types/AngledLineData) | Data to draw an angled line. | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Create a line segment from the current 2-dimensional sketch origin
along some angle (in degrees) for some relative length in the 'y' dimension. along some angle (in degrees) for some relative length in the 'y' dimension.
```js ```js
angledLineOfYLength(data: AngledLineData, sketch: Sketch, tag?: TagDeclarator) -> Sketch angledLineOfYLength(data: AngledLineData, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ angledLineOfYLength(data: AngledLineData, sketch: Sketch, tag?: TagDeclarator) -
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`AngledLineData`](/docs/kcl/types/AngledLineData) | Data to draw an angled line. | Yes | | `data` | [`AngledLineData`](/docs/kcl/types/AngledLineData) | Data to draw an angled line. | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Draw an angled line from the current origin, constructing a line segment
such that the newly created line intersects the desired target line segment. such that the newly created line intersects the desired target line segment.
```js ```js
angledLineThatIntersects(data: AngledLineThatIntersectsData, sketch: Sketch, tag?: TagDeclarator) -> Sketch angledLineThatIntersects(data: AngledLineThatIntersectsData, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ angledLineThatIntersects(data: AngledLineThatIntersectsData, sketch: Sketch, tag
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`AngledLineThatIntersectsData`](/docs/kcl/types/AngledLineThatIntersectsData) | Data for drawing an angled line that intersects with a given line. | Yes | | `data` | [`AngledLineThatIntersectsData`](/docs/kcl/types/AngledLineThatIntersectsData) | Data for drawing an angled line that intersects with a given line. | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Create a line segment from the current 2-dimensional sketch origin
along some angle (in degrees) for some length, ending at the provided value in the 'x' dimension. along some angle (in degrees) for some length, ending at the provided value in the 'x' dimension.
```js ```js
angledLineToX(data: AngledLineToData, sketch: Sketch, tag?: TagDeclarator) -> Sketch angledLineToX(data: AngledLineToData, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ angledLineToX(data: AngledLineToData, sketch: Sketch, tag?: TagDeclarator) -> Sk
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`AngledLineToData`](/docs/kcl/types/AngledLineToData) | Data to draw an angled line to a point. | Yes | | `data` | [`AngledLineToData`](/docs/kcl/types/AngledLineToData) | Data to draw an angled line to a point. | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Create a line segment from the current 2-dimensional sketch origin
along some angle (in degrees) for some length, ending at the provided value in the 'y' dimension. along some angle (in degrees) for some length, ending at the provided value in the 'y' dimension.
```js ```js
angledLineToY(data: AngledLineToData, sketch: Sketch, tag?: TagDeclarator) -> Sketch angledLineToY(data: AngledLineToData, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ angledLineToY(data: AngledLineToData, sketch: Sketch, tag?: TagDeclarator) -> Sk
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`AngledLineToData`](/docs/kcl/types/AngledLineToData) | Data to draw an angled line to a point. | Yes | | `data` | [`AngledLineToData`](/docs/kcl/types/AngledLineToData) | Data to draw an angled line to a point. | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -11,7 +11,7 @@ The arc is constructed such that the current position of the sketch is placed al
Unless this makes a lot of sense and feels like what you're looking for to construct your shape, you're likely looking for tangentialArc. Unless this makes a lot of sense and feels like what you're looking for to construct your shape, you're likely looking for tangentialArc.
```js ```js
arc(data: ArcData, sketch: Sketch, tag?: TagDeclarator) -> Sketch arc(data: ArcData, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -21,7 +21,7 @@ arc(data: ArcData, sketch: Sketch, tag?: TagDeclarator) -> Sketch
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`ArcData`](/docs/kcl/types/ArcData) | Data to draw an arc. | Yes | | `data` | [`ArcData`](/docs/kcl/types/ArcData) | Data to draw an arc. | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Draw a smooth, continuous, curved line segment from the current origin to
the desired (x, y), using a number of control points to shape the curve's shape. the desired (x, y), using a number of control points to shape the curve's shape.
```js ```js
bezierCurve(data: BezierData, sketch: Sketch, tag?: TagDeclarator) -> Sketch bezierCurve(data: BezierData, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ bezierCurve(data: BezierData, sketch: Sketch, tag?: TagDeclarator) -> Sketch
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`BezierData`](/docs/kcl/types/BezierData) | Data to draw a bezier curve. | Yes | | `data` | [`BezierData`](/docs/kcl/types/BezierData) | Data to draw a bezier curve. | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Cut a straight transitional edge along a tagged path.
Chamfer is similar in function and use to a fillet, except a fillet will blend the transition along an edge, rather than cut a sharp, straight transitional edge. Chamfer is similar in function and use to a fillet, except a fillet will blend the transition along an edge, rather than cut a sharp, straight transitional edge.
```js ```js
chamfer(data: ChamferData, solid: Solid, tag?: TagDeclarator) -> Solid chamfer(data: ChamferData, solid: Solid, tag?: TagNode) -> Solid
``` ```
@ -19,7 +19,7 @@ chamfer(data: ChamferData, solid: Solid, tag?: TagDeclarator) -> Solid
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`ChamferData`](/docs/kcl/types/ChamferData) | Data for chamfers. | Yes | | `data` | [`ChamferData`](/docs/kcl/types/ChamferData) | Data for chamfers. | Yes |
| `solid` | [`Solid`](/docs/kcl/types/Solid) | An solid is a collection of extrude surfaces. | Yes | | `solid` | [`Solid`](/docs/kcl/types/Solid) | An solid is a collection of extrude surfaces. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Construct a 2-dimensional circle, of the specified radius, centered at
the provided (x, y) origin point. the provided (x, y) origin point.
```js ```js
circle(data: CircleData, sketch_surface_or_group: SketchOrSurface, tag?: TagDeclarator) -> Sketch circle(data: CircleData, sketch_surface_or_group: SketchOrSurface, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ circle(data: CircleData, sketch_surface_or_group: SketchOrSurface, tag?: TagDecl
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`CircleData`](/docs/kcl/types/CircleData) | Data for drawing an circle | Yes | | `data` | [`CircleData`](/docs/kcl/types/CircleData) | Data for drawing an circle | Yes |
| `sketch_surface_or_group` | [`SketchOrSurface`](/docs/kcl/types/SketchOrSurface) | A sketch surface or a sketch. | Yes | | `sketch_surface_or_group` | [`SketchOrSurface`](/docs/kcl/types/SketchOrSurface) | A sketch surface or a sketch. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Construct a line segment from the current origin back to the profile's
origin, ensuring the resulting 2-dimensional sketch is not open-ended. origin, ensuring the resulting 2-dimensional sketch is not open-ended.
```js ```js
close(sketch: Sketch, tag?: TagDeclarator) -> Sketch close(sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -18,7 +18,7 @@ close(sketch: Sketch, tag?: TagDeclarator) -> Sketch
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Blend a transitional edge along a tagged path, smoothing the sharp edge.
Fillet is similar in function and use to a chamfer, except a chamfer will cut a sharp transition along an edge while fillet will smoothly blend the transition. Fillet is similar in function and use to a chamfer, except a chamfer will cut a sharp transition along an edge while fillet will smoothly blend the transition.
```js ```js
fillet(data: FilletData, solid: Solid, tag?: TagDeclarator) -> Solid fillet(data: FilletData, solid: Solid, tag?: TagNode) -> Solid
``` ```
@ -19,7 +19,7 @@ fillet(data: FilletData, solid: Solid, tag?: TagDeclarator) -> Solid
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`FilletData`](/docs/kcl/types/FilletData) | Data for fillets. | Yes | | `data` | [`FilletData`](/docs/kcl/types/FilletData) | Data for fillets. | Yes |
| `solid` | [`Solid`](/docs/kcl/types/Solid) | An solid is a collection of extrude surfaces. | Yes | | `solid` | [`Solid`](/docs/kcl/types/Solid) | An solid is a collection of extrude surfaces. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Draw a line relative to the current origin to a specified (x, y) away
from the current position. from the current position.
```js ```js
line(delta: [number], sketch: Sketch, tag?: TagDeclarator) -> Sketch line(delta: [number], sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ line(delta: [number], sketch: Sketch, tag?: TagDeclarator) -> Sketch
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `delta` | `[number]` | | Yes | | `delta` | `[number]` | | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Draw a line from the current origin to some absolute (x, y) point.
```js ```js
lineTo(to: [number], sketch: Sketch, tag?: TagDeclarator) -> Sketch lineTo(to: [number], sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ lineTo(to: [number], sketch: Sketch, tag?: TagDeclarator) -> Sketch
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `to` | `[number]` | | Yes | | `to` | `[number]` | | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Start a new profile at a given point.
```js ```js
startProfileAt(to: [number], sketch_surface: SketchSurface, tag?: TagDeclarator) -> Sketch startProfileAt(to: [number], sketch_surface: SketchSurface, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ startProfileAt(to: [number], sketch_surface: SketchSurface, tag?: TagDeclarator)
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `to` | `[number]` | | Yes | | `to` | `[number]` | | Yes |
| `sketch_surface` | [`SketchSurface`](/docs/kcl/types/SketchSurface) | A sketch type. | Yes | | `sketch_surface` | [`SketchSurface`](/docs/kcl/types/SketchSurface) | A sketch type. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@ Draw a curved line segment along part of an imaginary circle.
The arc is constructed such that the last line segment is placed tangent to the imaginary circle of the specified radius. The resulting arc is the segment of the imaginary circle from that tangent point for 'offset' degrees along the imaginary circle. The arc is constructed such that the last line segment is placed tangent to the imaginary circle of the specified radius. The resulting arc is the segment of the imaginary circle from that tangent point for 'offset' degrees along the imaginary circle.
```js ```js
tangentialArc(data: TangentialArcData, sketch: Sketch, tag?: TagDeclarator) -> Sketch tangentialArc(data: TangentialArcData, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ tangentialArc(data: TangentialArcData, sketch: Sketch, tag?: TagDeclarator) -> S
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`TangentialArcData`](/docs/kcl/types/TangentialArcData) | Data to draw a tangential arc. | Yes | | `data` | [`TangentialArcData`](/docs/kcl/types/TangentialArcData) | Data to draw a tangential arc. | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Starting at the current sketch's origin, draw a curved line segment along
some part of an imaginary circle until it reaches the desired (x, y) coordinates. some part of an imaginary circle until it reaches the desired (x, y) coordinates.
```js ```js
tangentialArcTo(to: [number], sketch: Sketch, tag?: TagDeclarator) -> Sketch tangentialArcTo(to: [number], sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ tangentialArcTo(to: [number], sketch: Sketch, tag?: TagDeclarator) -> Sketch
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `to` | `[number]` | | Yes | | `to` | `[number]` | | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Starting at the current sketch's origin, draw a curved line segment along
some part of an imaginary circle until it reaches a point the given (x, y) distance away. some part of an imaginary circle until it reaches a point the given (x, y) distance away.
```js ```js
tangentialArcToRelative(delta: [number], sketch: Sketch, tag?: TagDeclarator) -> Sketch tangentialArcToRelative(delta: [number], sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ tangentialArcToRelative(delta: [number], sketch: Sketch, tag?: TagDeclarator) ->
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `delta` | `[number]` | | Yes | | `delta` | `[number]` | | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -18,7 +18,7 @@ A base path.
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `from` |`[number, number]`| The from point. | No | | `from` |`[number, number]`| The from point. | No |
| `to` |`[number, number]`| The to point. | No | | `to` |`[number, number]`| The to point. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag of the path. | No |
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No | | `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |

View File

@ -22,12 +22,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `Literal`| | No | | `type` |enum: [`Literal`](/docs/kcl/types/Literal)| | No |
| `kind` |[`Literal`](/docs/kcl/types/Literal)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `value` |[`LiteralValue`](/docs/kcl/types/LiteralValue)| | No |
| `raw` |`string`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -43,10 +41,9 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No | | `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No |
| `kind` |[`Identifier`](/docs/kcl/types/Identifier)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `name` |`string`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -61,13 +58,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `BinaryExpression`| | No | | `type` |enum: [`BinaryExpression`](/docs/kcl/types/BinaryExpression)| | No |
| `kind` |[`BinaryExpression`](/docs/kcl/types/BinaryExpression)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `operator` |[`BinaryOperator`](/docs/kcl/types/BinaryOperator)| | No |
| `left` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| | No |
| `right` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -82,13 +76,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `CallExpression`| | No | | `type` |enum: [`CallExpression`](/docs/kcl/types/CallExpression)| | No |
| `kind` |[`CallExpression`](/docs/kcl/types/CallExpression)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `callee` |[`Identifier`](/docs/kcl/types/Identifier)| | No |
| `arguments` |`[` [`Expr`](/docs/kcl/types/Expr) `]`| | No |
| `optional` |`boolean`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -103,12 +94,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `UnaryExpression`| | No | | `type` |enum: [`UnaryExpression`](/docs/kcl/types/UnaryExpression)| | No |
| `kind` |[`UnaryExpression`](/docs/kcl/types/UnaryExpression)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `operator` |[`UnaryOperator`](/docs/kcl/types/UnaryOperator)| | No |
| `argument` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -123,13 +112,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `MemberExpression`| | No | | `type` |enum: [`MemberExpression`](/docs/kcl/types/MemberExpression)| | No |
| `kind` |[`MemberExpression`](/docs/kcl/types/MemberExpression)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `object` |[`MemberObject`](/docs/kcl/types/MemberObject)| | No |
| `property` |[`LiteralIdentifier`](/docs/kcl/types/LiteralIdentifier)| | No |
| `computed` |`boolean`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -144,14 +130,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `IfExpression`| | No | | `type` |enum: [`IfExpression`](/docs/kcl/types/IfExpression)| | No |
| `kind` |[`IfExpression`](/docs/kcl/types/IfExpression)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `cond` |[`Expr`](/docs/kcl/types/Expr)| | No |
| `then_val` |[`Program`](/docs/kcl/types/Program)| | No |
| `else_ifs` |`[` [`ElseIf`](/docs/kcl/types/ElseIf) `]`| | No |
| `final_else` |[`Program`](/docs/kcl/types/Program)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----

View File

@ -22,13 +22,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `ImportStatement`| | No | | `type` |enum: [`ImportStatement`](/docs/kcl/types/ImportStatement)| | No |
| `kind` |[`ImportStatement`](/docs/kcl/types/ImportStatement)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `items` |`[` [`ImportItem`](/docs/kcl/types/ImportItem) `]`| | No |
| `path` |`string`| | No |
| `raw_path` |`string`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -43,11 +40,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `ExpressionStatement`| | No | | `type` |enum: [`ExpressionStatement`](/docs/kcl/types/ExpressionStatement)| | No |
| `kind` |[`ExpressionStatement`](/docs/kcl/types/ExpressionStatement)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `expression` |[`Expr`](/docs/kcl/types/Expr)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -62,13 +58,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `VariableDeclaration`| | No | | `type` |enum: [`VariableDeclaration`](/docs/kcl/types/VariableDeclaration)| | No |
| `kind` |[`VariableDeclaration`](/docs/kcl/types/VariableDeclaration)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `declarations` |`[` [`VariableDeclarator`](/docs/kcl/types/VariableDeclarator) `]`| | No |
| `visibility` |[`ItemVisibility`](/docs/kcl/types/ItemVisibility)| | No |
| `kind` |[`VariableKind`](/docs/kcl/types/VariableKind)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -83,11 +76,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `ReturnStatement`| | No | | `type` |enum: [`ReturnStatement`](/docs/kcl/types/ReturnStatement)| | No |
| `kind` |[`ReturnStatement`](/docs/kcl/types/ReturnStatement)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `argument` |[`Expr`](/docs/kcl/types/Expr)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----

View File

@ -28,7 +28,7 @@ A fillet.
| `id` |`string`| The id of the engine command that called this fillet. | No | | `id` |`string`| The id of the engine command that called this fillet. | No |
| `radius` |`number`| | No | | `radius` |`number`| | No |
| `edgeId` |`string`| The engine id of the edge to fillet. | No | | `edgeId` |`string`| The engine id of the edge to fillet. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| | No |
---- ----
@ -48,7 +48,7 @@ A chamfer.
| `id` |`string`| The id of the engine command that called this chamfer. | No | | `id` |`string`| The id of the engine command that called this chamfer. | No |
| `length` |`number`| | No | | `length` |`number`| | No |
| `edgeId` |`string`| The engine id of the edge to chamfer. | No | | `edgeId` |`string`| The engine id of the edge to chamfer. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| | No |
---- ----

View File

@ -15,10 +15,8 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `cond` |[`Expr`](/docs/kcl/types/Expr)| | No | | `cond` |[`Expr`](/docs/kcl/types/Expr)| | No |
| `then_val` |[`Program`](/docs/kcl/types/Program)| | No | | `then_val` |[`UnboxedNode_for_Program`](/docs/kcl/types/UnboxedNode_for_Program)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No | | `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |

View File

@ -23,12 +23,10 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `Literal`| | No | | `type` |enum: [`Literal`](/docs/kcl/types/Literal)| | No |
| `kind` |[`Literal`](/docs/kcl/types/Literal)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `value` |[`LiteralValue`](/docs/kcl/types/LiteralValue)| An expression can be evaluated to yield a single KCL value. | No |
| `raw` |`string`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -44,10 +42,9 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No | | `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No |
| `kind` |[`Identifier`](/docs/kcl/types/Identifier)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `name` |`string`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -63,10 +60,9 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: [`TagDeclarator`](/docs/kcl/types#tag-declaration)| | No | | `type` |enum: [`TagDeclarator`](/docs/kcl/types#tag-declaration)| | No |
| `kind` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `value` |`string`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -81,13 +77,10 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `BinaryExpression`| | No | | `type` |enum: [`BinaryExpression`](/docs/kcl/types/BinaryExpression)| | No |
| `kind` |[`BinaryExpression`](/docs/kcl/types/BinaryExpression)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `operator` |[`BinaryOperator`](/docs/kcl/types/BinaryOperator)| An expression can be evaluated to yield a single KCL value. | No |
| `left` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| An expression can be evaluated to yield a single KCL value. | No |
| `right` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| An expression can be evaluated to yield a single KCL value. | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -103,11 +96,9 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: [`FunctionExpression`](/docs/kcl/types/FunctionExpression)| | No | | `type` |enum: [`FunctionExpression`](/docs/kcl/types/FunctionExpression)| | No |
| `kind` |[`FunctionExpression`](/docs/kcl/types/FunctionExpression)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `params` |`[` [`Parameter`](/docs/kcl/types/Parameter) `]`| | No |
| `body` |[`Program`](/docs/kcl/types/Program)| An expression can be evaluated to yield a single KCL value. | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -122,13 +113,10 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `CallExpression`| | No | | `type` |enum: [`CallExpression`](/docs/kcl/types/CallExpression)| | No |
| `kind` |[`CallExpression`](/docs/kcl/types/CallExpression)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `callee` |[`Identifier`](/docs/kcl/types/Identifier)| An expression can be evaluated to yield a single KCL value. | No |
| `arguments` |`[` [`Expr`](/docs/kcl/types/Expr) `]`| | No |
| `optional` |`boolean`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -143,12 +131,10 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `PipeExpression`| | No | | `type` |enum: [`PipeExpression`](/docs/kcl/types/PipeExpression)| | No |
| `kind` |[`PipeExpression`](/docs/kcl/types/PipeExpression)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `body` |`[` [`Expr`](/docs/kcl/types/Expr) `]`| | No |
| `nonCodeMeta` |[`NonCodeMeta`](/docs/kcl/types/NonCodeMeta)| An expression can be evaluated to yield a single KCL value. | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -163,10 +149,10 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `PipeSubstitution`| | No | | `type` |enum: [`PipeSubstitution`](/docs/kcl/types/PipeSubstitution)| | No |
| `kind` |[`PipeSubstitution`](/docs/kcl/types/PipeSubstitution)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -181,12 +167,10 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `ArrayExpression`| | No | | `type` |enum: [`ArrayExpression`](/docs/kcl/types/ArrayExpression)| | No |
| `kind` |[`ArrayExpression`](/docs/kcl/types/ArrayExpression)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `elements` |`[` [`Expr`](/docs/kcl/types/Expr) `]`| | No |
| `nonCodeMeta` |[`NonCodeMeta`](/docs/kcl/types/NonCodeMeta)| An expression can be evaluated to yield a single KCL value. | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -201,13 +185,10 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `ArrayRangeExpression`| | No | | `type` |enum: [`ArrayRangeExpression`](/docs/kcl/types/ArrayRangeExpression)| | No |
| `kind` |[`ArrayRangeExpression`](/docs/kcl/types/ArrayRangeExpression)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `startElement` |[`Expr`](/docs/kcl/types/Expr)| An expression can be evaluated to yield a single KCL value. | No |
| `endElement` |[`Expr`](/docs/kcl/types/Expr)| An expression can be evaluated to yield a single KCL value. | No |
| `endInclusive` |`boolean`| Is the `end_element` included in the range? | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -222,12 +203,10 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `ObjectExpression`| | No | | `type` |enum: [`ObjectExpression`](/docs/kcl/types/ObjectExpression)| | No |
| `kind` |[`ObjectExpression`](/docs/kcl/types/ObjectExpression)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `properties` |`[` [`ObjectProperty`](/docs/kcl/types/ObjectProperty) `]`| | No |
| `nonCodeMeta` |[`NonCodeMeta`](/docs/kcl/types/NonCodeMeta)| An expression can be evaluated to yield a single KCL value. | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -242,13 +221,10 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `MemberExpression`| | No | | `type` |enum: [`MemberExpression`](/docs/kcl/types/MemberExpression)| | No |
| `kind` |[`MemberExpression`](/docs/kcl/types/MemberExpression)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `object` |[`MemberObject`](/docs/kcl/types/MemberObject)| An expression can be evaluated to yield a single KCL value. | No |
| `property` |[`LiteralIdentifier`](/docs/kcl/types/LiteralIdentifier)| An expression can be evaluated to yield a single KCL value. | No |
| `computed` |`boolean`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -263,12 +239,10 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `UnaryExpression`| | No | | `type` |enum: [`UnaryExpression`](/docs/kcl/types/UnaryExpression)| | No |
| `kind` |[`UnaryExpression`](/docs/kcl/types/UnaryExpression)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `operator` |[`UnaryOperator`](/docs/kcl/types/UnaryOperator)| An expression can be evaluated to yield a single KCL value. | No |
| `argument` |[`BinaryPart`](/docs/kcl/types/BinaryPart)| An expression can be evaluated to yield a single KCL value. | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -283,14 +257,10 @@ An expression can be evaluated to yield a single KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `IfExpression`| | No | | `type` |enum: [`IfExpression`](/docs/kcl/types/IfExpression)| | No |
| `kind` |[`IfExpression`](/docs/kcl/types/IfExpression)| An expression can be evaluated to yield a single KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `cond` |[`Expr`](/docs/kcl/types/Expr)| An expression can be evaluated to yield a single KCL value. | No |
| `then_val` |[`Program`](/docs/kcl/types/Program)| An expression can be evaluated to yield a single KCL value. | No |
| `else_ifs` |`[` [`ElseIf`](/docs/kcl/types/ElseIf) `]`| | No |
| `final_else` |[`Program`](/docs/kcl/types/Program)| An expression can be evaluated to yield a single KCL value. | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----

View File

@ -26,7 +26,7 @@ An extrude plane.
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `extrudePlane`| | No | | `type` |enum: `extrudePlane`| | No |
| `faceId` |`string`| The face id for the extrude plane. | No | | `faceId` |`string`| The face id for the extrude plane. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag. | No |
| `id` |`string`| The id of the geometry. | No | | `id` |`string`| The id of the geometry. | No |
| `sourceRange` |`SourceRange`| The source range. | No | | `sourceRange` |`SourceRange`| The source range. | No |
@ -46,7 +46,7 @@ An extruded arc.
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `extrudeArc`| | No | | `type` |enum: `extrudeArc`| | No |
| `faceId` |`string`| The face id for the extrude plane. | No | | `faceId` |`string`| The face id for the extrude plane. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag. | No |
| `id` |`string`| The id of the geometry. | No | | `id` |`string`| The id of the geometry. | No |
| `sourceRange` |`SourceRange`| The source range. | No | | `sourceRange` |`SourceRange`| The source range. | No |
@ -66,7 +66,7 @@ Geometry metadata.
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `chamfer`| | No | | `type` |enum: `chamfer`| | No |
| `faceId` |`string`| The id for the chamfer surface. | No | | `faceId` |`string`| The id for the chamfer surface. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag. | No |
| `id` |`string`| The id of the geometry. | No | | `id` |`string`| The id of the geometry. | No |
| `sourceRange` |`SourceRange`| The source range. | No | | `sourceRange` |`SourceRange`| The source range. | No |
@ -86,7 +86,7 @@ Geometry metadata.
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `fillet`| | No | | `type` |enum: `fillet`| | No |
| `faceId` |`string`| The id for the fillet surface. | No | | `faceId` |`string`| The id for the fillet surface. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag. | No |
| `id` |`string`| The id of the geometry. | No | | `id` |`string`| The id of the geometry. | No |
| `sourceRange` |`SourceRange`| The source range. | No | | `sourceRange` |`SourceRange`| The source range. | No |

View File

@ -15,10 +15,8 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `params` |`[` [`Parameter`](/docs/kcl/types/Parameter) `]`| | No | | `params` |`[` [`Parameter`](/docs/kcl/types/Parameter) `]`| | No |
| `body` |[`Program`](/docs/kcl/types/Program)| | No | | `body` |[`UnboxedNode_for_Program`](/docs/kcl/types/UnboxedNode_for_Program)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No | | `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |

View File

@ -15,8 +15,6 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `name` |`string`| | No | | `name` |`string`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No | | `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |

View File

@ -15,10 +15,8 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `name` |[`Identifier`](/docs/kcl/types/Identifier)| Name of the item to import. | No | | `name` |[`UnboxedNode_for_Identifier`](/docs/kcl/types/UnboxedNode_for_Identifier)| Name of the item to import. | No |
| `alias` |[`Identifier`](/docs/kcl/types/Identifier)| Rename the item using an identifier after "as". | No | | `alias` |[`UnboxedNode_for_Identifier`](/docs/kcl/types/UnboxedNode_for_Identifier)| Rename the item using an identifier after "as". | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No | | `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |

View File

@ -59,10 +59,9 @@ Any KCL value.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: [`TagDeclarator`](/docs/kcl/types#tag-declaration)| | No | | `type` |enum: [`TagDeclarator`](/docs/kcl/types#tag-declaration)| | No |
| `kind` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| Any KCL value. | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `value` |`string`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -183,7 +182,7 @@ Data for an imported geometry.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `Function`| | No | | `type` |enum: `Function`| | No |
| `expression` |[`FunctionExpression`](/docs/kcl/types/FunctionExpression)| Any KCL value. | No | | `expression` |[`UnboxedNode_for_FunctionExpression`](/docs/kcl/types/UnboxedNode_for_FunctionExpression)| Any KCL value. | No |
| `memory` |[`ProgramMemory`](/docs/kcl/types/ProgramMemory)| Any KCL value. | No | | `memory` |[`ProgramMemory`](/docs/kcl/types/ProgramMemory)| Any KCL value. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No | | `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |

View File

@ -23,10 +23,9 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No | | `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No |
| `kind` |[`Identifier`](/docs/kcl/types/Identifier)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `name` |`string`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -41,12 +40,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `Literal`| | No | | `type` |enum: [`Literal`](/docs/kcl/types/Literal)| | No |
| `kind` |[`Literal`](/docs/kcl/types/Literal)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `value` |[`LiteralValue`](/docs/kcl/types/LiteralValue)| | No |
| `raw` |`string`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----

View File

@ -22,13 +22,10 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `MemberExpression`| | No | | `type` |enum: [`MemberExpression`](/docs/kcl/types/MemberExpression)| | No |
| `kind` |[`MemberExpression`](/docs/kcl/types/MemberExpression)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `object` |[`MemberObject`](/docs/kcl/types/MemberObject)| | No |
| `property` |[`LiteralIdentifier`](/docs/kcl/types/LiteralIdentifier)| | No |
| `computed` |`boolean`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----
@ -44,10 +41,9 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No | | `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No |
| `kind` |[`Identifier`](/docs/kcl/types/Identifier)| | No |
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `name` |`string`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |
---- ----

View File

@ -16,7 +16,7 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `nonCodeNodes` |`object`| | No | | `nonCodeNodes` |`object`| | No |
| `start` |`[` [`NonCodeNode`](/docs/kcl/types/NonCodeNode) `]`| | No | | `start` |`[` [`UnboxedNode_for_NonCodeNode`](/docs/kcl/types/UnboxedNode_for_NonCodeNode) `]`| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No | | `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |

View File

@ -15,8 +15,6 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `value` |[`NonCodeValue`](/docs/kcl/types/NonCodeValue)| | No | | `value` |[`NonCodeValue`](/docs/kcl/types/NonCodeValue)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No | | `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |

View File

@ -15,9 +15,7 @@ layout: manual
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No | | `key` |[`UnboxedNode_for_Identifier`](/docs/kcl/types/UnboxedNode_for_Identifier)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `key` |[`Identifier`](/docs/kcl/types/Identifier)| | No |
| `value` |[`Expr`](/docs/kcl/types/Expr)| | No | | `value` |[`Expr`](/docs/kcl/types/Expr)| | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No | | `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |

View File

@ -16,7 +16,7 @@ Parameter of a KCL function.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `identifier` |[`Identifier`](/docs/kcl/types/Identifier)| The parameter's label or name. | No | | `identifier` |[`UnboxedNode_for_Identifier`](/docs/kcl/types/UnboxedNode_for_Identifier)| The parameter's label or name. | No |
| `optional` |`boolean`| Is the parameter optional? | No | | `optional` |`boolean`| Is the parameter optional? | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No | | `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |

View File

@ -27,7 +27,7 @@ A path that goes to a point.
| `type` |enum: `ToPoint`| | No | | `type` |enum: `ToPoint`| | No |
| `from` |`[number, number]`| The from point. | No | | `from` |`[number, number]`| The from point. | No |
| `to` |`[number, number]`| The to point. | No | | `to` |`[number, number]`| The to point. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag of the path. | No |
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No | | `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
@ -49,7 +49,7 @@ A arc that is tangential to the last path segment that goes to a point
| `ccw` |`boolean`| arc's direction | No | | `ccw` |`boolean`| arc's direction | No |
| `from` |`[number, number]`| The from point. | No | | `from` |`[number, number]`| The from point. | No |
| `to` |`[number, number]`| The to point. | No | | `to` |`[number, number]`| The to point. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag of the path. | No |
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No | | `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
@ -71,7 +71,7 @@ A arc that is tangential to the last path segment
| `ccw` |`boolean`| arc's direction | No | | `ccw` |`boolean`| arc's direction | No |
| `from` |`[number, number]`| The from point. | No | | `from` |`[number, number]`| The from point. | No |
| `to` |`[number, number]`| The to point. | No | | `to` |`[number, number]`| The to point. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag of the path. | No |
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No | | `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
@ -94,7 +94,7 @@ a complete arc
| `ccw` |`boolean`| arc's direction | No | | `ccw` |`boolean`| arc's direction | No |
| `from` |`[number, number]`| The from point. | No | | `from` |`[number, number]`| The from point. | No |
| `to` |`[number, number]`| The to point. | No | | `to` |`[number, number]`| The to point. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag of the path. | No |
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No | | `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
@ -115,7 +115,7 @@ A path that is horizontal.
| `x` |`number`| The x coordinate. | No | | `x` |`number`| The x coordinate. | No |
| `from` |`[number, number]`| The from point. | No | | `from` |`[number, number]`| The from point. | No |
| `to` |`[number, number]`| The to point. | No | | `to` |`[number, number]`| The to point. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag of the path. | No |
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No | | `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
@ -137,7 +137,7 @@ An angled line to.
| `y` |`number`| The y coordinate. | No | | `y` |`number`| The y coordinate. | No |
| `from` |`[number, number]`| The from point. | No | | `from` |`[number, number]`| The from point. | No |
| `to` |`[number, number]`| The to point. | No | | `to` |`[number, number]`| The to point. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag of the path. | No |
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No | | `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
@ -157,7 +157,7 @@ A base path.
| `type` |enum: `Base`| | No | | `type` |enum: `Base`| | No |
| `from` |`[number, number]`| The from point. | No | | `from` |`[number, number]`| The from point. | No |
| `to` |`[number, number]`| The to point. | No | | `to` |`[number, number]`| The to point. | No |
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No | | `tag` |[`TagNode`](/docs/kcl/types/TagNode)| The tag of the path. | No |
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No | | `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |

View File

@ -16,10 +16,8 @@ A KCL program top level, or function body.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `body` |`[` [`BodyItem`](/docs/kcl/types/BodyItem) `]`| | No | | `body` |`[` [`BodyItem`](/docs/kcl/types/BodyItem) `]`| | No |
| `nonCodeMeta` |[`NonCodeMeta`](/docs/kcl/types/NonCodeMeta)| A KCL program top level, or function body. | No | | `nonCodeMeta` |[`UnboxedNode_for_NonCodeMeta`](/docs/kcl/types/UnboxedNode_for_NonCodeMeta)| A KCL program top level, or function body. | No |
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No | | `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |

View File

@ -9,7 +9,7 @@ Draw a line relative to the current origin to a specified distance away
from the current position along the 'x' axis. from the current position along the 'x' axis.
```js ```js
xLine(length: number, sketch: Sketch, tag?: TagDeclarator) -> Sketch xLine(length: number, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ xLine(length: number, sketch: Sketch, tag?: TagDeclarator) -> Sketch
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `length` | `number` | | Yes | | `length` | `number` | | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Draw a line parallel to the X axis, that ends at the given X.
E.g. if the previous line ended at (1, 1), then xLineTo(4) draws a line from (1, 1) to (4, 1) E.g. if the previous line ended at (1, 1), then xLineTo(4) draws a line from (1, 1) to (4, 1)
```js ```js
xLineTo(to: number, sketch: Sketch, tag?: TagDeclarator) -> Sketch xLineTo(to: number, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ xLineTo(to: number, sketch: Sketch, tag?: TagDeclarator) -> Sketch
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `to` | `number` | | Yes | | `to` | `number` | | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Draw a line relative to the current origin to a specified distance away
from the current position along the 'y' axis. from the current position along the 'y' axis.
```js ```js
yLine(length: number, sketch: Sketch, tag?: TagDeclarator) -> Sketch yLine(length: number, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ yLine(length: number, sketch: Sketch, tag?: TagDeclarator) -> Sketch
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `length` | `number` | | Yes | | `length` | `number` | | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -9,7 +9,7 @@ Draw a line parallel to the Y axis, that ends at the given Y.
E.g. if the previous line ended at (1, 1), then yLineTo(4) draws a line from (1, 1) to (1, 4) E.g. if the previous line ended at (1, 1), then yLineTo(4) draws a line from (1, 1) to (1, 4)
```js ```js
yLineTo(to: number, sketch: Sketch, tag?: TagDeclarator) -> Sketch yLineTo(to: number, sketch: Sketch, tag?: TagNode) -> Sketch
``` ```
@ -19,7 +19,7 @@ yLineTo(to: number, sketch: Sketch, tag?: TagDeclarator) -> Sketch
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `to` | `number` | | Yes | | `to` | `number` | | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagNode`](/docs/kcl/types/TagNode) | | No |
### Returns ### Returns

View File

@ -313,3 +313,45 @@ test(
await electronApp.close() await electronApp.close()
} }
) )
test(
'external change of file contents are reflected in editor',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const PROJECT_DIR_NAME = 'lee-was-here'
const {
electronApp,
page,
dir: projectsDir,
} = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const aProjectDir = join(dir, PROJECT_DIR_NAME)
await fsp.mkdir(aProjectDir, { recursive: true })
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await test.step('Open the project', async () => {
await expect(page.getByText(PROJECT_DIR_NAME)).toBeVisible()
await page.getByText(PROJECT_DIR_NAME).click()
await u.waitForPageLoad()
})
await u.openFilePanel()
await u.openKclCodePanel()
await test.step('Write to file externally and check for changed content', async () => {
const content = 'ha he ho ho ha blap scap be dap'
await fsp.writeFile(
join(projectsDir, PROJECT_DIR_NAME, 'main.kcl'),
content
)
await u.editorTextMatches(content)
})
await electronApp.close()
}
)

View File

@ -104,7 +104,7 @@ test(
}, },
{ timeout: 15_000 } { timeout: 15_000 }
) )
.toBe(431341) .toBeGreaterThan(300_000)
// clean up output.gltf // clean up output.gltf
await fsp.rm('output.gltf') await fsp.rm('output.gltf')
@ -179,7 +179,7 @@ test(
}, },
{ timeout: 15_000 } { timeout: 15_000 }
) )
.toBe(102040) .toBeGreaterThan(100_000)
// clean up output.gltf // clean up output.gltf
await fsp.rm('output.gltf') await fsp.rm('output.gltf')

View File

@ -1,6 +1,16 @@
import { test, expect } from '@playwright/test' import { test, expect } from '@playwright/test'
import fsp from 'fs/promises'
import { uuidv4 } from 'lib/utils' import { uuidv4 } from 'lib/utils'
import { getUtils, setup, tearDown } from './test-utils' import {
darkModeBgColor,
darkModePlaneColorXZ,
executorInputPath,
getUtils,
setup,
setupElectron,
tearDown,
} from './test-utils'
import { join } from 'path'
test.beforeEach(async ({ context, page }, testInfo) => { test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo) await setup(context, page, testInfo)
@ -974,4 +984,84 @@ test.describe('Editor tests', () => {
|> close(%) |> close(%)
|> extrude(5, %)`) |> extrude(5, %)`)
}) })
test(
`Can use the import stdlib function on a local OBJ file`,
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const bracketDir = join(dir, 'cube')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cube.obj'),
join(bracketDir, 'cube.obj')
)
await fsp.writeFile(join(bracketDir, 'main.kcl'), '')
},
})
const viewportSize = { width: 1200, height: 500 }
await page.setViewportSize(viewportSize)
// Locators and constants
const u = await getUtils(page)
const projectLink = page.getByRole('link', { name: 'cube' })
const gizmo = page.locator('[aria-label*=gizmo]')
const resetCameraButton = page.getByRole('button', { name: 'Reset view' })
const locationToHavColor = async (
position: { x: number; y: number },
color: [number, number, number]
) => {
return u.getGreatestPixDiff(position, color)
}
const notTheOrigin = {
x: viewportSize.width * 0.55,
y: viewportSize.height * 0.3,
}
const origin = { x: viewportSize.width / 2, y: viewportSize.height / 2 }
const errorIndicators = page.locator('.cm-lint-marker-error')
await test.step(`Open the empty file, see the default planes`, async () => {
await projectLink.click()
await u.waitForPageLoad()
await expect
.poll(
async () => locationToHavColor(notTheOrigin, darkModePlaneColorXZ),
{
timeout: 5000,
message: 'XZ plane color is visible',
}
)
.toBeLessThan(15)
})
await test.step(`Write the import function line`, async () => {
await u.codeLocator.fill(`import('cube.obj')`)
await page.waitForTimeout(800)
})
await test.step(`Reset the camera before checking`, async () => {
await u.doAndWaitForCmd(async () => {
await gizmo.click({ button: 'right' })
await resetCameraButton.click()
}, 'zoom_to_fit')
})
await test.step(`Verify that we see the imported geometry and no errors`, async () => {
await expect(errorIndicators).toHaveCount(0)
await expect
.poll(async () => locationToHavColor(origin, darkModePlaneColorXZ), {
timeout: 3000,
message: 'Plane color should not be visible',
})
.toBeGreaterThan(15)
await expect
.poll(async () => locationToHavColor(origin, darkModeBgColor), {
timeout: 3000,
message: 'Background color should not be visible',
})
.toBeGreaterThan(15)
})
await electronApp.close()
}
)
}) })

View File

@ -960,4 +960,171 @@ _test.describe('Deleting items from the file pane', () => {
'TODO - delete folder we are in, with no main.kcl', 'TODO - delete folder we are in, with no main.kcl',
async () => {} async () => {}
) )
// Copied from tests above.
_test(
`external deletion of project navigates back home`,
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const TEST_PROJECT_NAME = 'Test Project'
const {
electronApp,
page,
dir: projectsDirName,
} = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, TEST_PROJECT_NAME), { recursive: true })
await fsp.mkdir(join(dir, TEST_PROJECT_NAME, 'folderToDelete'), {
recursive: true,
})
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, TEST_PROJECT_NAME, 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, TEST_PROJECT_NAME, 'folderToDelete', 'someFileWithin.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
// Constants and locators
const projectCard = page.getByText(TEST_PROJECT_NAME)
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const folderToDelete = page.getByRole('button', {
name: 'folderToDelete',
})
const fileWithinFolder = page.getByRole('listitem').filter({
has: page.getByRole('button', { name: 'someFileWithin.kcl' }),
})
await _test.step(
'Open project and navigate into folderToDelete',
async () => {
await projectCard.click()
await u.waitForPageLoad()
await _expect(projectMenuButton).toContainText('main.kcl')
await u.closeKclCodePanel()
await u.openFilePanel()
await folderToDelete.click()
await _expect(fileWithinFolder).toBeVisible()
await fileWithinFolder.click()
await _expect(projectMenuButton).toContainText('someFileWithin.kcl')
}
)
// Point of divergence. Delete the project folder and see if it goes back
// to the home view.
await _test.step(
'Delete projectsDirName/<project-name> externally',
async () => {
await fsp.rm(join(projectsDirName, TEST_PROJECT_NAME), {
recursive: true,
force: true,
})
}
)
await _test.step('Check the app is back on the home view', async () => {
const projectsDirLink = page.getByText('Loaded from')
await _expect(projectsDirLink).toBeVisible()
})
await electronApp.close()
}
)
// Similar to the above
_test(
`external deletion of file in sub-directory updates the file tree and recreates it on code editor typing`,
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const TEST_PROJECT_NAME = 'Test Project'
const {
electronApp,
page,
dir: projectsDirName,
} = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, TEST_PROJECT_NAME), { recursive: true })
await fsp.mkdir(join(dir, TEST_PROJECT_NAME, 'folderToDelete'), {
recursive: true,
})
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, TEST_PROJECT_NAME, 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, TEST_PROJECT_NAME, 'folderToDelete', 'someFileWithin.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
// Constants and locators
const projectCard = page.getByText(TEST_PROJECT_NAME)
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const folderToDelete = page.getByRole('button', {
name: 'folderToDelete',
})
const fileWithinFolder = page.getByRole('listitem').filter({
has: page.getByRole('button', { name: 'someFileWithin.kcl' }),
})
await _test.step(
'Open project and navigate into folderToDelete',
async () => {
await projectCard.click()
await u.waitForPageLoad()
await _expect(projectMenuButton).toContainText('main.kcl')
await u.openFilePanel()
await folderToDelete.click()
await _expect(fileWithinFolder).toBeVisible()
await fileWithinFolder.click()
await _expect(projectMenuButton).toContainText('someFileWithin.kcl')
}
)
await _test.step(
'Delete projectsDirName/<project-name> externally',
async () => {
await fsp.rm(
join(
projectsDirName,
TEST_PROJECT_NAME,
'folderToDelete',
'someFileWithin.kcl'
)
)
}
)
await _test.step('Check the file is gone in the file tree', async () => {
await _expect(
page.getByTestId('file-pane-scroll-container')
).not.toContainText('someFileWithin.kcl')
})
await _test.step(
'Check the file is back in the file tree after typing in code editor',
async () => {
await u.pasteCodeInEditor('hello = 1')
await _expect(
page.getByTestId('file-pane-scroll-container')
).toContainText('someFileWithin.kcl')
}
)
await electronApp.close()
}
)
}) })

View File

@ -255,7 +255,7 @@ test.describe('Can export from electron app', () => {
}, },
{ timeout: 15_000 } { timeout: 15_000 }
) )
.toBe(431341) .toBeGreaterThan(300_000)
// clean up output.gltf // clean up output.gltf
await fsp.rm('output.gltf') await fsp.rm('output.gltf')
@ -851,7 +851,7 @@ test(
} }
) )
test( test.fixme(
'When the project folder is empty, user can create new project and open it.', 'When the project folder is empty, user can create new project and open it.',
{ tag: '@electron' }, { tag: '@electron' },
async ({ browserName }, testInfo) => { async ({ browserName }, testInfo) => {
@ -861,6 +861,12 @@ test(
page.on('console', console.log) page.on('console', console.log)
// Locators and constants
const gizmo = page.locator('[aria-label*=gizmo]')
const resetCameraButton = page.getByRole('button', { name: 'Reset view' })
const pointOnModel = { x: 660, y: 250 }
const expectedStartCamZPosition = 15633.47
// expect to see text "No Projects found" // expect to see text "No Projects found"
await expect(page.getByText('No Projects found')).toBeVisible() await expect(page.getByText('No Projects found')).toBeVisible()
@ -873,16 +879,7 @@ test(
await page.getByText('project-000').click() await page.getByText('project-000').click()
await expect(page.getByTestId('loading')).toBeAttached() await u.waitForPageLoad()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
await page.locator('.cm-content').fill(`sketch001 = startSketchOn('XZ') await page.locator('.cm-content').fill(`sketch001 = startSketchOn('XZ')
|> startProfileAt([-87.4, 282.92], %) |> startProfileAt([-87.4, 282.92], %)
@ -892,8 +889,28 @@ test(
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%) |> close(%)
extrude001 = extrude(200, sketch001)`) extrude001 = extrude(200, sketch001)`)
await page.waitForTimeout(800)
const pointOnModel = { x: 660, y: 250 } async function getCameraZValue() {
return page
.getByTestId('cam-z-position')
.inputValue()
.then((value) => parseFloat(value))
}
await test.step(`Reset camera`, async () => {
await u.openDebugPanel()
await u.clearCommandLogs()
await u.doAndWaitForCmd(async () => {
await gizmo.click({ button: 'right' })
await resetCameraButton.click()
}, 'zoom_to_fit')
await expect
.poll(getCameraZValue, {
message: 'Camera Z should be at expected position after reset',
})
.toEqual(expectedStartCamZPosition)
})
// gray at this pixel means the stream has loaded in the most // gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color) // user way we can verify it (pixel color)
@ -901,7 +918,7 @@ extrude001 = extrude(200, sketch001)`)
.poll(() => u.getGreatestPixDiff(pointOnModel, [143, 143, 143]), { .poll(() => u.getGreatestPixDiff(pointOnModel, [143, 143, 143]), {
timeout: 10_000, timeout: 10_000,
}) })
.toBeLessThan(15) .toBeLessThan(30)
await expect(async () => { await expect(async () => {
await page.mouse.move(0, 0, { steps: 5 }) await page.mouse.move(0, 0, { steps: 5 })

View File

@ -471,7 +471,7 @@ test(
await page.mouse.move(startXPx + PUR * 30, 500 - PUR * 20, { steps: 10 }) await page.mouse.move(startXPx + PUR * 30, 500 - PUR * 20, { steps: 10 })
await page.waitForTimeout(300) await page.waitForTimeout(1000)
await expect(page).toHaveScreenshot({ await expect(page).toHaveScreenshot({
maxDiffPixels: 100, maxDiffPixels: 100,
@ -528,6 +528,7 @@ test(
// Draw the rectangle // Draw the rectangle
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 30) await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 30)
await page.mouse.move(startXPx + PUR * 10, 500 - PUR * 10, { steps: 5 }) await page.mouse.move(startXPx + PUR * 10, 500 - PUR * 10, { steps: 5 })
await page.waitForTimeout(800)
// Ensure the draft rectangle looks the same as it usually does // Ensure the draft rectangle looks the same as it usually does
await expect(page).toHaveScreenshot({ await expect(page).toHaveScreenshot({
@ -895,7 +896,7 @@ test(
// Wait for the second extrusion to appear // Wait for the second extrusion to appear
// TODO: Find a way to truly know that the objects have finished // TODO: Find a way to truly know that the objects have finished
// rendering, because an execution-done message is not sufficient. // rendering, because an execution-done message is not sufficient.
await page.waitForTimeout(1000) await page.waitForTimeout(2000)
await expect(page).toHaveScreenshot({ await expect(page).toHaveScreenshot({
maxDiffPixels: 100, maxDiffPixels: 100,
@ -939,7 +940,7 @@ test(
// Wait for the second extrusion to appear // Wait for the second extrusion to appear
// TODO: Find a way to truly know that the objects have finished // TODO: Find a way to truly know that the objects have finished
// rendering, because an execution-done message is not sufficient. // rendering, because an execution-done message is not sufficient.
await page.waitForTimeout(1000) await page.waitForTimeout(2000)
await expect(page).toHaveScreenshot({ await expect(page).toHaveScreenshot({
maxDiffPixels: 100, maxDiffPixels: 100,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -47,6 +47,14 @@ export const commonPoints = {
num2: 14.44, num2: 14.44,
} }
/** A semi-reliable color to check the default XZ plane on
* in dark mode in the default camera position
*/
export const darkModePlaneColorXZ: [number, number, number] = [50, 50, 99]
/** A semi-reliable color to check the default dark mode bg color against */
export const darkModeBgColor: [number, number, number] = [27, 27, 27]
export const editorSelector = '[role="textbox"][data-language="kcl"]' export const editorSelector = '[role="textbox"][data-language="kcl"]'
type PaneId = 'variables' | 'code' | 'files' | 'logs' type PaneId = 'variables' | 'code' | 'files' | 'logs'
@ -463,6 +471,9 @@ export async function getUtils(page: Page, test_?: typeof test) {
return test_?.step( return test_?.step(
`Create and select project with text "${hasText}"`, `Create and select project with text "${hasText}"`,
async () => { async () => {
// Without this, we get unreliable project creation. It's probably
// due to a race between the FS being read and clicking doing something.
await page.waitForTimeout(100)
await page.getByTestId('home-new-file').click() await page.getByTestId('home-new-file').click()
const projectLinksPost = page.getByTestId('project-link') const projectLinksPost = page.getByTestId('project-link')
await projectLinksPost.filter({ hasText }).click() await projectLinksPost.filter({ hasText }).click()
@ -492,6 +503,11 @@ export async function getUtils(page: Page, test_?: typeof test) {
createNewFile: async (name: string) => { createNewFile: async (name: string) => {
return test?.step(`Create a file named ${name}`, async () => { return test?.step(`Create a file named ${name}`, async () => {
// If the application is in the middle of connecting a stream
// then creating a new file won't work in the end.
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await page.getByTestId('create-file-button').click() await page.getByTestId('create-file-button').click()
await page.getByTestId('file-rename-field').fill(name) await page.getByTestId('file-rename-field').fill(name)
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
@ -874,8 +890,8 @@ export async function setupElectron({
appSettings appSettings
? { settings: appSettings } ? { settings: appSettings }
: { : {
...TEST_SETTINGS,
settings: { settings: {
...TEST_SETTINGS,
app: { app: {
...TEST_SETTINGS.app, ...TEST_SETTINGS.app,
projectDirectory: projectDirName, projectDirectory: projectDirName,

View File

@ -9,7 +9,7 @@ import {
executorInputPath, executorInputPath,
} from './test-utils' } from './test-utils'
import { SaveSettingsPayload, SettingsLevel } from 'lib/settings/settingsTypes' import { SaveSettingsPayload, SettingsLevel } from 'lib/settings/settingsTypes'
import { SETTINGS_FILE_NAME } from 'lib/constants' import { SETTINGS_FILE_NAME, PROJECT_SETTINGS_FILE_NAME } from 'lib/constants'
import { import {
TEST_SETTINGS_KEY, TEST_SETTINGS_KEY,
TEST_SETTINGS_CORRUPTED, TEST_SETTINGS_CORRUPTED,
@ -445,6 +445,58 @@ test.describe('Testing settings', () => {
} }
) )
test(
'project settings reload on external change',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const {
electronApp,
page,
dir: projectDirName,
} = await setupElectron({
testInfo,
})
await page.setViewportSize({ width: 1200, height: 500 })
const logoLink = page.getByTestId('app-logo')
const projectDirLink = page.getByText('Loaded from')
await test.step('Wait for project view', async () => {
await expect(projectDirLink).toBeVisible()
})
const projectLinks = page.getByTestId('project-link')
const oldCount = await projectLinks.count()
await page.getByRole('button', { name: 'New project' }).click()
await expect(projectLinks).toHaveCount(oldCount + 1)
await projectLinks.filter({ hasText: 'project-000' }).first().click()
const changeColorFs = async (color: string) => {
const tempSettingsFilePath = join(
projectDirName,
'project-000',
PROJECT_SETTINGS_FILE_NAME
)
await fsp.writeFile(
tempSettingsFilePath,
`[settings.app]\nthemeColor = "${color}"`
)
}
await test.step('Check the color is first starting as we expect', async () => {
await expect(logoLink).toHaveCSS('--primary-hue', '264.5')
})
await test.step('Check color of logo changed', async () => {
await changeColorFs('99')
await expect(logoLink).toHaveCSS('--primary-hue', '99')
})
await electronApp.close()
}
)
test( test(
`Closing settings modal should go back to the original file being viewed`, `Closing settings modal should go back to the original file being viewed`,
{ tag: '@electron' }, { tag: '@electron' },

7
interface.d.ts vendored
View File

@ -20,10 +20,11 @@ export interface IElectronAPI {
version: typeof process.env.version version: typeof process.env.version
watchFileOn: ( watchFileOn: (
path: string, path: string,
key: string,
callback: (eventType: string, path: string) => void callback: (eventType: string, path: string) => void
) => void ) => void
watchFileOff: (path: string) => void readFile: typeof fs.readFile
readFile: (path: string) => ReturnType<fs.readFile> watchFileOff: (path: string, key: string) => void
writeFile: ( writeFile: (
path: string, path: string,
data: string | Uint8Array data: string | Uint8Array
@ -67,7 +68,7 @@ export interface IElectronAPI {
} }
} }
kittycad: (access: string, args: any) => any kittycad: (access: string, args: any) => any
listMachines: () => Promise<MachinesListing> listMachines: (machineApiIp: string) => Promise<MachinesListing>
getMachineApiIp: () => Promise<string | null> getMachineApiIp: () => Promise<string | null>
onUpdateDownloadStart: ( onUpdateDownloadStart: (
callback: (value: { version: string }) => void callback: (value: { version: string }) => void

View File

@ -70,7 +70,7 @@ echo ""
echo "Suggested changelog:" echo "Suggested changelog:"
echo "\`\`\`" echo "\`\`\`"
echo "## What's Changed" echo "## What's Changed"
git log $(git describe --tags --abbrev=0)..HEAD --oneline --pretty=format:%s | grep -v Bump | grep -v 'Cut release v' | awk '{print "* "toupper(substr($0,0,1))substr($0,2)}' git log $(git describe --tags --match="v[0-9]*" --abbrev=0)..HEAD --oneline --pretty=format:%s | grep -v Bump | grep -v 'Cut release v' | awk '{print "* "toupper(substr($0,0,1))substr($0,2)}'
echo "" echo ""
echo "**Full Changelog**: https://github.com/KittyCAD/modeling-app/compare/${latest_tag}...${new_version}" echo "**Full Changelog**: https://github.com/KittyCAD/modeling-app/compare/${latest_tag}...${new_version}"
echo "\`\`\`" echo "\`\`\`"

View File

@ -36,38 +36,297 @@
"description": "Extra machine-specific information regarding a connected machine.", "description": "Extra machine-specific information regarding a connected machine.",
"oneOf": [ "oneOf": [
{ {
"additionalProperties": false,
"properties": { "properties": {
"Moonraker": { "type": {
"type": "object" "enum": [
"moonraker"
],
"type": "string"
} }
}, },
"required": [ "required": [
"Moonraker" "type"
], ],
"type": "object" "type": "object"
}, },
{ {
"additionalProperties": false,
"properties": { "properties": {
"Usb": { "type": {
"type": "object" "enum": [
"usb"
],
"type": "string"
} }
}, },
"required": [ "required": [
"Usb" "type"
], ],
"type": "object" "type": "object"
}, },
{ {
"additionalProperties": false,
"properties": { "properties": {
"Bambu": { "current_stage": {
"type": "object" "allOf": [
{
"$ref": "#/components/schemas/Stage"
}
],
"description": "The current stage of the machine as defined by Bambu which can include errors, etc.",
"nullable": true
},
"nozzle_diameter": {
"allOf": [
{
"$ref": "#/components/schemas/NozzleDiameter"
}
],
"description": "The nozzle diameter of the machine."
},
"type": {
"enum": [
"bambu"
],
"type": "string"
} }
}, },
"required": [ "required": [
"Bambu" "nozzle_diameter",
"type"
],
"type": "object"
}
]
},
"FdmHardwareConfiguration": {
"description": "Configuration for a FDM-based printer.",
"properties": {
"filaments": {
"description": "The filaments the printer has access to.",
"items": {
"$ref": "#/components/schemas/Filament"
},
"type": "array"
},
"nozzle_diameter": {
"description": "Diameter of the extrusion nozzle, in mm.",
"format": "double",
"type": "number"
}
},
"required": [
"filaments",
"nozzle_diameter"
],
"type": "object"
},
"Filament": {
"description": "Information about the filament being used in a FDM printer.",
"properties": {
"color": {
"description": "The color (as hex without the `#`) of the filament, this is likely specific to the manufacturer.",
"maxLength": 6,
"minLength": 6,
"nullable": true,
"type": "string"
},
"material": {
"allOf": [
{
"$ref": "#/components/schemas/FilamentMaterial"
}
],
"description": "The material that the filament is made of."
},
"name": {
"description": "The name of the filament, this is likely specfic to the manufacturer.",
"nullable": true,
"type": "string"
}
},
"required": [
"material"
],
"type": "object"
},
"FilamentMaterial": {
"description": "The material that the filament is made of.",
"oneOf": [
{
"description": "Polylactic acid based plastics",
"properties": {
"type": {
"enum": [
"pla"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
{
"description": "Pla support",
"properties": {
"type": {
"enum": [
"pla_support"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
{
"description": "acrylonitrile butadiene styrene based plastics",
"properties": {
"type": {
"enum": [
"abs"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
{
"description": "polyethylene terephthalate glycol based plastics",
"properties": {
"type": {
"enum": [
"petg"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
{
"description": "unsuprisingly, nylon based",
"properties": {
"type": {
"enum": [
"nylon"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
{
"description": "thermoplastic polyurethane based urethane material",
"properties": {
"type": {
"enum": [
"tpu"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
{
"description": "polyvinyl alcohol based material",
"properties": {
"type": {
"enum": [
"pva"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
{
"description": "high impact polystyrene based material",
"properties": {
"type": {
"enum": [
"hips"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
{
"description": "composite material with stuff in other stuff, something like PLA mixed with carbon fiber, kevlar, or fiberglass",
"properties": {
"type": {
"enum": [
"composite"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
}
]
},
"HardwareConfiguration": {
"description": "The hardware configuration of a machine.",
"oneOf": [
{
"description": "No configuration is possible. This isn't the same conceptually as an `Option<HardwareConfiguration>`, because this indicates we positively know there is no possible configuration changes that are possible with this method of manufcture.",
"properties": {
"type": {
"enum": [
"none"
],
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
},
{
"description": "Hardware configuration specific to FDM based printers",
"properties": {
"config": {
"allOf": [
{
"$ref": "#/components/schemas/FdmHardwareConfiguration"
}
],
"description": "The configuration for the FDM printer."
},
"type": {
"enum": [
"fdm"
],
"type": "string"
}
},
"required": [
"config",
"type"
], ],
"type": "object" "type": "object"
} }
@ -85,6 +344,14 @@
"description": "Additional, per-machine information which is specific to the underlying machine type.", "description": "Additional, per-machine information which is specific to the underlying machine type.",
"nullable": true "nullable": true
}, },
"hardware_configuration": {
"allOf": [
{
"$ref": "#/components/schemas/HardwareConfiguration"
}
],
"description": "Information about how the Machine is currently configured."
},
"id": { "id": {
"description": "Machine Identifier (ID) for the specific Machine.", "description": "Machine Identifier (ID) for the specific Machine.",
"type": "string" "type": "string"
@ -114,6 +381,12 @@
"description": "Maximum part size that can be manufactured by this device. This may be some sort of theoretical upper bound, getting close to this limit seems like maybe a bad idea.\n\nThis may be `None` if the maximum size is not knowable by the Machine API.\n\nWhat \"close\" means is up to you!", "description": "Maximum part size that can be manufactured by this device. This may be some sort of theoretical upper bound, getting close to this limit seems like maybe a bad idea.\n\nThis may be `None` if the maximum size is not knowable by the Machine API.\n\nWhat \"close\" means is up to you!",
"nullable": true "nullable": true
}, },
"progress": {
"description": "Progress of the current print, if printing.",
"format": "double",
"nullable": true,
"type": "number"
},
"state": { "state": {
"allOf": [ "allOf": [
{ {
@ -124,6 +397,7 @@
} }
}, },
"required": [ "required": [
"hardware_configuration",
"id", "id",
"machine_type", "machine_type",
"make_model", "make_model",
@ -157,57 +431,111 @@
"oneOf": [ "oneOf": [
{ {
"description": "If a print state can not be resolved at this time, an Unknown may be returned.", "description": "If a print state can not be resolved at this time, an Unknown may be returned.",
"enum": [
"Unknown"
],
"type": "string"
},
{
"description": "Idle, and ready for another job.",
"enum": [
"Idle"
],
"type": "string"
},
{
"description": "Running a job -- 3D printing or CNC-ing a part.",
"enum": [
"Running"
],
"type": "string"
},
{
"description": "Machine is currently offline or unreachable.",
"enum": [
"Offline"
],
"type": "string"
},
{
"description": "Job is underway but halted, waiting for some action to take place.",
"enum": [
"Paused"
],
"type": "string"
},
{
"description": "Job is finished, but waiting manual action to move back to Idle.",
"enum": [
"Complete"
],
"type": "string"
},
{
"additionalProperties": false,
"description": "The printer has failed and is in an unknown state that may require manual attention to resolve. The inner value is a human readable description of what specifically has failed.",
"properties": { "properties": {
"Failed": { "state": {
"nullable": true, "enum": [
"unknown"
],
"type": "string" "type": "string"
} }
}, },
"required": [ "required": [
"Failed" "state"
],
"type": "object"
},
{
"description": "Idle, and ready for another job.",
"properties": {
"state": {
"enum": [
"idle"
],
"type": "string"
}
},
"required": [
"state"
],
"type": "object"
},
{
"description": "Running a job -- 3D printing or CNC-ing a part.",
"properties": {
"state": {
"enum": [
"running"
],
"type": "string"
}
},
"required": [
"state"
],
"type": "object"
},
{
"description": "Machine is currently offline or unreachable.",
"properties": {
"state": {
"enum": [
"offline"
],
"type": "string"
}
},
"required": [
"state"
],
"type": "object"
},
{
"description": "Job is underway but halted, waiting for some action to take place.",
"properties": {
"state": {
"enum": [
"paused"
],
"type": "string"
}
},
"required": [
"state"
],
"type": "object"
},
{
"description": "Job is finished, but waiting manual action to move back to Idle.",
"properties": {
"state": {
"enum": [
"complete"
],
"type": "string"
}
},
"required": [
"state"
],
"type": "object"
},
{
"description": "The printer has failed and is in an unknown state that may require manual attention to resolve. The inner value is a human readable description of what specifically has failed.",
"properties": {
"message": {
"description": "A human-readable message describing the failure.",
"nullable": true,
"type": "string"
},
"state": {
"enum": [
"failed"
],
"type": "string"
}
},
"required": [
"state"
], ],
"type": "object" "type": "object"
} }
@ -219,21 +547,54 @@
{ {
"description": "Use light to cure a resin to build up layers.", "description": "Use light to cure a resin to build up layers.",
"enum": [ "enum": [
"Stereolithography" "stereolithography"
], ],
"type": "string" "type": "string"
}, },
{ {
"description": "Fused Deposition Modeling, layers of melted plastic.", "description": "Fused Deposition Modeling, layers of melted plastic.",
"enum": [ "enum": [
"FusedDeposition" "fused_deposition"
], ],
"type": "string" "type": "string"
}, },
{ {
"description": "\"Computer numerical control\" - machine that grinds away material from a hunk of material to construct a part.", "description": "\"Computer numerical control\" - machine that grinds away material from a hunk of material to construct a part.",
"enum": [ "enum": [
"Cnc" "cnc"
],
"type": "string"
}
]
},
"NozzleDiameter": {
"description": "A nozzle diameter.",
"oneOf": [
{
"description": "0.2mm.",
"enum": [
"0.2"
],
"type": "string"
},
{
"description": "0.4mm.",
"enum": [
"0.4"
],
"type": "string"
},
{
"description": "0.6mm.",
"enum": [
"0.6"
],
"type": "string"
},
{
"description": "0.8mm.",
"enum": [
"0.8"
], ],
"type": "string" "type": "string"
} }
@ -284,6 +645,15 @@
"machine_id": { "machine_id": {
"description": "The machine id to print to.", "description": "The machine id to print to.",
"type": "string" "type": "string"
},
"slicer_configuration": {
"allOf": [
{
"$ref": "#/components/schemas/SlicerConfiguration"
}
],
"description": "Requested design-specific slicer configurations.",
"nullable": true
} }
}, },
"required": [ "required": [
@ -292,6 +662,283 @@
], ],
"type": "object" "type": "object"
}, },
"SlicerConfiguration": {
"description": "The slicer configuration is a set of parameters that are passed to the slicer to control how the gcode is generated.",
"properties": {
"filament_idx": {
"description": "The filament to use for the print.",
"format": "uint",
"minimum": 0,
"nullable": true,
"type": "integer"
}
},
"type": "object"
},
"Stage": {
"description": "The print stage. These come from: https://github.com/SoftFever/OrcaSlicer/blob/431978baf17961df90f0d01871b0ad1d839d7f5d/src/slic3r/GUI/DeviceManager.cpp#L78",
"oneOf": [
{
"description": "Nothing.",
"enum": [
"nothing"
],
"type": "string"
},
{
"description": "Empty.",
"enum": [
"empty"
],
"type": "string"
},
{
"description": "Auto bed leveling.",
"enum": [
"auto_bed_leveling"
],
"type": "string"
},
{
"description": "Heatbed preheating.",
"enum": [
"heatbed_preheating"
],
"type": "string"
},
{
"description": "Sweeping XY mech mode.",
"enum": [
"sweeping_xy_mech_mode"
],
"type": "string"
},
{
"description": "Changing filament.",
"enum": [
"changing_filament"
],
"type": "string"
},
{
"description": "M400 pause.",
"enum": [
"m400_pause"
],
"type": "string"
},
{
"description": "Paused due to filament runout.",
"enum": [
"paused_due_to_filament_runout"
],
"type": "string"
},
{
"description": "Heating hotend.",
"enum": [
"heating_hotend"
],
"type": "string"
},
{
"description": "Calibrating extrusion.",
"enum": [
"calibrating_extrusion"
],
"type": "string"
},
{
"description": "Scanning bed surface.",
"enum": [
"scanning_bed_surface"
],
"type": "string"
},
{
"description": "Inspecting first layer.",
"enum": [
"inspecting_first_layer"
],
"type": "string"
},
{
"description": "Identifying build plate type.",
"enum": [
"identifying_build_plate_type"
],
"type": "string"
},
{
"description": "Calibrating micro lidar.",
"enum": [
"calibrating_micro_lidar"
],
"type": "string"
},
{
"description": "Homing toolhead.",
"enum": [
"homing_toolhead"
],
"type": "string"
},
{
"description": "Cleaning nozzle tip.",
"enum": [
"cleaning_nozzle_tip"
],
"type": "string"
},
{
"description": "Checking extruder temperature.",
"enum": [
"checking_extruder_temperature"
],
"type": "string"
},
{
"description": "Printing was paused by the user.",
"enum": [
"printing_was_paused_by_the_user"
],
"type": "string"
},
{
"description": "Pause of front cover falling.",
"enum": [
"pause_of_front_cover_falling"
],
"type": "string"
},
{
"description": "Calibrating micro lidar.",
"enum": [
"calibrating_micro_lidar2"
],
"type": "string"
},
{
"description": "Calibrating extrusion flow.",
"enum": [
"calibrating_extrusion_flow"
],
"type": "string"
},
{
"description": "Paused due to nozzle temperature malfunction.",
"enum": [
"paused_due_to_nozzle_temperature_malfunction"
],
"type": "string"
},
{
"description": "Paused due to heat bed temperature malfunction.",
"enum": [
"paused_due_to_heat_bed_temperature_malfunction"
],
"type": "string"
},
{
"description": "Filament unloading.",
"enum": [
"filament_unloading"
],
"type": "string"
},
{
"description": "Skip step pause.",
"enum": [
"skip_step_pause"
],
"type": "string"
},
{
"description": "Filament loading.",
"enum": [
"filament_loading"
],
"type": "string"
},
{
"description": "Motor noise calibration.",
"enum": [
"motor_noise_calibration"
],
"type": "string"
},
{
"description": "Paused due to AMS lost.",
"enum": [
"paused_due_to_ams_lost"
],
"type": "string"
},
{
"description": "Paused due to low speed of the heat break fan.",
"enum": [
"paused_due_to_low_speed_of_the_heat_break_fan"
],
"type": "string"
},
{
"description": "Paused due to chamber temperature control error.",
"enum": [
"paused_due_to_chamber_temperature_control_error"
],
"type": "string"
},
{
"description": "Cooling chamber.",
"enum": [
"cooling_chamber"
],
"type": "string"
},
{
"description": "Paused by the Gcode inserted by the user.",
"enum": [
"paused_by_the_gcode_inserted_by_the_user"
],
"type": "string"
},
{
"description": "Motor noise showoff.",
"enum": [
"motor_noise_showoff"
],
"type": "string"
},
{
"description": "Nozzle filament covered detected pause.",
"enum": [
"nozzle_filament_covered_detected_pause"
],
"type": "string"
},
{
"description": "Cutter error pause.",
"enum": [
"cutter_error_pause"
],
"type": "string"
},
{
"description": "First layer error pause.",
"enum": [
"first_layer_error_pause"
],
"type": "string"
},
{
"description": "Nozzle clog pause.",
"enum": [
"nozzle_clog_pause"
],
"type": "string"
}
]
},
"Volume": { "Volume": {
"description": "Set of three values to represent the extent of a 3-D Volume. This contains the width, depth, and height values, generally used to represent some maximum or minimum.\n\nAll measurements are in millimeters.", "description": "Set of three values to represent the extent of a 3-D Volume. This contains the width, depth, and height values, generally used to represent some maximum or minimum.\n\nAll measurements are in millimeters.",
"properties": { "properties": {

View File

@ -1,6 +1,6 @@
{ {
"name": "zoo-modeling-app", "name": "zoo-modeling-app",
"version": "0.25.6", "version": "0.26.0",
"private": true, "private": true,
"productName": "Zoo Modeling App", "productName": "Zoo Modeling App",
"author": { "author": {

View File

@ -44,6 +44,7 @@ import {
import { ActionButton } from 'components/ActionButton' import { ActionButton } from 'components/ActionButton'
import { err, reportRejection, trap } from 'lib/trap' import { err, reportRejection, trap } from 'lib/trap'
import { useCommandsContext } from 'hooks/useCommandsContext' import { useCommandsContext } from 'hooks/useCommandsContext'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
function useShouldHideScene(): { hideClient: boolean; hideServer: boolean } { function useShouldHideScene(): { hideClient: boolean; hideServer: boolean } {
const [isCamMoving, setIsCamMoving] = useState(false) const [isCamMoving, setIsCamMoving] = useState(false)
@ -201,7 +202,7 @@ const Overlay = ({
let xAlignment = overlay.angle < 0 ? '0%' : '-100%' let xAlignment = overlay.angle < 0 ? '0%' : '-100%'
let yAlignment = overlay.angle < -90 || overlay.angle >= 90 ? '0%' : '-100%' let yAlignment = overlay.angle < -90 || overlay.angle >= 90 ? '0%' : '-100%'
const _node1 = getNodeFromPath<CallExpression>( const _node1 = getNodeFromPath<UnboxedNode<CallExpression>>(
kclManager.ast, kclManager.ast,
overlay.pathToNode, overlay.pathToNode,
'CallExpression' 'CallExpression'
@ -381,7 +382,7 @@ export async function deleteSegment({
pathToNode: PathToNode pathToNode: PathToNode
sketchDetails: SketchDetails | null sketchDetails: SketchDetails | null
}) { }) {
let modifiedAst: Program | Error = kclManager.ast let modifiedAst: UnboxedNode<Program> | Error = kclManager.ast
const dependentRanges = findUsesOfTagInPipe(modifiedAst, pathToNode) const dependentRanges = findUsesOfTagInPipe(modifiedAst, pathToNode)
const shouldContinueSegDelete = dependentRanges.length const shouldContinueSegDelete = dependentRanges.length

View File

@ -92,6 +92,7 @@ import { err, reportRejection, trap } from 'lib/trap'
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer' import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'
import { Point3d } from 'wasm-lib/kcl/bindings/Point3d' import { Point3d } from 'wasm-lib/kcl/bindings/Point3d'
import { SegmentInputs } from 'lang/std/stdTypes' import { SegmentInputs } from 'lang/std/stdTypes'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
type DraftSegment = 'line' | 'tangentialArcTo' type DraftSegment = 'line' | 'tangentialArcTo'
@ -369,14 +370,14 @@ export class SceneEntities {
selectionRanges, selectionRanges,
}: { }: {
sketchPathToNode: PathToNode sketchPathToNode: PathToNode
maybeModdedAst: Program maybeModdedAst: UnboxedNode<Program>
draftExpressionsIndices?: { start: number; end: number } draftExpressionsIndices?: { start: number; end: number }
forward: [number, number, number] forward: [number, number, number]
up: [number, number, number] up: [number, number, number]
position?: [number, number, number] position?: [number, number, number]
selectionRanges?: Selections selectionRanges?: Selections
}): Promise<{ }): Promise<{
truncatedAst: Program truncatedAst: UnboxedNode<Program>
programMemoryOverride: ProgramMemory programMemoryOverride: ProgramMemory
sketch: Sketch sketch: Sketch
variableDeclarationName: string variableDeclarationName: string
@ -561,7 +562,7 @@ export class SceneEntities {
} }
updateAstAndRejigSketch = async ( updateAstAndRejigSketch = async (
sketchPathToNode: PathToNode, sketchPathToNode: PathToNode,
modifiedAst: Program | Error, modifiedAst: UnboxedNode<Program> | Error,
forward: [number, number, number], forward: [number, number, number],
up: [number, number, number], up: [number, number, number],
origin: [number, number, number] origin: [number, number, number]
@ -1177,7 +1178,7 @@ export class SceneEntities {
} }
prepareTruncatedMemoryAndAst = ( prepareTruncatedMemoryAndAst = (
sketchPathToNode: PathToNode, sketchPathToNode: PathToNode,
ast?: Program, ast?: UnboxedNode<Program>,
draftSegment?: DraftSegment draftSegment?: DraftSegment
) => ) =>
prepareTruncatedMemoryAndAst( prepareTruncatedMemoryAndAst(
@ -1198,7 +1199,7 @@ export class SceneEntities {
sketchPathToNode: PathToNode sketchPathToNode: PathToNode
intersects: Intersection<Object3D<Object3DEventMap>>[] intersects: Intersection<Object3D<Object3DEventMap>>[]
draftInfo?: { draftInfo?: {
truncatedAst: Program truncatedAst: UnboxedNode<Program>
programMemoryOverride: ProgramMemory programMemoryOverride: ProgramMemory
variableDeclarationName: string variableDeclarationName: string
} }
@ -1234,7 +1235,7 @@ export class SceneEntities {
const dragTo: [number, number] = [intersection2d.x, intersection2d.y] const dragTo: [number, number] = [intersection2d.x, intersection2d.y]
let modifiedAst = draftInfo ? draftInfo.truncatedAst : { ...kclManager.ast } let modifiedAst = draftInfo ? draftInfo.truncatedAst : { ...kclManager.ast }
const _node = getNodeFromPath<CallExpression>( const _node = getNodeFromPath<UnboxedNode<CallExpression>>(
modifiedAst, modifiedAst,
pathToNode, pathToNode,
'CallExpression' 'CallExpression'
@ -1246,7 +1247,7 @@ export class SceneEntities {
let modded: let modded:
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNode: PathToNode pathToNode: PathToNode
} }
| Error | Error
@ -1541,7 +1542,7 @@ export class SceneEntities {
if (parent?.userData?.pathToNode) { if (parent?.userData?.pathToNode) {
const updatedAst = parse(recast(kclManager.ast)) const updatedAst = parse(recast(kclManager.ast))
if (trap(updatedAst)) return if (trap(updatedAst)) return
const _node = getNodeFromPath<CallExpression>( const _node = getNodeFromPath<UnboxedNode<CallExpression>>(
updatedAst, updatedAst,
parent.userData.pathToNode, parent.userData.pathToNode,
'CallExpression' 'CallExpression'
@ -1676,12 +1677,12 @@ export type DefaultPlaneStr = 'XY' | 'XZ' | 'YZ' | '-XY' | '-XZ' | '-YZ'
function prepareTruncatedMemoryAndAst( function prepareTruncatedMemoryAndAst(
sketchPathToNode: PathToNode, sketchPathToNode: PathToNode,
ast: Program, ast: UnboxedNode<Program>,
programMemory: ProgramMemory, programMemory: ProgramMemory,
draftSegment?: DraftSegment draftSegment?: DraftSegment
): ):
| { | {
truncatedAst: Program truncatedAst: UnboxedNode<Program>
programMemoryOverride: ProgramMemory programMemoryOverride: ProgramMemory
variableDeclarationName: string variableDeclarationName: string
} }
@ -1689,7 +1690,7 @@ function prepareTruncatedMemoryAndAst(
const bodyIndex = Number(sketchPathToNode?.[1]?.[0]) || 0 const bodyIndex = Number(sketchPathToNode?.[1]?.[0]) || 0
const _ast = structuredClone(ast) const _ast = structuredClone(ast)
const _node = getNodeFromPath<VariableDeclaration>( const _node = getNodeFromPath<UnboxedNode<VariableDeclaration>>(
_ast, _ast,
sketchPathToNode || [], sketchPathToNode || [],
'VariableDeclaration' 'VariableDeclaration'
@ -1739,15 +1740,15 @@ function prepareTruncatedMemoryAndAst(
).body.slice(-1)[0].start = lastPipeItem.start ).body.slice(-1)[0].start = lastPipeItem.start
_ast.end = lastPipeItem.end _ast.end = lastPipeItem.end
const varDec = _ast.body[bodyIndex] as VariableDeclaration const varDec = _ast.body[bodyIndex] as UnboxedNode<VariableDeclaration>
varDec.end = lastPipeItem.end varDec.end = lastPipeItem.end
const declarator = varDec.declarations[0] const declarator = varDec.declarations[0]
declarator.end = lastPipeItem.end declarator.end = lastPipeItem.end
const init = declarator.init as PipeExpression const init = declarator.init as UnboxedNode<PipeExpression>
init.end = lastPipeItem.end init.end = lastPipeItem.end
init.body.slice(-1)[0].end = lastPipeItem.end init.body.slice(-1)[0].end = lastPipeItem.end
} }
const truncatedAst: Program = { const truncatedAst: UnboxedNode<Program> = {
..._ast, ..._ast,
body: [structuredClone(_ast.body[bodyIndex])], body: [structuredClone(_ast.body[bodyIndex])],
} }

View File

@ -135,7 +135,9 @@ function CommandArgOptionInput({
<Combobox.Input <Combobox.Input
id="option-input" id="option-input"
ref={inputRef} ref={inputRef}
onChange={(event) => setQuery(event.target.value)} onChange={(event) =>
!event.target.disabled && setQuery(event.target.value)
}
className="flex-grow px-2 py-1 border-b border-b-chalkboard-100 dark:border-b-chalkboard-80 !bg-transparent focus:outline-none" className="flex-grow px-2 py-1 border-b border-b-chalkboard-100 dark:border-b-chalkboard-80 !bg-transparent focus:outline-none"
onKeyDown={(event) => { onKeyDown={(event) => {
if (event.metaKey && event.key === 'k') if (event.metaKey && event.key === 'k')
@ -175,9 +177,18 @@ function CommandArgOptionInput({
<Combobox.Option <Combobox.Option
key={option.name} key={option.name}
value={option} value={option}
disabled={option.disabled}
className="flex items-center gap-2 px-4 py-1 first:mt-2 last:mb-2 ui-active:bg-primary/10 dark:ui-active:bg-chalkboard-90" className="flex items-center gap-2 px-4 py-1 first:mt-2 last:mb-2 ui-active:bg-primary/10 dark:ui-active:bg-chalkboard-90"
> >
<p className="flex-grow">{option.name} </p> <p
className={`flex-grow ${
(option.disabled &&
'text-chalkboard-70 dark:text-chalkboard-50 cursor-not-allowed') ||
''
}`}
>
{option.name}
</p>
{option.value === currentOption?.value && ( {option.value === currentOption?.value && (
<small className="text-chalkboard-70 dark:text-chalkboard-50"> <small className="text-chalkboard-70 dark:text-chalkboard-50">
current current

View File

@ -2,7 +2,7 @@ import type { IndexLoaderData } from 'lib/types'
import { PATHS } from 'lib/paths' import { PATHS } from 'lib/paths'
import { ActionButton } from './ActionButton' import { ActionButton } from './ActionButton'
import Tooltip from './Tooltip' import Tooltip from './Tooltip'
import { Dispatch, useCallback, useEffect, useRef, useState } from 'react' import { Dispatch, useCallback, useRef, useState } from 'react'
import { useNavigate, useRouteLoaderData } from 'react-router-dom' import { useNavigate, useRouteLoaderData } from 'react-router-dom'
import { Disclosure } from '@headlessui/react' import { Disclosure } from '@headlessui/react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
@ -13,7 +13,6 @@ import { sortProject } from 'lib/desktopFS'
import { FILE_EXT } from 'lib/constants' import { FILE_EXT } from 'lib/constants'
import { CustomIcon } from './CustomIcon' import { CustomIcon } from './CustomIcon'
import { codeManager, kclManager } from 'lib/singletons' import { codeManager, kclManager } from 'lib/singletons'
import { useDocumentHasFocus } from 'hooks/useDocumentHasFocus'
import { useLspContext } from './LspProvider' import { useLspContext } from './LspProvider'
import useHotkeyWrapper from 'lib/hotkeyWrapper' import useHotkeyWrapper from 'lib/hotkeyWrapper'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
@ -21,6 +20,8 @@ import { DeleteConfirmationDialog } from './ProjectCard/DeleteProjectDialog'
import { ContextMenu, ContextMenuItem } from './ContextMenu' import { ContextMenu, ContextMenuItem } from './ContextMenu'
import usePlatform from 'hooks/usePlatform' import usePlatform from 'hooks/usePlatform'
import { FileEntry } from 'lib/project' import { FileEntry } from 'lib/project'
import { useFileSystemWatcher } from 'hooks/useFileSystemWatcher'
import { normalizeLineEndings } from 'lib/codeEditor'
function getIndentationCSS(level: number) { function getIndentationCSS(level: number) {
return `calc(1rem * ${level + 1})` return `calc(1rem * ${level + 1})`
@ -131,6 +132,23 @@ const FileTreeItem = ({
const isCurrentFile = fileOrDir.path === currentFile?.path const isCurrentFile = fileOrDir.path === currentFile?.path
const itemRef = useRef(null) const itemRef = useRef(null)
// Since every file or directory gets its own FileTreeItem, we can do this.
// Because subtrees only render when they are opened, that means this
// only listens when they open. Because this acts like a useEffect, when
// the ReactNodes are destroyed, so is this listener :)
useFileSystemWatcher(
async (eventType, path) => {
// Don't try to read a file that was removed.
if (isCurrentFile && eventType !== 'unlink') {
let code = await window.electron.readFile(path, { encoding: 'utf-8' })
code = normalizeLineEndings(code)
codeManager.updateCodeStateEditor(code)
}
fileSend({ type: 'Refresh' })
},
[fileOrDir.path]
)
const isRenaming = fileContext.itemsBeingRenamed.includes(fileOrDir.path) const isRenaming = fileContext.itemsBeingRenamed.includes(fileOrDir.path)
const removeCurrentItemFromRenaming = useCallback( const removeCurrentItemFromRenaming = useCallback(
() => () =>
@ -154,6 +172,13 @@ const FileTreeItem = ({
}) })
}, [fileContext.itemsBeingRenamed, fileOrDir.path, fileSend]) }, [fileContext.itemsBeingRenamed, fileOrDir.path, fileSend])
const clickDirectory = () => {
fileSend({
type: 'Set selected directory',
directory: fileOrDir,
})
}
function handleKeyUp(e: React.KeyboardEvent<HTMLButtonElement>) { function handleKeyUp(e: React.KeyboardEvent<HTMLButtonElement>) {
if (e.metaKey && e.key === 'Backspace') { if (e.metaKey && e.key === 'Backspace') {
// Open confirmation dialog // Open confirmation dialog
@ -242,18 +267,8 @@ const FileTreeItem = ({
} }
style={{ paddingInlineStart: getIndentationCSS(level) }} style={{ paddingInlineStart: getIndentationCSS(level) }}
onClick={(e) => e.currentTarget.focus()} onClick={(e) => e.currentTarget.focus()}
onClickCapture={(e) => onClickCapture={clickDirectory}
fileSend({ onFocusCapture={clickDirectory}
type: 'Set selected directory',
directory: fileOrDir,
})
}
onFocusCapture={(e) =>
fileSend({
type: 'Set selected directory',
directory: fileOrDir,
})
}
onKeyDown={(e) => e.key === 'Enter' && e.preventDefault()} onKeyDown={(e) => e.key === 'Enter' && e.preventDefault()}
onKeyUp={handleKeyUp} onKeyUp={handleKeyUp}
> >
@ -469,27 +484,30 @@ export const FileTreeInner = ({
const loaderData = useRouteLoaderData(PATHS.FILE) as IndexLoaderData const loaderData = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
const { send: fileSend, context: fileContext } = useFileContext() const { send: fileSend, context: fileContext } = useFileContext()
const { send: modelingSend } = useModelingContext() const { send: modelingSend } = useModelingContext()
const documentHasFocus = useDocumentHasFocus()
// Refresh the file tree when the document gets focus // Refresh the file tree when there are changes.
useEffect(() => { useFileSystemWatcher(
async (eventType, path) => {
fileSend({ type: 'Refresh' }) fileSend({ type: 'Refresh' })
}, [documentHasFocus]) },
[loaderData?.project?.path, fileContext.selectedDirectory.path].filter(
(x: string | undefined) => x !== undefined
)
)
const clickDirectory = () => {
fileSend({
type: 'Set selected directory',
directory: fileContext.project,
})
}
return ( return (
<div <div
className="overflow-auto pb-12 absolute inset-0" className="overflow-auto pb-12 absolute inset-0"
data-testid="file-pane-scroll-container" data-testid="file-pane-scroll-container"
> >
<ul <ul className="m-0 p-0 text-sm" onClickCapture={clickDirectory}>
className="m-0 p-0 text-sm"
onClickCapture={(e) => {
fileSend({
type: 'Set selected directory',
directory: fileContext.project,
})
}}
>
{sortProject(fileContext.project?.children || []).map((fileOrDir) => ( {sortProject(fileContext.project?.children || []).map((fileOrDir) => (
<FileTreeItem <FileTreeItem
project={fileContext.project} project={fileContext.project}

View File

@ -84,6 +84,7 @@ import {
import { submitAndAwaitTextToKcl } from 'lib/textToCad' import { submitAndAwaitTextToKcl } from 'lib/textToCad'
import { useFileContext } from 'hooks/useFileContext' import { useFileContext } from 'hooks/useFileContext'
import { uuidv4 } from 'lib/utils' import { uuidv4 } from 'lib/utils'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
type MachineContext<T extends AnyStateMachine> = { type MachineContext<T extends AnyStateMachine> = {
state: StateFrom<T> state: StateFrom<T>
@ -939,7 +940,7 @@ export const ModelingMachineProvider = ({
}) })
let parsed = parse(recast(kclManager.ast)) let parsed = parse(recast(kclManager.ast))
if (trap(parsed)) return Promise.reject(parsed) if (trap(parsed)) return Promise.reject(parsed)
parsed = parsed as Program parsed = parsed as UnboxedNode<Program>
const { modifiedAst: _modifiedAst, pathToReplacedNode } = const { modifiedAst: _modifiedAst, pathToReplacedNode } =
moveValueIntoNewVariablePath( moveValueIntoNewVariablePath(
@ -950,7 +951,7 @@ export const ModelingMachineProvider = ({
) )
parsed = parse(recast(_modifiedAst)) parsed = parse(recast(_modifiedAst))
if (trap(parsed)) return Promise.reject(parsed) if (trap(parsed)) return Promise.reject(parsed)
parsed = parsed as Program parsed = parsed as UnboxedNode<Program>
if (!pathToReplacedNode) if (!pathToReplacedNode)
return Promise.reject(new Error('No path to replaced node')) return Promise.reject(new Error('No path to replaced node'))

View File

@ -11,6 +11,7 @@ export const NetworkMachineIndicator = ({
}) => { }) => {
const machineCount = machineManager.machineCount() const machineCount = machineManager.machineCount()
const reason = machineManager.noMachinesReason() const reason = machineManager.noMachinesReason()
const machines = machineManager.machines
return isDesktop() ? ( return isDesktop() ? (
<Popover className="relative"> <Popover className="relative">
@ -46,20 +47,34 @@ export const NetworkMachineIndicator = ({
</div> </div>
{machineCount > 0 && ( {machineCount > 0 && (
<ul className="divide-y divide-chalkboard-20 dark:divide-chalkboard-80"> <ul className="divide-y divide-chalkboard-20 dark:divide-chalkboard-80">
{Object.entries(machineManager.machines).map( {machines.map((machine) => {
([hostname, machine]) => ( return (
<li key={hostname} className={'px-2 py-4 gap-1 last:mb-0 '}> <li key={machine.id} className={'px-2 py-4 gap-1 last:mb-0 '}>
<p className=""> <p className="">{machine.id.toUpperCase()}</p>
{machine.make_model.model ||
machine.make_model.manufacturer ||
'Unknown Machine'}
</p>
<p className="text-chalkboard-60 dark:text-chalkboard-50 text-xs"> <p className="text-chalkboard-60 dark:text-chalkboard-50 text-xs">
Hostname {hostname} {machine.make_model.model}
</p>
{machine.extra &&
machine.extra.type === 'bambu' &&
machine.extra.nozzle_diameter && (
<p className="text-chalkboard-60 dark:text-chalkboard-50 text-xs">
Nozzle Diameter: {machine.extra.nozzle_diameter}
</p>
)}
<p className="text-chalkboard-60 dark:text-chalkboard-50 text-xs">
{`Status: ${machine.state.state
.charAt(0)
.toUpperCase()}${machine.state.state.slice(1)}`}
{machine.state.state === 'failed' && machine.state.message
? ` (${machine.state.message})`
: ''}
{machine.state.state === 'running' && machine.progress
? ` (${Math.round(machine.progress)}%)`
: ''}
</p> </p>
</li> </li>
) )
)} })}
</ul> </ul>
)} )}
</Popover.Panel> </Popover.Panel>

View File

@ -221,6 +221,19 @@ export const SettingsAuthProviderBase = ({
useFileSystemWatcher( useFileSystemWatcher(
async () => { async () => {
// If there is a projectPath but it no longer exists it means
// it was exterally removed. If we let the code past this condition
// execute it will recreate the directory due to code in
// loadAndValidateSettings trying to recreate files. I do not
// wish to change the behavior in case anything else uses it.
// Go home.
if (loadedProject?.project?.path) {
if (!window.electron.exists(loadedProject?.project?.path)) {
navigate(PATHS.HOME)
return
}
}
const data = await loadAndValidateSettings(loadedProject?.project?.path) const data = await loadAndValidateSettings(loadedProject?.project?.path)
settingsSend({ settingsSend({
type: 'Set all settings', type: 'Set all settings',
@ -228,7 +241,9 @@ export const SettingsAuthProviderBase = ({
doNotPersist: true, doNotPersist: true,
}) })
}, },
settingsPath ? [settingsPath] : [] [settingsPath, loadedProject?.project?.path].filter(
(x: string | undefined) => x !== undefined
)
) )
// Add settings commands to the command bar // Add settings commands to the command bar

View File

@ -14,6 +14,7 @@ import {
import { TransformInfo } from 'lang/std/stdTypes' import { TransformInfo } from 'lang/std/stdTypes'
import { kclManager } from 'lib/singletons' import { kclManager } from 'lib/singletons'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
export function setEqualLengthInfo({ export function setEqualLengthInfo({
selectionRanges, selectionRanges,
@ -86,7 +87,7 @@ export function applyConstraintEqualLength({
selectionRanges: Selections selectionRanges: Selections
}): }):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNodeMap: PathToNodeMap pathToNodeMap: PathToNodeMap
} }
| Error { | Error {

View File

@ -13,6 +13,7 @@ import {
import { TransformInfo } from 'lang/std/stdTypes' import { TransformInfo } from 'lang/std/stdTypes'
import { kclManager } from 'lib/singletons' import { kclManager } from 'lib/singletons'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
export function horzVertInfo( export function horzVertInfo(
selectionRanges: Selections, selectionRanges: Selections,
@ -55,11 +56,11 @@ export function horzVertInfo(
export function applyConstraintHorzVert( export function applyConstraintHorzVert(
selectionRanges: Selections, selectionRanges: Selections,
horOrVert: 'vertical' | 'horizontal', horOrVert: 'vertical' | 'horizontal',
ast: Program, ast: UnboxedNode<Program>,
programMemory: ProgramMemory programMemory: ProgramMemory
): ):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNodeMap: PathToNodeMap pathToNodeMap: PathToNodeMap
} }
| Error { | Error {

View File

@ -19,6 +19,7 @@ import { createVariableDeclaration } from '../../lang/modifyAst'
import { removeDoubleNegatives } from '../AvailableVarsHelpers' import { removeDoubleNegatives } from '../AvailableVarsHelpers'
import { kclManager } from 'lib/singletons' import { kclManager } from 'lib/singletons'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
const getModalInfo = createInfoModal(GetInfoModal) const getModalInfo = createInfoModal(GetInfoModal)
@ -136,7 +137,7 @@ export async function applyConstraintIntersect({
}: { }: {
selectionRanges: Selections selectionRanges: Selections
}): Promise<{ }): Promise<{
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNodeMap: PathToNodeMap pathToNodeMap: PathToNodeMap
}> { }> {
const info = intersectInfo({ const info = intersectInfo({

View File

@ -13,6 +13,7 @@ import {
import { TransformInfo } from 'lang/std/stdTypes' import { TransformInfo } from 'lang/std/stdTypes'
import { kclManager } from 'lib/singletons' import { kclManager } from 'lib/singletons'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
export function removeConstrainingValuesInfo({ export function removeConstrainingValuesInfo({
selectionRanges, selectionRanges,
@ -77,7 +78,7 @@ export function applyRemoveConstrainingValues({
pathToNodes?: Array<PathToNode> pathToNodes?: Array<PathToNode>
}): }):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNodeMap: PathToNodeMap pathToNodeMap: PathToNodeMap
} }
| Error { | Error {

View File

@ -23,6 +23,7 @@ import {
import { removeDoubleNegatives } from '../AvailableVarsHelpers' import { removeDoubleNegatives } from '../AvailableVarsHelpers'
import { kclManager } from 'lib/singletons' import { kclManager } from 'lib/singletons'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
const getModalInfo = createSetAngleLengthModal(SetAngleLengthModal) const getModalInfo = createSetAngleLengthModal(SetAngleLengthModal)
@ -161,7 +162,7 @@ export function applyConstraintAxisAlign({
constraint: 'snapToYAxis' | 'snapToXAxis' constraint: 'snapToYAxis' | 'snapToXAxis'
}): }):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNodeMap: PathToNodeMap pathToNodeMap: PathToNodeMap
} }
| Error { | Error {

View File

@ -18,6 +18,7 @@ import { removeDoubleNegatives } from '../AvailableVarsHelpers'
import { kclManager } from 'lib/singletons' import { kclManager } from 'lib/singletons'
import { Selections } from 'lib/selections' import { Selections } from 'lib/selections'
import { cleanErrs, err } from 'lib/trap' import { cleanErrs, err } from 'lib/trap'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
const getModalInfo = createInfoModal(GetInfoModal) const getModalInfo = createInfoModal(GetInfoModal)
@ -185,7 +186,7 @@ export function applyConstraintHorzVertAlign({
constraint: 'setHorzDistance' | 'setVertDistance' constraint: 'setHorzDistance' | 'setVertDistance'
}): }):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNodeMap: PathToNodeMap pathToNodeMap: PathToNodeMap
} }
| Error { | Error {

View File

@ -11,7 +11,7 @@ export const kclHighlight = styleTags({
nil: t.null, nil: t.null,
'AddOp MultOp ExpOp': t.arithmeticOperator, 'AddOp MultOp ExpOp': t.arithmeticOperator,
BangOp: t.logicOperator, BangOp: t.logicOperator,
CompOp: t.logicOperator, CompOp: t.compareOperator,
'Equals Arrow': t.definitionOperator, 'Equals Arrow': t.definitionOperator,
PipeOperator: t.controlOperator, PipeOperator: t.controlOperator,
String: t.string, String: t.string,

View File

@ -90,7 +90,7 @@ commaSep1NoTrailingComma<term> { term ("," term)* }
MultOp { "/" | "*" | "\\" } MultOp { "/" | "*" | "\\" }
ExpOp { "^" } ExpOp { "^" }
BangOp { "!" } BangOp { "!" }
CompOp { $[<>] "="? | "!=" | "==" } CompOp { "==" | "!=" | "<=" | ">=" | "<" | ">" }
Equals { "=" } Equals { "=" }
Arrow { "=>" } Arrow { "=>" }
PipeOperator { "|>" } PipeOperator { "|>" }

View File

@ -12,35 +12,51 @@ type Path = string
// watcher.addListener(() => { ... }). // watcher.addListener(() => { ... }).
export const useFileSystemWatcher = ( export const useFileSystemWatcher = (
callback: (path: Path) => Promise<void>, callback: (eventType: string, path: Path) => Promise<void>,
dependencyArray: Path[] paths: Path[]
): void => { ): void => {
// Track a ref to the callback. This is how we get the callback updated // Used to track this instance of useFileSystemWatcher.
// across the NodeJS<->Browser boundary. // Assign to ref so it doesn't change between renders.
const callbackRef = useRef<{ fn: (path: Path) => Promise<void> }>({ const key = useRef(Math.random().toString())
fn: async (_path) => {},
}) const [output, setOutput] = useState<
{ eventType: string; path: string } | undefined
>(undefined)
// Used to track if paths list changes.
const [pathsTracked, setPathsTracked] = useState<Path[]>([])
useEffect(() => { useEffect(() => {
callbackRef.current.fn = callback if (!output) return
}, [callback]) callback(output.eventType, output.path).catch(reportRejection)
}, [output])
// Used to track if dependencyArrray changes.
const [dependencyArrayTracked, setDependencyArrayTracked] = useState<Path[]>(
[]
)
// On component teardown obliterate all watchers. // On component teardown obliterate all watchers.
useEffect(() => { useEffect(() => {
// The hook is useless on web. // The hook is useless on web.
if (!isDesktop()) return if (!isDesktop()) return
const cbWatcher = (eventType: string, path: string) => {
setOutput({ eventType, path })
}
for (let path of pathsTracked) {
// Because functions don't retain refs between NodeJS-Browser I need to
// pass an identifying key so we can later remove it.
// A way to think of the function call is:
// "For this path, add a new handler with this key"
// "There can be many keys (functions) per path"
// Again if refs were preserved, we wouldn't need to do this. Keys
// gives us uniqueness.
window.electron.watchFileOn(path, key.current, cbWatcher)
}
return () => { return () => {
for (let path of dependencyArray) { for (let path of pathsTracked) {
window.electron.watchFileOff(path) window.electron.watchFileOff(path, key.current)
} }
} }
}, []) }, [pathsTracked])
function difference<T>(l1: T[], l2: T[]): [T[], T[]] { function difference<T>(l1: T[], l2: T[]): [T[], T[]] {
return [ return [
@ -49,8 +65,7 @@ export const useFileSystemWatcher = (
] ]
} }
const hasDiff = const hasDiff = difference(paths, pathsTracked)[0].length !== 0
difference(dependencyArray, dependencyArrayTracked)[0].length !== 0
// Removing 1 watcher at a time is only possible because in a filesystem, // Removing 1 watcher at a time is only possible because in a filesystem,
// a path is unique (there can never be two paths with the same name). // a path is unique (there can never be two paths with the same name).
@ -61,19 +76,8 @@ export const useFileSystemWatcher = (
if (!hasDiff) return if (!hasDiff) return
const [pathsRemoved, pathsRemaining] = difference( const [, pathsRemaining] = difference(pathsTracked, paths)
dependencyArrayTracked, const [pathsAdded] = difference(paths, pathsTracked)
dependencyArray setPathsTracked(pathsRemaining.concat(pathsAdded))
)
for (let path of pathsRemoved) {
window.electron.watchFileOff(path)
}
const [pathsAdded] = difference(dependencyArray, dependencyArrayTracked)
for (let path of pathsAdded) {
window.electron.watchFileOn(path, (_eventType: string, path: Path) => {
callbackRef.current.fn(path).catch(reportRejection)
})
}
setDependencyArrayTracked(pathsRemaining.concat(pathsAdded))
}, [hasDiff]) }, [hasDiff])
} }

View File

@ -21,9 +21,10 @@ import {
import { getNodeFromPath } from './queryAst' import { getNodeFromPath } from './queryAst'
import { codeManager, editorManager, sceneInfra } from 'lib/singletons' import { codeManager, editorManager, sceneInfra } from 'lib/singletons'
import { Diagnostic } from '@codemirror/lint' import { Diagnostic } from '@codemirror/lint'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
interface ExecuteArgs { interface ExecuteArgs {
ast?: Program ast?: UnboxedNode<Program>
zoomToFit?: boolean zoomToFit?: boolean
executionId?: number executionId?: number
zoomOnRangeAndType?: { zoomOnRangeAndType?: {
@ -33,16 +34,14 @@ interface ExecuteArgs {
} }
export class KclManager { export class KclManager {
private _ast: Program = { private _ast: UnboxedNode<Program> = {
body: [], body: [],
start: 0, start: 0,
end: 0, end: 0,
nonCodeMeta: { nonCodeMeta: {
nonCodeNodes: {}, nonCodeNodes: {},
start: [], startNodes: [],
digest: null,
}, },
digest: null,
} }
private _execState: ExecState = emptyExecState() private _execState: ExecState = emptyExecState()
private _programMemory: ProgramMemory = ProgramMemory.empty() private _programMemory: ProgramMemory = ProgramMemory.empty()
@ -57,7 +56,7 @@ export class KclManager {
engineCommandManager: EngineCommandManager engineCommandManager: EngineCommandManager
private _isExecutingCallback: (arg: boolean) => void = () => {} private _isExecutingCallback: (arg: boolean) => void = () => {}
private _astCallBack: (arg: Program) => void = () => {} private _astCallBack: (arg: UnboxedNode<Program>) => void = () => {}
private _programMemoryCallBack: (arg: ProgramMemory) => void = () => {} private _programMemoryCallBack: (arg: ProgramMemory) => void = () => {}
private _logsCallBack: (arg: string[]) => void = () => {} private _logsCallBack: (arg: string[]) => void = () => {}
private _kclErrorsCallBack: (arg: KCLError[]) => void = () => {} private _kclErrorsCallBack: (arg: KCLError[]) => void = () => {}
@ -183,7 +182,7 @@ export class KclManager {
setWasmInitFailed, setWasmInitFailed,
}: { }: {
setProgramMemory: (arg: ProgramMemory) => void setProgramMemory: (arg: ProgramMemory) => void
setAst: (arg: Program) => void setAst: (arg: UnboxedNode<Program>) => void
setLogs: (arg: string[]) => void setLogs: (arg: string[]) => void
setKclErrors: (arg: KCLError[]) => void setKclErrors: (arg: KCLError[]) => void
setIsExecuting: (arg: boolean) => void setIsExecuting: (arg: boolean) => void
@ -207,14 +206,12 @@ export class KclManager {
end: 0, end: 0,
nonCodeMeta: { nonCodeMeta: {
nonCodeNodes: {}, nonCodeNodes: {},
start: [], startNodes: [],
digest: null,
}, },
digest: null,
} }
} }
safeParse(code: string): Program | null { safeParse(code: string): UnboxedNode<Program> | null {
const ast = parse(code) const ast = parse(code)
this.lints = [] this.lints = []
this.kclErrors = [] this.kclErrors = []
@ -381,7 +378,7 @@ export class KclManager {
Array.from(this.engineCommandManager.artifactGraph).forEach( Array.from(this.engineCommandManager.artifactGraph).forEach(
([commandId, artifact]) => { ([commandId, artifact]) => {
if (!('codeRef' in artifact)) return if (!('codeRef' in artifact)) return
const _node1 = getNodeFromPath<CallExpression>( const _node1 = getNodeFromPath<UnboxedNode<CallExpression>>(
this.ast, this.ast,
artifact.codeRef.pathToNode, artifact.codeRef.pathToNode,
'CallExpression' 'CallExpression'
@ -445,7 +442,7 @@ export class KclManager {
// but should probably have think about which of the function to keep // but should probably have think about which of the function to keep
// This always updates the code state and editor and writes to the file system. // This always updates the code state and editor and writes to the file system.
async updateAst( async updateAst(
ast: Program, ast: UnboxedNode<Program>,
execute: boolean, execute: boolean,
optionalParams?: { optionalParams?: {
focusPath?: Array<PathToNode> focusPath?: Array<PathToNode>
@ -456,7 +453,7 @@ export class KclManager {
} }
} }
): Promise<{ ): Promise<{
newAst: Program newAst: UnboxedNode<Program>
selections?: Selections selections?: Selections
}> { }> {
const newCode = recast(ast) const newCode = recast(ast)
@ -592,7 +589,7 @@ export class KclManager {
} }
// Determines if there is no KCL code which means it is executing a blank KCL file // Determines if there is no KCL code which means it is executing a blank KCL file
_isAstEmpty(ast: Program) { _isAstEmpty(ast: UnboxedNode<Program>) {
return ast.start === 0 && ast.end === 0 && ast.body.length === 0 return ast.start === 0 && ast.end === 0 && ast.body.length === 0
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -172,7 +172,6 @@ const sk2 = startSketchOn('XY')
start: 114, start: 114,
type: 'TagDeclarator', type: 'TagDeclarator',
value: 'p', value: 'p',
digest: null,
}, },
id: expect.any(String), id: expect.any(String),
sourceRange: [95, 117], sourceRange: [95, 117],
@ -223,7 +222,6 @@ const sk2 = startSketchOn('XY')
start: 114, start: 114,
type: 'TagDeclarator', type: 'TagDeclarator',
value: 'p', value: 'p',
digest: null,
}, },
__geoMeta: { __geoMeta: {
id: expect.any(String), id: expect.any(String),
@ -266,7 +264,6 @@ const sk2 = startSketchOn('XY')
start: 417, start: 417,
type: 'TagDeclarator', type: 'TagDeclarator',
value: 'o', value: 'o',
digest: null,
}, },
id: expect.any(String), id: expect.any(String),
sourceRange: [399, 420], sourceRange: [399, 420],
@ -317,7 +314,6 @@ const sk2 = startSketchOn('XY')
start: 417, start: 417,
type: 'TagDeclarator', type: 'TagDeclarator',
value: 'o', value: 'o',
digest: null,
}, },
__geoMeta: { __geoMeta: {
id: expect.any(String), id: expect.any(String),

View File

@ -73,7 +73,6 @@ const newVar = myVar + 1`
start: 89, start: 89,
type: 'TagDeclarator', type: 'TagDeclarator',
value: 'myPath', value: 'myPath',
digest: null,
}, },
}, },
{ {
@ -99,7 +98,6 @@ const newVar = myVar + 1`
start: 143, start: 143,
type: 'TagDeclarator', type: 'TagDeclarator',
value: 'rightPath', value: 'rightPath',
digest: null,
}, },
}, },
]) ])
@ -201,7 +199,6 @@ const newVar = myVar + 1`
start: 109, start: 109,
type: 'TagDeclarator', type: 'TagDeclarator',
value: 'myPath', value: 'myPath',
digest: null,
}, },
}, },
{ {

View File

@ -12,6 +12,7 @@ import { EngineCommandManager } from 'lang/std/engineConnection'
import { KCLError } from 'lang/errors' import { KCLError } from 'lang/errors'
import { Diagnostic } from '@codemirror/lint' import { Diagnostic } from '@codemirror/lint'
import { IdGenerator } from 'wasm-lib/kcl/bindings/IdGenerator' import { IdGenerator } from 'wasm-lib/kcl/bindings/IdGenerator'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
export type ToolTip = export type ToolTip =
| 'lineTo' | 'lineTo'
@ -52,7 +53,7 @@ export async function executeAst({
programMemoryOverride, programMemoryOverride,
idGenerator, idGenerator,
}: { }: {
ast: Program ast: UnboxedNode<Program>
engineCommandManager: EngineCommandManager engineCommandManager: EngineCommandManager
useFakeExecutor?: boolean useFakeExecutor?: boolean
programMemoryOverride?: ProgramMemory programMemoryOverride?: ProgramMemory

View File

@ -21,6 +21,7 @@ import { enginelessExecutor } from '../lib/testHelpers'
import { findUsesOfTagInPipe, getNodePathFromSourceRange } from './queryAst' import { findUsesOfTagInPipe, getNodePathFromSourceRange } from './queryAst'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { SimplifiedArgDetails } from './std/stdTypes' import { SimplifiedArgDetails } from './std/stdTypes'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
beforeAll(async () => { beforeAll(async () => {
await initPromise await initPromise
@ -100,16 +101,16 @@ describe('Testing findUniqueName', () => {
it('should find a unique name', () => { it('should find a unique name', () => {
const result = findUniqueName( const result = findUniqueName(
JSON.stringify([ JSON.stringify([
{ type: 'Identifier', name: 'yo01', start: 0, end: 0, digest: null }, { type: 'Identifier', name: 'yo01', start: 0, end: 0 },
{ type: 'Identifier', name: 'yo02', start: 0, end: 0, digest: null }, { type: 'Identifier', name: 'yo02', start: 0, end: 0 },
{ type: 'Identifier', name: 'yo03', start: 0, end: 0, digest: null }, { type: 'Identifier', name: 'yo03', start: 0, end: 0 },
{ type: 'Identifier', name: 'yo04', start: 0, end: 0, digest: null }, { type: 'Identifier', name: 'yo04', start: 0, end: 0 },
{ type: 'Identifier', name: 'yo05', start: 0, end: 0, digest: null }, { type: 'Identifier', name: 'yo05', start: 0, end: 0 },
{ type: 'Identifier', name: 'yo06', start: 0, end: 0, digest: null }, { type: 'Identifier', name: 'yo06', start: 0, end: 0 },
{ type: 'Identifier', name: 'yo07', start: 0, end: 0, digest: null }, { type: 'Identifier', name: 'yo07', start: 0, end: 0 },
{ type: 'Identifier', name: 'yo08', start: 0, end: 0, digest: null }, { type: 'Identifier', name: 'yo08', start: 0, end: 0 },
{ type: 'Identifier', name: 'yo09', start: 0, end: 0, digest: null }, { type: 'Identifier', name: 'yo09', start: 0, end: 0 },
] satisfies Identifier[]), ] satisfies UnboxedNode<Identifier>[]),
'yo', 'yo',
2 2
) )
@ -123,8 +124,7 @@ describe('Testing addSketchTo', () => {
body: [], body: [],
start: 0, start: 0,
end: 0, end: 0,
nonCodeMeta: { nonCodeNodes: {}, start: [], digest: null }, nonCodeMeta: { nonCodeNodes: {}, startNodes: [] },
digest: null,
}, },
'yz' 'yz'
) )

View File

@ -42,12 +42,13 @@ import { SimplifiedArgDetails } from './std/stdTypes'
import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator' import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import { ExtrudeFacePlane } from 'machines/modelingMachine' import { ExtrudeFacePlane } from 'machines/modelingMachine'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
export function startSketchOnDefault( export function startSketchOnDefault(
node: Program, node: UnboxedNode<Program>,
axis: DefaultPlaneStr, axis: DefaultPlaneStr,
name = '' name = ''
): { modifiedAst: Program; id: string; pathToNode: PathToNode } { ): { modifiedAst: UnboxedNode<Program>; id: string; pathToNode: PathToNode } {
const _node = { ...node } const _node = { ...node }
const _name = const _name =
name || findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH) name || findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH)
@ -76,10 +77,10 @@ export function startSketchOnDefault(
} }
export function addStartProfileAt( export function addStartProfileAt(
node: Program, node: UnboxedNode<Program>,
pathToNode: PathToNode, pathToNode: PathToNode,
at: [number, number] at: [number, number]
): { modifiedAst: Program; pathToNode: PathToNode } | Error { ): { modifiedAst: UnboxedNode<Program>; pathToNode: PathToNode } | Error {
const _node1 = getNodeFromPath<VariableDeclaration>( const _node1 = getNodeFromPath<VariableDeclaration>(
node, node,
pathToNode, pathToNode,
@ -114,7 +115,7 @@ export function addStartProfileAt(
} }
export function addSketchTo( export function addSketchTo(
node: Program, node: UnboxedNode<Program>,
axis: 'xy' | 'xz' | 'yz', axis: 'xy' | 'xz' | 'yz',
name = '' name = ''
): { modifiedAst: Program; id: string; pathToNode: PathToNode } { ): { modifiedAst: Program; id: string; pathToNode: PathToNode } {
@ -210,7 +211,7 @@ export function mutateArrExp(node: Expr, updateWith: ArrayExpression): boolean {
export function mutateObjExpProp( export function mutateObjExpProp(
node: Expr, node: Expr,
updateWith: Literal | ArrayExpression, updateWith: UnboxedNode<Literal> | UnboxedNode<ArrayExpression>,
key: string key: string
): boolean { ): boolean {
if (node.type === 'ObjectExpression') { if (node.type === 'ObjectExpression') {
@ -241,7 +242,6 @@ export function mutateObjExpProp(
value: updateWith, value: updateWith,
start: 0, start: 0,
end: 0, end: 0,
digest: null,
}) })
} }
} }
@ -249,13 +249,13 @@ export function mutateObjExpProp(
} }
export function extrudeSketch( export function extrudeSketch(
node: Program, node: UnboxedNode<Program>,
pathToNode: PathToNode, pathToNode: PathToNode,
shouldPipe = false, shouldPipe = false,
distance: Expr = createLiteral(4) distance: Expr = createLiteral(4)
): ):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNode: PathToNode pathToNode: PathToNode
pathToExtrudeArg: PathToNode pathToExtrudeArg: PathToNode
} }
@ -344,13 +344,13 @@ export function extrudeSketch(
} }
export function revolveSketch( export function revolveSketch(
node: Program, node: UnboxedNode<Program>,
pathToNode: PathToNode, pathToNode: PathToNode,
shouldPipe = false, shouldPipe = false,
angle: Expr = createLiteral(4) angle: Expr = createLiteral(4)
): ):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNode: PathToNode pathToNode: PathToNode
pathToRevolveArg: PathToNode pathToRevolveArg: PathToNode
} }
@ -440,7 +440,7 @@ export function revolveSketch(
} }
export function sketchOnExtrudedFace( export function sketchOnExtrudedFace(
node: Program, node: UnboxedNode<Program>,
sketchPathToNode: PathToNode, sketchPathToNode: PathToNode,
extrudePathToNode: PathToNode, extrudePathToNode: PathToNode,
info: ExtrudeFacePlane['faceInfo'] = { type: 'wall' } info: ExtrudeFacePlane['faceInfo'] = { type: 'wall' }
@ -572,50 +572,48 @@ export function splitPathAtPipeExpression(pathToNode: PathToNode): {
return splitPathAtPipeExpression(pathToNode.slice(0, -1)) return splitPathAtPipeExpression(pathToNode.slice(0, -1))
} }
export function createLiteral(value: string | number): Literal { export function createLiteral(value: string | number): UnboxedNode<Literal> {
return { return {
type: 'Literal', type: 'Literal',
start: 0, start: 0,
end: 0, end: 0,
value, value,
raw: `${value}`, raw: `${value}`,
digest: null,
} }
} }
export function createTagDeclarator(value: string): TagDeclarator { export function createTagDeclarator(value: string): UnboxedNode<TagDeclarator> {
return { return {
type: 'TagDeclarator', type: 'TagDeclarator',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
value, value,
} }
} }
export function createIdentifier(name: string): Identifier { export function createIdentifier(name: string): UnboxedNode<Identifier> {
return { return {
type: 'Identifier', type: 'Identifier',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
name, name,
} }
} }
export function createPipeSubstitution(): PipeSubstitution { export function createPipeSubstitution(): UnboxedNode<PipeSubstitution> {
return { return {
type: 'PipeSubstitution', type: 'PipeSubstitution',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
} }
} }
export function createCallExpressionStdLib( export function createCallExpressionStdLib(
name: string, name: string,
args: CallExpression['arguments'] args: CallExpression['arguments']
): CallExpression { ): UnboxedNode<CallExpression> {
return { return {
type: 'CallExpression', type: 'CallExpression',
start: 0, start: 0,
@ -624,19 +622,18 @@ export function createCallExpressionStdLib(
type: 'Identifier', type: 'Identifier',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
name, name,
}, },
optional: false, optional: false,
arguments: args, arguments: args,
digest: null,
} }
} }
export function createCallExpression( export function createCallExpression(
name: string, name: string,
args: CallExpression['arguments'] args: CallExpression['arguments']
): CallExpression { ): UnboxedNode<CallExpression> {
return { return {
type: 'CallExpression', type: 'CallExpression',
start: 0, start: 0,
@ -645,23 +642,22 @@ export function createCallExpression(
type: 'Identifier', type: 'Identifier',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
name, name,
}, },
optional: false, optional: false,
arguments: args, arguments: args,
digest: null,
} }
} }
export function createArrayExpression( export function createArrayExpression(
elements: ArrayExpression['elements'] elements: ArrayExpression['elements']
): ArrayExpression { ): UnboxedNode<ArrayExpression> {
return { return {
type: 'ArrayExpression', type: 'ArrayExpression',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
nonCodeMeta: nonCodeMetaEmpty(), nonCodeMeta: nonCodeMetaEmpty(),
elements, elements,
} }
@ -669,12 +665,12 @@ export function createArrayExpression(
export function createPipeExpression( export function createPipeExpression(
body: PipeExpression['body'] body: PipeExpression['body']
): PipeExpression { ): UnboxedNode<PipeExpression> {
return { return {
type: 'PipeExpression', type: 'PipeExpression',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
body, body,
nonCodeMeta: nonCodeMetaEmpty(), nonCodeMeta: nonCodeMetaEmpty(),
} }
@ -685,18 +681,18 @@ export function createVariableDeclaration(
init: VariableDeclarator['init'], init: VariableDeclarator['init'],
visibility: VariableDeclaration['visibility'] = 'default', visibility: VariableDeclaration['visibility'] = 'default',
kind: VariableDeclaration['kind'] = 'const' kind: VariableDeclaration['kind'] = 'const'
): VariableDeclaration { ): UnboxedNode<VariableDeclaration> {
return { return {
type: 'VariableDeclaration', type: 'VariableDeclaration',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
declarations: [ declarations: [
{ {
type: 'VariableDeclarator', type: 'VariableDeclarator',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
id: createIdentifier(varName), id: createIdentifier(varName),
init, init,
}, },
@ -708,19 +704,19 @@ export function createVariableDeclaration(
export function createObjectExpression(properties: { export function createObjectExpression(properties: {
[key: string]: Expr [key: string]: Expr
}): ObjectExpression { }): UnboxedNode<ObjectExpression> {
return { return {
type: 'ObjectExpression', type: 'ObjectExpression',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
nonCodeMeta: nonCodeMetaEmpty(), nonCodeMeta: nonCodeMetaEmpty(),
properties: Object.entries(properties).map(([key, value]) => ({ properties: Object.entries(properties).map(([key, value]) => ({
type: 'ObjectProperty', type: 'ObjectProperty',
start: 0, start: 0,
end: 0, end: 0,
key: createIdentifier(key), key: createIdentifier(key),
digest: null,
value, value,
})), })),
} }
@ -729,12 +725,12 @@ export function createObjectExpression(properties: {
export function createUnaryExpression( export function createUnaryExpression(
argument: UnaryExpression['argument'], argument: UnaryExpression['argument'],
operator: UnaryExpression['operator'] = '-' operator: UnaryExpression['operator'] = '-'
): UnaryExpression { ): UnboxedNode<UnaryExpression> {
return { return {
type: 'UnaryExpression', type: 'UnaryExpression',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
operator, operator,
argument, argument,
} }
@ -744,12 +740,12 @@ export function createBinaryExpression([left, operator, right]: [
BinaryExpression['left'], BinaryExpression['left'],
BinaryExpression['operator'], BinaryExpression['operator'],
BinaryExpression['right'] BinaryExpression['right']
]): BinaryExpression { ]): UnboxedNode<BinaryExpression> {
return { return {
type: 'BinaryExpression', type: 'BinaryExpression',
start: 0, start: 0,
end: 0, end: 0,
digest: null,
operator, operator,
left, left,
right, right,
@ -759,19 +755,19 @@ export function createBinaryExpression([left, operator, right]: [
export function createBinaryExpressionWithUnary([left, right]: [ export function createBinaryExpressionWithUnary([left, right]: [
BinaryExpression['left'], BinaryExpression['left'],
BinaryExpression['right'] BinaryExpression['right']
]): BinaryExpression { ]): UnboxedNode<BinaryExpression> {
if (right.type === 'UnaryExpression' && right.operator === '-') if (right.type === 'UnaryExpression' && right.operator === '-')
return createBinaryExpression([left, '-', right.argument]) return createBinaryExpression([left, '-', right.argument])
return createBinaryExpression([left, '+', right]) return createBinaryExpression([left, '+', right])
} }
export function giveSketchFnCallTag( export function giveSketchFnCallTag(
ast: Program, ast: UnboxedNode<Program>,
range: Selection['range'], range: Selection['range'],
tag?: string tag?: string
): ):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
tag: string tag: string
isTagExisting: boolean isTagExisting: boolean
pathToNode: PathToNode pathToNode: PathToNode
@ -806,7 +802,7 @@ export function giveSketchFnCallTag(
} }
export function moveValueIntoNewVariablePath( export function moveValueIntoNewVariablePath(
ast: Program, ast: UnboxedNode<Program>,
programMemory: ProgramMemory, programMemory: ProgramMemory,
pathToNode: PathToNode, pathToNode: PathToNode,
variableName: string variableName: string
@ -839,12 +835,12 @@ export function moveValueIntoNewVariablePath(
} }
export function moveValueIntoNewVariable( export function moveValueIntoNewVariable(
ast: Program, ast: UnboxedNode<Program>,
programMemory: ProgramMemory, programMemory: ProgramMemory,
sourceRange: Selection['range'], sourceRange: Selection['range'],
variableName: string variableName: string
): { ): {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToReplacedNode?: PathToNode pathToReplacedNode?: PathToNode
} { } {
const meta = isNodeSafeToReplace(ast, sourceRange) const meta = isNodeSafeToReplace(ast, sourceRange)
@ -877,17 +873,17 @@ export function moveValueIntoNewVariable(
*/ */
export function deleteSegmentFromPipeExpression( export function deleteSegmentFromPipeExpression(
dependentRanges: SourceRange[], dependentRanges: SourceRange[],
modifiedAst: Program, modifiedAst: UnboxedNode<Program>,
programMemory: ProgramMemory, programMemory: ProgramMemory,
code: string, code: string,
pathToNode: PathToNode pathToNode: PathToNode
): Program | Error { ): UnboxedNode<Program> | Error {
let _modifiedAst = structuredClone(modifiedAst) let _modifiedAst = structuredClone(modifiedAst)
dependentRanges.forEach((range) => { dependentRanges.forEach((range) => {
const path = getNodePathFromSourceRange(_modifiedAst, range) const path = getNodePathFromSourceRange(_modifiedAst, range)
const callExp = getNodeFromPath<CallExpression>( const callExp = getNodeFromPath<UnboxedNode<CallExpression>>(
_modifiedAst, _modifiedAst,
path, path,
'CallExpression', 'CallExpression',
@ -933,11 +929,11 @@ export function deleteSegmentFromPipeExpression(
export function removeSingleConstraintInfo( export function removeSingleConstraintInfo(
pathToCallExp: PathToNode, pathToCallExp: PathToNode,
argDetails: SimplifiedArgDetails, argDetails: SimplifiedArgDetails,
ast: Program, ast: UnboxedNode<Program>,
programMemory: ProgramMemory programMemory: ProgramMemory
): ):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNodeMap: PathToNodeMap pathToNodeMap: PathToNodeMap
} }
| false { | false {
@ -959,12 +955,12 @@ export function removeSingleConstraintInfo(
} }
export async function deleteFromSelection( export async function deleteFromSelection(
ast: Program, ast: UnboxedNode<Program>,
selection: Selection, selection: Selection,
programMemory: ProgramMemory, programMemory: ProgramMemory,
getFaceDetails: (id: string) => Promise<Models['FaceIsPlanar_type']> = () => getFaceDetails: (id: string) => Promise<Models['FaceIsPlanar_type']> = () =>
({} as any) ({} as any)
): Promise<Program | Error> { ): Promise<UnboxedNode<Program> | Error> {
const astClone = structuredClone(ast) const astClone = structuredClone(ast)
const range = selection.range const range = selection.range
const path = getNodePathFromSourceRange(ast, range) const path = getNodePathFromSourceRange(ast, range)
@ -1139,5 +1135,5 @@ export async function deleteFromSelection(
} }
const nonCodeMetaEmpty = () => { const nonCodeMetaEmpty = () => {
return { nonCodeNodes: {}, start: [], digest: null } return { nonCodeNodes: {}, startNodes: [], start: 0, end: 0 }
} }

View File

@ -41,7 +41,7 @@ beforeAll(async () => {
}, },
}) })
}) })
}, 20_000) }, 30_000)
afterAll(() => { afterAll(() => {
engineCommandManager.tearDown() engineCommandManager.tearDown()

View File

@ -36,11 +36,12 @@ import {
getSweepFromSuspectedPath, getSweepFromSuspectedPath,
} from 'lang/std/artifactGraph' } from 'lang/std/artifactGraph'
import { kclManager, engineCommandManager, editorManager } from 'lib/singletons' import { kclManager, engineCommandManager, editorManager } from 'lib/singletons'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
// Apply Fillet To Selection // Apply Fillet To Selection
export function applyFilletToSelection( export function applyFilletToSelection(
ast: Program, ast: UnboxedNode<Program>,
selection: Selections, selection: Selections,
radius: KclCommandValue radius: KclCommandValue
): void | Error { ): void | Error {
@ -55,10 +56,12 @@ export function applyFilletToSelection(
} }
export function modifyAstCloneWithFilletAndTag( export function modifyAstCloneWithFilletAndTag(
ast: Program, ast: UnboxedNode<Program>,
selection: Selections, selection: Selections,
radius: KclCommandValue radius: KclCommandValue
): { modifiedAst: Program; pathToFilletNode: Array<PathToNode> } | Error { ):
| { modifiedAst: UnboxedNode<Program>; pathToFilletNode: Array<PathToNode> }
| Error {
let clonedAst = structuredClone(ast) let clonedAst = structuredClone(ast)
const clonedAstForGetExtrude = structuredClone(ast) const clonedAstForGetExtrude = structuredClone(ast)
@ -246,7 +249,7 @@ export function getPathToExtrudeForSegmentSelection(
} }
async function updateAstAndFocus( async function updateAstAndFocus(
modifiedAst: Program, modifiedAst: UnboxedNode<Program>,
pathToFilletNode: Array<PathToNode> pathToFilletNode: Array<PathToNode>
) { ) {
const updatedAst = await kclManager.updateAst(modifiedAst, true, { const updatedAst = await kclManager.updateAst(modifiedAst, true, {
@ -258,7 +261,7 @@ async function updateAstAndFocus(
} }
function mutateAstWithTagForSketchSegment( function mutateAstWithTagForSketchSegment(
astClone: Program, astClone: UnboxedNode<Program>,
pathToSegmentNode: PathToNode pathToSegmentNode: PathToNode
): { modifiedAst: Program; tag: string } | Error { ): { modifiedAst: Program; tag: string } | Error {
const segmentNode = getNodeFromPath<CallExpression>( const segmentNode = getNodeFromPath<CallExpression>(
@ -292,7 +295,7 @@ function mutateAstWithTagForSketchSegment(
function getEdgeTagCall( function getEdgeTagCall(
tag: string, tag: string,
selectionType: string selectionType: string
): Identifier | CallExpression { ): UnboxedNode<Identifier | CallExpression> {
let tagCall: Expr = createIdentifier(tag) let tagCall: Expr = createIdentifier(tag)
// Modify the tag based on selectionType // Modify the tag based on selectionType
@ -426,7 +429,7 @@ export const hasValidFilletSelection = ({
code, code,
}: { }: {
selectionRanges: Selections selectionRanges: Selections
ast: Program ast: UnboxedNode<Program>
code: string code: string
}) => { }) => {
// check if there is anything filletable in the scene // check if there is anything filletable in the scene
@ -454,7 +457,7 @@ export const hasValidFilletSelection = ({
for (const selection of selectionRanges.codeBasedSelections) { for (const selection of selectionRanges.codeBasedSelections) {
// check if all selections are in sketchLineHelperMap // check if all selections are in sketchLineHelperMap
const path = getNodePathFromSourceRange(ast, selection.range) const path = getNodePathFromSourceRange(ast, selection.range)
const segmentNode = getNodeFromPath<CallExpression>( const segmentNode = getNodeFromPath<UnboxedNode<CallExpression>>(
ast, ast,
path, path,
'CallExpression' 'CallExpression'
@ -534,7 +537,7 @@ export const isTagUsedInFillet = ({
ast, ast,
callExp, callExp,
}: { }: {
ast: Program ast: UnboxedNode<Program>
callExp: CallExpression callExp: CallExpression
}): Array<EdgeTypes> => { }): Array<EdgeTypes> => {
const tag = getTagFromCallExpression(callExp) const tag = getTagFromCallExpression(callExp)

View File

@ -29,6 +29,7 @@ import {
} from './std/sketchcombos' } from './std/sketchcombos'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { ImportStatement } from 'wasm-lib/kcl/bindings/ImportStatement' import { ImportStatement } from 'wasm-lib/kcl/bindings/ImportStatement'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
/** /**
* Retrieves a node from a given path within a Program node structure, optionally stopping at a specified node type. * Retrieves a node from a given path within a Program node structure, optionally stopping at a specified node type.
@ -121,12 +122,13 @@ export function getNodeFromPathCurry(
} }
function moreNodePathFromSourceRange( function moreNodePathFromSourceRange(
node: node: UnboxedNode<
| Expr | Expr
| ImportStatement | ImportStatement
| ExpressionStatement | ExpressionStatement
| VariableDeclaration | VariableDeclaration
| ReturnStatement, | ReturnStatement
>,
sourceRange: Selection['range'], sourceRange: Selection['range'],
previousPath: PathToNode = [['body', '']] previousPath: PathToNode = [['body', '']]
): PathToNode { ): PathToNode {
@ -344,15 +346,16 @@ export function getNodePathFromSourceRange(
return path return path
} }
type KCLNode = type KCLNode = UnboxedNode<
| Expr | Expr
| ExpressionStatement | ExpressionStatement
| VariableDeclaration | VariableDeclaration
| VariableDeclarator | VariableDeclarator
| ReturnStatement | ReturnStatement
>
export function traverse( export function traverse(
node: KCLNode | Program, node: KCLNode | UnboxedNode<Program>,
option: { option: {
enter?: (node: KCLNode, pathToNode: PathToNode) => void enter?: (node: KCLNode, pathToNode: PathToNode) => void
leave?: (node: KCLNode) => void leave?: (node: KCLNode) => void
@ -512,9 +515,9 @@ export function findAllPreviousVariables(
} }
type ReplacerFn = ( type ReplacerFn = (
_ast: Program, _ast: UnboxedNode<Program>,
varName: string varName: string
) => { modifiedAst: Program; pathToReplaced: PathToNode } | Error ) => { modifiedAst: UnboxedNode<Program>; pathToReplaced: PathToNode } | Error
export function isNodeSafeToReplacePath( export function isNodeSafeToReplacePath(
ast: Program, ast: Program,
@ -583,12 +586,12 @@ export function isNodeSafeToReplacePath(
} }
export function isNodeSafeToReplace( export function isNodeSafeToReplace(
ast: Program, ast: UnboxedNode<Program>,
sourceRange: [number, number] sourceRange: [number, number]
): ):
| { | {
isSafe: boolean isSafe: boolean
value: Expr value: UnboxedNode<Expr>
replacer: ReplacerFn replacer: ReplacerFn
} }
| Error { | Error {
@ -837,7 +840,7 @@ export function findUsesOfTagInPipe(
? String(thirdParam.value) ? String(thirdParam.value)
: thirdParam.name : thirdParam.name
const varDec = getNodeFromPath<VariableDeclaration>( const varDec = getNodeFromPath<UnboxedNode<VariableDeclaration>>(
ast, ast,
pathToNode, pathToNode,
'VariableDeclaration' 'VariableDeclaration'

View File

@ -18,7 +18,7 @@ class FileSystemManager {
return Promise.resolve(window.electron.path.join(dir, path)) return Promise.resolve(window.electron.path.join(dir, path))
} }
async readFile(path: string): Promise<Uint8Array | void> { async readFile(path: string): Promise<Uint8Array> {
// Using local file system only works from desktop. // Using local file system only works from desktop.
if (!isDesktop()) { if (!isDesktop()) {
return Promise.reject( return Promise.reject(

View File

@ -17,6 +17,7 @@ import {
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst' import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
import { enginelessExecutor } from '../../lib/testHelpers' import { enginelessExecutor } from '../../lib/testHelpers'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
const eachQuad: [number, [number, number]][] = [ const eachQuad: [number, [number, number]][] = [
[-315, [1, 1]], [-315, [1, 1]],
@ -687,7 +688,7 @@ describe('testing getConstraintInfo', () => {
] ]
if (err(ast)) return ast if (err(ast)) return ast
const pathToNode = getNodePathFromSourceRange(ast, sourceRange) const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
const callExp = getNodeFromPath<CallExpression>( const callExp = getNodeFromPath<UnboxedNode<CallExpression>>(
ast, ast,
pathToNode, pathToNode,
'CallExpression' 'CallExpression'
@ -841,7 +842,7 @@ describe('testing getConstraintInfo', () => {
] ]
if (err(ast)) return ast if (err(ast)) return ast
const pathToNode = getNodePathFromSourceRange(ast, sourceRange) const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
const callExp = getNodeFromPath<CallExpression>( const callExp = getNodeFromPath<UnboxedNode<CallExpression>>(
ast, ast,
pathToNode, pathToNode,
'CallExpression' 'CallExpression'
@ -1197,7 +1198,7 @@ describe('testing getConstraintInfo', () => {
] ]
if (err(ast)) return ast if (err(ast)) return ast
const pathToNode = getNodePathFromSourceRange(ast, sourceRange) const pathToNode = getNodePathFromSourceRange(ast, sourceRange)
const callExp = getNodeFromPath<CallExpression>( const callExp = getNodeFromPath<UnboxedNode<CallExpression>>(
ast, ast,
pathToNode, pathToNode,
'CallExpression' 'CallExpression'

View File

@ -55,6 +55,7 @@ import { err } from 'lib/trap'
import { perpendicularDistance } from 'sketch-helpers' import { perpendicularDistance } from 'sketch-helpers'
import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator' import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator'
import { EdgeCutInfo } from 'machines/modelingMachine' import { EdgeCutInfo } from 'machines/modelingMachine'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
const STRAIGHT_SEGMENT_ERR = new Error( const STRAIGHT_SEGMENT_ERR = new Error(
'Invalid input, expected "straight-segment"' 'Invalid input, expected "straight-segment"'
@ -1785,7 +1786,8 @@ export const angledLineThatIntersects: SketchLineHelper = {
) )
} }
if (intersectTag !== -1) { if (intersectTag !== -1) {
const tag = firstArg.properties[intersectTag]?.value as Identifier const tag = firstArg.properties[intersectTag]
?.value as UnboxedNode<Identifier>
const pathToTagProp: PathToNode = [ const pathToTagProp: PathToNode = [
...pathToObjectExp, ...pathToObjectExp,
[intersectTag, 'index'], [intersectTag, 'index'],
@ -1823,11 +1825,12 @@ export const updateStartProfileAtArgs: SketchLineHelper['updateArgs'] = ({
start: 0, start: 0,
end: 0, end: 0,
body: [], body: [],
digest: null,
nonCodeMeta: { nonCodeMeta: {
start: [], start: 0,
end: 0,
startNodes: [],
nonCodeNodes: [], nonCodeNodes: [],
digest: null,
}, },
}, },
pathToNode, pathToNode,
@ -1866,7 +1869,7 @@ export const sketchLineHelperMap: { [key: string]: SketchLineHelper } = {
} as const } as const
export function changeSketchArguments( export function changeSketchArguments(
node: Program, node: UnboxedNode<Program>,
programMemory: ProgramMemory, programMemory: ProgramMemory,
sourceRangeOrPath: sourceRangeOrPath:
| { | {
@ -1878,7 +1881,7 @@ export function changeSketchArguments(
pathToNode: PathToNode pathToNode: PathToNode
}, },
input: SegmentInputs input: SegmentInputs
): { modifiedAst: Program; pathToNode: PathToNode } | Error { ): { modifiedAst: UnboxedNode<Program>; pathToNode: PathToNode } | Error {
const _node = { ...node } const _node = { ...node }
const thePath = const thePath =
sourceRangeOrPath.type === 'sourceRange' sourceRangeOrPath.type === 'sourceRange'
@ -1907,7 +1910,7 @@ export function changeSketchArguments(
} }
export function getConstraintInfo( export function getConstraintInfo(
callExpression: CallExpression, callExpression: UnboxedNode<CallExpression>,
code: string, code: string,
pathToNode: PathToNode pathToNode: PathToNode
): ConstrainInfo[] { ): ConstrainInfo[] {
@ -1945,7 +1948,7 @@ export function compareVec2Epsilon2(
} }
interface CreateLineFnCallArgs { interface CreateLineFnCallArgs {
node: Program node: UnboxedNode<Program>
programMemory: ProgramMemory programMemory: ProgramMemory
input: SegmentInputs input: SegmentInputs
fnName: ToolTip fnName: ToolTip
@ -1962,7 +1965,7 @@ export function addNewSketchLn({
spliceBetween = false, spliceBetween = false,
}: CreateLineFnCallArgs): }: CreateLineFnCallArgs):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNode: PathToNode pathToNode: PathToNode
} }
| Error { | Error {
@ -1972,8 +1975,12 @@ export function addNewSketchLn({
return new Error('not a sketch line helper') return new Error('not a sketch line helper')
} }
getNodeFromPath<VariableDeclarator>(node, pathToNode, 'VariableDeclarator') getNodeFromPath<UnboxedNode<VariableDeclarator>>(
getNodeFromPath<PipeExpression | CallExpression>( node,
pathToNode,
'VariableDeclarator'
)
getNodeFromPath<UnboxedNode<PipeExpression | CallExpression>>(
node, node,
pathToNode, pathToNode,
'PipeExpression' 'PipeExpression'
@ -1992,13 +1999,13 @@ export function addCallExpressionsToPipe({
pathToNode, pathToNode,
expressions, expressions,
}: { }: {
node: Program node: UnboxedNode<Program>
programMemory: ProgramMemory programMemory: ProgramMemory
pathToNode: PathToNode pathToNode: PathToNode
expressions: CallExpression[] expressions: UnboxedNode<CallExpression>[]
}) { }) {
const _node = { ...node } const _node = { ...node }
const pipeExpression = getNodeFromPath<PipeExpression>( const pipeExpression = getNodeFromPath<UnboxedNode<PipeExpression>>(
_node, _node,
pathToNode, pathToNode,
'PipeExpression' 'PipeExpression'
@ -2047,7 +2054,7 @@ export function replaceSketchLine({
replaceExistingCallback, replaceExistingCallback,
referencedSegment, referencedSegment,
}: { }: {
node: Program node: UnboxedNode<Program>
programMemory: ProgramMemory programMemory: ProgramMemory
pathToNode: PathToNode pathToNode: PathToNode
fnName: ToolTip fnName: ToolTip
@ -2056,7 +2063,7 @@ export function replaceSketchLine({
referencedSegment?: Path referencedSegment?: Path
}): }):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
valueUsedInTransform?: number valueUsedInTransform?: number
pathToNode: PathToNode pathToNode: PathToNode
} }
@ -2108,7 +2115,7 @@ function addTagToChamfer(
edgeCutMeta: EdgeCutInfo | null edgeCutMeta: EdgeCutInfo | null
): ):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
tag: string tag: string
} }
| Error { | Error {
@ -2235,7 +2242,7 @@ export function addTagForSketchOnFace(
edgeCutMeta: EdgeCutInfo | null edgeCutMeta: EdgeCutInfo | null
): ):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
tag: string tag: string
} }
| Error { | Error {
@ -2273,12 +2280,14 @@ function isAngleLiteral(lineArugement: Expr): boolean {
: false : false
} }
type addTagFn = (a: AddTagInfo) => { modifiedAst: Program; tag: string } | Error type addTagFn = (
a: AddTagInfo
) => { modifiedAst: UnboxedNode<Program>; tag: string } | Error
function addTag(tagIndex = 2): addTagFn { function addTag(tagIndex = 2): addTagFn {
return ({ node, pathToNode }) => { return ({ node, pathToNode }) => {
const _node = { ...node } const _node = { ...node }
const callExpr = getNodeFromPath<CallExpression>( const callExpr = getNodeFromPath<UnboxedNode<CallExpression>>(
_node, _node,
pathToNode, pathToNode,
'CallExpression' 'CallExpression'

View File

@ -49,6 +49,7 @@ import {
getSketchSegmentFromSourceRange, getSketchSegmentFromSourceRange,
} from './sketchConstraints' } from './sketchConstraints'
import { getAngle, roundOff, normaliseAngle } from '../../lib/utils' import { getAngle, roundOff, normaliseAngle } from '../../lib/utils'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
export type LineInputsType = export type LineInputsType =
| 'xAbsolute' | 'xAbsolute'
@ -325,7 +326,7 @@ const setHorzVertDistanceCreateNode =
if (isUndef(refNum) || err(literalArg)) return REF_NUM_ERR if (isUndef(refNum) || err(literalArg)) return REF_NUM_ERR
const valueUsedInTransform = roundOff(literalArg - refNum, 2) const valueUsedInTransform = roundOff(literalArg - refNum, 2)
let finalValue: Expr = createBinaryExpressionWithUnary([ let finalValue: UnboxedNode<Expr> = createBinaryExpressionWithUnary([
createSegEnd(referenceSegName, !index), createSegEnd(referenceSegName, !index),
forceValueUsedInTransform || createLiteral(valueUsedInTransform), forceValueUsedInTransform || createLiteral(valueUsedInTransform),
]) ])
@ -1541,7 +1542,7 @@ export function transformSecondarySketchLinesTagFirst({
forceSegName, forceSegName,
forceValueUsedInTransform, forceValueUsedInTransform,
}: { }: {
ast: Program ast: UnboxedNode<Program>
selectionRanges: Selections selectionRanges: Selections
transformInfos: TransformInfo[] transformInfos: TransformInfo[]
programMemory: ProgramMemory programMemory: ProgramMemory
@ -1549,7 +1550,7 @@ export function transformSecondarySketchLinesTagFirst({
forceValueUsedInTransform?: BinaryPart forceValueUsedInTransform?: BinaryPart
}): }):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
valueUsedInTransform?: number valueUsedInTransform?: number
pathToNodeMap: PathToNodeMap pathToNodeMap: PathToNodeMap
tagInfo: { tagInfo: {
@ -1620,7 +1621,7 @@ export function transformAstSketchLines({
forceValueUsedInTransform, forceValueUsedInTransform,
referencedSegmentRange, referencedSegmentRange,
}: { }: {
ast: Program ast: UnboxedNode<Program>
selectionRanges: Selections | PathToNode[] selectionRanges: Selections | PathToNode[]
transformInfos: TransformInfo[] transformInfos: TransformInfo[]
programMemory: ProgramMemory programMemory: ProgramMemory
@ -1629,7 +1630,7 @@ export function transformAstSketchLines({
referencedSegmentRange?: Selection['range'] referencedSegmentRange?: Selection['range']
}): }):
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
valueUsedInTransform?: number valueUsedInTransform?: number
pathToNodeMap: PathToNodeMap pathToNodeMap: PathToNodeMap
} }
@ -1647,7 +1648,7 @@ export function transformAstSketchLines({
const getNode = getNodeFromPathCurry(node, _pathToNode) const getNode = getNodeFromPathCurry(node, _pathToNode)
const callExp = getNode<CallExpression>('CallExpression') const callExp = getNode<UnboxedNode<CallExpression>>('CallExpression')
if (err(callExp)) return callExp if (err(callExp)) return callExp
const varDec = getNode<VariableDeclarator>('VariableDeclarator') const varDec = getNode<VariableDeclarator>('VariableDeclarator')
if (err(varDec)) return varDec if (err(varDec)) return varDec
@ -1806,13 +1807,16 @@ function createSegAngle(referenceSegName: string): BinaryPart {
return createCallExpression('segAng', [createIdentifier(referenceSegName)]) return createCallExpression('segAng', [createIdentifier(referenceSegName)])
} }
function createSegEnd(referenceSegName: string, isX: boolean): CallExpression { function createSegEnd(
referenceSegName: string,
isX: boolean
): UnboxedNode<CallExpression> {
return createCallExpression(isX ? 'segEndX' : 'segEndY', [ return createCallExpression(isX ? 'segEndX' : 'segEndY', [
createIdentifier(referenceSegName), createIdentifier(referenceSegName),
]) ])
} }
function createLastSeg(isX: boolean): CallExpression { function createLastSeg(isX: boolean): UnboxedNode<CallExpression> {
return createCallExpression(isX ? 'lastSegX' : 'lastSegY', [ return createCallExpression(isX ? 'lastSegX' : 'lastSegY', [
createPipeSubstitution(), createPipeSubstitution(),
]) ])
@ -1830,7 +1834,7 @@ export function getConstraintLevelFromSourceRange(
ast: Program | Error ast: Program | Error
): Error | { range: [number, number]; level: ConstraintLevel } { ): Error | { range: [number, number]; level: ConstraintLevel } {
if (err(ast)) return ast if (err(ast)) return ast
const nodeMeta = getNodeFromPath<CallExpression>( const nodeMeta = getNodeFromPath<UnboxedNode<CallExpression>>(
ast, ast,
getNodePathFromSourceRange(ast, cursorRange), getNodePathFromSourceRange(ast, cursorRange),
'CallExpression' 'CallExpression'

View File

@ -11,16 +11,17 @@ import {
BinaryPart, BinaryPart,
} from '../wasm' } from '../wasm'
import { LineInputsType } from './sketchcombos' import { LineInputsType } from './sketchcombos'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
export interface ModifyAstBase { export interface ModifyAstBase {
node: Program node: UnboxedNode<Program>
// TODO #896: Remove ProgramMemory from this interface // TODO #896: Remove ProgramMemory from this interface
previousProgramMemory: ProgramMemory previousProgramMemory: ProgramMemory
pathToNode: PathToNode pathToNode: PathToNode
} }
export interface AddTagInfo { export interface AddTagInfo {
node: Program node: UnboxedNode<Program>
pathToNode: PathToNode pathToNode: PathToNode
} }
@ -134,7 +135,7 @@ type _InputArg<T> =
* Which is why a union type is used that can be type narrowed using the {@link RawArg.type} property * Which is why a union type is used that can be type narrowed using the {@link RawArg.type} property
* {@link RawArg.expr} is common to all of these types * {@link RawArg.expr} is common to all of these types
*/ */
export type InputArg = _InputArg<Expr> export type InputArg = _InputArg<UnboxedNode<Expr>>
/** /**
* {@link RawArg.expr} is the literal equivalent of whatever current expression is * {@link RawArg.expr} is the literal equivalent of whatever current expression is
@ -142,7 +143,7 @@ export type InputArg = _InputArg<Expr>
* but of course works for expressions like myVar + someFn() etc too * but of course works for expressions like myVar + someFn() etc too
* This is useful in cases where we want to "un-constrain" inputs to segments * This is useful in cases where we want to "un-constrain" inputs to segments
*/ */
type RawArg = _InputArg<Literal> type RawArg = _InputArg<UnboxedNode<Literal>>
export type InputArgs = Array<InputArg> export type InputArgs = Array<InputArg>
@ -186,7 +187,7 @@ export type CreateStdLibSketchCallExpr = (args: {
inputs: InputArgs inputs: InputArgs
rawArgs: RawArgs rawArgs: RawArgs
referenceSegName: string referenceSegName: string
tag?: Expr tag?: UnboxedNode<Expr>
forceValueUsedInTransform?: BinaryPart forceValueUsedInTransform?: BinaryPart
referencedSegment?: Path referencedSegment?: Path
}) => CreatedSketchExprResult | Error }) => CreatedSketchExprResult | Error
@ -215,26 +216,26 @@ export interface ConstrainInfo {
export interface SketchLineHelper { export interface SketchLineHelper {
add: (a: addCall) => add: (a: addCall) =>
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNode: PathToNode pathToNode: PathToNode
valueUsedInTransform?: number valueUsedInTransform?: number
} }
| Error | Error
updateArgs: (a: updateArgs) => updateArgs: (a: updateArgs) =>
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
pathToNode: PathToNode pathToNode: PathToNode
} }
| Error | Error
getTag: (a: CallExpression) => string | Error getTag: (a: CallExpression) => string | Error
addTag: (a: AddTagInfo) => addTag: (a: AddTagInfo) =>
| { | {
modifiedAst: Program modifiedAst: UnboxedNode<Program>
tag: string tag: string
} }
| Error | Error
getConstraintInfo: ( getConstraintInfo: (
callExp: CallExpression, callExp: UnboxedNode<CallExpression>,
code: string, code: string,
pathToNode: PathToNode pathToNode: PathToNode
) => ConstrainInfo[] ) => ConstrainInfo[]

13
src/lang/wasm.test.ts Normal file
View File

@ -0,0 +1,13 @@
import { err } from 'lib/trap'
import { parse } from './wasm'
import { enginelessExecutor } from 'lib/testHelpers'
it('can execute parsed AST', async () => {
const code = `x = 1
// A comment.`
const ast = parse(code)
expect(err(ast)).toEqual(false)
const execState = await enginelessExecutor(ast)
expect(err(ast)).toEqual(false)
expect(execState.memory.get('x')).toEqual(1)
})

View File

@ -42,6 +42,7 @@ import { ExecState as RawExecState } from '../wasm-lib/kcl/bindings/ExecState'
import { ProgramMemory as RawProgramMemory } from '../wasm-lib/kcl/bindings/ProgramMemory' import { ProgramMemory as RawProgramMemory } from '../wasm-lib/kcl/bindings/ProgramMemory'
import { EnvironmentRef } from '../wasm-lib/kcl/bindings/EnvironmentRef' import { EnvironmentRef } from '../wasm-lib/kcl/bindings/EnvironmentRef'
import { Environment } from '../wasm-lib/kcl/bindings/Environment' import { Environment } from '../wasm-lib/kcl/bindings/Environment'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
export type { Program } from '../wasm-lib/kcl/bindings/Program' export type { Program } from '../wasm-lib/kcl/bindings/Program'
export type { Expr } from '../wasm-lib/kcl/bindings/Expr' export type { Expr } from '../wasm-lib/kcl/bindings/Expr'
@ -122,11 +123,11 @@ export const initPromise = initialise()
export const rangeTypeFix = (ranges: number[][]): [number, number][] => export const rangeTypeFix = (ranges: number[][]): [number, number][] =>
ranges.map(([start, end]) => [start, end]) ranges.map(([start, end]) => [start, end])
export const parse = (code: string | Error): Program | Error => { export const parse = (code: string | Error): UnboxedNode<Program> | Error => {
if (err(code)) return code if (err(code)) return code
try { try {
const program: Program = parse_wasm(code) const program: UnboxedNode<Program> = parse_wasm(code)
return program return program
} catch (e: any) { } catch (e: any) {
// throw e // throw e
@ -378,7 +379,7 @@ export function sketchFromKclValue(
} }
export const executor = async ( export const executor = async (
node: Program, node: UnboxedNode<Program>,
programMemory: ProgramMemory | Error = ProgramMemory.empty(), programMemory: ProgramMemory | Error = ProgramMemory.empty(),
idGenerator: IdGenerator = defaultIdGenerator(), idGenerator: IdGenerator = defaultIdGenerator(),
engineCommandManager: EngineCommandManager, engineCommandManager: EngineCommandManager,
@ -402,7 +403,7 @@ export const executor = async (
} }
export const _executor = async ( export const _executor = async (
node: Program, node: UnboxedNode<Program>,
programMemory: ProgramMemory | Error = ProgramMemory.empty(), programMemory: ProgramMemory | Error = ProgramMemory.empty(),
idGenerator: IdGenerator = defaultIdGenerator(), idGenerator: IdGenerator = defaultIdGenerator(),
engineCommandManager: EngineCommandManager, engineCommandManager: EngineCommandManager,
@ -493,13 +494,13 @@ export function lexer(str: string): Token[] | Error {
export const modifyAstForSketch = async ( export const modifyAstForSketch = async (
engineCommandManager: EngineCommandManager, engineCommandManager: EngineCommandManager,
ast: Program, ast: UnboxedNode<Program>,
variableName: string, variableName: string,
currentPlane: string, currentPlane: string,
engineId: string engineId: string
): Promise<Program> => { ): Promise<UnboxedNode<Program>> => {
try { try {
const updatedAst: Program = await modify_ast_for_sketch_wasm( const updatedAst: UnboxedNode<Program> = await modify_ast_for_sketch_wasm(
engineCommandManager, engineCommandManager,
JSON.stringify(ast), JSON.stringify(ast),
variableName, variableName,

3
src/lib/codeEditor.ts Normal file
View File

@ -0,0 +1,3 @@
export const normalizeLineEndings = (str: string, normalized = '\n') => {
return str.replace(/\r?\n/g, normalized)
}

View File

@ -190,10 +190,31 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
options: () => { options: () => {
return Object.entries(machineManager.machines).map( return Object.entries(machineManager.machines).map(
([_, machine]) => ({ ([_, machine]) => ({
name: `${machine.id} (${ name:
`${machine.id} (${
machine.make_model.model || machine.make_model.manufacturer machine.make_model.model || machine.make_model.manufacturer
}) via ${machineManager.machineApiIp || 'the local network'}`, }) (${machine.state.state})` +
(machine.hardware_configuration &&
machine.hardware_configuration.type !== 'none' &&
machine.hardware_configuration.config.nozzle_diameter
? ` - Nozzle Diameter: ${machine.hardware_configuration.config.nozzle_diameter}`
: '') +
(machine.hardware_configuration &&
machine.hardware_configuration.type !== 'none' &&
machine.hardware_configuration.config.filaments &&
machine.hardware_configuration.config.filaments[0]
? ` - ${
machine.hardware_configuration.config.filaments[0].name
} #${
machine.hardware_configuration.config &&
machine.hardware_configuration.config.filaments[0].color?.slice(
0,
6
)
}`
: ''),
isCurrent: false, isCurrent: false,
disabled: machine.state.state !== 'idle',
value: machine as components['schemas']['MachineInfoResponse'], value: machine as components['schemas']['MachineInfoResponse'],
}) })
) )

Some files were not shown because too many files have changed in this diff Show More