Compare commits

...

29 Commits

Author SHA1 Message Date
cccb71fd30 Set initial window size depending on screen size (#5845)
* set initial electron window size to be almost full screen with some space left

* refine initial window size and position

* slightly larger

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-18 15:39:04 -04:00
44be072d04 Fix deep links and double clicks on second instance (#5865)
* Deep links or double clicks don't work on second instance on Windows
Fixes #5864

* A snapshot a day keeps the bugs away! 📷🐛

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-18 15:17:21 -04:00
86beb6ebf1 Improve local setup instructions (#5860)
* Fix overwrite confirmation on existing wasm-pack

* Recommend using local .env for overrides
2025-03-18 14:39:02 -04:00
6d72104faa fix unused vars and imports (#5852)
* update eslintrc, and fix most of the errors

* more

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

* fix last one

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

* fixes

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

* updates

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

* A snapshot a day keeps the bugs away! 📷🐛

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-18 09:52:10 -07:00
f2c5661710 Use less Namespace resources by shifting ubuntu to AWS (#5847)
* Attempt: Hourly tests on ubuntu only

* Attempt: Hourly tests on ubuntu only through os exlusion rules

* Attempt: Hourly tests on ubuntu only through dummy boolean key

* Clean up for PR

* Draft: Use less namespace vCPUs for e2e

* All on gh, just to see

* Disable concurrency, bump to 45min step retry timeout

* 2 workers for non-windows machineis

* Step retry down to 3

* Change to ubuntu aws, change macos to macos-latest-large

* Fix name for ubuntu aws, back to 10 step retry

* Back to 4 shards to see the diff

* Snaptshots on ubuntu aws

* Cleaning up to get closer to a review-able state

* Should be ready for review

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-18 09:44:54 -04:00
ecb2359bc5 Fix tsc errors (#5857)
fix tsc errors
2025-03-18 08:56:08 -04:00
6e5058bbdc Bump zip from 2.2.3 to 2.4.1 in /rust in the security group (#5854) 2025-03-18 00:40:56 -04:00
988a068d6d Collect simple stats about engine usage (#5823)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-03-18 16:19:24 +13:00
0688ce7fe9 #4391 Move axis meshes behind so they don't block line segments from being selected (#5807)
Move axis meshes behind so they will be picked after line segment by raycaster
2025-03-17 22:00:21 -04:00
f9e09893e7 update template (#5853)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-18 01:53:32 +00:00
dd1534a61d Cleanup rust/ts interface a but more w new rustContext (#5848)
* do the rust side

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

* cleanup ts side

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

* updates

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

* typo

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-18 01:26:11 +00:00
e17c6e272c Add 3 point arc (#5722)
* bare minimum

* start of segment util added

* remove redundant handle

* some probably buggy handling of arc handles, can fix later

* probably bug implementation of update args, but data flow through is mostly there can fix bugs after

* fix update for arc

* fix math for center handle

* fix up length indicator

* tweak math

* stub out xState logic for arc

* more progress on adding point and click, implemented more of sketchLineHelper for arc

* small unrelated tweak

* fix up draft arc bugs

* fix arc last click

* fix draft segment animation and add comment

* add draft point snapping for arcs

* add helper stuff to arc

* clone arc point and click as base for arc-three-point

* rust change for arc three point

* can draw three point arc

* make arcTo editable

* can add new three point arc, so long as it continues existing profile

* get overlays working

* make snap to for continuing profile work for three point arcs

* add draft animation

* tangent issue fix

* action rename

* tmp test fix up

* fix silly bug

* fix couple problems causing tests to fail

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* fix up

* add delet segment test for new segments

* update docs

* draft segments should look right

* add test for dragging new segment handles

* arc tools can be chained now

* make three point arc can start a new profile (not only extend existing paths)

* add test for equiping and unequiping the tool plus drawing with it

* fix console noise

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* clean up

* update rust/docs

* put toolbar mode check into fixture

* do thing for lee

* use TEST_COLORSs

* fix colors

* don't await file write

* remove commented code

* remove unneeded template strings

* power to **2

* remove magic numbers

* more string templates

* some odd bits of clean up

* arc should be enable in dev

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* add new simulation test

* fix test code from kwark migration

* issues Frank found

* fix deleting half complete ark

* fix

* small fix on dele index

* tsc post main merge

* fix up snaping to profile start

* add cross hari for three point arc

* block snapping if it's the only segment

* add tests for canceling arcTo halfway through

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-18 11:14:12 +11:00
cb0470a31d Change playwright to always use env vars (#5851)
* Change playwright to always use env vars

* Change to not be so noisy
2025-03-18 00:00:07 +00:00
ff6186f4f0 Format a whole directory easily (#5816)
* recast a whole directory

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

* move

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

* updates

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

* fixes

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

* updates

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

* fixes

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-17 15:55:25 -07:00
4dd669bd46 Hourly e2e tests only on Ubuntu (#5846)
* Attempt: Hourly tests on ubuntu only

* Attempt: Hourly tests on ubuntu only through os exlusion rules

* Attempt: Hourly tests on ubuntu only through dummy boolean key

* Clean up for PR
2025-03-17 17:01:33 -04:00
09131722e3 fix not giving miette error in bindings (#5844)
* try python unit test

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

* try python unit test

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

* updates

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

* updates

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

* updates

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

* updates

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

* fix

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

* updates

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

* fixes;

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

* fixes;

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-17 13:35:49 -07:00
87ab8fe78d Only one playwright worker and less retries. Plus auto-retries on snapshots (#5842)
* 8 shards, 1 workers, 10 retries

* Trigger CI

* Add retries to snapshots

* Clean up for PR, retry to 15

* Trigger CI

* Back to 4 shards for simplicity

* Revert "Back to 4 shards for simplicity"

This reverts commit 413de2fc61.
2025-03-17 15:53:48 -04:00
bc928a34ef Bug Fix: Implement automatic write to disk on route change or refresh (#5761)
* chore: implement faster write function to call when rerouting

* fix: codespell typo

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-17 15:52:23 -04:00
dca78acdf2 #4236 Fix corner rect panning bug (#5817)
* check mouse button in

* same for center rectangle

---------

Co-authored-by: 49fl <ircsurfer33@gmail.com>
2025-03-17 14:45:20 -04:00
40f4450995 Bump the minor group with 23 updates (#5836)
Bumps the minor group with 23 updates:

| Package | From | To |
| --- | --- | --- |
| [@codemirror/autocomplete](https://github.com/codemirror/autocomplete) | `6.17.0` | `6.18.6` |
| [@codemirror/language](https://github.com/codemirror/language) | `6.10.8` | `6.11.0` |
| [@fortawesome/fontawesome-svg-core](https://github.com/FortAwesome/Font-Awesome) | `6.6.0` | `6.7.2` |
| [@fortawesome/free-brands-svg-icons](https://github.com/FortAwesome/Font-Awesome) | `6.6.0` | `6.7.2` |
| [@fortawesome/free-solid-svg-icons](https://github.com/FortAwesome/Font-Awesome) | `6.6.0` | `6.7.2` |
| [bonjour-service](https://github.com/onlxltd/bonjour-service) | `1.2.1` | `1.3.0` |
| [fuse.js](https://github.com/krisk/Fuse) | `7.0.0` | `7.1.0` |
| [re-resizable](https://github.com/bokuweb/react-resizable-box) | `6.9.17` | `6.11.2` |
| [react-hot-toast](https://github.com/timolins/react-hot-toast) | `2.4.1` | `2.5.2` |
| [three](https://github.com/mrdoob/three.js) | `0.172.0` | `0.174.0` |
| [@types/three](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/three) | `0.172.0` | `0.174.0` |
| [uuid](https://github.com/uuidjs/uuid) | `11.0.2` | `11.1.0` |
| [vscode-uri](https://github.com/microsoft/vscode-uri) | `3.0.8` | `3.1.0` |
| [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) | `7.25.4` | `7.26.9` |
| [@electron-forge/cli](https://github.com/electron/forge) | `7.6.1` | `7.7.0` |
| [@electron-forge/plugin-fuses](https://github.com/electron/forge) | `7.6.1` | `7.7.0` |
| [@electron-forge/plugin-vite](https://github.com/electron/forge/tree/HEAD/packages/plugin/vite) | `7.6.1` | `7.7.0` |
| [@playwright/test](https://github.com/microsoft/playwright) | `1.49.1` | `1.51.0` |
| [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import) | `2.30.0` | `2.31.0` |
| [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) | `28.10.0` | `28.11.0` |
| [eslint-plugin-react-hooks](https://github.com/facebook/react/tree/HEAD/packages/eslint-plugin-react-hooks) | `5.1.0` | `5.2.0` |
| [typescript](https://github.com/microsoft/TypeScript) | `5.7.3` | `5.8.2` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.23.0` | `8.26.1` |


Updates `@codemirror/autocomplete` from 6.17.0 to 6.18.6
- [Changelog](https://github.com/codemirror/autocomplete/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/autocomplete/compare/6.17.0...6.18.6)

Updates `@codemirror/language` from 6.10.8 to 6.11.0
- [Changelog](https://github.com/codemirror/language/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/language/compare/6.10.8...6.11.0)

Updates `@fortawesome/fontawesome-svg-core` from 6.6.0 to 6.7.2
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.6.0...6.7.2)

Updates `@fortawesome/free-brands-svg-icons` from 6.6.0 to 6.7.2
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.6.0...6.7.2)

Updates `@fortawesome/free-solid-svg-icons` from 6.6.0 to 6.7.2
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.6.0...6.7.2)

Updates `bonjour-service` from 1.2.1 to 1.3.0
- [Release notes](https://github.com/onlxltd/bonjour-service/releases)
- [Commits](https://github.com/onlxltd/bonjour-service/compare/1.2.1...1.3.0)

Updates `fuse.js` from 7.0.0 to 7.1.0
- [Release notes](https://github.com/krisk/Fuse/releases)
- [Changelog](https://github.com/krisk/Fuse/blob/main/CHANGELOG.md)
- [Commits](https://github.com/krisk/Fuse/compare/v7.0.0...v7.1.0)

Updates `re-resizable` from 6.9.17 to 6.11.2
- [Release notes](https://github.com/bokuweb/react-resizable-box/releases)
- [Changelog](https://github.com/bokuweb/re-resizable/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bokuweb/react-resizable-box/commits)

Updates `react-hot-toast` from 2.4.1 to 2.5.2
- [Release notes](https://github.com/timolins/react-hot-toast/releases)
- [Commits](https://github.com/timolins/react-hot-toast/compare/v2.4.1...v2.5.2)

Updates `three` from 0.172.0 to 0.174.0
- [Release notes](https://github.com/mrdoob/three.js/releases)
- [Commits](https://github.com/mrdoob/three.js/commits)

Updates `@types/three` from 0.172.0 to 0.174.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/three)

Updates `uuid` from 11.0.2 to 11.1.0
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v11.0.2...v11.1.0)

Updates `vscode-uri` from 3.0.8 to 3.1.0
- [Release notes](https://github.com/microsoft/vscode-uri/releases)
- [Commits](https://github.com/microsoft/vscode-uri/compare/v3.0.8...v3.1.0)

Updates `@babel/preset-env` from 7.25.4 to 7.26.9
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.9/packages/babel-preset-env)

Updates `@electron-forge/cli` from 7.6.1 to 7.7.0
- [Release notes](https://github.com/electron/forge/releases)
- [Changelog](https://github.com/electron/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/electron/forge/compare/v7.6.1...v7.7.0)

Updates `@electron-forge/plugin-fuses` from 7.6.1 to 7.7.0
- [Release notes](https://github.com/electron/forge/releases)
- [Changelog](https://github.com/electron/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/electron/forge/compare/v7.6.1...v7.7.0)

Updates `@electron-forge/plugin-vite` from 7.6.1 to 7.7.0
- [Release notes](https://github.com/electron/forge/releases)
- [Changelog](https://github.com/electron/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/electron/forge/commits/v7.7.0/packages/plugin/vite)

Updates `@playwright/test` from 1.49.1 to 1.51.0
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.49.1...v1.51.0)

Updates `@types/three` from 0.172.0 to 0.174.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/three)

Updates `eslint-plugin-import` from 2.30.0 to 2.31.0
- [Release notes](https://github.com/import-js/eslint-plugin-import/releases)
- [Changelog](https://github.com/import-js/eslint-plugin-import/blob/main/CHANGELOG.md)
- [Commits](https://github.com/import-js/eslint-plugin-import/compare/v2.30.0...v2.31.0)

Updates `eslint-plugin-jest` from 28.10.0 to 28.11.0
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v28.10.0...v28.11.0)

Updates `eslint-plugin-react-hooks` from 5.1.0 to 5.2.0
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/HEAD/packages/eslint-plugin-react-hooks)

Updates `typescript` from 5.7.3 to 5.8.2
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.7.3...v5.8.2)

Updates `typescript-eslint` from 8.23.0 to 8.26.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.26.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@codemirror/autocomplete"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@codemirror/language"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@fortawesome/fontawesome-svg-core"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@fortawesome/free-brands-svg-icons"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@fortawesome/free-solid-svg-icons"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: bonjour-service
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: fuse.js
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: re-resizable
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: react-hot-toast
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: three
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@types/three"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: uuid
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: vscode-uri
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@babel/preset-env"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@electron-forge/cli"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@electron-forge/plugin-fuses"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@electron-forge/plugin-vite"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@playwright/test"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@types/three"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: eslint-plugin-import
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: eslint-plugin-jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: eslint-plugin-react-hooks
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: typescript-eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 10:45:35 -07:00
178d943423 Bump the minor group in /packages/codemirror-lsp-client with 4 updates (#5824)
Bumps the minor group in /packages/codemirror-lsp-client with 4 updates: [@codemirror/language](https://github.com/codemirror/language), [@codemirror/state](https://github.com/codemirror/state), [typescript](https://github.com/microsoft/TypeScript) and [vscode-uri](https://github.com/microsoft/vscode-uri).


Updates `@codemirror/language` from 6.10.2 to 6.11.0
- [Changelog](https://github.com/codemirror/language/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/language/compare/6.10.2...6.11.0)

Updates `@codemirror/state` from 6.4.1 to 6.5.2
- [Changelog](https://github.com/codemirror/state/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/state/compare/6.4.1...6.5.2)

Updates `typescript` from 5.7.2 to 5.8.2
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.7.2...v5.8.2)

Updates `vscode-uri` from 3.0.8 to 3.1.0
- [Release notes](https://github.com/microsoft/vscode-uri/releases)
- [Commits](https://github.com/microsoft/vscode-uri/compare/v3.0.8...v3.1.0)

---
updated-dependencies:
- dependency-name: "@codemirror/language"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: "@codemirror/state"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: typescript
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: vscode-uri
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 09:40:03 -07:00
e78788482e Move build:wasm commands to dedicated scripts (#5813)
* add script to build on mac mini

* Remove wasm-prep, rust flag only on wasm-pack build, add ps1 script

* Make it exectuable, tested on macOS

* Add set -e

* Stop scripts on error

---------

Co-authored-by: lf94 <ircsurfer33@gmail.com>
2025-03-17 12:24:40 -04:00
e50e9a00d4 Make scripts/get-latest-wasm-bundle.sh executable (#5791) 2025-03-17 12:23:28 -04:00
dc82b4c8ea Fix mixed units assemblies to work, regardless of project settings (#5818)
* Add mixed units test

* Add incorrect output

* Change to always set units since old units are not accurate

* Update output after fix
2025-03-17 15:26:56 +00:00
a8b0e1a771 Use arrays for multiple geometry (#5770)
* Parse [T] instead of T[] for array types

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* homogenous arrays, type coercion, remove solid set and sketch set, etc

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-03-17 17:57:26 +13:00
75a975b1e1 Replace snapshot mechanism with epochs (#5764)
* Make tag identifiers monotonic

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Use epochs rather than snapshots in memory

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-03-17 12:28:51 +13:00
3f02bb2065 deterministic id generator per module (#5811)
* deterministic id generator per module

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

* non

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

* updates

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

* do not remake the planes if they are alreaady made;

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

* updates

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

* do not remake the planes if they are alreaady made;

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

* clippy

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-15 17:08:39 +00:00
9c986d3aa8 Fix window creation failures on Mac (most noteable in CI) (#5809)
Allow window to be larger than screen on mac as well, fixing tests
2025-03-14 21:29:00 +00:00
4741d9592b Add edit flow for Shell thickness (#5525)
* WIP: Add edit flow for Shell thickness
Would fix #5406 but not like this :sad:

* Early win with working edit on shell

* Extend to logic to walls with tags

* Remove skip

* Add wall test

* Fixing inconsistencies in code. Tests not working on win

* Refactor addShell for consitency

* Clean up

* More clean up

* Add validation on both params

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Passing tests

* Prettier

* Change from test.skip to comment

* Clean up for review

* Add review suggestions and disable thickness validator

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Remove uneccessary changes

* Add edit flow for Shell thickness
Fixes #5406

* Enable edit step in test that works only if the start code is properly formatted

* Clean up for review

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-14 16:05:41 -04:00
351 changed files with 360311 additions and 413387 deletions

View File

@ -22,6 +22,13 @@
"rules": {
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-misused-promises": "error",
"@typescript-eslint/no-unused-vars": ["error", {
"varsIgnorePattern": "^_",
"argsIgnorePattern": "^_",
"ignoreRestSiblings": true,
"vars": "all",
"args": "none"
}],
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-autofocus": "off",
"jsx-a11y/no-noninteractive-element-interactions": "off",

View File

@ -75,7 +75,7 @@ jobs:
prepare-wasm:
# seperate job on Ubuntu to build or fetch the wasm blob once on the fastest runner
runs-on: namespace-profile-ubuntu-8-cores
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
needs: conditions
steps:
- uses: actions/checkout@v4
@ -163,7 +163,7 @@ jobs:
snapshots:
name: playwright:snapshots:ubuntu
runs-on: namespace-profile-ubuntu-8-cores
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
needs: [conditions, prepare-wasm]
steps:
- uses: actions/create-github-app-token@v1
@ -220,8 +220,12 @@ jobs:
- name: Run ubuntu/chrome snapshots
if: needs.conditions.outputs.should-run == 'true'
run: |
yarn test:snapshots
uses: nick-fields/retry@v3.0.2
with:
shell: bash
command: yarn test:snapshots
timeout_minutes: 30
max_attempts: 3
env:
CI: true
NODE_ENV: development
@ -233,19 +237,14 @@ jobs:
- uses: actions/upload-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}
with:
name: playwright-report-snapshots-${{ matrix.os }}-snapshot-${{ matrix.shardIndex }}-${{ github.sha }}
name: playwright-report-ubuntu-snapshot-${{ github.sha }}
path: playwright-report/
include-hidden-files: true
retention-days: 30
overwrite: true
- name: Clean up test-results
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}
continue-on-error: true
run: rm -r test-results
- name: check for changes
if: ${{ needs.conditions.outputs.should-run == 'true' && matrix.os == 'namespace-profile-ubuntu-8-cores' && matrix.shardIndex == 1 && github.ref != 'refs/heads/main' }}
if: ${{ needs.conditions.outputs.should-run == 'true' && github.ref != 'refs/heads/main' }}
shell: bash
id: git-check
run: |
@ -266,31 +265,36 @@ jobs:
git fetch origin
echo ${{ github.head_ref }}
git checkout ${{ github.head_ref }}
git commit -m "A snapshot a day keeps the bugs away! 📷🐛 (OS: ${{matrix.os}})" || true
git commit -m "A snapshot a day keeps the bugs away! 📷🐛" || true
git push
git push origin ${{ github.head_ref }}
# only upload artifacts if there's actually changes
- uses: actions/upload-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && steps.git-check.outputs.modified == 'true' }}
with:
name: playwright-report-ubuntu-${{ github.sha }}
path: playwright-report/
include-hidden-files: true
retention-days: 30
electron:
needs: [conditions, prepare-wasm]
timeout-minutes: 60
name: playwright:electron:${{ matrix.os }} ${{ matrix.shardIndex }} ${{ matrix.shardTotal }}
env:
OS_NAME: ${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}
name: playwright:electron:${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}:${{ matrix.shardIndex }}:${{ matrix.shardTotal }}
strategy:
fail-fast: false
matrix:
# TODO: enable self-hosted-windows-8-cores once available
os: [namespace-profile-ubuntu-8-cores, namespace-profile-macos-8-cores, windows-16-cores]
# TODO: enable namespace-profile-windows-latest once available
os:
- "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
- namespace-profile-macos-8-cores
- windows-latest
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
# Disable macos and windows tests on hourly e2e tests since we only care
# about server side changes.
# Technique from https://github.com/joaomcteixeira/python-project-skeleton/pull/31/files
isScheduled:
- ${{ github.event_name == 'schedule' }}
exclude:
- os: namespace-profile-macos-8-cores
isScheduled: true
- os: windows-latest
isScheduled: true
# TODO: add ref here for main and latest release tag
runs-on: ${{ matrix.os }}
steps:
@ -347,7 +351,7 @@ jobs:
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}
continue-on-error: true
with:
name: test-results-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/
- name: Run playwright/electron flow (with retries)
@ -356,9 +360,9 @@ jobs:
uses: nick-fields/retry@v3.0.2
with:
shell: bash
command: .github/ci-cd-scripts/playwright-electron.sh ${{matrix.shardIndex}} ${{matrix.shardTotal}} ${{matrix.os}}
timeout_minutes: 30
max_attempts: 25
command: .github/ci-cd-scripts/playwright-electron.sh ${{matrix.shardIndex}} ${{matrix.shardTotal}} ${{ env.OS_NAME }}
timeout_minutes: 45
max_attempts: 15
env:
CI: true
FAIL_ON_CONSOLE_ERRORS: true
@ -370,7 +374,7 @@ jobs:
- uses: actions/upload-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && always() }}
with:
name: test-results-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/
include-hidden-files: true
retention-days: 30
@ -379,7 +383,7 @@ jobs:
- uses: actions/upload-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && always() }}
with:
name: playwright-report-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
name: playwright-report-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
include-hidden-files: true
retention-days: 30

View File

@ -105,7 +105,7 @@ Finally, to run the web app only, run:
yarn start
```
If you're not a Zoo employee you won't be able to access the dev environment, you should copy everything from `.env.production` to `.env.development` to make it point to production instead, then when you navigate to `localhost:3000` the easiest way to sign in is to paste `localStorage.setItem('TOKEN_PERSIST_KEY', "your-token-from-https://zoo.dev/account/api-tokens")` replacing the with a real token from https://zoo.dev/account/api-tokens of course, then navigate to localhost:3000 again. Note that navigating to `localhost:3000/signin` removes your token so you will need to set the token again.
If you're not a Zoo employee you won't be able to access the dev environment, you should copy everything from `.env.production` to `.env.development.local` to make it point to production instead, then when you navigate to `localhost:3000` the easiest way to sign in is to paste `localStorage.setItem('TOKEN_PERSIST_KEY', "your-token-from-https://zoo.dev/account/api-tokens")` replacing the with a real token from https://zoo.dev/account/api-tokens of course, then navigate to `localhost:3000` again. Note that navigating to `localhost:3000/signin` removes your token so you will need to set the token again.
### Development environment variables
@ -122,7 +122,7 @@ Third-Party Cookies".
## Desktop
To spin up the desktop app, `yarn install` and `yarn build:wasm` need to have been done before hand then
To spin up the desktop app, `yarn install` and `yarn build:wasm` need to have been done before hand then:
```
yarn tron:start
@ -130,13 +130,13 @@ yarn tron:start
This will start the application and hot-reload on changes.
Devtools can be opened with the usual Cmd-Opt-I (Mac) or Ctrl-Shift-I (Linux and Windows).
Devtools can be opened with the usual Command-Option-I (macOS) or Ctrl-Shift-I (Linux and Windows).
To package the app for your platform with electron-builder, run `yarn tronb:package:dev` (or `yarn tronb:package:prod` to point to the .env.production variables)
To package the app for your platform with electron-builder, run `yarn tronb:package:dev` (or `yarn tronb:package:prod` to point to the .env.production variables).
## Checking out commits / Bisecting
Which commands from setup are one off vs need to be run every time?
Which commands from setup are one off vs. need to be run every time?
The following will need to be run when checking out a new commit and guarantees the build is not stale:

View File

@ -10,11 +10,11 @@ This will work on any solid, including extruded solids, revolved solids, and she
```js
appearance(
solidSet: SolidSet,
solids: [Solid],
color: String,
metalness?: number,
roughness?: number,
): SolidSet
): [Solid]
```
@ -22,14 +22,14 @@ appearance(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `solidSet` | [`SolidSet`](/docs/kcl/types/SolidSet) | The solid(s) whose appearance is being set | Yes |
| `solids` | [`[Solid]`](/docs/kcl/types/Solid) | The solid(s) whose appearance is being set | Yes |
| `color` | `String` | Color of the new material, a hex string like '#ff0000' | Yes |
| `metalness` | [`number`](/docs/kcl/types/number) | Metalness of the new material, a percentage like 95.7. | No |
| `roughness` | [`number`](/docs/kcl/types/number) | Roughness of the new material, a percentage like 95.7. | No |
### Returns
[`SolidSet`](/docs/kcl/types/SolidSet) - A solid or a group of solids.
[`[Solid]`](/docs/kcl/types/Solid)
### Examples

View File

@ -10,9 +10,9 @@ You can provide more than one sketch to extrude, and they will all be extruded i
```js
extrude(
sketchSet: SketchSet,
sketches: [Sketch],
length: number,
): SolidSet
): [Solid]
```
@ -20,12 +20,12 @@ extrude(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `sketchSet` | [`SketchSet`](/docs/kcl/types/SketchSet) | Which sketch or set of sketches should be extruded | Yes |
| `sketches` | [`[Sketch]`](/docs/kcl/types/Sketch) | Which sketch or sketches should be extruded | Yes |
| `length` | [`number`](/docs/kcl/types/number) | How far to extrude the given sketches | Yes |
### Returns
[`SolidSet`](/docs/kcl/types/SolidSet) - A solid or a group of solids.
[`[Solid]`](/docs/kcl/types/Solid)
### Examples

View File

@ -10,7 +10,7 @@ Use a 2-dimensional sketch to cut a hole in another 2-dimensional sketch.
```js
hole(
holeSketch: SketchSet,
holeSketch: [Sketch],
sketch: Sketch,
): Sketch
```
@ -20,7 +20,7 @@ hole(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `holeSketch` | [`SketchSet`](/docs/kcl/types/SketchSet) | A sketch or a group of sketches. | Yes |
| `holeSketch` | [`[Sketch]`](/docs/kcl/types/Sketch) | | Yes |
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | | Yes |
### Returns

View File

@ -13,7 +13,7 @@ Mirror occurs around a local sketch axis rather than a global axis.
```js
mirror2d(
data: Mirror2dData,
sketchSet: SketchSet,
sketches: [Sketch],
): [Sketch]
```
@ -23,7 +23,7 @@ mirror2d(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `data` | [`Mirror2dData`](/docs/kcl/types/Mirror2dData) | Data for a mirror. | Yes |
| `sketchSet` | [`SketchSet`](/docs/kcl/types/SketchSet) | A sketch or a group of sketches. | Yes |
| `sketches` | [`[Sketch]`](/docs/kcl/types/Sketch) | | Yes |
### Returns

View File

@ -10,7 +10,7 @@ Repeat a 2-dimensional sketch some number of times along a partial or complete c
```js
patternCircular2d(
sketchSet: SketchSet,
sketchSet: [Sketch],
instances: integer,
center: [number],
arcDegrees: number,
@ -24,7 +24,7 @@ patternCircular2d(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `sketchSet` | [`SketchSet`](/docs/kcl/types/SketchSet) | Which sketch(es) to pattern | Yes |
| `sketchSet` | [`[Sketch]`](/docs/kcl/types/Sketch) | Which sketch(es) to pattern | Yes |
| `instances` | `integer` | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
| `center` | [`[number]`](/docs/kcl/types/number) | The center about which to make the pattern. This is a 2D vector. | Yes |
| `arcDegrees` | [`number`](/docs/kcl/types/number) | The arc angle (in degrees) to place the repetitions. Must be greater than 0. | Yes |

View File

@ -10,7 +10,7 @@ Repeat a 3-dimensional solid some number of times along a partial or complete ci
```js
patternCircular3d(
solidSet: SolidSet,
solids: [Solid],
instances: integer,
axis: [number],
center: [number],
@ -25,7 +25,7 @@ patternCircular3d(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `solidSet` | [`SolidSet`](/docs/kcl/types/SolidSet) | Which solid(s) to pattern | Yes |
| `solids` | [`[Solid]`](/docs/kcl/types/Solid) | Which solid(s) to pattern | Yes |
| `instances` | `integer` | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
| `axis` | [`[number]`](/docs/kcl/types/number) | The axis around which to make the pattern. This is a 3D vector | Yes |
| `center` | [`[number]`](/docs/kcl/types/number) | The center about which to make the pattern. This is a 3D vector. | Yes |

View File

@ -10,7 +10,7 @@ Repeat a 2-dimensional sketch along some dimension, with a dynamic amount of dis
```js
patternLinear2d(
sketchSet: SketchSet,
sketches: [Sketch],
instances: integer,
distance: number,
axis: [number],
@ -23,7 +23,7 @@ patternLinear2d(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `sketchSet` | [`SketchSet`](/docs/kcl/types/SketchSet) | The sketch(es) to duplicate | Yes |
| `sketches` | [`[Sketch]`](/docs/kcl/types/Sketch) | The sketch(es) to duplicate | Yes |
| `instances` | `integer` | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
| `distance` | [`number`](/docs/kcl/types/number) | Distance between each repetition. Also known as 'spacing'. | Yes |
| `axis` | [`[number]`](/docs/kcl/types/number) | The axis of the pattern. A 2D vector. | Yes |

View File

@ -10,7 +10,7 @@ Repeat a 3-dimensional solid along a linear path, with a dynamic amount of dista
```js
patternLinear3d(
solidSet: SolidSet,
solids: [Solid],
instances: integer,
distance: number,
axis: [number],
@ -23,7 +23,7 @@ patternLinear3d(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `solidSet` | [`SolidSet`](/docs/kcl/types/SolidSet) | The solid(s) to duplicate | Yes |
| `solids` | [`[Solid]`](/docs/kcl/types/Solid) | The solid(s) to duplicate | Yes |
| `instances` | `integer` | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
| `distance` | [`number`](/docs/kcl/types/number) | Distance between each repetition. Also known as 'spacing'. | Yes |
| `axis` | [`[number]`](/docs/kcl/types/number) | The axis of the pattern. A 2D vector. | Yes |

View File

@ -36,7 +36,7 @@ The transform function returns a transform object. All properties of the object
```js
patternTransform(
solidSet: SolidSet,
solids: [Solid],
instances: integer,
transform: FunctionSource,
useOriginal?: bool,
@ -48,7 +48,7 @@ patternTransform(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `solidSet` | [`SolidSet`](/docs/kcl/types/SolidSet) | The solid(s) to duplicate | Yes |
| `solids` | [`[Solid]`](/docs/kcl/types/Solid) | The solid(s) to duplicate | Yes |
| `instances` | `integer` | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
| `transform` | `FunctionSource` | How each replica should be transformed. The transform function takes a single parameter: an integer representing which number replication the transform is for. E.g. the first replica to be transformed will be passed the argument `1`. This simplifies your math: the transform function can rely on id `0` being the original instance passed into the `patternTransform`. See the examples. | Yes |
| `useOriginal` | [`bool`](/docs/kcl/types/bool) | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false. | No |

View File

@ -10,7 +10,7 @@ Just like patternTransform, but works on 2D sketches not 3D solids.
```js
patternTransform2d(
sketchSet: SketchSet,
sketches: [Sketch],
instances: integer,
transform: FunctionSource,
useOriginal?: bool,
@ -22,7 +22,7 @@ patternTransform2d(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `sketchSet` | [`SketchSet`](/docs/kcl/types/SketchSet) | The sketch(es) to duplicate | Yes |
| `sketches` | [`[Sketch]`](/docs/kcl/types/Sketch) | The sketch(es) to duplicate | Yes |
| `instances` | `integer` | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
| `transform` | `FunctionSource` | How each replica should be transformed. The transform function takes a single parameter: an integer representing which number replication the transform is for. E.g. the first replica to be transformed will be passed the argument `1`. This simplifies your math: the transform function can rely on id `0` being the original instance passed into the `patternTransform`. See the examples. | Yes |
| `useOriginal` | [`bool`](/docs/kcl/types/bool) | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false. | No |

View File

@ -15,8 +15,8 @@ You can provide more than one sketch to revolve, and they will all be revolved a
```js
revolve(
data: RevolveData,
sketchSet: SketchSet,
): SolidSet
sketches: [Sketch],
): [Solid]
```
@ -25,11 +25,11 @@ revolve(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `data` | [`RevolveData`](/docs/kcl/types/RevolveData) | Data for revolution surfaces. | Yes |
| `sketchSet` | [`SketchSet`](/docs/kcl/types/SketchSet) | A sketch or a group of sketches. | Yes |
| `sketches` | [`[Sketch]`](/docs/kcl/types/Sketch) | | Yes |
### Returns
[`SolidSet`](/docs/kcl/types/SolidSet) - A solid or a group of solids.
[`[Solid]`](/docs/kcl/types/Solid)
### Examples

View File

@ -24,7 +24,7 @@ When rotating a part around an axis, you specify the axis of rotation and the an
```js
rotate(
solidSet: SolidOrImportedGeometry,
solids: SolidOrImportedGeometry,
roll?: number,
pitch?: number,
yaw?: number,
@ -39,7 +39,7 @@ rotate(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `solidSet` | [`SolidOrImportedGeometry`](/docs/kcl/types/SolidOrImportedGeometry) | The solid or set of solids to rotate. | Yes |
| `solids` | [`SolidOrImportedGeometry`](/docs/kcl/types/SolidOrImportedGeometry) | The solid or set of solids to rotate. | Yes |
| `roll` | [`number`](/docs/kcl/types/number) | The roll angle in degrees. Must be used with `pitch` and `yaw`. Must be between -360 and 360. | No |
| `pitch` | [`number`](/docs/kcl/types/number) | The pitch angle in degrees. Must be used with `roll` and `yaw`. Must be between -360 and 360. | No |
| `yaw` | [`number`](/docs/kcl/types/number) | The yaw angle in degrees. Must be used with `roll` and `pitch`. Must be between -360 and 360. | No |

View File

@ -12,7 +12,7 @@ If you want to apply the transform in global space, set `global` to `true`. The
```js
scale(
solidSet: SolidOrImportedGeometry,
solids: SolidOrImportedGeometry,
scale: [number],
global?: bool,
): SolidOrImportedGeometry
@ -23,7 +23,7 @@ scale(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `solidSet` | [`SolidOrImportedGeometry`](/docs/kcl/types/SolidOrImportedGeometry) | The solid or set of solids to scale. | Yes |
| `solids` | [`SolidOrImportedGeometry`](/docs/kcl/types/SolidOrImportedGeometry) | The solid or set of solids to scale. | Yes |
| `scale` | [`[number]`](/docs/kcl/types/number) | The scale factor for the x, y, and z axes. | Yes |
| `global` | [`bool`](/docs/kcl/types/bool) | If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move. | No |

View File

@ -10,10 +10,10 @@ Remove volume from a 3-dimensional shape such that a wall of the provided thickn
```js
shell(
solidSet: SolidSet,
solids: [Solid],
thickness: number,
faces: [FaceTag],
): SolidSet
): [Solid]
```
@ -21,13 +21,13 @@ shell(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `solidSet` | [`SolidSet`](/docs/kcl/types/SolidSet) | Which solid (or solids) to shell out | Yes |
| `solids` | [`[Solid]`](/docs/kcl/types/Solid) | Which solid (or solids) to shell out | Yes |
| `thickness` | [`number`](/docs/kcl/types/number) | The thickness of the shell | Yes |
| `faces` | [`[FaceTag]`](/docs/kcl/types/FaceTag) | The faces you want removed | Yes |
### Returns
[`SolidSet`](/docs/kcl/types/SolidSet) - A solid or a group of solids.
[`[Solid]`](/docs/kcl/types/Solid)
### Examples

File diff suppressed because it is too large Load Diff

View File

@ -12,11 +12,11 @@ You can provide more than one sketch to sweep, and they will all be swept along
```js
sweep(
sketchSet: SketchSet,
sketches: [Sketch],
path: SweepPath,
sectional?: bool,
tolerance?: number,
): SolidSet
): [Solid]
```
@ -24,14 +24,14 @@ sweep(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `sketchSet` | [`SketchSet`](/docs/kcl/types/SketchSet) | The sketch or set of sketches that should be swept in space | Yes |
| `sketches` | [`[Sketch]`](/docs/kcl/types/Sketch) | The sketch or set of sketches that should be swept in space | Yes |
| `path` | [`SweepPath`](/docs/kcl/types/SweepPath) | The path to sweep the sketch along | Yes |
| `sectional` | [`bool`](/docs/kcl/types/bool) | If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components. | No |
| `tolerance` | [`number`](/docs/kcl/types/number) | Tolerance for this operation | No |
### Returns
[`SolidSet`](/docs/kcl/types/SolidSet) - A solid or a group of solids.
[`[Solid]`](/docs/kcl/types/Solid)
### Examples

View File

@ -10,7 +10,7 @@ Move a solid.
```js
translate(
solidSet: SolidOrImportedGeometry,
solids: SolidOrImportedGeometry,
translate: [number],
global?: bool,
): SolidOrImportedGeometry
@ -21,7 +21,7 @@ translate(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `solidSet` | [`SolidOrImportedGeometry`](/docs/kcl/types/SolidOrImportedGeometry) | The solid or set of solids to move. | Yes |
| `solids` | [`SolidOrImportedGeometry`](/docs/kcl/types/SolidOrImportedGeometry) | The solid or set of solids to move. | Yes |
| `translate` | [`[number]`](/docs/kcl/types/number) | The amount to move the solid in all three axes. | Yes |
| `global` | [`bool`](/docs/kcl/types/bool) | If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move. | No |

View File

@ -100,6 +100,22 @@ Any KCL value.
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `HomArray`| | No |
| `value` |`[` [`KclValue`](/docs/kcl/types/KclValue) `]`| | No |
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
@ -122,7 +138,6 @@ Any KCL value.
|----------|------|-------------|----------|
| `type` |enum: [`TagIdentifier`](/docs/kcl/types#tag-identifier)| | No |
| `value` |[`string`](/docs/kcl/types/string)| | No |
| `info` |[`TagEngineInfo`](/docs/kcl/types/TagEngineInfo)| | No |
----
@ -200,22 +215,6 @@ Any KCL value.
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Sketches`| | No |
| `value` |`[` [`Sketch`](/docs/kcl/types/Sketch) `]`| | No |
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
@ -232,22 +231,6 @@ Any KCL value.
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Solids`| | No |
| `value` |`[` [`Solid`](/docs/kcl/types/Solid) `]`| | No |
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
@ -338,22 +321,6 @@ Data for an imported geometry.
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Tombstone`| | No |
| `value` |`null`| | No |
----

View File

@ -126,6 +126,30 @@ A base path.
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
----
A base path.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `ArcThreePoint`| | No |
| `p1` |`[number, number]`| Point 1 of the arc (base on the end of previous segment) | No |
| `p2` |`[number, number]`| Point 2 of the arc (interior kwarg) | No |
| `p3` |`[number, number]`| Point 3 of the arc (end kwarg) | No |
| `from` |`[number, number]`| The from point. | No |
| `to` |`[number, number]`| The to point. | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A unit of length. | No |
| [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No |
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
----
A path that is horizontal.

View File

@ -1,56 +0,0 @@
---
title: "SketchSet"
excerpt: "A sketch or a group of sketches."
layout: manual
---
A sketch or a group of sketches.
**This schema accepts exactly one of the following:**
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `sketch`| | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the sketch (this will change when the engine's reference to it changes). | No |
| `paths` |`[` [`Path`](/docs/kcl/types/Path) `]`| The paths in the sketch. | No |
| `on` |[`SketchSurface`](/docs/kcl/types/SketchSurface)| What the sketch is on (can be a plane or a face). | No |
| `start` |[`BasePath`](/docs/kcl/types/BasePath)| The starting path. | No |
| `tags` |`object`| Tag identifiers that have been declared in this sketch. | No |
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The original id of the sketch. This stays the same even if the sketch is is sketched on face etc. | No |
| `originalId` |[`string`](/docs/kcl/types/string)| | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A unit of length. | No |
----
**Type:** `[object, array]`
`[` [`Sketch`](/docs/kcl/types/Sketch) `]`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `sketches`| | No |
----

View File

@ -12,30 +12,6 @@ Data for a solid or an imported geometry.
**This schema accepts exactly one of the following:**
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `solid`| | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the solid. | No |
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID of the solid. Unlike `id`, this doesn't change. | No |
| `value` |`[` [`ExtrudeSurface`](/docs/kcl/types/ExtrudeSurface) `]`| The extrude surfaces. | No |
| `sketch` |[`Sketch`](/docs/kcl/types/Sketch)| The sketch. | No |
| `height` |[`number`](/docs/kcl/types/number)| The height of the solid. | No |
| `startCapId` |[`string`](/docs/kcl/types/string)| The id of the extrusion start cap | No |
| `endCapId` |[`string`](/docs/kcl/types/string)| The id of the extrusion end cap | No |
| `edgeCuts` |`[` [`EdgeCut`](/docs/kcl/types/EdgeCut) `]`| Chamfers or fillets on this solid. | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A unit of length. | No |
----
Data for an imported geometry.
**Type:** `object`

View File

@ -1,57 +0,0 @@
---
title: "SolidSet"
excerpt: "A solid or a group of solids."
layout: manual
---
A solid or a group of solids.
**This schema accepts exactly one of the following:**
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `solid`| | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the solid. | No |
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID of the solid. Unlike `id`, this doesn't change. | No |
| `value` |`[` [`ExtrudeSurface`](/docs/kcl/types/ExtrudeSurface) `]`| The extrude surfaces. | No |
| `sketch` |[`Sketch`](/docs/kcl/types/Sketch)| The sketch. | No |
| `height` |[`number`](/docs/kcl/types/number)| The height of the solid. | No |
| `startCapId` |[`string`](/docs/kcl/types/string)| The id of the extrusion start cap | No |
| `endCapId` |[`string`](/docs/kcl/types/string)| The id of the extrusion end cap | No |
| `edgeCuts` |`[` [`EdgeCut`](/docs/kcl/types/EdgeCut) `]`| Chamfers or fillets on this solid. | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A unit of length. | No |
----
**Type:** `[object, array]`
`[` [`Solid`](/docs/kcl/types/Solid) `]`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `solids`| | No |
----

View File

@ -100,7 +100,8 @@ test(
try {
const outputGltf = await fsp.readFile(firstFileFullPath)
return outputGltf.byteLength
} catch (e) {
} catch (error: unknown) {
void error
return 0
}
},
@ -179,7 +180,8 @@ test(
try {
const outputGltf = await fsp.readFile(secondFileFullPath)
return outputGltf.byteLength
} catch (e) {
} catch (error: unknown) {
void error
return 0
}
},

View File

@ -1197,7 +1197,7 @@ test.describe('Undo and redo do not keep history when navigating between files',
`cloned file has an incremented name and same contents`,
{ tag: '@electron' },
async ({ page, context, homePage }, testInfo) => {
const { panesOpen, createNewFile, cloneFile } = await getUtils(page, test)
const { panesOpen, cloneFile } = await getUtils(page, test)
const { dir } = await context.folderSetupFn(async (dir) => {
const finalDir = join(dir, 'testDefault')

View File

@ -3,25 +3,15 @@
import type {
BrowserContext,
ElectronApplication,
Fixtures as PlaywrightFixtures,
TestInfo,
Page,
} from '@playwright/test'
import {
_electron as electron,
PlaywrightTestArgs,
PlaywrightWorkerArgs,
} from '@playwright/test'
import { _electron as electron } from '@playwright/test'
import * as TOML from '@iarna/toml'
import {
TEST_SETTINGS_KEY,
TEST_SETTINGS_CORRUPTED,
TEST_SETTINGS,
TEST_SETTINGS_DEFAULT_THEME,
} from '../storageStates'
import { SETTINGS_FILE_NAME, PROJECT_SETTINGS_FILE_NAME } from 'lib/constants'
import { TEST_SETTINGS } from '../storageStates'
import { SETTINGS_FILE_NAME } from 'lib/constants'
import { getUtils, setup } from '../test-utils'
import fsp from 'fs/promises'
import fs from 'node:fs'
@ -31,7 +21,6 @@ import { EditorFixture } from './editorFixture'
import { ToolbarFixture } from './toolbarFixture'
import { SceneFixture } from './sceneFixture'
import { HomePageFixture } from './homePageFixture'
import { unsafeTypedKeys } from 'lib/utils'
import { DeepPartial } from 'lib/types'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
@ -278,13 +267,14 @@ export class ElectronZoo {
if (fs.existsSync(this.projectDirName)) {
await fsp.rm(this.projectDirName, { recursive: true })
}
} catch (e) {
console.error(e)
} catch (_e) {
console.error(_e)
}
try {
await fsp.mkdir(this.projectDirName)
} catch (e) {
} catch (error: unknown) {
void error
// Not a problem if it already exists.
}

View File

@ -8,6 +8,7 @@ import {
} from '../test-utils'
import { SidebarType } from 'components/ModelingSidebar/ModelingPanes'
import { SIDEBAR_BUTTON_SUFFIX } from 'lib/constants'
import { ToolbarModeName } from 'lib/toolbar'
export class ToolbarFixture {
public page: Page
@ -120,6 +121,15 @@ export class ToolbarFixture {
// this is for the engine animation, as it takes 500ms to complete
await this.page.waitForTimeout(600)
}
private _getMode = () =>
this.page.locator('[data-current-mode]').getAttribute('data-current-mode')
expectToolbarMode = {
toBe: (mode: ToolbarModeName) => expect.poll(this._getMode).toEqual(mode),
not: {
toBe: (mode: ToolbarModeName) =>
expect.poll(this._getMode).not.toEqual(mode),
},
}
private _serialiseFileTree = async () => {
return this.page
@ -176,6 +186,22 @@ export class ToolbarFixture {
).toBeVisible()
await this.page.getByTestId('dropdown-circle-three-points').click()
}
selectArc = async () => {
await this.page
.getByRole('button', { name: 'caret down Tangential Arc:' })
.click()
await expect(this.page.getByTestId('dropdown-arc')).toBeVisible()
await this.page.getByTestId('dropdown-arc').click()
}
selectThreePointArc = async () => {
await this.page
.getByRole('button', { name: 'caret down Tangential Arc:' })
.click()
await expect(
this.page.getByTestId('dropdown-three-point-arc')
).toBeVisible()
await this.page.getByTestId('dropdown-three-point-arc').click()
}
async closePane(paneId: SidebarType) {
return closePane(this.page, paneId + SIDEBAR_BUTTON_SUFFIX)

View File

@ -1024,7 +1024,7 @@ openSketch = startSketchOn('XY')
await page.waitForTimeout(15000)
await test.step(`Look for the blue of the XZ plane`, async () => {
await scene.expectPixelColor([50, 51, 96], testPoint, 15)
//await scene.expectPixelColor([50, 51, 96], testPoint, 15) // FIXME
})
await test.step(`Go through the command bar flow`, async () => {
await toolbar.offsetPlaneButton.click()
@ -1066,7 +1066,7 @@ openSketch = startSketchOn('XY')
)
await operationButton.click({ button: 'left' })
await page.keyboard.press('Delete')
await scene.expectPixelColor([50, 51, 96], testPoint, 15)
//await scene.expectPixelColor([50, 51, 96], testPoint, 15) // FIXME
})
})
@ -1906,7 +1906,6 @@ extrude001 = extrude(sketch001, length = -12)
// Locators
const firstEdgeLocation = { x: 600, y: 193 }
const secondEdgeLocation = { x: 600, y: 383 }
const bodyLocation = { x: 630, y: 290 }
const [clickOnFirstEdge] = scene.makeMouseHelpers(
firstEdgeLocation.x,
firstEdgeLocation.y
@ -1919,7 +1918,6 @@ extrude001 = extrude(sketch001, length = -12)
// Colors
const edgeColorWhite: [number, number, number] = [248, 248, 248]
const edgeColorYellow: [number, number, number] = [251, 251, 40] // Mac:B=67 Ubuntu:B=12
const bodyColor: [number, number, number] = [155, 155, 155]
const chamferColor: [number, number, number] = [168, 168, 168]
const backgroundColor: [number, number, number] = [30, 30, 30]
const lowTolerance = 20
@ -2271,8 +2269,8 @@ chamfer04 = chamfer(extrude001, length = 5, tags = [getOppositeEdge(seg02)])
cmdBar,
}) => {
const initialCode = `sketch001 = startSketchOn('XZ')
|> circle(center = [0, 0], radius = 30)
extrude001 = extrude(sketch001, length = 30)
|> circle(center = [0, 0], radius = 30)
extrude001 = extrude(sketch001, length = 30)
`
await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode)
@ -2286,6 +2284,8 @@ chamfer04 = chamfer(extrude001, length = 5, tags = [getOppositeEdge(seg02)])
const [clickOnCap] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
const shellDeclaration =
"shell001 = shell(extrude001, faces = ['end'], thickness = 5)"
const editedShellDeclaration =
"shell001 = shell(extrude001, faces = ['end'], thickness = 2)"
await test.step(`Look for the grey of the shape`, async () => {
await scene.expectPixelColor([127, 127, 127], testPoint, 15)
@ -2352,6 +2352,45 @@ chamfer04 = chamfer(extrude001, length = 5, tags = [getOppositeEdge(seg02)])
})
await scene.expectPixelColor([146, 146, 146], testPoint, 15)
})
await test.step('Edit shell via feature tree selection works', async () => {
await toolbar.closePane('code')
await toolbar.openPane('feature-tree')
const operationButton = await toolbar.getFeatureTreeOperation(
'Shell',
0
)
await operationButton.dblclick()
await cmdBar.expectState({
stage: 'arguments',
currentArgKey: 'thickness',
currentArgValue: '5',
headerArguments: {
Thickness: '5',
},
highlightedHeaderArg: 'thickness',
commandName: 'Shell',
})
await page.keyboard.insertText('2')
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Thickness: '2',
},
commandName: 'Shell',
})
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await scene.expectPixelColor([150, 150, 150], testPoint, 15)
await toolbar.openPane('code')
await editor.expectEditor.toContain(editedShellDeclaration)
await editor.expectState({
diagnostics: [],
activeLines: [editedShellDeclaration],
highlightedCode: '',
})
})
})
})
@ -2387,6 +2426,8 @@ extrude001 = extrude(sketch001, length = 40)
const mutatedCode = 'xLine(length = -40, tag = $seg01)'
const shellDeclaration =
"shell001 = shell(extrude001, faces = ['end', seg01], thickness = 5)"
const editedShellDeclaration =
"shell001 = shell(extrude001, faces = ['end', seg01], thickness = 1)"
await test.step(`Look for the grey of the shape`, async () => {
await scene.expectPixelColor([99, 99, 99], testPoint, 15)
@ -2435,6 +2476,41 @@ extrude001 = extrude(sketch001, length = 40)
await scene.expectPixelColor([49, 49, 49], testPoint, 15)
})
await test.step('Edit shell via feature tree selection works', async () => {
await editor.closePane()
const operationButton = await toolbar.getFeatureTreeOperation('Shell', 0)
await operationButton.dblclick({ button: 'left' })
await cmdBar.expectState({
stage: 'arguments',
currentArgKey: 'thickness',
currentArgValue: '5',
headerArguments: {
Thickness: '5',
},
highlightedHeaderArg: 'thickness',
commandName: 'Shell',
})
await page.keyboard.insertText('1')
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Thickness: '1',
},
commandName: 'Shell',
})
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await scene.expectPixelColor([150, 150, 150], testPoint, 15)
await toolbar.openPane('code')
await editor.expectEditor.toContain(editedShellDeclaration)
await editor.expectState({
diagnostics: [],
activeLines: [editedShellDeclaration],
highlightedCode: '',
})
})
await test.step('Delete shell via feature tree selection', async () => {
await editor.closePane()
const operationButton = await toolbar.getFeatureTreeOperation('Shell', 0)
@ -2529,7 +2605,7 @@ extrude002 = extrude(sketch002, length = 50)
highlightedCode: '',
})
await toolbar.closePane('code')
await scene.expectPixelColor([73, 73, 73], testPoint, 15)
await scene.expectPixelColor([80, 80, 80], testPoint, 15)
})
})
})

View File

@ -539,7 +539,8 @@ test.describe('Can export from electron app', () => {
try {
const outputGltf = await fsp.readFile(filepath)
return outputGltf.byteLength
} catch (e) {
} catch (error: unknown) {
void error
return 0
}
},

View File

@ -53,46 +53,47 @@ sketch003 = startSketchOn('XY')
|> close()
extrude003 = extrude(sketch003, length = 20)
`
test.describe('edit with AI example snapshots', () => {
test(
`change colour`,
{ tag: '@snapshot' },
async ({ context, homePage, cmdBar, editor, page, scene }) => {
await context.addInitScript((file) => {
localStorage.setItem('persistCode', file)
}, file)
await homePage.goToModelingScene()
await scene.waitForExecutionDone()
test(
`change colour`,
{ tag: '@snapshot' },
async ({ context, homePage, cmdBar, editor, page, scene }) => {
await context.addInitScript((file) => {
localStorage.setItem('persistCode', file)
}, file)
await homePage.goToModelingScene()
await scene.waitForExecutionDone()
const body1CapCoords = { x: 571, y: 351 }
const [clickBody1Cap] = scene.makeMouseHelpers(
body1CapCoords.x,
body1CapCoords.y
)
const yellow: [number, number, number] = [179, 179, 131]
const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
const body1CapCoords = { x: 571, y: 351 }
const [clickBody1Cap] = scene.makeMouseHelpers(
body1CapCoords.x,
body1CapCoords.y
)
const yellow: [number, number, number] = [179, 179, 131]
const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
await test.step('wait for scene to load select body and check selection came through', async () => {
await scene.expectPixelColor([134, 134, 134], body1CapCoords, 15)
await clickBody1Cap()
await scene.expectPixelColor(yellow, body1CapCoords, 20)
await editor.expectState({
highlightedCode: '',
activeLines: ['|>startProfileAt([-73.64,-42.89],%)'],
diagnostics: [],
await test.step('wait for scene to load select body and check selection came through', async () => {
await scene.expectPixelColor([134, 134, 134], body1CapCoords, 15)
await clickBody1Cap()
await scene.expectPixelColor(yellow, body1CapCoords, 20)
await editor.expectState({
highlightedCode: '',
activeLines: ['|>startProfileAt([-73.64,-42.89],%)'],
diagnostics: [],
})
})
})
await test.step('fire off edit prompt', async () => {
await cmdBar.captureTextToCadRequestSnapshot(test.info())
await cmdBar.openCmdBar('promptToEdit')
// being specific about the color with a hex means asserting pixel color is more stable
await page
.getByTestId('cmd-bar-arg-value')
.fill('make this neon green please, use #39FF14')
await page.waitForTimeout(100)
await cmdBar.progressCmdBar()
await expect(submittingToast).toBeVisible()
})
}
)
await test.step('fire off edit prompt', async () => {
await cmdBar.captureTextToCadRequestSnapshot(test.info())
await cmdBar.openCmdBar('promptToEdit')
// being specific about the color with a hex means asserting pixel color is more stable
await page
.getByTestId('cmd-bar-arg-value')
.fill('make this neon green please, use #39FF14')
await page.waitForTimeout(100)
await cmdBar.progressCmdBar()
await expect(submittingToast).toBeVisible()
})
}
)
})

View File

@ -319,7 +319,6 @@ extrude001 = extrude(sketch001, length = 50)
'when engine fails export we handle the failure and alert the user',
{ tag: '@skipLocalEngine' },
async ({ scene, page, homePage, cmdBar }) => {
const u = await getUtils(page)
await page.addInitScript(
async ({ code }) => {
localStorage.setItem('persistCode', code)
@ -636,11 +635,8 @@ extrude001 = extrude(sketch001, length = 50)
await homePage.goToModelingScene()
})
const toolBarMode = () =>
page.locator('[data-currentMode]').getAttribute('data-currentMode')
await test.step('Start sketch and select a plane', async () => {
await expect.poll(toolBarMode).toEqual('modeling')
await toolbar.expectToolbarMode.toBe('modeling')
// Click the start sketch button
await toolbar.startSketchPlaneSelection()
@ -649,10 +645,10 @@ extrude001 = extrude(sketch001, length = 50)
// Check that the modeling toolbar doesn't appear during the animation
// The animation typically takes around 500ms, so we'll check for a second
await expect.poll(toolBarMode, { timeout: 1000 }).not.toEqual('modeling')
await toolbar.expectToolbarMode.not.toBe('modeling')
// After animation completes, we should see the sketching toolbar
await expect.poll(toolBarMode).toEqual('sketching')
await toolbar.expectToolbarMode.toBe('sketching')
})
})

View File

@ -1,8 +1,9 @@
import { readFileSync } from 'fs'
const secrets: Record<string, string> = {}
const secretsPath = './e2e/playwright/playwright-secrets.env'
try {
const file = readFileSync('./e2e/playwright/playwright-secrets.env', 'utf8')
const file = readFileSync(secretsPath, 'utf8')
file
.split('\n')
.filter((line) => line && line.length > 1)
@ -13,11 +14,15 @@ try {
// prefer env vars over secrets file
secrets[key] = process.env[key] || (value as any).replaceAll('"', '')
})
} catch (err) {
} catch (error: unknown) {
void error
// probably running in CI
secrets.token = process.env.token || ''
secrets.snapshottoken = process.env.snapshottoken || ''
// add more env vars here to make them available in CI
console.warn(
`Error reading ${secretsPath}; environment variables will be used`
)
}
secrets.token = secrets.token || process.env.token || ''
secrets.snapshottoken = secrets.snapshottoken || process.env.snapshottoken || ''
// add more env vars here to make them available in CI
export { secrets }

View File

@ -12,6 +12,7 @@ import {
} from './test-utils'
import { uuidv4, roundOff } from 'lib/utils'
import { SceneFixture } from './fixtures/sceneFixture'
import { CmdBarFixture } from './fixtures/cmdBarFixture'
test.describe('Sketch tests', { tag: ['@skipWin'] }, () => {
test('multi-sketch file shows multiple Edit Sketch buttons', async ({
@ -191,7 +192,8 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
page: Page,
homePage: HomePageFixture,
openPanes: string[],
scene: SceneFixture
scene: SceneFixture,
cmdBar: CmdBarFixture
) => {
// Load the app with the code panes
await page.addInitScript(async () => {
@ -201,13 +203,22 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
|> startProfileAt([4.61, -14.01], %)
|> line(end = [12.73, -0.09])
|> tangentialArcTo([24.95, -5.38], %)
|> arcTo({
interior = [20.18, -1.7],
end = [11.82, -1.16]
}, %)
|> arc({
radius = 5.92,
angleStart = -89.36,
angleEnd = 135.81
}, %)
|> close()`
)
})
const u = await getUtils(page)
await homePage.goToModelingScene()
await scene.waitForExecutionDone()
await scene.settled(cmdBar)
await expect(
page.getByRole('button', { name: 'Start Sketch' })
@ -242,7 +253,17 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
|> startProfileAt([4.61, -14.01], %)
|> line(end = [12.73, -0.09])
|> tangentialArcTo([24.95, -5.38], %)
|> close()`)
|> arcTo({
interior = [20.18, -1.7],
end = [11.82, -1.16]
}, %)
|> arc({
radius = 5.92,
angleStart = -89.36,
angleEnd = 135.81
}, %)
|> close()
`)
} else {
// Ensure we don't see the code.
await expect(u.codeLocator).not.toBeVisible()
@ -272,7 +293,7 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
const step5 = { steps: 5 }
await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
await expect(page.getByTestId('segment-overlay')).toHaveCount(5)
// drag startProfileAt handle
await page.mouse.move(startPX[0], startPX[1])
@ -310,22 +331,93 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
}
// drag arcTo interior handle (three point arc)
const arcToHandle = await u.getBoundingBox('[data-overlay-index="2"]')
await page.mouse.move(arcToHandle.x, arcToHandle.y - 5)
await page.mouse.down()
await page.mouse.move(
arcToHandle.x - dragPX,
arcToHandle.y + dragPX,
step5
)
await page.mouse.up()
await page.waitForTimeout(100)
if (openPanes.includes('code')) {
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText()
}
// drag arcTo end handle (three point arc)
const arcToEndHandle = await u.getBoundingBox('[data-overlay-index="3"]')
await page.mouse.move(arcToEndHandle.x, arcToEndHandle.y - 5)
await page.mouse.down()
await page.mouse.move(
arcToEndHandle.x - dragPX,
arcToEndHandle.y + dragPX,
step5
)
await page.mouse.up()
await page.waitForTimeout(100)
if (openPanes.includes('code')) {
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText()
}
// drag arc radius handle
const arcRadiusHandle = await u.getBoundingBox('[data-overlay-index="4"]')
await page.mouse.move(arcRadiusHandle.x, arcRadiusHandle.y - 5)
await page.mouse.down()
await page.mouse.move(
arcRadiusHandle.x - dragPX,
arcRadiusHandle.y + dragPX,
step5
)
await page.mouse.up()
await page.waitForTimeout(100)
if (openPanes.includes('code')) {
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
}
// drag arc center handle (we'll have to hardcode the position because it doesn't have a overlay near the handle)
const arcCenterHandle = { x: 745, y: 214 }
await page.mouse.move(arcCenterHandle.x, arcCenterHandle.y - 5)
await page.mouse.down()
await page.mouse.move(
arcCenterHandle.x - dragPX,
arcCenterHandle.y + dragPX,
step5
)
await page.mouse.up()
await page.waitForTimeout(100)
if (openPanes.includes('code')) {
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
}
// Open the code pane
await u.openKclCodePanel()
// expect the code to have changed
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([6.44, -12.07], %)
|> line(end = [14.72, 1.97])
|> tangentialArcTo([24.95, -5.38], %)
|> line(end = [1.97, 2.06])
|> close()`)
|> startProfileAt([6.44, -12.07], %)
|> line(end = [14.72, 1.97])
|> tangentialArcTo([26.92, -3.32], %)
|> arcTo({
interior = [18.11, -3.73],
end = [9.77, -3.19]
}, %)
|> arc({
radius = 3.75,
angleStart = -58.29,
angleEnd = 161.17
}, %)
|> close()
`)
}
test(
'code pane open at start-handles',
{ tag: ['@skipWin'] },
async ({ page, homePage, scene }) => {
async ({ page, homePage, scene, cmdBar }) => {
// Load the app with the code panes
await page.addInitScript(async () => {
localStorage.setItem(
@ -338,14 +430,20 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
})
)
})
await doEditSegmentsByDraggingHandle(page, homePage, ['code'], scene)
await doEditSegmentsByDraggingHandle(
page,
homePage,
['code'],
scene,
cmdBar
)
}
)
test(
'code pane closed at start-handles',
{ tag: ['@skipWin'] },
async ({ page, homePage, scene }) => {
async ({ page, homePage, scene, cmdBar }) => {
// Load the app with the code panes
await page.addInitScript(async (persistModelingContext) => {
localStorage.setItem(
@ -353,7 +451,7 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
JSON.stringify({ openPanes: [] })
)
}, PERSIST_MODELING_CONTEXT)
await doEditSegmentsByDraggingHandle(page, homePage, [], scene)
await doEditSegmentsByDraggingHandle(page, homePage, [], scene, cmdBar)
}
)
})
@ -362,6 +460,8 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
page,
editor,
homePage,
scene,
cmdBar,
}) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
@ -373,6 +473,8 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
})
await homePage.goToModelingScene()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await expect(
page.getByRole('button', { name: 'Start Sketch' })
@ -1174,7 +1276,7 @@ profile001 = startProfileAt([${roundOff(scale * 69.6)}, ${roundOff(
|> line(endAbsolute = [
railWideWidth / 2,
railClampable / 2 + railBaseLength
], $seg01)
], tag = $seg01)
|> line(endAbsolute = [railTop / 2, railBaseLength])
|> line(endAbsolute = [railBaseWidth / 2, railBaseLength])
|> line(endAbsolute = [railBaseWidth / 2, 0])
@ -1355,7 +1457,7 @@ test.describe('multi-profile sketching', () => {
test(
`test it removes half-finished expressions when changing tools in sketch mode`,
{ tag: ['@skipWin'] },
async ({ context, page, scene, toolbar, editor, homePage }) => {
async ({ context, page, scene, toolbar, editor, homePage, cmdBar }) => {
// We seed the scene with a single offset plane
await context.addInitScript(() => {
localStorage.setItem(
@ -1375,7 +1477,10 @@ profile002 = startProfileAt([117.2, 56.08], sketch001)
)
})
const [continueProfile2Clk] = scene.makeMouseHelpers(954, 282)
await homePage.goToModelingScene()
await scene.settled(cmdBar)
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
@ -1386,7 +1491,13 @@ profile002 = startProfileAt([117.2, 56.08], sketch001)
const [circlePoint1] = scene.makeMouseHelpers(700, 200)
await test.step('equip circle tool and click first point', async () => {
await toolbar.circleBtn.click()
// await page.waitForTimeout(100)
await expect
.poll(async () => {
await toolbar.circleBtn.click()
return toolbar.circleBtn.getAttribute('aria-pressed')
})
.toBe('true')
await page.waitForTimeout(100)
await circlePoint1()
await editor.expectEditor.toContain(
@ -1401,6 +1512,7 @@ profile002 = startProfileAt([117.2, 56.08], sketch001)
const [circle3Point1] = scene.makeMouseHelpers(650, 200)
const [circle3Point2] = scene.makeMouseHelpers(750, 200)
// const [circle3Point3] = scene.makeMouseHelpers(700, 150)
await test.step('equip three point circle tool and click first two points', async () => {
await toolbar.selectCircleThreePoint()
@ -1411,25 +1523,40 @@ profile002 = startProfileAt([117.2, 56.08], sketch001)
await editor.expectEditor.toContain('profile003 = circleThreePoint(')
})
await test.step('equip line tool and verify three point circle code is removed', async () => {
await test.step('equip line tool and verify three-point circle code is removed', async () => {
await toolbar.lineBtn.click()
await editor.expectEditor.not.toContain(
'profile003 = circleThreePoint('
)
})
await test.step('equip three-point-arc tool and click first two points', async () => {
await page.waitForTimeout(200)
await toolbar.selectThreePointArc()
await page.waitForTimeout(200)
await circle3Point1()
await page.waitForTimeout(200)
await circle3Point2()
await editor.expectEditor.toContain('arcTo({')
})
await test.step('equip line tool and verify three-point-arc code is removed after second click', async () => {
await toolbar.lineBtn.click()
await editor.expectEditor.not.toContain('arcTo({')
})
const [cornerRectPoint1] = scene.makeMouseHelpers(600, 300)
await test.step('equip corner rectangle tool and click first point', async () => {
await toolbar.rectangleBtn.click()
await page.waitForTimeout(100)
await cornerRectPoint1()
await editor.expectEditor.toContain('profile003 = startProfileAt(')
await editor.expectEditor.toContain('profile004 = startProfileAt(')
})
await test.step('equip line tool and verify corner rectangle code is removed', async () => {
await toolbar.lineBtn.click()
await editor.expectEditor.not.toContain('profile003 = startProfileAt(')
await editor.expectEditor.not.toContain('profile004 = startProfileAt(')
})
const [centerRectPoint1] = scene.makeMouseHelpers(700, 300)
@ -1438,12 +1565,24 @@ profile002 = startProfileAt([117.2, 56.08], sketch001)
await toolbar.selectCenterRectangle()
await page.waitForTimeout(100)
await centerRectPoint1()
await editor.expectEditor.toContain('profile003 = startProfileAt(')
await editor.expectEditor.toContain('profile004 = startProfileAt(')
})
await test.step('equip line tool and verify center rectangle code is removed', async () => {
await toolbar.lineBtn.click()
await editor.expectEditor.not.toContain('profile003 = startProfileAt(')
await editor.expectEditor.not.toContain('profile004 = startProfileAt(')
})
await test.step('continue profile002 with the three point arc tool, and then switch back to the line tool to verify it only removes the last expression in the pipe', async () => {
await toolbar.selectThreePointArc()
await page.waitForTimeout(200)
await continueProfile2Clk()
await page.waitForTimeout(200)
await circle3Point1()
await editor.expectEditor.toContain('arcTo({')
await toolbar.lineBtn.click()
await editor.expectEditor.not.toContain('arcTo({')
await editor.expectEditor.toContain('profile002')
})
}
)
@ -1532,6 +1671,7 @@ profile003 = startProfileAt([206.63, -56.73], sketch001)
}) => {
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await scene.connectionEstablished()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
@ -1595,7 +1735,7 @@ profile003 = startProfileAt([206.63, -56.73], sketch001)
// timeout wait for engine animation is unavoidable
await page.waitForTimeout(600)
await editor.expectEditor.toContain(`sketch001 = startSketchOn('XZ')`)
await test.step('Create a close profile stopping mid profile to equip the tangential arc, and than back to the line tool', async () => {
await test.step('Create a close profile stopping mid profile to equip the tangential arc, then three-point arc, and then back to the line tool', async () => {
await startProfile1()
await editor.expectEditor.toContain(
`profile001 = startProfileAt([4.61, 12.21], sketch001)`
@ -1613,12 +1753,45 @@ profile003 = startProfileAt([206.63, -56.73], sketch001)
await editor.expectEditor.toContain(
`|> tangentialArcTo([16.61, 4.14], %)`
)
// Add a three-point arc segment
await toolbar.selectThreePointArc()
await page.waitForTimeout(300)
// select end of profile again
await endLineStartTanArc()
await page.waitForTimeout(300)
// Define points for the three-point arc
const [threePointInterior, threePointInteriorMove] =
scene.makeMouseHelpers(600, 200)
const [threePointEnd, threePointEndMove] = scene.makeMouseHelpers(
590,
270
)
// Create the three-point arc
await page.waitForTimeout(300)
await threePointInteriorMove()
await threePointInterior()
await page.waitForTimeout(300)
await threePointEndMove()
await threePointEnd()
await page.waitForTimeout(300)
// Verify the three-point arc was created correctly
await editor.expectEditor.toContain(`|> arcTo(`)
// Switch back to line tool to continue
await toolbar.lineBtn.click()
await page.waitForTimeout(300)
await endArcStartLine()
// Continue with the original line segment
await threePointEnd()
await page.waitForTimeout(300)
await page.mouse.click(572, 110)
await editor.expectEditor.toContain(`|> line(end = [-11.73, 5.35])`)
await editor.expectEditor.toContain(`|> line(end = [-1.22, 10.85])`)
await startProfile1()
await editor.expectEditor.toContain(
`|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
@ -1820,8 +1993,68 @@ profile003 = startProfileAt([206.63, -56.73], sketch001)
)
})
await test.step('double check that circle three point can be unequiped', async () => {
// this was tested implicitly for other tools, but not for circle three point since it's last
await test.step('create three-point arcs in a row without an unequip', async () => {
// Define points for the first three-point arc
const [arc1Point1, arc1Point1Move] = scene.makeMouseHelpers(700, 397)
const [arc1Point2, arc1Point2Move] = scene.makeMouseHelpers(724, 346)
const [arc1Point3, arc1Point3Move] = scene.makeMouseHelpers(785, 415)
// Define points for the second three-point arc
const [arc2Point1, arc2Point1Move] = scene.makeMouseHelpers(792, 225)
const [arc2Point2, arc2Point2Move] = scene.makeMouseHelpers(820, 207)
const [arc2Point3, arc2Point3Move] = scene.makeMouseHelpers(905, 229)
// Select the three-point arc tool
await toolbar.selectThreePointArc()
// Create the first three-point arc
await arc1Point1Move()
await arc1Point1()
await page.waitForTimeout(300)
await arc1Point2Move()
await arc1Point2()
await page.waitForTimeout(300)
await arc1Point3Move()
await arc1Point3()
await page.waitForTimeout(300)
// Verify the first three-point arc was created correctly
await editor.expectEditor.toContain(
`profile011 = startProfileAt([13.56, -9.97], sketch001)
|> arcTo({
interior = [15.19, -6.51],
end = [19.33, -11.19]
}, %)`,
{ shouldNormalise: true }
)
// Create the second three-point arc
await arc2Point1Move()
await arc2Point1()
await page.waitForTimeout(300)
await arc2Point2Move()
await arc2Point2()
await page.waitForTimeout(300)
await arc2Point3Move()
await arc2Point3()
await page.waitForTimeout(300)
// Verify the second three-point arc was created correctly
await editor.expectEditor.toContain(
` |> arcTo({
interior = [19.8, 1.7],
end = [21.7, 2.92]
}, %)
|> arcTo({
interior = [27.47, 1.42],
end = [27.57, 1.52]
}, %)`,
{ shouldNormalise: true }
)
})
await test.step('double check that three-point arc can be unequipped', async () => {
// this was tested implicitly for other tools, but not for three-point arc since it's last
await page.waitForTimeout(300)
await expect
.poll(async () => {
@ -2085,7 +2318,7 @@ profile003 = circle(sketch001, center = [6.92, -4.2], radius = 3.16)
test(
'can enter sketch when there is an extrude',
{ tag: ['@skipWin'] },
async ({ homePage, scene, toolbar, page }) => {
async ({ homePage, scene, toolbar, page, cmdBar }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
@ -2122,6 +2355,8 @@ extrude001 = extrude(profile003, length = 5)
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
@ -2134,9 +2369,11 @@ extrude001 = extrude(profile003, length = 5)
await page.waitForTimeout(600)
await test.step('check the sketch is still drawn properly', async () => {
await scene.expectPixelColor([255, 255, 255], { x: 596, y: 165 }, 15)
await scene.expectPixelColor([255, 255, 255], { x: 641, y: 220 }, 15)
await scene.expectPixelColor([255, 255, 255], { x: 763, y: 214 }, 15)
await Promise.all([
scene.expectPixelColor(TEST_COLORS.WHITE, { x: 596, y: 165 }, 15),
scene.expectPixelColor(TEST_COLORS.WHITE, { x: 641, y: 220 }, 15),
scene.expectPixelColor(TEST_COLORS.WHITE, { x: 763, y: 214 }, 15),
])
})
}
)
@ -2293,7 +2530,7 @@ extrude001 = extrude(thePart, length = 75)
test(
'Can enter sketch on sketch of wall and cap for segment, solid2d, extrude-wall, extrude-cap selections',
{ tag: ['@skipWin'] },
async ({ homePage, scene, toolbar, editor, page }) => {
async ({ homePage, scene, toolbar, editor, page, cmdBar }) => {
// TODO this test should include a test for selecting revolve walls and caps
await page.addInitScript(async () => {
@ -2378,6 +2615,8 @@ extrude003 = extrude(profile011, length = 2.5)
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
@ -2387,11 +2626,6 @@ extrude003 = extrude(profile011, length = 2.5)
{ x: 834, y: -680, z: 534 },
{ x: -54, y: -476, z: 148 }
)
const camPositionForSelectingSketchOnCapProfiles = () =>
scene.moveCameraTo(
{ x: 404, y: 690, z: 38 },
{ x: 16, y: -140, z: -10 }
)
const wallSelectionOptions = [
{
title: 'select wall segment',
@ -2414,103 +2648,25 @@ extrude003 = extrude(profile011, length = 2.5)
selectClick: scene.makeMouseHelpers(836, 103)[0],
},
] as const
const capSelectionOptions = [
{
title: 'select cap segment',
selectClick: scene.makeMouseHelpers(688, 91)[0],
},
{
title: 'select cap solid 2d',
selectClick: scene.makeMouseHelpers(733, 204)[0],
},
// TODO keeps failing
// {
// title: 'select cap circle',
// selectClick: scene.makeMouseHelpers(679, 290)[0],
// },
{
title: 'select cap extrude wall',
selectClick: scene.makeMouseHelpers(649, 402)[0],
},
{
title: 'select cap extrude cap',
selectClick: scene.makeMouseHelpers(693, 408)[0],
},
] as const
const verifyWallProfilesAreDrawn = async () =>
test.step('verify wall profiles are drawn', async () => {
// open polygon
await scene.expectPixelColor(
TEST_COLORS.WHITE,
{ x: 599, y: 168 },
15
)
// closed polygon
await scene.expectPixelColor(
TEST_COLORS.WHITE,
{ x: 656, y: 171 },
15
)
// revolved profile
await scene.expectPixelColor(
TEST_COLORS.WHITE,
{ x: 655, y: 264 },
15
)
// extruded profile
await scene.expectPixelColor(
TEST_COLORS.WHITE,
{ x: 808, y: 396 },
15
)
// circle
await scene.expectPixelColor(
[
TEST_COLORS.WHITE,
TEST_COLORS.BLUE, // When entering via the circle, it's selected and therefore blue
],
{ x: 742, y: 386 },
15
)
})
const verifyCapProfilesAreDrawn = async () =>
test.step('verify cap profiles are drawn', async () => {
// open polygon
await scene.expectPixelColor(
TEST_COLORS.WHITE,
// TEST_COLORS.BLUE, // When entering via the circle, it's selected and therefore blue
{ x: 620, y: 58 },
15
)
// revolved profile
await scene.expectPixelColor(
TEST_COLORS.WHITE,
{ x: 641, y: 110 },
15
)
// closed polygon
await scene.expectPixelColor(
TEST_COLORS.WHITE,
{ x: 632, y: 200 },
15
)
// extruded profile
await scene.expectPixelColor(
TEST_COLORS.WHITE,
{ x: 628, y: 410 },
15
)
// circle
await scene.expectPixelColor(
[
TEST_COLORS.WHITE,
TEST_COLORS.BLUE, // When entering via the circle, it's selected and therefore blue
],
{ x: 681, y: 303 },
15
)
await Promise.all([
// open polygon
scene.expectPixelColor(TEST_COLORS.WHITE, { x: 599, y: 168 }, 15),
// closed polygon
scene.expectPixelColor(TEST_COLORS.WHITE, { x: 656, y: 171 }, 15),
// revolved profile
scene.expectPixelColor(TEST_COLORS.WHITE, { x: 655, y: 264 }, 15),
// extruded profile
scene.expectPixelColor(TEST_COLORS.WHITE, { x: 808, y: 396 }, 15),
// circle (When entering via the circle, it's selected and therefore blue)
scene.expectPixelColor(
[TEST_COLORS.WHITE, TEST_COLORS.BLUE],
{ x: 742, y: 386 },
15
),
])
})
await test.step('select wall profiles', async () => {

View File

@ -7,12 +7,7 @@ import { spawn } from 'child_process'
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
import JSZip from 'jszip'
import path from 'path'
import {
IS_PLAYWRIGHT_KEY,
TEST_SETTINGS,
TEST_SETTINGS_KEY,
} from './storageStates'
import * as TOML from '@iarna/toml'
import { TEST_SETTINGS, TEST_SETTINGS_KEY } from './storageStates'
import { SceneFixture } from './fixtures/sceneFixture'
import { CmdBarFixture } from './fixtures/cmdBarFixture'
@ -410,9 +405,9 @@ test.describe(
test(
'Draft segments should look right',
{ tag: '@snapshot' },
async ({ page, context, scene, cmdBar }) => {
async ({ page, scene, toolbar }) => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
// test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
@ -421,6 +416,23 @@ test(
await scene.connectionEstablished()
const startXPx = 600
const [endOfTangentClk, endOfTangentMv] = scene.makeMouseHelpers(
startXPx + PUR * 30,
500 - PUR * 20,
{ steps: 10 }
)
const [threePointArcMidPointClk, threePointArcMidPointMv] =
scene.makeMouseHelpers(800, 250, { steps: 10 })
const [threePointArcEndPointClk, threePointArcEndPointMv] =
scene.makeMouseHelpers(750, 285, { steps: 10 })
const [arcCenterClk, arcCenterMv] = scene.makeMouseHelpers(750, 210, {
steps: 10,
})
const [arcEndClk, arcEndMv] = scene.makeMouseHelpers(750, 150, {
steps: 10,
})
// click on "Start Sketch" button
await u.doAndWaitForImageDiff(
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
@ -435,7 +447,6 @@ test(
await page.waitForTimeout(700) // TODO detect animation ending, or disable animation
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
code += `profile001 = startProfileAt([7.19, -9.7], sketch001)`
await expect(page.locator('.cm-content')).toHaveText(code)
@ -471,12 +482,52 @@ test(
await page.mouse.move(813, 392, { steps: 10 })
await page.waitForTimeout(500)
await page.mouse.move(startXPx + PUR * 30, 500 - PUR * 20, { steps: 10 })
await endOfTangentMv()
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
mask: [page.getByTestId('model-state-indicator')],
})
await endOfTangentClk()
await toolbar.selectThreePointArc()
await page.waitForTimeout(500)
await endOfTangentClk()
await threePointArcMidPointMv()
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
mask: [page.getByTestId('model-state-indicator')],
})
await threePointArcMidPointClk()
await page.waitForTimeout(100)
await threePointArcEndPointMv()
await page.waitForTimeout(500)
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
mask: [page.getByTestId('model-state-indicator')],
})
await threePointArcEndPointClk()
await page.waitForTimeout(100)
await toolbar.selectArc()
await page.waitForTimeout(100)
// continue the profile
await threePointArcEndPointClk()
await page.waitForTimeout(100)
await arcCenterMv()
await page.waitForTimeout(500)
await arcCenterClk()
await arcEndMv()
await page.waitForTimeout(500)
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
mask: [page.getByTestId('model-state-indicator')],
})
await arcEndClk()
}
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -0,0 +1,33 @@
{
"original_source_code": "sketch001 = startSketchOn('XZ')\nprofile001 = startProfileAt([57.81, 250.51], sketch001)\n |> line(end = [121.13, 56.63], tag = $seg02)\n |> line(end = [83.37, -34.61], tag = $seg01)\n |> line(end = [19.66, -116.4])\n |> line(end = [-221.8, -41.69])\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude001 = extrude(profile001, length = 200)\nsketch002 = startSketchOn('XZ')\n |> startProfileAt([-73.64, -42.89], %)\n |> xLine(length = 173.71)\n |> line(end = [-22.12, -94.4])\n |> xLine(length = -156.98)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude002 = extrude(sketch002, length = 50)\nsketch003 = startSketchOn('XY')\n |> startProfileAt([52.92, 157.81], %)\n |> angledLine([0, 176.4], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 53.4\n ], %, $rectangleSegmentB001)\n |> angledLine([\n segAng(rectangleSegmentA001),\n -segLen(rectangleSegmentA001)\n ], %, $rectangleSegmentC001)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude003 = extrude(sketch003, length = 20)\n",
"prompt": "make this neon green please, use #39FF14",
"source_ranges": [
{
"prompt": "The users main selection is the end cap of a general-sweep (that is an extrusion, revolve, sweep or loft).\nThe source range most likely refers to \"startProfileAt\" simply because this is the start of the profile that was swept.\nIf you need to operate on this cap, for example for sketching on the face, you can use the special string END i.e. `startSketchOn(someSweepVariable, END)`\nWhen they made this selection they main have intended this surface directly or meant something more general like the sweep body.\nSee later source ranges for more context.",
"range": {
"start": {
"line": 11,
"column": 5
},
"end": {
"line": 11,
"column": 40
}
}
},
{
"prompt": "This is the sweep's source range from the user's main selection of the end cap.",
"range": {
"start": {
"line": 17,
"column": 13
},
"end": {
"line": 17,
"column": 44
}
}
}
],
"kcl_version": "0.2.50"
}

View File

@ -1,4 +1,3 @@
import { MouseControlType } from '@rust/kcl-lib/bindings/MouseControlType'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
import { Themes } from 'lib/theme'

View File

@ -2,15 +2,12 @@ import {
expect,
BrowserContext,
TestInfo,
_electron as electron,
ElectronApplication,
Locator,
Page,
} from '@playwright/test'
import { test } from './zoo-test'
import { EngineCommand } from 'lang/std/artifactGraph'
import fsp from 'fs/promises'
import fsSync from 'fs'
import path from 'path'
import pixelMatch from 'pixelmatch'
import { PNG } from 'pngjs'
@ -24,14 +21,11 @@ import {
IS_PLAYWRIGHT_KEY,
} from './storageStates'
import * as TOML from '@iarna/toml'
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
import { SETTINGS_FILE_NAME } from 'lib/constants'
import { isErrorWhitelisted } from './lib/console-error-whitelist'
import { isArray } from 'lib/utils'
import { reportRejection } from 'lib/trap'
import { DeepPartial } from 'lib/types'
import { Configuration } from 'lang/wasm'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
const toNormalizedCode = (text: string) => {
return text.replace(/\s+/g, '')
@ -928,10 +922,6 @@ export async function setup(
// await page.reload()
}
let electronApp: ElectronApplication | undefined = undefined
let context: BrowserContext | undefined = undefined
let page: Page | undefined = undefined
function failOnConsoleErrors(page: Page, testInfo?: TestInfo) {
// enabled for chrome for now
if (page.context().browser()?.browserType().name() === 'chromium') {

View File

@ -4,7 +4,6 @@ import { bracket } from 'lib/exampleKcl'
import * as fsp from 'fs/promises'
import { join } from 'path'
import { FILE_EXT } from 'lib/constants'
import { UnitLength_type } from '@kittycad/lib/dist/types/src/models'
test.describe('Testing in-app sample loading', () => {
/**
@ -49,8 +48,6 @@ test.describe('Testing in-app sample loading', () => {
})
const warningText = page.getByText('Overwrite current file and units?')
const confirmButton = page.getByRole('button', { name: 'Submit command' })
const unitsToast = (unit: UnitLength_type) =>
page.getByText(`Set default unit to "${unit}" for this project`)
await test.step(`Precondition: check the initial code`, async () => {
await u.openKclCodePanel()
@ -125,8 +122,6 @@ test.describe('Testing in-app sample loading', () => {
page.getByRole('listitem').filter({
has: page.getByRole('button', { name }),
})
const unitsToast = (unit: UnitLength_type) =>
page.getByText(`Set default unit to "${unit}" for this project`)
await test.step(`Test setup`, async () => {
await page.setBodyDimensions({ width: 1200, height: 500 })

View File

@ -159,7 +159,6 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
const unconstrainedLocator = page.locator(
`[data-constraint-type="${constraintType}"][data-is-constrained="false"]`
)
await expect(unconstrainedLocator).toBeVisible()
await unconstrainedLocator.hover()
await expect(
await page.getByTestId('constraint-symbol-popover').count()
@ -274,8 +273,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
let ang = 0
const line = await u.getBoundingBox(`[data-overlay-index="${0}"]`)
ang = await u.getAngle(`[data-overlay-index="${0}"]`)
const line = await u.getBoundingBox('[data-overlay-index="0"]')
ang = await u.getAngle('[data-overlay-index="0"]')
console.log('line1', line, ang)
await clickConstrained({
hoverPos: { x: line.x, y: line.y },
@ -297,8 +296,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
locator: '[data-overlay-index="0"]',
})
const angledLine = await u.getBoundingBox(`[data-overlay-index="1"]`)
ang = await u.getAngle(`[data-overlay-index="1"]`)
const angledLine = await u.getBoundingBox('[data-overlay-index="1"]')
ang = await u.getAngle('[data-overlay-index="1"]')
console.log('angledLine1')
await clickConstrained({
hoverPos: { x: angledLine.x, y: angledLine.y },
@ -327,8 +326,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.mouse.move(700, 250)
await page.waitForTimeout(100)
let lineTo = await u.getBoundingBox(`[data-overlay-index="2"]`)
ang = await u.getAngle(`[data-overlay-index="2"]`)
let lineTo = await u.getBoundingBox('[data-overlay-index="2"]')
ang = await u.getAngle('[data-overlay-index="2"]')
console.log('lineTo1')
await clickConstrained({
hoverPos: { x: lineTo.x, y: lineTo.y },
@ -353,8 +352,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
locator: '[data-overlay-toolbar-index="2"]',
})
const xLineTo = await u.getBoundingBox(`[data-overlay-index="3"]`)
ang = await u.getAngle(`[data-overlay-index="3"]`)
const xLineTo = await u.getBoundingBox('[data-overlay-index="3"]')
ang = await u.getAngle('[data-overlay-index="3"]')
console.log('xlineTo1')
await clickConstrained({
hoverPos: { x: xLineTo.x, y: xLineTo.y },
@ -419,8 +418,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
let ang = 0
const yLineTo = await u.getBoundingBox(`[data-overlay-index="4"]`)
ang = await u.getAngle(`[data-overlay-index="4"]`)
const yLineTo = await u.getBoundingBox('[data-overlay-index="4"]')
ang = await u.getAngle('[data-overlay-index="4"]')
console.log('ylineTo1')
await clickUnconstrained({
hoverPos: { x: yLineTo.x, y: yLineTo.y - 200 },
@ -432,8 +431,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
locator: '[data-overlay-toolbar-index="4"]',
})
const xLine = await u.getBoundingBox(`[data-overlay-index="5"]`)
ang = await u.getAngle(`[data-overlay-index="5"]`)
const xLine = await u.getBoundingBox('[data-overlay-index="5"]')
ang = await u.getAngle('[data-overlay-index="5"]')
console.log('xline')
await clickUnconstrained({
hoverPos: { x: xLine.x, y: xLine.y },
@ -501,8 +500,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
let ang = 0
const yLine = await u.getBoundingBox(`[data-overlay-index="6"]`)
ang = await u.getAngle(`[data-overlay-index="6"]`)
const yLine = await u.getBoundingBox('[data-overlay-index="6"]')
ang = await u.getAngle('[data-overlay-index="6"]')
console.log('yline1')
await clickConstrained({
hoverPos: { x: yLine.x, y: yLine.y },
@ -515,9 +514,9 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
const angledLineOfXLength = await u.getBoundingBox(
`[data-overlay-index="7"]`
'[data-overlay-index="7"]'
)
ang = await u.getAngle(`[data-overlay-index="7"]`)
ang = await u.getAngle('[data-overlay-index="7"]')
console.log('angledLineOfXLength1')
await clickConstrained({
hoverPos: { x: angledLineOfXLength.x, y: angledLineOfXLength.y },
@ -547,9 +546,9 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
const angledLineOfYLength = await u.getBoundingBox(
`[data-overlay-index="8"]`
'[data-overlay-index="8"]'
)
ang = await u.getAngle(`[data-overlay-index="8"]`)
ang = await u.getAngle('[data-overlay-index="8"]')
console.log('angledLineOfYLength1')
await clickUnconstrained({
hoverPos: { x: angledLineOfYLength.x, y: angledLineOfYLength.y },
@ -632,8 +631,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
let ang = 0
const angledLineToX = await u.getBoundingBox(`[data-overlay-index="9"]`)
ang = await u.getAngle(`[data-overlay-index="9"]`)
const angledLineToX = await u.getBoundingBox('[data-overlay-index="9"]')
ang = await u.getAngle('[data-overlay-index="9"]')
console.log('angledLineToX')
await clickConstrained({
hoverPos: { x: angledLineToX.x, y: angledLineToX.y },
@ -659,9 +658,9 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
const angledLineToY = await u.getBoundingBox(
`[data-overlay-index="10"]`
'[data-overlay-index="10"]'
)
ang = await u.getAngle(`[data-overlay-index="10"]`)
ang = await u.getAngle('[data-overlay-index="10"]')
console.log('angledLineToY')
await clickUnconstrained({
hoverPos: { x: angledLineToY.x, y: angledLineToY.y },
@ -689,9 +688,9 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
const angledLineThatIntersects = await u.getBoundingBox(
`[data-overlay-index="11"]`
'[data-overlay-index="11"]'
)
ang = await u.getAngle(`[data-overlay-index="11"]`)
ang = await u.getAngle('[data-overlay-index="11"]')
console.log('angledLineThatIntersects')
await clickUnconstrained({
hoverPos: {
@ -821,6 +820,138 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
locator: '[data-overlay-toolbar-index="12"]',
})
})
test('for segment [arcTo]', async ({
page,
editor,
homePage,
scene,
cmdBar,
}) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn('XZ')
profile001 = startProfileAt([56.37, 120.33], sketch001)
|> line(end = [162.86, 106.48])
|> arcTo({
interior = [360.16, 231.76],
end = [391.48, 131.54]
}, %)
|> yLine(-131.54, %)
|> arc({
radius = 126.46,
angleStart = 33.53,
angleEnd = -141.07
}, %)
`
)
localStorage.setItem('disableAxis', 'true')
})
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
await scene.connectionEstablished()
await scene.settled(cmdBar)
// wait for execution done
await page.getByText('line(end = [162.86, 106.48])').click()
await page.waitForTimeout(100)
await page.getByRole('button', { name: 'Edit Sketch' }).click()
await page.waitForTimeout(500)
await expect(page.getByTestId('segment-overlay')).toHaveCount(5)
const clickUnconstrained = _clickUnconstrained(page, editor)
const clickConstrained = _clickConstrained(page, editor)
const arcTo = await u.getBoundingBox('[data-overlay-index="1"]')
let ang = await u.getAngle('[data-overlay-index="1"]')
console.log('arcTo interior x')
await clickUnconstrained({
hoverPos: { x: arcTo.x, y: arcTo.y },
constraintType: 'xAbsolute',
expectBeforeUnconstrained: `arcTo({
interior = [360.16, 231.76],
end = [391.48, 131.54]
}, %)`,
expectAfterUnconstrained: `arcTo({
interior = [360.16, 231.76],
end = [391.48, 131.54]
}, %)`,
expectFinal: `arcTo({
interior = [xAbs001, 231.76],
end = [391.48, 131.54]
}, %)`,
ang: ang,
steps: 6,
locator: '[data-overlay-toolbar-index="1"]',
})
console.log('arcTo interior y')
await clickUnconstrained({
hoverPos: { x: arcTo.x, y: arcTo.y },
constraintType: 'yAbsolute',
expectBeforeUnconstrained: `arcTo({
interior = [xAbs001, 231.76],
end = [391.48, 131.54]
}, %)`,
expectAfterUnconstrained: `arcTo({
interior = [xAbs001, yAbs001],
end = [391.48, 131.54]
}, %)`,
expectFinal: `arcTo({
interior = [xAbs001, 231.76],
end = [391.48, 131.54]
}, %)`,
ang: ang,
steps: 10,
locator: '[data-overlay-toolbar-index="1"]',
})
console.log('arcTo end x')
await clickConstrained({
hoverPos: { x: arcTo.x, y: arcTo.y },
constraintType: 'xAbsolute',
expectBeforeUnconstrained: `arcTo({
interior = [xAbs001, 231.76],
end = [391.48, 131.54]
}, %)`,
expectAfterUnconstrained: `arcTo({
interior = [xAbs001, 231.76],
end = [391.48, 131.54]
}, %)`,
expectFinal: `arcTo({
interior = [xAbs001, 231.76],
end = [xAbs002, 131.54]
}, %)`,
ang: ang + 180,
steps: 6,
locator: '[data-overlay-toolbar-index="1"]',
})
console.log('arcTo end y')
await clickUnconstrained({
hoverPos: { x: arcTo.x, y: arcTo.y },
constraintType: 'yAbsolute',
expectBeforeUnconstrained: `arcTo({
interior = [xAbs001, 231.76],
end = [xAbs002, 131.54]
}, %)`,
expectAfterUnconstrained: `arcTo({
interior = [xAbs001, 231.76],
end = [xAbs002, yAbs002]
}, %)`,
expectFinal: `arcTo({
interior = [xAbs001, 231.76],
end = [xAbs002, 131.54]
}, %)`,
ang: ang + 180,
steps: 10,
locator: '[data-overlay-toolbar-index="1"]',
})
})
test('for segment [circle]', async ({ page, editor, homePage }) => {
await page.addInitScript(async () => {
localStorage.setItem(
@ -928,36 +1059,55 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
shouldNormalise: true,
})
await page.locator(`[data-stdlib-fn-name="${stdLibFnName}"]`).click()
await page
.locator(`[data-stdlib-fn-name="${stdLibFnName}"]`)
.first()
.click()
await page.getByText('Delete Segment').click()
await editor.expectEditor.not.toContain(codeToBeDeleted, {
shouldNormalise: true,
})
}
test('all segment types', async ({ page, editor, homePage }) => {
test('all segment types', async ({
page,
editor,
homePage,
scene,
cmdBar,
}) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`part001 = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
|> line(endAbsolute = [33, 11.5 + 0])
|> xLine(endAbsolute = 9 - 5)
|> yLine(endAbsolute = -10.77, tag = $a)
|> xLine(length = 26.04)
|> yLine(length = 21.14 + 0)
|> angledLineOfXLength({ angle = 181 + 0, length = 23.14 }, %)
|> angledLineOfYLength({ angle = -91, length = 19 + 0 }, %)
|> angledLineToX({ angle = 3 + 0, to = 26 }, %)
|> angledLineToY({ angle = 89, to = 9.14 + 0 }, %)
|> angledLineThatIntersects({
angle = 4.14,
intersectTag = a,
offset = 9
}, %)
|> tangentialArcTo([3.14 + 13, 1.14], %)
|>startProfileAt([0, 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
|> line(endAbsolute = [33, 11.5 + 0])
|> xLine(endAbsolute = 9 - 5)
|> yLine(endAbsolute = -10.77, tag = $a)
|> xLine(length = 26.04)
|> yLine(length = 21.14 + 0)
|> angledLineOfXLength({ angle = 181 + 0, length = 23.14 }, %)
|> angledLineOfYLength({ angle = -91, length = 19 + 0 }, %)
|> angledLineToX({ angle = 3 + 0, to = 26 }, %)
|> angledLineToY({ angle = 89, to = 9.14 + 0 }, %)
|> angledLineThatIntersects({
angle = 4.14,
intersectTag = a,
offset = 9
}, %)
|> tangentialArcTo([3.14 + 13, 1.14], %)
|> arcTo({
interior = [16.25, 5.12],
end = [21.61, 4.15]
}, %)
|> arc({
radius = 9.03,
angleStart = 40.27,
angleEnd = -38.05
}, %)
`
)
localStorage.setItem('disableAxis', 'true')
@ -966,27 +1116,55 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await u.waitForPageLoad()
// wait for execution done
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
await page.getByText('xLine(endAbsolute = 9 - 5)').click()
await page.waitForTimeout(100)
await page.getByRole('button', { name: 'Edit Sketch' }).click()
await page.waitForTimeout(500)
await expect(page.getByTestId('segment-overlay')).toHaveCount(13)
await expect(page.getByTestId('segment-overlay')).toHaveCount(16)
const deleteSegmentSequence = _deleteSegmentSequence(page, editor)
let segmentToDelete
const getOverlayByIndex = (index: number) =>
u.getBoundingBox(`[data-overlay-index="${index}"]`)
segmentToDelete = await getOverlayByIndex(14)
let ang = await u.getAngle('[data-overlay-index="14"]')
await editor.scrollToText('angleEnd')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: `arc({
radius = 9.03,
angleStart = 40.27,
angleEnd = -38.05
}, %)`,
stdLibFnName: 'arc',
ang: ang + 180,
steps: 6,
locator: '[data-overlay-toolbar-index="14"]',
})
segmentToDelete = await getOverlayByIndex(13)
ang = await u.getAngle('[data-overlay-index="13"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: `arcTo({
interior = [16.25, 5.12],
end = [21.61, 4.15]
}, %)`,
stdLibFnName: 'arcTo',
ang: ang,
steps: 6,
locator: '[data-overlay-toolbar-index="13"]',
})
segmentToDelete = await getOverlayByIndex(12)
let ang = await u.getAngle(`[data-overlay-index="${12}"]`)
ang = await u.getAngle('[data-overlay-index="12"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'tangentialArcTo([3.14 + 13, 1.14], %)',
@ -997,7 +1175,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(11)
ang = await u.getAngle(`[data-overlay-index="${11}"]`)
ang = await u.getAngle('[data-overlay-index="11"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: `angledLineThatIntersects({
@ -1012,7 +1190,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(10)
ang = await u.getAngle(`[data-overlay-index="${10}"]`)
ang = await u.getAngle('[data-overlay-index="10"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'angledLineToY({ angle = 89, to = 9.14 + 0 }, %)',
@ -1022,7 +1200,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(9)
ang = await u.getAngle(`[data-overlay-index="${9}"]`)
ang = await u.getAngle('[data-overlay-index="9"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'angledLineToX({ angle = 3 + 0, to = 26 }, %)',
@ -1032,7 +1210,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(8)
ang = await u.getAngle(`[data-overlay-index="${8}"]`)
ang = await u.getAngle('[data-overlay-index="8"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted:
@ -1043,7 +1221,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(7)
ang = await u.getAngle(`[data-overlay-index="${7}"]`)
ang = await u.getAngle('[data-overlay-index="7"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted:
@ -1054,7 +1232,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(6)
ang = await u.getAngle(`[data-overlay-index="${6}"]`)
ang = await u.getAngle('[data-overlay-index="6"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'yLine(length = 21.14 + 0)',
@ -1064,7 +1242,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(5)
ang = await u.getAngle(`[data-overlay-index="${5}"]`)
ang = await u.getAngle('[data-overlay-index="5"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'xLine(length = 26.04)',
@ -1074,7 +1252,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(4)
ang = await u.getAngle(`[data-overlay-index="${4}"]`)
ang = await u.getAngle('[data-overlay-index="4"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'yLine(endAbsolute = -10.77, tag = $a)',
@ -1084,7 +1262,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(3)
ang = await u.getAngle(`[data-overlay-index="${3}"]`)
ang = await u.getAngle('[data-overlay-index="3"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'xLine(endAbsolute = 9 - 5)',
@ -1094,7 +1272,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(2)
ang = await u.getAngle(`[data-overlay-index="${2}"]`)
ang = await u.getAngle('[data-overlay-index="2"]')
await expect(page.getByText('Added variable')).not.toBeVisible()
const hoverPos = { x: segmentToDelete.x, y: segmentToDelete.y }
@ -1127,7 +1305,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(1)
ang = await u.getAngle(`[data-overlay-index="${1}"]`)
ang = await u.getAngle('[data-overlay-index="1"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'angledLine({ angle = 3 + 0, length = 32 + 0 }, %)',
@ -1137,7 +1315,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
})
segmentToDelete = await getOverlayByIndex(0)
ang = await u.getAngle(`[data-overlay-index="${0}"]`)
ang = await u.getAngle('[data-overlay-index="0"]')
await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'line(end = [0.5, -14 + 0])',
@ -1208,7 +1386,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
page.getByRole('button', { name: 'Edit Sketch' })
).toBeVisible()
return true
} catch (_) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (_e) {
return false
}
})
@ -1366,7 +1545,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await expect(page.getByText('Added variable')).not.toBeVisible()
const hoverPos = await u.getBoundingBox(`[data-overlay-index="0"]`)
let ang = await u.getAngle(`[data-overlay-index="${0}"]`)
let ang = await u.getAngle('[data-overlay-index="0"]')
ang += 180
await page.mouse.move(0, 0)

View File

@ -364,7 +364,6 @@ profile003 = startProfileAt([40.16, -120.48], sketch006)
await camPosition1()
const revolve = { x: 635, y: 253 }
const parentExtrude = { x: 915, y: 133 }
const solid2d = { x: 770, y: 167 }
const individualProfile = { x: 694, y: 432 }

View File

@ -7,7 +7,7 @@ import {
createProject,
tomlToSettings,
} from './test-utils'
import { SaveSettingsPayload, SettingsLevel } from 'lib/settings/settingsTypes'
import { SettingsLevel } from 'lib/settings/settingsTypes'
import { SETTINGS_FILE_NAME, PROJECT_SETTINGS_FILE_NAME } from 'lib/constants'
import {
TEST_SETTINGS_KEY,
@ -15,7 +15,6 @@ import {
TEST_SETTINGS,
TEST_SETTINGS_DEFAULT_THEME,
} from './storageStates'
import * as TOML from '@iarna/toml'
import { DeepPartial } from 'lib/types'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
@ -1006,11 +1005,6 @@ fn cube`
page.getByText(
`Set highlight edges to "${String(value)}" as a user default`
)
const initialPath = testInfo.snapshotPath('toggle-settings-initial.png')
const initialScreenshot = await scene.streamWrapper.screenshot({
path: initialPath,
mask: [page.getByTestId('model-state-indicator')],
})
await test.step(`Toggle highlightEdges off`, async () => {
await cmdBar.openCmdBar()

View File

@ -1,6 +1,6 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { test as playwrightTestFn, ElectronApplication } from '@playwright/test'
import { test as playwrightTestFn } from '@playwright/test'
import {
fixturesBasedOnProcessEnvPlatform,
@ -8,8 +8,6 @@ import {
ElectronZoo,
} from './fixtures/fixtureSetup'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
import { DeepPartial } from 'lib/types'
export { expect } from '@playwright/test'
declare module '@playwright/test' {

View File

@ -12,17 +12,17 @@
"main": ".vite/build/main.js",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.17.0",
"@codemirror/autocomplete": "^6.18.6",
"@codemirror/commands": "^6.8.0",
"@codemirror/language": "^6.10.8",
"@codemirror/language": "^6.11.0",
"@codemirror/lint": "^6.8.4",
"@codemirror/search": "^6.5.10",
"@codemirror/state": "^6.4.1",
"@codemirror/theme-one-dark": "^6.1.2",
"@csstools/postcss-oklab-function": "^4.0.7",
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-brands-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.4.2",
"@fortawesome/fontawesome-svg-core": "^6.7.2",
"@fortawesome/free-brands-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.7.19",
"@headlessui/tailwindcss": "^0.2.0",
@ -35,35 +35,35 @@
"@tweenjs/tween.js": "^23.1.1",
"@xstate/inspect": "^0.8.0",
"@xstate/react": "^4.1.1",
"bonjour-service": "^1.2.1",
"bonjour-service": "^1.3.0",
"chokidar": "^4.0.1",
"codemirror": "^6.0.1",
"decamelize": "^6.0.0",
"diff": "^7.0.0",
"electron-updater": "^6.6.0",
"fuse.js": "^7.0.0",
"fuse.js": "^7.1.0",
"html2canvas-pro": "^1.5.8",
"isomorphic-fetch": "^3.0.0",
"json-rpc-2.0": "^1.6.0",
"jszip": "^3.10.1",
"minimist": "^1.2.8",
"openid-client": "^5.6.5",
"re-resizable": "^6.9.11",
"re-resizable": "^6.11.2",
"react": "^18.3.1",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
"react-hot-toast": "^2.5.2",
"react-hotkeys-hook": "^4.6.1",
"react-json-view": "^1.21.3",
"react-modal": "^3.16.3",
"react-modal-promise": "^1.0.2",
"react-router-dom": "^6.28.0",
"sketch-helpers": "^0.0.4",
"three": "^0.172.0",
"three": "^0.174.0",
"ua-parser-js": "^1.0.37",
"uuid": "^11.0.2",
"uuid": "^11.1.0",
"vscode-jsonrpc": "^8.2.1",
"vscode-languageserver-protocol": "^3.17.5",
"vscode-uri": "^3.0.8",
"vscode-uri": "^3.1.0",
"web-vitals": "^3.5.2",
"xstate": "^5.19.2",
"yargs": "^17.7.2"
@ -71,7 +71,7 @@
"scripts": {
"install:rust": "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none && source \"$HOME/.cargo/env\" && (cd rust && (rustup show active-toolchain || rustup toolchain install))",
"install:rust:windows": "winget install Microsoft.VisualStudio.2022.Community --silent --override \"--wait --quiet --add ProductLang En-us --add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended\" && winget install Rustlang.Rustup",
"install:wasm-pack:sh": ". $HOME/.cargo/env && curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -y",
"install:wasm-pack:sh": ". $HOME/.cargo/env && curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f",
"install:wasm-pack:cargo": "cargo install wasm-pack",
"install:tools:windows": "winget install jqlang.jq MikeFarah.yq GitHub.cli",
"start": "vite --port=3000 --host=0.0.0.0",
@ -93,11 +93,9 @@
"fetch:wasm:windows": "./scripts/get-latest-wasm-bundle.ps1",
"fetch:samples": "rm -rf public/kcl-samples* && curl -L -o public/kcl-samples.zip https://github.com/KittyCAD/kcl-samples/archive/refs/heads/achalmers/kw-args-xylineto.zip && unzip -o public/kcl-samples.zip -d public && mv public/kcl-samples-* public/kcl-samples",
"build:wasm-dev": "yarn wasm-prep && (cd rust && wasm-pack build kcl-wasm-lib --dev --target web --out-dir pkg && cargo test -p kcl-lib export_bindings) && yarn isomorphic-copy-wasm && yarn fmt",
"build:wasm:nocopy": "yarn wasm-prep && cd rust && RUSTFLAGS='--cfg getrandom_backend=\"wasm_js\"' wasm-pack build kcl-wasm-lib --release --target web --out-dir pkg && cargo test -p kcl-lib export_bindings",
"build:wasm": "yarn build:wasm:nocopy && cp rust/kcl-wasm-lib/pkg/kcl_wasm_lib_bg.wasm public && yarn fmt",
"build:wasm:windows": "yarn install:wasm-pack:cargo && yarn build:wasm:nocopy && ./scripts/copy-wasm.ps1 && yarn fmt",
"build:wasm": "./scripts/build-wasm.sh",
"build:wasm:windows": "./scripts/build-wasm.ps1",
"remove-importmeta": "sed -i 's/import.meta.url/window.location.origin/g' \"./rust/kcl-wasm-lib/pkg/kcl_wasm_lib.js\"; sed -i '' 's/import.meta.url/window.location.origin/g' \"./rust/kcl-wasm-lib/pkg/kcl_wasm_lib.js\" || echo \"sed for both mac and linux\"",
"wasm-prep": "rimraf rust/kcl-wasm-lib/pkg && mkdirp rust/kcl-wasm-lib/pkg && rimraf rust/kcl-lib/bindings",
"lint-fix": "eslint --fix --ext .ts --ext .tsx src e2e packages/codemirror-lsp-client/src rust/kcl-language-server/client/src",
"lint": "eslint --max-warnings 0 --ext .ts --ext .tsx src e2e packages/codemirror-lsp-client/src rust/kcl-language-server/client/src",
"files:set-version": "echo \"$(jq --arg v \"$VERSION\" '.version=$v' package.json --indent 2)\" > package.json",
@ -153,16 +151,16 @@
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-env": "^7.25.4",
"@electron-forge/cli": "^7.6.1",
"@electron-forge/plugin-fuses": "^7.6.1",
"@electron-forge/plugin-vite": "^7.6.1",
"@babel/preset-env": "^7.26.9",
"@electron-forge/cli": "^7.7.0",
"@electron-forge/plugin-fuses": "^7.7.0",
"@electron-forge/plugin-vite": "^7.7.0",
"@electron/fuses": "^1.8.0",
"@electron/notarize": "^2.5.0",
"@iarna/toml": "^2.2.5",
"@lezer/generator": "^1.7.2",
"@nabla/vite-plugin-eslint": "^2.0.5",
"@playwright/test": "^1.49.0",
"@playwright/test": "^1.51.0",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^15.0.2",
"@types/diff": "^7.0.1",
@ -176,7 +174,7 @@
"@types/react": "^18.3.4",
"@types/react-dom": "^18.3.1",
"@types/react-modal": "^3.16.3",
"@types/three": "^0.172.0",
"@types/three": "^0.174.0",
"@types/ua-parser-js": "^0.7.39",
"@types/uuid": "^9.0.8",
"@types/wicg-file-system-access": "^2023.10.5",
@ -189,11 +187,11 @@
"electron-builder": "^26.0.6",
"eslint": "^8.0.1",
"eslint-plugin-css-modules": "^2.12.0",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-jest": "^28.10.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-perf": "^3.3.3",
"eslint-plugin-suggest-no-throw": "^1.0.0",
"eslint-plugin-testing-library": "^7.1.1",
@ -210,8 +208,8 @@
"setimmediate": "^1.0.5",
"tailwindcss": "^3.4.17",
"ts-node": "^10.0.0",
"typescript": "^5.7.3",
"typescript-eslint": "^8.23.0",
"typescript": "^5.8.2",
"typescript-eslint": "^8.26.1",
"vite": "^5.4.12",
"vite-plugin-package-version": "^1.1.0",
"vite-tsconfig-paths": "^4.3.2",

View File

@ -19,14 +19,14 @@
"private": false,
"dependencies": {
"@codemirror/autocomplete": "6.18.6",
"@codemirror/language": "^6.10.2",
"@codemirror/state": "^6.4.1",
"@codemirror/language": "^6.11.0",
"@codemirror/state": "^6.5.2",
"@lezer/highlight": "^1.2.0",
"@ts-stack/markdown": "^1.5.0",
"json-rpc-2.0": "^1.7.0",
"typescript": "^5.7.2",
"typescript": "^5.8.2",
"vscode-languageserver-protocol": "^3.17.5",
"vscode-uri": "^3.0.8"
"vscode-uri": "^3.1.0"
},
"devDependencies": {
"@types/node": "^22.13.9",

View File

@ -12,10 +12,10 @@
"@codemirror/view" "^6.17.0"
"@lezer/common" "^1.0.0"
"@codemirror/language@^6.0.0", "@codemirror/language@^6.10.2":
version "6.10.2"
resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.10.2.tgz#4056dc219619627ffe995832eeb09cea6060be61"
integrity sha512-kgbTYTo0Au6dCSc/TFy7fK3fpJmgHDv1sG1KNQKJXVi+xBTEeBPY/M30YXiU6mMXeH+YIDLsbrT4ZwNRdtF+SA==
"@codemirror/language@^6.0.0", "@codemirror/language@^6.11.0":
version "6.11.0"
resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.11.0.tgz#5ae90972601497f4575f30811519d720bf7232c9"
integrity sha512-A7+f++LodNNc1wGgoRDTt78cOwWm9KVezApgjOMp1W4hM0898nsqBXwF+sbePE7ZRcjN7Sa1Z5m2oN27XkmEjQ==
dependencies:
"@codemirror/state" "^6.0.0"
"@codemirror/view" "^6.23.0"
@ -24,10 +24,12 @@
"@lezer/lr" "^1.0.0"
style-mod "^4.0.0"
"@codemirror/state@^6.0.0", "@codemirror/state@^6.4.0", "@codemirror/state@^6.4.1":
version "6.4.1"
resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.4.1.tgz#da57143695c056d9a3c38705ed34136e2b68171b"
integrity sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==
"@codemirror/state@^6.0.0", "@codemirror/state@^6.4.0", "@codemirror/state@^6.5.2":
version "6.5.2"
resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.5.2.tgz#8eca3a64212a83367dc85475b7d78d5c9b7076c6"
integrity sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==
dependencies:
"@marijn/find-cluster-break" "^1.0.0"
"@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0":
version "6.28.2"
@ -82,6 +84,11 @@
dependencies:
"@lezer/common" "^1.0.0"
"@marijn/find-cluster-break@^1.0.0":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz#775374306116d51c0c500b8c4face0f9a04752d8"
integrity sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==
"@ts-stack/markdown@^1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@ts-stack/markdown/-/markdown-1.5.0.tgz#5dc298a20dc3dc040143c5a5948201eb6bf5419d"
@ -182,10 +189,10 @@ tslib@^2.3.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0"
integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
typescript@^5.7.2:
version "5.7.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6"
integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==
typescript@^5.8.2:
version "5.8.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4"
integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==
undici-types@~6.20.0:
version "6.20.0"
@ -215,10 +222,10 @@ vscode-languageserver-types@3.17.5:
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz#3273676f0cf2eab40b3f44d085acbb7f08a39d8a"
integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==
vscode-uri@^3.0.8:
version "3.0.8"
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.8.tgz#1770938d3e72588659a172d0fd4642780083ff9f"
integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==
vscode-uri@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c"
integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==
w3c-keyname@^2.2.4:
version "2.2.8"

View File

@ -1,4 +1,5 @@
import { defineConfig, devices } from '@playwright/test'
import { platform } from 'os'
/**
* See https://playwright.dev/docs/test-configuration.
@ -13,7 +14,7 @@ export default defineConfig({
/* Do not retry */
retries: 0,
/* Different amount of parallelism on CI and local. */
workers: 8,
workers: platform() === 'win32' ? 1 : 2,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: [
['dot'],

File diff suppressed because one or more lines are too long

View File

@ -3073,7 +3073,7 @@ DATA;
#3057 = CARTESIAN_POINT('NONE', (0.051104890518972546, -0.039940414856583686, -0.0635));
#3058 = CARTESIAN_POINT('NONE', (0.052242074077479335, -0.038876903045998674, -0.0635));
#3059 = CARTESIAN_POINT('NONE', (0.05224392753122875, -0.03887516966712757, -0.0635));
#3060 = CARTESIAN_POINT('NONE', (0.05311532463588208, -0.03767579444673182, -0.0635));
#3060 = CARTESIAN_POINT('NONE', (0.05311532463588208, -0.03767579444673181, -0.0635));
#3061 = CARTESIAN_POINT('NONE', (0.05311674489404425, -0.03767383962907501, -0.0635));
#3062 = CARTESIAN_POINT('NONE', (0.053776795686355607, -0.03626367057234418, -0.0635));
#3063 = CARTESIAN_POINT('NONE', (0.05377787147891932, -0.036261372189549286, -0.0635));
@ -3087,7 +3087,7 @@ DATA;
#3071 = CARTESIAN_POINT('NONE', (0.053252818350252196, -0.029748655756475863, -0.0635));
#3072 = CARTESIAN_POINT('NONE', (0.05233460363130192, -0.028414043632913145, -0.0635));
#3073 = CARTESIAN_POINT('NONE', (0.05233310706682834, -0.028411868397590818, -0.0635));
#3074 = CARTESIAN_POINT('NONE', (0.051232952266167, -0.02734405921816657, -0.0635));
#3074 = CARTESIAN_POINT('NONE', (0.05123295226616701, -0.02734405921816657, -0.0635));
#3075 = CARTESIAN_POINT('NONE', (0.05123115916423111, -0.027342318835171704, -0.0635));
#3076 = CARTESIAN_POINT('NONE', (0.0499865731843106, -0.02652506813979786, -0.0635));
#3077 = CARTESIAN_POINT('NONE', (0.049984544679296, -0.026523736132881105, -0.0635));
@ -3105,7 +3105,7 @@ DATA;
#3089 = CARTESIAN_POINT('NONE', (0.0407616757108459, -0.02775624333996861, -0.0635));
#3090 = CARTESIAN_POINT('NONE', (0.03976400232776854, -0.0288872140372878, -0.0635));
#3091 = CARTESIAN_POINT('NONE', (0.03976237625653429, -0.028889057364922765, -0.0635));
#3092 = B_SPLINE_CURVE_WITH_KNOTS('NONE', 2, (#3029, #3030, #3031, #3032, #3033, #3034, #3035, #3036, #3037, #3038, #3039, #3040, #3041, #3042, #3043, #3044, #3045, #3046, #3047, #3048, #3049, #3050, #3051, #3052, #3053, #3054, #3055, #3056, #3057, #3058, #3059, #3060, #3061, #3062, #3063, #3064, #3065, #3066, #3067, #3068, #3069, #3070, #3071, #3072, #3073, #3074, #3075, #3076, #3077, #3078, #3079, #3080, #3081, #3082, #3083, #3084, #3085, #3086, #3087, #3088, #3089, #3090, #3091), .UNSPECIFIED., .F., .F., (3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3), (0, 0.01639344262295082, 0.03278688524590164, 0.04918032786885246, 0.06557377049180328, 0.0819672131147541, 0.09836065573770492, 0.11475409836065574, 0.13114754098360656, 0.14754098360655737, 0.1639344262295082, 0.18032786885245902, 0.19672131147540983, 0.21311475409836067, 0.22950819672131148, 0.24590163934426232, 0.26229508196721313, 0.27868852459016397, 0.29508196721311475, 0.3114754098360656, 0.3278688524590164, 0.3442622950819672, 0.36065573770491804, 0.3770491803278689, 0.39344262295081966, 0.4098360655737705, 0.42622950819672134, 0.4426229508196722, 0.45901639344262296, 0.4754098360655738, 0.49180327868852464, 0.5081967213114753, 0.5245901639344261, 0.540983606557377, 0.5573770491803278, 0.5737704918032787, 0.5901639344262295, 0.6065573770491803, 0.6229508196721312, 0.639344262295082, 0.6557377049180328, 0.6721311475409836, 0.6885245901639344, 0.7049180327868853, 0.721311475409836, 0.7377049180327868, 0.7540983606557377, 0.7704918032786885, 0.7868852459016393, 0.8032786885245902, 0.819672131147541, 0.8360655737704918, 0.8524590163934427, 0.8688524590163934, 0.8852459016393442, 0.9016393442622951, 0.9180327868852459, 0.9344262295081968, 0.9508196721311475, 0.9672131147540983, 0.9836065573770492, 1), .UNSPECIFIED.);
#3092 = B_SPLINE_CURVE_WITH_KNOTS('NONE', 2, (#3029, #3030, #3031, #3032, #3033, #3034, #3035, #3036, #3037, #3038, #3039, #3040, #3041, #3042, #3043, #3044, #3045, #3046, #3047, #3048, #3049, #3050, #3051, #3052, #3053, #3054, #3055, #3056, #3057, #3058, #3059, #3060, #3061, #3062, #3063, #3064, #3065, #3066, #3067, #3068, #3069, #3070, #3071, #3072, #3073, #3074, #3075, #3076, #3077, #3078, #3079, #3080, #3081, #3082, #3083, #3084, #3085, #3086, #3087, #3088, #3089, #3090, #3091), .UNSPECIFIED., .F., .F., (3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3), (-1, -0.9836065573770492, -0.9672131147540983, -0.9508196721311475, -0.9344262295081968, -0.9180327868852459, -0.9016393442622951, -0.8852459016393442, -0.8688524590163934, -0.8524590163934427, -0.8360655737704918, -0.819672131147541, -0.8032786885245902, -0.7868852459016393, -0.7704918032786885, -0.7540983606557377, -0.7377049180327868, -0.721311475409836, -0.7049180327868853, -0.6885245901639344, -0.6721311475409836, -0.6557377049180328, -0.639344262295082, -0.6229508196721312, -0.6065573770491803, -0.5901639344262295, -0.5737704918032787, -0.5573770491803278, -0.540983606557377, -0.5245901639344261, -0.5081967213114753, -0.49180327868852464, -0.4754098360655738, -0.45901639344262296, -0.4426229508196722, -0.42622950819672134, -0.4098360655737705, -0.39344262295081966, -0.3770491803278689, -0.36065573770491804, -0.3442622950819672, -0.3278688524590164, -0.3114754098360656, -0.29508196721311475, -0.27868852459016397, -0.26229508196721313, -0.24590163934426232, -0.22950819672131148, -0.21311475409836067, -0.19672131147540983, -0.18032786885245902, -0.1639344262295082, -0.14754098360655737, -0.13114754098360656, -0.11475409836065574, -0.09836065573770492, -0.0819672131147541, -0.06557377049180328, -0.04918032786885246, -0.03278688524590164, -0.01639344262295082, -0), .UNSPECIFIED.);
#3093 = DIRECTION('NONE', (0, 0, 1));
#3094 = VECTOR('NONE', #3093, 1);
#3095 = CARTESIAN_POINT('NONE', (0.03976237625653429, -0.028889057364922765, -0.063501));

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,7 @@ uses-engine = { max-threads = 4 }
after-engine = { max-threads = 12 }
[profile.default]
slow-timeout = { period = "30s", terminate-after = 1 }
slow-timeout = { period = "90s", terminate-after = 1 }
[profile.ci]
slow-timeout = { period = "50s", terminate-after = 5 }

34
rust/Cargo.lock generated
View File

@ -2194,6 +2194,17 @@ dependencies = [
"crc",
]
[[package]]
name = "lzma-sys"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "measurements"
version = "0.11.0"
@ -3463,6 +3474,12 @@ dependencies = [
"digest",
]
[[package]]
name = "sha1_smol"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
[[package]]
name = "sha2"
version = "0.10.8"
@ -4378,6 +4395,7 @@ dependencies = [
"getrandom 0.3.1",
"js-sys",
"serde",
"sha1_smol",
"wasm-bindgen",
]
@ -4855,6 +4873,15 @@ version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547"
[[package]]
name = "xz2"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
dependencies = [
"lzma-sys",
]
[[package]]
name = "yaml-rust"
version = "0.4.5"
@ -4999,9 +5026,9 @@ dependencies = [
[[package]]
name = "zip"
version = "2.2.3"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b280484c454e74e5fff658bbf7df8fdbe7a07c6b2de4a53def232c15ef138f3a"
checksum = "938cc23ac49778ac8340e366ddc422b2227ea176edb447e23fc0627608dddadd"
dependencies = [
"aes",
"arbitrary",
@ -5012,15 +5039,16 @@ dependencies = [
"deflate64",
"displaydoc",
"flate2",
"getrandom 0.3.1",
"hmac",
"indexmap 2.8.0",
"lzma-rs",
"memchr",
"pbkdf2",
"rand 0.8.5",
"sha1",
"thiserror 2.0.12",
"time",
"xz2",
"zeroize",
"zopfli",
"zstd",

View File

@ -49,7 +49,7 @@ tokio = { version = "1" }
tower-lsp = { version = "0.20.0", default-features = false }
tracing-subscriber = { version = "0.3.19", features = ["registry", "std", "fmt", "smallvec", "ansi", "tracing-log", "json"] }
uuid = { version = "1", features = ["v4", "serde"] }
zip = { version = "2.2.2", default-features = false }
zip = { version = "2.4.1", default-features = false }
[workspace.lints.clippy]
assertions_on_result_states = "warn"

View File

@ -802,7 +802,7 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx.run(&program, &mut crate::execution::ExecState::new(&ctx.settings)).await {
if let Err(e) = ctx.run(&program, &mut crate::execution::ExecState::new(&ctx)).await {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,
filename: format!("{}{}", #fn_name, #index),

View File

@ -15,10 +15,7 @@ mod test_examples_someFn {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -15,10 +15,7 @@ mod test_examples_someFn {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -16,10 +16,7 @@ mod test_examples_show {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -16,10 +16,7 @@ mod test_examples_show {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -17,10 +17,7 @@ mod test_examples_my_func {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -17,10 +17,7 @@ mod test_examples_line_to {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -16,10 +16,7 @@ mod test_examples_min {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -16,10 +16,7 @@ mod test_examples_show {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -16,10 +16,7 @@ mod test_examples_import {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -16,10 +16,7 @@ mod test_examples_import {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -16,10 +16,7 @@ mod test_examples_import {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -16,10 +16,7 @@ mod test_examples_show {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -15,10 +15,7 @@ mod test_examples_some_function {
context_type: crate::execution::ContextType::Mock,
};
if let Err(e) = ctx
.run(
&program,
&mut crate::execution::ExecState::new(&ctx.settings),
)
.run(&program, &mut crate::execution::ExecState::new(&ctx))
.await
{
return Err(miette::Report::new(crate::errors::Report {

View File

@ -248,6 +248,7 @@ export class Ctx {
this.clientSubscriptions = []
try {
await this._client?.dispose(2000)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
// DO nothing.
}

View File

@ -80,7 +80,7 @@ ts-rs = { version = "10.1.0", features = [
] }
tynm = "0.1.10"
url = { version = "2.5.4", features = ["serde"] }
uuid = { workspace = true, features = ["v4", "js", "serde"] }
uuid = { workspace = true, features = ["v4", "v5", "js", "serde"] }
validator = { version = "0.20.0", features = ["derive"] }
web-time = "1.1"
winnow = "=0.6.24"

View File

@ -77,7 +77,7 @@ fn run_benchmarks(c: &mut Criterion) {
b.iter(|| {
if let Err(err) = rt.block_on(async {
let ctx = kcl_lib::ExecutorContext::new_with_default_client(Default::default()).await?;
let mut exec_state = kcl_lib::ExecState::new(&ctx.settings);
let mut exec_state = kcl_lib::ExecState::new(&ctx);
ctx.run(black_box(&program), &mut exec_state).await?;
ctx.close().await;
Ok::<(), anyhow::Error>(())

View File

@ -2053,7 +2053,7 @@ sketch000 = startSketchOn('XY')
let ctx = kcl_lib::ExecutorContext::new_with_default_client(Default::default())
.await
.unwrap();
let mut exec_state = kcl_lib::ExecState::new(&ctx.settings);
let mut exec_state = kcl_lib::ExecState::new(&ctx);
let program = kcl_lib::Program::parse_no_errs(code).unwrap();
ctx.run(&program, &mut exec_state).await.unwrap();
@ -2078,7 +2078,7 @@ async fn kcl_test_ensure_nothing_left_in_batch_multi_file() {
let ctx = kcl_lib::ExecutorContext::new_with_default_client(Default::default())
.await
.unwrap();
let mut exec_state = kcl_lib::ExecState::new(&ctx.settings);
let mut exec_state = kcl_lib::ExecState::new(&ctx);
let program = kcl_lib::Program::parse_no_errs(&code).unwrap();
ctx.run(&program, &mut exec_state).await.unwrap();
@ -2106,7 +2106,7 @@ async fn kcl_test_better_type_names() {
},
None => todo!(),
};
assert_eq!(err, "This function expected the input argument to be of type SolidSet but it's actually of type Sketch. You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`");
assert_eq!(err, "This function expected the input argument to be one or more Solids but it's actually of type Sketch. You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`");
}
#[tokio::test(flavor = "multi_thread")]

View File

@ -10,9 +10,9 @@ use pretty_assertions::assert_eq;
async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, ModuleId, uuid::Uuid)> {
let program = Program::parse_no_errs(code)?;
let ctx = kcl_lib::ExecutorContext::new_with_default_client(Default::default()).await?;
let mut exec_state = ExecState::new(&ctx.settings);
let mut exec_state = ExecState::new(&ctx);
let result = ctx.run(&program, &mut exec_state).await?;
let outcome = exec_state.to_wasm_outcome(result.0);
let outcome = exec_state.to_wasm_outcome(result.0).await;
// We need to get the sketch ID.
let KclValue::Sketch { value: sketch } = outcome.variables.get(name).unwrap() else {

View File

@ -1153,7 +1153,7 @@ fn find_examples(text: &str, filename: &str) -> Vec<(String, String)> {
async fn run_example(text: &str) -> Result<()> {
let program = crate::Program::parse_no_errs(text)?;
let ctx = ExecutorContext::new_with_default_client(crate::UnitLength::Mm).await?;
let mut exec_state = crate::execution::ExecState::new(&ctx.settings);
let mut exec_state = crate::execution::ExecState::new(&ctx);
ctx.run(&program, &mut exec_state).await?;
Ok(())
}

View File

@ -128,9 +128,9 @@ impl StdLibFnArg {
""
};
if self.type_ == "Sketch"
|| self.type_ == "SketchSet"
|| self.type_ == "[Sketch]"
|| self.type_ == "Solid"
|| self.type_ == "SolidSet"
|| self.type_ == "[Solid]"
|| self.type_ == "SketchSurface"
|| self.type_ == "SketchOrSurface"
|| self.type_ == "SolidOrImportedGeometry"

View File

@ -18,7 +18,7 @@ use tokio::sync::{mpsc, oneshot, RwLock};
use tokio_tungstenite::tungstenite::Message as WsMsg;
use uuid::Uuid;
use super::ExecutionKind;
use super::{EngineStats, ExecutionKind};
use crate::{
engine::EngineManager,
errors::{KclError, KclErrorDetails},
@ -52,6 +52,7 @@ pub struct EngineConnection {
session_data: Arc<RwLock<Option<ModelingSessionData>>>,
execution_kind: Arc<RwLock<ExecutionKind>>,
stats: EngineStats,
}
pub struct TcpRead {
@ -344,6 +345,7 @@ impl EngineConnection {
default_planes: Default::default(),
session_data,
execution_kind: Default::default(),
stats: Default::default(),
})
}
}
@ -378,22 +380,12 @@ impl EngineManager for EngineConnection {
original
}
async fn default_planes(
&self,
id_generator: &mut IdGenerator,
source_range: SourceRange,
) -> Result<DefaultPlanes, KclError> {
{
let opt = self.default_planes.read().await.as_ref().cloned();
if let Some(planes) = opt {
return Ok(planes);
}
} // drop the read lock
fn stats(&self) -> &EngineStats {
&self.stats
}
let new_planes = self.new_default_planes(id_generator, source_range).await?;
*self.default_planes.write().await = Some(new_planes.clone());
Ok(new_planes)
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
self.default_planes.clone()
}
async fn clear_scene_post_hook(

View File

@ -16,7 +16,7 @@ use kittycad_modeling_cmds::{self as kcmc};
use tokio::sync::RwLock;
use uuid::Uuid;
use super::ExecutionKind;
use super::{EngineStats, ExecutionKind};
use crate::{
errors::KclError,
exec::DefaultPlanes,
@ -30,6 +30,9 @@ pub struct EngineConnection {
batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>,
execution_kind: Arc<RwLock<ExecutionKind>>,
/// The default planes for the scene.
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
stats: EngineStats,
}
impl EngineConnection {
@ -39,6 +42,8 @@ impl EngineConnection {
batch_end: Arc::new(RwLock::new(IndexMap::new())),
artifact_commands: Arc::new(RwLock::new(Vec::new())),
execution_kind: Default::default(),
default_planes: Default::default(),
stats: Default::default(),
})
}
}
@ -57,6 +62,10 @@ impl crate::engine::EngineManager for EngineConnection {
Arc::new(RwLock::new(IndexMap::new()))
}
fn stats(&self) -> &EngineStats {
&self.stats
}
fn artifact_commands(&self) -> Arc<RwLock<Vec<ArtifactCommand>>> {
self.artifact_commands.clone()
}
@ -73,12 +82,8 @@ impl crate::engine::EngineManager for EngineConnection {
original
}
async fn default_planes(
&self,
_id_generator: &mut IdGenerator,
_source_range: SourceRange,
) -> Result<DefaultPlanes, KclError> {
Ok(DefaultPlanes::default())
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
self.default_planes.clone()
}
async fn clear_scene_post_hook(

View File

@ -11,7 +11,7 @@ use uuid::Uuid;
use wasm_bindgen::prelude::*;
use crate::{
engine::ExecutionKind,
engine::{EngineStats, ExecutionKind},
errors::{KclError, KclErrorDetails},
execution::{ArtifactCommand, DefaultPlanes, IdGenerator},
SourceRange,
@ -31,12 +31,6 @@ extern "C" {
idToRangeStr: String,
) -> Result<js_sys::Promise, js_sys::Error>;
#[wasm_bindgen(method, js_name = wasmGetDefaultPlanes, catch)]
fn get_default_planes(this: &EngineCommandManager) -> Result<js_sys::Promise, js_sys::Error>;
#[wasm_bindgen(method, js_name = clearDefaultPlanes, catch)]
fn clear_default_planes(this: &EngineCommandManager) -> Result<(), js_sys::Error>;
#[wasm_bindgen(method, js_name = startNewSession, catch)]
fn start_new_session(this: &EngineCommandManager) -> Result<js_sys::Promise, js_sys::Error>;
}
@ -49,6 +43,9 @@ pub struct EngineConnection {
responses: Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>>,
artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>,
execution_kind: Arc<RwLock<ExecutionKind>>,
/// The default planes for the scene.
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
stats: EngineStats,
}
// Safety: WebAssembly will only ever run in a single-threaded context.
@ -65,6 +62,8 @@ impl EngineConnection {
responses: Arc::new(RwLock::new(IndexMap::new())),
artifact_commands: Arc::new(RwLock::new(Vec::new())),
execution_kind: Default::default(),
default_planes: Default::default(),
stats: Default::default(),
})
}
@ -144,6 +143,10 @@ impl crate::engine::EngineManager for EngineConnection {
self.responses.clone()
}
fn stats(&self) -> &EngineStats {
&self.stats
}
fn artifact_commands(&self) -> Arc<RwLock<Vec<ArtifactCommand>>> {
self.artifact_commands.clone()
}
@ -160,59 +163,18 @@ impl crate::engine::EngineManager for EngineConnection {
original
}
async fn default_planes(
&self,
_id_generator: &mut IdGenerator,
source_range: SourceRange,
) -> Result<DefaultPlanes, KclError> {
// Get the default planes.
let promise = self.manager.get_default_planes().map_err(|e| {
KclError::Engine(KclErrorDetails {
message: e.to_string().into(),
source_ranges: vec![source_range],
})
})?;
let value = crate::wasm::JsFuture::from(promise).await.map_err(|e| {
KclError::Engine(KclErrorDetails {
message: format!("Failed to wait for promise from get default planes: {:?}", e),
source_ranges: vec![source_range],
})
})?;
// Parse the value as a string.
let s = value.as_string().ok_or_else(|| {
KclError::Engine(KclErrorDetails {
message: format!(
"Failed to get string from response from get default planes: `{:?}`",
value
),
source_ranges: vec![source_range],
})
})?;
// Deserialize the response.
let default_planes: DefaultPlanes = serde_json::from_str(&s).map_err(|e| {
KclError::Engine(KclErrorDetails {
message: format!("Failed to deserialize default planes: {:?}", e),
source_ranges: vec![source_range],
})
})?;
Ok(default_planes)
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
self.default_planes.clone()
}
async fn clear_scene_post_hook(
&self,
_id_generator: &mut IdGenerator,
id_generator: &mut IdGenerator,
source_range: SourceRange,
) -> Result<(), KclError> {
self.manager.clear_default_planes().map_err(|e| {
KclError::Engine(KclErrorDetails {
message: e.to_string().into(),
source_ranges: vec![source_range],
})
})?;
// 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?;
*self.default_planes.write().await = Some(new_planes);
// Start a new session.
let promise = self.manager.start_new_session().map_err(|e| {

View File

@ -8,7 +8,13 @@ pub mod conn_mock;
#[cfg(feature = "engine")]
pub mod conn_wasm;
use std::{collections::HashMap, sync::Arc};
use std::{
collections::HashMap,
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
};
use indexmap::IndexMap;
use kcmc::{
@ -58,6 +64,21 @@ impl ExecutionKind {
}
}
#[derive(Default, Debug)]
pub struct EngineStats {
pub commands_batched: AtomicUsize,
pub batches_sent: AtomicUsize,
}
impl Clone for EngineStats {
fn clone(&self) -> Self {
Self {
commands_batched: AtomicUsize::new(self.commands_batched.load(Ordering::Relaxed)),
batches_sent: AtomicUsize::new(self.batches_sent.load(Ordering::Relaxed)),
}
}
}
#[async_trait::async_trait]
pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
/// Get the batch of commands to be sent to the engine.
@ -95,11 +116,28 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind;
/// Get the default planes.
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>>;
fn stats(&self) -> &EngineStats;
/// Get the default planes, creating them if they don't exist.
async fn default_planes(
&self,
id_generator: &mut IdGenerator,
_source_range: SourceRange,
) -> Result<DefaultPlanes, crate::errors::KclError>;
source_range: SourceRange,
) -> Result<DefaultPlanes, KclError> {
{
let opt = self.get_default_planes().read().await.as_ref().cloned();
if let Some(planes) = opt {
return Ok(planes);
}
} // drop the read lock
let new_planes = self.new_default_planes(id_generator, source_range).await?;
*self.get_default_planes().write().await = Some(new_planes.clone());
Ok(new_planes)
}
/// Helpers to be called after clearing a scene.
/// (These really only apply to wasm for now).
@ -239,6 +277,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// Add cmd to the batch.
self.batch().write().await.push((req, source_range));
self.stats().commands_batched.fetch_add(1, Ordering::Relaxed);
Ok(())
}
@ -262,6 +301,9 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
for cmd in cmds {
extended_cmds.push((WebSocketRequest::ModelingCmdReq(cmd.clone()), source_range));
}
self.stats()
.commands_batched
.fetch_add(extended_cmds.len(), Ordering::Relaxed);
self.batch().write().await.extend(extended_cmds);
Ok(())
@ -288,6 +330,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// Add cmd to the batch end.
self.batch_end().write().await.insert(id, (req, source_range));
self.stats().commands_batched.fetch_add(1, Ordering::Relaxed);
Ok(())
}
@ -390,6 +433,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
if batch_end {
self.batch_end().write().await.clear();
}
self.stats().batches_sent.fetch_add(1, Ordering::Relaxed);
// We pop off the responses to cleanup our mappings.
match final_req {

View File

@ -4,7 +4,7 @@ use thiserror::Error;
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
use crate::{
execution::{ArtifactCommand, ArtifactGraph, Operation},
execution::{ArtifactCommand, ArtifactGraph, DefaultPlanes, Operation},
lsp::IntoDiagnostic,
modules::{ModulePath, ModuleSource},
source_range::SourceRange,
@ -131,6 +131,7 @@ pub struct KclErrorWithOutputs {
pub artifact_graph: ArtifactGraph,
pub filenames: IndexMap<ModuleId, ModulePath>,
pub source_files: IndexMap<ModuleId, ModuleSource>,
pub default_planes: Option<DefaultPlanes>,
}
impl KclErrorWithOutputs {
@ -141,6 +142,7 @@ impl KclErrorWithOutputs {
artifact_graph: ArtifactGraph,
filenames: IndexMap<ModuleId, ModulePath>,
source_files: IndexMap<ModuleId, ModuleSource>,
default_planes: Option<DefaultPlanes>,
) -> Self {
Self {
error,
@ -149,6 +151,7 @@ impl KclErrorWithOutputs {
artifact_graph,
filenames,
source_files,
default_planes,
}
}
pub fn no_outputs(error: KclError) -> Self {
@ -159,6 +162,7 @@ impl KclErrorWithOutputs {
artifact_graph: Default::default(),
filenames: Default::default(),
source_files: Default::default(),
default_planes: Default::default(),
}
}
pub fn into_miette_report_with_outputs(self, code: &str) -> anyhow::Result<ReportWithOutputs> {

View File

@ -180,15 +180,9 @@ pub enum OpKclValue {
Sketch {
value: Box<OpSketch>,
},
Sketches {
value: Vec<OpSketch>,
},
Solid {
value: Box<OpSolid>,
},
Solids {
value: Vec<OpSolid>,
},
Helix {
value: Box<OpHelix>,
},
@ -234,7 +228,7 @@ impl From<&KclValue> for OpKclValue {
ty: ty.clone(),
},
KclValue::String { value, .. } => Self::String { value: value.clone() },
KclValue::MixedArray { value, .. } => {
KclValue::MixedArray { value, .. } | KclValue::HomArray { value, .. } => {
let value = value.iter().map(Self::from).collect();
Self::Array { value }
}
@ -244,7 +238,7 @@ impl From<&KclValue> for OpKclValue {
}
KclValue::TagIdentifier(tag_identifier) => Self::TagIdentifier {
value: tag_identifier.value.clone(),
artifact_id: tag_identifier.info.as_ref().map(|info| ArtifactId::new(info.id)),
artifact_id: tag_identifier.get_cur_info().map(|info| ArtifactId::new(info.id)),
},
KclValue::TagDeclarator(node) => Self::TagDeclarator {
name: node.name.clone(),
@ -260,29 +254,11 @@ impl From<&KclValue> for OpKclValue {
artifact_id: value.artifact_id,
}),
},
KclValue::Sketches { value } => {
let value = value
.iter()
.map(|sketch| OpSketch {
artifact_id: sketch.artifact_id,
})
.collect();
Self::Sketches { value }
}
KclValue::Solid { value } => Self::Solid {
value: Box::new(OpSolid {
artifact_id: value.artifact_id,
}),
},
KclValue::Solids { value } => {
let value = value
.iter()
.map(|solid| OpSolid {
artifact_id: solid.artifact_id,
})
.collect();
Self::Solids { value }
}
KclValue::Helix { value } => Self::Helix {
value: Box::new(OpHelix {
artifact_id: value.artifact_id,
@ -295,7 +271,6 @@ impl From<&KclValue> for OpKclValue {
KclValue::Module { .. } => Self::Module {},
KclValue::KclNone { .. } => Self::KclNone {},
KclValue::Type { .. } => Self::Type {},
KclValue::Tombstone { .. } => unreachable!("Tombstone OpKclValue"),
}
}
}

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