Add stdlib functions for getting sketch profile start and its components (#2373)
* Add stdlib functions for getting sketch profile start and its components * Fix it up and actually generate snapshots * cargo fmt * Use `.to` instead of `.from` * Update docs with EXPECTORATE=overwrite * Add README * fmt * Update flow test to account for more autocompletion options when typing "start" --------- Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
This commit is contained in:
19
README.md
19
README.md
@ -59,7 +59,9 @@ followed by:
|
|||||||
```
|
```
|
||||||
yarn build:wasm-dev
|
yarn build:wasm-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
or if you have the gh cli installed
|
or if you have the gh cli installed
|
||||||
|
|
||||||
```
|
```
|
||||||
./get-latest-wasm-bundle.sh # this will download the latest main wasm bundle
|
./get-latest-wasm-bundle.sh # this will download the latest main wasm bundle
|
||||||
```
|
```
|
||||||
@ -100,6 +102,7 @@ yarn test
|
|||||||
Which will run our suite of [Vitest unit](https://vitest.dev/) and [React Testing Library E2E](https://testing-library.com/docs/react-testing-library/intro/) tests, in interactive mode by default.
|
Which will run our suite of [Vitest unit](https://vitest.dev/) and [React Testing Library E2E](https://testing-library.com/docs/react-testing-library/intro/) tests, in interactive mode by default.
|
||||||
|
|
||||||
For running the rust (not tauri rust though) only, you can
|
For running the rust (not tauri rust though) only, you can
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd src/wasm-lib
|
cd src/wasm-lib
|
||||||
cargo test
|
cargo test
|
||||||
@ -162,6 +165,7 @@ console.log(
|
|||||||
- `)
|
- `)
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
grab the md list and delete any that are older than the last bump
|
grab the md list and delete any that are older than the last bump
|
||||||
|
|
||||||
2. Merge the PR
|
2. Merge the PR
|
||||||
@ -191,23 +195,26 @@ $ cargo +nightly fuzz run parser
|
|||||||
For more information on fuzzing you can check out
|
For more information on fuzzing you can check out
|
||||||
[this guide](https://rust-fuzz.github.io/book/cargo-fuzz.html).
|
[this guide](https://rust-fuzz.github.io/book/cargo-fuzz.html).
|
||||||
|
|
||||||
|
|
||||||
### Playwright
|
### Playwright
|
||||||
|
|
||||||
First time running plawright locally, you'll need to add the secrets file
|
First time running plawright locally, you'll need to add the secrets file
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
touch ./e2e/playwright/playwright-secrets.env
|
touch ./e2e/playwright/playwright-secrets.env
|
||||||
printf 'token="your-token"\nsnapshottoken="your-snapshot-token"' > ./e2e/playwright/playwright-secrets.env
|
printf 'token="your-token"\nsnapshottoken="your-snapshot-token"' > ./e2e/playwright/playwright-secrets.env
|
||||||
```
|
```
|
||||||
|
|
||||||
then replace "your-token" with a dev token from dev.zoo.dev/account/api-tokens
|
then replace "your-token" with a dev token from dev.zoo.dev/account/api-tokens
|
||||||
|
|
||||||
then:
|
then:
|
||||||
run playwright
|
run playwright
|
||||||
|
|
||||||
```
|
```
|
||||||
yarn playwright test
|
yarn playwright test
|
||||||
```
|
```
|
||||||
|
|
||||||
run a specific test suite
|
run a specific test suite
|
||||||
|
|
||||||
```
|
```
|
||||||
yarn playwright test src/e2e-tests/example.spec.ts
|
yarn playwright test src/e2e-tests/example.spec.ts
|
||||||
```
|
```
|
||||||
@ -216,14 +223,17 @@ run a specific test change the test from `test('...` to `test.only('...`
|
|||||||
(note if you commit this, the tests will instantly fail without running any of the tests)
|
(note if you commit this, the tests will instantly fail without running any of the tests)
|
||||||
|
|
||||||
run headed
|
run headed
|
||||||
|
|
||||||
```
|
```
|
||||||
yarn playwright test --headed
|
yarn playwright test --headed
|
||||||
```
|
```
|
||||||
|
|
||||||
run with step through debugger
|
run with step through debugger
|
||||||
|
|
||||||
```
|
```
|
||||||
PWDEBUG=1 yarn playwright test
|
PWDEBUG=1 yarn playwright test
|
||||||
```
|
```
|
||||||
|
|
||||||
However, if you want a debugger I recommend using VSCode and the `playwright` extension, as the above command is a cruder debugger that steps into every function call which is annoying.
|
However, if you want a debugger I recommend using VSCode and the `playwright` extension, as the above command is a cruder debugger that steps into every function call which is annoying.
|
||||||
With the extension you can set a breakpoint after `waitForDefaultPlanesVisibilityChange` in order to skip app loading, then the vscode debugger's "step over" is much better for being able to stay at the right level of abstraction as you debug the code.
|
With the extension you can set a breakpoint after `waitForDefaultPlanesVisibilityChange` in order to skip app loading, then the vscode debugger's "step over" is much better for being able to stay at the right level of abstraction as you debug the code.
|
||||||
|
|
||||||
@ -268,12 +278,11 @@ Where `./store` should look like this
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
However because much of our tests involve clicking in the stream at specific locations, it's code-gen looks `await page.locator('video').click();` when really we need to use a pixel coord, so I think it's of limited use.
|
However because much of our tests involve clicking in the stream at specific locations, it's code-gen looks `await page.locator('video').click();` when really we need to use a pixel coord, so I think it's of limited use.
|
||||||
|
|
||||||
#### Some notes on CI
|
#### Some notes on CI
|
||||||
|
|
||||||
The tests are broken into snapshot tests and non-snapshot tests, and they run in that order, they automatically commit new snap shots, so if you see an image commit check it was an intended change. If we have non-determinism in the snapshots such that they are always committing new images, hopefully this annoyance makes us fix them asap, if you notice this happening let Kurt know. But for the odd occasion `git reset --hard HEAD~ && git push -f` is your friend.
|
The tests are broken into snapshot tests and non-snapshot tests, and they run in that order, they automatically commit new snap shots, so if you see an image commit check it was an intended change. If we have non-determinism in the snapshots such that they are always committing new images, hopefully this annoyance makes us fix them asap, if you notice this happening let Kurt know. But for the odd occasion `git reset --hard HEAD~ && git push -f` is your friend.
|
||||||
|
|
||||||
How to interpret failing playwright tests?
|
How to interpret failing playwright tests?
|
||||||
If your tests fail, click through to the action and see that the tests failed on a line that includes `await page.getByTestId('loading').waitFor({ state: 'detached' })`, this means the test fail because the stream never started. It's you choice if you want to re-run the test, or ignore the failure.
|
If your tests fail, click through to the action and see that the tests failed on a line that includes `await page.getByTestId('loading').waitFor({ state: 'detached' })`, this means the test fail because the stream never started. It's you choice if you want to re-run the test, or ignore the failure.
|
||||||
@ -299,3 +308,7 @@ PS: for the debug panel, the following JSON is useful for snapping the camera
|
|||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## KCL
|
||||||
|
|
||||||
|
For how to contribute to KCL, [see our KCL README](https://github.com/KittyCAD/modeling-app/tree/main/src/wasm-lib/kcl).
|
||||||
|
@ -56,6 +56,9 @@ layout: manual
|
|||||||
* [`patternLinear3d`](kcl/patternLinear3d)
|
* [`patternLinear3d`](kcl/patternLinear3d)
|
||||||
* [`pi`](kcl/pi)
|
* [`pi`](kcl/pi)
|
||||||
* [`pow`](kcl/pow)
|
* [`pow`](kcl/pow)
|
||||||
|
* [`profileStart`](kcl/profileStart)
|
||||||
|
* [`profileStartX`](kcl/profileStartX)
|
||||||
|
* [`profileStartY`](kcl/profileStartY)
|
||||||
* [`revolve`](kcl/revolve)
|
* [`revolve`](kcl/revolve)
|
||||||
* [`segAng`](kcl/segAng)
|
* [`segAng`](kcl/segAng)
|
||||||
* [`segEndX`](kcl/segEndX)
|
* [`segEndX`](kcl/segEndX)
|
||||||
|
206
docs/kcl/profileStart.md
Normal file
206
docs/kcl/profileStart.md
Normal file
File diff suppressed because one or more lines are too long
201
docs/kcl/profileStartX.md
Normal file
201
docs/kcl/profileStartX.md
Normal file
File diff suppressed because one or more lines are too long
200
docs/kcl/profileStartY.md
Normal file
200
docs/kcl/profileStartY.md
Normal file
File diff suppressed because one or more lines are too long
2972
docs/kcl/std.json
2972
docs/kcl/std.json
File diff suppressed because it is too large
Load Diff
@ -646,8 +646,8 @@ test('Auto complete works', async ({ page }) => {
|
|||||||
await page.click('.cm-content')
|
await page.click('.cm-content')
|
||||||
await page.keyboard.type('const part001 = start')
|
await page.keyboard.type('const part001 = start')
|
||||||
|
|
||||||
// expect there to be three auto complete options
|
// expect there to be six auto complete options
|
||||||
await expect(page.locator('.cm-completionLabel')).toHaveCount(3)
|
await expect(page.locator('.cm-completionLabel')).toHaveCount(6)
|
||||||
await page.getByText('startSketchOn').click()
|
await page.getByText('startSketchOn').click()
|
||||||
await page.keyboard.type("'XZ'")
|
await page.keyboard.type("'XZ'")
|
||||||
await page.keyboard.press('Tab')
|
await page.keyboard.press('Tab')
|
||||||
|
20
src/wasm-lib/kcl/README.md
Normal file
20
src/wasm-lib/kcl/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# KCL
|
||||||
|
|
||||||
|
Our language for defining geometry and working with our Geometry Engine efficiently. Short for KittyCAD Language, named after our Design API.
|
||||||
|
|
||||||
|
## Contributing a standard library function
|
||||||
|
|
||||||
|
We've built a lot of tooling to make contributing to KCL easier. If you are interested in contributing a new standard library function to KCL, here is the rough process:
|
||||||
|
|
||||||
|
1. Open just the wasm-lib folder in your editor of choice. VS Code, for example, struggles to run rust-analyzer on the entire modeling-app directory because it's such a turducken of TS and Rust code.
|
||||||
|
2. Find the definition for similar standard library functions in `./kcl/src/std` and place your new one near it or in the same category file.
|
||||||
|
3. Add your new code. A new standard library function consists of:
|
||||||
|
4. A `pub async` of the actual standard library function in Rust
|
||||||
|
5. A doc comment block containing at least one example using your new standard library function (the Rust compiler will error if you don't provide an example our teammates are dope)
|
||||||
|
6. A `stdlib` macro providing the name that will need to be written by KCL users to use the function (this is usually a camelCase version of your Rust implementation, which is named with snake_case)
|
||||||
|
7. An inner function that is published only to the crate
|
||||||
|
8. Add your new standard library function to [the long list of CORE_FNS in mod.rs](https://github.com/KittyCAD/modeling-app/blob/main/src/wasm-lib/kcl/src/std/mod.rs#L42)
|
||||||
|
9. Get a production Zoo dev token and run `export KITTYCAD_API_TOKEN=your-token-here` in a terminal
|
||||||
|
10. Run `TWENTY_TWENTY=overwrite cargo nextest run --workspace --no-fail-fast` to take snapshot tests of your example code running in the engine
|
||||||
|
11. Run `EXPECTORATE=overwrite cargo test --all generate_stdlib -- --nocapture` to generate new Markdown documentation for your function that will be used [to generate docs on our website](https://zoo.dev/docs/kcl).
|
||||||
|
12. Create a PR in GitHub.
|
@ -68,6 +68,9 @@ lazy_static! {
|
|||||||
Box::new(crate::std::sketch::StartSketchAt),
|
Box::new(crate::std::sketch::StartSketchAt),
|
||||||
Box::new(crate::std::sketch::StartSketchOn),
|
Box::new(crate::std::sketch::StartSketchOn),
|
||||||
Box::new(crate::std::sketch::StartProfileAt),
|
Box::new(crate::std::sketch::StartProfileAt),
|
||||||
|
Box::new(crate::std::sketch::ProfileStartX),
|
||||||
|
Box::new(crate::std::sketch::ProfileStartY),
|
||||||
|
Box::new(crate::std::sketch::ProfileStart),
|
||||||
Box::new(crate::std::sketch::Close),
|
Box::new(crate::std::sketch::Close),
|
||||||
Box::new(crate::std::sketch::Arc),
|
Box::new(crate::std::sketch::Arc),
|
||||||
Box::new(crate::std::sketch::TangentialArc),
|
Box::new(crate::std::sketch::TangentialArc),
|
||||||
|
@ -12,7 +12,7 @@ use crate::{
|
|||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{
|
executor::{
|
||||||
BasePath, ExtrudeGroup, ExtrudeSurface, Face, GeoMeta, MemoryItem, Path, Plane, PlaneType, Point2d, Point3d,
|
BasePath, ExtrudeGroup, ExtrudeSurface, Face, GeoMeta, MemoryItem, Path, Plane, PlaneType, Point2d, Point3d,
|
||||||
Position, Rotation, SketchGroup, SketchGroupSet, SketchSurface, SourceRange,
|
Position, Rotation, SketchGroup, SketchGroupSet, SketchSurface, SourceRange, UserVal,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
utils::{
|
utils::{
|
||||||
@ -1214,6 +1214,78 @@ pub(crate) async fn inner_start_profile_at(
|
|||||||
Ok(Box::new(sketch_group))
|
Ok(Box::new(sketch_group))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the X component of the sketch profile start point.
|
||||||
|
pub async fn profile_start_x(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
|
let sketch_group: Box<SketchGroup> = args.get_sketch_group()?;
|
||||||
|
let x = inner_profile_start_x(sketch_group)?;
|
||||||
|
args.make_user_val_from_f64(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ```no_run
|
||||||
|
/// const sketch001 = startSketchOn('XY')
|
||||||
|
/// |> startProfileAt([5, 2], %)
|
||||||
|
/// |> angledLine([-26.6, 50], %)
|
||||||
|
/// |> angledLine([90, 50], %)
|
||||||
|
/// |> angledLineToX({ angle: 30, to: profileStartX(%) }, %)
|
||||||
|
/// ```
|
||||||
|
#[stdlib {
|
||||||
|
name = "profileStartX"
|
||||||
|
}]
|
||||||
|
pub(crate) fn inner_profile_start_x(sketch_group: Box<SketchGroup>) -> Result<f64, KclError> {
|
||||||
|
Ok(sketch_group.start.to[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the Y component of the sketch profile start point.
|
||||||
|
pub async fn profile_start_y(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
|
let sketch_group: Box<SketchGroup> = args.get_sketch_group()?;
|
||||||
|
let x = inner_profile_start_y(sketch_group)?;
|
||||||
|
args.make_user_val_from_f64(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ```no_run
|
||||||
|
/// const sketch001 = startSketchOn('XY')
|
||||||
|
/// |> startProfileAt([5, 2], %)
|
||||||
|
/// |> angledLine({ angle: -60, length: 14 }, %)
|
||||||
|
/// |> angledLineToY({ angle: 30, to: profileStartY(%) }, %)
|
||||||
|
/// ```
|
||||||
|
#[stdlib {
|
||||||
|
name = "profileStartY"
|
||||||
|
}]
|
||||||
|
pub(crate) fn inner_profile_start_y(sketch_group: Box<SketchGroup>) -> Result<f64, KclError> {
|
||||||
|
Ok(sketch_group.start.to[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sketch profile start point.
|
||||||
|
pub async fn profile_start(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
|
let sketch_group: Box<SketchGroup> = args.get_sketch_group()?;
|
||||||
|
let point = inner_profile_start(sketch_group)?;
|
||||||
|
Ok(MemoryItem::UserVal(UserVal {
|
||||||
|
value: serde_json::to_value(point).map_err(|e| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("Failed to convert point to json: {}", e),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})?,
|
||||||
|
meta: Default::default(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ```no_run
|
||||||
|
/// const sketch001 = startSketchOn('XY')
|
||||||
|
/// |> startProfileAt([5, 2], %)
|
||||||
|
/// |> angledLine({ angle: 120, length: 50 }, %, 'seg01')
|
||||||
|
/// |> angledLine({ angle: segAng('seg01', %) + 120, length: 50 }, %)
|
||||||
|
/// |> lineTo(profileStart(%), %)
|
||||||
|
/// |> close(%)
|
||||||
|
/// |> extrude(20, %)
|
||||||
|
/// ```
|
||||||
|
#[stdlib {
|
||||||
|
name = "profileStart"
|
||||||
|
}]
|
||||||
|
pub(crate) fn inner_profile_start(sketch_group: Box<SketchGroup>) -> Result<[f64; 2], KclError> {
|
||||||
|
Ok(sketch_group.start.to)
|
||||||
|
}
|
||||||
|
|
||||||
/// Close the current sketch.
|
/// Close the current sketch.
|
||||||
pub async fn close(args: Args) -> Result<MemoryItem, KclError> {
|
pub async fn close(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
let (sketch_group, tag): (Box<SketchGroup>, Option<String>) = args.get_sketch_group_and_optional_tag()?;
|
let (sketch_group, tag): (Box<SketchGroup>, Option<String>) = args.get_sketch_group_and_optional_tag()?;
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 106 KiB |
Binary file not shown.
After Width: | Height: | Size: 109 KiB |
Binary file not shown.
After Width: | Height: | Size: 95 KiB |
Reference in New Issue
Block a user