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]
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.*
- uses: actions/upload-artifact@v3
if: ${{ env.CUT_RELEASE_PR == 'true' }}
if: ${{ env.BUILD_RELEASE == 'true' }}
with:
name: out-yml
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.
```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 |
| `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

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.
```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 |
| `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

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.
```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 |
| `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

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.
```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 |
| `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

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.
```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 |
| `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

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.
```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 |
| `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

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.
```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 |
| `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

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.
```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 |
| `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

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.
```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 |
| `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

View File

@ -9,7 +9,7 @@ Construct a 2-dimensional circle, of the specified radius, centered at
the provided (x, y) origin point.
```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 |
| `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

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.
```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 |
|----------|------|-------------|----------|
| `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

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.
```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 |
| `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

View File

@ -9,7 +9,7 @@ Draw a line relative to the current origin to a specified (x, y) away
from the current position.
```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 |
| `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

View File

@ -9,7 +9,7 @@ Draw a line from the current origin to some absolute (x, y) point.
```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 |
| `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

View File

@ -9,7 +9,7 @@ Start a new profile at a given point.
```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 |
| `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

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.
```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 |
| `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

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.
```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 |
| `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

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.
```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 |
| `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

View File

@ -18,7 +18,7 @@ A base path.
|----------|------|-------------|----------|
| `from` |`[number, number]`| The from 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 |

View File

