Compare commits
34 Commits
achalmers/
...
kcl-0.2.28
Author | SHA1 | Date | |
---|---|---|---|
f876e6ca3c | |||
60a0c811ab | |||
cab0c1e6a1 | |||
417d720b22 | |||
77293952c0 | |||
ea3d604b73 | |||
023a659491 | |||
dd3a2b14f9 | |||
424b409cc1 | |||
82a58e69c2 | |||
776b420031 | |||
1087d4223b | |||
089d6df889 | |||
efb067af58 | |||
2aa27eab01 | |||
9c47ac5b57 | |||
5ae1aecd74 | |||
68ae7e98f9 | |||
56771d561a | |||
f09411817c | |||
bed7ae3b8b | |||
c43510732c | |||
51f0b669a4 | |||
3cbedcd3e7 | |||
5d2fa43150 | |||
ec49b0752e | |||
3b171fb881 | |||
0548409da0 | |||
dd052b35fd | |||
46be4e7eef | |||
412d1b7a99 | |||
cfdd22af74 | |||
68a11e7aa5 | |||
3139e18dc7 |
17
.github/workflows/build-apps.yml
vendored
@ -383,12 +383,13 @@ jobs:
|
|||||||
parent: false
|
parent: false
|
||||||
destination: 'dl.kittycad.io/releases/modeling-app/nightly'
|
destination: 'dl.kittycad.io/releases/modeling-app/nightly'
|
||||||
|
|
||||||
- name: Create draft release
|
- name: Tag nightly commit
|
||||||
uses: softprops/action-gh-release@v2
|
if: ${{ env.IS_NIGHTLY == 'true' }}
|
||||||
if: ${{ env.IS_RELEASE == 'true' }}
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
name: ${{ env.VERSION }}
|
script: |
|
||||||
tag_name: ${{ env.VERSION }}
|
const { VERSION } = process.env
|
||||||
draft: true
|
const { owner, repo } = context.repo
|
||||||
generate_release_notes: true
|
const { sha } = context
|
||||||
files: 'out/Zoo*'
|
const ref = `refs/tags/nightly-${VERSION}`
|
||||||
|
github.rest.git.createRef({ owner, repo, sha, ref })
|
||||||
|
4
.github/workflows/e2e-tests.yml
vendored
@ -68,7 +68,7 @@ jobs:
|
|||||||
- name: Download Wasm Cache
|
- name: Download Wasm Cache
|
||||||
id: download-wasm
|
id: download-wasm
|
||||||
if: needs.check-rust-changes.outputs.rust-changed == 'false'
|
if: needs.check-rust-changes.outputs.rust-changed == 'false'
|
||||||
uses: dawidd6/action-download-artifact@v6
|
uses: dawidd6/action-download-artifact@v7
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||||
@ -255,7 +255,7 @@ jobs:
|
|||||||
- name: Download Wasm Cache
|
- name: Download Wasm Cache
|
||||||
id: download-wasm
|
id: download-wasm
|
||||||
if: needs.check-rust-changes.outputs.rust-changed == 'false'
|
if: needs.check-rust-changes.outputs.rust-changed == 'false'
|
||||||
uses: dawidd6/action-download-artifact@v6
|
uses: dawidd6/action-download-artifact@v7
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
6
.github/workflows/publish-apps-release.yml
vendored
@ -132,6 +132,12 @@ jobs:
|
|||||||
gcloud compute url-maps invalidate-cdn-cache dl-url-map --path="/releases/modeling-app/latest-mac.yml" --async
|
gcloud compute url-maps invalidate-cdn-cache dl-url-map --path="/releases/modeling-app/latest-mac.yml" --async
|
||||||
gcloud compute url-maps invalidate-cdn-cache dl-url-map --path="/releases/modeling-app/latest.yml" --async
|
gcloud compute url-maps invalidate-cdn-cache dl-url-map --path="/releases/modeling-app/latest.yml" --async
|
||||||
|
|
||||||
|
- name: Upload release files to Github
|
||||||
|
if: ${{ github.event_name == 'release' }}
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: 'out/Zoo*'
|
||||||
|
|
||||||
|
|
||||||
announce_release:
|
announce_release:
|
||||||
needs: [publish-apps-release]
|
needs: [publish-apps-release]
|
||||||
|
20
README.md
@ -136,7 +136,7 @@ https://github.com/KittyCAD/modeling-app/issues/new
|
|||||||
|
|
||||||
#### 2. Push a new tag
|
#### 2. Push a new tag
|
||||||
|
|
||||||
Create a new tag and push it to the repo (eg. `v0.28.0` for `$VERSION`)
|
Create a new tag and push it to the repo. The `semantic-release.sh` script will automatically bump the minor part, which we use the most. For instance going from `v0.27.0` to `v0.28.0`.
|
||||||
|
|
||||||
```
|
```
|
||||||
VERSION=$(./scripts/semantic-release.sh)
|
VERSION=$(./scripts/semantic-release.sh)
|
||||||
@ -146,16 +146,14 @@ git push origin --tags
|
|||||||
|
|
||||||
This will trigger the `build-apps` workflow, set the version, build & sign the apps, and generate release files as well as updater-test artifacts.
|
This will trigger the `build-apps` workflow, set the version, build & sign the apps, and generate release files as well as updater-test artifacts.
|
||||||
|
|
||||||
Once the workflow succeeds, a draft release will be created at https://github.com/KittyCAD/modeling-app/releases.
|
The workflow should be listed right away [in this list](https://github.com/KittyCAD/modeling-app/actions/workflows/build-apps.yml?query=event%3Apush)).
|
||||||
|
|
||||||
#### 3. Manually test artifacts from the Cut Release PR
|
#### 3. Manually test artifacts
|
||||||
|
|
||||||
##### Release builds
|
##### Release builds
|
||||||
|
|
||||||
The release builds can be found under the `out-{arch}-{platform}` zip files, at the very bottom of the `build-apps` summary page for the workflow (triggered by the tag in 2.).
|
The release builds can be found under the `out-{arch}-{platform}` zip files, at the very bottom of the `build-apps` summary page for the workflow (triggered by the tag in 2.).
|
||||||
|
|
||||||
Alternatively, the draft release will also include these builds.
|
|
||||||
|
|
||||||
Manually test against this [list](https://github.com/KittyCAD/modeling-app/issues/3588) across Windows, MacOS, Linux and posting results as comments in the issue.
|
Manually test against this [list](https://github.com/KittyCAD/modeling-app/issues/3588) across Windows, MacOS, Linux and posting results as comments in the issue.
|
||||||
|
|
||||||
##### Updater-test builds
|
##### Updater-test builds
|
||||||
@ -178,9 +176,11 @@ If the prompt doesn't show up, start the app in command line to grab the electro
|
|||||||
|
|
||||||
#### 4. Publish the release
|
#### 4. Publish the release
|
||||||
|
|
||||||
Head over to https://github.com/KittyCAD/modeling-app/releases, paste in the changelog discussed in the issue, and publish the draft release created by the `build-apps` workflow from step 2.
|
Head over to https://github.com/KittyCAD/modeling-app/releases/new, pick the newly created tag and type it in the _Release title_ field as well.
|
||||||
|
|
||||||
A new Action kicks in at https://github.com/KittyCAD/modeling-app/actions, which can be found under `release` event filter. On success, the files will be uploaded to the public bucket and the announcement on Discord will be sent.
|
Hit _Generate release notes_ as a starting point to discuss the changelog in the issue. Once done, make sure _Set as the latest release_ is checked, and hit _Publish release_.
|
||||||
|
|
||||||
|
A new `publish-apps-release` will kick in and you should be able to find it [here](https://github.com/KittyCAD/modeling-app/actions?query=event%3Arelease). On success, the files will be uploaded to the public bucket as well as to the GitHub release, and the announcement on Discord will be sent.
|
||||||
|
|
||||||
#### 5. Close the issue
|
#### 5. Close the issue
|
||||||
|
|
||||||
@ -450,3 +450,9 @@ PS: for the debug panel, the following JSON is useful for snapping the camera
|
|||||||
## KCL
|
## KCL
|
||||||
|
|
||||||
For how to contribute to KCL, [see our KCL README](https://github.com/KittyCAD/modeling-app/tree/main/src/wasm-lib/kcl).
|
For how to contribute to KCL, [see our KCL README](https://github.com/KittyCAD/modeling-app/tree/main/src/wasm-lib/kcl).
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
|
||||||
|
To display logging (to the terminal or console) set `ZOO_LOG=1`. This will log some warnings and simple performance metrics. To view these in test runs, use `-- --nocapture`.
|
||||||
|
|
||||||
|
To enable memory metrics, build with `--features dhat-heap`.
|
||||||
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 259 KiB |
BIN
assets/icon.ico
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 114 KiB |
BIN
assets/icon.png
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
@ -58,7 +58,7 @@ mountingPlate = extrude(thickness, mountingPlateSketch)
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
// Sketch on the face of a chamfer.
|
// Sketch on the face of a chamfer.
|
||||||
fn cube = (pos, scale) => {
|
fn cube(pos, scale) {
|
||||||
sg = startSketchOn('XY')
|
sg = startSketchOn('XY')
|
||||||
|> startProfileAt(pos, %)
|
|> startProfileAt(pos, %)
|
||||||
|> line([0, scale], %)
|
|> line([0, scale], %)
|
||||||
|
@ -37,7 +37,7 @@ assertEqual(n, 3, 0.0001, "5/2 = 2.5, rounded up makes 3")
|
|||||||
startSketchOn('XZ')
|
startSketchOn('XZ')
|
||||||
|> circle({ center = [0, 0], radius = 2 }, %)
|
|> circle({ center = [0, 0], radius = 2 }, %)
|
||||||
|> extrude(5, %)
|
|> extrude(5, %)
|
||||||
|> patternTransform(n, (id) => {
|
|> patternTransform(n, fn(id) {
|
||||||
return { translate = [4 * id, 0, 0] }
|
return { translate = [4 * id, 0, 0] }
|
||||||
}, %)
|
}, %)
|
||||||
```
|
```
|
||||||
|
@ -29,7 +29,7 @@ map(array: [KclValue], map_fn: FunctionParam) -> [KclValue]
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
r = 10 // radius
|
r = 10 // radius
|
||||||
fn drawCircle = (id) => {
|
fn drawCircle(id) {
|
||||||
return startSketchOn("XY")
|
return startSketchOn("XY")
|
||||||
|> circle({ center = [id * 2 * r, 0], radius = r }, %)
|
|> circle({ center = [id * 2 * r, 0], radius = r }, %)
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ circles = map([1..3], drawCircle)
|
|||||||
```js
|
```js
|
||||||
r = 10 // radius
|
r = 10 // radius
|
||||||
// Call `map`, using an anonymous function instead of a named one.
|
// Call `map`, using an anonymous function instead of a named one.
|
||||||
circles = map([1..3], (id) => {
|
circles = map([1..3], (id) {
|
||||||
return startSketchOn("XY")
|
return startSketchOn("XY")
|
||||||
|> circle({ center = [id * 2 * r, 0], radius = r }, %)
|
|> circle({ center = [id * 2 * r, 0], radius = r }, %)
|
||||||
})
|
})
|
||||||
|
@ -12,7 +12,7 @@ to other modules.
|
|||||||
|
|
||||||
```
|
```
|
||||||
// util.kcl
|
// util.kcl
|
||||||
export fn increment = (x) => {
|
export fn increment(x) {
|
||||||
return x + 1
|
return x + 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -37,11 +37,11 @@ Multiple functions can be exported in a file.
|
|||||||
|
|
||||||
```
|
```
|
||||||
// util.kcl
|
// util.kcl
|
||||||
export fn increment = (x) => {
|
export fn increment(x) {
|
||||||
return x + 1
|
return x + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn decrement = (x) => {
|
export fn decrement(x) {
|
||||||
return x - 1
|
return x - 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -30,7 +30,7 @@ patternTransform2d(total_instances: u32, transform_function: FunctionParam, soli
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
// Each instance will be shifted along the X axis.
|
// Each instance will be shifted along the X axis.
|
||||||
fn transform = (id) => {
|
fn transform(id) {
|
||||||
return { translate = [4 * id, 0] }
|
return { translate = [4 * id, 0] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,14 +30,14 @@ reduce(array: [KclValue], start: KclValue, reduce_fn: FunctionParam) -> KclValue
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
// This function adds two numbers.
|
// This function adds two numbers.
|
||||||
fn add = (a, b) => {
|
fn add(a, b) {
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function adds an array of numbers.
|
// This function adds an array of numbers.
|
||||||
// It uses the `reduce` function, to call the `add` function on every
|
// It uses the `reduce` function, to call the `add` function on every
|
||||||
// element of the `arr` parameter. The starting value is 0.
|
// element of the `arr` parameter. The starting value is 0.
|
||||||
fn sum = (arr) => {
|
fn sum(arr) {
|
||||||
return reduce(arr, 0, add)
|
return reduce(arr, 0, add)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ assertEqual(sum([1, 2, 3]), 6, 0.00001, "1 + 2 + 3 summed is 6")
|
|||||||
// an anonymous `add` function as its parameter, instead of declaring a
|
// an anonymous `add` function as its parameter, instead of declaring a
|
||||||
// named function outside.
|
// named function outside.
|
||||||
arr = [1, 2, 3]
|
arr = [1, 2, 3]
|
||||||
sum = reduce(arr, 0, (i, result_so_far) => {
|
sum = reduce(arr, 0, (i, result_so_far) {
|
||||||
return i + result_so_far
|
return i + result_so_far
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ assertEqual(sum, 6, 0.00001, "1 + 2 + 3 summed is 6")
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
// Declare a function that sketches a decagon.
|
// Declare a function that sketches a decagon.
|
||||||
fn decagon = (radius) => {
|
fn decagon(radius) {
|
||||||
// Each side of the decagon is turned this many degrees from the previous angle.
|
// Each side of the decagon is turned this many degrees from the previous angle.
|
||||||
stepAngle = 1 / 10 * tau()
|
stepAngle = 1 / 10 * tau()
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ fn decagon = (radius) => {
|
|||||||
// Use a `reduce` to draw the remaining decagon sides.
|
// Use a `reduce` to draw the remaining decagon sides.
|
||||||
// For each number in the array 1..10, run the given function,
|
// For each number in the array 1..10, run the given function,
|
||||||
// which takes a partially-sketched decagon and adds one more edge to it.
|
// which takes a partially-sketched decagon and adds one more edge to it.
|
||||||
fullDecagon = reduce([1..10], startOfDecagonSketch, (i, partialDecagon) => {
|
fullDecagon = reduce([1..10], startOfDecagonSketch, (i, partialDecagon) {
|
||||||
// Draw one edge of the decagon.
|
// Draw one edge of the decagon.
|
||||||
x = cos(stepAngle * i) * radius
|
x = cos(stepAngle * i) * radius
|
||||||
y = sin(stepAngle * i) * radius
|
y = sin(stepAngle * i) * radius
|
||||||
|
@ -36,7 +36,7 @@ cube = startSketchAt([0, 0])
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(5, %)
|
|> extrude(5, %)
|
||||||
|
|
||||||
fn cylinder = (radius, tag) => {
|
fn cylinder(radius, tag) {
|
||||||
return startSketchAt([0, 0])
|
return startSketchAt([0, 0])
|
||||||
|> circle({
|
|> circle({
|
||||||
radius = radius,
|
radius = radius,
|
||||||
|
@ -36,7 +36,7 @@ cube = startSketchAt([0, 0])
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(5, %)
|
|> extrude(5, %)
|
||||||
|
|
||||||
fn cylinder = (radius, tag) => {
|
fn cylinder(radius, tag) {
|
||||||
return startSketchAt([0, 0])
|
return startSketchAt([0, 0])
|
||||||
|> circle({
|
|> circle({
|
||||||
radius = radius,
|
radius = radius,
|
||||||
|
20030
docs/kcl/std.json
@ -41,7 +41,7 @@ If you want to get a value from an array you can use the index like so:
|
|||||||
An object is defined with `{}` braces. Here is an example object:
|
An object is defined with `{}` braces. Here is an example object:
|
||||||
|
|
||||||
```
|
```
|
||||||
myObj = {a: 0, b: "thing"}
|
myObj = { a = 0, b = "thing" }
|
||||||
```
|
```
|
||||||
|
|
||||||
We support two different ways of getting properties from objects, you can call
|
We support two different ways of getting properties from objects, you can call
|
||||||
@ -54,7 +54,7 @@ We also have support for defining your own functions. Functions can take in any
|
|||||||
type of argument. Below is an example of the syntax:
|
type of argument. Below is an example of the syntax:
|
||||||
|
|
||||||
```
|
```
|
||||||
fn myFn = (x) => {
|
fn myFn(x) {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -90,12 +90,12 @@ startSketchOn('XZ')
|
|||||||
|> startProfileAt(origin, %)
|
|> startProfileAt(origin, %)
|
||||||
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|
||||||
|> angledLine([
|
|> angledLine([
|
||||||
segAng(rectangleSegmentA001, %) - 90,
|
segAng(rectangleSegmentA001) - 90,
|
||||||
196.99
|
196.99
|
||||||
], %, $rectangleSegmentB001)
|
], %, $rectangleSegmentB001)
|
||||||
|> angledLine([
|
|> angledLine([
|
||||||
segAng(rectangleSegmentA001, %),
|
segAng(rectangleSegmentA001),
|
||||||
-segLen(rectangleSegmentA001, %)
|
-segLen(rectangleSegmentA001)
|
||||||
], %, $rectangleSegmentC001)
|
], %, $rectangleSegmentC001)
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
@ -118,17 +118,17 @@ use the tag `rectangleSegmentA001` in any function or expression in the file.
|
|||||||
However if the code was written like this:
|
However if the code was written like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
fn rect = (origin) => {
|
fn rect(origin) {
|
||||||
return startSketchOn('XZ')
|
return startSketchOn('XZ')
|
||||||
|> startProfileAt(origin, %)
|
|> startProfileAt(origin, %)
|
||||||
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|
||||||
|> angledLine([
|
|> angledLine([
|
||||||
segAng(rectangleSegmentA001, %) - 90,
|
segAng(rectangleSegmentA001) - 90,
|
||||||
196.99
|
196.99
|
||||||
], %, $rectangleSegmentB001)
|
], %, $rectangleSegmentB001)
|
||||||
|> angledLine([
|
|> angledLine([
|
||||||
segAng(rectangleSegmentA001, %),
|
segAng(rectangleSegmentA001),
|
||||||
-segLen(rectangleSegmentA001, %)
|
-segLen(rectangleSegmentA001)
|
||||||
], %, $rectangleSegmentC001)
|
], %, $rectangleSegmentC001)
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
@ -146,17 +146,17 @@ Tags are accessible through the sketch group they are declared in.
|
|||||||
For example the following code works.
|
For example the following code works.
|
||||||
|
|
||||||
```
|
```
|
||||||
fn rect = (origin) => {
|
fn rect(origin) {
|
||||||
return startSketchOn('XZ')
|
return startSketchOn('XZ')
|
||||||
|> startProfileAt(origin, %)
|
|> startProfileAt(origin, %)
|
||||||
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|
||||||
|> angledLine([
|
|> angledLine([
|
||||||
segAng(rectangleSegmentA001, %) - 90,
|
segAng(rectangleSegmentA001) - 90,
|
||||||
196.99
|
196.99
|
||||||
], %, $rectangleSegmentB001)
|
], %, $rectangleSegmentB001)
|
||||||
|> angledLine([
|
|> angledLine([
|
||||||
segAng(rectangleSegmentA001, %),
|
segAng(rectangleSegmentA001),
|
||||||
-segLen(rectangleSegmentA001, %)
|
-segLen(rectangleSegmentA001)
|
||||||
], %, $rectangleSegmentC001)
|
], %, $rectangleSegmentC001)
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
@ -167,7 +167,10 @@ myRect = rect([20, 0])
|
|||||||
|
|
||||||
myRect
|
myRect
|
||||||
|> extrude(10, %)
|
|> extrude(10, %)
|
||||||
|> fillet({radius: 0.5, tags: [myRect.tags.rectangleSegmentA001]}, %)
|
|> fillet({
|
||||||
|
radius = 0.5,
|
||||||
|
tags = [myRect.tags.rectangleSegmentA001]
|
||||||
|
}, %)
|
||||||
```
|
```
|
||||||
|
|
||||||
See how we use the tag `rectangleSegmentA001` in the `fillet` function outside
|
See how we use the tag `rectangleSegmentA001` in the `fillet` function outside
|
||||||
|
@ -1,161 +0,0 @@
|
|||||||
---
|
|
||||||
title: "BinaryOperator"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
Add two numbers.
|
|
||||||
|
|
||||||
**enum:** `+`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Subtract two numbers.
|
|
||||||
|
|
||||||
**enum:** `-`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Multiply two numbers.
|
|
||||||
|
|
||||||
**enum:** `*`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Divide two numbers.
|
|
||||||
|
|
||||||
**enum:** `/`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Modulo two numbers.
|
|
||||||
|
|
||||||
**enum:** `%`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Raise a number to a power.
|
|
||||||
|
|
||||||
**enum:** `^`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Are two numbers equal?
|
|
||||||
|
|
||||||
**enum:** `==`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Are two numbers not equal?
|
|
||||||
|
|
||||||
**enum:** `!=`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Is left greater than right
|
|
||||||
|
|
||||||
**enum:** `>`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Is left greater than or equal to right
|
|
||||||
|
|
||||||
**enum:** `>=`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Is left less than right
|
|
||||||
|
|
||||||
**enum:** `<`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Is left less than or equal to right
|
|
||||||
|
|
||||||
**enum:** `<=`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
|||||||
---
|
|
||||||
title: "BinaryPart"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `Literal`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `BinaryExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `CallExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `UnaryExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `MemberExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `IfExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
|||||||
---
|
|
||||||
title: "BodyItem"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ImportStatement`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ExpressionStatement`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `VariableDeclaration`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ReturnStatement`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
|||||||
---
|
|
||||||
title: "CommentStyle"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
Like // foo
|
|
||||||
|
|
||||||
**enum:** `line`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Like /* foo */
|
|
||||||
|
|
||||||
**enum:** `block`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: "ElseIf"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `cond` |[`Expr`](/docs/kcl/types/Expr)| | No |
|
|
||||||
| `then_val` |[`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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
title: "EnvironmentRef"
|
|
||||||
excerpt: "An index pointing to an environment."
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
An index pointing to an environment.
|
|
||||||
|
|
||||||
**Type:** `integer` (`uint`)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,318 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Expr"
|
|
||||||
excerpt: "An expression can be evaluated to yield a single KCL value."
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
An expression can be evaluated to yield a single KCL value.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `Literal`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`TagDeclarator`](/docs/kcl/types#tag-declaration)| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `BinaryExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`FunctionExpression`](/docs/kcl/types/FunctionExpression)| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `CallExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `PipeExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `PipeSubstitution`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ArrayExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ArrayRangeExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `ObjectExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `MemberExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `UnaryExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `IfExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
KCL value for an optional parameter which was not given an argument. (remember, parameters are in the function declaration, arguments are in the function call/application).
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `None`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: "FunctionExpression"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `params` |`[` [`Parameter`](/docs/kcl/types/Parameter) `]`| | No |
|
|
||||||
| `body` |[`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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Identifier"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: "ImportItem"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| 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 |
|
|
||||||
| `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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
title: "ItemVisibility"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**enum:** `default`, `export`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -317,7 +317,6 @@ Data for an imported geometry.
|
|||||||
| Property | Type | Description | Required |
|
| Property | Type | Description | Required |
|
||||||
|----------|------|-------------|----------|
|
|----------|------|-------------|----------|
|
||||||
| `type` |enum: `Function`| | No |
|
| `type` |enum: `Function`| | No |
|
||||||
| `expression` |[`FunctionExpression`](/docs/kcl/types/FunctionExpression)| Any KCL value. | No |
|
|
||||||
| `memory` |[`ProgramMemory`](/docs/kcl/types/ProgramMemory)| Any KCL value. | No |
|
| `memory` |[`ProgramMemory`](/docs/kcl/types/ProgramMemory)| Any KCL value. | No |
|
||||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
|
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
|
||||||
|
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
---
|
|
||||||
title: "LiteralIdentifier"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `Literal`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
---
|
|
||||||
title: "LiteralValue"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts any of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `number` (`double`)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `string`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `boolean`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
|||||||
---
|
|
||||||
title: "MemberObject"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `MemberExpression`| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: [`Identifier`](/docs/kcl/types/Identifier)| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
---
|
|
||||||
title: "NonCodeMeta"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `nonCodeNodes` |`object`| | No |
|
|
||||||
| `startNodes` |`[` [`NonCodeNode`](/docs/kcl/types/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 |
|
|
||||||
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
title: "NonCodeNode"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
|||||||
---
|
|
||||||
title: "NonCodeValue"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
An inline comment. Here are examples: `1 + 1 // This is an inline comment`. `1 + 1 /* Here's another */`.
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `inlineComment`| | No |
|
|
||||||
| `value` |`string`| | No |
|
|
||||||
| `style` |[`CommentStyle`](/docs/kcl/types/CommentStyle)| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
A block comment. An example of this is the following: ```python,no_run /* This is a block comment */ 1 + 1 ``` Now this is important. The block comment is attached to the next line. This is always the case. Also the block comment doesn't have a new line above it. If it did it would be a `NewLineBlockComment`.
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `blockComment`| | No |
|
|
||||||
| `value` |`string`| | No |
|
|
||||||
| `style` |[`CommentStyle`](/docs/kcl/types/CommentStyle)| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
A block comment that has a new line above it. The user explicitly added a new line above the block comment.
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `newLineBlockComment`| | No |
|
|
||||||
| `value` |`string`| | No |
|
|
||||||
| `style` |[`CommentStyle`](/docs/kcl/types/CommentStyle)| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `type` |enum: `newLine`| | No |
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: "ObjectProperty"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `key` |[`Identifier`](/docs/kcl/types/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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Parameter"
|
|
||||||
excerpt: "Parameter of a KCL function."
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
Parameter of a KCL function.
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `identifier` |[`Identifier`](/docs/kcl/types/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 |
|
|
||||||
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Program"
|
|
||||||
excerpt: "A KCL program top level, or function body."
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
A KCL program top level, or function body.
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `body` |`[` [`BodyItem`](/docs/kcl/types/BodyItem) `]`| | No |
|
|
||||||
| `nonCodeMeta` |[`NonCodeMeta`](/docs/kcl/types/NonCodeMeta)| A KCL program top level, or function body. | No |
|
|
||||||
| `shebang` |[`Shebang`](/docs/kcl/types/Shebang)| | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Shebang"
|
|
||||||
excerpt: "A shebang. This is a special type of comment that is at the top of the file. It looks like this: ```python,no_run #!/usr/bin/env python ```"
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
A shebang. This is a special type of comment that is at the top of the file. It looks like this: ```python,no_run #!/usr/bin/env python ```
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `content` |`string`| | No |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Uint"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `integer` (`uint32`)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
|||||||
---
|
|
||||||
title: "UnaryOperator"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
Negate a number.
|
|
||||||
|
|
||||||
**enum:** `-`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Negate a boolean.
|
|
||||||
|
|
||||||
**enum:** `!`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: "VariableDeclarator"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
**Type:** `object`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description | Required |
|
|
||||||
|----------|------|-------------|----------|
|
|
||||||
| `id` |[`Identifier`](/docs/kcl/types/Identifier)| The identifier of the variable. | No |
|
|
||||||
| `init` |[`Expr`](/docs/kcl/types/Expr)| The value of the variable. | 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 |
|
|
||||||
| `start` |`integer`| | No |
|
|
||||||
| `end` |`integer`| | No |
|
|
||||||
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
|||||||
---
|
|
||||||
title: "VariableKind"
|
|
||||||
excerpt: ""
|
|
||||||
layout: manual
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**This schema accepts exactly one of the following:**
|
|
||||||
|
|
||||||
Declare a named constant.
|
|
||||||
|
|
||||||
**enum:** `const`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
Declare a function.
|
|
||||||
|
|
||||||
**enum:** `fn`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -45,7 +45,6 @@ test.describe('integrations tests', () => {
|
|||||||
{
|
{
|
||||||
title: 'test-sample',
|
title: 'test-sample',
|
||||||
fileCount: 1,
|
fileCount: 1,
|
||||||
folderCount: 1,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
sortBy: 'last-modified-desc',
|
sortBy: 'last-modified-desc',
|
||||||
@ -233,7 +232,6 @@ test.describe('when using the file tree to', () => {
|
|||||||
{
|
{
|
||||||
title: projectName,
|
title: projectName,
|
||||||
fileCount: 2,
|
fileCount: 2,
|
||||||
folderCount: 2, // TODO: This is a pre-existing bug, there are no folders within the project
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
sortBy: 'last-modified-desc',
|
sortBy: 'last-modified-desc',
|
||||||
|
@ -4,7 +4,6 @@ import { expect } from '@playwright/test'
|
|||||||
interface ProjectCardState {
|
interface ProjectCardState {
|
||||||
title: string
|
title: string
|
||||||
fileCount: number
|
fileCount: number
|
||||||
folderCount: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HomePageState {
|
interface HomePageState {
|
||||||
@ -61,15 +60,13 @@ export class HomePageFixture {
|
|||||||
const projectCards = await this.projectCard.all()
|
const projectCards = await this.projectCard.all()
|
||||||
const projectCardStates: Array<ProjectCardState> = []
|
const projectCardStates: Array<ProjectCardState> = []
|
||||||
for (const projectCard of projectCards) {
|
for (const projectCard of projectCards) {
|
||||||
const [title, fileCount, folderCount] = await Promise.all([
|
const [title, fileCount] = await Promise.all([
|
||||||
(await projectCard.locator(this.projectCardTitle).textContent()) || '',
|
(await projectCard.locator(this.projectCardTitle).textContent()) || '',
|
||||||
Number(await projectCard.locator(this.projectCardFile).textContent()),
|
Number(await projectCard.locator(this.projectCardFile).textContent()),
|
||||||
Number(await projectCard.locator(this.projectCardFolder).textContent()),
|
|
||||||
])
|
])
|
||||||
projectCardStates.push({
|
projectCardStates.push({
|
||||||
title: title,
|
title: title,
|
||||||
fileCount,
|
fileCount,
|
||||||
folderCount,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return projectCardStates
|
return projectCardStates
|
||||||
|
@ -28,6 +28,7 @@ type SceneSerialised = {
|
|||||||
|
|
||||||
type ClickHandler = (clickParams?: mouseParams) => Promise<void | boolean>
|
type ClickHandler = (clickParams?: mouseParams) => Promise<void | boolean>
|
||||||
type MoveHandler = (moveParams?: mouseParams) => Promise<void | boolean>
|
type MoveHandler = (moveParams?: mouseParams) => Promise<void | boolean>
|
||||||
|
type DblClickHandler = (clickParams?: mouseParams) => Promise<void | boolean>
|
||||||
type DragToHandler = (dragParams: mouseDragToParams) => Promise<void | boolean>
|
type DragToHandler = (dragParams: mouseDragToParams) => Promise<void | boolean>
|
||||||
type DragFromHandler = (
|
type DragFromHandler = (
|
||||||
dragParams: mouseDragFromParams
|
dragParams: mouseDragFromParams
|
||||||
@ -68,7 +69,7 @@ export class SceneFixture {
|
|||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
{ steps }: { steps: number } = { steps: 20 }
|
{ steps }: { steps: number } = { steps: 20 }
|
||||||
): [ClickHandler, MoveHandler] =>
|
): [ClickHandler, MoveHandler, DblClickHandler] =>
|
||||||
[
|
[
|
||||||
(clickParams?: mouseParams) => {
|
(clickParams?: mouseParams) => {
|
||||||
if (clickParams?.pixelDiff) {
|
if (clickParams?.pixelDiff) {
|
||||||
@ -90,6 +91,16 @@ export class SceneFixture {
|
|||||||
}
|
}
|
||||||
return this.page.mouse.move(x, y, { steps })
|
return this.page.mouse.move(x, y, { steps })
|
||||||
},
|
},
|
||||||
|
(clickParams?: mouseParams) => {
|
||||||
|
if (clickParams?.pixelDiff) {
|
||||||
|
return doAndWaitForImageDiff(
|
||||||
|
this.page,
|
||||||
|
() => this.page.mouse.dblclick(x, y),
|
||||||
|
clickParams.pixelDiff
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return this.page.mouse.dblclick(x, y)
|
||||||
|
},
|
||||||
] as const
|
] as const
|
||||||
makeDragHelpers = (
|
makeDragHelpers = (
|
||||||
x: number,
|
x: number,
|
||||||
|
@ -6,6 +6,7 @@ export class ToolbarFixture {
|
|||||||
public page: Page
|
public page: Page
|
||||||
|
|
||||||
extrudeButton!: Locator
|
extrudeButton!: Locator
|
||||||
|
loftButton!: Locator
|
||||||
offsetPlaneButton!: Locator
|
offsetPlaneButton!: Locator
|
||||||
startSketchBtn!: Locator
|
startSketchBtn!: Locator
|
||||||
lineBtn!: Locator
|
lineBtn!: Locator
|
||||||
@ -26,6 +27,7 @@ export class ToolbarFixture {
|
|||||||
reConstruct = (page: Page) => {
|
reConstruct = (page: Page) => {
|
||||||
this.page = page
|
this.page = page
|
||||||
this.extrudeButton = page.getByTestId('extrude')
|
this.extrudeButton = page.getByTestId('extrude')
|
||||||
|
this.loftButton = page.getByTestId('loft')
|
||||||
this.offsetPlaneButton = page.getByTestId('plane-offset')
|
this.offsetPlaneButton = page.getByTestId('plane-offset')
|
||||||
this.startSketchBtn = page.getByTestId('sketch')
|
this.startSketchBtn = page.getByTestId('sketch')
|
||||||
this.lineBtn = page.getByTestId('line')
|
this.lineBtn = page.getByTestId('line')
|
||||||
|
@ -552,6 +552,82 @@ test(`Verify axis, origin, and horizontal snapping`, async ({
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test(`Verify user can double-click to edit a sketch`, async ({
|
||||||
|
app,
|
||||||
|
editor,
|
||||||
|
toolbar,
|
||||||
|
scene,
|
||||||
|
}) => {
|
||||||
|
const initialCode = `closedSketch = startSketchOn('XZ')
|
||||||
|
|> circle({ center = [8, 5], radius = 2 }, %)
|
||||||
|
openSketch = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-5, 0], %)
|
||||||
|
|> lineTo([0, 5], %)
|
||||||
|
|> xLine(5, %)
|
||||||
|
|> tangentialArcTo([10, 0], %)
|
||||||
|
`
|
||||||
|
await app.initialise(initialCode)
|
||||||
|
|
||||||
|
const pointInsideCircle = {
|
||||||
|
x: app.viewPortSize.width * 0.63,
|
||||||
|
y: app.viewPortSize.height * 0.5,
|
||||||
|
}
|
||||||
|
const pointOnPathAfterSketching = {
|
||||||
|
x: app.viewPortSize.width * 0.58,
|
||||||
|
y: app.viewPortSize.height * 0.5,
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const [_clickOpenPath, moveToOpenPath, dblClickOpenPath] =
|
||||||
|
scene.makeMouseHelpers(
|
||||||
|
pointOnPathAfterSketching.x,
|
||||||
|
pointOnPathAfterSketching.y
|
||||||
|
)
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const [_clickCircle, moveToCircle, dblClickCircle] = scene.makeMouseHelpers(
|
||||||
|
pointInsideCircle.x,
|
||||||
|
pointInsideCircle.y
|
||||||
|
)
|
||||||
|
|
||||||
|
const exitSketch = async () => {
|
||||||
|
await test.step(`Exit sketch mode`, async () => {
|
||||||
|
await toolbar.exitSketchBtn.click()
|
||||||
|
await expect(toolbar.exitSketchBtn).not.toBeVisible()
|
||||||
|
await expect(toolbar.startSketchBtn).toBeEnabled()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await test.step(`Double-click on the closed sketch`, async () => {
|
||||||
|
await moveToCircle()
|
||||||
|
await dblClickCircle()
|
||||||
|
await expect(toolbar.startSketchBtn).not.toBeVisible()
|
||||||
|
await expect(toolbar.exitSketchBtn).toBeVisible()
|
||||||
|
await editor.expectState({
|
||||||
|
activeLines: [`|>circle({center=[8,5],radius=2},%)`],
|
||||||
|
highlightedCode: 'circle({center=[8,5],radius=2},%)',
|
||||||
|
diagnostics: [],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
await exitSketch()
|
||||||
|
|
||||||
|
await test.step(`Double-click on the open sketch`, async () => {
|
||||||
|
await moveToOpenPath()
|
||||||
|
await scene.expectPixelColor([250, 250, 250], pointOnPathAfterSketching, 15)
|
||||||
|
// There is a full execution after exiting sketch that clears the scene.
|
||||||
|
await app.page.waitForTimeout(500)
|
||||||
|
await dblClickOpenPath()
|
||||||
|
await expect(toolbar.startSketchBtn).not.toBeVisible()
|
||||||
|
await expect(toolbar.exitSketchBtn).toBeVisible()
|
||||||
|
// Wait for enter sketch mode to complete
|
||||||
|
await app.page.waitForTimeout(500)
|
||||||
|
await editor.expectState({
|
||||||
|
activeLines: [`|>xLine(5,%)`],
|
||||||
|
highlightedCode: 'xLine(5,%)',
|
||||||
|
diagnostics: [],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test(`Offset plane point-and-click`, async ({
|
test(`Offset plane point-and-click`, async ({
|
||||||
app,
|
app,
|
||||||
scene,
|
scene,
|
||||||
@ -601,3 +677,94 @@ test(`Offset plane point-and-click`, async ({
|
|||||||
await scene.expectPixelColor([74, 74, 74], testPoint, 15)
|
await scene.expectPixelColor([74, 74, 74], testPoint, 15)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const loftPointAndClickCases = [
|
||||||
|
{ shouldPreselect: true },
|
||||||
|
{ shouldPreselect: false },
|
||||||
|
]
|
||||||
|
loftPointAndClickCases.forEach(({ shouldPreselect }) => {
|
||||||
|
test(`Loft point-and-click (preselected sketches: ${shouldPreselect})`, async ({
|
||||||
|
app,
|
||||||
|
page,
|
||||||
|
scene,
|
||||||
|
editor,
|
||||||
|
toolbar,
|
||||||
|
cmdBar,
|
||||||
|
}) => {
|
||||||
|
const initialCode = `sketch001 = startSketchOn('XZ')
|
||||||
|
|> circle({ center = [0, 0], radius = 30 }, %)
|
||||||
|
plane001 = offsetPlane('XZ', 50)
|
||||||
|
sketch002 = startSketchOn(plane001)
|
||||||
|
|> circle({ center = [0, 0], radius = 20 }, %)
|
||||||
|
`
|
||||||
|
await app.initialise(initialCode)
|
||||||
|
|
||||||
|
// One dumb hardcoded screen pixel value
|
||||||
|
const testPoint = { x: 575, y: 200 }
|
||||||
|
const [clickOnSketch1] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||||
|
const [clickOnSketch2] = scene.makeMouseHelpers(
|
||||||
|
testPoint.x,
|
||||||
|
testPoint.y + 80
|
||||||
|
)
|
||||||
|
const loftDeclaration = 'loft001 = loft([sketch001, sketch002])'
|
||||||
|
|
||||||
|
await test.step(`Look for the white of the sketch001 shape`, async () => {
|
||||||
|
await scene.expectPixelColor([254, 254, 254], testPoint, 15)
|
||||||
|
})
|
||||||
|
|
||||||
|
async function selectSketches() {
|
||||||
|
await clickOnSketch1()
|
||||||
|
await page.keyboard.down('Shift')
|
||||||
|
await clickOnSketch2()
|
||||||
|
await app.page.waitForTimeout(500)
|
||||||
|
await page.keyboard.up('Shift')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldPreselect) {
|
||||||
|
await test.step(`Go through the command bar flow without preselected sketches`, async () => {
|
||||||
|
await toolbar.loftButton.click()
|
||||||
|
await cmdBar.expectState({
|
||||||
|
stage: 'arguments',
|
||||||
|
currentArgKey: 'selection',
|
||||||
|
currentArgValue: '',
|
||||||
|
headerArguments: { Selection: '' },
|
||||||
|
highlightedHeaderArg: 'selection',
|
||||||
|
commandName: 'Loft',
|
||||||
|
})
|
||||||
|
await selectSketches()
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await cmdBar.expectState({
|
||||||
|
stage: 'review',
|
||||||
|
headerArguments: { Selection: '2 faces' },
|
||||||
|
commandName: 'Loft',
|
||||||
|
})
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await test.step(`Preselect the two sketches`, async () => {
|
||||||
|
await selectSketches()
|
||||||
|
})
|
||||||
|
|
||||||
|
await test.step(`Go through the command bar flow with preselected sketches`, async () => {
|
||||||
|
await toolbar.loftButton.click()
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await cmdBar.expectState({
|
||||||
|
stage: 'review',
|
||||||
|
headerArguments: { Selection: '2 faces' },
|
||||||
|
commandName: 'Loft',
|
||||||
|
})
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
|
||||||
|
await editor.expectEditor.toContain(loftDeclaration)
|
||||||
|
await editor.expectState({
|
||||||
|
diagnostics: [],
|
||||||
|
activeLines: [loftDeclaration],
|
||||||
|
highlightedCode: '',
|
||||||
|
})
|
||||||
|
await scene.expectPixelColor([89, 89, 89], testPoint, 15)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
@ -192,7 +192,7 @@
|
|||||||
"eslint-plugin-css-modules": "^2.12.0",
|
"eslint-plugin-css-modules": "^2.12.0",
|
||||||
"eslint-plugin-import": "^2.30.0",
|
"eslint-plugin-import": "^2.30.0",
|
||||||
"eslint-plugin-suggest-no-throw": "^1.0.0",
|
"eslint-plugin-suggest-no-throw": "^1.0.0",
|
||||||
"happy-dom": "^15.10.2",
|
"happy-dom": "^15.11.7",
|
||||||
"http-server": "^14.1.1",
|
"http-server": "^14.1.1",
|
||||||
"husky": "^9.1.5",
|
"husky": "^9.1.5",
|
||||||
"kill-port": "^2.0.1",
|
"kill-port": "^2.0.1",
|
||||||
@ -212,7 +212,7 @@
|
|||||||
"vite-tsconfig-paths": "^4.3.2",
|
"vite-tsconfig-paths": "^4.3.2",
|
||||||
"vitest": "^1.6.0",
|
"vitest": "^1.6.0",
|
||||||
"vitest-webgl-canvas-mock": "^1.1.0",
|
"vitest-webgl-canvas-mock": "^1.1.0",
|
||||||
"wasm-pack": "^0.13.0",
|
"wasm-pack": "^0.13.1",
|
||||||
"ws": "^8.17.0",
|
"ws": "^8.17.0",
|
||||||
"yarn": "^1.22.22"
|
"yarn": "^1.22.22"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
export VERSION=$(date +'%-y.%-m.%-d')
|
export VERSION=$(date +'%-y.%-m.%-d')
|
||||||
|
export TAG="nightly-v$VERSION"
|
||||||
|
export PREVIOUS_TAG=$(git describe --tags --match="nightly-v[0-9]*" --abbrev=0)
|
||||||
export COMMIT=$(git rev-parse --short HEAD)
|
export COMMIT=$(git rev-parse --short HEAD)
|
||||||
|
|
||||||
# package.json
|
# package.json
|
||||||
@ -13,7 +15,7 @@ yq -i '.publish[0].url = "https://dl.zoo.dev/releases/modeling-app/nightly"' ele
|
|||||||
yq -i '.appId = "dev.zoo.modeling-app-nightly"' electron-builder.yml
|
yq -i '.appId = "dev.zoo.modeling-app-nightly"' electron-builder.yml
|
||||||
|
|
||||||
# Release notes
|
# Release notes
|
||||||
echo "Nightly build $VERSION (commit $COMMIT)" > release-notes.md
|
./scripts/get-nightly-changelog.sh > release-notes.md
|
||||||
|
|
||||||
# icons
|
# icons
|
||||||
cp assets/icon-nightly.png assets/icon.png
|
cp assets/icon-nightly.png assets/icon.png
|
||||||
|
5
scripts/get-nightly-changelog.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "## What's Changed"
|
||||||
|
git log ${PREVIOUS_TAG}..HEAD --oneline --pretty=format:%s | grep -v Bump | awk '{print "* "toupper(substr($0,0,1))substr($0,2)}'
|
||||||
|
echo ""
|
||||||
|
echo "**Full Changelog**: https://github.com/KittyCAD/modeling-app/compare/${PREVIOUS_TAG}...${TAG}"
|
@ -273,14 +273,26 @@ export class CameraControls {
|
|||||||
camSettings.center.y,
|
camSettings.center.y,
|
||||||
camSettings.center.z
|
camSettings.center.z
|
||||||
)
|
)
|
||||||
const quat = new Quaternion(
|
const orientation = new Quaternion(
|
||||||
camSettings.orientation.x,
|
camSettings.orientation.x,
|
||||||
camSettings.orientation.y,
|
camSettings.orientation.y,
|
||||||
camSettings.orientation.z,
|
camSettings.orientation.z,
|
||||||
camSettings.orientation.w
|
camSettings.orientation.w
|
||||||
).invert()
|
).invert()
|
||||||
|
|
||||||
this.camera.up.copy(new Vector3(0, 1, 0).applyQuaternion(quat))
|
const newUp = new Vector3(
|
||||||
|
camSettings.up.x,
|
||||||
|
camSettings.up.y,
|
||||||
|
camSettings.up.z
|
||||||
|
)
|
||||||
|
this.camera.quaternion.set(
|
||||||
|
orientation.x,
|
||||||
|
orientation.y,
|
||||||
|
orientation.z,
|
||||||
|
orientation.w
|
||||||
|
)
|
||||||
|
this.camera.up.copy(newUp)
|
||||||
|
this.camera.updateProjectionMatrix()
|
||||||
if (this.camera instanceof PerspectiveCamera && camSettings.ortho) {
|
if (this.camera instanceof PerspectiveCamera && camSettings.ortho) {
|
||||||
this.useOrthographicCamera()
|
this.useOrthographicCamera()
|
||||||
}
|
}
|
||||||
@ -1164,7 +1176,7 @@ export class CameraControls {
|
|||||||
this.camera.updateProjectionMatrix()
|
this.camera.updateProjectionMatrix()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.syncDirection === 'clientToEngine' || forceUpdate)
|
if (this.syncDirection === 'clientToEngine' || forceUpdate) {
|
||||||
this.throttledUpdateEngineCamera({
|
this.throttledUpdateEngineCamera({
|
||||||
quaternion: this.camera.quaternion,
|
quaternion: this.camera.quaternion,
|
||||||
position: this.camera.position,
|
position: this.camera.position,
|
||||||
@ -1172,6 +1184,7 @@ export class CameraControls {
|
|||||||
isPerspective: this.isPerspective,
|
isPerspective: this.isPerspective,
|
||||||
target: this.target,
|
target: this.target,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
this.deferReactUpdate(this.reactCameraProperties)
|
this.deferReactUpdate(this.reactCameraProperties)
|
||||||
Object.values(this._camChangeCallbacks).forEach((cb) => cb())
|
Object.values(this._camChangeCallbacks).forEach((cb) => cb())
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ import {
|
|||||||
isSketchPipe,
|
isSketchPipe,
|
||||||
Selections,
|
Selections,
|
||||||
updateSelections,
|
updateSelections,
|
||||||
|
canLoftSelection,
|
||||||
} from 'lib/selections'
|
} from 'lib/selections'
|
||||||
import { applyConstraintIntersect } from './Toolbar/Intersect'
|
import { applyConstraintIntersect } from './Toolbar/Intersect'
|
||||||
import { applyConstraintAbsDistance } from './Toolbar/SetAbsDistance'
|
import { applyConstraintAbsDistance } from './Toolbar/SetAbsDistance'
|
||||||
@ -82,7 +83,7 @@ import { getVarNameModal } from 'hooks/useToolbarGuards'
|
|||||||
import { err, reportRejection, trap } from 'lib/trap'
|
import { err, reportRejection, trap } from 'lib/trap'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
import { modelingMachineEvent } from 'editor/manager'
|
import { modelingMachineEvent } from 'editor/manager'
|
||||||
import { hasValidFilletSelection } from 'lang/modifyAst/addFillet'
|
import { hasValidEdgeTreatmentSelection } from 'lang/modifyAst/addEdgeTreatment'
|
||||||
import {
|
import {
|
||||||
ExportIntent,
|
ExportIntent,
|
||||||
EngineConnectionStateType,
|
EngineConnectionStateType,
|
||||||
@ -569,6 +570,21 @@ export const ModelingMachineProvider = ({
|
|||||||
if (err(canSweep)) return false
|
if (err(canSweep)) return false
|
||||||
return canSweep
|
return canSweep
|
||||||
},
|
},
|
||||||
|
'has valid loft selection': ({ context: { selectionRanges } }) => {
|
||||||
|
const hasNoSelection =
|
||||||
|
selectionRanges.graphSelections.length === 0 ||
|
||||||
|
isRangeBetweenCharacters(selectionRanges) ||
|
||||||
|
isSelectionLastLine(selectionRanges, codeManager.code)
|
||||||
|
|
||||||
|
if (hasNoSelection) {
|
||||||
|
const count = 2
|
||||||
|
return doesSceneHaveSweepableSketch(kclManager.ast, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
const canLoft = canLoftSelection(selectionRanges)
|
||||||
|
if (err(canLoft)) return false
|
||||||
|
return canLoft
|
||||||
|
},
|
||||||
'has valid selection for deletion': ({
|
'has valid selection for deletion': ({
|
||||||
context: { selectionRanges },
|
context: { selectionRanges },
|
||||||
}) => {
|
}) => {
|
||||||
@ -576,8 +592,10 @@ export const ModelingMachineProvider = ({
|
|||||||
if (selectionRanges.graphSelections.length <= 0) return false
|
if (selectionRanges.graphSelections.length <= 0) return false
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
'has valid fillet selection': ({ context: { selectionRanges } }) => {
|
'has valid edge treatment selection': ({
|
||||||
return hasValidFilletSelection({
|
context: { selectionRanges },
|
||||||
|
}) => {
|
||||||
|
return hasValidEdgeTreatmentSelection({
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
ast: kclManager.ast,
|
ast: kclManager.ast,
|
||||||
code: codeManager.code,
|
code: codeManager.code,
|
||||||
|
@ -18,6 +18,8 @@ import { useRouteLoaderData } from 'react-router-dom'
|
|||||||
import { PATHS } from 'lib/paths'
|
import { PATHS } from 'lib/paths'
|
||||||
import { IndexLoaderData } from 'lib/types'
|
import { IndexLoaderData } from 'lib/types'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
|
import { err, reportRejection } from 'lib/trap'
|
||||||
|
import { getArtifactOfTypes } from 'lang/std/artifactGraph'
|
||||||
|
|
||||||
enum StreamState {
|
enum StreamState {
|
||||||
Playing = 'playing',
|
Playing = 'playing',
|
||||||
@ -280,12 +282,49 @@ export const Stream = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On double-click of sketch entities we automatically enter sketch mode with the selected sketch,
|
||||||
|
* allowing for quick editing of sketches. TODO: This should be moved to a more central place.
|
||||||
|
*/
|
||||||
|
const enterSketchModeIfSelectingSketch: MouseEventHandler<HTMLDivElement> = (
|
||||||
|
e
|
||||||
|
) => {
|
||||||
|
if (
|
||||||
|
!isNetworkOkay ||
|
||||||
|
!videoRef.current ||
|
||||||
|
state.matches('Sketch') ||
|
||||||
|
state.matches({ idle: 'showPlanes' }) ||
|
||||||
|
sceneInfra.camControls.wasDragging === true ||
|
||||||
|
!btnName(e.nativeEvent).left
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sendSelectEventToEngine(e, videoRef.current)
|
||||||
|
.then(({ entity_id }) => {
|
||||||
|
if (!entity_id) {
|
||||||
|
// No entity selected. This is benign
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const path = getArtifactOfTypes(
|
||||||
|
{ key: entity_id, types: ['path', 'solid2D', 'segment'] },
|
||||||
|
engineCommandManager.artifactGraph
|
||||||
|
)
|
||||||
|
if (err(path)) {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
sceneInfra.modelingSend({ type: 'Enter sketch' })
|
||||||
|
})
|
||||||
|
.catch(reportRejection)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="absolute inset-0 z-0"
|
className="absolute inset-0 z-0"
|
||||||
id="stream"
|
id="stream"
|
||||||
data-testid="stream"
|
data-testid="stream"
|
||||||
onClick={handleMouseUp}
|
onClick={handleMouseUp}
|
||||||
|
onDoubleClick={enterSketchModeIfSelectingSketch}
|
||||||
onContextMenu={(e) => e.preventDefault()}
|
onContextMenu={(e) => e.preventDefault()}
|
||||||
onContextMenuCapture={(e) => e.preventDefault()}
|
onContextMenuCapture={(e) => e.preventDefault()}
|
||||||
>
|
>
|
||||||
|
@ -384,7 +384,6 @@ const myVar = funcN(1, 2)`
|
|||||||
raw: '2',
|
raw: '2',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optional: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -465,7 +464,6 @@ describe('testing pipe operator special', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optional: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'CallExpression',
|
type: 'CallExpression',
|
||||||
@ -508,7 +506,6 @@ describe('testing pipe operator special', () => {
|
|||||||
end: 60,
|
end: 60,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optional: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'CallExpression',
|
type: 'CallExpression',
|
||||||
@ -556,7 +553,6 @@ describe('testing pipe operator special', () => {
|
|||||||
value: 'myPath',
|
value: 'myPath',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optional: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'CallExpression',
|
type: 'CallExpression',
|
||||||
@ -598,7 +594,6 @@ describe('testing pipe operator special', () => {
|
|||||||
end: 115,
|
end: 115,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optional: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'CallExpression',
|
type: 'CallExpression',
|
||||||
@ -625,7 +620,6 @@ describe('testing pipe operator special', () => {
|
|||||||
end: 130,
|
end: 130,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optional: false,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -711,7 +705,6 @@ describe('testing pipe operator special', () => {
|
|||||||
end: 35,
|
end: 35,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optional: false,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -1765,7 +1758,6 @@ describe('test UnaryExpression', () => {
|
|||||||
raw: '100',
|
raw: '100',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optional: false,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -1837,11 +1829,9 @@ describe('testing nested call expressions', () => {
|
|||||||
raw: '3',
|
raw: '3',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optional: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optional: false,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -1879,7 +1869,6 @@ describe('should recognise callExpresions in binaryExpressions', () => {
|
|||||||
name: 'seg02',
|
name: 'seg02',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optional: false,
|
|
||||||
},
|
},
|
||||||
right: {
|
right: {
|
||||||
type: 'Literal',
|
type: 'Literal',
|
||||||
|
@ -346,6 +346,37 @@ export function extrudeSketch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function loftSketches(
|
||||||
|
node: Node<Program>,
|
||||||
|
declarators: VariableDeclarator[]
|
||||||
|
): {
|
||||||
|
modifiedAst: Node<Program>
|
||||||
|
pathToNode: PathToNode
|
||||||
|
} {
|
||||||
|
const modifiedAst = structuredClone(node)
|
||||||
|
const name = findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.LOFT)
|
||||||
|
const elements = declarators.map((d) => createIdentifier(d.id.name))
|
||||||
|
const loft = createCallExpressionStdLib('loft', [
|
||||||
|
createArrayExpression(elements),
|
||||||
|
])
|
||||||
|
const declaration = createVariableDeclaration(name, loft)
|
||||||
|
modifiedAst.body.push(declaration)
|
||||||
|
const pathToNode: PathToNode = [
|
||||||
|
['body', ''],
|
||||||
|
[modifiedAst.body.length - 1, 'index'],
|
||||||
|
['declarations', 'VariableDeclaration'],
|
||||||
|
['0', 'index'],
|
||||||
|
['init', 'VariableDeclarator'],
|
||||||
|
['arguments', 'CallExpression'],
|
||||||
|
[0, 'index'],
|
||||||
|
]
|
||||||
|
|
||||||
|
return {
|
||||||
|
modifiedAst,
|
||||||
|
pathToNode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function revolveSketch(
|
export function revolveSketch(
|
||||||
node: Node<Program>,
|
node: Node<Program>,
|
||||||
pathToNode: PathToNode,
|
pathToNode: PathToNode,
|
||||||
@ -727,7 +758,6 @@ export function createCallExpressionStdLib(
|
|||||||
|
|
||||||
name,
|
name,
|
||||||
},
|
},
|
||||||
optional: false,
|
|
||||||
arguments: args,
|
arguments: args,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -749,7 +779,6 @@ export function createCallExpression(
|
|||||||
|
|
||||||
name,
|
name,
|
||||||
},
|
},
|
||||||
optional: false,
|
|
||||||
arguments: args,
|
arguments: args,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,18 +10,21 @@ import {
|
|||||||
VariableDeclarator,
|
VariableDeclarator,
|
||||||
} from '../wasm'
|
} from '../wasm'
|
||||||
import {
|
import {
|
||||||
|
EdgeTreatmentType,
|
||||||
getPathToExtrudeForSegmentSelection,
|
getPathToExtrudeForSegmentSelection,
|
||||||
hasValidFilletSelection,
|
hasValidEdgeTreatmentSelection,
|
||||||
isTagUsedInFillet,
|
isTagUsedInEdgeTreatment,
|
||||||
modifyAstWithFilletAndTag,
|
modifyAstWithEdgeTreatmentAndTag,
|
||||||
} from './addFillet'
|
FilletParameters,
|
||||||
|
ChamferParameters,
|
||||||
|
EdgeTreatmentParameters,
|
||||||
|
} from './addEdgeTreatment'
|
||||||
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
|
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
|
||||||
import { createLiteral } from 'lang/modifyAst'
|
import { createLiteral } from 'lang/modifyAst'
|
||||||
import { err } from 'lib/trap'
|
import { err } from 'lib/trap'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { engineCommandManager, kclManager } from 'lib/singletons'
|
import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||||
import { VITE_KC_DEV_TOKEN } from 'env'
|
import { VITE_KC_DEV_TOKEN } from 'env'
|
||||||
import { KclCommandValue } from 'lib/commandTypes'
|
|
||||||
import { isOverlap } from 'lib/utils'
|
import { isOverlap } from 'lib/utils'
|
||||||
import { codeRefFromRange } from 'lang/std/artifactGraph'
|
import { codeRefFromRange } from 'lang/std/artifactGraph'
|
||||||
|
|
||||||
@ -253,10 +256,10 @@ extrude003 = extrude(-15, sketch003)`
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const runModifyAstCloneWithFilletAndTag = async (
|
const runModifyAstCloneWithEdgeTreatmentAndTag = async (
|
||||||
code: string,
|
code: string,
|
||||||
selectionSnippets: Array<string>,
|
selectionSnippets: Array<string>,
|
||||||
radiusValue: number,
|
parameters: EdgeTreatmentParameters,
|
||||||
expectedCode: string
|
expectedCode: string
|
||||||
) => {
|
) => {
|
||||||
// ast
|
// ast
|
||||||
@ -274,13 +277,6 @@ const runModifyAstCloneWithFilletAndTag = async (
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
// radius
|
|
||||||
const radius: KclCommandValue = {
|
|
||||||
valueAst: createLiteral(radiusValue),
|
|
||||||
valueText: radiusValue.toString(),
|
|
||||||
valueCalculated: radiusValue.toString(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// executeAst
|
// executeAst
|
||||||
await kclManager.executeAst({ ast })
|
await kclManager.executeAst({ ast })
|
||||||
const artifactGraph = engineCommandManager.artifactGraph
|
const artifactGraph = engineCommandManager.artifactGraph
|
||||||
@ -299,8 +295,8 @@ const runModifyAstCloneWithFilletAndTag = async (
|
|||||||
otherSelections: [],
|
otherSelections: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply fillet to selection
|
// apply edge treatment to seleciton
|
||||||
const result = modifyAstWithFilletAndTag(ast, selection, radius)
|
const result = modifyAstWithEdgeTreatmentAndTag(ast, selection, parameters)
|
||||||
if (err(result)) {
|
if (err(result)) {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -310,8 +306,41 @@ const runModifyAstCloneWithFilletAndTag = async (
|
|||||||
|
|
||||||
expect(newCode).toContain(expectedCode)
|
expect(newCode).toContain(expectedCode)
|
||||||
}
|
}
|
||||||
describe('Testing applyFilletToSelection', () => {
|
const createFilletParameters = (radiusValue: number): FilletParameters => ({
|
||||||
it('should add a fillet to a specific segment', async () => {
|
type: EdgeTreatmentType.Fillet,
|
||||||
|
radius: {
|
||||||
|
valueAst: createLiteral(radiusValue),
|
||||||
|
valueText: radiusValue.toString(),
|
||||||
|
valueCalculated: radiusValue.toString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const createChamferParameters = (lengthValue: number): ChamferParameters => ({
|
||||||
|
type: EdgeTreatmentType.Chamfer,
|
||||||
|
length: {
|
||||||
|
valueAst: createLiteral(lengthValue),
|
||||||
|
valueText: lengthValue.toString(),
|
||||||
|
valueCalculated: lengthValue.toString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// Iterate tests over all edge treatment types
|
||||||
|
Object.values(EdgeTreatmentType).forEach(
|
||||||
|
(edgeTreatmentType: EdgeTreatmentType) => {
|
||||||
|
// create parameters based on the edge treatment type
|
||||||
|
let parameterName: string
|
||||||
|
let parameters: EdgeTreatmentParameters
|
||||||
|
if (edgeTreatmentType === EdgeTreatmentType.Fillet) {
|
||||||
|
parameterName = 'radius'
|
||||||
|
parameters = createFilletParameters(3)
|
||||||
|
} else if (edgeTreatmentType === EdgeTreatmentType.Chamfer) {
|
||||||
|
parameterName = 'length'
|
||||||
|
parameters = createChamferParameters(3)
|
||||||
|
} else {
|
||||||
|
// Handle future edge treatments
|
||||||
|
return new Error(`Unsupported edge treatment type: ${edgeTreatmentType}`)
|
||||||
|
}
|
||||||
|
// run tests
|
||||||
|
describe(`Testing modifyAstCloneWithEdgeTreatmentAndTag with ${edgeTreatmentType}s`, () => {
|
||||||
|
it(`should add a ${edgeTreatmentType} to a specific segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
@ -321,7 +350,6 @@ describe('Testing applyFilletToSelection', () => {
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)`
|
||||||
const segmentSnippets = ['line([0, -20], %)']
|
const segmentSnippets = ['line([0, -20], %)']
|
||||||
const radiusValue = 3
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
@ -330,16 +358,16 @@ extrude001 = extrude(-15, sketch001)`
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg01] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet to the sketch pipe', async () => {
|
it(`should add a ${edgeTreatmentType} to the sketch pipe`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
@ -349,7 +377,6 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(-15, %)`
|
|> extrude(-15, %)`
|
||||||
const segmentSnippets = ['line([0, -20], %)']
|
const segmentSnippets = ['line([0, -20], %)']
|
||||||
const radiusValue = 3
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
@ -358,16 +385,16 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
|> extrude(-15, %)
|
|> extrude(-15, %)
|
||||||
|> fillet({ radius = 3, tags = [seg01] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet to an already tagged segment', async () => {
|
it(`should add a ${edgeTreatmentType} to an already tagged segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
@ -377,7 +404,6 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)`
|
||||||
const segmentSnippets = ['line([0, -20], %, $seg01)']
|
const segmentSnippets = ['line([0, -20], %, $seg01)']
|
||||||
const radiusValue = 3
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
@ -386,16 +412,16 @@ extrude001 = extrude(-15, sketch001)`
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg01] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet with existing tag on other segment', async () => {
|
it(`should add a ${edgeTreatmentType} with existing tag on other segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
@ -405,7 +431,6 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)`
|
||||||
const segmentSnippets = ['line([-20, 0], %)']
|
const segmentSnippets = ['line([-20, 0], %)']
|
||||||
const radiusValue = 3
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
@ -414,16 +439,16 @@ extrude001 = extrude(-15, sketch001)`
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg02] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg02] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet with existing fillet on other segment', async () => {
|
it(`should add a ${edgeTreatmentType} with existing fillet on other segment`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
@ -434,7 +459,6 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 5, tags = [seg01] }, %)`
|
|> fillet({ radius = 5, tags = [seg01] }, %)`
|
||||||
const segmentSnippets = ['line([-20, 0], %)']
|
const segmentSnippets = ['line([-20, 0], %)']
|
||||||
const radiusValue = 3
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
@ -444,16 +468,45 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 5, tags = [seg01] }, %)
|
|> fillet({ radius = 5, tags = [seg01] }, %)
|
||||||
|> fillet({ radius = 3, tags = [seg02] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg02] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add a fillet to two segments of a single extrusion', async () => {
|
it(`should add a ${edgeTreatmentType} with existing chamfer on other segment`, async () => {
|
||||||
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, 10], %)
|
||||||
|
|> line([20, 0], %, $seg01)
|
||||||
|
|> line([0, -20], %)
|
||||||
|
|> line([-20, 0], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(-15, sketch001)
|
||||||
|
|> chamfer({ length: 5, tags: [seg01] }, %)`
|
||||||
|
const segmentSnippets = ['line([-20, 0], %)']
|
||||||
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, 10], %)
|
||||||
|
|> line([20, 0], %, $seg01)
|
||||||
|
|> line([0, -20], %)
|
||||||
|
|> line([-20, 0], %, $seg02)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
extrude001 = extrude(-15, sketch001)
|
||||||
|
|> chamfer({ length: 5, tags: [seg01] }, %)
|
||||||
|
|> ${edgeTreatmentType}({ ${parameterName}: 3, tags: [seg02] }, %)`
|
||||||
|
|
||||||
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
|
code,
|
||||||
|
segmentSnippets,
|
||||||
|
parameters,
|
||||||
|
expectedCode
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it(`should add a ${edgeTreatmentType} to two segments of a single extrusion`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
@ -463,7 +516,6 @@ extrude001 = extrude(-15, sketch001)
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)`
|
extrude001 = extrude(-15, sketch001)`
|
||||||
const segmentSnippets = ['line([20, 0], %)', 'line([-20, 0], %)']
|
const segmentSnippets = ['line([20, 0], %)', 'line([-20, 0], %)']
|
||||||
const radiusValue = 3
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
@ -472,16 +524,16 @@ extrude001 = extrude(-15, sketch001)`
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg01, seg02] }, %)`
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01, seg02] }, %)`
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should add fillets to two bodies', async () => {
|
it(`should add ${edgeTreatmentType}s to two bodies`, async () => {
|
||||||
const code = `sketch001 = startSketchOn('XY')
|
const code = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %)
|
|> line([20, 0], %)
|
||||||
@ -503,7 +555,6 @@ extrude002 = extrude(-25, sketch002)` // <--- body 2
|
|||||||
'line([-20, 0], %)',
|
'line([-20, 0], %)',
|
||||||
'line([0, -15], %)',
|
'line([0, -15], %)',
|
||||||
]
|
]
|
||||||
const radiusValue = 3
|
|
||||||
const expectedCode = `sketch001 = startSketchOn('XY')
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
||||||
|> startProfileAt([-10, 10], %)
|
|> startProfileAt([-10, 10], %)
|
||||||
|> line([20, 0], %, $seg01)
|
|> line([20, 0], %, $seg01)
|
||||||
@ -512,7 +563,7 @@ extrude002 = extrude(-25, sketch002)` // <--- body 2
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude001 = extrude(-15, sketch001)
|
extrude001 = extrude(-15, sketch001)
|
||||||
|> fillet({ radius = 3, tags = [seg01, seg02] }, %)
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg01, seg02] }, %)
|
||||||
sketch002 = startSketchOn('XY')
|
sketch002 = startSketchOn('XY')
|
||||||
|> startProfileAt([30, 10], %)
|
|> startProfileAt([30, 10], %)
|
||||||
|> line([15, 0], %)
|
|> line([15, 0], %)
|
||||||
@ -521,18 +572,20 @@ sketch002 = startSketchOn('XY')
|
|||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|> close(%)
|
|> close(%)
|
||||||
extrude002 = extrude(-25, sketch002)
|
extrude002 = extrude(-25, sketch002)
|
||||||
|> fillet({ radius = 3, tags = [seg03] }, %)` // <-- able to add a new one
|
|> ${edgeTreatmentType}({ ${parameterName} = 3, tags = [seg03] }, %)` // <-- able to add a new one
|
||||||
|
|
||||||
await runModifyAstCloneWithFilletAndTag(
|
await runModifyAstCloneWithEdgeTreatmentAndTag(
|
||||||
code,
|
code,
|
||||||
segmentSnippets,
|
segmentSnippets,
|
||||||
radiusValue,
|
parameters,
|
||||||
expectedCode
|
expectedCode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
describe('Testing isTagUsedInFillet', () => {
|
describe('Testing isTagUsedInEdgeTreatment', () => {
|
||||||
const code = `sketch001 = startSketchOn('XZ')
|
const code = `sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([7.72, 4.13], %)
|
|> startProfileAt([7.72, 4.13], %)
|
||||||
|> line([7.11, 3.48], %, $seg01)
|
|> line([7.11, 3.48], %, $seg01)
|
||||||
@ -565,7 +618,7 @@ extrude001 = extrude(-5, sketch001)
|
|||||||
'CallExpression'
|
'CallExpression'
|
||||||
)
|
)
|
||||||
if (err(callExp)) return
|
if (err(callExp)) return
|
||||||
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
const edges = isTagUsedInEdgeTreatment({ ast, callExp: callExp.node })
|
||||||
expect(edges).toEqual(['getOppositeEdge', 'baseEdge'])
|
expect(edges).toEqual(['getOppositeEdge', 'baseEdge'])
|
||||||
})
|
})
|
||||||
it('should correctly identify getPreviousAdjacentEdge edges', () => {
|
it('should correctly identify getPreviousAdjacentEdge edges', () => {
|
||||||
@ -584,7 +637,7 @@ extrude001 = extrude(-5, sketch001)
|
|||||||
'CallExpression'
|
'CallExpression'
|
||||||
)
|
)
|
||||||
if (err(callExp)) return
|
if (err(callExp)) return
|
||||||
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
const edges = isTagUsedInEdgeTreatment({ ast, callExp: callExp.node })
|
||||||
expect(edges).toEqual(['getPreviousAdjacentEdge'])
|
expect(edges).toEqual(['getPreviousAdjacentEdge'])
|
||||||
})
|
})
|
||||||
it('should correctly identify no edges', () => {
|
it('should correctly identify no edges', () => {
|
||||||
@ -603,7 +656,7 @@ extrude001 = extrude(-5, sketch001)
|
|||||||
'CallExpression'
|
'CallExpression'
|
||||||
)
|
)
|
||||||
if (err(callExp)) return
|
if (err(callExp)) return
|
||||||
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
const edges = isTagUsedInEdgeTreatment({ ast, callExp: callExp.node })
|
||||||
expect(edges).toEqual([])
|
expect(edges).toEqual([])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -638,7 +691,7 @@ describe('Testing button states', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// state
|
// state
|
||||||
const buttonState = hasValidFilletSelection({
|
const buttonState = hasValidEdgeTreatmentSelection({
|
||||||
ast,
|
ast,
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
code,
|
code,
|
@ -44,32 +44,49 @@ import {
|
|||||||
} from 'lib/singletons'
|
} from 'lib/singletons'
|
||||||
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
||||||
|
|
||||||
// Apply Fillet To Selection
|
// Edge Treatment Types
|
||||||
|
export enum EdgeTreatmentType {
|
||||||
|
Chamfer = 'chamfer',
|
||||||
|
Fillet = 'fillet',
|
||||||
|
}
|
||||||
|
|
||||||
export function applyFilletToSelection(
|
export interface ChamferParameters {
|
||||||
|
type: EdgeTreatmentType.Chamfer
|
||||||
|
length: KclCommandValue
|
||||||
|
}
|
||||||
|
export interface FilletParameters {
|
||||||
|
type: EdgeTreatmentType.Fillet
|
||||||
|
radius: KclCommandValue
|
||||||
|
}
|
||||||
|
export type EdgeTreatmentParameters = ChamferParameters | FilletParameters
|
||||||
|
|
||||||
|
// Apply Edge Treatment (Fillet or Chamfer) To Selection
|
||||||
|
export function applyEdgeTreatmentToSelection(
|
||||||
ast: Node<Program>,
|
ast: Node<Program>,
|
||||||
selection: Selections,
|
selection: Selections,
|
||||||
radius: KclCommandValue
|
parameters: EdgeTreatmentParameters
|
||||||
): void | Error {
|
): void | Error {
|
||||||
// 1. clone and modify with fillet and tag
|
// 1. clone and modify with edge treatment and tag
|
||||||
const result = modifyAstWithFilletAndTag(ast, selection, radius)
|
const result = modifyAstWithEdgeTreatmentAndTag(ast, selection, parameters)
|
||||||
if (err(result)) return result
|
if (err(result)) return result
|
||||||
const { modifiedAst, pathToFilletNode } = result
|
const { modifiedAst, pathToEdgeTreatmentNode } = result
|
||||||
|
|
||||||
// 2. update ast
|
// 2. update ast
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
updateAstAndFocus(modifiedAst, pathToFilletNode)
|
updateAstAndFocus(modifiedAst, pathToEdgeTreatmentNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function modifyAstWithFilletAndTag(
|
export function modifyAstWithEdgeTreatmentAndTag(
|
||||||
ast: Node<Program>,
|
ast: Node<Program>,
|
||||||
selections: Selections,
|
selections: Selections,
|
||||||
radius: KclCommandValue
|
parameters: EdgeTreatmentParameters
|
||||||
): { modifiedAst: Node<Program>; pathToFilletNode: Array<PathToNode> } | Error {
|
):
|
||||||
|
| { modifiedAst: Node<Program>; pathToEdgeTreatmentNode: Array<PathToNode> }
|
||||||
|
| Error {
|
||||||
let clonedAst = structuredClone(ast)
|
let clonedAst = structuredClone(ast)
|
||||||
const clonedAstForGetExtrude = structuredClone(ast)
|
const clonedAstForGetExtrude = structuredClone(ast)
|
||||||
|
|
||||||
const astResult = insertRadiusIntoAst(clonedAst, radius)
|
const astResult = insertParametersIntoAst(clonedAst, parameters)
|
||||||
if (err(astResult)) return astResult
|
if (err(astResult)) return astResult
|
||||||
|
|
||||||
const artifactGraph = engineCommandManager.artifactGraph
|
const artifactGraph = engineCommandManager.artifactGraph
|
||||||
@ -119,21 +136,26 @@ export function modifyAstWithFilletAndTag(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Apply fillet(s) for each extrude node (body)
|
// Step 2: Apply edge treatments for each extrude node (body)
|
||||||
let pathToFilletNodes: Array<PathToNode> = []
|
let pathToEdgeTreatmentNodes: Array<PathToNode> = []
|
||||||
for (const [pathToExtrudeNode, tagInfos] of extrudeToTagsMap.entries()) {
|
for (const [pathToExtrudeNode, tagInfos] of extrudeToTagsMap.entries()) {
|
||||||
// Create a fillet expression with multiple tags
|
// Create an edge treatment expression with multiple tags
|
||||||
const radiusValue =
|
|
||||||
'variableName' in radius ? radius.variableIdentifierAst : radius.valueAst
|
|
||||||
|
|
||||||
|
// edge treatment parameter
|
||||||
|
const parameterResult = getParameterNameAndValue(parameters)
|
||||||
|
if (err(parameterResult)) return parameterResult
|
||||||
|
const { parameterName, parameterValue } = parameterResult
|
||||||
|
|
||||||
|
// tag calls
|
||||||
const tagCalls = tagInfos.map(({ tag, artifact }) => {
|
const tagCalls = tagInfos.map(({ tag, artifact }) => {
|
||||||
return getEdgeTagCall(tag, artifact)
|
return getEdgeTagCall(tag, artifact)
|
||||||
})
|
})
|
||||||
const firstTag = tagCalls[0] // can be Identifier or CallExpression (for opposite and adjacent edges)
|
const firstTag = tagCalls[0] // can be Identifier or CallExpression (for opposite and adjacent edges)
|
||||||
|
|
||||||
const filletCall = createCallExpressionStdLib('fillet', [
|
// edge treatment call
|
||||||
|
const edgeTreatmentCall = createCallExpressionStdLib(parameters.type, [
|
||||||
createObjectExpression({
|
createObjectExpression({
|
||||||
radius: radiusValue,
|
[parameterName]: parameterValue,
|
||||||
tags: createArrayExpression(tagCalls),
|
tags: createArrayExpression(tagCalls),
|
||||||
}),
|
}),
|
||||||
createPipeSubstitution(),
|
createPipeSubstitution(),
|
||||||
@ -147,64 +169,89 @@ export function modifyAstWithFilletAndTag(
|
|||||||
if (err(locatedExtrudeDeclarator)) return locatedExtrudeDeclarator
|
if (err(locatedExtrudeDeclarator)) return locatedExtrudeDeclarator
|
||||||
const { extrudeDeclarator } = locatedExtrudeDeclarator
|
const { extrudeDeclarator } = locatedExtrudeDeclarator
|
||||||
|
|
||||||
// Modify the extrude expression to include this fillet expression
|
// Modify the extrude expression to include this edge treatment expression
|
||||||
// CallExpression - no fillet
|
// CallExpression - no edge treatment
|
||||||
// PipeExpression - fillet exists or extrude in sketch pipe
|
// PipeExpression - edge treatment exists or body in sketch pipe
|
||||||
|
|
||||||
let pathToFilletNode: PathToNode = []
|
let pathToEdgeTreatmentNode: PathToNode
|
||||||
|
|
||||||
if (extrudeDeclarator.init.type === 'CallExpression') {
|
if (extrudeDeclarator.init.type === 'CallExpression') {
|
||||||
// 1. case when no fillet exists
|
// 1. case when no edge treatment exists
|
||||||
|
|
||||||
// modify ast with new fillet call by mutating the extrude node
|
// modify ast with new edge treatment call by mutating the extrude node
|
||||||
extrudeDeclarator.init = createPipeExpression([
|
extrudeDeclarator.init = createPipeExpression([
|
||||||
extrudeDeclarator.init,
|
extrudeDeclarator.init,
|
||||||
filletCall,
|
edgeTreatmentCall,
|
||||||
])
|
])
|
||||||
|
|
||||||
// get path to the fillet node
|
// get path to the edge treatment node
|
||||||
pathToFilletNode = getPathToNodeOfFilletLiteral(
|
pathToEdgeTreatmentNode = getPathToNodeOfEdgeTreatmentLiteral(
|
||||||
pathToExtrudeNode,
|
pathToExtrudeNode,
|
||||||
extrudeDeclarator,
|
extrudeDeclarator,
|
||||||
firstTag
|
firstTag,
|
||||||
|
parameters
|
||||||
)
|
)
|
||||||
pathToFilletNodes.push(pathToFilletNode)
|
pathToEdgeTreatmentNodes.push(pathToEdgeTreatmentNode)
|
||||||
} else if (extrudeDeclarator.init.type === 'PipeExpression') {
|
} else if (extrudeDeclarator.init.type === 'PipeExpression') {
|
||||||
// 2. case when fillet exists or extrude in sketch pipe
|
// 2. case when edge treatment exists or extrude in sketch pipe
|
||||||
|
|
||||||
// mutate the extrude node with the new fillet call
|
// mutate the extrude node with the new edge treatment call
|
||||||
extrudeDeclarator.init.body.push(filletCall)
|
extrudeDeclarator.init.body.push(edgeTreatmentCall)
|
||||||
|
|
||||||
// get path to the fillet node
|
// get path to the edge treatment node
|
||||||
pathToFilletNode = getPathToNodeOfFilletLiteral(
|
pathToEdgeTreatmentNode = getPathToNodeOfEdgeTreatmentLiteral(
|
||||||
pathToExtrudeNode,
|
pathToExtrudeNode,
|
||||||
extrudeDeclarator,
|
extrudeDeclarator,
|
||||||
firstTag
|
firstTag,
|
||||||
|
parameters
|
||||||
)
|
)
|
||||||
pathToFilletNodes.push(pathToFilletNode)
|
pathToEdgeTreatmentNodes.push(pathToEdgeTreatmentNode)
|
||||||
} else {
|
} else {
|
||||||
return new Error('Unsupported extrude type.')
|
return new Error('Unsupported extrude type.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { modifiedAst: clonedAst, pathToFilletNode: pathToFilletNodes }
|
return {
|
||||||
|
modifiedAst: clonedAst,
|
||||||
|
pathToEdgeTreatmentNode: pathToEdgeTreatmentNodes,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertRadiusIntoAst(
|
function insertParametersIntoAst(
|
||||||
ast: Program,
|
ast: Program,
|
||||||
radius: KclCommandValue
|
parameters: EdgeTreatmentParameters
|
||||||
): { ast: Program } | Error {
|
): { ast: Program } | Error {
|
||||||
try {
|
try {
|
||||||
// Validate and update AST
|
|
||||||
if (
|
|
||||||
'variableName' in radius &&
|
|
||||||
radius.variableName &&
|
|
||||||
radius.insertIndex !== undefined
|
|
||||||
) {
|
|
||||||
const newAst = structuredClone(ast)
|
const newAst = structuredClone(ast)
|
||||||
newAst.body.splice(radius.insertIndex, 0, radius.variableDeclarationAst)
|
|
||||||
return { ast: newAst }
|
// handle radius parameter
|
||||||
|
if (
|
||||||
|
parameters.type === EdgeTreatmentType.Fillet &&
|
||||||
|
'variableName' in parameters.radius &&
|
||||||
|
parameters.radius.variableName &&
|
||||||
|
parameters.radius.insertIndex !== undefined
|
||||||
|
) {
|
||||||
|
newAst.body.splice(
|
||||||
|
parameters.radius.insertIndex,
|
||||||
|
0,
|
||||||
|
parameters.radius.variableDeclarationAst
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return { ast }
|
// handle length parameter
|
||||||
|
if (
|
||||||
|
parameters.type === EdgeTreatmentType.Chamfer &&
|
||||||
|
'variableName' in parameters.length &&
|
||||||
|
parameters.length.variableName &&
|
||||||
|
parameters.length.insertIndex !== undefined
|
||||||
|
) {
|
||||||
|
newAst.body.splice(
|
||||||
|
parameters.length.insertIndex,
|
||||||
|
0,
|
||||||
|
parameters.length.variableDeclarationAst
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle upcoming parameters here (for blend, bevel, etc.)
|
||||||
|
return { ast: newAst }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return new Error(`Failed to handle AST: ${(error as Error).message}`)
|
return new Error(`Failed to handle AST: ${(error as Error).message}`)
|
||||||
}
|
}
|
||||||
@ -248,10 +295,10 @@ export function getPathToExtrudeForSegmentSelection(
|
|||||||
|
|
||||||
async function updateAstAndFocus(
|
async function updateAstAndFocus(
|
||||||
modifiedAst: Node<Program>,
|
modifiedAst: Node<Program>,
|
||||||
pathToFilletNode: Array<PathToNode>
|
pathToEdgeTreatmentNode: Array<PathToNode>
|
||||||
) {
|
) {
|
||||||
const updatedAst = await kclManager.updateAst(modifiedAst, true, {
|
const updatedAst = await kclManager.updateAst(modifiedAst, true, {
|
||||||
focusPath: pathToFilletNode,
|
focusPath: pathToEdgeTreatmentNode,
|
||||||
})
|
})
|
||||||
|
|
||||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||||
@ -340,27 +387,38 @@ function locateExtrudeDeclarator(
|
|||||||
return { extrudeDeclarator }
|
return { extrudeDeclarator }
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPathToNodeOfFilletLiteral(
|
function getPathToNodeOfEdgeTreatmentLiteral(
|
||||||
pathToExtrudeNode: PathToNode,
|
pathToExtrudeNode: PathToNode,
|
||||||
extrudeDeclarator: VariableDeclarator,
|
extrudeDeclarator: VariableDeclarator,
|
||||||
tag: Identifier | CallExpression
|
tag: Identifier | CallExpression,
|
||||||
|
parameters: EdgeTreatmentParameters
|
||||||
): PathToNode {
|
): PathToNode {
|
||||||
let pathToFilletObj: PathToNode = []
|
let pathToEdgeTreatmentObj: PathToNode = []
|
||||||
let inFillet = false
|
let inEdgeTreatment = false
|
||||||
|
|
||||||
traverse(extrudeDeclarator.init, {
|
traverse(extrudeDeclarator.init, {
|
||||||
enter(node, path) {
|
enter(node, path) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = true
|
node.type === 'CallExpression' &&
|
||||||
|
node.callee.name === parameters.type
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = true
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
if (!hasTag(node, tag)) return false
|
if (!hasTag(node, tag)) return false
|
||||||
pathToFilletObj = getPathToRadiusLiteral(node, path)
|
pathToEdgeTreatmentObj = getPathToEdgeTreatmentParameterLiteral(
|
||||||
|
node,
|
||||||
|
path,
|
||||||
|
parameters
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave(node) {
|
leave(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = false
|
node.type === 'CallExpression' &&
|
||||||
|
node.callee.name === parameters.type
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -375,7 +433,7 @@ function getPathToNodeOfFilletLiteral(
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
...pathToExtrudeNode.slice(0, indexOfPipeExpression),
|
...pathToExtrudeNode.slice(0, indexOfPipeExpression),
|
||||||
...pathToFilletObj,
|
...pathToEdgeTreatmentObj,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,23 +466,62 @@ function hasTag(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPathToRadiusLiteral(node: ObjectExpression, path: any): PathToNode {
|
function getPathToEdgeTreatmentParameterLiteral(
|
||||||
let pathToFilletObj = path
|
node: ObjectExpression,
|
||||||
|
path: any,
|
||||||
|
parameters: EdgeTreatmentParameters
|
||||||
|
): PathToNode {
|
||||||
|
let pathToEdgeTreatmentObj = path
|
||||||
|
const parameterResult = getParameterNameAndValue(parameters)
|
||||||
|
if (err(parameterResult)) return pathToEdgeTreatmentObj
|
||||||
|
const { parameterName } = parameterResult
|
||||||
|
|
||||||
node.properties.forEach((prop, index) => {
|
node.properties.forEach((prop, index) => {
|
||||||
if (prop.key.name === 'radius') {
|
if (prop.key.name === parameterName) {
|
||||||
pathToFilletObj.push(
|
pathToEdgeTreatmentObj.push(
|
||||||
['properties', 'ObjectExpression'],
|
['properties', 'ObjectExpression'],
|
||||||
[index, 'index'],
|
[index, 'index'],
|
||||||
['value', 'Property']
|
['value', 'Property']
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return pathToFilletObj
|
return pathToEdgeTreatmentObj
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParameterNameAndValue(
|
||||||
|
parameters: EdgeTreatmentParameters
|
||||||
|
): { parameterName: string; parameterValue: Expr } | Error {
|
||||||
|
if (parameters.type === EdgeTreatmentType.Fillet) {
|
||||||
|
const parameterValue =
|
||||||
|
'variableName' in parameters.radius
|
||||||
|
? parameters.radius.variableIdentifierAst
|
||||||
|
: parameters.radius.valueAst
|
||||||
|
return { parameterName: 'radius', parameterValue }
|
||||||
|
} else if (parameters.type === EdgeTreatmentType.Chamfer) {
|
||||||
|
const parameterValue =
|
||||||
|
'variableName' in parameters.length
|
||||||
|
? parameters.length.variableIdentifierAst
|
||||||
|
: parameters.length.valueAst
|
||||||
|
return { parameterName: 'length', parameterValue }
|
||||||
|
} else {
|
||||||
|
return new Error('Unsupported edge treatment type}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type Guards
|
||||||
|
function isEdgeTreatmentType(name: string): name is EdgeTreatmentType {
|
||||||
|
return name === EdgeTreatmentType.Chamfer || name === EdgeTreatmentType.Fillet
|
||||||
|
}
|
||||||
|
function isEdgeType(name: string): name is EdgeTypes {
|
||||||
|
return (
|
||||||
|
name === 'getNextAdjacentEdge' ||
|
||||||
|
name === 'getPreviousAdjacentEdge' ||
|
||||||
|
name === 'getOppositeEdge'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Button states
|
// Button states
|
||||||
|
export const hasValidEdgeTreatmentSelection = ({
|
||||||
export const hasValidFilletSelection = ({
|
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
ast,
|
ast,
|
||||||
code,
|
code,
|
||||||
@ -433,11 +530,14 @@ export const hasValidFilletSelection = ({
|
|||||||
ast: Node<Program>
|
ast: Node<Program>
|
||||||
code: string
|
code: string
|
||||||
}) => {
|
}) => {
|
||||||
// check if there is anything filletable in the scene
|
// check if there is anything valid for the edge treatment in the scene
|
||||||
let extrudeExists = false
|
let extrudeExists = false
|
||||||
traverse(ast, {
|
traverse(ast, {
|
||||||
enter(node) {
|
enter(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'extrude') {
|
if (
|
||||||
|
node.type === 'CallExpression' &&
|
||||||
|
(node.callee.name === 'extrude' || node.callee.name === 'revolve')
|
||||||
|
) {
|
||||||
extrudeExists = true
|
extrudeExists = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -494,32 +594,39 @@ export const hasValidFilletSelection = ({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// check if tag is used in fillet
|
// check if tag is used in edge treatment
|
||||||
if (tagExists && selection.artifact) {
|
if (tagExists && selection.artifact) {
|
||||||
// create tag call
|
// create tag call
|
||||||
let tagCall: Expr = getEdgeTagCall(tag, selection.artifact)
|
let tagCall: Expr = getEdgeTagCall(tag, selection.artifact)
|
||||||
|
|
||||||
// check if tag is used in fillet
|
// check if tag is used in edge treatment
|
||||||
let inFillet = false
|
let inEdgeTreatment = false
|
||||||
let tagUsedInFillet = false
|
let tagUsedInEdgeTreatment = false
|
||||||
|
|
||||||
traverse(ast, {
|
traverse(ast, {
|
||||||
enter(node) {
|
enter(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = true
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = true
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
if (hasTag(node, tagCall)) {
|
if (hasTag(node, tagCall)) {
|
||||||
tagUsedInFillet = true
|
tagUsedInEdgeTreatment = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave(node) {
|
leave(node) {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = false
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (tagUsedInFillet) {
|
if (tagUsedInEdgeTreatment) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -533,7 +640,7 @@ type EdgeTypes =
|
|||||||
| 'getPreviousAdjacentEdge'
|
| 'getPreviousAdjacentEdge'
|
||||||
| 'getOppositeEdge'
|
| 'getOppositeEdge'
|
||||||
|
|
||||||
export const isTagUsedInFillet = ({
|
export const isTagUsedInEdgeTreatment = ({
|
||||||
ast,
|
ast,
|
||||||
callExp,
|
callExp,
|
||||||
}: {
|
}: {
|
||||||
@ -543,16 +650,21 @@ export const isTagUsedInFillet = ({
|
|||||||
const tag = getTagFromCallExpression(callExp)
|
const tag = getTagFromCallExpression(callExp)
|
||||||
if (err(tag)) return []
|
if (err(tag)) return []
|
||||||
|
|
||||||
let inFillet = false
|
let inEdgeTreatment = false
|
||||||
let inObj = false
|
let inObj = false
|
||||||
let inTagHelper: EdgeTypes | '' = ''
|
let inTagHelper: EdgeTypes | '' = ''
|
||||||
const edges: Array<EdgeTypes> = []
|
const edges: Array<EdgeTypes> = []
|
||||||
|
|
||||||
traverse(ast, {
|
traverse(ast, {
|
||||||
enter: (node) => {
|
enter: (node) => {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
// Check if we are entering an edge treatment call
|
||||||
inFillet = true
|
if (
|
||||||
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = true
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
node.properties.forEach((prop) => {
|
node.properties.forEach((prop) => {
|
||||||
if (
|
if (
|
||||||
prop.key.name === 'tags' &&
|
prop.key.name === 'tags' &&
|
||||||
@ -564,17 +676,15 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
node.type === 'CallExpression' &&
|
node.type === 'CallExpression' &&
|
||||||
(node.callee.name === 'getOppositeEdge' ||
|
isEdgeType(node.callee.name)
|
||||||
node.callee.name === 'getNextAdjacentEdge' ||
|
|
||||||
node.callee.name === 'getPreviousAdjacentEdge')
|
|
||||||
) {
|
) {
|
||||||
inTagHelper = node.callee.name
|
inTagHelper = node.callee.name
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
!inTagHelper &&
|
!inTagHelper &&
|
||||||
node.type === 'Identifier' &&
|
node.type === 'Identifier' &&
|
||||||
node.name === tag
|
node.name === tag
|
||||||
@ -583,7 +693,7 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
inTagHelper &&
|
inTagHelper &&
|
||||||
node.type === 'Identifier' &&
|
node.type === 'Identifier' &&
|
||||||
node.name === tag
|
node.name === tag
|
||||||
@ -592,10 +702,13 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave: (node) => {
|
leave: (node) => {
|
||||||
if (node.type === 'CallExpression' && node.callee.name === 'fillet') {
|
if (
|
||||||
inFillet = false
|
node.type === 'CallExpression' &&
|
||||||
|
isEdgeTreatmentType(node.callee.name)
|
||||||
|
) {
|
||||||
|
inEdgeTreatment = false
|
||||||
}
|
}
|
||||||
if (inFillet && node.type === 'ObjectExpression') {
|
if (inEdgeTreatment && node.type === 'ObjectExpression') {
|
||||||
node.properties.forEach((prop) => {
|
node.properties.forEach((prop) => {
|
||||||
if (
|
if (
|
||||||
prop.key.name === 'tags' &&
|
prop.key.name === 'tags' &&
|
||||||
@ -607,11 +720,9 @@ export const isTagUsedInFillet = ({
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inObj &&
|
inObj &&
|
||||||
inFillet &&
|
inEdgeTreatment &&
|
||||||
node.type === 'CallExpression' &&
|
node.type === 'CallExpression' &&
|
||||||
(node.callee.name === 'getOppositeEdge' ||
|
isEdgeType(node.callee.name)
|
||||||
node.callee.name === 'getNextAdjacentEdge' ||
|
|
||||||
node.callee.name === 'getPreviousAdjacentEdge')
|
|
||||||
) {
|
) {
|
||||||
inTagHelper = ''
|
inTagHelper = ''
|
||||||
}
|
}
|
@ -628,6 +628,18 @@ sketch002 = startSketchOn(extrude001, $seg01)
|
|||||||
const extrudable = doesSceneHaveSweepableSketch(ast)
|
const extrudable = doesSceneHaveSweepableSketch(ast)
|
||||||
expect(extrudable).toBeTruthy()
|
expect(extrudable).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
it('finds sketch001 and sketch002 pipes to be lofted', async () => {
|
||||||
|
const exampleCode = `sketch001 = startSketchOn('XZ')
|
||||||
|
|> circle({ center = [0, 0], radius = 1 }, %)
|
||||||
|
plane001 = offsetPlane('XZ', 2)
|
||||||
|
sketch002 = startSketchOn(plane001)
|
||||||
|
|> circle({ center = [0, 0], radius = 3 }, %)
|
||||||
|
`
|
||||||
|
const ast = parse(exampleCode)
|
||||||
|
if (err(ast)) throw ast
|
||||||
|
const extrudable = doesSceneHaveSweepableSketch(ast, 2)
|
||||||
|
expect(extrudable).toBeTruthy()
|
||||||
|
})
|
||||||
it('find sketch002 NOT pipe to be extruded', async () => {
|
it('find sketch002 NOT pipe to be extruded', async () => {
|
||||||
const exampleCode = `sketch001 = startSketchOn('XZ')
|
const exampleCode = `sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([3.29, 7.86], %)
|
|> startProfileAt([3.29, 7.86], %)
|
||||||
|
@ -975,7 +975,9 @@ export function hasSketchPipeBeenExtruded(selection: Selection, ast: Program) {
|
|||||||
if (
|
if (
|
||||||
node.type === 'CallExpression' &&
|
node.type === 'CallExpression' &&
|
||||||
node.callee.type === 'Identifier' &&
|
node.callee.type === 'Identifier' &&
|
||||||
(node.callee.name === 'extrude' || node.callee.name === 'revolve') &&
|
(node.callee.name === 'extrude' ||
|
||||||
|
node.callee.name === 'revolve' ||
|
||||||
|
node.callee.name === 'loft') &&
|
||||||
node.arguments?.[1]?.type === 'Identifier' &&
|
node.arguments?.[1]?.type === 'Identifier' &&
|
||||||
node.arguments[1].name === varDec.id.name
|
node.arguments[1].name === varDec.id.name
|
||||||
) {
|
) {
|
||||||
@ -988,7 +990,7 @@ export function hasSketchPipeBeenExtruded(selection: Selection, ast: Program) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** File must contain at least one sketch that has not been extruded already */
|
/** File must contain at least one sketch that has not been extruded already */
|
||||||
export function doesSceneHaveSweepableSketch(ast: Node<Program>) {
|
export function doesSceneHaveSweepableSketch(ast: Node<Program>, count = 1) {
|
||||||
const theMap: any = {}
|
const theMap: any = {}
|
||||||
traverse(ast as any, {
|
traverse(ast as any, {
|
||||||
enter(node) {
|
enter(node) {
|
||||||
@ -1037,7 +1039,7 @@ export function doesSceneHaveSweepableSketch(ast: Node<Program>) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return Object.keys(theMap).length > 0
|
return Object.keys(theMap).length >= count
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getObjExprProperty(
|
export function getObjExprProperty(
|
||||||
|
@ -63,7 +63,7 @@ log(5, myVar)
|
|||||||
})
|
})
|
||||||
it('function declaration with call', () => {
|
it('function declaration with call', () => {
|
||||||
const code = [
|
const code = [
|
||||||
'fn funcN = (a, b) => {',
|
'fn funcN(a, b) {',
|
||||||
' return a + b',
|
' return a + b',
|
||||||
'}',
|
'}',
|
||||||
'theVar = 60',
|
'theVar = 60',
|
||||||
@ -101,7 +101,7 @@ log(5, myVar)
|
|||||||
})
|
})
|
||||||
it('recast BinaryExpression piped into CallExpression', () => {
|
it('recast BinaryExpression piped into CallExpression', () => {
|
||||||
const code = [
|
const code = [
|
||||||
'fn myFn = (a) => {',
|
'fn myFn(a) {',
|
||||||
' return a + 1',
|
' return a + 1',
|
||||||
'}',
|
'}',
|
||||||
'myVar = 5 + 1',
|
'myVar = 5 + 1',
|
||||||
@ -245,7 +245,7 @@ key = 'c'
|
|||||||
expect(recasted).toBe(code)
|
expect(recasted).toBe(code)
|
||||||
})
|
})
|
||||||
it('comments in a fn block', () => {
|
it('comments in a fn block', () => {
|
||||||
const code = `fn myFn = () => {
|
const code = `fn myFn() {
|
||||||
// this is a comment
|
// this is a comment
|
||||||
yo = { a = { b = { c = '123' } } }
|
yo = { a = { b = { c = '123' } } }
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ Map {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
"range": [
|
"range": [
|
||||||
37,
|
12,
|
||||||
64,
|
31,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -1,382 +0,0 @@
|
|||||||
import { lexer, initPromise } from './wasm'
|
|
||||||
import { err } from 'lib/trap'
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
await initPromise
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('testing lexer', () => {
|
|
||||||
it('async lexer works too', async () => {
|
|
||||||
const code = '1 + 2'
|
|
||||||
const code2 = `const yo = {key: 'value'}`
|
|
||||||
const code3 = `const yo = 45 /* this is a comment
|
|
||||||
const ya = 6 */
|
|
||||||
const yi=45`
|
|
||||||
expect(lexer(code)).toEqual(lexer(code))
|
|
||||||
expect(lexer(code2)).toEqual(lexer(code2))
|
|
||||||
expect(lexer(code3)).toEqual(lexer(code3))
|
|
||||||
})
|
|
||||||
it('test lexer', () => {
|
|
||||||
expect(stringSummaryLexer('1 + 2')).toEqual([
|
|
||||||
"number '1' from 0 to 1",
|
|
||||||
"whitespace ' ' from 1 to 3",
|
|
||||||
"operator '+' from 3 to 4",
|
|
||||||
"whitespace ' ' from 4 to 5",
|
|
||||||
"number '2' from 5 to 6",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer('54 + 22500 + 6')).toEqual([
|
|
||||||
"number '54' from 0 to 2",
|
|
||||||
"whitespace ' ' from 2 to 3",
|
|
||||||
"operator '+' from 3 to 4",
|
|
||||||
"whitespace ' ' from 4 to 5",
|
|
||||||
"number '22500' from 5 to 10",
|
|
||||||
"whitespace ' ' from 10 to 11",
|
|
||||||
"operator '+' from 11 to 12",
|
|
||||||
"whitespace ' ' from 12 to 13",
|
|
||||||
"number '6' from 13 to 14",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer('a + bo + t5 - 6')).toEqual([
|
|
||||||
"word 'a' from 0 to 1",
|
|
||||||
"whitespace ' ' from 1 to 2",
|
|
||||||
"operator '+' from 2 to 3",
|
|
||||||
"whitespace ' ' from 3 to 4",
|
|
||||||
"word 'bo' from 4 to 6",
|
|
||||||
"whitespace ' ' from 6 to 7",
|
|
||||||
"operator '+' from 7 to 8",
|
|
||||||
"whitespace ' ' from 8 to 9",
|
|
||||||
"word 't5' from 9 to 11",
|
|
||||||
"whitespace ' ' from 11 to 12",
|
|
||||||
"operator '-' from 12 to 13",
|
|
||||||
"whitespace ' ' from 13 to 14",
|
|
||||||
"number '6' from 14 to 15",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer('a + "a str" - 6')).toEqual([
|
|
||||||
"word 'a' from 0 to 1",
|
|
||||||
"whitespace ' ' from 1 to 2",
|
|
||||||
"operator '+' from 2 to 3",
|
|
||||||
"whitespace ' ' from 3 to 4",
|
|
||||||
'string \'"a str"\' from 4 to 11',
|
|
||||||
"whitespace ' ' from 11 to 12",
|
|
||||||
"operator '-' from 12 to 13",
|
|
||||||
"whitespace ' ' from 13 to 14",
|
|
||||||
"number '6' from 14 to 15",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer("a + 'str'")).toEqual([
|
|
||||||
"word 'a' from 0 to 1",
|
|
||||||
"whitespace ' ' from 1 to 2",
|
|
||||||
"operator '+' from 2 to 3",
|
|
||||||
"whitespace ' ' from 3 to 4",
|
|
||||||
"string ''str'' from 4 to 9",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer("a +'str'")).toEqual([
|
|
||||||
"word 'a' from 0 to 1",
|
|
||||||
"whitespace ' ' from 1 to 2",
|
|
||||||
"operator '+' from 2 to 3",
|
|
||||||
"string ''str'' from 3 to 8",
|
|
||||||
])
|
|
||||||
|
|
||||||
expect(stringSummaryLexer('a + (sick)')).toEqual([
|
|
||||||
"word 'a' from 0 to 1",
|
|
||||||
"whitespace ' ' from 1 to 2",
|
|
||||||
"operator '+' from 2 to 3",
|
|
||||||
"whitespace ' ' from 3 to 4",
|
|
||||||
"brace '(' from 4 to 5",
|
|
||||||
"word 'sick' from 5 to 9",
|
|
||||||
"brace ')' from 9 to 10",
|
|
||||||
])
|
|
||||||
|
|
||||||
expect(stringSummaryLexer('a + { sick}')).toEqual([
|
|
||||||
"word 'a' from 0 to 1",
|
|
||||||
"whitespace ' ' from 1 to 2",
|
|
||||||
"operator '+' from 2 to 3",
|
|
||||||
"whitespace ' ' from 3 to 4",
|
|
||||||
"brace '{' from 4 to 5",
|
|
||||||
"whitespace ' ' from 5 to 6",
|
|
||||||
"word 'sick' from 6 to 10",
|
|
||||||
"brace '}' from 10 to 11",
|
|
||||||
])
|
|
||||||
|
|
||||||
expect(stringSummaryLexer("log('hi')")).toEqual([
|
|
||||||
"word 'log' from 0 to 3",
|
|
||||||
"brace '(' from 3 to 4",
|
|
||||||
"string ''hi'' from 4 to 8",
|
|
||||||
"brace ')' from 8 to 9",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer("log('hi', 'hello')")).toEqual([
|
|
||||||
"word 'log' from 0 to 3",
|
|
||||||
"brace '(' from 3 to 4",
|
|
||||||
"string ''hi'' from 4 to 8",
|
|
||||||
"comma ',' from 8 to 9",
|
|
||||||
"whitespace ' ' from 9 to 10",
|
|
||||||
"string ''hello'' from 10 to 17",
|
|
||||||
"brace ')' from 17 to 18",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer('fn funcName = (param1, param2) => {}')).toEqual([
|
|
||||||
"keyword 'fn' from 0 to 2",
|
|
||||||
"whitespace ' ' from 2 to 3",
|
|
||||||
"word 'funcName' from 3 to 11",
|
|
||||||
"whitespace ' ' from 11 to 12",
|
|
||||||
"operator '=' from 12 to 13",
|
|
||||||
"whitespace ' ' from 13 to 14",
|
|
||||||
"brace '(' from 14 to 15",
|
|
||||||
"word 'param1' from 15 to 21",
|
|
||||||
"comma ',' from 21 to 22",
|
|
||||||
"whitespace ' ' from 22 to 23",
|
|
||||||
"word 'param2' from 23 to 29",
|
|
||||||
"brace ')' from 29 to 30",
|
|
||||||
"whitespace ' ' from 30 to 31",
|
|
||||||
"operator '=>' from 31 to 33",
|
|
||||||
"whitespace ' ' from 33 to 34",
|
|
||||||
"brace '{' from 34 to 35",
|
|
||||||
"brace '}' from 35 to 36",
|
|
||||||
])
|
|
||||||
})
|
|
||||||
it('test negative and decimal numbers', () => {
|
|
||||||
expect(stringSummaryLexer('-1')).toEqual([
|
|
||||||
"operator '-' from 0 to 1",
|
|
||||||
"number '1' from 1 to 2",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer('-1.5')).toEqual([
|
|
||||||
"operator '-' from 0 to 1",
|
|
||||||
"number '1.5' from 1 to 4",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer('1.5')).toEqual([
|
|
||||||
"number '1.5' from 0 to 3",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer('1.5 + 2.5')).toEqual([
|
|
||||||
"number '1.5' from 0 to 3",
|
|
||||||
"whitespace ' ' from 3 to 4",
|
|
||||||
"operator '+' from 4 to 5",
|
|
||||||
"whitespace ' ' from 5 to 6",
|
|
||||||
"number '2.5' from 6 to 9",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer('1.5 - 2.5')).toEqual([
|
|
||||||
"number '1.5' from 0 to 3",
|
|
||||||
"whitespace ' ' from 3 to 4",
|
|
||||||
"operator '-' from 4 to 5",
|
|
||||||
"whitespace ' ' from 5 to 6",
|
|
||||||
"number '2.5' from 6 to 9",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer('1.5 + -2.5')).toEqual([
|
|
||||||
"number '1.5' from 0 to 3",
|
|
||||||
"whitespace ' ' from 3 to 4",
|
|
||||||
"operator '+' from 4 to 5",
|
|
||||||
"whitespace ' ' from 5 to 6",
|
|
||||||
"operator '-' from 6 to 7",
|
|
||||||
"number '2.5' from 7 to 10",
|
|
||||||
])
|
|
||||||
expect(stringSummaryLexer('-1.5 + 2.5')).toEqual([
|
|
||||||
"operator '-' from 0 to 1",
|
|
||||||
"number '1.5' from 1 to 4",
|
|
||||||
"whitespace ' ' from 4 to 5",
|
|
||||||
"operator '+' from 5 to 6",
|
|
||||||
"whitespace ' ' from 6 to 7",
|
|
||||||
"number '2.5' from 7 to 10",
|
|
||||||
])
|
|
||||||
})
|
|
||||||
it('testing piping operator', () => {
|
|
||||||
const result = stringSummaryLexer(`sketch mySketch {
|
|
||||||
lineTo(2, 3)
|
|
||||||
} |> rx(45, %)`)
|
|
||||||
expect(result).toEqual([
|
|
||||||
"type 'sketch' from 0 to 6",
|
|
||||||
"whitespace ' ' from 6 to 7",
|
|
||||||
"word 'mySketch' from 7 to 15",
|
|
||||||
"whitespace ' ' from 15 to 16",
|
|
||||||
"brace '{' from 16 to 17",
|
|
||||||
"whitespace '\n ' from 17 to 24",
|
|
||||||
"word 'lineTo' from 24 to 30",
|
|
||||||
"brace '(' from 30 to 31",
|
|
||||||
"number '2' from 31 to 32",
|
|
||||||
"comma ',' from 32 to 33",
|
|
||||||
"whitespace ' ' from 33 to 34",
|
|
||||||
"number '3' from 34 to 35",
|
|
||||||
"brace ')' from 35 to 36",
|
|
||||||
"whitespace '\n ' from 36 to 41",
|
|
||||||
"brace '}' from 41 to 42",
|
|
||||||
"whitespace ' ' from 42 to 43",
|
|
||||||
"operator '|>' from 43 to 45",
|
|
||||||
"whitespace ' ' from 45 to 46",
|
|
||||||
"word 'rx' from 46 to 48",
|
|
||||||
"brace '(' from 48 to 49",
|
|
||||||
"number '45' from 49 to 51",
|
|
||||||
"comma ',' from 51 to 52",
|
|
||||||
"whitespace ' ' from 52 to 53",
|
|
||||||
"operator '%' from 53 to 54",
|
|
||||||
"brace ')' from 54 to 55",
|
|
||||||
])
|
|
||||||
})
|
|
||||||
it('testing array declaration', () => {
|
|
||||||
const result = stringSummaryLexer(`const yo = [1, 2]`)
|
|
||||||
expect(result).toEqual([
|
|
||||||
"keyword 'const' from 0 to 5",
|
|
||||||
"whitespace ' ' from 5 to 6",
|
|
||||||
"word 'yo' from 6 to 8",
|
|
||||||
"whitespace ' ' from 8 to 9",
|
|
||||||
"operator '=' from 9 to 10",
|
|
||||||
"whitespace ' ' from 10 to 11",
|
|
||||||
"brace '[' from 11 to 12",
|
|
||||||
"number '1' from 12 to 13",
|
|
||||||
"comma ',' from 13 to 14",
|
|
||||||
"whitespace ' ' from 14 to 15",
|
|
||||||
"number '2' from 15 to 16",
|
|
||||||
"brace ']' from 16 to 17",
|
|
||||||
])
|
|
||||||
})
|
|
||||||
it('testing object declaration', () => {
|
|
||||||
const result = stringSummaryLexer(`const yo = {key: 'value'}`)
|
|
||||||
expect(result).toEqual([
|
|
||||||
"keyword 'const' from 0 to 5",
|
|
||||||
"whitespace ' ' from 5 to 6",
|
|
||||||
"word 'yo' from 6 to 8",
|
|
||||||
"whitespace ' ' from 8 to 9",
|
|
||||||
"operator '=' from 9 to 10",
|
|
||||||
"whitespace ' ' from 10 to 11",
|
|
||||||
"brace '{' from 11 to 12",
|
|
||||||
"word 'key' from 12 to 15",
|
|
||||||
"colon ':' from 15 to 16",
|
|
||||||
"whitespace ' ' from 16 to 17",
|
|
||||||
"string ''value'' from 17 to 24",
|
|
||||||
"brace '}' from 24 to 25",
|
|
||||||
])
|
|
||||||
})
|
|
||||||
it('testing object property access', () => {
|
|
||||||
const result = stringSummaryLexer(`const yo = {key: 'value'}
|
|
||||||
const prop = yo.key
|
|
||||||
const prop2 = yo['key']
|
|
||||||
const key = 'key'
|
|
||||||
const prop3 = yo[key]`)
|
|
||||||
expect(result).toEqual([
|
|
||||||
"keyword 'const' from 0 to 5",
|
|
||||||
"whitespace ' ' from 5 to 6",
|
|
||||||
"word 'yo' from 6 to 8",
|
|
||||||
"whitespace ' ' from 8 to 9",
|
|
||||||
"operator '=' from 9 to 10",
|
|
||||||
"whitespace ' ' from 10 to 11",
|
|
||||||
"brace '{' from 11 to 12",
|
|
||||||
"word 'key' from 12 to 15",
|
|
||||||
"colon ':' from 15 to 16",
|
|
||||||
"whitespace ' ' from 16 to 17",
|
|
||||||
"string ''value'' from 17 to 24",
|
|
||||||
"brace '}' from 24 to 25",
|
|
||||||
"whitespace '\n' from 25 to 26",
|
|
||||||
"keyword 'const' from 26 to 31",
|
|
||||||
"whitespace ' ' from 31 to 32",
|
|
||||||
"word 'prop' from 32 to 36",
|
|
||||||
"whitespace ' ' from 36 to 37",
|
|
||||||
"operator '=' from 37 to 38",
|
|
||||||
"whitespace ' ' from 38 to 39",
|
|
||||||
"word 'yo' from 39 to 41",
|
|
||||||
"period '.' from 41 to 42",
|
|
||||||
"word 'key' from 42 to 45",
|
|
||||||
"whitespace '\n' from 45 to 46",
|
|
||||||
"keyword 'const' from 46 to 51",
|
|
||||||
"whitespace ' ' from 51 to 52",
|
|
||||||
"word 'prop2' from 52 to 57",
|
|
||||||
"whitespace ' ' from 57 to 58",
|
|
||||||
"operator '=' from 58 to 59",
|
|
||||||
"whitespace ' ' from 59 to 60",
|
|
||||||
"word 'yo' from 60 to 62",
|
|
||||||
"brace '[' from 62 to 63",
|
|
||||||
"string ''key'' from 63 to 68",
|
|
||||||
"brace ']' from 68 to 69",
|
|
||||||
"whitespace '\n' from 69 to 70",
|
|
||||||
"keyword 'const' from 70 to 75",
|
|
||||||
"whitespace ' ' from 75 to 76",
|
|
||||||
"word 'key' from 76 to 79",
|
|
||||||
"whitespace ' ' from 79 to 80",
|
|
||||||
"operator '=' from 80 to 81",
|
|
||||||
"whitespace ' ' from 81 to 82",
|
|
||||||
"string ''key'' from 82 to 87",
|
|
||||||
"whitespace '\n' from 87 to 88",
|
|
||||||
"keyword 'const' from 88 to 93",
|
|
||||||
"whitespace ' ' from 93 to 94",
|
|
||||||
"word 'prop3' from 94 to 99",
|
|
||||||
"whitespace ' ' from 99 to 100",
|
|
||||||
"operator '=' from 100 to 101",
|
|
||||||
"whitespace ' ' from 101 to 102",
|
|
||||||
"word 'yo' from 102 to 104",
|
|
||||||
"brace '[' from 104 to 105",
|
|
||||||
"word 'key' from 105 to 108",
|
|
||||||
"brace ']' from 108 to 109",
|
|
||||||
])
|
|
||||||
})
|
|
||||||
it('testing tokenising line comments', () => {
|
|
||||||
const result = stringSummaryLexer(`const yo = 45 // this is a comment
|
|
||||||
const yo = 6`)
|
|
||||||
expect(result).toEqual([
|
|
||||||
"keyword 'const' from 0 to 5",
|
|
||||||
"whitespace ' ' from 5 to 6",
|
|
||||||
"word 'yo' from 6 to 8",
|
|
||||||
"whitespace ' ' from 8 to 9",
|
|
||||||
"operator '=' from 9 to 10",
|
|
||||||
"whitespace ' ' from 10 to 11",
|
|
||||||
"number '45' from 11 to 13",
|
|
||||||
"whitespace ' ' from 13 to 14",
|
|
||||||
"lineComment '// this is a comment' from 14 to 34",
|
|
||||||
"whitespace '\n' from 34 to 35",
|
|
||||||
"keyword 'const' from 35 to 40",
|
|
||||||
"whitespace ' ' from 40 to 41",
|
|
||||||
"word 'yo' from 41 to 43",
|
|
||||||
"whitespace ' ' from 43 to 44",
|
|
||||||
"operator '=' from 44 to 45",
|
|
||||||
"whitespace ' ' from 45 to 46",
|
|
||||||
"number '6' from 46 to 47",
|
|
||||||
])
|
|
||||||
})
|
|
||||||
it('testing tokenising line comments by itself', () => {
|
|
||||||
const result = stringSummaryLexer(`log('hi')
|
|
||||||
// comment on a line by itself
|
|
||||||
const yo=45`)
|
|
||||||
expect(result).toEqual([
|
|
||||||
"word 'log' from 0 to 3",
|
|
||||||
"brace '(' from 3 to 4",
|
|
||||||
"string ''hi'' from 4 to 8",
|
|
||||||
"brace ')' from 8 to 9",
|
|
||||||
"whitespace '\n' from 9 to 10",
|
|
||||||
"lineComment '// comment on a line by itself' from 10 to 40",
|
|
||||||
"whitespace '\n' from 40 to 41",
|
|
||||||
"keyword 'const' from 41 to 46",
|
|
||||||
"whitespace ' ' from 46 to 47",
|
|
||||||
"word 'yo' from 47 to 49",
|
|
||||||
"operator '=' from 49 to 50",
|
|
||||||
"number '45' from 50 to 52",
|
|
||||||
])
|
|
||||||
})
|
|
||||||
it('testing tokenising block comments', () => {
|
|
||||||
const result = stringSummaryLexer(`const yo = 45 /* this is a comment
|
|
||||||
const ya = 6 */
|
|
||||||
const yi=45`)
|
|
||||||
expect(result).toEqual([
|
|
||||||
"keyword 'const' from 0 to 5",
|
|
||||||
"whitespace ' ' from 5 to 6",
|
|
||||||
"word 'yo' from 6 to 8",
|
|
||||||
"whitespace ' ' from 8 to 9",
|
|
||||||
"operator '=' from 9 to 10",
|
|
||||||
"whitespace ' ' from 10 to 11",
|
|
||||||
"number '45' from 11 to 13",
|
|
||||||
"whitespace ' ' from 13 to 14",
|
|
||||||
`blockComment '/* this is a comment
|
|
||||||
const ya = 6 */' from 14 to 50`,
|
|
||||||
"whitespace '\n' from 50 to 51",
|
|
||||||
"keyword 'const' from 51 to 56",
|
|
||||||
"whitespace ' ' from 56 to 57",
|
|
||||||
"word 'yi' from 57 to 59",
|
|
||||||
"operator '=' from 59 to 60",
|
|
||||||
"number '45' from 60 to 62",
|
|
||||||
])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
|
|
||||||
const stringSummaryLexer = (input: string) => {
|
|
||||||
const tokens = lexer(input)
|
|
||||||
if (err(tokens)) return []
|
|
||||||
return tokens.map(
|
|
||||||
({ type, value, start, end }) =>
|
|
||||||
`${type.padEnd(12, ' ')} ${`'${value}'`.padEnd(10, ' ')} from ${String(
|
|
||||||
start
|
|
||||||
).padEnd(3, ' ')} to ${end}`
|
|
||||||
)
|
|
||||||
}
|
|
@ -3,7 +3,6 @@ import init, {
|
|||||||
recast_wasm,
|
recast_wasm,
|
||||||
execute_wasm,
|
execute_wasm,
|
||||||
kcl_lint,
|
kcl_lint,
|
||||||
lexer_wasm,
|
|
||||||
modify_ast_for_sketch_wasm,
|
modify_ast_for_sketch_wasm,
|
||||||
is_points_ccw,
|
is_points_ccw,
|
||||||
get_tangential_arc_to_info,
|
get_tangential_arc_to_info,
|
||||||
@ -24,7 +23,6 @@ import { EngineCommandManager } from './std/engineConnection'
|
|||||||
import { Discovered } from '../wasm-lib/kcl/bindings/Discovered'
|
import { Discovered } from '../wasm-lib/kcl/bindings/Discovered'
|
||||||
import { KclValue } from '../wasm-lib/kcl/bindings/KclValue'
|
import { KclValue } from '../wasm-lib/kcl/bindings/KclValue'
|
||||||
import type { Program } from '../wasm-lib/kcl/bindings/Program'
|
import type { Program } from '../wasm-lib/kcl/bindings/Program'
|
||||||
import type { Token } from '../wasm-lib/kcl/bindings/Token'
|
|
||||||
import { Coords2d } from './std/sketch'
|
import { Coords2d } from './std/sketch'
|
||||||
import { fileSystemManager } from 'lang/std/fileSystemManager'
|
import { fileSystemManager } from 'lang/std/fileSystemManager'
|
||||||
import { CoreDumpInfo } from 'wasm-lib/kcl/bindings/CoreDumpInfo'
|
import { CoreDumpInfo } from 'wasm-lib/kcl/bindings/CoreDumpInfo'
|
||||||
@ -507,10 +505,6 @@ export const modifyGrid = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function lexer(str: string): Token[] | Error {
|
|
||||||
return lexer_wasm(str)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const modifyAstForSketch = async (
|
export const modifyAstForSketch = async (
|
||||||
engineCommandManager: EngineCommandManager,
|
engineCommandManager: EngineCommandManager,
|
||||||
ast: Node<Program>,
|
ast: Node<Program>,
|
||||||
|
@ -31,6 +31,9 @@ export type ModelingCommandSchema = {
|
|||||||
// result: (typeof EXTRUSION_RESULTS)[number]
|
// result: (typeof EXTRUSION_RESULTS)[number]
|
||||||
distance: KclCommandValue
|
distance: KclCommandValue
|
||||||
}
|
}
|
||||||
|
Loft: {
|
||||||
|
selection: Selections
|
||||||
|
}
|
||||||
Revolve: {
|
Revolve: {
|
||||||
selection: Selections
|
selection: Selections
|
||||||
angle: KclCommandValue
|
angle: KclCommandValue
|
||||||
@ -260,6 +263,20 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loft: {
|
||||||
|
description: 'Create a 3D body by blending between two or more sketches',
|
||||||
|
icon: 'loft',
|
||||||
|
needsReview: true,
|
||||||
|
args: {
|
||||||
|
selection: {
|
||||||
|
inputType: 'selection',
|
||||||
|
selectionTypes: ['solid2D'],
|
||||||
|
multiple: true,
|
||||||
|
required: true,
|
||||||
|
skip: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
// TODO: Update this configuration, copied from extrude for MVP of revolve, specifically the args.selection
|
// TODO: Update this configuration, copied from extrude for MVP of revolve, specifically the args.selection
|
||||||
Revolve: {
|
Revolve: {
|
||||||
description: 'Create a 3D body by rotating a sketch region about an axis.',
|
description: 'Create a 3D body by rotating a sketch region about an axis.',
|
||||||
|
@ -52,6 +52,7 @@ export const ONBOARDING_PROJECT_NAME = 'Tutorial Project $nn'
|
|||||||
export const KCL_DEFAULT_CONSTANT_PREFIXES = {
|
export const KCL_DEFAULT_CONSTANT_PREFIXES = {
|
||||||
SKETCH: 'sketch',
|
SKETCH: 'sketch',
|
||||||
EXTRUDE: 'extrude',
|
EXTRUDE: 'extrude',
|
||||||
|
LOFT: 'loft',
|
||||||
SEGMENT: 'seg',
|
SEGMENT: 'seg',
|
||||||
REVOLVE: 'revolve',
|
REVOLVE: 'revolve',
|
||||||
PLANE: 'plane',
|
PLANE: 'plane',
|
||||||
|
@ -46,9 +46,21 @@ describe('desktop utilities', () => {
|
|||||||
'project-without-kcl-files',
|
'project-without-kcl-files',
|
||||||
'another-valid-project',
|
'another-valid-project',
|
||||||
],
|
],
|
||||||
'/test/projects/valid-project': ['file1.kcl', 'file2.stp'],
|
'/test/projects/valid-project': [
|
||||||
|
'file1.kcl',
|
||||||
|
'file2.stp',
|
||||||
|
'file3.kcl',
|
||||||
|
'directory1',
|
||||||
|
],
|
||||||
|
'/test/projects/valid-project/directory1': [],
|
||||||
'/test/projects/project-without-kcl-files': ['file3.glb'],
|
'/test/projects/project-without-kcl-files': ['file3.glb'],
|
||||||
'/test/projects/another-valid-project': ['file4.kcl'],
|
'/test/projects/another-valid-project': [
|
||||||
|
'file4.kcl',
|
||||||
|
'directory2',
|
||||||
|
'directory3',
|
||||||
|
],
|
||||||
|
'/test/projects/another-valid-project/directory2': [],
|
||||||
|
'/test/projects/another-valid-project/directory3': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -119,6 +131,15 @@ describe('desktop utilities', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('correctly counts directories and files', async () => {
|
||||||
|
const projects = await listProjects(mockConfig)
|
||||||
|
// Verify that directories and files are counted correctly
|
||||||
|
expect(projects[0].directory_count).toEqual(1)
|
||||||
|
expect(projects[0].kcl_file_count).toEqual(2)
|
||||||
|
expect(projects[1].directory_count).toEqual(2)
|
||||||
|
expect(projects[1].kcl_file_count).toEqual(1)
|
||||||
|
})
|
||||||
|
|
||||||
it('handles empty project directory', async () => {
|
it('handles empty project directory', async () => {
|
||||||
// Adjust mockFileSystem to simulate empty directory
|
// Adjust mockFileSystem to simulate empty directory
|
||||||
mockFileSystem['/test/projects'] = []
|
mockFileSystem['/test/projects'] = []
|
||||||
|
@ -307,7 +307,10 @@ const directoryCount = (file: FileEntry) => {
|
|||||||
let count = 0
|
let count = 0
|
||||||
if (file.children) {
|
if (file.children) {
|
||||||
for (let entry of file.children) {
|
for (let entry of file.children) {
|
||||||
|
// We only want to count FileEntries with children, e.g. folders
|
||||||
|
if (entry.children !== null) {
|
||||||
count += 1
|
count += 1
|
||||||
|
}
|
||||||
directoryCount(entry)
|
directoryCount(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -529,6 +529,10 @@ function nodeHasExtrude(node: CommonASTNode) {
|
|||||||
doesPipeHaveCallExp({
|
doesPipeHaveCallExp({
|
||||||
calleeName: 'revolve',
|
calleeName: 'revolve',
|
||||||
...node,
|
...node,
|
||||||
|
}) ||
|
||||||
|
doesPipeHaveCallExp({
|
||||||
|
calleeName: 'loft',
|
||||||
|
...node,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -559,6 +563,22 @@ export function canSweepSelection(selection: Selections) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function canLoftSelection(selection: Selections) {
|
||||||
|
const commonNodes = selection.graphSelections.map((_, i) =>
|
||||||
|
buildCommonNodeFromSelection(selection, i)
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
!!isCursorInSketchCommandRange(
|
||||||
|
engineCommandManager.artifactGraph,
|
||||||
|
selection
|
||||||
|
) &&
|
||||||
|
commonNodes.length > 1 &&
|
||||||
|
commonNodes.every((n) => !hasSketchPipeBeenExtruded(n.selection, n.ast)) &&
|
||||||
|
commonNodes.every((n) => nodeHasClose(n) || nodeHasCircle(n)) &&
|
||||||
|
commonNodes.every((n) => !nodeHasExtrude(n))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// This accounts for non-geometry selections under "other"
|
// This accounts for non-geometry selections under "other"
|
||||||
export type ResolvedSelectionType = Artifact['type'] | 'other'
|
export type ResolvedSelectionType = Artifact['type'] | 'other'
|
||||||
export type SelectionCountsByType = Map<ResolvedSelectionType, number>
|
export type SelectionCountsByType = Map<ResolvedSelectionType, number>
|
||||||
|
@ -139,9 +139,14 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'loft',
|
id: 'loft',
|
||||||
onClick: () => console.error('Loft not yet implemented'),
|
onClick: ({ commandBarSend }) =>
|
||||||
|
commandBarSend({
|
||||||
|
type: 'Find and select command',
|
||||||
|
data: { name: 'Loft', groupId: 'modeling' },
|
||||||
|
}),
|
||||||
|
disabled: (state) => !state.can({ type: 'Loft' }),
|
||||||
icon: 'loft',
|
icon: 'loft',
|
||||||
status: 'kcl-only',
|
status: 'available',
|
||||||
title: 'Loft',
|
title: 'Loft',
|
||||||
hotkey: 'L',
|
hotkey: 'L',
|
||||||
description:
|
description:
|
||||||
|
@ -44,9 +44,14 @@ import {
|
|||||||
addOffsetPlane,
|
addOffsetPlane,
|
||||||
deleteFromSelection,
|
deleteFromSelection,
|
||||||
extrudeSketch,
|
extrudeSketch,
|
||||||
|
loftSketches,
|
||||||
revolveSketch,
|
revolveSketch,
|
||||||
} from 'lang/modifyAst'
|
} from 'lang/modifyAst'
|
||||||
import { applyFilletToSelection } from 'lang/modifyAst/addFillet'
|
import {
|
||||||
|
applyEdgeTreatmentToSelection,
|
||||||
|
EdgeTreatmentType,
|
||||||
|
FilletParameters,
|
||||||
|
} from 'lang/modifyAst/addEdgeTreatment'
|
||||||
import { getNodeFromPath } from '../lang/queryAst'
|
import { getNodeFromPath } from '../lang/queryAst'
|
||||||
import {
|
import {
|
||||||
applyConstraintEqualAngle,
|
applyConstraintEqualAngle,
|
||||||
@ -252,6 +257,7 @@ export type ModelingMachineEvent =
|
|||||||
| { type: 'Export'; data: ModelingCommandSchema['Export'] }
|
| { type: 'Export'; data: ModelingCommandSchema['Export'] }
|
||||||
| { type: 'Make'; data: ModelingCommandSchema['Make'] }
|
| { type: 'Make'; data: ModelingCommandSchema['Make'] }
|
||||||
| { type: 'Extrude'; data?: ModelingCommandSchema['Extrude'] }
|
| { type: 'Extrude'; data?: ModelingCommandSchema['Extrude'] }
|
||||||
|
| { type: 'Loft'; data?: ModelingCommandSchema['Loft'] }
|
||||||
| { type: 'Revolve'; data?: ModelingCommandSchema['Revolve'] }
|
| { type: 'Revolve'; data?: ModelingCommandSchema['Revolve'] }
|
||||||
| { type: 'Fillet'; data?: ModelingCommandSchema['Fillet'] }
|
| { type: 'Fillet'; data?: ModelingCommandSchema['Fillet'] }
|
||||||
| { type: 'Offset plane'; data: ModelingCommandSchema['Offset plane'] }
|
| { type: 'Offset plane'; data: ModelingCommandSchema['Offset plane'] }
|
||||||
@ -383,7 +389,8 @@ export const modelingMachine = setup({
|
|||||||
guards: {
|
guards: {
|
||||||
'Selection is on face': () => false,
|
'Selection is on face': () => false,
|
||||||
'has valid sweep selection': () => false,
|
'has valid sweep selection': () => false,
|
||||||
'has valid fillet selection': () => false,
|
'has valid loft selection': () => false,
|
||||||
|
'has valid edge treatment selection': () => false,
|
||||||
'Has exportable geometry': () => false,
|
'Has exportable geometry': () => false,
|
||||||
'has valid selection for deletion': () => false,
|
'has valid selection for deletion': () => false,
|
||||||
'has made first point': ({ context }) => {
|
'has made first point': ({ context }) => {
|
||||||
@ -739,14 +746,19 @@ export const modelingMachine = setup({
|
|||||||
// Extract inputs
|
// Extract inputs
|
||||||
const ast = kclManager.ast
|
const ast = kclManager.ast
|
||||||
const { selection, radius } = event.data
|
const { selection, radius } = event.data
|
||||||
|
const parameters: FilletParameters = {
|
||||||
|
type: EdgeTreatmentType.Fillet,
|
||||||
|
radius,
|
||||||
|
}
|
||||||
|
|
||||||
// Apply fillet to selection
|
// Apply fillet to selection
|
||||||
const applyFilletToSelectionResult = applyFilletToSelection(
|
const applyEdgeTreatmentToSelectionResult = applyEdgeTreatmentToSelection(
|
||||||
ast,
|
ast,
|
||||||
selection,
|
selection,
|
||||||
radius
|
parameters
|
||||||
)
|
)
|
||||||
if (err(applyFilletToSelectionResult)) return applyFilletToSelectionResult
|
if (err(applyEdgeTreatmentToSelectionResult))
|
||||||
|
return applyEdgeTreatmentToSelectionResult
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||||
@ -1520,6 +1532,50 @@ export const modelingMachine = setup({
|
|||||||
updateAstResult.newAst
|
updateAstResult.newAst
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (updateAstResult?.selections) {
|
||||||
|
editorManager.selectRange(updateAstResult?.selections)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
loftAstMod: fromPromise(
|
||||||
|
async ({
|
||||||
|
input,
|
||||||
|
}: {
|
||||||
|
input: ModelingCommandSchema['Loft'] | undefined
|
||||||
|
}) => {
|
||||||
|
if (!input) return new Error('No input provided')
|
||||||
|
// Extract inputs
|
||||||
|
const ast = kclManager.ast
|
||||||
|
const { selection } = input
|
||||||
|
const declarators = selection.graphSelections.flatMap((s) => {
|
||||||
|
const path = getNodePathFromSourceRange(ast, s?.codeRef.range)
|
||||||
|
const nodeFromPath = getNodeFromPath<VariableDeclarator>(
|
||||||
|
ast,
|
||||||
|
path,
|
||||||
|
'VariableDeclarator'
|
||||||
|
)
|
||||||
|
return err(nodeFromPath) ? [] : nodeFromPath.node
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: add better validation on selection
|
||||||
|
if (!(declarators && declarators.length > 1)) {
|
||||||
|
trap('Not enough sketches selected')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the loft
|
||||||
|
const loftSketchesRes = loftSketches(ast, declarators)
|
||||||
|
const updateAstResult = await kclManager.updateAst(
|
||||||
|
loftSketchesRes.modifiedAst,
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
focusPath: [loftSketchesRes.pathToNode],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
await codeManager.updateEditorWithAstAndWriteToFile(
|
||||||
|
updateAstResult.newAst
|
||||||
|
)
|
||||||
|
|
||||||
if (updateAstResult?.selections) {
|
if (updateAstResult?.selections) {
|
||||||
editorManager.selectRange(updateAstResult?.selections)
|
editorManager.selectRange(updateAstResult?.selections)
|
||||||
}
|
}
|
||||||
@ -1561,9 +1617,14 @@ export const modelingMachine = setup({
|
|||||||
reenter: false,
|
reenter: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loft: {
|
||||||
|
target: 'Applying loft',
|
||||||
|
reenter: true,
|
||||||
|
},
|
||||||
|
|
||||||
Fillet: {
|
Fillet: {
|
||||||
target: 'idle',
|
target: 'idle',
|
||||||
guard: 'has valid fillet selection', // TODO: fix selections
|
guard: 'has valid edge treatment selection',
|
||||||
actions: ['AST fillet'],
|
actions: ['AST fillet'],
|
||||||
reenter: false,
|
reenter: false,
|
||||||
},
|
},
|
||||||
@ -2309,6 +2370,19 @@ export const modelingMachine = setup({
|
|||||||
onError: ['idle'],
|
onError: ['idle'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'Applying loft': {
|
||||||
|
invoke: {
|
||||||
|
src: 'loftAstMod',
|
||||||
|
id: 'loftAstMod',
|
||||||
|
input: ({ event }) => {
|
||||||
|
if (event.type !== 'Loft') return undefined
|
||||||
|
return event.data
|
||||||
|
},
|
||||||
|
onDone: ['idle'],
|
||||||
|
onError: ['idle'],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
initial: 'idle',
|
initial: 'idle',
|
||||||
|
87
src/wasm-lib/Cargo.lock
generated
@ -443,9 +443,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.20"
|
version = "4.5.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
|
checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -453,9 +453,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.20"
|
version = "4.5.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
|
checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -774,6 +774,22 @@ dependencies = [
|
|||||||
"syn 2.0.87",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dhat"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98cd11d84628e233de0ce467de10b8633f4ddaecafadefc86e13b84b8739b827"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace",
|
||||||
|
"lazy_static",
|
||||||
|
"mintex",
|
||||||
|
"parking_lot 0.12.3",
|
||||||
|
"rustc-hash 1.1.0",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thousands",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diff"
|
name = "diff"
|
||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
@ -1166,9 +1182,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.0"
|
version = "0.15.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
|
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
@ -1573,7 +1589,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.15.0",
|
"hashbrown 0.15.2",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1690,7 +1706,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kcl-lib"
|
name = "kcl-lib"
|
||||||
version = "0.2.26"
|
version = "0.2.28"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"approx 0.5.1",
|
"approx 0.5.1",
|
||||||
@ -1705,6 +1721,7 @@ dependencies = [
|
|||||||
"dashmap 6.1.0",
|
"dashmap 6.1.0",
|
||||||
"databake",
|
"databake",
|
||||||
"derive-docs",
|
"derive-docs",
|
||||||
|
"dhat",
|
||||||
"expectorate",
|
"expectorate",
|
||||||
"fnv",
|
"fnv",
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
@ -1749,6 +1766,7 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
|
"web-time",
|
||||||
"winnow",
|
"winnow",
|
||||||
"zip",
|
"zip",
|
||||||
]
|
]
|
||||||
@ -1782,9 +1800,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad"
|
name = "kittycad"
|
||||||
version = "0.3.25"
|
version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6359cc0a1bbccbcf78775eea17a033cf2aa89d3fe6a9784f8ce94e5f882c185"
|
checksum = "933cb5f77624386c87d296e3fd493daf50156d1cbfa03b9f333a6d4da2896369"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -1813,7 +1831,7 @@ dependencies = [
|
|||||||
"serde_bytes",
|
"serde_bytes",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"thiserror 1.0.68",
|
"thiserror 2.0.0",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
@ -2056,6 +2074,12 @@ version = "0.5.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff"
|
checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mintex"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9bec4598fddb13cc7b528819e697852653252b760f1228b7642679bf2ff2cd07"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@ -2644,7 +2668,7 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"quinn-proto",
|
"quinn-proto",
|
||||||
"quinn-udp",
|
"quinn-udp",
|
||||||
"rustc-hash",
|
"rustc-hash 2.0.0",
|
||||||
"rustls",
|
"rustls",
|
||||||
"socket2",
|
"socket2",
|
||||||
"thiserror 1.0.68",
|
"thiserror 1.0.68",
|
||||||
@ -2661,7 +2685,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"ring",
|
"ring",
|
||||||
"rustc-hash",
|
"rustc-hash 2.0.0",
|
||||||
"rustls",
|
"rustls",
|
||||||
"slab",
|
"slab",
|
||||||
"thiserror 1.0.68",
|
"thiserror 1.0.68",
|
||||||
@ -2897,9 +2921,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest-conditional-middleware"
|
name = "reqwest-conditional-middleware"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1663d9d4fbb6e3900f91455d6d7833301c91ae3c7fc6e116fd7acd40e478a93"
|
checksum = "f67ad7fdf5c0a015763fcd164bee294b13fb7b6f89f1b55961d40f00c3e32d6b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
@ -2909,9 +2933,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest-middleware"
|
name = "reqwest-middleware"
|
||||||
version = "0.3.3"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "562ceb5a604d3f7c885a792d42c199fd8af239d0a51b2fa6a78aafa092452b04"
|
checksum = "d1ccd3b55e711f91a9885a2fa6fbbb2e39db1776420b062efc058c6410f7e5e3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -2924,9 +2948,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest-retry"
|
name = "reqwest-retry"
|
||||||
version = "0.6.1"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a83df1aaec00176d0fabb65dea13f832d2a446ca99107afc17c5d2d4981221d0"
|
checksum = "29c73e4195a6bfbcb174b790d9b3407ab90646976c55de58a6515da25d851178"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -2938,6 +2962,7 @@ dependencies = [
|
|||||||
"reqwest",
|
"reqwest",
|
||||||
"reqwest-middleware",
|
"reqwest-middleware",
|
||||||
"retry-policies",
|
"retry-policies",
|
||||||
|
"thiserror 1.0.68",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"wasm-timer",
|
"wasm-timer",
|
||||||
@ -2945,9 +2970,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest-tracing"
|
name = "reqwest-tracing"
|
||||||
version = "0.5.3"
|
version = "0.5.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bfdd9bfa64c72233d8dd99ab7883efcdefe9e16d46488ecb9228b71a2e2ceb45"
|
checksum = "ff82cf5730a1311fb9413b0bc2b8e743e0157cd73f010ab4ec374a923873b6a2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -3001,6 +3026,12 @@ version = "0.1.24"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@ -3035,9 +3066,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.13"
|
version = "0.23.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8"
|
checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ring",
|
"ring",
|
||||||
@ -3071,9 +3102,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.9.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55"
|
checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
@ -3637,6 +3668,12 @@ dependencies = [
|
|||||||
"syn 2.0.87",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thousands"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.1.8"
|
version = "1.1.8"
|
||||||
|
@ -74,8 +74,8 @@ members = [
|
|||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
http = "1"
|
http = "1"
|
||||||
kittycad = { version = "0.3.25", default-features = false, features = ["js", "requests"] }
|
kittycad = { version = "0.3.28", default-features = false, features = ["js", "requests"] }
|
||||||
kittycad-modeling-cmds = { version = "0.2.76", features = ["websocket"] }
|
kittycad-modeling-cmds = { version = "0.2.77", features = ["websocket"] }
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "executor"
|
name = "executor"
|
||||||
|
@ -171,7 +171,7 @@ fn do_stdlib_inner(
|
|||||||
code_blocks.iter().map(|cb| {
|
code_blocks.iter().map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
|
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
}).collect::<Vec<String>>()
|
}).collect::<Vec<String>>()
|
||||||
|
@ -113,7 +113,7 @@ impl crate::docs::StdLibFn for SomeFn {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -113,7 +113,7 @@ impl crate::docs::StdLibFn for SomeFn {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -150,7 +150,7 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -113,7 +113,7 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -150,7 +150,7 @@ impl crate::docs::StdLibFn for MyFunc {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -158,7 +158,7 @@ impl crate::docs::StdLibFn for LineTo {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -150,7 +150,7 @@ impl crate::docs::StdLibFn for Min {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -113,7 +113,7 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -113,7 +113,7 @@ impl crate::docs::StdLibFn for Import {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -113,7 +113,7 @@ impl crate::docs::StdLibFn for Import {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -113,7 +113,7 @@ impl crate::docs::StdLibFn for Import {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -113,7 +113,7 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -108,7 +108,7 @@ impl crate::docs::StdLibFn for SomeFunction {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|cb| {
|
.map(|cb| {
|
||||||
let program = crate::Program::parse(cb).unwrap();
|
let program = crate::Program::parse(cb).unwrap();
|
||||||
let mut options: crate::ast::types::FormatOptions = Default::default();
|
let mut options: crate::parsing::ast::types::FormatOptions = Default::default();
|
||||||
options.insert_final_newline = false;
|
options.insert_final_newline = false;
|
||||||
program.ast.recast(&options, 0)
|
program.ast.recast(&options, 0)
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "kcl-lib"
|
name = "kcl-lib"
|
||||||
description = "KittyCAD Language implementation and tools"
|
description = "KittyCAD Language implementation and tools"
|
||||||
version = "0.2.26"
|
version = "0.2.28"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/KittyCAD/modeling-app"
|
repository = "https://github.com/KittyCAD/modeling-app"
|
||||||
@ -16,11 +16,15 @@ async-recursion = "1.1.1"
|
|||||||
async-trait = "0.1.83"
|
async-trait = "0.1.83"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
chrono = "0.4.38"
|
chrono = "0.4.38"
|
||||||
clap = { version = "4.5.20", default-features = false, optional = true, features = ["std", "derive"] }
|
clap = { version = "4.5.21", default-features = false, optional = true, features = [
|
||||||
|
"std",
|
||||||
|
"derive",
|
||||||
|
] }
|
||||||
convert_case = "0.6.0"
|
convert_case = "0.6.0"
|
||||||
dashmap = "6.1.0"
|
dashmap = "6.1.0"
|
||||||
databake = { version = "0.1.8", features = ["derive"] }
|
databake = { version = "0.1.8", features = ["derive"] }
|
||||||
derive-docs = { version = "0.1.29", path = "../derive-docs" }
|
derive-docs = { version = "0.1.29", path = "../derive-docs" }
|
||||||
|
dhat = { version = "0.3", optional = true }
|
||||||
fnv = "1.0.7"
|
fnv = "1.0.7"
|
||||||
form_urlencoded = "1.2.1"
|
form_urlencoded = "1.2.1"
|
||||||
futures = { version = "0.3.31" }
|
futures = { version = "0.3.31" }
|
||||||
@ -37,27 +41,46 @@ miette = "7.2.0"
|
|||||||
mime_guess = "2.0.5"
|
mime_guess = "2.0.5"
|
||||||
parse-display = "0.9.1"
|
parse-display = "0.9.1"
|
||||||
pyo3 = { version = "0.22.6", optional = true }
|
pyo3 = { version = "0.22.6", optional = true }
|
||||||
reqwest = { version = "0.12", default-features = false, features = ["stream", "rustls-tls"] }
|
reqwest = { version = "0.12", default-features = false, features = [
|
||||||
|
"stream",
|
||||||
|
"rustls-tls",
|
||||||
|
] }
|
||||||
ropey = "1.6.1"
|
ropey = "1.6.1"
|
||||||
schemars = { version = "0.8.17", features = ["impl_json_schema", "indexmap2", "url", "uuid1", "preserve_order"] }
|
schemars = { version = "0.8.17", features = [
|
||||||
|
"impl_json_schema",
|
||||||
|
"indexmap2",
|
||||||
|
"url",
|
||||||
|
"uuid1",
|
||||||
|
"preserve_order",
|
||||||
|
] }
|
||||||
serde = { version = "1.0.214", features = ["derive"] }
|
serde = { version = "1.0.214", features = ["derive"] }
|
||||||
serde_json = "1.0.128"
|
serde_json = "1.0.128"
|
||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
tabled = { version = "0.15.0", optional = true }
|
tabled = { version = "0.15.0", optional = true }
|
||||||
thiserror = "2.0.0"
|
thiserror = "2.0.0"
|
||||||
toml = "0.8.19"
|
toml = "0.8.19"
|
||||||
ts-rs = { version = "10.0.0", features = ["uuid-impl", "url-impl", "chrono-impl", "indexmap-impl", "no-serde-warnings", "serde-json-impl"] }
|
ts-rs = { version = "10.0.0", features = [
|
||||||
|
"uuid-impl",
|
||||||
|
"url-impl",
|
||||||
|
"chrono-impl",
|
||||||
|
"indexmap-impl",
|
||||||
|
"no-serde-warnings",
|
||||||
|
"serde-json-impl",
|
||||||
|
] }
|
||||||
url = { version = "2.5.3", features = ["serde"] }
|
url = { version = "2.5.3", features = ["serde"] }
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
uuid = { version = "1.11.0", features = ["v4", "js", "serde"] }
|
uuid = { version = "1.11.0", features = ["v4", "js", "serde"] }
|
||||||
validator = { version = "0.19.0", features = ["derive"] }
|
validator = { version = "0.19.0", features = ["derive"] }
|
||||||
|
web-time = "1.1"
|
||||||
winnow = "0.6.18"
|
winnow = "0.6.18"
|
||||||
zip = { version = "2.0.0", default-features = false }
|
zip = { version = "2.0.0", default-features = false }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
js-sys = { version = "0.3.72" }
|
js-sys = { version = "0.3.72" }
|
||||||
tokio = { version = "1.41.1", features = ["sync", "time"] }
|
tokio = { version = "1.41.1", features = ["sync", "time"] }
|
||||||
tower-lsp = { version = "0.20.0", default-features = false, features = ["runtime-agnostic"] }
|
tower-lsp = { version = "0.20.0", default-features = false, features = [
|
||||||
|
"runtime-agnostic",
|
||||||
|
] }
|
||||||
wasm-bindgen = "0.2.91"
|
wasm-bindgen = "0.2.91"
|
||||||
wasm-bindgen-futures = "0.4.44"
|
wasm-bindgen-futures = "0.4.44"
|
||||||
web-sys = { version = "0.3.72", features = ["console"] }
|
web-sys = { version = "0.3.72", features = ["console"] }
|
||||||
@ -66,12 +89,15 @@ web-sys = { version = "0.3.72", features = ["console"] }
|
|||||||
approx = "0.5"
|
approx = "0.5"
|
||||||
bson = { version = "2.13.0", features = ["uuid-1", "chrono"] }
|
bson = { version = "2.13.0", features = ["uuid-1", "chrono"] }
|
||||||
tokio = { version = "1.41.1", features = ["full"] }
|
tokio = { version = "1.41.1", features = ["full"] }
|
||||||
tokio-tungstenite = { version = "0.24.0", features = ["rustls-tls-native-roots"] }
|
tokio-tungstenite = { version = "0.24.0", features = [
|
||||||
|
"rustls-tls-native-roots",
|
||||||
|
] }
|
||||||
tower-lsp = { version = "0.20.0", features = ["proposed"] }
|
tower-lsp = { version = "0.20.0", features = ["proposed"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["engine"]
|
default = ["engine"]
|
||||||
cli = ["dep:clap"]
|
cli = ["dep:clap"]
|
||||||
|
dhat-heap = ["dep:dhat"]
|
||||||
# For the lsp server, when run with stdout for rpc we want to disable println.
|
# For the lsp server, when run with stdout for rpc we want to disable println.
|
||||||
# This is used for editor extensions that use the lsp server.
|
# This is used for editor extensions that use the lsp server.
|
||||||
disable-println = []
|
disable-println = []
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
pub mod modify;
|
|
||||||
pub mod types;
|
|
@ -797,7 +797,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialize_function() {
|
fn test_serialize_function() {
|
||||||
let some_function = crate::ast::types::Function::StdLib {
|
let some_function = crate::parsing::ast::types::Function::StdLib {
|
||||||
func: Box::new(crate::std::sketch::Line),
|
func: Box::new(crate::std::sketch::Line),
|
||||||
};
|
};
|
||||||
let serialized = serde_json::to_string(&some_function).unwrap();
|
let serialized = serde_json::to_string(&some_function).unwrap();
|
||||||
@ -807,11 +807,11 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_deserialize_function() {
|
fn test_deserialize_function() {
|
||||||
let some_function_string = r#"{"type":"StdLib","func":{"name":"line","summary":"","description":"","tags":[],"returnValue":{"type":"","required":false,"name":"","schema":{},"schemaDefinitions":{}},"args":[],"unpublished":false,"deprecated":false, "examples": []}}"#;
|
let some_function_string = r#"{"type":"StdLib","func":{"name":"line","summary":"","description":"","tags":[],"returnValue":{"type":"","required":false,"name":"","schema":{},"schemaDefinitions":{}},"args":[],"unpublished":false,"deprecated":false, "examples": []}}"#;
|
||||||
let some_function: crate::ast::types::Function = serde_json::from_str(some_function_string).unwrap();
|
let some_function: crate::parsing::ast::types::Function = serde_json::from_str(some_function_string).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
some_function,
|
some_function,
|
||||||
crate::ast::types::Function::StdLib {
|
crate::parsing::ast::types::Function::StdLib {
|
||||||
func: Box::new(crate::std::sketch::Line)
|
func: Box::new(crate::std::sketch::Line)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -18,14 +18,14 @@ use kittycad_modeling_cmds as kcmc;
|
|||||||
use tokio::sync::{mpsc, oneshot, RwLock};
|
use tokio::sync::{mpsc, oneshot, RwLock};
|
||||||
use tokio_tungstenite::tungstenite::Message as WsMsg;
|
use tokio_tungstenite::tungstenite::Message as WsMsg;
|
||||||
|
|
||||||
|
use super::ExecutionKind;
|
||||||
use crate::{
|
use crate::{
|
||||||
engine::EngineManager,
|
engine::EngineManager,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{DefaultPlanes, IdGenerator},
|
executor::{DefaultPlanes, IdGenerator},
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::ExecutionKind;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
enum SocketHealth {
|
enum SocketHealth {
|
||||||
Active,
|
Active,
|
||||||
@ -41,8 +41,8 @@ pub struct EngineConnection {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
tcp_read_handle: Arc<TcpReadHandle>,
|
tcp_read_handle: Arc<TcpReadHandle>,
|
||||||
socket_health: Arc<Mutex<SocketHealth>>,
|
socket_health: Arc<Mutex<SocketHealth>>,
|
||||||
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch: Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>>,
|
||||||
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
|
||||||
|
|
||||||
/// The default planes for the scene.
|
/// The default planes for the scene.
|
||||||
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
|
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
|
||||||
@ -282,8 +282,8 @@ impl EngineConnection {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
match &e {
|
match &e {
|
||||||
WebSocketReadError::Read(e) => eprintln!("could not read from WS: {:?}", e),
|
WebSocketReadError::Read(e) => crate::logln!("could not read from WS: {:?}", e),
|
||||||
WebSocketReadError::Deser(e) => eprintln!("could not deserialize msg from WS: {:?}", e),
|
WebSocketReadError::Deser(e) => crate::logln!("could not deserialize msg from WS: {:?}", e),
|
||||||
}
|
}
|
||||||
*socket_health_tcp_read.lock().unwrap() = SocketHealth::Inactive;
|
*socket_health_tcp_read.lock().unwrap() = SocketHealth::Inactive;
|
||||||
return Err(e);
|
return Err(e);
|
||||||
@ -311,11 +311,11 @@ impl EngineConnection {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl EngineManager for EngineConnection {
|
impl EngineManager for EngineConnection {
|
||||||
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch.clone()
|
self.batch.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch_end.clone()
|
self.batch_end.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,7 +334,7 @@ impl EngineManager for EngineConnection {
|
|||||||
async fn default_planes(
|
async fn default_planes(
|
||||||
&self,
|
&self,
|
||||||
id_generator: &mut IdGenerator,
|
id_generator: &mut IdGenerator,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<DefaultPlanes, KclError> {
|
) -> Result<DefaultPlanes, KclError> {
|
||||||
{
|
{
|
||||||
let opt = self.default_planes.read().await.as_ref().cloned();
|
let opt = self.default_planes.read().await.as_ref().cloned();
|
||||||
@ -352,7 +352,7 @@ impl EngineManager for EngineConnection {
|
|||||||
async fn clear_scene_post_hook(
|
async fn clear_scene_post_hook(
|
||||||
&self,
|
&self,
|
||||||
id_generator: &mut IdGenerator,
|
id_generator: &mut IdGenerator,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<(), KclError> {
|
) -> Result<(), KclError> {
|
||||||
// Remake the default planes, since they would have been removed after the scene was cleared.
|
// Remake the default planes, since they would have been removed after the scene was cleared.
|
||||||
let new_planes = self.new_default_planes(id_generator, source_range).await?;
|
let new_planes = self.new_default_planes(id_generator, source_range).await?;
|
||||||
@ -364,9 +364,9 @@ impl EngineManager for EngineConnection {
|
|||||||
async fn inner_send_modeling_cmd(
|
async fn inner_send_modeling_cmd(
|
||||||
&self,
|
&self,
|
||||||
id: uuid::Uuid,
|
id: uuid::Uuid,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
cmd: WebSocketRequest,
|
cmd: WebSocketRequest,
|
||||||
_id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
_id_to_source_range: std::collections::HashMap<uuid::Uuid, SourceRange>,
|
||||||
) -> Result<WebSocketResponse, KclError> {
|
) -> Result<WebSocketResponse, KclError> {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
|
|
||||||
|
@ -17,17 +17,17 @@ use kcmc::{
|
|||||||
};
|
};
|
||||||
use kittycad_modeling_cmds::{self as kcmc};
|
use kittycad_modeling_cmds::{self as kcmc};
|
||||||
|
|
||||||
|
use super::ExecutionKind;
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::KclError,
|
errors::KclError,
|
||||||
executor::{DefaultPlanes, IdGenerator},
|
executor::{DefaultPlanes, IdGenerator},
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::ExecutionKind;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct EngineConnection {
|
pub struct EngineConnection {
|
||||||
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch: Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>>,
|
||||||
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
|
||||||
execution_kind: Arc<Mutex<ExecutionKind>>,
|
execution_kind: Arc<Mutex<ExecutionKind>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,11 +43,11 @@ impl EngineConnection {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl crate::engine::EngineManager for EngineConnection {
|
impl crate::engine::EngineManager for EngineConnection {
|
||||||
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch.clone()
|
self.batch.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch_end.clone()
|
self.batch_end.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn default_planes(
|
async fn default_planes(
|
||||||
&self,
|
&self,
|
||||||
_id_generator: &mut IdGenerator,
|
_id_generator: &mut IdGenerator,
|
||||||
_source_range: crate::executor::SourceRange,
|
_source_range: SourceRange,
|
||||||
) -> Result<DefaultPlanes, KclError> {
|
) -> Result<DefaultPlanes, KclError> {
|
||||||
Ok(DefaultPlanes::default())
|
Ok(DefaultPlanes::default())
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn clear_scene_post_hook(
|
async fn clear_scene_post_hook(
|
||||||
&self,
|
&self,
|
||||||
_id_generator: &mut IdGenerator,
|
_id_generator: &mut IdGenerator,
|
||||||
_source_range: crate::executor::SourceRange,
|
_source_range: SourceRange,
|
||||||
) -> Result<(), KclError> {
|
) -> Result<(), KclError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -82,9 +82,9 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn inner_send_modeling_cmd(
|
async fn inner_send_modeling_cmd(
|
||||||
&self,
|
&self,
|
||||||
id: uuid::Uuid,
|
id: uuid::Uuid,
|
||||||
_source_range: crate::executor::SourceRange,
|
_source_range: SourceRange,
|
||||||
cmd: WebSocketRequest,
|
cmd: WebSocketRequest,
|
||||||
_id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
_id_to_source_range: std::collections::HashMap<uuid::Uuid, SourceRange>,
|
||||||
) -> Result<WebSocketResponse, KclError> {
|
) -> Result<WebSocketResponse, KclError> {
|
||||||
match cmd {
|
match cmd {
|
||||||
WebSocketRequest::ModelingCmdBatchReq(ModelingBatch {
|
WebSocketRequest::ModelingCmdBatchReq(ModelingBatch {
|
||||||
|
@ -12,6 +12,7 @@ use crate::{
|
|||||||
engine::ExecutionKind,
|
engine::ExecutionKind,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{DefaultPlanes, IdGenerator},
|
executor::{DefaultPlanes, IdGenerator},
|
||||||
|
SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[wasm_bindgen(module = "/../../lang/std/engineConnection.ts")]
|
#[wasm_bindgen(module = "/../../lang/std/engineConnection.ts")]
|
||||||
@ -41,8 +42,8 @@ extern "C" {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct EngineConnection {
|
pub struct EngineConnection {
|
||||||
manager: Arc<EngineCommandManager>,
|
manager: Arc<EngineCommandManager>,
|
||||||
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch: Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>>,
|
||||||
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>>,
|
batch_end: Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
|
||||||
execution_kind: Arc<Mutex<ExecutionKind>>,
|
execution_kind: Arc<Mutex<ExecutionKind>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,11 +64,11 @@ impl EngineConnection {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl crate::engine::EngineManager for EngineConnection {
|
impl crate::engine::EngineManager for EngineConnection {
|
||||||
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch.clone()
|
self.batch.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>> {
|
fn batch_end(&self) -> Arc<Mutex<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>> {
|
||||||
self.batch_end.clone()
|
self.batch_end.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn default_planes(
|
async fn default_planes(
|
||||||
&self,
|
&self,
|
||||||
_id_generator: &mut IdGenerator,
|
_id_generator: &mut IdGenerator,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<DefaultPlanes, KclError> {
|
) -> Result<DefaultPlanes, KclError> {
|
||||||
// Get the default planes.
|
// Get the default planes.
|
||||||
let promise = self.manager.get_default_planes().map_err(|e| {
|
let promise = self.manager.get_default_planes().map_err(|e| {
|
||||||
@ -128,7 +129,7 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn clear_scene_post_hook(
|
async fn clear_scene_post_hook(
|
||||||
&self,
|
&self,
|
||||||
_id_generator: &mut IdGenerator,
|
_id_generator: &mut IdGenerator,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<(), KclError> {
|
) -> Result<(), KclError> {
|
||||||
self.manager.clear_default_planes().map_err(|e| {
|
self.manager.clear_default_planes().map_err(|e| {
|
||||||
KclError::Engine(KclErrorDetails {
|
KclError::Engine(KclErrorDetails {
|
||||||
@ -158,9 +159,9 @@ impl crate::engine::EngineManager for EngineConnection {
|
|||||||
async fn inner_send_modeling_cmd(
|
async fn inner_send_modeling_cmd(
|
||||||
&self,
|
&self,
|
||||||
id: uuid::Uuid,
|
id: uuid::Uuid,
|
||||||
source_range: crate::executor::SourceRange,
|
source_range: SourceRange,
|
||||||
cmd: WebSocketRequest,
|
cmd: WebSocketRequest,
|
||||||
id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
id_to_source_range: std::collections::HashMap<uuid::Uuid, SourceRange>,
|
||||||
) -> Result<WebSocketResponse, KclError> {
|
) -> Result<WebSocketResponse, KclError> {
|
||||||
let source_range_str = serde_json::to_string(&source_range).map_err(|e| {
|
let source_range_str = serde_json::to_string(&source_range).map_err(|e| {
|
||||||
KclError::Engine(KclErrorDetails {
|
KclError::Engine(KclErrorDetails {
|
||||||
|