@ -22,12 +22,10 @@ layout: manual
| 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 |
| `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 |
|----------|------|-------------|----------|
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No |
| `kind` |[`Identifier`](/docs/kcl/types/Identifier)| | No |
| `start` |[`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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
| `radius` |`number`| | 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 |
| `length` |`number`| | 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 |
|----------|------|-------------|----------|
| `start` |[`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 |
| `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 |

View File

@ -23,12 +23,10 @@ An expression can be evaluated to yield a single KCL value.
| 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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
| `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 |
| `sourceRange` |`SourceRange`| The source range. | No |
@ -46,7 +46,7 @@ An extruded arc.
|----------|------|-------------|----------|
| `type` |enum: `extrudeArc`| | 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 |
| `sourceRange` |`SourceRange`| The source range. | No |
@ -66,7 +66,7 @@ Geometry metadata.
|----------|------|-------------|----------|
| `type` |enum: `chamfer`| | 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 |
| `sourceRange` |`SourceRange`| The source range. | No |
@ -86,7 +86,7 @@ Geometry metadata.
|----------|------|-------------|----------|
| `type` |enum: `fillet`| | 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 |
| `sourceRange` |`SourceRange`| The source range. | No |

View File

@ -15,10 +15,8 @@ layout: manual
| 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 |
| `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 |

View File

@ -15,8 +15,6 @@ layout: manual
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `start` |[`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

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

View File

@ -23,10 +23,9 @@ layout: manual
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No |
| `kind` |[`Identifier`](/docs/kcl/types/Identifier)| | No |
| `start` |[`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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `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 |
| `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 |
|----------|------|-------------|----------|
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | No |
| `kind` |[`Identifier`](/docs/kcl/types/Identifier)| | No |
| `start` |[`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 |
|----------|------|-------------|----------|
| `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 |

View File

@ -15,8 +15,6 @@ layout: manual
| 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 |
| `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 |
|----------|------|-------------|----------|
| `start` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `end` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| | No |
| `key` |[`Identifier`](/docs/kcl/types/Identifier)| | No |
| `key` |[`UnboxedNode_for_Identifier`](/docs/kcl/types/UnboxedNode_for_Identifier)| | 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 |

View File

@ -16,7 +16,7 @@ Parameter of a KCL function.
| 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 |
| `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 |
| `from` |`[number, number]`| The from 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 |
@ -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 |
| `from` |`[number, number]`| The from 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 |
@ -71,7 +71,7 @@ A arc that is tangential to the last path segment
| `ccw` |`boolean`| arc's direction | No |
| `from` |`[number, number]`| The from 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 |
@ -94,7 +94,7 @@ a complete arc
| `ccw` |`boolean`| arc's direction | No |
| `from` |`[number, number]`| The from 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 |
@ -115,7 +115,7 @@ A path that is horizontal.
| `x` |`number`| The x coordinate. | No |
| `from` |`[number, number]`| The from 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 |
@ -137,7 +137,7 @@ An angled line to.
| `y` |`number`| The y coordinate. | No |
| `from` |`[number, number]`| The from 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 |
@ -157,7 +157,7 @@ A base path.
| `type` |enum: `Base`| | No |
| `from` |`[number, number]`| The from 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 |

View File

@ -16,10 +16,8 @@ A KCL program top level, or function body.
| 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 |
| `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 |

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.
```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 |
| `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

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)
```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 |
| `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

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.
```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 |
| `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

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)
```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 |
| `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

View File

@ -313,3 +313,45 @@ test(
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 }
)
.toBe(431341)
.toBeGreaterThan(300_000)
// clean up output.gltf
await fsp.rm('output.gltf')
@ -179,7 +179,7 @@ test(
},
{ timeout: 15_000 }
)
.toBe(102040)
.toBeGreaterThan(100_000)
// clean up output.gltf
await fsp.rm('output.gltf')

View File

@ -1,6 +1,16 @@
import { test, expect } from '@playwright/test'
import fsp from 'fs/promises'
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) => {
await setup(context, page, testInfo)
@ -974,4 +984,84 @@ test.describe('Editor tests', () => {
|> close(%)
|> 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',
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 }
)
.toBe(431341)
.toBeGreaterThan(300_000)
// clean up 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.',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
@ -861,6 +861,12 @@ test(
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"
await expect(page.getByText('No Projects found')).toBeVisible()
@ -873,16 +879,7 @@ test(
await page.getByText('project-000').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
await u.waitForPageLoad()
await page.locator('.cm-content').fill(`sketch001 = startSketchOn('XZ')
|> startProfileAt([-87.4, 282.92], %)
@ -892,8 +889,28 @@ test(
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
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
// user way we can verify it (pixel color)
@ -901,7 +918,7 @@ extrude001 = extrude(200, sketch001)`)
.poll(() => u.getGreatestPixDiff(pointOnModel, [143, 143, 143]), {
timeout: 10_000,
})
.toBeLessThan(15)
.toBeLessThan(30)
await expect(async () => {
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.waitForTimeout(300)
await page.waitForTimeout(1000)
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
@ -528,6 +528,7 @@ test(
// Draw the rectangle
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 30)
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
await expect(page).toHaveScreenshot({
@ -895,7 +896,7 @@ test(
// Wait for the second extrusion to appear
// TODO: Find a way to truly know that the objects have finished
// rendering, because an execution-done message is not sufficient.
await page.waitForTimeout(1000)
await page.waitForTimeout(2000)
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
@ -939,7 +940,7 @@ test(
// Wait for the second extrusion to appear
// TODO: Find a way to truly know that the objects have finished
// rendering, because an execution-done message is not sufficient.
await page.waitForTimeout(1000)
await page.waitForTimeout(2000)
await expect(page).toHaveScreenshot({
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,
}
/** 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"]'
type PaneId = 'variables' | 'code' | 'files' | 'logs'
@ -463,6 +471,9 @@ export async function getUtils(page: Page, test_?: typeof test) {
return test_?.step(
`Create and select project with text "${hasText}"`,
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()
const projectLinksPost = page.getByTestId('project-link')
await projectLinksPost.filter({ hasText }).click()
@ -492,6 +503,11 @@ export async function getUtils(page: Page, test_?: typeof test) {
createNewFile: async (name: string) => {
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('file-rename-field').fill(name)
await page.keyboard.press('Enter')
@ -874,8 +890,8 @@ export async function setupElectron({
appSettings
? { settings: appSettings }
: {
...TEST_SETTINGS,
settings: {
...TEST_SETTINGS,
app: {
...TEST_SETTINGS.app,
projectDirectory: projectDirName,

View File

@ -9,7 +9,7 @@ import {
executorInputPath,
} from './test-utils'
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 {
TEST_SETTINGS_KEY,
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(
`Closing settings modal should go back to the original file being viewed`,
{ tag: '@electron' },

7
interface.d.ts vendored
View File

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

View File

@ -70,7 +70,7 @@ echo ""
echo "Suggested changelog:"
echo "\`\`\`"
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 "**Full Changelog**: https://github.com/KittyCAD/modeling-app/compare/${latest_tag}...${new_version}"
echo "\`\`\`"

View File

@ -36,38 +36,297 @@
"description": "Extra machine-specific information regarding a connected machine.",
"oneOf": [
{
"additionalProperties": false,
"properties": {
"Moonraker": {
"type": "object"
"type": {
"enum": [
"moonraker"
],
"type": "string"
}
},
"required": [
"Moonraker"
"type"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"Usb": {
"type": "object"
"type": {
"enum": [
"usb"
],
"type": "string"
}
},
"required": [
"Usb"
"type"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"Bambu": {
"type": "object"
"current_stage": {
"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": [
"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"
}
@ -85,6 +344,14 @@
"description": "Additional, per-machine information which is specific to the underlying machine type.",
"nullable": true
},
"hardware_configuration": {
"allOf": [
{
"$ref": "#/components/schemas/HardwareConfiguration"
}
],
"description": "Information about how the Machine is currently configured."
},
"id": {
"description": "Machine Identifier (ID) for the specific Machine.",
"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!",
"nullable": true
},
"progress": {
"description": "Progress of the current print, if printing.",
"format": "double",
"nullable": true,
"type": "number"
},
"state": {
"allOf": [
{
@ -124,6 +397,7 @@
}
},
"required": [
"hardware_configuration",
"id",
"machine_type",
"make_model",
@ -157,57 +431,111 @@
"oneOf": [
{
"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": {
"Failed": {
"nullable": true,
"state": {
"enum": [
"unknown"
],
"type": "string"
}
},
"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"
}
@ -219,21 +547,54 @@
{
"description": "Use light to cure a resin to build up layers.",
"enum": [
"Stereolithography"
"stereolithography"
],
"type": "string"
},
{
"description": "Fused Deposition Modeling, layers of melted plastic.",
"enum": [
"FusedDeposition"
"fused_deposition"
],
"type": "string"
},
{
"description": "\"Computer numerical control\" - machine that grinds away material from a hunk of material to construct a part.",
"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"
}
@ -284,6 +645,15 @@
"machine_id": {
"description": "The machine id to print to.",
"type": "string"
},
"slicer_configuration": {
"allOf": [
{
"$ref": "#/components/schemas/SlicerConfiguration"
}
],
"description": "Requested design-specific slicer configurations.",
"nullable": true
}
},
"required": [
@ -292,6 +662,283 @@
],
"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": {
"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": {

View File

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

View File

@ -44,6 +44,7 @@ import {
import { ActionButton } from 'components/ActionButton'
import { err, reportRejection, trap } from 'lib/trap'
import { useCommandsContext } from 'hooks/useCommandsContext'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
function useShouldHideScene(): { hideClient: boolean; hideServer: boolean } {
const [isCamMoving, setIsCamMoving] = useState(false)
@ -201,7 +202,7 @@ const Overlay = ({
let xAlignment = overlay.angle < 0 ? '0%' : '-100%'
let yAlignment = overlay.angle < -90 || overlay.angle >= 90 ? '0%' : '-100%'
const _node1 = getNodeFromPath<CallExpression>(
const _node1 = getNodeFromPath<UnboxedNode<CallExpression>>(
kclManager.ast,
overlay.pathToNode,
'CallExpression'
@ -381,7 +382,7 @@ export async function deleteSegment({
pathToNode: PathToNode
sketchDetails: SketchDetails | null
}) {
let modifiedAst: Program | Error = kclManager.ast
let modifiedAst: UnboxedNode<Program> | Error = kclManager.ast
const dependentRanges = findUsesOfTagInPipe(modifiedAst, pathToNode)
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 { Point3d } from 'wasm-lib/kcl/bindings/Point3d'
import { SegmentInputs } from 'lang/std/stdTypes'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
type DraftSegment = 'line' | 'tangentialArcTo'
@ -369,14 +370,14 @@ export class SceneEntities {
selectionRanges,
}: {
sketchPathToNode: PathToNode
maybeModdedAst: Program
maybeModdedAst: UnboxedNode<Program>
draftExpressionsIndices?: { start: number; end: number }
forward: [number, number, number]
up: [number, number, number]
position?: [number, number, number]
selectionRanges?: Selections
}): Promise<{
truncatedAst: Program
truncatedAst: UnboxedNode<Program>
programMemoryOverride: ProgramMemory
sketch: Sketch
variableDeclarationName: string
@ -561,7 +562,7 @@ export class SceneEntities {
}
updateAstAndRejigSketch = async (
sketchPathToNode: PathToNode,
modifiedAst: Program | Error,
modifiedAst: UnboxedNode<Program> | Error,
forward: [number, number, number],
up: [number, number, number],
origin: [number, number, number]
@ -1177,7 +1178,7 @@ export class SceneEntities {
}
prepareTruncatedMemoryAndAst = (
sketchPathToNode: PathToNode,
ast?: Program,
ast?: UnboxedNode<Program>,
draftSegment?: DraftSegment
) =>
prepareTruncatedMemoryAndAst(
@ -1198,7 +1199,7 @@ export class SceneEntities {
sketchPathToNode: PathToNode
intersects: Intersection<Object3D<Object3DEventMap>>[]
draftInfo?: {
truncatedAst: Program
truncatedAst: UnboxedNode<Program>
programMemoryOverride: ProgramMemory
variableDeclarationName: string
}
@ -1234,7 +1235,7 @@ export class SceneEntities {
const dragTo: [number, number] = [intersection2d.x, intersection2d.y]
let modifiedAst = draftInfo ? draftInfo.truncatedAst : { ...kclManager.ast }
const _node = getNodeFromPath<CallExpression>(
const _node = getNodeFromPath<UnboxedNode<CallExpression>>(
modifiedAst,
pathToNode,
'CallExpression'
@ -1246,7 +1247,7 @@ export class SceneEntities {
let modded:
| {
modifiedAst: Program
modifiedAst: UnboxedNode<Program>
pathToNode: PathToNode
}
| Error
@ -1541,7 +1542,7 @@ export class SceneEntities {
if (parent?.userData?.pathToNode) {
const updatedAst = parse(recast(kclManager.ast))
if (trap(updatedAst)) return
const _node = getNodeFromPath<CallExpression>(
const _node = getNodeFromPath<UnboxedNode<CallExpression>>(
updatedAst,
parent.userData.pathToNode,
'CallExpression'
@ -1676,12 +1677,12 @@ export type DefaultPlaneStr = 'XY' | 'XZ' | 'YZ' | '-XY' | '-XZ' | '-YZ'
function prepareTruncatedMemoryAndAst(
sketchPathToNode: PathToNode,
ast: Program,
ast: UnboxedNode<Program>,
programMemory: ProgramMemory,
draftSegment?: DraftSegment
):
| {
truncatedAst: Program
truncatedAst: UnboxedNode<Program>
programMemoryOverride: ProgramMemory
variableDeclarationName: string
}
@ -1689,7 +1690,7 @@ function prepareTruncatedMemoryAndAst(
const bodyIndex = Number(sketchPathToNode?.[1]?.[0]) || 0
const _ast = structuredClone(ast)
const _node = getNodeFromPath<VariableDeclaration>(
const _node = getNodeFromPath<UnboxedNode<VariableDeclaration>>(
_ast,
sketchPathToNode || [],
'VariableDeclaration'
@ -1739,15 +1740,15 @@ function prepareTruncatedMemoryAndAst(
).body.slice(-1)[0].start = lastPipeItem.start
_ast.end = lastPipeItem.end
const varDec = _ast.body[bodyIndex] as VariableDeclaration
const varDec = _ast.body[bodyIndex] as UnboxedNode<VariableDeclaration>
varDec.end = lastPipeItem.end
const declarator = varDec.declarations[0]
declarator.end = lastPipeItem.end
const init = declarator.init as PipeExpression
const init = declarator.init as UnboxedNode<PipeExpression>
init.end = lastPipeItem.end
init.body.slice(-1)[0].end = lastPipeItem.end
}
const truncatedAst: Program = {
const truncatedAst: UnboxedNode<Program> = {
..._ast,
body: [structuredClone(_ast.body[bodyIndex])],
}

View File

@ -135,7 +135,9 @@ function CommandArgOptionInput({
<Combobox.Input
id="option-input"
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"
onKeyDown={(event) => {
if (event.metaKey && event.key === 'k')
@ -175,9 +177,18 @@ function CommandArgOptionInput({
<Combobox.Option
key={option.name}
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"
>
<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 && (
<small className="text-chalkboard-70 dark:text-chalkboard-50">
current

View File

@ -2,7 +2,7 @@ import type { IndexLoaderData } from 'lib/types'
import { PATHS } from 'lib/paths'
import { ActionButton } from './ActionButton'
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 { Disclosure } from '@headlessui/react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
@ -13,7 +13,6 @@ import { sortProject } from 'lib/desktopFS'
import { FILE_EXT } from 'lib/constants'
import { CustomIcon } from './CustomIcon'
import { codeManager, kclManager } from 'lib/singletons'
import { useDocumentHasFocus } from 'hooks/useDocumentHasFocus'
import { useLspContext } from './LspProvider'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
import { useModelingContext } from 'hooks/useModelingContext'
@ -21,6 +20,8 @@ import { DeleteConfirmationDialog } from './ProjectCard/DeleteProjectDialog'
import { ContextMenu, ContextMenuItem } from './ContextMenu'
import usePlatform from 'hooks/usePlatform'
import { FileEntry } from 'lib/project'
import { useFileSystemWatcher } from 'hooks/useFileSystemWatcher'
import { normalizeLineEndings } from 'lib/codeEditor'
function getIndentationCSS(level: number) {
return `calc(1rem * ${level + 1})`
@ -131,6 +132,23 @@ const FileTreeItem = ({
const isCurrentFile = fileOrDir.path === currentFile?.path
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 removeCurrentItemFromRenaming = useCallback(
() =>
@ -154,6 +172,13 @@ const FileTreeItem = ({
})
}, [fileContext.itemsBeingRenamed, fileOrDir.path, fileSend])
const clickDirectory = () => {
fileSend({
type: 'Set selected directory',
directory: fileOrDir,
})
}
function handleKeyUp(e: React.KeyboardEvent<HTMLButtonElement>) {
if (e.metaKey && e.key === 'Backspace') {
// Open confirmation dialog
@ -242,18 +267,8 @@ const FileTreeItem = ({
}
style={{ paddingInlineStart: getIndentationCSS(level) }}
onClick={(e) => e.currentTarget.focus()}
onClickCapture={(e) =>
fileSend({
type: 'Set selected directory',
directory: fileOrDir,
})
}
onFocusCapture={(e) =>
fileSend({
type: 'Set selected directory',
directory: fileOrDir,
})
}
onClickCapture={clickDirectory}
onFocusCapture={clickDirectory}
onKeyDown={(e) => e.key === 'Enter' && e.preventDefault()}
onKeyUp={handleKeyUp}
>
@ -469,27 +484,30 @@ export const FileTreeInner = ({
const loaderData = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
const { send: fileSend, context: fileContext } = useFileContext()
const { send: modelingSend } = useModelingContext()
const documentHasFocus = useDocumentHasFocus()
// Refresh the file tree when the document gets focus
useEffect(() => {
fileSend({ type: 'Refresh' })
}, [documentHasFocus])
// Refresh the file tree when there are changes.
useFileSystemWatcher(
async (eventType, path) => {
fileSend({ type: 'Refresh' })
},
[loaderData?.project?.path, fileContext.selectedDirectory.path].filter(
(x: string | undefined) => x !== undefined
)
)
const clickDirectory = () => {
fileSend({
type: 'Set selected directory',
directory: fileContext.project,
})
}
return (
<div
className="overflow-auto pb-12 absolute inset-0"
data-testid="file-pane-scroll-container"
>
<ul
className="m-0 p-0 text-sm"
onClickCapture={(e) => {
fileSend({
type: 'Set selected directory',
directory: fileContext.project,
})
}}
>
<ul className="m-0 p-0 text-sm" onClickCapture={clickDirectory}>
{sortProject(fileContext.project?.children || []).map((fileOrDir) => (
<FileTreeItem
project={fileContext.project}

View File

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

View File

@ -11,6 +11,7 @@ export const NetworkMachineIndicator = ({
}) => {
const machineCount = machineManager.machineCount()
const reason = machineManager.noMachinesReason()
const machines = machineManager.machines
return isDesktop() ? (
<Popover className="relative">
@ -46,20 +47,34 @@ export const NetworkMachineIndicator = ({
</div>
{machineCount > 0 && (
<ul className="divide-y divide-chalkboard-20 dark:divide-chalkboard-80">
{Object.entries(machineManager.machines).map(
([hostname, machine]) => (
<li key={hostname} className={'px-2 py-4 gap-1 last:mb-0 '}>
<p className="">
{machine.make_model.model ||
machine.make_model.manufacturer ||
'Unknown Machine'}
</p>
{machines.map((machine) => {
return (
<li key={machine.id} className={'px-2 py-4 gap-1 last:mb-0 '}>
<p className="">{machine.id.toUpperCase()}</p>
<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>
</li>
)
)}
})}
</ul>
)}
</Popover.Panel>

View File

@ -221,6 +221,19 @@ export const SettingsAuthProviderBase = ({
useFileSystemWatcher(
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)
settingsSend({
type: 'Set all settings',
@ -228,7 +241,9 @@ export const SettingsAuthProviderBase = ({
doNotPersist: true,
})
},
settingsPath ? [settingsPath] : []
[settingsPath, loadedProject?.project?.path].filter(
(x: string | undefined) => x !== undefined
)
)
// Add settings commands to the command bar

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,35 +12,51 @@ type Path = string
// watcher.addListener(() => { ... }).
export const useFileSystemWatcher = (
callback: (path: Path) => Promise<void>,
dependencyArray: Path[]
callback: (eventType: string, path: Path) => Promise<void>,
paths: Path[]
): void => {
// Track a ref to the callback. This is how we get the callback updated
// across the NodeJS<->Browser boundary.
const callbackRef = useRef<{ fn: (path: Path) => Promise<void> }>({
fn: async (_path) => {},
})
// Used to track this instance of useFileSystemWatcher.
// Assign to ref so it doesn't change between renders.
const key = useRef(Math.random().toString())
const [output, setOutput] = useState<
{ eventType: string; path: string } | undefined
>(undefined)
// Used to track if paths list changes.
const [pathsTracked, setPathsTracked] = useState<Path[]>([])
useEffect(() => {
callbackRef.current.fn = callback
}, [callback])
// Used to track if dependencyArrray changes.
const [dependencyArrayTracked, setDependencyArrayTracked] = useState<Path[]>(
[]
)
if (!output) return
callback(output.eventType, output.path).catch(reportRejection)
}, [output])
// On component teardown obliterate all watchers.
useEffect(() => {
// The hook is useless on web.
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 () => {
for (let path of dependencyArray) {
window.electron.watchFileOff(path)
for (let path of pathsTracked) {
window.electron.watchFileOff(path, key.current)
}
}
}, [])
}, [pathsTracked])
function difference<T>(l1: T[], l2: T[]): [T[], T[]] {
return [
@ -49,8 +65,7 @@ export const useFileSystemWatcher = (
]
}
const hasDiff =
difference(dependencyArray, dependencyArrayTracked)[0].length !== 0
const hasDiff = difference(paths, pathsTracked)[0].length !== 0
// 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).
@ -61,19 +76,8 @@ export const useFileSystemWatcher = (
if (!hasDiff) return
const [pathsRemoved, pathsRemaining] = difference(
dependencyArrayTracked,
dependencyArray
)
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))
const [, pathsRemaining] = difference(pathsTracked, paths)
const [pathsAdded] = difference(paths, pathsTracked)
setPathsTracked(pathsRemaining.concat(pathsAdded))
}, [hasDiff])
}

View File

@ -21,9 +21,10 @@ import {
import { getNodeFromPath } from './queryAst'
import { codeManager, editorManager, sceneInfra } from 'lib/singletons'
import { Diagnostic } from '@codemirror/lint'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
interface ExecuteArgs {
ast?: Program
ast?: UnboxedNode<Program>
zoomToFit?: boolean
executionId?: number
zoomOnRangeAndType?: {
@ -33,16 +34,14 @@ interface ExecuteArgs {
}
export class KclManager {
private _ast: Program = {
private _ast: UnboxedNode<Program> = {
body: [],
start: 0,
end: 0,
nonCodeMeta: {
nonCodeNodes: {},
start: [],
digest: null,
startNodes: [],
},
digest: null,
}
private _execState: ExecState = emptyExecState()
private _programMemory: ProgramMemory = ProgramMemory.empty()
@ -57,7 +56,7 @@ export class KclManager {
engineCommandManager: EngineCommandManager
private _isExecutingCallback: (arg: boolean) => void = () => {}
private _astCallBack: (arg: Program) => void = () => {}
private _astCallBack: (arg: UnboxedNode<Program>) => void = () => {}
private _programMemoryCallBack: (arg: ProgramMemory) => void = () => {}
private _logsCallBack: (arg: string[]) => void = () => {}
private _kclErrorsCallBack: (arg: KCLError[]) => void = () => {}
@ -183,7 +182,7 @@ export class KclManager {
setWasmInitFailed,
}: {
setProgramMemory: (arg: ProgramMemory) => void
setAst: (arg: Program) => void
setAst: (arg: UnboxedNode<Program>) => void
setLogs: (arg: string[]) => void
setKclErrors: (arg: KCLError[]) => void
setIsExecuting: (arg: boolean) => void
@ -207,14 +206,12 @@ export class KclManager {
end: 0,
nonCodeMeta: {
nonCodeNodes: {},
start: [],
digest: null,
startNodes: [],
},
digest: null,
}
}
safeParse(code: string): Program | null {
safeParse(code: string): UnboxedNode<Program> | null {
const ast = parse(code)
this.lints = []
this.kclErrors = []
@ -381,7 +378,7 @@ export class KclManager {
Array.from(this.engineCommandManager.artifactGraph).forEach(
([commandId, artifact]) => {
if (!('codeRef' in artifact)) return
const _node1 = getNodeFromPath<CallExpression>(
const _node1 = getNodeFromPath<UnboxedNode<CallExpression>>(
this.ast,
artifact.codeRef.pathToNode,
'CallExpression'
@ -445,7 +442,7 @@ export class KclManager {
// 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.
async updateAst(
ast: Program,
ast: UnboxedNode<Program>,
execute: boolean,
optionalParams?: {
focusPath?: Array<PathToNode>
@ -456,7 +453,7 @@ export class KclManager {
}
}
): Promise<{
newAst: Program
newAst: UnboxedNode<Program>
selections?: Selections
}> {
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
_isAstEmpty(ast: Program) {
_isAstEmpty(ast: UnboxedNode<Program>) {
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,
type: 'TagDeclarator',
value: 'p',
digest: null,
},
id: expect.any(String),
sourceRange: [95, 117],
@ -223,7 +222,6 @@ const sk2 = startSketchOn('XY')
start: 114,
type: 'TagDeclarator',
value: 'p',
digest: null,
},
__geoMeta: {
id: expect.any(String),
@ -266,7 +264,6 @@ const sk2 = startSketchOn('XY')
start: 417,
type: 'TagDeclarator',
value: 'o',
digest: null,
},
id: expect.any(String),
sourceRange: [399, 420],
@ -317,7 +314,6 @@ const sk2 = startSketchOn('XY')
start: 417,
type: 'TagDeclarator',
value: 'o',
digest: null,
},
__geoMeta: {
id: expect.any(String),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,7 +18,7 @@ class FileSystemManager {
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.
if (!isDesktop()) {
return Promise.reject(

View File

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

View File

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

View File

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

View File

@ -11,16 +11,17 @@ import {
BinaryPart,
} from '../wasm'
import { LineInputsType } from './sketchcombos'
import { UnboxedNode } from 'wasm-lib/kcl/bindings/UnboxedNode'
export interface ModifyAstBase {
node: Program
node: UnboxedNode<Program>
// TODO #896: Remove ProgramMemory from this interface
previousProgramMemory: ProgramMemory
pathToNode: PathToNode
}
export interface AddTagInfo {
node: Program
node: UnboxedNode<Program>
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
* {@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
@ -142,7 +143,7 @@ export type InputArg = _InputArg<Expr>
* 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
*/
type RawArg = _InputArg<Literal>
type RawArg = _InputArg<UnboxedNode<Literal>>
export type InputArgs = Array<InputArg>
@ -186,7 +187,7 @@ export type CreateStdLibSketchCallExpr = (args: {
inputs: InputArgs
rawArgs: RawArgs
referenceSegName: string
tag?: Expr
tag?: UnboxedNode<Expr>
forceValueUsedInTransform?: BinaryPart
referencedSegment?: Path
}) => CreatedSketchExprResult | Error
@ -215,26 +216,26 @@ export interface ConstrainInfo {
export interface SketchLineHelper {
add: (a: addCall) =>
| {
modifiedAst: Program
modifiedAst: UnboxedNode<Program>
pathToNode: PathToNode
valueUsedInTransform?: number
}
| Error
updateArgs: (a: updateArgs) =>
| {
modifiedAst: Program
modifiedAst: UnboxedNode<Program>
pathToNode: PathToNode
}
| Error
getTag: (a: CallExpression) => string | Error
addTag: (a: AddTagInfo) =>
| {
modifiedAst: Program
modifiedAst: UnboxedNode<Program>
tag: string
}
| Error
getConstraintInfo: (
callExp: CallExpression,
callExp: UnboxedNode<CallExpression>,
code: string,
pathToNode: PathToNode
) => 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 { EnvironmentRef } from '../wasm-lib/kcl/bindings/EnvironmentRef'
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 { Expr } from '../wasm-lib/kcl/bindings/Expr'
@ -122,11 +123,11 @@ export const initPromise = initialise()
export const rangeTypeFix = (ranges: number[][]): [number, number][] =>
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
try {
const program: Program = parse_wasm(code)
const program: UnboxedNode<Program> = parse_wasm(code)
return program
} catch (e: any) {
// throw e
@ -378,7 +379,7 @@ export function sketchFromKclValue(
}
export const executor = async (
node: Program,
node: UnboxedNode<Program>,
programMemory: ProgramMemory | Error = ProgramMemory.empty(),
idGenerator: IdGenerator = defaultIdGenerator(),
engineCommandManager: EngineCommandManager,
@ -402,7 +403,7 @@ export const executor = async (
}
export const _executor = async (
node: Program,
node: UnboxedNode<Program>,
programMemory: ProgramMemory | Error = ProgramMemory.empty(),
idGenerator: IdGenerator = defaultIdGenerator(),
engineCommandManager: EngineCommandManager,
@ -493,13 +494,13 @@ export function lexer(str: string): Token[] | Error {
export const modifyAstForSketch = async (
engineCommandManager: EngineCommandManager,
ast: Program,
ast: UnboxedNode<Program>,
variableName: string,
currentPlane: string,
engineId: string
): Promise<Program> => {
): Promise<UnboxedNode<Program>> => {
try {
const updatedAst: Program = await modify_ast_for_sketch_wasm(
const updatedAst: UnboxedNode<Program> = await modify_ast_for_sketch_wasm(
engineCommandManager,
JSON.stringify(ast),
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: () => {
return Object.entries(machineManager.machines).map(
([_, machine]) => ({
name: `${machine.id} (${
machine.make_model.model || machine.make_model.manufacturer
}) via ${machineManager.machineApiIp || 'the local network'}`,
name:
`${machine.id} (${
machine.make_model.model || machine.make_model.manufacturer
}) (${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,
disabled: machine.state.state !== 'idle',
value: machine as components['schemas']['MachineInfoResponse'],
})
)

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